diff --git a/CMakeLists.txt b/CMakeLists.txt index be0cb858d..e60054813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,16 +35,16 @@ cmake_dependent_option(TARGET_DESKTOP_GLES "Build for OpenGL ES on desktop" OFF # Parts of the library option(WITH_DEBUGTOOLS "Build DebugTools library" ON) cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" ON "NOT WITH_DEBUGTOOLS" ON) -cmake_dependent_option(WITH_PHYSICS "Build Physics library" ON "NOT WITH_DEBUGTOOLS" ON) cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" ON "NOT WITH_DEBUGTOOLS" ON) -cmake_dependent_option(WITH_SCENEGRAPH "Build SceneGraph library" ON "NOT WITH_DEBUGTOOLS;NOT WITH_PHYSICS" ON) +cmake_dependent_option(WITH_SCENEGRAPH "Build SceneGraph library" ON "NOT WITH_DEBUGTOOLS;NOT WITH_SHAPES" ON) cmake_dependent_option(WITH_SHADERS "Build Shaders library" ON "NOT WITH_DEBUGTOOLS" ON) +cmake_dependent_option(WITH_SHAPES "Build Shapes library" ON "NOT WITH_DEBUGTOOLS" ON) option(WITH_TEXT "Build Text library" ON) cmake_dependent_option(WITH_TEXTURETOOLS "Build TextureTools library" ON "NOT WITH_TEXT" ON) -option(WITH_MAGNUMINFO "Build magnum-info utility" ON) +option(WITH_MAGNUMINFO "Build magnum-info utility" OFF) # Application libraries -if(${CMAKE_SYSTEM_NAME} STREQUAL NaCl) +if(CORRADE_TARGET_NACL) option(WITH_NACLAPPLICATION "Build NaClApplication library" OFF) else() option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF) @@ -73,14 +73,19 @@ endif() find_package(Corrade REQUIRED) -if(BUILD_STATIC) - set(MAGNUM_BUILD_STATIC 1) -endif() - -# If targeting NaCl, set explicit OpenGL ES 2.0 support -if(CORRADE_TARGET_NACL) +# If targeting NaCl or Emscripten, set explicit OpenGL ES 2.0 support +if(CORRADE_TARGET_NACL OR CORRADE_TARGET_EMSCRIPTEN) set(TARGET_GLES 1) set(TARGET_GLES2 1) + + # Newlib toolchain supports only static linking + if(CORRADE_TARGET_NACL_NEWLIB) + set(BUILD_STATIC OFF) + endif() +endif() + +if(BUILD_STATIC) + set(MAGNUM_BUILD_STATIC 1) endif() # Check dependencies diff --git a/Doxyfile b/Doxyfile index 54e5ba71f..c6ab1a574 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,8 +1,10 @@ -# Doxyfile 1.8.1 +# Doxyfile 1.8.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # +# All text after a double hash (##) is considered a comment and is placed +# in front of the TAG it is preceding . # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] @@ -70,9 +72,9 @@ CREATE_SUBDIRS = NO # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English @@ -126,7 +128,9 @@ FULL_PATH_NAMES = YES # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the -# path to strip. +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. STRIP_FROM_PATH = ../ @@ -254,14 +258,15 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. EXTENSION_MAPPING = @@ -274,6 +279,13 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and @@ -294,10 +306,10 @@ CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. @@ -326,13 +338,13 @@ SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). -# `YES` causes unclosed element for TgaImporter class in tag file +## `YES` causes unclosed element for TgaImporter class in tag file INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum @@ -345,30 +357,14 @@ INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. LOOKUP_CACHE_SIZE = 0 @@ -379,7 +375,7 @@ LOOKUP_CACHE_SIZE = 0 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO @@ -388,7 +384,8 @@ EXTRACT_ALL = NO EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. EXTRACT_PACKAGE = NO @@ -490,7 +487,7 @@ INLINE_INFO = YES # alphabetically by member name. If set to NO the members will appear in # declaration order. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically @@ -559,7 +556,8 @@ GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = @@ -604,7 +602,7 @@ FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file +# output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. @@ -617,7 +615,8 @@ LAYOUT_FILE = # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = @@ -734,9 +733,7 @@ EXCLUDE_SYMLINKS = NO # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = */Test/* \ - */Implementation/* \ - *Visibility.h +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -744,7 +741,8 @@ EXCLUDE_PATTERNS = */Test/* \ # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = Magnum::*Implementation \ + Magnum::*Test # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see @@ -778,8 +776,10 @@ IMAGE_PATH = ../magnum-examples/src/ # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. +# If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. INPUT_FILTER = @@ -808,6 +808,13 @@ FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- @@ -826,7 +833,7 @@ INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES @@ -929,17 +936,27 @@ HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# style sheet in the HTML output directory as well, or it will be erased! +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. HTML_STYLESHEET = +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. @@ -978,9 +995,7 @@ HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# page has loaded. HTML_DYNAMIC_SECTIONS = NO @@ -1022,9 +1037,9 @@ DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher @@ -1209,6 +1224,13 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax @@ -1226,6 +1248,11 @@ MATHJAX_RELPATH = http://www.mathjax.org/mathjax MATHJAX_EXTENSIONS = +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using @@ -1237,15 +1264,55 @@ MATHJAX_EXTENSIONS = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. SERVER_BASED_SEARCH = NO +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- @@ -1283,7 +1350,7 @@ COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. +# executive. If left blank a4 will be used. PAPER_TYPE = a4 @@ -1306,6 +1373,13 @@ LATEX_HEADER = LATEX_FOOTER = +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references @@ -1450,6 +1524,21 @@ XML_DTD = XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -1597,7 +1686,13 @@ ALLEXTERNALS = NO # in the modules index. If set to NO, only the current project's groups will # be listed. -EXTERNAL_GROUPS = YES +EXTERNAL_GROUPS = NO + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = NO # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). @@ -1695,7 +1790,7 @@ UML_LOOK = NO # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be +# manageable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 diff --git a/README.md b/README.md index 8aa48981c..292534235 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,8 @@ SUPPORTED PLATFORMS * **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through GLUT or SDL2 toolkit) * **Windows** (through GLUT or SDL2 toolkit) -* **Google Chrome Native Client** (natively using PPAPI, both `newlib` - and `glibc` toolchains are supported) +* **Google Chrome** (through [Native Client](https://developers.google.com/native-client/), + both `newlib` and `glibc` toolchains are supported) FEATURES ======== diff --git a/doc/building.dox b/doc/building.dox index 621984b12..67f412056 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -97,17 +97,17 @@ below). Using `WITH_*` CMake parameters you can specify which parts will be buil and which not: - `WITH_DEBUGTOOLS` - DebugTools library. Enables also building of MeshTools, - Physics, Primitives, SceneGraph and Shaders libraries. + Primitives, SceneGraph, Shaders and Shapes libraries. - `WITH_MESHTOOLS` - MeshTools library. Enabled automatically if `WITH_DEBUGTOOLS` is enabled. - - `WITH_PHYSICS` - Physics library. Enables also building of SceneGraph - library. Enabled automatically if `WITH_DEBUGTOOLS` is enabled. - `WITH_PRIMITIVES` - Primitives library. Enabled automatically if `WITH_DEBUGTOOLS` is enabled. - `WITH_SCENEGRAPH` - SceneGraph library. Enabled automatically if `WITH_DEBUGTOOLS` - or `WITH_PHYSICS` is enabled. + or `WITH_SHAPES` is enabled. - `WITH_SHADERS` - Shaders library. Enabled automatically if `WITH_DEBUGTOOLS` is enabled. + - `WITH_SHAPES` - Shapes library. Enables also building of SceneGraph library. + Enabled automatically if `WITH_DEBUGTOOLS` is enabled. - `WITH_TEXT` - Text library. Enables also building of TextureTools library. - `WITH_TEXTURETOOLS` - TextureTools library. Enabled automatically if `WITH_TEXT` is enabled. @@ -207,17 +207,21 @@ depending projects. You will need [Native Client SDK](https://developers.google.com/native-client/beta/sdk/download). Tested version is `pepper_22`. -Make sure you have `toolchains` Git submodule updated, as -@ref building-download "explained above". Don't forget to adapt `NACL_PREFIX` -variable in `generic/NaCl-glibc-x86-32.cmake` and `generic/NaCl-glibc-x86-64.cmake` -to path where your SDK is installed. Default is `/usr/nacl`. You may need to -adapt also `NACL_TOOLCHAIN_PATH` so CMake is able to find the compiler. +Make sure you have `toolchains` submodule updated, as +@ref building-download "explained above". You can choose from either `glibc` or +`newlib` toolchain. `Newlib` supports only static linking, thus `BUILD_STATIC` +is always enabled. Don't forget to adapt `NACL_PREFIX` variable in +`generic/NaCl-*-x86-32.cmake` and `generic/NaCl-*-x86-64.cmake` to path where +your SDK is installed. Default is `/usr/nacl`. You may need to adapt also +`NACL_TOOLCHAIN_PATH` so CMake is able to find the compiler. NaCl currently +supports only OpenGL ES 2, thus `TARGET_GLES` and `TARGET_GLES2` is always +enabled. Then create build directories for x86-32 and x86-64 and run cmake and make in -them. The toolchains needs access to its platform file, so be sure to properly +them. The toolchains need access to its platform file, so be sure to properly set **absolute** path to `modules/` directory containing `Platform/NaCl.cmake`. -Also adapt `CMAKE_INSTALL_PREFIX` to the same value you entered into toolchain -files above. +Also adapt `CMAKE_INSTALL_PREFIX` to the same value as in `NACL_PREFIX` in +toolchain file. mkdir -p build-nacl-x86-32 cd build-nacl-x86-32 @@ -243,8 +247,8 @@ files above. Then you can install both versions using `make install` to make them available for depending projects. The headers are shared by both versions. -For ArchLinux there is also prepared package file in root, named -`PKGBUILD-nacl`. +For ArchLinux there are also prepared package files in root, named +`PKGBUILD-nacl-glibc` and `PKGBUILD-nacl-newlib`. */ } diff --git a/doc/cmake.dox b/doc/cmake.dox index ad07c3acd..b23a19c51 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -51,13 +51,13 @@ components. The base library depends on %Corrade, OpenGL and GLEW libraries (or OpenGL ES libraries). Additional dependencies are specified by the components. The optional components are: -- `%DebugTools` -- DebugTools library (depends on `%MeshTools`, `%Physics`, - `%Primitives`, `%SceneGraph` and `%Shaders` components) +- `%DebugTools` -- DebugTools library (depends on `%MeshTools`, + `%Primitives`, `%SceneGraph`, `%Shaders` and `%Shapes` components) - `%MeshTools` -- MeshTools library -- `%Physics` -- Physics library (depends on `%SceneGraph` component) - `%Primitives` -- Primitives library - `%SceneGraph` -- SceneGraph library - `%Shaders` -- Shaders library +- `%Shapes` -- Shapes library (depends on `%SceneGraph` component) - `%Text` -- Text library (depends on `%TextureTools` component) - `%TextureTools` -- TextureTools library diff --git a/doc/coding-style.dox b/doc/coding-style.dox index 68a8ea39f..28e892516 100644 --- a/doc/coding-style.dox +++ b/doc/coding-style.dox @@ -100,9 +100,9 @@ void setPolygonMode(PolygonMode mode); Additionally to @c \@todoc, @c \@debugoperator @c \@configurationvalue and @c \@configurationvalueref (same as in Corrade), these are defined: -@subsubsection documentation-commands-collisionoperator Physics collision operators +@subsubsection documentation-commands-collisionoperator Shape collision operators -Out-of-class operators for collision in Physics namespace should be marked with +Out-of-class operators for collision in Shapes namespace should be marked with @c \@collisionoperator, e.g.: @code // @collisionoperator{Point,Sphere} @@ -139,7 +139,7 @@ in @c \@see block with @c \@fn_gl command. If only specific definition is used in the function, document it with @c \@def_gl command. Example usage: @code // @see @fn_gl{Enable}/@fn_gl{Disable} with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS} -inline static void setSeamless(bool enabled) { +static void setSeamless(bool enabled) { enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } @endcode diff --git a/doc/collision-detection.dox b/doc/collision-detection.dox deleted file mode 100644 index e263492a0..000000000 --- a/doc/collision-detection.dox +++ /dev/null @@ -1,134 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -namespace Magnum { namespace Physics { -/** @page collision-detection Collision detection -@brief Collection of simple shapes for high performance collision detection. - -The essential thing in collision detection is to define a complex object with -collection of simple shapes, for which it is easy to detect collisions. These -shapes can be either one-, two- or three-dimensional and they can be grouped -together using various operations. - -@tableofcontents - -@section collision-detection-shape-collection Available shapes - -@subsection collision-detection-shapes1D One-dimensional shapes - -- @ref Physics::Point "Physics::Point*D" - @copybrief Physics::Point -- @ref Physics::Line "Physics::Line*D" - @copybrief Physics::Line -- @ref Physics::LineSegment "Physics::LineSegment*D" - @copybrief Physics::LineSegment - -Because of numerical instability it's not possible to detect collisions of -line and point. Collision of two lines can be detected only in 2D. - -@subsection collision-detection-shapes2D Two-dimensional shapes - -- Physics::Plane - @copybrief Physics::Plane - -@subsection collision-detection-shapes3D Three-dimensional shapes - -- @ref Physics::Sphere "Physics::Sphere*D" - @copybrief Physics::Sphere -- @ref Physics::Capsule "Physics::Capsule*D" - @copybrief Physics::Capsule -- @ref Physics::AxisAlignedBox "Physics::AxisAlignedBox*D" - @copybrief Physics::AxisAlignedBox -- @ref Physics::Box "Physics::Box*D" - @copybrief Physics::Box - -The easiest (and most efficient) shape combination for detecting collisions -is point and sphere, followed by two spheres. Computing collision of two boxes -is least efficient. - -@section collision-detection-shape-groups Creating hierarchic groups of shapes - -Shapes can be grouped together using one of three available logical -operations: AND, OR and NOT. These operations are mapped to operator&&(), -operator||() and operator!(), so for example creating negation of logical OR -of line segment and point is simple as this: -@code -Physics::LineSegment3D segment; -Physics::Point3D point; - -Physics::ShapeGroup3D group = !(segment || point); -@endcode - -@note Logical operations are not the same as set operations -- intersection of - two spheres will not generate any collision if they are disjoint, but - logical AND will if the object collides with both of them. - -The resulting object internally stores copies of both shapes, so the original -instances can be destroyed. For simple combinations appropriate resulting -shape is generated (e.g. logical OR of point and sphere can be only the sphere, -if the point lies inside) and stored inside ShapeGroup instead of two original -objects. - -@subsection collision-detection-shape-reference Referencing the shapes for later changes - -Sometimes you may want to modify the shape based on changes of the object -itself. In previous example all the shapes were copied into ShapeGroup, so it -was not possible to change their properties such as sphere radius without -recreating the group again. You can, however, explicitly pass a reference to -original object, so you can change it later: -@code -Physics::LineSegment3D segment; -Physics::Point3D point; - -Physics::ShapeGroup3D group = !(segment || std::ref(point)); - -point.setPosition({1.0f, -6.0f, 0.5f}); -@endcode - -Note that passing a reference implies that you must not destroy the original -instance (in this case the point). Also because the referenced instance could -change, there are no shape optimizations done, unlike above. - -@subsection collision-detection-shape-simplification Providing simplified version of shape for better performance - -If there are many shapes grouped together, it might hurt performance of -collision detection, because it might be testing collision with more shapes -than necessary. It's then good to specify simplified version of such shape, -so the collision detection is done on the original if and only if collision -was detected with the simplified shape. It is in fact logical AND using -operator&&() - the collision is initially detected on first (simplified) shape -and then on the other: -@code -Physics::Sphere3D sphere; -Physics::Box3D box; -Physics::AxisAlignedBox3D simplified; - -Physics::ShapeGroup3D object = simplified && (sphere || box); -@endcode - -@section collision-detection-shape-collisions Detecting shape collisions - -Shape pairs which have collision detection implemented can be tested for -collision using operator%(), for example: -@code -Physics::Point3D point; -Physics::Sphere3D sphere; - -bool collide = point % sphere; -@endcode - -*/ -}}} diff --git a/doc/compilation-speedup.dox b/doc/compilation-speedup.dox index f05196e0a..efdd3db0a 100644 --- a/doc/compilation-speedup.dox +++ b/doc/compilation-speedup.dox @@ -46,9 +46,9 @@ available, each namespace has its own: - Math/Math.h - Magnum.h - DebugTools/DebugTools.h - - Physics/Physics.h - SceneGraph/SceneGraph.h - Shaders/Shaders.h + - Shapes/Shapes.h - Text/Text.h - Trade/Trade.h diff --git a/doc/features.dox b/doc/features.dox index f06747f7c..a2e0e22db 100644 --- a/doc/features.dox +++ b/doc/features.dox @@ -31,7 +31,7 @@ namespace Magnum { - @subpage matrix-vector -- @copybrief matrix-vector - @subpage transformations -- @copybrief transformations - @subpage scenegraph -- @copybrief scenegraph -- @subpage collision-detection -- @copybrief collision-detection +- @subpage shapes -- @copybrief shapes - @subpage debug-tools -- @copybrief debug-tools */ } diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 660d85cf6..7ed82d7d5 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -68,8 +68,8 @@ namespace Magnum { - **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through GLUT or SDL2 toolkit) - **Windows** (through GLUT or SDL2 toolkit) -- **Google Chrome Native Client** (natively using PPAPI, both `newlib` - and `glibc` toolchains are supported) +- **Google Chrome** (through [Native Client](https://developers.google.com/native-client/), + both `newlib` and `glibc` toolchains are supported) @section mainpage-features Features diff --git a/doc/method-chaining.dox b/doc/method-chaining.dox index 798830984..3c8f99407 100644 --- a/doc/method-chaining.dox +++ b/doc/method-chaining.dox @@ -43,9 +43,9 @@ number of needed bindings. Consider the following example: @code Texture2D *carDiffuseTexture, *carSpecularTexture, *carBumpTexture; -carDiffuseTexture->setStorage(5, Texture2D::InternalFormat::SRGB8); -carSpecularTexture->setStorage(3, Texture2D::InternalFormat::R8); -carBumpTexture->setStorage(5, Texture2D::InternalFormat::RGB8); +carDiffuseTexture->setStorage(5, TextureFormat::SRGB8); +carSpecularTexture->setStorage(3, TextureFormat::R8); +carBumpTexture->setStorage(5, TextureFormat::RGB8); carDiffuseTexture->setSubImage(0, {}, diffuse); carSpecularTexture->setSubImage(0, {}, specular; carBumpTexture->setSubImage(0, {}, bump); @@ -61,13 +61,13 @@ names and after each configuration step the texture must be rebound to another. With method chaining used the code looks much lighter and each object is configured in one run, reducing count of bind calls from 9 to 3. @code -carDiffuseTexture->setStorage(5, Texture2D::InternalFormat::SRGB8) +carDiffuseTexture->setStorage(5, TextureFormat::SRGB8) ->setSubImage(0, {}, diffuse) ->generateMipmap(); -carSpecularTexture->setStorage(3, Texture2D::InternalFormat::R8) +carSpecularTexture->setStorage(3, TextureFormat::R8) ->setSubImage(0, {}, diffuse) ->generateMipmap(); -carBumpTexture->setStorage(5, Texture2D::InternalFormat::RGB8) +carBumpTexture->setStorage(5, TextureFormat::RGB8) ->setSubImage(0, {}, bump) ->generateMipmap(); @endcode @@ -86,5 +86,10 @@ Scene3D scene; ->rotateX(90.0_degf) ->translate({-1.5f, 0.5f, 7.0f}); @endcode + +In most cases method chaining methods return pointer to the object, because +most of the objects are commonly created on the heap. The only exception are +Shader methods, which return reference, because the class is commonly created +as local variable in shader constructors. */ } diff --git a/doc/namespaces.dox b/doc/namespaces.dox index e60a77c03..8a4e1b3b7 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -155,16 +155,15 @@ This library is built when `WITH_SHADERS` is enabled and found as `%Shaders` component in CMake. See @ref building and @ref cmake for more information. */ -/** @dir Physics - * @brief Namespace Magnum::Physics +/** @dir Shapes + * @brief Namespace Magnum::Shapes */ -/** @namespace Magnum::Physics -@brief %Physics library +/** @namespace Magnum::Shapes +@brief %Shape library -Collision detection system and rigid body objects. See @ref collision-detection -for introduction. +Collision detection system. See @ref shapes for introduction. -This library is built when `WITH_PHYSICS` is enabled and found as `%Physics` +This library is built when `WITH_SHAPES` is enabled and found as `%Shapes` component in CMake. See @ref building and @ref cmake for more information. */ diff --git a/doc/platform.dox b/doc/platform.dox index 525355321..365886087 100644 --- a/doc/platform.dox +++ b/doc/platform.dox @@ -76,7 +76,7 @@ void MyApplication::viewportEvent(const Vector2i& size) { void MyApplication::drawEvent() { // Clear the window - defaultFramebuffer.clear(); + defaultFramebuffer.clear(DefaultFramebuffer::Clear::Color); // The context is double-buffered, swap buffers swapBuffers(); diff --git a/doc/scenegraph.dox b/doc/scenegraph.dox index d634c0188..f20938241 100644 --- a/doc/scenegraph.dox +++ b/doc/scenegraph.dox @@ -151,7 +151,7 @@ Simplified example: @code class Bomb: public Object3D, SceneGraph::Drawable3D<>, SceneGraph:.Animable3D<> { public: - inline Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D<>(this), SceneGraph::Animable3D<>(this) {} + Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D<>(this), SceneGraph::Animable3D<>(this) {} protected: // drawing implementation for Drawable feature diff --git a/doc/shapes.dox b/doc/shapes.dox new file mode 100644 index 000000000..cb99d5454 --- /dev/null +++ b/doc/shapes.dox @@ -0,0 +1,120 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +namespace Magnum { namespace Shapes { +/** @page shapes Collision detection +@brief Collection of simple shapes for high performance collision detection. + +The essential thing in collision detection is to define a complex object with +collection of simple shapes, for which it is easy to detect collisions. These +shapes can be either one-, two- or three-dimensional and they can be grouped +together using various operations. + +@tableofcontents + +@section shapes-collection Available shapes + +@subsection shapes-1D One-dimensional shapes + +- @ref Shapes::Point "Shapes::Point*D" -- @copybrief Shapes::Point +- @ref Shapes::Line "Shapes::Line*D" -- @copybrief Shapes::Line +- @ref Shapes::LineSegment "Shapes::LineSegment*D" -- @copybrief Shapes::LineSegment + +Because of numerical instability it's not possible to detect collisions of +line and point. Collision of two lines can be detected only in 2D. + +@subsection shapes-2D Two-dimensional shapes + +- Shapes::Plane -- @copybrief Shapes::Plane + +@subsection shapes-3D Three-dimensional shapes + +- @ref Shapes::Sphere "Shapes::Sphere*D" -- @copybrief Shapes::Sphere +- @ref Shapes::Capsule "Shapes::Capsule*D" -- @copybrief Shapes::Capsule +- @ref Shapes::AxisAlignedBox "Shapes::AxisAlignedBox*D" -- @copybrief Shapes::AxisAlignedBox +- @ref Shapes::Box "Shapes::Box*D" -- @copybrief Shapes::Box + +The easiest (and most efficient) shape combination for detecting collisions +is point and sphere, followed by two spheres. Computing collision of two boxes +is least efficient. + +@section shapes-composition Creating shape compositions + +%Shapes can be composed together using one of three available logical +operations: AND, OR and NOT. These operations are mapped to operator&&(), +operator||() and operator!(), so for example creating negation of logical OR +of line segment and point is simple as this: +@code +Shapes::LineSegment3D segment; +Shapes::Point3D point; + +Shapes::Composition3D composition = !(segment || point); +@endcode + +@note Logical operations are not the same as set operations -- intersection of + two spheres will not generate any collision if they are disjoint, but + logical AND will if the object collides with both of them. + +@subsection shapes-simplification Providing simplified version of shape for better performance + +If there are many shapes composed together, it might hurt performance of +collision detection, because it might be testing collision with more shapes +than necessary. It's then good to specify simplified version of such shape, +so the collision detection is done on the complex one if and only if collision +was detected with the simplified shape. It is in fact logical AND using +operator&&() - the collision is initially detected on first (simplified) shape +and then on the other: +@code +Shapes::Sphere3D sphere; +Shapes::Box3D box; +Shapes::AxisAlignedBox3D simplified; + +Shapes::Composition3D composition = simplified && (sphere || box); +@endcode + +@section shapes-collisions Detecting shape collisions + +%Shape pairs which have collision detection implemented can be tested for +collision using operator%(), for example: +@code +Shapes::Point3D point; +Shapes::Sphere3D sphere; + +bool collide = point % sphere; +@endcode + +@section shapes-scenegraph Integration with scene graph + +%Shape can be attached to object in the scene using Shapes::Shape feature and +then used for collision detection. You can also use DebugTools::ShapeRenderer +to visualize the shape for debugging purposes. +@code +Object3D object; +auto shape = Shapes::Shape(object, {{}, 23.0f}); +@endcode + +See also @ref scenegraph for introduction. + +*/ +}}} diff --git a/external/OpenGL/GL/glcorearb.h b/external/OpenGL/GL/glcorearb.h index 855606477..9274c0fb4 100644 --- a/external/OpenGL/GL/glcorearb.h +++ b/external/OpenGL/GL/glcorearb.h @@ -608,7 +608,7 @@ typedef void GLvoid; #define GL_CONTEXT_FLAGS 0x821E #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A @@ -1560,7 +1560,7 @@ typedef void GLvoid; #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 @@ -1706,9 +1706,9 @@ typedef void GLvoid; #ifndef GL_ARB_copy_buffer #define GL_COPY_READ_BUFFER_BINDING 0x8F36 -#define GL_COPY_READ_BUFFER GL_COPY_READ_BUFFER_BINDING +#define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 -#define GL_COPY_WRITE_BUFFER GL_COPY_WRITE_BUFFER_BINDING +#define GL_COPY_WRITE_BUFFER 0x8F37 #endif #ifndef GL_ARB_depth_clamp @@ -1955,9 +1955,9 @@ typedef void GLvoid; #ifndef GL_ARB_transform_feedback2 #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED GL_TRANSFORM_FEEDBACK_PAUSED +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE GL_TRANSFORM_FEEDBACK_ACTIVE +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #endif @@ -2579,8 +2579,8 @@ typedef void GLvoid; #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF -#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000 -#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 /* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */ #endif diff --git a/external/OpenGL/GLES2/gl2ext.h b/external/OpenGL/GLES2/gl2ext.h index d0827839b..162a09cfb 100644 --- a/external/OpenGL/GLES2/gl2ext.h +++ b/external/OpenGL/GLES2/gl2ext.h @@ -1,7 +1,7 @@ #ifndef __gl2ext_h_ #define __gl2ext_h_ -/* $Revision: 20800 $ on $Date:: 2013-03-07 03:33:09 -0800 #$ */ +/* $Revision: 21470 $ on $Date:: 2013-05-08 17:33:40 -0700 #$ */ #ifdef __cplusplus extern "C" { @@ -16,6 +16,20 @@ extern "C" { # define GL_APIENTRYP GL_APIENTRY* #endif +/* New types shared by several extensions */ + +#ifndef __gl3_h_ +/* These are defineed with respect to in the + * Apple extension spec, but they are also used by non-APPLE + * extensions, and in the Khronos header we use the Khronos + * portable types in khrplatform.h, which must be defined. + */ +typedef khronos_int64_t GLint64; +typedef khronos_uint64_t GLuint64; +typedef struct __GLsync *GLsync; +#endif + + /*------------------------------------------------------------------------* * OES extension tokens *------------------------------------------------------------------------*/ @@ -183,47 +197,47 @@ typedef void* GLeglImageOES; *------------------------------------------------------------------------*/ #ifndef GL_KHR_debug -typedef void (GL_APIENTRYP GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#define GL_DEBUG_SOURCE_API 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#define GL_DEBUG_SOURCE_OTHER 0x824B -#define GL_DEBUG_TYPE_ERROR 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#define GL_DEBUG_TYPE_OTHER 0x8251 -#define GL_DEBUG_TYPE_MARKER 0x8268 -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#define GL_BUFFER 0x82E0 -#define GL_SHADER 0x82E1 -#define GL_PROGRAM 0x82E2 -#define GL_QUERY 0x82E3 +typedef void (GL_APIENTRYP GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define GL_DEBUG_SOURCE_API_KHR 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define GL_BUFFER_KHR 0x82E0 +#define GL_SHADER_KHR 0x82E1 +#define GL_PROGRAM_KHR 0x82E2 +#define GL_QUERY_KHR 0x82E3 /* PROGRAM_PIPELINE only in GL */ -#define GL_SAMPLER 0x82E6 +#define GL_SAMPLER_KHR 0x82E6 /* DISPLAY_LIST only in GL */ -#define GL_MAX_LABEL_LENGTH 0x82E8 -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#define GL_DEBUG_OUTPUT 0x92E0 -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 +#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define GL_DEBUG_OUTPUT_KHR 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define GL_STACK_OVERFLOW_KHR 0x0503 +#define GL_STACK_UNDERFLOW_KHR 0x0504 #endif #ifndef GL_KHR_texture_compression_astc_ldr @@ -385,19 +399,6 @@ typedef void (GL_APIENTRYP GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLen /* GL_APPLE_sync */ #ifndef GL_APPLE_sync -#ifndef __gl3_h_ -/* These types are defined with reference to - * in the Apple extension spec, but here we use the Khronos - * portable types in khrplatform.h, and assume those types - * are always defined. - * If any other extensions using these types are defined, - * the typedefs must move out of this block and be shared. - */ -typedef khronos_int64_t GLint64; -typedef khronos_uint64_t GLuint64; -typedef struct __GLsync *GLsync; -#endif - #define GL_SYNC_OBJECT_APPLE 0x8A53 #define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111 #define GL_OBJECT_TYPE_APPLE 0x9112 @@ -483,6 +484,17 @@ typedef struct __GLsync *GLsync; #define GL_STENCIL_EXT 0x1802 #endif +#ifndef GL_EXT_disjoint_timer_query +#define GL_EXT_disjoint_timer_query 1 +#define GL_QUERY_COUNTER_BITS_EXT 0x8864 +#define GL_CURRENT_QUERY_EXT 0x8865 +#define GL_QUERY_RESULT_EXT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 +#define GL_TIME_ELAPSED_EXT 0x88BF +#define GL_TIMESTAMP_EXT 0x8E28 +#define GL_GPU_DISJOINT_EXT 0x8FBB +#endif + /* GL_EXT_map_buffer_range */ #ifndef GL_EXT_map_buffer_range #define GL_MAP_READ_BIT_EXT 0x0001 @@ -1145,29 +1157,29 @@ typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); #ifndef GL_KHR_debug #define GL_KHR_debug 1 #ifdef GL_GLEXT_PROTOTYPES -GL_APICALL void GL_APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GL_APICALL void GL_APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GL_APICALL void GL_APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); -GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -GL_APICALL void GL_APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); -GL_APICALL void GL_APIENTRY glPopDebugGroup (void); -GL_APICALL void GL_APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -GL_APICALL void GL_APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -GL_APICALL void GL_APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); -GL_APICALL void GL_APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); -GL_APICALL void GL_APIENTRY glGetPointerv (GLenum pname, void **params); -#endif -typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); -typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); -typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); -typedef void (GL_APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); -typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); -typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); -typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); -typedef void (GL_APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params); +GL_APICALL void GL_APIENTRY glDebugMessageControlKHR (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GL_APICALL void GL_APIENTRY glDebugMessageInsertKHR (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GL_APICALL void GL_APIENTRY glDebugMessageCallbackKHR (GLDEBUGPROCKHR callback, const void *userParam); +GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLogKHR (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GL_APICALL void GL_APIENTRY glPushDebugGroupKHR (GLenum source, GLuint id, GLsizei length, const GLchar *message); +GL_APICALL void GL_APIENTRY glPopDebugGroupKHR (void); +GL_APICALL void GL_APIENTRY glObjectLabelKHR (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GL_APICALL void GL_APIENTRY glGetObjectLabelKHR (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GL_APICALL void GL_APIENTRY glObjectPtrLabelKHR (const void *ptr, GLsizei length, const GLchar *label); +GL_APICALL void GL_APIENTRY glGetObjectPtrLabelKHR (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +GL_APICALL void GL_APIENTRY glGetPointervKHR (GLenum pname, void **params); +#endif +typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC) (GLDEBUGPROCKHR callback, const void *userParam); +typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC) (void); +typedef void (GL_APIENTRYP PFNGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (GL_APIENTRYP PFNGLGETPOINTERVKHRPROC) (GLenum pname, void **params); #endif #ifndef GL_KHR_texture_compression_astc_ldr @@ -1421,6 +1433,34 @@ GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numA typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); #endif +#ifndef GL_EXT_disjoint_timer_query +#define GL_EXT_disjoint_timer_query 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids); +GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids); +GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id); +GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id); +GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target); +GL_APICALL void GL_APIENTRY glQueryCounterEXT (GLuint id, GLenum target); +GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectivEXT (GLuint id, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64EXT *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64EXT *params); +#endif +typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids); +typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id); +typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id); +typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target); +typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params); +#endif /* GL_EXT_disjoint_timer_query */ + /* GL_EXT_map_buffer_range */ #ifndef GL_EXT_map_buffer_range #define GL_EXT_map_buffer_range 1 diff --git a/modules/FindCorrade.cmake b/modules/FindCorrade.cmake index d205b4989..7f9d4a247 100644 --- a/modules/FindCorrade.cmake +++ b/modules/FindCorrade.cmake @@ -32,6 +32,7 @@ # Native Client with `newlib` toolchain # CORRADE_TARGET_NACL_GLIBC - Defined if compiled for Google Chrome # Native Client with `glibc` toolchain +# CORRADE_TARGET_EMSCRIPTEN - Defined if compiled for Emscripten # # Corrade provides these macros and functions: # @@ -184,6 +185,10 @@ string(FIND "${_corradeConfigure}" "#define CORRADE_TARGET_NACL_GLIBC" _TARGET_N if(NOT _TARGET_NACL_GLIBC EQUAL -1) set(CORRADE_TARGET_NACL_GLIBC 1) endif() +string(FIND "${_corradeConfigure}" "#define CORRADE_TARGET_EMSCRIPTEN" _TARGET_EMSCRIPTEN) +if(NOT _TARGET_EMSCRIPTEN EQUAL -1) + set(CORRADE_TARGET_EMSCRIPTEN 1) +endif() set(CORRADE_UTILITY_LIBRARIES ${CORRADE_UTILITY_LIBRARY}) set(CORRADE_INTERCONNECT_LIBRARIES ${CORRADE_INTERCONNECT_LIBRARY} ${CORRADE_UTILITY_LIBRARIES}) diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 3050a3ebc..7c871037a 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -14,13 +14,13 @@ # components. The base library depends on Corrade, OpenGL and GLEW # libraries. Additional dependencies are specified by the components. The # optional components are: -# DebugTools - DebugTools library (depends on MeshTools, Physics, -# Primitives, SceneGraph and Shaders components) +# DebugTools - DebugTools library (depends on MeshTools, Primitives, +# SceneGraph, Shaders and Shapes components) # MeshTools - MeshTools library -# Physics - Physics library (depends on SceneGraph component) # Primitives - Primitives library # SceneGraph - SceneGraph library # Shaders - Shaders library +# Shapes - Shapes library (depends on SceneGraph component) # Text - Text library (depends on TextureTools component) # TextureTools - TextureTools library # GlutApplication - GLUT application (depends on GLUT library) @@ -224,7 +224,7 @@ foreach(component ${Magnum_FIND_COMPONENTS}) # DebugTools library if(${component} STREQUAL DebugTools) - set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Profiler.h) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES DebugTools.h) endif() # Mesh tools library @@ -232,11 +232,6 @@ foreach(component ${Magnum_FIND_COMPONENTS}) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES CompressIndices.h) endif() - # Physics library - if(${component} STREQUAL Physics) - set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES AbstractShape.h) - endif() - # Primitives library if(${component} STREQUAL Primitives) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Cube.h) @@ -244,17 +239,22 @@ foreach(component ${Magnum_FIND_COMPONENTS}) # Scene graph library if(${component} STREQUAL SceneGraph) - set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Scene.h) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES SceneGraph.h) endif() # Shaders library if(${component} STREQUAL Shaders) - set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongShader.h) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Shaders.h) + endif() + + # Shapes library + if(${component} STREQUAL Shapes) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Shapes.h) endif() # Text library if(${component} STREQUAL Text) - set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES AbstractFont.h) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Text.h) endif() # TextureTools library diff --git a/modules/FindNodeJs.cmake b/modules/FindNodeJs.cmake new file mode 100644 index 000000000..90f7ebf21 --- /dev/null +++ b/modules/FindNodeJs.cmake @@ -0,0 +1,37 @@ +# - Find Node.js +# +# This module defines: +# +# NODEJS_FOUND - True if Node.js executable is found +# NODEJS_EXECUTABLE - Node.js executable +# + +# +# This file is part of Corrade. +# +# Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013 +# Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +find_program(NODEJS_EXECUTABLE node) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args("NodeJs" DEFAULT_MSG NODEJS_EXECUTABLE) diff --git a/modules/FindOpenGLES2.cmake b/modules/FindOpenGLES2.cmake index 3bc3865a3..ab7a9e11f 100644 --- a/modules/FindOpenGLES2.cmake +++ b/modules/FindOpenGLES2.cmake @@ -31,10 +31,14 @@ # DEALINGS IN THE SOFTWARE. # -# Library -find_library(OPENGLES2_LIBRARY NAMES - GLESv2 - ppapi_gles2) # NaCl +# In Emscripten OpenGL ES 2 is linked automatically, thus no need to find the +# library. +if(NOT CORRADE_TARGET_EMSCRIPTEN) + find_library(OPENGLES2_LIBRARY NAMES + GLESv2 + ppapi_gles2) # NaCl + set(OPENGLES2_LIBRARY_NEEDED OPENGLES2_LIBRARY) +endif() # Include dir find_path(OPENGLES2_INCLUDE_DIR @@ -44,6 +48,6 @@ find_path(OPENGLES2_INCLUDE_DIR include(FindPackageHandleStandardArgs) find_package_handle_standard_args("OpenGLES2" DEFAULT_MSG - OPENGLES2_LIBRARY + ${OPENGLES2_LIBRARY_NEEDED} OPENGLES2_INCLUDE_DIR ) diff --git a/modules/FindSDL2.cmake b/modules/FindSDL2.cmake index f352a7b58..68ef7ae0f 100644 --- a/modules/FindSDL2.cmake +++ b/modules/FindSDL2.cmake @@ -31,17 +31,24 @@ # DEALINGS IN THE SOFTWARE. # -# Library -find_library(SDL2_LIBRARY SDL2) +# In Emscripten SDL is linked automatically, thus no need to find the library. +# Also the includes are in SDL subdirectory, not SDL2. +if(CORRADE_TARGET_EMSCRIPTEN) + set(PATH_SUFFIXES SDL) +else() + find_library(SDL2_LIBRARY SDL2) + set(SDL2_LIBRARY_NEEDED SDL2_LIBRARY) + set(PATH_SUFFIXES SDL2) +endif() # Include dir find_path(SDL2_INCLUDE_DIR NAMES SDL.h SDL_scancode.h - PATH_SUFFIXES SDL2 + PATH_SUFFIXES ${PATH_SUFFIXES} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args("SDL2" DEFAULT_MSG - SDL2_LIBRARY + ${SDL2_LIBRARY_NEEDED} SDL2_INCLUDE_DIR ) diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index 7c353bcbd..bc9b20eb5 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -34,32 +34,33 @@ namespace Magnum { -#ifndef DOXYGEN_GENERATING_OUTPUT +AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault; + AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; -AbstractFramebuffer::Target AbstractFramebuffer::readTarget = AbstractFramebuffer::Target::ReadDraw; -AbstractFramebuffer::Target AbstractFramebuffer::drawTarget = AbstractFramebuffer::Target::ReadDraw; -#endif +FramebufferTarget AbstractFramebuffer::readTarget = FramebufferTarget::ReadDraw; +FramebufferTarget AbstractFramebuffer::drawTarget = FramebufferTarget::ReadDraw; + +AbstractFramebuffer::~AbstractFramebuffer() {} -void AbstractFramebuffer::bind(Target target) { +void AbstractFramebuffer::bind(FramebufferTarget target) { bindInternal(target); setViewportInternal(); } -#ifndef DOXYGEN_GENERATING_OUTPUT -void AbstractFramebuffer::bindInternal(Target target) { +void AbstractFramebuffer::bindInternal(FramebufferTarget target) { Implementation::FramebufferState* state = Context::current()->state()->framebuffer; /* If already bound, done, otherwise update tracked state */ - if(target == Target::Read) { + if(target == FramebufferTarget::Read) { if(state->readBinding == _id) return; state->readBinding = _id; - } else if(target == Target::Draw) { + } else if(target == FramebufferTarget::Draw) { if(state->drawBinding == _id) return; state->drawBinding = _id; - } else if(target == Target::ReadDraw) { + } else if(target == FramebufferTarget::ReadDraw) { if(state->readBinding == _id && state->drawBinding == _id) return; state->readBinding = state->drawBinding = _id; } else CORRADE_ASSERT_UNREACHABLE(); @@ -67,29 +68,28 @@ void AbstractFramebuffer::bindInternal(Target target) { glBindFramebuffer(static_cast(target), _id); } -AbstractFramebuffer::Target AbstractFramebuffer::bindInternal() { +FramebufferTarget AbstractFramebuffer::bindInternal() { Implementation::FramebufferState* state = Context::current()->state()->framebuffer; /* Return target to which the framebuffer is already bound */ if(state->readBinding == _id && state->drawBinding == _id) - return Target::ReadDraw; + return FramebufferTarget::ReadDraw; if(state->readBinding == _id) - return Target::Read; + return FramebufferTarget::Read; if(state->drawBinding == _id) - return Target::Draw; + return FramebufferTarget::Draw; /* Or bind it, if not already */ state->readBinding = _id; - if(readTarget == Target::ReadDraw) state->drawBinding = _id; + if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; glBindFramebuffer(GLenum(readTarget), _id); return readTarget; } -#endif -void AbstractFramebuffer::blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, AbstractFramebuffer::BlitMask mask, AbstractFramebuffer::BlitFilter filter) { - source.bindInternal(AbstractFramebuffer::Target::Read); - destination.bindInternal(AbstractFramebuffer::Target::Draw); +void AbstractFramebuffer::blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, FramebufferBlitMask mask, FramebufferBlitFilter filter) { + source.bindInternal(FramebufferTarget::Read); + destination.bindInternal(FramebufferTarget::Draw); /** @todo Get some extension wrangler instead to avoid undeclared glBlitFramebuffer() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glBlitFramebuffer(sourceRectangle.left(), sourceRectangle.bottom(), sourceRectangle.right(), sourceRectangle.top(), destinationRectangle.left(), destinationRectangle.bottom(), destinationRectangle.right(), destinationRectangle.top(), static_cast(mask), static_cast(filter)); @@ -111,7 +111,6 @@ AbstractFramebuffer* AbstractFramebuffer::setViewport(const Rectanglei& rectangl return this; } -#ifndef DOXYGEN_GENERATING_OUTPUT void AbstractFramebuffer::setViewportInternal() { Implementation::FramebufferState* state = Context::current()->state()->framebuffer; @@ -125,34 +124,34 @@ void AbstractFramebuffer::setViewportInternal() { state->viewport = _viewport; glViewport(_viewport.left(), _viewport.bottom(), _viewport.width(), _viewport.height()); } -#endif -void AbstractFramebuffer::clear(ClearMask mask) { +void AbstractFramebuffer::clear(FramebufferClearMask mask) { bindInternal(drawTarget); glClear(static_cast(mask)); } -void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image) { +void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Image2D* image) { bindInternal(readTarget); - char* data = new char[AbstractImage::pixelSize(format, type)*size.product()]; - glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); - image->setData(size, format, type, data); + const std::size_t dataSize = image->pixelSize()*size.product(); + char* const data = new char[dataSize]; + readImplementation(offset, size, image->format(), image->type(), dataSize, data); + image->setData(size, image->format(), image->type(), data); } #ifndef MAGNUM_TARGET_GLES2 -void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage) { +void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, BufferImage2D* image, Buffer::Usage usage) { bindInternal(readTarget); /* If the buffer doesn't have sufficient size, resize it */ /** @todo Explicitly reset also when buffer usage changes */ - if(image->size() != size || image->format() != format || image->type() != type) - image->setData(size, format, type, nullptr, usage); + if(image->size() != size) + image->setData(size, image->format(), image->type(), nullptr, usage); image->buffer()->bind(Buffer::Target::PixelPack); - glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), nullptr); + /** @todo De-duplicate buffer size computation */ + readImplementation(offset, size, image->format(), image->type(), image->pixelSize()*size.product(), nullptr); } #endif -#ifndef DOXYGEN_GENERATING_OUTPUT void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attachments) { /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -175,15 +174,14 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach static_cast(rectangle); #endif } -#endif void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) { #ifndef MAGNUM_TARGET_GLES if(context->isExtensionSupported()) { Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::framebuffer_blit::string() << "features"; - readTarget = Target::Read; - drawTarget = Target::Draw; + readTarget = FramebufferTarget::Read; + drawTarget = FramebufferTarget::Draw; } if(context->isExtensionSupported()) { @@ -193,6 +191,26 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; } + #endif + + #ifndef MAGNUM_TARGET_GLES3 + #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 + + /** @todo Enable when extension wrangler for ES is available */ + #ifndef MAGNUM_TARGET_GLES + readImplementation = &AbstractFramebuffer::readImplementationRobustness; + #endif + } #else static_cast(context); #endif @@ -251,4 +269,26 @@ void AbstractFramebuffer::readBufferImplementationDSA(GLenum buffer) { } #endif +void AbstractFramebuffer::readImplementationDefault(const Vector2i& offset, const Vector2i& size, const ImageFormat format, const ImageType type, const std::size_t, GLvoid* const data) { + glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); +} + +#ifndef MAGNUM_TARGET_GLES3 +void AbstractFramebuffer::readImplementationRobustness(const Vector2i& offset, const Vector2i& size, const ImageFormat format, const ImageType type, const std::size_t dataSize, GLvoid* const data) { + /** @todo Enable when extension wrangler for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glReadnPixelsARB(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), dataSize, data); + #else + CORRADE_INTERNAL_ASSERT(false); + //glReadnPixelsEXT(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); + static_cast(offset); + static_cast(size); + static_cast(format); + static_cast(type); + static_cast(dataSize); + static_cast(data); + #endif +} +#endif + } diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index 1bf676428..e64fdfa72 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -31,22 +31,111 @@ #include #include "Math/Geometry/Rectangle.h" -#include "AbstractImage.h" #include "Buffer.h" namespace Magnum { +/** + * @brief Mask for framebuffer clearing + * + * @see AbstractFramebuffer, FramebufferClearMask + */ +enum class FramebufferClear: GLbitfield { + Color = GL_COLOR_BUFFER_BIT, /**< Color */ + Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ + Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ +}; + +/** + * @brief Mask for clearing + * + * @see AbstractFramebuffer::clear() + */ +typedef Containers::EnumSet FramebufferClearMask; + +/** + * @brief Mask for framebuffer blitting + * + * @see AbstractFramebuffer, FramebufferBlitMask + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + * @es_extension{NV,framebuffer_blit} + */ +enum class FramebufferBlit: GLbitfield { + ColorBuffer = GL_COLOR_BUFFER_BIT, /**< Color buffer */ + DepthBuffer = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */ + StencilBuffer = GL_STENCIL_BUFFER_BIT /**< Stencil buffer */ +}; + +/** + * @brief Mask for framebuffer blitting + * + * @see AbstractFramebuffer::blit() + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + * @es_extension{NV,framebuffer_blit} + */ +typedef Containers::EnumSet FramebufferBlitMask; + +/** + * @brief %Framebuffer blit filtering + * + * @see AbstractFramebuffer::blit() + */ +enum class FramebufferBlitFilter: GLenum { + Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ + Linear = GL_LINEAR /**< Linear interpolation filtering */ +}; + +/** + * @brief Target for binding framebuffer + * + * @see DefaultFramebuffer::bind(), Framebuffer::bind() + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + */ +enum class FramebufferTarget: GLenum { + /** + * For reading only. + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, + * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} + */ + #ifndef MAGNUM_TARGET_GLES2 + Read = GL_READ_FRAMEBUFFER, + #else + Read = GL_READ_FRAMEBUFFER_APPLE, + #endif + + /** + * For drawing only. + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, + * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} + */ + #ifndef MAGNUM_TARGET_GLES2 + Draw = GL_DRAW_FRAMEBUFFER, + #else + Draw = GL_DRAW_FRAMEBUFFER_APPLE, + #endif + + ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */ +}; + /** @brief Base for default and named framebuffers See DefaultFramebuffer and Framebuffer for more information. -@section AbstractFramebuffer-performance-optimization Performance optimizations +@section AbstractFramebuffer-performance-optimization Performance optimizations and security The engine tracks currently bound framebuffer and current viewport to avoid unnecessary calls to @fn_gl{BindFramebuffer} and @fn_gl{Viewport} when switching framebuffers. +If @extension{ARB,robustness} is available, read() operations are protected +from buffer overflow. @todo @extension{ARB,viewport_array} */ class MAGNUM_EXPORT AbstractFramebuffer { @@ -58,94 +147,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { AbstractFramebuffer& operator=(AbstractFramebuffer&&) = delete; public: - /** - * @brief Mask for clearing - * - * @see ClearMask - */ - enum class Clear: GLbitfield { - Color = GL_COLOR_BUFFER_BIT, /**< Color */ - Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ - Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ - }; - - /** - * @brief Mask for clearing - * - * @see clear() - */ - typedef Corrade::Containers::EnumSet ClearMask; - - /** - * @brief Mask for blitting - * - * @see BlitMask - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or - * @es_extension{NV,framebuffer_blit} - */ - enum class Blit: GLbitfield { - ColorBuffer = GL_COLOR_BUFFER_BIT, /**< Color buffer */ - DepthBuffer = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */ - StencilBuffer = GL_STENCIL_BUFFER_BIT /**< Stencil buffer */ - }; - - /** - * @brief Mask for blitting - * - * @see blit() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or - * @es_extension{NV,framebuffer_blit} - */ - typedef Corrade::Containers::EnumSet BlitMask; - - /** - * @brief Blit filtering - * - * @see blit() - */ - enum class BlitFilter: GLenum { - Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ - Linear = GL_LINEAR /**< Linear interpolation filtering */ - }; - - /** - * @brief Target for binding framebuffer - * - * @see DefaultFramebuffer::bind(), Framebuffer::bind() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - */ - enum class Target: GLenum { - /** - * For reading only. - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, - * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} - */ - #ifndef MAGNUM_TARGET_GLES2 - Read = GL_READ_FRAMEBUFFER, - #else - Read = GL_READ_FRAMEBUFFER_APPLE, - #endif - - /** - * For drawing only. - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, - * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} - */ - #ifndef MAGNUM_TARGET_GLES2 - Draw = GL_DRAW_FRAMEBUFFER, - #else - Draw = GL_DRAW_FRAMEBUFFER_APPLE, - #endif - - ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */ - }; - /** * @brief Copy block of pixels * @param source Source framebuffer @@ -155,9 +156,9 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @param mask Which buffers to perform blit operation on * @param filter Interpolation filter * - * Binds @p source framebuffer to @ref Target "Target::Read" and - * @p destination framebuffer to @ref Target "Target::Draw" and - * performs blitting operation. See DefaultFramebuffer::mapForRead(), + * Binds @p source framebuffer to @ref FramebufferTarget "FramebufferTarget::Read" + * and @p destination framebuffer to @ref FramebufferTarget "FramebufferTarget::Draw" + * and performs blitting operation. See DefaultFramebuffer::mapForRead(), * Framebuffer::mapForRead(), DefaultFramebuffer::mapForDraw() and * Framebuffer::mapForDraw() for specifying particular buffers for * blitting operation. @@ -166,7 +167,7 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or * @es_extension{NV,framebuffer_blit} */ - static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, BlitMask mask, BlitFilter filter); + static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, FramebufferBlitMask mask, FramebufferBlitFilter filter); /** * @brief Copy block of pixels @@ -178,14 +179,15 @@ class MAGNUM_EXPORT AbstractFramebuffer { * Convenience alternative to above function when source rectangle is * the same as destination rectangle. As the image is copied * pixel-by-pixel, no interpolation is needed and thus - * @ref BlitFilter "BlitFilter::Nearest" filtering is used by default. + * @ref FramebufferBlitFilter "FramebufferBlitFilter::Nearest" + * filtering is used by default. * @see @fn_gl{BlitFramebuffer} * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or * @es_extension{NV,framebuffer_blit} */ - inline static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& rectangle, BlitMask mask) { - blit(source, destination, rectangle, rectangle, mask, BlitFilter::Nearest); + static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& rectangle, FramebufferBlitMask mask) { + blit(source, destination, rectangle, rectangle, mask, FramebufferBlitFilter::Nearest); } explicit AbstractFramebuffer(); @@ -200,10 +202,10 @@ class MAGNUM_EXPORT AbstractFramebuffer { * Framebuffer::mapForDraw(), @fn_gl{BindFramebuffer}, * @fn_gl{Viewport} */ - void bind(Target target); + void bind(FramebufferTarget target); /** @brief Viewport rectangle */ - inline Rectanglei viewport() const { return _viewport; } + Rectanglei viewport() const { return _viewport; } /** * @brief Set viewport @@ -228,46 +230,50 @@ class MAGNUM_EXPORT AbstractFramebuffer { * Renderer::setClearStencil(), @fn_gl{BindFramebuffer}, * @fn_gl{Clear} */ - void clear(ClearMask mask); + void clear(FramebufferClearMask mask); /** * @brief Read block of pixels from framebuffer to image * @param offset Offset in the framebuffer * @param size %Image size - * @param format Format of pixel data - * @param type Data type of pixel data * @param image %Image where to put the data * - * @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels} - * @todo Read size, format & type from image? + * %Image parameters like format and type of pixel data are taken from + * given image. + * + * If @extension{ARB,robustness} is available, the operation is + * protected from buffer overflow. + * @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels} or + * @fn_gl_extension{ReadnPixels,ARB,robustness} */ - void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image); + void read(const Vector2i& offset, const Vector2i& size, Image2D* image); #ifndef MAGNUM_TARGET_GLES2 /** * @brief Read block of pixels from framebuffer to buffer image * @param offset Offset in the framebuffer * @param size %Image size - * @param format Format of pixel data - * @param type Data type of pixel data * @param image %Buffer image where to put the data * @param usage %Buffer usage * - * @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels} + * See read(const Vector2i&, const Vector2i&, Image2D*) for more + * information. * @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. - * @todo Read size, format & type from image? */ - void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage); + void read(const Vector2i& offset, const Vector2i& size, BufferImage2D* image, Buffer::Usage usage); #endif - #ifndef DOXYGEN_GENERATING_OUTPUT + #ifdef DOXYGEN_GENERATING_OUTPUT + private: + #else protected: - void MAGNUM_LOCAL bindInternal(Target target); - Target MAGNUM_LOCAL bindInternal(); + #endif + void MAGNUM_LOCAL bindInternal(FramebufferTarget target); + FramebufferTarget MAGNUM_LOCAL bindInternal(); void MAGNUM_LOCAL setViewportInternal(); - static MAGNUM_LOCAL Target readTarget; - static MAGNUM_LOCAL Target drawTarget; + static MAGNUM_LOCAL FramebufferTarget readTarget; + static MAGNUM_LOCAL FramebufferTarget drawTarget; typedef void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*); static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation; @@ -283,7 +289,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { GLuint _id; Rectanglei _viewport; - #endif private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); @@ -302,13 +307,19 @@ class MAGNUM_EXPORT AbstractFramebuffer { #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL readBufferImplementationDSA(GLenum buffer); #endif + + typedef void(*ReadImplementation)(const Vector2i&, const Vector2i&, ImageFormat, ImageType, std::size_t, GLvoid*); + static void MAGNUM_LOCAL readImplementationDefault(const Vector2i& offset, const Vector2i& size, ImageFormat format, ImageType type, std::size_t dataSize, GLvoid* data); + #ifndef MAGNUM_TARGET_GLES3 + static void MAGNUM_LOCAL readImplementationRobustness(const Vector2i& offset, const Vector2i& size, ImageFormat format, ImageType type, std::size_t dataSize, GLvoid* data); + #endif + static ReadImplementation MAGNUM_LOCAL readImplementation; }; inline AbstractFramebuffer::AbstractFramebuffer() = default; -inline AbstractFramebuffer::~AbstractFramebuffer() {} -CORRADE_ENUMSET_OPERATORS(AbstractFramebuffer::ClearMask) -CORRADE_ENUMSET_OPERATORS(AbstractFramebuffer::BlitMask) +CORRADE_ENUMSET_OPERATORS(FramebufferClearMask) +CORRADE_ENUMSET_OPERATORS(FramebufferBlitMask) } diff --git a/src/AbstractImage.cpp b/src/AbstractImage.cpp index 761f15dd8..253f2ec37 100644 --- a/src/AbstractImage.cpp +++ b/src/AbstractImage.cpp @@ -26,109 +26,113 @@ #include +#include "ImageFormat.h" + namespace Magnum { -std::size_t AbstractImage::pixelSize(Format format, Type type) { +AbstractImage::~AbstractImage() {} + +std::size_t AbstractImage::pixelSize(ImageFormat format, ImageType type) { std::size_t size = 0; switch(type) { - case Type::UnsignedByte: + case ImageType::UnsignedByte: #ifndef MAGNUM_TARGET_GLES2 - case Type::Byte: + case ImageType::Byte: #endif size = 1; break; - case Type::UnsignedShort: + case ImageType::UnsignedShort: #ifndef MAGNUM_TARGET_GLES2 - case Type::Short: + case ImageType::Short: #endif - case Type::HalfFloat: + case ImageType::HalfFloat: size = 2; break; - case Type::UnsignedInt: + case ImageType::UnsignedInt: #ifndef MAGNUM_TARGET_GLES2 - case Type::Int: + case ImageType::Int: #endif - case Type::Float: + case ImageType::Float: size = 4; break; #ifndef MAGNUM_TARGET_GLES - case Type::UnsignedByte332: - case Type::UnsignedByte233Rev: + case ImageType::UnsignedByte332: + case ImageType::UnsignedByte233Rev: return 1; #endif - case Type::UnsignedShort565: + case ImageType::UnsignedShort565: #ifndef MAGNUM_TARGET_GLES - case Type::UnsignedShort565Rev: + case ImageType::UnsignedShort565Rev: #endif - case Type::UnsignedShort4444: + case ImageType::UnsignedShort4444: #ifndef MAGNUM_TARGET_GLES3 - case Type::UnsignedShort4444Rev: + case ImageType::UnsignedShort4444Rev: #endif - case Type::UnsignedShort5551: + case ImageType::UnsignedShort5551: #ifndef MAGNUM_TARGET_GLES3 - case Type::UnsignedShort1555Rev: + case ImageType::UnsignedShort1555Rev: #endif return 2; #ifndef MAGNUM_TARGET_GLES - case Type::UnsignedInt8888: - case Type::UnsignedInt8888Rev: - case Type::UnsignedInt1010102: + case ImageType::UnsignedInt8888: + case ImageType::UnsignedInt8888Rev: + case ImageType::UnsignedInt1010102: #endif - case Type::UnsignedInt2101010Rev: + case ImageType::UnsignedInt2101010Rev: #ifndef MAGNUM_TARGET_GLES2 - case Type::UnsignedInt10F11F11FRev: - case Type::UnsignedInt5999Rev: + case ImageType::UnsignedInt10F11F11FRev: + case ImageType::UnsignedInt5999Rev: #endif - case Type::UnsignedInt248: + case ImageType::UnsignedInt248: return 4; #ifndef MAGNUM_TARGET_GLES2 - case Type::Float32UnsignedInt248Rev: + case ImageType::Float32UnsignedInt248Rev: return 8; #endif } switch(format) { - case Format::Red: + case ImageFormat::Red: #ifndef MAGNUM_TARGET_GLES2 - case Format::RedInteger: + case ImageFormat::RedInteger: #endif #ifndef MAGNUM_TARGET_GLES - case Format::Green: - case Format::Blue: - case Format::GreenInteger: - case Format::BlueInteger: + case ImageFormat::Green: + case ImageFormat::Blue: + case ImageFormat::GreenInteger: + case ImageFormat::BlueInteger: #endif return 1*size; - case Format::RG: + case ImageFormat::RG: #ifndef MAGNUM_TARGET_GLES2 - case Format::RGInteger: + case ImageFormat::RGInteger: #endif return 2*size; - case Format::RGB: + case ImageFormat::RGB: #ifndef MAGNUM_TARGET_GLES2 - case Format::RGBInteger: + case ImageFormat::RGBInteger: #endif #ifndef MAGNUM_TARGET_GLES - case Format::BGR: - case Format::BGRInteger: + case ImageFormat::BGR: + case ImageFormat::BGRInteger: #endif return 3*size; - case Format::RGBA: + case ImageFormat::RGBA: #ifndef MAGNUM_TARGET_GLES2 - case Format::RGBAInteger: + case ImageFormat::RGBAInteger: #endif #ifndef MAGNUM_TARGET_GLES3 - case Format::BGRA: + case ImageFormat::BGRA: #endif #ifndef MAGNUM_TARGET_GLES - case Format::BGRAInteger: + case ImageFormat::BGRAInteger: #endif return 4*size; /* Handled above */ - case Format::DepthComponent: + case ImageFormat::DepthComponent: #ifndef MAGNUM_TARGET_GLES3 - case Format::StencilIndex: + case ImageFormat::StencilIndex: #endif - case Format::DepthStencil: + case ImageFormat::DepthStencil: CORRADE_ASSERT_UNREACHABLE(); } @@ -136,101 +140,4 @@ std::size_t AbstractImage::pixelSize(Format format, Type type) { return 0; } -#ifndef DOXYGEN_GENERATING_OUTPUT -Debug operator<<(Debug debug, AbstractImage::Format value) { - switch(value) { - #define _c(value) case AbstractImage::Format::value: return debug << "AbstractImage::Format::" #value; - _c(Red) - #ifndef MAGNUM_TARGET_GLES - _c(Green) - _c(Blue) - #endif - _c(RG) - _c(RGB) - _c(RGBA) - #ifndef MAGNUM_TARGET_GLES - _c(BGR) - #endif - #ifndef MAGNUM_TARGET_GLES3 - _c(BGRA) - #endif - #ifndef MAGNUM_TARGET_GLES2 - _c(RedInteger) - #ifndef MAGNUM_TARGET_GLES - _c(GreenInteger) - _c(BlueInteger) - #endif - _c(RGInteger) - _c(RGBInteger) - _c(RGBAInteger) - #ifndef MAGNUM_TARGET_GLES - _c(BGRInteger) - _c(BGRAInteger) - #endif - #endif - _c(DepthComponent) - #ifndef MAGNUM_TARGET_GLES3 - _c(StencilIndex) - #endif - _c(DepthStencil) - #undef _c - } - - return debug << "AbstractImage::Format::(invalid)"; -} - -Debug operator<<(Debug debug, AbstractImage::Type value) { - switch(value) { - #define _c(value) case AbstractImage::Type::value: return debug << "AbstractImage::Type::" #value; - _c(UnsignedByte) - #ifndef MAGNUM_TARGET_GLES2 - _c(Byte) - #endif - _c(UnsignedShort) - #ifndef MAGNUM_TARGET_GLES2 - _c(Short) - #endif - _c(UnsignedInt) - #ifndef MAGNUM_TARGET_GLES2 - _c(Int) - #endif - _c(HalfFloat) - _c(Float) - #ifndef MAGNUM_TARGET_GLES - _c(UnsignedByte332) - _c(UnsignedByte233Rev) - #endif - _c(UnsignedShort565) - #ifndef MAGNUM_TARGET_GLES - _c(UnsignedShort565Rev) - #endif - _c(UnsignedShort4444) - #ifndef MAGNUM_TARGET_GLES3 - _c(UnsignedShort4444Rev) - #endif - _c(UnsignedShort5551) - #ifndef MAGNUM_TARGET_GLES3 - _c(UnsignedShort1555Rev) - #endif - #ifndef MAGNUM_TARGET_GLES - _c(UnsignedInt8888) - _c(UnsignedInt8888Rev) - _c(UnsignedInt1010102) - #endif - _c(UnsignedInt2101010Rev) - #ifndef MAGNUM_TARGET_GLES2 - _c(UnsignedInt10F11F11FRev) - _c(UnsignedInt5999Rev) - #endif - _c(UnsignedInt248) - #ifndef MAGNUM_TARGET_GLES2 - _c(Float32UnsignedInt248Rev) - #endif - #undef _c - } - - return debug << "AbstractImage::Type::(invalid)"; -} -#endif - } diff --git a/src/AbstractImage.h b/src/AbstractImage.h index 5ba4002c6..aef3c71ec 100644 --- a/src/AbstractImage.h +++ b/src/AbstractImage.h @@ -31,7 +31,6 @@ #include #include "Magnum.h" -#include "OpenGL.h" #include "magnumVisibility.h" namespace Magnum { @@ -53,480 +52,47 @@ class MAGNUM_EXPORT AbstractImage { AbstractImage& operator=(AbstractImage&&) = delete; public: - /** - * @{ @name Image formats - * - * Note that some formats can be used only for framebuffer reading - * (using Framebuffer::read()) and some only for texture data (using - * Texture::setImage() and others). - */ - - /** - * @brief Format of pixel data - * - * @see pixelSize() - */ - enum class Format: 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}. - */ - #ifndef MAGNUM_TARGET_GLES2 - Red = GL_RED, - #else - Red = GL_RED_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Floating-point green channel. - * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::Red" - * is available in OpenGL ES. - */ - Green = GL_GREEN, - - /** - * Floating-point blue channel. - * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::Red" - * is available in OpenGL ES. - */ - Blue = GL_BLUE, - - /** @todo GL_ALPHA? */ - #endif - - /** - * 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_es_extension For framebuffer reading, extension - * @es_extension{EXT,texture_rg}. - */ - #ifndef MAGNUM_TARGET_GLES2 - RG = GL_RG, - #else - RG = GL_RG_EXT, - #endif - - /** - * Floating-point RGB. - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - */ - RGB = GL_RGB, - - /** Floating-point RGBA. */ - RGBA = GL_RGBA, - - #ifndef MAGNUM_TARGET_GLES - /** - * Floating-point BGR. - * @requires_gl Only RGB component ordering is available in OpenGL - * ES. - */ - BGR = GL_BGR, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * Floating-point BGRA. - * @requires_es_extension %Extension @es_extension{EXT,read_format_bgra} - * for framebuffer reading, extension @es_extension{APPLE,texture_format_BGRA8888} - * or @es_extension{EXT,texture_format_BGRA8888} for texture - * data. - */ - #ifndef MAGNUM_TARGET_GLES - BGRA = GL_BGRA, - #else - BGRA = GL_BGRA_EXT, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Integer red channel. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only floating-point image data are available - * in OpenGL ES 2.0. - */ - RedInteger = GL_RED_INTEGER, - - #ifndef MAGNUM_TARGET_GLES - /** - * Integer green channel. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::RedInteger" - * is available in OpenGL ES 3.0, only floating-point image - * data are available in OpenGL ES 2.0. - */ - GreenInteger = GL_GREEN_INTEGER, - - /** - * Integer blue channel. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::RedInteger" - * is available in OpenGL ES 3.0, only floating-point image - * data are available in OpenGL ES 2.0. - */ - BlueInteger = GL_BLUE_INTEGER, - #endif - - /** - * Integer red and green channel. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - * @requires_gles30 For texture data only, only floating-point image - * data are available in OpenGL ES 2.0. - */ - RGInteger = GL_RG_INTEGER, - - /** - * Integer RGB. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - * @requires_gles30 For texture data only, only floating-point image - * data are available in OpenGL ES 2.0. - */ - RGBInteger = GL_RGB_INTEGER, - - /** - * Integer RGBA. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only floating-point image data are available - * in OpenGL ES 2.0. - */ - RGBAInteger = GL_RGBA_INTEGER, - - #ifndef MAGNUM_TARGET_GLES - /** - * Integer BGR. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::RGBInteger" - * is available in OpenGL ES 3.0, only floating-point image - * data are available in OpenGL ES 2.0. - */ - BGRInteger = GL_BGR_INTEGER, - - /** - * Integer BGRA. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::RGBAInteger" - * is available in OpenGL ES 3.0, only floating-point image - * data are available in OpenGL ES 2.0. - */ - BGRAInteger = GL_BGRA_INTEGER, - #endif - #endif - - /** - * Depth component. - * @requires_gles30 For texture data only, extension - * @es_extension{ANGLE,depth_texture}. - * @requires_es_extension For framebuffer reading only, extension - * @es_extension2{NV,read_depth,GL_NV_read_depth_stencil}. - */ - DepthComponent = GL_DEPTH_COMPONENT, - - #ifndef MAGNUM_TARGET_GLES3 - /** - * Stencil index. For framebuffer reading only. - * @requires_es_extension %Extension @es_extension2{NV,read_stencil,GL_NV_read_depth_stencil} - * @todo Where to get GL_STENCIL_INDEX in ES? - */ - #ifndef MAGNUM_TARGET_GLES - StencilIndex = GL_STENCIL_INDEX, - #else - StencilIndex = 0x1901, - #endif - #endif - - /** - * Depth and stencil. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} - * @requires_gles30 For texture data only, extension - * @es_extension{OES,packed_depth_stencil}. - * @requires_es_extension For framebuffer reading only, extension - * @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil}. - */ - #ifndef MAGNUM_TARGET_GLES2 - DepthStencil = GL_DEPTH_STENCIL - #else - DepthStencil = GL_DEPTH_STENCIL_OES - #endif - }; - - /** - * @brief Data type of pixel data - * - * @see pixelSize() - */ - enum class Type: GLenum { - /** Each component unsigned byte. */ - UnsignedByte = GL_UNSIGNED_BYTE, - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Each component signed byte. - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - * @requires_gles30 For texture data only, only - * @ref Magnum::AbstractImage::Type "Type::UnsignedByte" is - * available in OpenGL ES 2.0. - */ - Byte = GL_BYTE, - #endif - - /** - * 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}. - */ - UnsignedShort = GL_UNSIGNED_SHORT, - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Each component signed short. - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - * @requires_gles30 For texture data only, only - * @ref Magnum::AbstractImage::Type "Type::UnsignedShort" is - * available in OpenGL ES 2.0. - */ - Short = GL_SHORT, - #endif - - /** - * 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}. - */ - UnsignedInt = GL_UNSIGNED_INT, - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Each component signed int. - * @requires_gles30 Only @ref Magnum::AbstractImage::Type "Type::UnsignedInt" - * is available in OpenGL ES 2.0. - */ - Int = GL_INT, - #endif - - /** - * 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}. - */ - #ifndef MAGNUM_TARGET_GLES2 - HalfFloat = GL_HALF_FLOAT, - #else - HalfFloat = GL_HALF_FLOAT_OES, - #endif - - /** - * Each component float. - * @requires_gles30 For texture data only, extension - * @es_extension{OES,texture_float}. - */ - Float = GL_FLOAT, - - #ifndef MAGNUM_TARGET_GLES - /** - * RGB, unsigned byte, red and green component 3bit, blue - * component 2bit. - * @requires_gl Packed 12bit types are not available in OpenGL ES. - */ - UnsignedByte332 = GL_UNSIGNED_BYTE_3_3_2, - - /** - * BGR, unsigned byte, red and green component 3bit, blue - * component 2bit. - * @requires_gl Packed 12bit types are not available in OpenGL ES. - */ - UnsignedByte233Rev = GL_UNSIGNED_BYTE_2_3_3_REV, - #endif - - /** - * RGB, unsigned byte, red and blue component 5bit, green 6bit. - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - */ - UnsignedShort565 = GL_UNSIGNED_SHORT_5_6_5, - - #ifndef MAGNUM_TARGET_GLES - /** - * BGR, unsigned short, red and blue 5bit, green 6bit. - * @requires_gl Only @ref Magnum::AbstractImage::Type "Type::RGB565" - * is available in OpenGL ES. - */ - UnsignedShort565Rev = GL_UNSIGNED_SHORT_5_6_5_REV, - #endif - - /** - * RGBA, unsigned short, each component 4bit. - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - */ - UnsignedShort4444 = GL_UNSIGNED_SHORT_4_4_4_4, - - #ifndef MAGNUM_TARGET_GLES3 - /** - * ABGR, unsigned short, each component 4bit. - * @requires_es_extension For framebuffer reading only, extension - * @es_extension{EXT,read_format_bgra}. - */ - #ifndef MAGNUM_TARGET_GLES - UnsignedShort4444Rev = GL_UNSIGNED_SHORT_4_4_4_4_REV, - #else - UnsignedShort4444Rev = GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, - #endif - #endif - - /** - * RGBA, unsigned short, each RGB component 5bit, alpha component - * 1bit. - * @requires_gl Can't be used for framebuffer reading in OpenGL ES. - */ - UnsignedShort5551 = GL_UNSIGNED_SHORT_5_5_5_1, - - #ifndef MAGNUM_TARGET_GLES3 - /** - * ABGR, unsigned short, each RGB component 5bit, alpha component - * 1bit. - * @requires_es_extension For framebuffer reading only, extension - * @es_extension{EXT,read_format_bgra}. - */ - #ifndef MAGNUM_TARGET_GLES - UnsignedShort1555Rev = GL_UNSIGNED_SHORT_1_5_5_5_REV, - #else - UnsignedShort1555Rev = GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * RGBA, unsigned int, each component 8bit. - * @requires_gl Use @ref Magnum::AbstractImage::Type "Type::UnsignedByte" - * in OpenGL ES instead. - */ - UnsignedInt8888 = GL_UNSIGNED_INT_8_8_8_8, - - /** - * ABGR, unsigned int, each component 8bit. - * @requires_gl Only RGBA component ordering is available in - * OpenGL ES, see @ref Magnum::AbstractImage::Format "Format::UnsignedInt8888" - * for more information. - */ - UnsignedInt8888Rev = GL_UNSIGNED_INT_8_8_8_8_REV, - - /** - * RGBA, unsigned int, each RGB component 10bit, alpha component - * 2bit. - * @requires_gl Only @ref Magnum::AbstractImage::Type "Type::UnsignedInt2101010Rev" - * is available in OpenGL ES. - */ - UnsignedInt1010102 = GL_UNSIGNED_INT_10_10_10_2, - #endif - - /** - * 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}. - */ - #ifndef MAGNUM_TARGET_GLES2 - UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, - #else - UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * BGR, unsigned int, red and green 11bit float, blue 10bit float. - * @requires_gl30 %Extension @extension{EXT,packed_float} - * @requires_gles30 Floating-point types are not available in - * OpenGL ES 2.0. - */ - UnsignedInt10F11F11FRev = GL_UNSIGNED_INT_10F_11F_11F_REV, - - /** - * BGR, unsigned int, each component 9bit + 5bit exponent. - * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} - * @requires_gles30 Only 8bit and 16bit types are available in - * OpenGL ES 2.0. - */ - UnsignedInt5999Rev = GL_UNSIGNED_INT_5_9_9_9_REV, - #endif - - /** - * Unsigned int, depth component 24bit, stencil index 8bit. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} - * @requires_gles30 For texture data only, extension - * @es_extension{OES,packed_depth_stencil}. - */ - #ifdef MAGNUM_TARGET_GLES2 - UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES - #else - UnsignedInt248 = GL_UNSIGNED_INT_24_8, - - /** - * Float + unsigned int, depth component 32bit float, 24bit gap, - * stencil index 8bit. - * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} - * @requires_gles30 For texture data only, only - * @ref Magnum::AbstractImage::Type "Type::UnsignedInt248" is - * available in OpenGL ES 2.0. - */ - Float32UnsignedInt248Rev = GL_FLOAT_32_UNSIGNED_INT_24_8_REV - #endif - }; - - /*@}*/ - /** * @brief Pixel size (in bytes) * @param format Format of the pixel * @param type Data type of the pixel + * + * @see pixelSize() const */ - static std::size_t pixelSize(Format format, Type type); + static std::size_t pixelSize(ImageFormat format, ImageType type); /** * @brief Constructor * @param format Format of pixel data * @param type Data type of pixel data */ - inline explicit AbstractImage(Format format, Type type): _format(format), _type(type) {} + explicit AbstractImage(ImageFormat format, ImageType type): _format(format), _type(type) {} /** @brief Destructor */ virtual ~AbstractImage() = 0; /** @brief Format of pixel data */ - inline Format format() const { return _format; } + ImageFormat format() const { return _format; } /** @brief Data type of pixel data */ - inline Type type() const { return _type; } + ImageType type() const { return _type; } - #ifndef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Pixel size (in bytes) + * + * Convenience member alternative for pixelSize(Format, Type). + */ + std::size_t pixelSize() const { return pixelSize(_format, _type); } + + #ifdef DOXYGEN_GENERATING_OUTPUT + private: + #else protected: - Format _format; - Type _type; #endif + ImageFormat _format; + ImageType _type; }; -inline AbstractImage::~AbstractImage() {} - -/** @debugoperator{Magnum::AbstractImage} */ -Debug MAGNUM_EXPORT operator<<(Debug debug, AbstractImage::Format value); - -/** @debugoperator{Magnum::AbstractImage} */ -Debug MAGNUM_EXPORT operator<<(Debug debug, AbstractImage::Type value); - } #endif diff --git a/src/AbstractResourceLoader.h b/src/AbstractResourceLoader.h index 194157607..ae38375b5 100644 --- a/src/AbstractResourceLoader.h +++ b/src/AbstractResourceLoader.h @@ -98,18 +98,16 @@ template class AbstractResourceLoader { friend class Implementation::ResourceManagerData; public: - inline explicit AbstractResourceLoader(): manager(nullptr), _requestedCount(0), _loadedCount(0), _notFoundCount(0) {} + explicit AbstractResourceLoader(): manager(nullptr), _requestedCount(0), _loadedCount(0), _notFoundCount(0) {} - inline virtual ~AbstractResourceLoader() { - if(manager) manager->_loader = nullptr; - } + virtual ~AbstractResourceLoader(); /** * @brief Count of requested resources * * Count of resources requested by calling load(). */ - inline std::size_t requestedCount() const { return _requestedCount; } + std::size_t requestedCount() const { return _requestedCount; } /** * @brief Count of not found resources @@ -117,7 +115,7 @@ template class AbstractResourceLoader { * Count of resources requested by calling load(), but not found by * the loader. */ - inline std::size_t notFoundCount() const { return _notFoundCount; } + std::size_t notFoundCount() const { return _notFoundCount; } /** * @brief Count of loaded resources @@ -125,7 +123,7 @@ template class AbstractResourceLoader { * Count of resources requested by calling load(), but not found by * the loader. */ - inline std::size_t loadedCount() const { return _loadedCount; } + std::size_t loadedCount() const { return _loadedCount; } /** * @brief %Resource name corresponding to given key @@ -160,12 +158,7 @@ template class AbstractResourceLoader { * ResourceManager::set() for more information. * @see loadedCount() */ - inline void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { - CORRADE_ASSERT(state == ResourceDataState::Mutable || state == ResourceDataState::Final, - "AbstractResourceLoader::set(): state must be either Mutable or Final", ); - ++_loadedCount; - manager->set(key, data, state, policy); - } + void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy); /** * @brief Mark resource as not found @@ -174,11 +167,7 @@ template class AbstractResourceLoader { * ResourceManager::setNotFound() for more information. * @see notFountCount() */ - inline void setNotFound(ResourceKey key) { - ++_notFoundCount; - /** @todo What policy for notfound resources? */ - manager->set(key, nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident); - } + void setNotFound(ResourceKey key); private: Implementation::ResourceManagerData* manager; @@ -187,14 +176,31 @@ template class AbstractResourceLoader { std::size_t _notFoundCount; }; -template inline std::string AbstractResourceLoader::name(ResourceKey) const { return {}; } +template AbstractResourceLoader::~AbstractResourceLoader() { + if(manager) manager->_loader = nullptr; +} + +template std::string AbstractResourceLoader::name(ResourceKey) const { return {}; } -template inline void AbstractResourceLoader::load(ResourceKey key) { +template void AbstractResourceLoader::load(ResourceKey key) { ++_requestedCount; /** @todo What policy for loading resources? */ manager->set(key, nullptr, ResourceDataState::Loading, ResourcePolicy::Resident); } +template void AbstractResourceLoader::set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { + CORRADE_ASSERT(state == ResourceDataState::Mutable || state == ResourceDataState::Final, + "AbstractResourceLoader::set(): state must be either Mutable or Final", ); + ++_loadedCount; + manager->set(key, data, state, policy); +} + +template inline void AbstractResourceLoader::setNotFound(ResourceKey key) { + ++_notFoundCount; + /** @todo What policy for notfound resources? */ + manager->set(key, nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident); +} + } #endif diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index bd5c52273..af7e6a218 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -24,16 +24,11 @@ #include "AbstractShaderProgram.h" -#include -#include - #include "Math/RectangularMatrix.h" +#include "Extensions.h" #include "Shader.h" -#include "Implementation/State.h" #include "Implementation/ShaderProgramState.h" -#include "Extensions.h" - -#define LINKER_MESSAGE_MAX_LENGTH 1024 +#include "Implementation/State.h" namespace Magnum { @@ -91,83 +86,105 @@ Int AbstractShaderProgram::maxSupportedVertexAttributeCount() { return value; } +AbstractShaderProgram::AbstractShaderProgram(): _id(glCreateProgram()) {} + +AbstractShaderProgram::AbstractShaderProgram(AbstractShaderProgram&& other) noexcept: _id(other._id) { + other._id = 0; +} + AbstractShaderProgram::~AbstractShaderProgram() { /* Remove current usage from the state */ GLuint& current = Context::current()->state()->shaderProgram->current; if(current == _id) current = 0; - glDeleteProgram(_id); + if(_id) glDeleteProgram(_id); +} + +AbstractShaderProgram& AbstractShaderProgram::operator=(AbstractShaderProgram&& other) noexcept { + std::swap(_id, other._id); + return *this; } -bool AbstractShaderProgram::use() { - if(state != Linked) return false; +std::pair AbstractShaderProgram::validate() { + glValidateProgram(_id); + + /* Check validation status */ + GLint success, logLength; + glGetProgramiv(_id, GL_VALIDATE_STATUS, &success); + glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength); + /* Error or warning message. The string is returned null-terminated, scrap + the \0 at the end afterwards */ + std::string message(logLength, '\n'); + if(!message.empty()) { + glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); + message.resize(logLength-1); + } + + return {success, std::move(message)}; +} + +void AbstractShaderProgram::use() { /* Use only if the program isn't already in use */ GLuint& current = Context::current()->state()->shaderProgram->current; if(current != _id) glUseProgram(current = _id); - return true; } -bool AbstractShaderProgram::attachShader(Shader& shader) { - GLuint _shader = shader.compile(); - if(!_shader) return false; - - glAttachShader(_id, _shader); - return true; +void AbstractShaderProgram::attachShader(Shader& shader) { + glAttachShader(_id, shader.id()); } void AbstractShaderProgram::bindAttributeLocation(UnsignedInt location, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", ); - glBindAttribLocation(_id, location, name.c_str()); } #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::bindFragmentDataLocation(UnsignedInt location, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); - glBindFragDataLocation(_id, location, name.c_str()); } void AbstractShaderProgram::bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); - glBindFragDataLocationIndexed(_id, location, index, name.c_str()); } #endif -void AbstractShaderProgram::link() { - /* Already compiled or failed, exit */ - if(state != Initialized) return; - +bool AbstractShaderProgram::link() { /* Link shader program */ glLinkProgram(_id); /* Check link status */ - GLint status; - glGetProgramiv(_id, GL_LINK_STATUS, &status); - - /* Display errors or warnings */ - char message[LINKER_MESSAGE_MAX_LENGTH]; - glGetProgramInfoLog(_id, LINKER_MESSAGE_MAX_LENGTH, nullptr, message); + GLint success, logLength; + glGetProgramiv(_id, GL_LINK_STATUS, &success); + glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength); + + /* Error or warning message. The string is returned null-terminated, scrap + the \0 at the end afterwards */ + std::string message(logLength, '\n'); + if(!message.empty()) { + glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); + message.resize(logLength-1); + } /* Show error log and delete shader */ - if(status == GL_FALSE) { - Error() << "AbstractShaderProgram: linking failed with the following message:\n" - << message; + if(!success) { + Error out; + out.setFlag(Debug::NewLineAtTheEnd, false); + out.setFlag(Debug::SpaceAfterEachValue, false); + out << "AbstractShaderProgram: linking failed with the following message:\n" + << message; /* Or just warnings, if there are any */ - } else if(message[0] != 0) { - Debug() << "AbstractShaderProgram: linking succeeded with the following message:\n" - << message; + } else if(!message.empty()) { + Debug out; + out.setFlag(Debug::NewLineAtTheEnd, false); + out.setFlag(Debug::SpaceAfterEachValue, false); + out << "AbstractShaderProgram: linking succeeded with the following message:\n" + << message; } - state = status == GL_FALSE ? Failed : Linked; + return success; } Int AbstractShaderProgram::uniformLocation(const std::string& name) { - /** @todo What if linking just failed (not programmer error?) */ - CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1); - GLint location = glGetUniformLocation(_id, name.c_str()); if(location == -1) Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!"; @@ -578,7 +595,6 @@ void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const } #endif -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { std::size_t FloatAttribute::size(GLint components, DataType dataType) { @@ -837,6 +853,5 @@ Debug operator<<(Debug debug, Attribute>::DataType value) } } -#endif } diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h index f4c51e81f..06e76489a 100644 --- a/src/AbstractShaderProgram.h +++ b/src/AbstractShaderProgram.h @@ -35,15 +35,11 @@ #include "OpenGL.h" #include "magnumVisibility.h" -/** @todo early asserts (no bool returns?) */ - namespace Magnum { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Attribute; } -#endif /** @brief Base for shader program implementations @@ -86,12 +82,19 @@ Int TransformationUniform = 0, gets uniform locations, for example: @code MyShader() { - // Load shaders from file and attach them to the program - attachShader(Shader::fromFile(Version::430, Shader::Type::Vertex, "PhongShader.vert")); - attachShader(Shader::fromFile(Version::430, Shader::Type::Fragment, "PhongShader.frag")); - - // Link - link(); + // Load shaders, compile them and attach them to the program + Shader vert(Version::GL430, Shader::Type::Vertex); + vert.attachFile("PhongShader.vert"); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); + + Shader frag(Version::GL430, Shader::Type::Fragment); + frag.attachFile("PhongShader.vert"); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); + + // Link the program together + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } @endcode - **Uniform setting functions**, which will provide public interface for @@ -283,230 +286,8 @@ comes in handy. class MAGNUM_EXPORT AbstractShaderProgram { friend class Context; - AbstractShaderProgram(const AbstractShaderProgram&) = delete; - AbstractShaderProgram(AbstractShaderProgram&&) = delete; - AbstractShaderProgram& operator=(const AbstractShaderProgram&) = delete; - AbstractShaderProgram& operator=(AbstractShaderProgram&&) = delete; - public: - /** - * @brief Base struct for attribute location and type - * - * Template parameter @p location is vertex attribute location, number - * between `0` and maxSupportedVertexAttributeCount(). To ensure - * compatibility, you should always have vertex attribute with - * location `0`. - * - * Template parameter @p T is the type which is used for shader - * attribute, e.g. @ref Vector4i for `ivec4`. DataType is type of - * passed data when adding vertex buffers to mesh. By default it is - * the same as type used in shader (e.g. @ref DataType "DataType::Int" - * for @ref Vector4i). It's also possible to pass integer data to - * floating-point shader inputs. In this case you may want to - * normalize the values (e.g. color components from 0-255 to - * 0.0f - 1.0f) -- see @ref DataOption "DataOption::Normalize". - * - * Only some types are allowed as attribute types, see - * @ref AbstractShaderProgram-types or TypeTraits::AttributeType for - * more information. - * - * See @ref AbstractShaderProgram-subclassing for example usage in - * shaders and @ref Mesh-configuration for example usage when adding - * vertex buffers to mesh. - */ - template class Attribute { - public: - enum: UnsignedInt { - Location = location /**< Location to which the attribute is bound */ - }; - - /** - * @brief Type - * - * Type used in shader code. - * @see DataType - */ - typedef typename Implementation::Attribute::Type Type; - - /** - * @brief Component count - * - * Count of components passed to the shader. If passing smaller - * count of components than corresponding type has, unspecified - * components are set to default values (second and third to `0`, - * fourth to `1`). - */ - #ifdef DOXYGEN_GENERATING_OUTPUT - enum class Components: GLint { - /** - * Only first component is specified. Second, third and - * fourth component are set to `0`, `0`, `1`, respectively. - * Only for scalar and vector types, not matrices. - */ - One = 1, - - /** - * First two components are specified. Third and fourth - * component are set to `0`, `1`, respectively. Only for - * two, three and four-component vector types and 2x2, 3x2 - * and 4x2 matrix types. - */ - Two = 2, - - /** - * First three components are specified. Fourth component is - * set to `1`. Only for three and four-component vector - * types, 2x3, 3x3 and 4x3 matrix types. - */ - Three = 3, - - /** - * All four components are specified. Only for four-component - * vector types and 2x4, 3x4 and 4x4 matrix types. - */ - Four = 4 - - #ifndef MAGNUM_TARGET_GLES - , - /** - * Four components with BGRA ordering. Only for four-component - * float vector type. - * @requires_gl32 %Extension @extension{ARB,vertex_array_bgra} - * @requires_gl Only RGBA component ordering is supported - * in OpenGL ES. - */ - BGRA = 1 << 1 - #endif - }; - #else - typedef typename Implementation::Attribute::Components Components; - #endif - - /** - * @brief Data type - * - * Type of data passed to shader. - * @see Type, DataOptions, Attribute() - */ - #ifdef DOXYGEN_GENERATING_OUTPUT - enum class DataType: GLenum { - UnsignedByte = GL_UNSIGNED_BYTE, /**< Unsigned byte */ - Byte = GL_BYTE, /**< Byte */ - UnsignedShort = GL_UNSIGNED_SHORT, /**< Unsigned short */ - Short = GL_SHORT, /**< Short */ - UnsignedInt = GL_UNSIGNED_INT, /**< Unsigned int */ - Int = GL_INT, /**< Int */ - - /** - * Half float. Only for float attribute types. - * @requires_gl30 %Extension @extension{NV,half_float} - * @requires_gles30 %Extension @es_extension{OES,vertex_half_float} - */ - HalfFloat = GL_HALF_FLOAT, - - /** Float. Only for float attribute types. */ - Float = GL_FLOAT, - - #ifndef MAGNUM_TARGET_GLES - /** - * Double. Only for float and double attribute types. - * @requires_gl Only floats are available in OpenGL ES. - */ - Double = GL_DOUBLE, - #endif - - /* GL_FIXED not supported */ - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Unsigned 2.10.10.10 packed integer. Only for - * four-component 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) - */ - UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, - - /** - * 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) - */ - Int2101010Rev = GL_INT_2_10_10_10_REV - #endif - }; - #else - typedef typename Implementation::Attribute::DataType DataType; - #endif - - /** - * @brief Data option - * @see DataOptions, Attribute() - */ - #ifdef DOXYGEN_GENERATING_OUTPUT - enum class DataOption: UnsignedByte { - /** - * Normalize integer components. Only for float attribute - * types. Default is to not normalize. - */ - Normalize = 1 << 0 - }; - #else - typedef typename Implementation::Attribute::DataOption DataOption; - #endif - - /** - * @brief Data options - * @see Attribute() - */ - #ifdef DOXYGEN_GENERATING_OUTPUT - typedef typename Corrade::Containers::EnumSet DataOptions; - #else - typedef typename Implementation::Attribute::DataOptions DataOptions; - #endif - - /** - * @brief Constructor - * @param components Component count - * @param dataType Type of passed data. Default is the - * same as type used in shader (e.g. DataType::Integer - * for Vector4i). - * @param dataOptions Data options. Default is no options. - */ - inline constexpr Attribute(Components components, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(components), _dataType(dataType), _dataOptions(dataOptions) {} - - /** - * @brief Constructor - * @param dataType Type of passed data. Default is the - * same as type used in shader (e.g. DataType::Integer - * for Vector4i). - * @param dataOptions Data options. Default is no options. - * - * Component count is set to the same value as in type used in - * shader (e.g. @ref Components "Components::Three" for Vector3). - */ - inline constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(Implementation::Attribute::DefaultComponents), _dataType(dataType), _dataOptions(dataOptions) {} - - /** @brief Component count of passed data */ - inline constexpr Components components() const { return _components; } - - /** @brief Type of passed data */ - inline constexpr DataType dataType() const { return _dataType; } - - /** @brief Size of passed data */ - inline std::size_t dataSize() const { - return Implementation::Attribute::size(GLint(_components)*Implementation::Attribute::vectorCount(), _dataType); - } - - /** @brief Data options */ - inline constexpr DataOptions dataOptions() const { return _dataOptions; } - - private: - const Components _components; - const DataType _dataType; - const DataOptions _dataOptions; - }; + template class Attribute; /** * @brief Max supported vertex attribute count @@ -523,9 +304,13 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Creates one OpenGL shader program. * @see @fn_gl{CreateProgram} */ - inline explicit AbstractShaderProgram(): state(Initialized) { - _id = glCreateProgram(); - } + explicit AbstractShaderProgram(); + + /** @brief Copying is not allowed */ + AbstractShaderProgram(const AbstractShaderProgram&) = delete; + + /** @brief Move constructor */ + AbstractShaderProgram(AbstractShaderProgram&& other) noexcept; /** * @brief Destructor @@ -535,14 +320,31 @@ class MAGNUM_EXPORT AbstractShaderProgram { */ virtual ~AbstractShaderProgram() = 0; + /** @brief Copying is not allowed */ + AbstractShaderProgram& operator=(const AbstractShaderProgram&) = delete; + + /** @brief Move assignment */ + AbstractShaderProgram& operator=(AbstractShaderProgram&& other) noexcept; + + /** @brief OpenGL program ID */ + GLuint id() const { return _id; } + + /** + * @brief Validate program + * + * Returns validation status and optional validation message. + * @see @fn_gl{ValidateProgram}, @fn_gl{GetProgram} with + * @def_gl{VALIDATE_STATUS}, @def_gl{INFO_LOG_LENGTH}, + * @fn_gl{GetProgramInfoLog} + */ + std::pair validate(); + /** * @brief Use shader for rendering - * @return False if the program wasn't successfully linked, true - * otherwise. * * @see @fn_gl{UseProgram} */ - bool use(); + void use(); protected: #ifndef MAGNUM_TARGET_GLES2 @@ -550,13 +352,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @brief Allow retrieving program binary * * Initially disabled. - * @note This function should be called after attachShader() calls and - * before link(). * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_BINARY_RETRIEVABLE_HINT} * @requires_gl41 %Extension @extension{ARB,get_program_binary} * @requires_gles30 Always allowed in OpenGL ES 2.0. */ - inline void setRetrievableBinary(bool enabled) { + void setRetrievableBinary(bool enabled) { glProgramParameteri(_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, enabled ? GL_TRUE : GL_FALSE); } #endif @@ -565,13 +365,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @brief Allow the program to be bound to individual pipeline stages * * Initially disabled. - * @note This function should be called after attachShader() calls and - * before link(). * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_SEPARABLE} * @requires_gl41 %Extension @extension{ARB,separate_shader_objects} * @requires_es_extension %Extension @es_extension{EXT,separate_shader_objects} */ - inline void setSeparable(bool enabled) { + void setSeparable(bool enabled) { /** @todo Remove when extension wrangler is available for ES */ #ifndef MAGNUM_TARGET_GLES glProgramParameteri(_id, GL_PROGRAM_SEPARABLE, enabled ? GL_TRUE : GL_FALSE); @@ -581,20 +379,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { } /** - * @brief Load shader - * @return False if the shader wasn't successfully compiled, true - * otherwise. + * @brief Attach shader * - * Compiles the shader, if it is not already, and prepares it for - * linking. - * @see Shader::compile(), @fn_gl{AttachShader} + * @fn_gl{AttachShader} */ - bool attachShader(Shader& shader); - - /** @overload */ - inline bool attachShader(Shader&& shader) { - return attachShader(shader); - } + void attachShader(Shader& shader); /** * @brief Bind attribute to given location @@ -603,8 +392,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { * * Binds attribute to location which is used later for binding vertex * buffers. - * @note This function should be called after attachShader() calls and - * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-attribute-location "class documentation" @@ -623,8 +410,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Binds fragment data to location which is used later for framebuffer * operations. See also Framebuffer::BlendFunction for more * information about using color input index. - * @note This function should be called after attachShader() calls and - * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-attribute-location "class documentation" @@ -654,18 +439,19 @@ class MAGNUM_EXPORT AbstractShaderProgram { /** * @brief Link the shader * - * Binds previously specified attributes to given indexes and links the - * shader program together. + * Returns `false` if linking failed, `true` otherwise. Compiler + * message (if any) is printed to error output. All attached shaders + * must be explicitly compiled with Shader::compile() before linking. * @see @fn_gl{LinkProgram}, @fn_gl{GetProgram} with - * @def_gl{LINK_STATUS}, @fn_gl{GetProgramInfoLog} + * @def_gl{LINK_STATUS} and @def_gl{INFO_LOG_LENGTH}, + * @fn_gl{GetProgramInfoLog} */ - void link(); + bool link(); /** * @brief Get uniform location * @param name Uniform name * - * @note This function should be called after link(). * @deprecated Preferred usage is to specify uniform location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-uniform-location "class documentation" @@ -685,26 +471,26 @@ class MAGNUM_EXPORT AbstractShaderProgram { #ifdef DOXYGEN_GENERATING_OUTPUT template inline void setUniform(Int location, const T& value); #else - inline void setUniform(Int location, Float value) { + void setUniform(Int location, Float value) { setUniform(location, 1, &value); } - inline void setUniform(Int location, Int value) { + void setUniform(Int location, Int value) { setUniform(location, 1, &value); } #ifndef MAGNUM_TARGET_GLES2 - inline void setUniform(Int location, UnsignedInt value) { + void setUniform(Int location, UnsignedInt value) { setUniform(location, 1, &value); } #endif #ifndef MAGNUM_TARGET_GLES - inline void setUniform(Int location, Double value) { + void setUniform(Int location, Double value) { setUniform(location, 1, &value); } #endif - template inline void setUniform(Int location, const Math::Vector& value) { + template void setUniform(Int location, const Math::Vector& value) { setUniform(location, 1, &value); } - template inline void setUniform(Int location, const Math::RectangularMatrix& value) { + template void setUniform(Int location, const Math::RectangularMatrix& value) { setUniform(location, 1, &value); } #endif @@ -719,45 +505,44 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @extension{EXT,direct_state_access} is available, the shader is * marked for use before the operation. * @see setUniform(Int, const T&), @fn_gl{UseProgram}, @fn_gl{Uniform} - * or `glProgramUniform()` from - * @extension{ARB,separate_shader_objects}/@extension{EXT,direct_state_access}. + * or @fn_gl{ProgramUniform}/@fn_gl_extension{ProgramUniform,EXT,direct_state_access}. */ - inline void setUniform(Int location, UnsignedInt count, const Float* values) { + void setUniform(Int location, UnsignedInt count, const Float* values) { (this->*uniform1fvImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Float>* values) { (this->*uniform2fvImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Float>* values) { (this->*uniform3fvImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Float>* values) { (this->*uniform4fvImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Int* values) { + void setUniform(Int location, UnsignedInt count, const Int* values) { (this->*uniform1ivImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Int>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Int>* values) { (this->*uniform2ivImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Int>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Int>* values) { (this->*uniform3ivImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Int>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Int>* values) { (this->*uniform4ivImplementation)(location, count, values); } @@ -767,7 +552,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const UnsignedInt* values) { + void setUniform(Int location, UnsignedInt count, const UnsignedInt* values) { (this->*uniform1uivImplementation)(location, count, values); } @@ -776,7 +561,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<2, UnsignedInt>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, UnsignedInt>* values) { (this->*uniform2uivImplementation)(location, count, values); } @@ -785,7 +570,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<3, UnsignedInt>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, UnsignedInt>* values) { (this->*uniform3uivImplementation)(location, count, values); } @@ -794,7 +579,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<4, UnsignedInt>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, UnsignedInt>* values) { (this->*uniform4uivImplementation)(location, count, values); } #endif @@ -805,7 +590,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Double* values) { + void setUniform(Int location, UnsignedInt count, const Double* values) { (this->*uniform1dvImplementation)(location, count, values); } @@ -814,7 +599,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Double>* values) { (this->*uniform2dvImplementation)(location, count, values); } @@ -823,7 +608,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Double>* values) { (this->*uniform3dvImplementation)(location, count, values); } @@ -832,23 +617,23 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Double>* values) { (this->*uniform4dvImplementation)(location, count, values); } #endif /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Float>* values) { (this->*uniformMatrix2fvImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Float>* values) { (this->*uniformMatrix3fvImplementation)(location, count, values); } /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Float>* values) { (this->*uniformMatrix4fvImplementation)(location, count, values); } @@ -857,7 +642,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Float>* values) { (this->*uniformMatrix2x3fvImplementation)(location, count, values); } @@ -865,7 +650,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Float>* values) { (this->*uniformMatrix3x2fvImplementation)(location, count, values); } @@ -873,7 +658,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Float>* values) { (this->*uniformMatrix2x4fvImplementation)(location, count, values); } @@ -881,7 +666,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Float>* values) { (this->*uniformMatrix4x2fvImplementation)(location, count, values); } @@ -889,7 +674,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Float>* values) { (this->*uniformMatrix3x4fvImplementation)(location, count, values); } @@ -897,7 +682,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Float>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Float>* values) { (this->*uniformMatrix4x3fvImplementation)(location, count, values); } #endif @@ -908,7 +693,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Double>* values) { (this->*uniformMatrix2dvImplementation)(location, count, values); } @@ -917,7 +702,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Double>* values) { (this->*uniformMatrix3dvImplementation)(location, count, values); } @@ -926,7 +711,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Double>* values) { (this->*uniformMatrix4dvImplementation)(location, count, values); } @@ -935,7 +720,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Double>* values) { (this->*uniformMatrix2x3dvImplementation)(location, count, values); } @@ -944,7 +729,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Double>* values) { (this->*uniformMatrix3x2dvImplementation)(location, count, values); } @@ -953,7 +738,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Double>* values) { (this->*uniformMatrix2x4dvImplementation)(location, count, values); } @@ -962,7 +747,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Double>* values) { (this->*uniformMatrix4x2dvImplementation)(location, count, values); } @@ -971,7 +756,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Double>* values) { (this->*uniformMatrix3x4dvImplementation)(location, count, values); } @@ -980,18 +765,12 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Double>* values) { + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Double>* values) { (this->*uniformMatrix4x3dvImplementation)(location, count, values); } #endif private: - enum State { - Initialized, - Linked, - Failed - }; - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); typedef void(AbstractShaderProgram::*Uniform1fvImplementation)(GLint, GLsizei, const GLfloat*); @@ -1157,7 +936,216 @@ class MAGNUM_EXPORT AbstractShaderProgram { #endif GLuint _id; - State state; +}; + +/** +@brief Base struct for attribute location and type + +Template parameter @p location is vertex attribute location, number between `0` +and maxSupportedVertexAttributeCount(). To ensure compatibility, you should +always have vertex attribute with location `0`. + +Template parameter @p T is the type which is used for shader attribute, e.g. +@ref Vector4i for `ivec4`. DataType is type of passed data when adding vertex +buffers to mesh. By default it is the same as type used in shader (e.g. +@ref DataType "DataType::Int" for @ref Vector4i). It's also possible to pass +integer data to floating-point shader inputs. In this case you may want to +normalize the values (e.g. color components from 0-255 to 0.0f - 1.0f) -- see +@ref DataOption "DataOption::Normalize". + +Only some types are allowed as attribute types, see @ref AbstractShaderProgram-types +or TypeTraits::AttributeType for more information. + +See @ref AbstractShaderProgram-subclassing for example usage in shaders and +@ref Mesh-configuration for example usage when adding vertex buffers to mesh. +*/ +template class AbstractShaderProgram::Attribute { + public: + enum: UnsignedInt { + Location = location /**< Location to which the attribute is bound */ + }; + + /** + * @brief Type + * + * Type used in shader code. + * @see DataType + */ + typedef typename Implementation::Attribute::Type Type; + + /** + * @brief Component count + * + * Count of components passed to the shader. If passing smaller count + * of components than corresponding type has, unspecified components + * are set to default values (second and third to `0`, fourth to `1`). + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class Components: GLint { + /** + * Only first component is specified. Second, third and fourth + * component are set to `0`, `0`, `1`, respectively. Only for + * scalar and vector types, not matrices. + */ + One = 1, + + /** + * First two components are specified. Third and fourth component + * are set to `0`, `1`, respectively. Only for two, three and + * four-component vector types and 2x2, 3x2 and 4x2 matrix types. + */ + Two = 2, + + /** + * First three components are specified. Fourth component is set to + * `1`. Only for three and four-component vector types, 2x3, 3x3 + * and 4x3 matrix types. + */ + Three = 3, + + /** + * All four components are specified. Only for four-component + * vector types and 2x4, 3x4 and 4x4 matrix types. + */ + Four = 4, + + #ifndef MAGNUM_TARGET_GLES + /** + * Four components with BGRA ordering. Only for four-component + * float vector type. + * @requires_gl32 %Extension @extension{ARB,vertex_array_bgra} + * @requires_gl Only RGBA component ordering is supported in OpenGL + * ES. + */ + BGRA = 1 << 1 + #endif + }; + #else + typedef typename Implementation::Attribute::Components Components; + #endif + + /** + * @brief Data type + * + * Type of data passed to shader. + * @see Type, DataOptions, Attribute() + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class DataType: GLenum { + UnsignedByte = GL_UNSIGNED_BYTE, /**< Unsigned byte */ + Byte = GL_BYTE, /**< Byte */ + UnsignedShort = GL_UNSIGNED_SHORT, /**< Unsigned short */ + Short = GL_SHORT, /**< Short */ + UnsignedInt = GL_UNSIGNED_INT, /**< Unsigned int */ + Int = GL_INT, /**< Int */ + + /** + * Half float. Only for float attribute types. + * @requires_gl30 %Extension @extension{NV,half_float} + * @requires_gles30 %Extension @es_extension{OES,vertex_half_float} + */ + HalfFloat = GL_HALF_FLOAT, + + /** Float. Only for float attribute types. */ + Float = GL_FLOAT, + + #ifndef MAGNUM_TARGET_GLES + /** + * Double. Only for float and double attribute types. + * @requires_gl Only floats are available in OpenGL ES. + */ + Double = GL_DOUBLE, + #endif + + /* GL_FIXED not supported */ + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Unsigned 2.10.10.10 packed integer. Only for four-component + * 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) + */ + UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, + + /** + * 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) + */ + Int2101010Rev = GL_INT_2_10_10_10_REV + #endif + }; + #else + typedef typename Implementation::Attribute::DataType DataType; + #endif + + /** + * @brief Data option + * @see DataOptions, Attribute() + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class DataOption: UnsignedByte { + /** + * Normalize integer components. Only for float attribute types. + * Default is to not normalize. + */ + Normalize = 1 << 0 + }; + #else + typedef typename Implementation::Attribute::DataOption DataOption; + #endif + + /** + * @brief Data options + * @see Attribute() + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + typedef typename Containers::EnumSet DataOptions; + #else + typedef typename Implementation::Attribute::DataOptions DataOptions; + #endif + + /** + * @brief Constructor + * @param components Component count + * @param dataType Type of passed data. Default is the same as + * type used in shader (e.g. DataType::Integer for Vector4i). + * @param dataOptions Data options. Default is no options. + */ + constexpr Attribute(Components components, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(components), _dataType(dataType), _dataOptions(dataOptions) {} + + /** + * @brief Constructor + * @param dataType Type of passed data. Default is the same as + * type used in shader (e.g. DataType::Integer for Vector4i). + * @param dataOptions Data options. Default is no options. + * + * Component count is set to the same value as in type used in shader + * (e.g. @ref Components "Components::Three" for Vector3). + */ + constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(Implementation::Attribute::DefaultComponents), _dataType(dataType), _dataOptions(dataOptions) {} + + /** @brief Component count of passed data */ + constexpr Components components() const { return _components; } + + /** @brief Type of passed data */ + constexpr DataType dataType() const { return _dataType; } + + /** @brief Size of passed data */ + std::size_t dataSize() const { + return Implementation::Attribute::size(GLint(_components)*Implementation::Attribute::vectorCount(), _dataType); + } + + /** @brief Data options */ + constexpr DataOptions dataOptions() const { return _dataOptions; } + + private: + const Components _components; + const DataType _dataType; + const DataOptions _dataOptions; }; #ifdef DOXYGEN_GENERATING_OUTPUT @@ -1168,7 +1156,6 @@ template Debug operator<<(Debug debug, AbstractShaderProgram::Attribute template Debug operator<<(Debug debug, AbstractShaderProgram::Attribute::DataType); #endif -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { /* Base for sized attributes */ @@ -1176,7 +1163,7 @@ template struct SizedAttribute; /* Vector attribute sizes */ template struct SizedVectorAttribute { - inline constexpr static std::size_t vectorCount() { return cols; } + constexpr static std::size_t vectorCount() { return cols; } }; template<> struct SizedAttribute<1, 1>: SizedVectorAttribute<1> { enum class Components: GLint { One = 1 }; @@ -1299,7 +1286,7 @@ struct FloatAttribute { enum class DataOption: UnsignedByte { Normalized = 1 << 0 }; - typedef Corrade::Containers::EnumSet DataOptions; + typedef Containers::EnumSet DataOptions; static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; @@ -1329,7 +1316,7 @@ struct IntAttribute { DataType DefaultDataType = DataType::Int; enum class DataOption: UnsignedByte {}; - typedef Corrade::Containers::EnumSet DataOptions; + typedef Containers::EnumSet DataOptions; static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; @@ -1349,9 +1336,9 @@ struct UnsignedIntAttribute { DataType DefaultDataType = DataType::UnsignedInt; typedef IntAttribute::DataOption DataOption; - typedef Corrade::Containers::EnumSet DataOptions; + typedef Containers::EnumSet DataOptions; - inline static std::size_t size(GLint components, DataType dataType) { + static std::size_t size(GLint components, DataType dataType) { return IntAttribute::size(components, dataType); } }; @@ -1373,7 +1360,7 @@ struct DoubleAttribute { DataType DefaultDataType = DataType::Double; enum class DataOption: UnsignedByte {}; - typedef Corrade::Containers::EnumSet DataOptions; + typedef Containers::EnumSet DataOptions; static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; @@ -1435,9 +1422,9 @@ template<> struct Attribute> { enum class DataOption: UnsignedByte { Normalized = 1 << 0 }; - typedef Corrade::Containers::EnumSet DataOptions; + typedef Containers::EnumSet DataOptions; - inline constexpr static std::size_t vectorCount() { return 1; } + constexpr static std::size_t vectorCount() { return 1; } static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; @@ -1488,7 +1475,6 @@ template struct Attribute>: Attribute struct Attribute>: Attribute> {}; } -#endif } diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index d13609061..315cdd811 100644 --- a/src/AbstractTexture.cpp +++ b/src/AbstractTexture.cpp @@ -28,6 +28,7 @@ #include "BufferImage.h" #include "Context.h" #include "Extensions.h" +#include "Image.h" #include "Implementation/State.h" #include "Implementation/TextureState.h" @@ -56,6 +57,8 @@ AbstractTexture::Storage2DImplementation AbstractTexture::storage2DImplementatio AbstractTexture::Storage3DImplementation AbstractTexture::storage3DImplementation = &AbstractTexture::storageImplementationDefault; #ifndef MAGNUM_TARGET_GLES +AbstractTexture::GetImageImplementation AbstractTexture::getImageImplementation = + &AbstractTexture::getImageImplementationDefault; AbstractTexture::Image1DImplementation AbstractTexture::image1DImplementation = &AbstractTexture::imageImplementationDefault; #endif @@ -72,45 +75,13 @@ AbstractTexture::SubImage2DImplementation AbstractTexture::subImage2DImplementat AbstractTexture::SubImage3DImplementation AbstractTexture::subImage3DImplementation = &AbstractTexture::subImageImplementationDefault; -AbstractTexture::InvalidateImplementation AbstractTexture::invalidateImplementation = &AbstractTexture::invalidateImplementationNoOp; -AbstractTexture::InvalidateSubImplementation AbstractTexture::invalidateSubImplementation = &AbstractTexture::invalidateSubImplementationNoOp; - -#ifndef DOXYGEN_GENERATING_OUTPUT - -/* Check correctness of binary OR in setMinificationFilter(). If nobody fucks - anything up, this assert should produce the same results on all dimensions, - thus testing only on AbstractTexture. */ -#define filter_or(filter, mipmap) \ - (static_cast(AbstractTexture::Filter::filter)|static_cast(AbstractTexture::Mipmap::mipmap)) -static_assert((filter_or(Nearest, Base) == GL_NEAREST) && - (filter_or(Nearest, Nearest) == GL_NEAREST_MIPMAP_NEAREST) && - (filter_or(Nearest, Linear) == GL_NEAREST_MIPMAP_LINEAR) && - (filter_or(Linear, Base) == GL_LINEAR) && - (filter_or(Linear, Nearest) == GL_LINEAR_MIPMAP_NEAREST) && - (filter_or(Linear, Linear) == GL_LINEAR_MIPMAP_LINEAR), - "Unsupported constants for GL texture filtering"); -#undef filter_or -#endif +AbstractTexture::InvalidateImageImplementation AbstractTexture::invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationNoOp; +AbstractTexture::InvalidateSubImageImplementation AbstractTexture::invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationNoOp; Int AbstractTexture::maxSupportedLayerCount() { return Context::current()->state()->texture->maxSupportedLayerCount; } -#ifndef MAGNUM_TARGET_GLES3 -Float AbstractTexture::maxSupportedAnisotropy() { - GLfloat& value = Context::current()->state()->texture->maxSupportedAnisotropy; - - /** @todo Re-enable when extension header is available */ - #ifndef MAGNUM_TARGET_GLES - /* Get the value, if not already cached */ - if(value == 0.0f) - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value); - #endif - - return value; -} -#endif - void AbstractTexture::destroy() { /* Moved out */ if(!_id) return; @@ -169,9 +140,9 @@ void AbstractTexture::bindImplementationDSA(GLint layer) { } #endif -AbstractTexture* AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) { +AbstractTexture* AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) { #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::Base, "AbstractTexture: rectangle textures cannot have mipmaps", this); + CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Sampler::Mipmap::Base, "AbstractTexture: rectangle textures cannot have mipmaps", this); #endif (this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER, @@ -199,7 +170,6 @@ void AbstractTexture::mipmapImplementationDSA() { } #endif -#ifndef DOXYGEN_GENERATING_OUTPUT void AbstractTexture::bindInternal() { Implementation::TextureState* const textureState = Context::current()->state()->texture; @@ -216,7 +186,6 @@ void AbstractTexture::bindInternal() { if(textureState->bindings[internalLayer] != _id) glBindTexture(_target, (textureState->bindings[internalLayer] = _id)); } -#endif void AbstractTexture::initializeContextBasedFunctionality(Context* context) { Implementation::TextureState* const textureState = context->state()->texture; @@ -239,6 +208,7 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { storage1DImplementation = &AbstractTexture::storageImplementationDSA; storage2DImplementation = &AbstractTexture::storageImplementationDSA; storage3DImplementation = &AbstractTexture::storageImplementationDSA; + getImageImplementation = &AbstractTexture::getImageImplementationDSA; image1DImplementation = &AbstractTexture::imageImplementationDSA; image2DImplementation = &AbstractTexture::imageImplementationDSA; image3DImplementation = &AbstractTexture::imageImplementationDSA; @@ -250,8 +220,15 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { if(context->isExtensionSupported()) { Debug() << "AbstractTexture: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; - invalidateImplementation = &AbstractTexture::invalidateImplementationARB; - invalidateSubImplementation = &AbstractTexture::invalidateSubImplementationARB; + invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationARB; + invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationARB; + } + + if(context->isExtensionSupported() && + !context->isExtensionSupported()) { + Debug() << "AbstractTexture: using" << Extensions::GL::ARB::robustness::string() << "features"; + + getImageImplementation = &AbstractTexture::getImageImplementationRobustness; } #endif } @@ -301,7 +278,7 @@ void AbstractTexture::getLevelParameterImplementationDSA(GLenum target, GLint le #endif #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { +void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -315,12 +292,12 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels #endif } -void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { glTextureStorage1DEXT(_id, target, levels, GLenum(internalFormat), size[0]); } #endif -void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector2i& size) { +void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -335,12 +312,12 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector2i& size) { +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) { glTextureStorage2DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y()); } #endif -void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector3i& size) { +void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -355,32 +332,60 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector3i& size) { +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { glTextureStorage3DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); } +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::getImageImplementationDefault(const GLenum target, const GLint level, const ImageFormat format, const ImageType type, const std::size_t, GLvoid* const data) { + bindInternal(); + glGetTexImage(target, level, GLenum(format), GLenum(type), data); +} + +void AbstractTexture::getImageImplementationDSA(const GLenum target, const GLint level, const ImageFormat format, const ImageType type, const std::size_t, GLvoid* const data) { + glGetTextureImageEXT(_id, target, level, GLenum(format), GLenum(type), data); +} -void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::getImageImplementationRobustness(const GLenum target, const GLint level, const ImageFormat format, const ImageType type, const std::size_t dataSize, GLvoid* const data) { + #ifndef MAGNUM_TARGET_GLES + bindInternal(); + glGetnTexImageARB(target, level, GLenum(format), GLenum(type), dataSize, data); + #else + CORRADE_INTERNAL_ASSERT(false); + static_cast(target); + static_cast(level); + static_cast(format); + static_cast(type); + static_cast(dataSize); + static_cast(data); + #endif +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data) { bindInternal(); glTexImage1D(target, level, static_cast(internalFormat), size[0], 0, static_cast(format), static_cast(type), data); } -void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data) { glTextureImage1DEXT(_id, target, level, GLint(internalFormat), size[0], 0, static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data) { bindInternal(); glTexImage2D(target, level, GLint(internalFormat), size.x(), size.y(), 0, static_cast(format), static_cast(type), data); } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data) { glTextureImage2DEXT(_id, target, level, GLint(internalFormat), size.x(), size.y(), 0, static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data) { bindInternal(); /** @todo Get some extension wrangler instead to avoid linker errors to glTexImage3D() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -397,34 +402,34 @@ void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, Int } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data) { glTextureImage3DEXT(_id, target, level, GLint(internalFormat), size.x(), size.y(), size.z(), 0, static_cast(format), static_cast(type), data); } #endif #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data) { bindInternal(); glTexSubImage1D(target, level, offset[0], size[0], static_cast(format), static_cast(type), data); } -void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data) { glTextureSubImage1DEXT(_id, target, level, offset[0], size[0], static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data) { bindInternal(); glTexSubImage2D(target, level, offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data) { glTextureSubImage2DEXT(_id, target, level, offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data) { bindInternal(); /** @todo Get some extension wrangler instead to avoid linker errors to glTexSubImage3D() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -441,27 +446,57 @@ void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data) { glTextureSubImage3DEXT(_id, target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::invalidateImplementationNoOp(GLint) {} +void AbstractTexture::invalidateImageImplementationNoOp(GLint) {} #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::invalidateImplementationARB(GLint level) { +void AbstractTexture::invalidateImageImplementationARB(GLint level) { glInvalidateTexImage(_id, level); } #endif -void AbstractTexture::invalidateSubImplementationNoOp(GLint, const Vector3i&, const Vector3i&) {} +void AbstractTexture::invalidateSubImageImplementationNoOp(GLint, const Vector3i&, const Vector3i&) {} #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::invalidateSubImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size) { +void AbstractTexture::invalidateSubImageImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size) { glInvalidateTexSubImage(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z()); } #endif +#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(); + char* data = new char[dataSize]; + (this->*getImageImplementation)(target, level, image->format(), image->type(), dataSize, data); + image->setData(size, image->format(), image->type(), data); +} + +template void AbstractTexture::image<1>(GLenum, GLint, Image<1>*); +template void AbstractTexture::image<2>(GLenum, GLint, Image<2>*); +template void AbstractTexture::image<3>(GLenum, GLint, Image<3>*); + +template void AbstractTexture::image(GLenum target, GLint level, BufferImage* image, Buffer::Usage usage) { + const Math::Vector size = DataHelper::imageSize(this, target, level); + const std::size_t dataSize = size.product()*image->pixelSize(); + if(image->size() != size) + image->setData(size, image->format(), image->type(), nullptr, usage); + + image->buffer()->bind(Buffer::Target::PixelPack); + (this->*getImageImplementation)(target, level, image->format(), image->type(), dataSize, nullptr); +} + +template void AbstractTexture::image<1>(GLenum, GLint, BufferImage<1>*, Buffer::Usage); +template void AbstractTexture::image<2>(GLenum, GLint, BufferImage<2>*, Buffer::Usage); +template void AbstractTexture::image<3>(GLenum, GLint, BufferImage<3>*, Buffer::Usage); +#endif +#endif + #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_TARGET_GLES2 namespace Implementation { @@ -499,16 +534,16 @@ Vector3i AbstractTexture::DataHelper<3>::imageSize(AbstractTexture* texture, GLe } #endif -void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Array2D& wrapping) { +void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Array2D& wrapping) { #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(texture->_target != GL_TEXTURE_RECTANGLE || ((wrapping.x() == Wrapping::ClampToEdge || wrapping.x() == Wrapping::ClampToBorder) && (wrapping.y() == Wrapping::ClampToEdge || wrapping.y() == Wrapping::ClampToEdge)), "AbstractTexture: rectangle texture wrapping must either clamp 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::ClampToEdge)), "AbstractTexture: rectangle texture wrapping must either clamp to border or to edge", ); #endif (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping.x())); (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast(wrapping.y())); } -void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Array3D& wrapping) { +void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Array3D& wrapping) { (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping.x())); (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast(wrapping.y())); #ifndef MAGNUM_TARGET_GLES diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index a67b00430..912800636 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -33,7 +33,7 @@ #include "Buffer.h" #endif #include "Color.h" -#include "AbstractImage.h" +#include "Sampler.h" namespace Magnum { @@ -43,7 +43,7 @@ namespace Magnum { See Texture, CubeMapTexture and CubeMapTextureArray documentation for more information and usage examples. -@section AbstractTexture-performance-optimization Performance optimizations +@section AbstractTexture-performance-optimization Performance optimizations and security The engine tracks currently bound textures in all available layers to avoid unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. %Texture @@ -58,6 +58,12 @@ configuration and data updating functions use DSA functions to avoid unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. See respective function documentation for more information. +If extension @extension{ARB,robustness} is available, image reading operations +(such as Texture::image()) are 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. + To achieve least state changes, fully configure each texture in one run -- method chaining comes in handy -- and try to have often used textures in dedicated layers, not occupied by other textures. First configure the texture @@ -86,906 +92,6 @@ class MAGNUM_EXPORT AbstractTexture { AbstractTexture& operator=(const AbstractTexture&) = delete; public: - /** - * @brief %Texture filtering - * - * @see setMagnificationFilter() and setMinificationFilter() - */ - enum class Filter: GLint { - Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ - - /** - * Linear interpolation filtering. - * @requires_gles30 %Extension @es_extension{OES,texture_float_linear} / - * @es_extension2{OES,texture_half_float_linear,OES_texture_float_linear} - * for linear interpolation of textures with - * @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::HalfFloat" - * / @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::Float" - * in OpenGL ES 2.0. - */ - Linear = GL_LINEAR - }; - - /** - * @brief Mip level selection - * - * @see setMinificationFilter() - */ - enum class Mipmap: GLint { - Base = GL_NEAREST & ~GL_NEAREST, /**< Select base mip level */ - - /** - * Select nearest mip level. **Unavailable on rectangle textures.** - */ - Nearest = GL_NEAREST_MIPMAP_NEAREST & ~GL_NEAREST, - - /** - * Linear interpolation of nearest mip levels. **Unavailable on - * rectangle textures.** - * @requires_gles30 %Extension @es_extension{OES,texture_float_linear} / - * @es_extension2{OES,texture_half_float_linear,OES_texture_float_linear} - * for linear interpolation of textures with - * @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::HalfFloat" - * / @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::Float" - * in OpenGL ES 2.0. - */ - Linear = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST - }; - - /** - * @brief %Texture wrapping - * - * @see @ref Texture::setWrapping() "setWrapping()" - */ - enum class Wrapping: GLint { - /** Repeat texture. **Unavailable on rectangle textures.** */ - Repeat = GL_REPEAT, - - /** - * Repeat mirrored texture. **Unavailable on rectangle textures.** - */ - MirroredRepeat = GL_MIRRORED_REPEAT, - - /** - * Clamp to edge. Coordinates out of the range will be clamped to - * first / last column / row in given direction. - */ - ClampToEdge = GL_CLAMP_TO_EDGE, - - #ifndef MAGNUM_TARGET_GLES3 - /** - * Clamp to border color. Coordinates out of range will be clamped - * to border color (set with setBorderColor()). - * @requires_es_extension %Extension @es_extension{NV,texture_border_clamp} - */ - #ifndef MAGNUM_TARGET_GLES - ClampToBorder = GL_CLAMP_TO_BORDER - #else - ClampToBorder = GL_CLAMP_TO_BORDER_NV - #endif - #endif - }; - - /** - * @brief Internal format - * - * @see @ref Texture::setImage() "setImage()" - */ - enum class InternalFormat: GLint { - /** - * Red component, normalized unsigned, size implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::R8". - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} - */ - #ifndef MAGNUM_TARGET_GLES2 - Red = GL_RED, - #else - Red = GL_RED_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Red component, normalized unsigned byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::Red" - * in OpenGL ES 2.0 instead. - */ - R8 = GL_R8, - #endif - - /** - * Red and green component, normalized unsigned, size - * implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RG8". - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} - */ - #ifndef MAGNUM_TARGET_GLES2 - RG = GL_RG, - #else - RG = GL_RG_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Red and green component, each normalized unsigned byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RG" - * in OpenGL ES 2.0 instead. - */ - RG8 = GL_RG8, - #endif - - /** - * RGB, normalized unsigned, size implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RGB8". - */ - RGB = GL_RGB, - - /** - * RGB, each component normalized unsigned byte. - * @requires_gles30 %Extension @es_extension{OES,required_internalformat} - */ - #ifndef MAGNUM_TARGET_GLES2 - RGB8 = GL_RGB8, - #else - RGB8 = GL_RGB8_OES, - #endif - - /** - * RGBA, normalized unsigned, size implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RGBA8". - */ - RGBA = GL_RGBA, - - /** - * RGBA, each component normalized unsigned byte. - * @requires_gles30 %Extension @es_extension{OES,required_internalformat} - */ - #ifndef MAGNUM_TARGET_GLES2 - RGBA8 = GL_RGBA8, - #else - RGBA8 = GL_RGBA8_OES, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Red component, normalized signed byte. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gles30 Only unsigned formats are available in OpenGL - * ES 2.0. - */ - R8Snorm = GL_R8_SNORM, - - /** - * Red and green component, each normalized signed byte. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gles30 Only unsigned formats are available in OpenGL - * ES 2.0. - */ - RG8Snorm = GL_RG8_SNORM, - - /** - * RGB, each component normalized signed byte. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gles30 Only unsigned formats are available in OpenGL - * ES 2.0. - */ - RGB8Snorm = GL_RGB8_SNORM, - - /** - * RGBA, each component normalized signed byte. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gles30 Only unsigned formats are available in OpenGL - * ES 2.0. - */ - RGBA8Snorm = GL_RGBA8_SNORM, - - #ifndef MAGNUM_TARGET_GLES - /** - * Red component, normalized unsigned short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - R16 = GL_R16, - - /** - * Red and green component, each normalized unsigned short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RG16 = GL_RG16, - - /** - * RGB, each component normalized unsigned short. - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RGB16 = GL_RGB16, - - /** - * RGBA, each component normalized unsigned short. - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RGBA16 = GL_RGBA16, - - /** - * Red component, normalized signed short. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - R16Snorm = GL_R16_SNORM, - - /** - * Red and green component, each normalized signed short. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RG16Snorm = GL_RG16_SNORM, - - /** - * RGB, each component normalized signed short. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RGB16Snorm = GL_RGB16_SNORM, - - /** - * RGBA, each component normalized signed short. - * @requires_gl31 %Extension @extension{EXT,texture_snorm} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RGBA16Snorm = GL_RGBA16_SNORM, - #endif - - /** - * Red component, non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R8UI = GL_R8UI, - - /** - * Red and green component, each non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG8UI = GL_RG8UI, - - /** - * RGB, each component non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB8UI = GL_RGB8UI, - - /** - * RGBA, each component non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA8UI = GL_RGBA8UI, - - /** - * Red component, non-normalized signed byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R8I = GL_R8I, - - /** - * Red and green component, each non-normalized signed byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG8I = GL_RG8I, - - /** - * RGB, each component non-normalized signed byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB8I = GL_RGB8I, - - /** - * RGBA, each component non-normalized signed byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA8I = GL_RGBA8I, - - /** - * Red component, non-normalized unsigned short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R16UI = GL_R16UI, - - /** - * Red and green component, each non-normalized unsigned short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG16UI = GL_RG16UI, - - /** - * RGB, each component non-normalized unsigned short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB16UI = GL_RGB16UI, - - /** - * RGBA, each component non-normalized unsigned short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA16UI = GL_RGBA16UI, - - /** - * Red component, non-normalized signed short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R16I = GL_R16I, - - /** - * Red and green component, each non-normalized signed short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG16I = GL_RG16I, - - /** - * RGB, each component non-normalized signed short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB16I = GL_RGB16I, - - /** - * RGBA, each component non-normalized signed short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA16I = GL_RGBA16I, - - /** - * Red component, non-normalized unsigned int. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R32UI = GL_R32UI, - - /** - * Red and green component, each non-normalized unsigned int. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG32UI = GL_RG32UI, - - /** - * RGB, each component non-normalized unsigned int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB32UI = GL_RGB32UI, - - /** - * RGBA, each component non-normalized unsigned int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA32UI = GL_RGBA32UI, - - /** - * Red component, non-normalized signed int. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R32I = GL_R32I, - - /** - * Red and green component, each non-normalized signed int. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG32I = GL_RG32I, - - /** - * RGB, each component non-normalized signed int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB32I = GL_RGB32I, - - /** - * RGBA, each component non-normalized signed int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA32I = GL_RGBA32I, - - /** - * Red component, half float. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R16F = GL_R16F, - - /** - * Red and green component, each half float. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG16F = GL_RG16F, - - /** - * RGB, each component half float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB16F = GL_RGB16F, - - /** - * RGBA, each component half float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA16F = GL_RGBA16F, - - /** - * Red component, float. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R32F = GL_R32F, - - /** - * Red and green component, each float. - * @requires_gl30 %Extension @extension{ARB,texture_rg} and - * @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG32F = GL_RG32F, - - /** - * RGB, each component float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB32F = GL_RGB32F, - - /** - * RGBA, each component float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA32F = GL_RGBA32F, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * RGB, normalized unsigned, red and green component 3bit, blue - * 2bit. - * @requires_gl Packed 8bit types are not available in OpenGL ES. - */ - R3B3G2 = GL_R3_G3_B2, - - /** - * RGB, each component normalized unsigned 4bit. - * @requires_gl Packed 12bit types are not available in OpenGL ES. - */ - RGB4 = GL_RGB4, - - /** - * RGB, each component normalized unsigned 5bit. - * @requires_gl Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RGB5A1" - * or @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RGB565" in OpenGL ES. - */ - RGB5 = GL_RGB5, - #endif - - /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is - GL_ARB_ES2_compatibility */ - #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT) - /** - * RGB, normalized unsigned, red and blue component 5bit, green 6bit. - * @requires_gles30 %Extension @es_extension{OES,required_internalformat} - */ - RGB565 = GL_RGB565, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * RGB, each component normalized unsigned 10bit. - * @requires_es_extension %Extension @es_extension{OES,required_internalformat} - * and @es_extension{EXT,texture_type_2_10_10_10_REV} - */ - #ifndef MAGNUM_TARGET_GLES - RGB10 = GL_RGB10, - #else - RGB10 = GL_RGB10_EXT, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * RGB, each component normalized unsigned 12bit. - * @requires_gl Packed 36bit types are not available in OpenGL ES. - */ - RGB12 = GL_RGB12, - - /** - * RGBA, normalized unsigned, each component 2bit. - * @requires_gl Packed 8bit types are not available in OpenGL ES. - */ - RGBA2 = GL_RGBA2, - #endif - - /** - * RGBA, normalized unsigned, each component 4bit. - * @requires_gles30 %Extension @es_extension{OES,required_internalformat} - */ - RGBA4 = GL_RGBA4, - - /** - * RGBA, normalized unsigned, each RGB component 5bit, alpha 1bit. - * @requires_gles30 %Extension @es_extension{OES,required_internalformat} - */ - 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} - */ - #ifndef MAGNUM_TARGET_GLES2 - RGB10A2 = GL_RGB10_A2, - #else - RGB10A2 = GL_RGB10_A2_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * RGBA, non-normalized unsigned, each RGB component 10bit, alpha - * 2bit. - * @requires_gl33 %Extension @extension{ARB,texture_rgb10_a2ui} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB10A2UI = GL_RGB10_A2UI, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * RGBA, each component normalized unsigned 12bit. - * @requires_gl Packed 48bit types are not available in OpenGL ES. - */ - RGBA12 = GL_RGBA12, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * RGB, float, red and green component 11bit, blue 10bit. - * @requires_gl30 %Extension @extension{EXT,packed_float} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R11FG11FB10F = GL_R11F_G11F_B10F, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * RGB, unsigned with exponent, each RGB component 9bit, exponent 5bit. - * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} - * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RGB" - * in OpenGL ES 2.0 instead. - */ - RGB9E5 = GL_RGB9_E5, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * sRGB, normalized unsigned, size implementation-dependent. - * @todo is this allowed in core? - * @deprecated Prefer to use the exactly specified version of this - * format, i.e. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGB8". - * @requires_es_extension %Extension @es_extension{EXT,sRGB} in - * OpenGL ES 2.0, use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGB8" - * in OpenGL ES 3.0 instead. - */ - #ifndef MAGNUM_TARGET_GLES - SRGB = GL_SRGB, - #else - SRGB = GL_SRGB_EXT, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * sRGB, each component normalized unsigned byte. - * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGB" - * in OpenGL ES 2.0 instead. - */ - SRGB8 = GL_SRGB8, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * sRGBA, normalized unsigned, size implementation-dependent. - * @todo is this allowed in core? - * @deprecated Prefer to use the exactly specified version of this - * format, i.e. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGB8Alpha8". - * @requires_es_extension %Extension @es_extension{EXT,sRGB} in - * OpenGL ES 2.0, use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGB8Alpha8" - * in OpenGL ES 3.0 instead. - */ - #ifndef MAGNUM_TARGET_GLES - SRGBAlpha = GL_SRGB_ALPHA, - #else - SRGBAlpha = GL_SRGB_ALPHA_EXT, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * sRGBA, each component normalized unsigned byte. - * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGBAlpha" - * in OpenGL ES 2.0 instead. - */ - SRGB8Alpha8 = GL_SRGB8_ALPHA8, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Compressed red channel, normalized unsigned. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Generic texture compression is not available in - * OpenGL ES. - */ - CompressedRed = GL_COMPRESSED_RED, - - /** - * Compressed red and green channel, normalized unsigned. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Generic texture compression is not available in - * OpenGL ES. - */ - CompressedRG = GL_COMPRESSED_RG, - - /** - * Compressed RGB, normalized unsigned. - * @requires_gl Generic texture compression is not available in - * OpenGL ES. - */ - CompressedRGB = GL_COMPRESSED_RGB, - - /** - * Compressed RGBA, normalized unsigned. - * @requires_gl Generic texture compression is not available in - * OpenGL ES. - */ - CompressedRGBA = GL_COMPRESSED_RGBA, - - /** - * RTGC compressed red channel, normalized unsigned. - * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} - * @requires_gl RGTC texture compression is not available in - * OpenGL ES. - */ - CompressedRedRtgc1 = GL_COMPRESSED_RED_RGTC1, - - /** - * RTGC compressed red and green channel, normalized unsigned. - * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} - * @requires_gl RGTC texture compression is not available in - * OpenGL ES. - */ - CompressedRGRgtc2 = GL_COMPRESSED_RG_RGTC2, - - /** - * RTGC compressed red channel, normalized signed. - * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} - * @requires_gl RGTC texture compression is not available in - * OpenGL ES. - */ - CompressedSignedRedRgtc1 = GL_COMPRESSED_SIGNED_RED_RGTC1, - - /** - * RTGC compressed red and green channel, normalized signed. - * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} - * @requires_gl RGTC texture compression is not available in - * OpenGL ES. - */ - CompressedSignedRGRgtc2 = GL_COMPRESSED_SIGNED_RG_RGTC2, - - /* These are named with _ARB suffix, because glcorearb.h doesn't - have suffixless version (?!) and GLEW has it without suffix as - late as of 1.8.0 { */ - - /** - * BPTC compressed RGBA, normalized unsigned. - * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} - * @requires_gl BPTC texture compression is not available in - * OpenGL ES. - */ - CompressedRGBABtpcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, - - /** - * BPTC compressed sRGBA, normalized unsigned. - * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} - * @requires_gl BPTC texture compression is not available in - * OpenGL ES. - */ - CompressedSRGBAlphaBtpcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, - - /** - * BPTC compressed RGB, unsigned float. - * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} - * @requires_gl BPTC texture compression is not available in - * OpenGL ES. - */ - CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, - - /** - * BPTC compressed RGB, signed float. - * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} - * @requires_gl BPTC texture compression is not available in - * OpenGL ES. - */ - CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, - - /*}*/ - #endif - - /** - * Depth component, size implementation-dependent. - * @deprecated Prefer to use exactly specified version of this - * format, e.g. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::DepthComponent16". - * @requires_gles30 %Extension @es_extension{OES,depth_texture} or - * @es_extension{ANGLE,depth_texture} - */ - DepthComponent = GL_DEPTH_COMPONENT, - - /** - * Depth and stencil component, size implementation-dependent. - * @deprecated Prefer to use exactly specified version of this - * format, e.g. @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::Depth24Stencil8". - * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} - */ - #ifndef MAGNUM_TARGET_GLES2 - DepthStencil = GL_DEPTH_STENCIL, - #else - DepthStencil = GL_DEPTH_STENCIL_OES, - #endif - - /** - * Depth component, 16bit. - * @requires_gles30 %Extension (@es_extension{OES,required_internalformat} - * and @es_extension{OES,depth_texture}) or (@es_extension{EXT,texture_storage} - * and @es_extension{ANGLE,depth_texture}) - */ - DepthComponent16 = GL_DEPTH_COMPONENT16, - - /** - * Depth component, 24bit. - * @requires_gles30 %Extension @es_extension{OES,required_internalformat}, - * @es_extension{OES,depth_texture} and @es_extension{OES,depth24} - */ - #ifndef MAGNUM_TARGET_GLES2 - DepthComponent24 = GL_DEPTH_COMPONENT24, - #else - DepthComponent24 = GL_DEPTH_COMPONENT24_OES, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * Depth component, 32bit. - * @requires_es_extension %Extension (@es_extension{OES,required_internalformat}, - * @es_extension{OES,depth_texture} and @es_extension{OES,depth32}) - * or (@es_extension{EXT,texture_storage} and @es_extension{ANGLE,depth_texture}) - */ - #ifndef MAGNUM_TARGET_GLES2 - DepthComponent32 = GL_DEPTH_COMPONENT32, - #else - DepthComponent32 = GL_DEPTH_COMPONENT32_OES, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Depth component, 32bit float. - * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} - * @requires_gles30 Only integral depth textures are available in - * OpenGL ES 2.0. - */ - DepthComponent32F = GL_DEPTH_COMPONENT32F, - #endif - - /** - * 24bit depth and 8bit stencil component. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} - * @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})) - */ - #ifdef MAGNUM_TARGET_GLES2 - Depth24Stencil8 = GL_DEPTH24_STENCIL8_OES - #else - Depth24Stencil8 = GL_DEPTH24_STENCIL8, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * 32bit float depth component and 8bit stencil component. - * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} - * @requires_gles30 Only integral depth textures are available in - * OpenGL ES 2.0. - */ - Depth32FStencil8 = GL_DEPTH32F_STENCIL8 - #endif - }; - /** * @brief Max supported layer count * @@ -997,21 +103,8 @@ class MAGNUM_EXPORT AbstractTexture { */ static Int maxSupportedLayerCount(); - #ifndef MAGNUM_TARGET_GLES3 - /** - * @brief Max supported anisotropy - * - * The result is cached, repeated queries don't result in repeated - * OpenGL calls. - * @see setMaxAnisotropy(), @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT} - * @requires_extension %Extension @extension{EXT,texture_filter_anisotropic} - * @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic} - */ - static Float maxSupportedAnisotropy(); - #endif - #ifndef DOXYGEN_GENERATING_OUTPUT - inline explicit AbstractTexture(GLenum target): _target(target) { + explicit AbstractTexture(GLenum target): _target(target) { glGenTextures(1, &_id); } #endif @@ -1031,7 +124,7 @@ class MAGNUM_EXPORT AbstractTexture { AbstractTexture& operator=(AbstractTexture&& other); /** @brief OpenGL texture ID */ - inline GLuint id() const { return _id; } + GLuint id() const { return _id; } /** * @brief Bind texture for rendering @@ -1057,17 +150,16 @@ class MAGNUM_EXPORT AbstractTexture { * 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 AbstractTexture::Filter "Filter::Nearest", - * @ref AbstractTexture::Mipmap "Mipmap::Linear"). + * Initial value is (@ref Sampler::Filter "Sampler::Filter::Nearest", + * @ref Sampler::Mipmap "Sampler::Mipmap::Linear"). * @attention For rectangle textures only some modes are supported, - * see @ref AbstractTexture::Filter "Filter" and - * @ref AbstractTexture::Mipmap "Mipmap" documentation for more - * information. + * see @ref Sampler::Filter "Sampler::Filter" and @ref Sampler::Mipmap "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(Filter filter, Mipmap mipmap = Mipmap::Base); + AbstractTexture* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base); /** * @brief Set magnification filter @@ -1077,12 +169,12 @@ class MAGNUM_EXPORT AbstractTexture { * 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 AbstractTexture::Filter "Filter::Linear". + * Initial value is @ref Sampler::Filter "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} */ - inline AbstractTexture* setMagnificationFilter(Filter filter) { + AbstractTexture* setMagnificationFilter(Sampler::Filter filter) { (this->*parameteriImplementation)(GL_TEXTURE_MAG_FILTER, static_cast(filter)); return this; } @@ -1092,16 +184,16 @@ class MAGNUM_EXPORT AbstractTexture { * @brief Set border color * @return Pointer to self (for method chaining) * - * Border color when @ref AbstractTexture::Wrapping "wrapping" is set - * to `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}`. + * Border color when wrapping is set to @ref Sampler::Wrapping "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} */ - inline AbstractTexture* setBorderColor(const Color4<>& color) { + AbstractTexture* setBorderColor(const Color4<>& color) { #ifndef MAGNUM_TARGET_GLES (this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data()); #else @@ -1125,7 +217,7 @@ class MAGNUM_EXPORT AbstractTexture { * @requires_extension %Extension @extension{EXT,texture_filter_anisotropic} * @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic} */ - inline AbstractTexture* setMaxAnisotropy(Float anisotropy) { + AbstractTexture* setMaxAnisotropy(Float anisotropy) { (this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); return this; } @@ -1140,8 +232,8 @@ class MAGNUM_EXPORT AbstractTexture { * @see @ref Texture::invalidateSubImage() "invalidateSubImage()", * @fn_gl{InvalidateTexImage} */ - inline void invalidateImage(Int level) { - (this->*invalidateImplementation)(level); + void invalidateImage(Int level) { + (this->*invalidateImageImplementation)(level); } /** @@ -1158,16 +250,23 @@ class MAGNUM_EXPORT AbstractTexture { */ AbstractTexture* generateMipmap(); + #ifdef DOXYGEN_GENERATING_OUTPUT + private: + #else protected: - #ifndef DOXYGEN_GENERATING_OUTPUT + #endif template struct DataHelper {}; /* Unlike bind() this also sets the binding layer as active */ void MAGNUM_LOCAL bindInternal(); - GLenum _target; + #ifndef MAGNUM_TARGET_GLES + template void MAGNUM_LOCAL image(GLenum target, GLint level, Image* image); + template void MAGNUM_LOCAL image(GLenum target, GLint level, BufferImage* image, Buffer::Usage usage); #endif + GLenum _target; + private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); @@ -1214,81 +313,89 @@ class MAGNUM_EXPORT AbstractTexture { static MAGNUM_LOCAL MipmapImplementation mipmapImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*Storage1DImplementation)(GLenum, GLsizei, InternalFormat, const Math::Vector<1, GLsizei>&); - void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size); - void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size); + typedef void(AbstractTexture::*Storage1DImplementation)(GLenum, GLsizei, TextureFormat, const Math::Vector<1, GLsizei>&); + 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, InternalFormat, const Vector2i&); - void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector2i& size); + typedef void(AbstractTexture::*Storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&); + 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, InternalFormat internalFormat, const Vector2i& size); + void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); #endif static Storage2DImplementation storage2DImplementation; - typedef void(AbstractTexture::*Storage3DImplementation)(GLenum, GLsizei, InternalFormat, const Vector3i&); - void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector3i& size); + typedef void(AbstractTexture::*Storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&); + 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, InternalFormat internalFormat, const Vector3i& size); + void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); #endif static Storage3DImplementation storage3DImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*Image1DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector<1, GLsizei>&, AbstractImage::Format, AbstractImage::Type, const GLvoid*); - void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); - void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + typedef void(AbstractTexture::*GetImageImplementation)(GLenum, GLint, ImageFormat, ImageType, std::size_t, GLvoid*); + void MAGNUM_LOCAL getImageImplementationDefault(GLenum target, GLint level, ImageFormat format, ImageType type, std::size_t dataSize, GLvoid* data); + void MAGNUM_LOCAL getImageImplementationDSA(GLenum target, GLint level, ImageFormat format, ImageType type, std::size_t dataSize, GLvoid* data); + void MAGNUM_LOCAL getImageImplementationRobustness(GLenum target, GLint level, ImageFormat format, ImageType 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>&, ImageFormat, ImageType, const GLvoid*); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data); static Image1DImplementation image1DImplementation; #endif - typedef void(AbstractTexture::*Image2DImplementation)(GLenum, GLint, InternalFormat, const Vector2i&, AbstractImage::Format, AbstractImage::Type, const GLvoid*); - void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + typedef void(AbstractTexture::*Image2DImplementation)(GLenum, GLint, TextureFormat, const Vector2i&, ImageFormat, ImageType, const GLvoid*); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data); #endif static Image2DImplementation image2DImplementation; - typedef void(AbstractTexture::*Image3DImplementation)(GLenum, GLint, InternalFormat, const Vector3i&, AbstractImage::Format, AbstractImage::Type, const GLvoid*); - void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + typedef void(AbstractTexture::*Image3DImplementation)(GLenum, GLint, TextureFormat, const Vector3i&, ImageFormat, ImageType, const GLvoid*); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ImageFormat format, ImageType 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>&, AbstractImage::Format, AbstractImage::Type, const GLvoid*); - void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); - void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + typedef void(AbstractTexture::*SubImage1DImplementation)(GLenum, GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, ImageFormat, ImageType, const GLvoid*); + void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data); + void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ImageFormat format, ImageType type, const GLvoid* data); static SubImage1DImplementation subImage1DImplementation; #endif - typedef void(AbstractTexture::*SubImage2DImplementation)(GLenum, GLint, const Vector2i&, const Vector2i&, AbstractImage::Format, AbstractImage::Type, const GLvoid*); - void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + typedef void(AbstractTexture::*SubImage2DImplementation)(GLenum, GLint, const Vector2i&, const Vector2i&, ImageFormat, ImageType, const GLvoid*); + void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ImageFormat format, ImageType type, const GLvoid* data); #endif static SubImage2DImplementation subImage2DImplementation; - typedef void(AbstractTexture::*SubImage3DImplementation)(GLenum, GLint, const Vector3i&, const Vector3i&, AbstractImage::Format, AbstractImage::Type, const GLvoid*); - void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + typedef void(AbstractTexture::*SubImage3DImplementation)(GLenum, GLint, const Vector3i&, const Vector3i&, ImageFormat, ImageType, const GLvoid*); + void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data); + void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ImageFormat format, ImageType type, const GLvoid* data); #endif static SubImage3DImplementation subImage3DImplementation; - typedef void(AbstractTexture::*InvalidateImplementation)(GLint); - void MAGNUM_LOCAL invalidateImplementationNoOp(GLint level); + typedef void(AbstractTexture::*InvalidateImageImplementation)(GLint); + void MAGNUM_LOCAL invalidateImageImplementationNoOp(GLint level); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL invalidateImplementationARB(GLint level); + void MAGNUM_LOCAL invalidateImageImplementationARB(GLint level); #endif - static InvalidateImplementation invalidateImplementation; + static InvalidateImageImplementation invalidateImageImplementation; - typedef void(AbstractTexture::*InvalidateSubImplementation)(GLint, const Vector3i&, const Vector3i&); - void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLint level, const Vector3i& offset, const Vector3i& size); + 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 invalidateSubImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size); + void MAGNUM_LOCAL invalidateSubImageImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size); #endif - static InvalidateSubImplementation invalidateSubImplementation; + static InvalidateSubImageImplementation invalidateSubImageImplementation; void MAGNUM_LOCAL destroy(); void MAGNUM_LOCAL move(); @@ -1299,7 +406,7 @@ class MAGNUM_EXPORT AbstractTexture { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct ImageHelper { - inline static const GLvoid* dataOrPixelUnpackBuffer(Image* image) { + static const GLvoid* dataOrPixelUnpackBuffer(Image* image) { #ifndef MAGNUM_TARGET_GLES2 Buffer::unbind(Buffer::Target::PixelUnpack); #endif @@ -1320,105 +427,108 @@ template<> struct AbstractTexture::DataHelper<1> { Texture1D = GL_TEXTURE_1D }; - inline constexpr static Target target() { return Target::Texture1D; } + constexpr static Target target() { return Target::Texture1D; } static Math::Vector<1, GLint> imageSize(AbstractTexture* texture, GLenum target, GLint level); - inline static void setWrapping(AbstractTexture* texture, const Array1D& wrapping) { + static void setWrapping(AbstractTexture* texture, const Array1D& wrapping) { (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping.x())); } - inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size) { + static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) { (texture->*storage1DImplementation)(target, levels, internalFormat, size); } - template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat internalFormat, Image* image) { + template static typename std::enable_if::type setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, Image* image) { (texture->*image1DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, Image* image) { + template static typename std::enable_if::type setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, Image* image) { (texture->*subImage1DImplementation)(target, level, offset, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - inline static void invalidateSub(AbstractTexture* texture, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLint>& size) { - (texture->*invalidateSubImplementation)(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) { + (texture->*invalidateSubImageImplementation)(level, {offset[0], 0, 0}, {size[0], 1, 1}); } }; #endif template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { enum class Target: GLenum { - Texture2D = GL_TEXTURE_2D + Texture2D = GL_TEXTURE_2D, #ifndef MAGNUM_TARGET_GLES - , + Texture2DMultisample = GL_TEXTURE_2D_MULTISAMPLE, Texture1DArray = GL_TEXTURE_1D_ARRAY, Rectangle = GL_TEXTURE_RECTANGLE #endif }; - inline constexpr static Target target() { return Target::Texture2D; } + constexpr static Target target() { return Target::Texture2D; } #ifndef MAGNUM_TARGET_GLES 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); - inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector2i& size) { + static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) { (texture->*storage2DImplementation)(target, levels, internalFormat, size); } - template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat internalFormat, Image* image) { + template static typename std::enable_if::type setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, Image* image) { (texture->*image2DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, Image* image) { + template static typename std::enable_if::type setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, Image* image) { (texture->*subImage2DImplementation)(target, level, offset, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, Image* image) { + template static typename std::enable_if::type setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, Image* image) { (texture->*subImage2DImplementation)(target, level, offset, Vector2i(image->size(), 1), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - inline static void invalidateSub(AbstractTexture* texture, GLint level, const Vector2i& offset, const Vector2i& size) { - (texture->*invalidateSubImplementation)(level, {offset, 0}, {size, 1}); + static void invalidateSubImage(AbstractTexture* texture, GLint level, const Vector2i& offset, const Vector2i& size) { + (texture->*invalidateSubImageImplementation)(level, {offset, 0}, {size, 1}); } }; template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { enum class Target: GLenum { #ifndef MAGNUM_TARGET_GLES2 Texture3D = GL_TEXTURE_3D, - Texture2DArray = GL_TEXTURE_2D_ARRAY + Texture2DArray = GL_TEXTURE_2D_ARRAY, + #ifndef MAGNUM_TARGET_GLES + Texture2DMultisampleArray = GL_TEXTURE_2D_MULTISAMPLE_ARRAY, + #endif #else Texture3D = GL_TEXTURE_3D_OES #endif }; - inline constexpr static Target target() { return Target::Texture3D; } + constexpr static Target target() { return Target::Texture3D; } #ifndef MAGNUM_TARGET_GLES 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); - inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector3i& size) { + static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { (texture->*storage3DImplementation)(target, levels, internalFormat, size); } - template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat internalFormat, Image* image) { + template static typename std::enable_if::type setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, Image* image) { (texture->*image3DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, Image* image) { + template static typename std::enable_if::type setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, Image* image) { (texture->*subImage3DImplementation)(target, level, offset, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, Image* image) { + template static typename std::enable_if::type setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, Image* image) { (texture->*subImage3DImplementation)(target, level, offset, Vector3i(image->size(), 1), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); } - inline static void invalidateSub(AbstractTexture* texture, GLint level, const Vector3i& offset, const Vector3i& size) { - (texture->*invalidateSubImplementation)(level, offset, size); + static void invalidateSubImage(AbstractTexture* texture, GLint level, const Vector3i& offset, const Vector3i& size) { + (texture->*invalidateSubImageImplementation)(level, offset, size); } }; #endif diff --git a/src/Array.h b/src/Array.h index 5c79267e2..b2099a88a 100644 --- a/src/Array.h +++ b/src/Array.h @@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. */ -/** @file +/** @file /Array.h * @brief Class Magnum::Array, Magnum::Array1D, Magnum::Array2D, Magnum::Array3D */ @@ -55,7 +55,7 @@ template class Array { * * Sets all components to their default-constructed values */ - inline constexpr /*implicit*/ Array(): _data() {} + constexpr /*implicit*/ Array(): _data() {} /** * @brief Initializer-list constructor @@ -63,45 +63,45 @@ template class Array { * @param next Next values */ #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr /*implicit*/ Array(T first, T second, U... next): _data{first, second, next...} { + template constexpr /*implicit*/ Array(T first, T second, U... next): _data{first, second, next...} { static_assert(sizeof...(next)+2 == dimensions, "Improper number of arguments passed to Array constructor"); } - template inline constexpr /*implicit*/ Array(typename std::enable_if::value && dimensions == 1, U>::type first): _data{first} {} + template constexpr /*implicit*/ Array(typename std::enable_if::value && dimensions == 1, U>::type first): _data{first} {} #else - template inline constexpr /*implicit*/ Array(T first, U... next); + template constexpr /*implicit*/ Array(T first, U... next); #endif /** * @brief Constructor * @param value Value for all fields */ - template::value && dimensions != 1, U>::type> inline /*implicit*/ Array(U value) { + template::value && dimensions != 1, U>::type> /*implicit*/ Array(U value) { for(UnsignedInt i = 0; i != dimensions; ++i) _data[i] = value; } /** @brief Equality */ - inline bool operator==(const Array& other) const { + bool operator==(const Array& other) const { for(UnsignedInt i = 0; i != dimensions; ++i) if(_data[i] != other._data[i]) return false; return true; } /** @brief Non-equality */ - inline bool operator!=(const Array& other) const { + bool operator!=(const Array& other) const { return !operator==(other); } /** @brief Value at given position */ - inline T& operator[](UnsignedInt pos) { return _data[pos]; } - inline constexpr T operator[](UnsignedInt pos) const { return _data[pos]; } /**< @overload */ + T& operator[](UnsignedInt pos) { return _data[pos]; } + constexpr T operator[](UnsignedInt pos) const { return _data[pos]; } /**< @overload */ /** * @brief Raw data * @return One-dimensional array of `dimensions` length */ - inline T* data() { return _data; } - inline constexpr const T* data() const { return _data; } /**< @overload */ + T* data() { return _data; } + constexpr const T* data() const { return _data; } /**< @overload */ private: T _data[dimensions]; @@ -114,19 +114,19 @@ template class Array { template class Array1D: public Array<1, T> { public: /** @copydoc Array::Array() */ - inline constexpr /*implicit*/ Array1D() = default; + constexpr /*implicit*/ Array1D() = default; /** * @brief Constructor * @param x X component */ - inline constexpr /*implicit*/ Array1D(T x): Array<1, T>(x) {} + constexpr /*implicit*/ Array1D(T x): Array<1, T>(x) {} /** @brief Copy constructor */ - inline constexpr Array1D(const Array<1, T>& other): Array<1, T>(other) {} + constexpr Array1D(const Array<1, T>& other): Array<1, T>(other) {} - inline T& x() { return (*this)[0]; } /**< @brief X component */ - inline constexpr T x() const { return (*this)[0]; } /**< @overload */ + T& x() { return (*this)[0]; } /**< @brief X component */ + constexpr T x() const { return (*this)[0]; } /**< @overload */ }; /** @@ -136,25 +136,25 @@ template class Array1D: public Array<1, T> { template class Array2D: public Array<2, T> { public: /** @copydoc Array::Array() */ - inline constexpr /*implicit*/ Array2D() = default; + constexpr /*implicit*/ Array2D() = default; /** * @brief Constructor * @param x X component * @param y Y component */ - inline constexpr /*implicit*/ Array2D(T x, T y): Array<2, T>(x, y) {} + constexpr /*implicit*/ Array2D(T x, T y): Array<2, T>(x, y) {} /** @copydoc Array::Array(U) */ - inline constexpr /*implicit*/ Array2D(T value): Array<2, T>(value, value) {} + constexpr /*implicit*/ Array2D(T value): Array<2, T>(value, value) {} /** @brief Copy constructor */ - inline constexpr Array2D(const Array<2, T>& other): Array<2, T>(other) {} + constexpr Array2D(const Array<2, T>& other): Array<2, T>(other) {} - inline T& x() { return (*this)[0]; } /**< @brief X component */ - inline constexpr T x() const { return (*this)[0]; } /**< @overload */ - inline T& y() { return (*this)[1]; } /**< @brief Y component */ - inline constexpr T y() const { return (*this)[1]; } /**< @overload */ + T& x() { return (*this)[0]; } /**< @brief X component */ + constexpr T x() const { return (*this)[0]; } /**< @overload */ + T& y() { return (*this)[1]; } /**< @brief Y component */ + constexpr T y() const { return (*this)[1]; } /**< @overload */ }; /** @@ -164,7 +164,7 @@ template class Array2D: public Array<2, T> { template class Array3D: public Array<3, T> { public: /** @copydoc Array::Array() */ - inline constexpr /*implicit*/ Array3D() {} + constexpr /*implicit*/ Array3D() {} /** * @brief Constructor @@ -172,20 +172,20 @@ template class Array3D: public Array<3, T> { * @param y Y component * @param z Z component */ - inline constexpr /*implicit*/ Array3D(T x, T y, T z): Array<3, T>(x, y, z) {} + constexpr /*implicit*/ Array3D(T x, T y, T z): Array<3, T>(x, y, z) {} /** @copydoc Array::Array(U) */ - inline constexpr /*implicit*/ Array3D(T value): Array<3, T>(value, value, value) {} + constexpr /*implicit*/ Array3D(T value): Array<3, T>(value, value, value) {} /** @brief Copy constructor */ - inline constexpr Array3D(const Array<3, T>& other): Array<3, T>(other) {} - - inline T& x() { return (*this)[0]; } /**< @brief X component */ - inline constexpr T x() const { return (*this)[0]; } /**< @overload */ - inline T& y() { return (*this)[1]; } /**< @brief Y component */ - inline constexpr T y() const { return (*this)[1]; } /**< @overload */ - inline T& z() { return (*this)[2]; } /**< @brief Z component */ - inline constexpr T z() const { return (*this)[2]; } /**< @overload */ + constexpr Array3D(const Array<3, T>& other): Array<3, T>(other) {} + + T& x() { return (*this)[0]; } /**< @brief X component */ + constexpr T x() const { return (*this)[0]; } /**< @overload */ + T& y() { return (*this)[1]; } /**< @brief Y component */ + constexpr T y() const { return (*this)[1]; } /**< @overload */ + T& z() { return (*this)[2]; } /**< @brief Z component */ + constexpr T z() const { return (*this)[2]; } /**< @overload */ }; /** @debugoperator{Magnum::Array} */ diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 4c2e18718..1bdbaa335 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -24,6 +24,7 @@ #include "Buffer.h" +#include #include #include "Context.h" @@ -36,8 +37,12 @@ namespace Magnum { #ifndef MAGNUM_TARGET_GLES2 Buffer::CopyImplementation Buffer::copyImplementation = &Buffer::copyImplementationDefault; #endif -Buffer::SetDataImplementation Buffer::setDataImplementation = &Buffer::setDataImplementationDefault; -Buffer::SetSubDataImplementation Buffer::setSubDataImplementation = &Buffer::setSubDataImplementationDefault; +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; #ifndef MAGNUM_TARGET_GLES3 @@ -53,8 +58,10 @@ void Buffer::initializeContextBasedFunctionality(Context* context) { Debug() << "Buffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; copyImplementation = &Buffer::copyImplementationDSA; - setDataImplementation = &Buffer::setDataImplementationDSA; - setSubDataImplementation = &Buffer::setSubDataImplementationDSA; + getParameterImplementation = &Buffer::getParameterImplementationDSA; + getSubDataImplementation = &Buffer::getSubDataImplementationDSA; + dataImplementation = &Buffer::dataImplementationDSA; + subDataImplementation = &Buffer::subDataImplementationDSA; mapImplementation = &Buffer::mapImplementationDSA; mapRangeImplementation = &Buffer::mapRangeImplementationDSA; flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDSA; @@ -101,8 +108,9 @@ Buffer::Target Buffer::bindInternal(Target hint) { if(hintBinding == _id) return hint; /* Return first target in which the buffer is bound */ + /** @todo wtf there is one more? */ for(std::size_t i = 1; i != Implementation::BufferState::TargetCount; ++i) - if(bindings[i] == _id) return Implementation::BufferState::targetForIndex[i]; + if(bindings[i] == _id) return Implementation::BufferState::targetForIndex[i-1]; /* Bind the buffer to hint target otherwise */ hintBinding = _id; @@ -110,6 +118,28 @@ Buffer::Target Buffer::bindInternal(Target hint) { return hint; } +Int Buffer::size() { + /** + * @todo there is something like glGetBufferParameteri64v in 3.2 (I + * couldn't find any matching extension, though) + */ + GLint size; + (this->*getParameterImplementation)(GL_BUFFER_SIZE, &size); + return size; +} + +#ifndef MAGNUM_TARGET_GLES +Containers::Array Buffer::data() { + return subData(0, size()); +} + +Containers::Array Buffer::subData(const GLintptr offset, const GLsizeiptr size) { + Containers::Array data(size); + if(size) (this->*getSubDataImplementation)(offset, size, data); + return std::move(data); +} +#endif + #ifndef MAGNUM_TARGET_GLES2 void Buffer::copyImplementationDefault(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { glCopyBufferSubData(static_cast(read->bindInternal(Target::CopyRead)), static_cast(write->bindInternal(Target::CopyWrite)), readOffset, writeOffset, size); @@ -122,22 +152,42 @@ void Buffer::copyImplementationDSA(Buffer* read, Buffer* write, GLintptr readOff #endif #endif -void Buffer::setDataImplementationDefault(GLsizeiptr size, const GLvoid* data, Buffer::Usage usage) { +void Buffer::getParameterImplementationDefault(const GLenum value, GLint* const data) { + glGetBufferParameteriv(GLenum(bindInternal(_targetHint)), value, data); +} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::getParameterImplementationDSA(const GLenum value, GLint* const data) { + glGetNamedBufferParameterivEXT(_id, value, data); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void Buffer::getSubDataImplementationDefault(const GLintptr offset, const GLsizeiptr size, GLvoid* const data) { + glGetBufferSubData(GLenum(bindInternal(_targetHint)), offset, size, data); +} + +void Buffer::getSubDataImplementationDSA(const GLintptr offset, const GLsizeiptr size, GLvoid* const data) { + glGetNamedBufferSubDataEXT(_id, offset, size, data); +} +#endif + +void Buffer::dataImplementationDefault(GLsizeiptr size, const GLvoid* data, Buffer::Usage usage) { glBufferData(static_cast(bindInternal(_targetHint)), size, data, static_cast(usage)); } #ifndef MAGNUM_TARGET_GLES -void Buffer::setDataImplementationDSA(GLsizeiptr size, const GLvoid* data, Buffer::Usage usage) { +void Buffer::dataImplementationDSA(GLsizeiptr size, const GLvoid* data, Buffer::Usage usage) { glNamedBufferDataEXT(_id, size, data, static_cast(usage)); } #endif -void Buffer::setSubDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data) { +void Buffer::subDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data) { glBufferSubData(static_cast(bindInternal(_targetHint)), offset, size, data); } #ifndef MAGNUM_TARGET_GLES -void Buffer::setSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data) { +void Buffer::subDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data) { glNamedBufferSubDataEXT(_id, offset, size, data); } #endif diff --git a/src/Buffer.h b/src/Buffer.h index 63be6124e..9ef4d2c9f 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "Magnum.h" @@ -428,7 +429,7 @@ class MAGNUM_EXPORT Buffer { * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} */ - typedef Corrade::Containers::EnumSet MapFlags; + typedef Containers::EnumSet MapFlags; /** * @brief Unbind any buffer from given target @@ -436,7 +437,7 @@ class MAGNUM_EXPORT Buffer { * * @see @fn_gl{BindBuffer} */ - inline static void unbind(Target target) { bind(target, 0); } + static void unbind(Target target) { bind(target, 0); } #ifndef MAGNUM_TARGET_GLES2 /** @@ -456,7 +457,7 @@ class MAGNUM_EXPORT Buffer { * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 %Buffer copying is not available in OpenGL ES 2.0. */ - inline static void copy(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { + static void copy(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { copyImplementation(read, write, readOffset, writeOffset, size); } #endif @@ -469,7 +470,7 @@ class MAGNUM_EXPORT Buffer { * Generates new OpenGL buffer. * @see @fn_gl{GenBuffers} */ - inline explicit Buffer(Target targetHint = Target::Array): _targetHint(targetHint) { + explicit Buffer(Target targetHint = Target::Array): _targetHint(targetHint) { glGenBuffers(1, &_id); } @@ -482,13 +483,14 @@ class MAGNUM_EXPORT Buffer { virtual ~Buffer(); /** @brief OpenGL buffer ID */ - inline GLuint id() const { return _id; } + GLuint id() const { return _id; } /** @brief Target hint */ - inline Target targetHint() const { return _targetHint; } + Target targetHint() const { return _targetHint; } /** * @brief Set target hint + * @return Pointer to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available, the buffer * must be internally bound to some target before any operation. You @@ -501,7 +503,10 @@ class MAGNUM_EXPORT Buffer { * http://www.opengl.org/wiki/Vertex_Specification#Index_buffers * ... damned GL state */ - inline void setTargetHint(Target hint) { _targetHint = hint; } + Buffer* setTargetHint(Target hint) { + _targetHint = hint; + return this; + } /** * @brief Bind buffer @@ -513,13 +518,58 @@ class MAGNUM_EXPORT Buffer { * @todo Don't allow user to bind buffers? * @see @fn_gl{BindBuffer} */ - inline void bind(Target target) { bind(target, _id); } + void bind(Target target) { bind(target, _id); } + + /** + * @brief %Buffer size + * + * If @extension{EXT,direct_state_access} is not available and the + * buffer is not already bound somewhere, it is bound to hinted target + * before the operation. + * @see @fn_gl{BindBuffer} and @fn_gl{GetBufferParameter} or + * @fn_gl_extension{GetNamedBufferParameter,EXT,direct_state_access} + * with @def_gl{BUFFER_SIZE} + */ + Int size(); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief %Buffer data + * + * Returns data of whole buffer. If @extension{EXT,direct_state_access} + * is not available and the buffer is not already bound somewhere, it + * is bound to hinted target before the operation. + * @see size(), subData(), setData(), @fn_gl{BindBuffer} and @fn_gl{GetBufferParameter} or + * @fn_gl_extension{GetNamedBufferParameter,EXT,direct_state_access} + * with @def_gl{BUFFER_SIZE}, @fn_gl{GetBufferSubData} or + * @fn_gl_extension{GetNamedBufferSubData,EXT,direct_state_access} + * @requires_gl %Buffer data queries are not available in OpenGL ES. + * Use @ref Magnum::Buffer::map() "map()" instead. + */ + Containers::Array data(); + + /** + * @brief %Buffer subdata + * @param offset Offset in the buffer + * @param size Data size + * + * Returns data of given buffer portion. If @extension{EXT,direct_state_access} + * is not available and the buffer is not already bound somewhere, it + * is bound to hinted target before the operation. + * @see size(), data(), setSubData(), @fn_gl{BindBuffer} and @fn_gl{GetBufferSubData} + * or @fn_gl_extension{GetNamedBufferSubData,EXT,direct_state_access} + * @requires_gl %Buffer data queries are not available in OpenGL ES. + * Use @ref Magnum::Buffer::map() "map()" instead. + */ + Containers::Array subData(GLintptr offset, GLsizeiptr size); + #endif /** * @brief Set buffer data * @param size Data size * @param data Pointer to data * @param usage %Buffer usage + * @return Pointer to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target @@ -527,34 +577,39 @@ class MAGNUM_EXPORT Buffer { * @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferData} or * @fn_gl_extension{NamedBufferData,EXT,direct_state_access} */ - inline void setData(GLsizeiptr size, const GLvoid* data, Usage usage) { - (this->*setDataImplementation)(size, data, usage); + Buffer* setData(GLsizeiptr size, const GLvoid* data, Usage usage) { + (this->*dataImplementation)(size, data, usage); + return this; } /** * @brief Set buffer data * @param data Fixed-size array with data * @param usage %Buffer usage + * @return Pointer to self (for method chaining) * * @see setData(GLsizeiptr, const GLvoid*, Usage). */ - template inline void setData(const T(&data)[size], Usage usage) { + template Buffer* setData(const T(&data)[size], Usage usage) { setData(size*sizeof(T), data, usage); + return this; } /** * @brief Set buffer data * @param data Vector with data * @param usage %Buffer usage + * @return Pointer to self (for method chaining) * * @see setData(GLsizeiptr, const GLvoid*, Usage) */ - template inline void setData(const std::vector& data, Usage usage) { + template Buffer* setData(const std::vector& data, Usage usage) { setData(data.size()*sizeof(T), data.data(), usage); + return this; } /** @overload */ - template inline void setData(const std::array& data, Usage usage) { + template void setData(const std::array& data, Usage usage) { setData(data.size()*sizeof(T), data.data(), usage); } @@ -563,6 +618,7 @@ class MAGNUM_EXPORT Buffer { * @param offset Offset in the buffer * @param size Data size * @param data Pointer to data + * @return Pointer to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the * buffer is not already bound somewhere, it is bound to hinted target @@ -570,60 +626,70 @@ class MAGNUM_EXPORT Buffer { * @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferSubData} * or @fn_gl_extension{NamedBufferSubData,EXT,direct_state_access} */ - inline void setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) { - (this->*setSubDataImplementation)(offset, size, data); + Buffer* setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) { + (this->*subDataImplementation)(offset, size, data); + return this; } /** * @brief Set buffer subdata * @param offset Offset in the buffer * @param data Fixed-size array with data + * @return Pointer to self (for method chaining) * * @see setSubData(GLintptr, GLsizeiptr, const GLvoid*) */ - template inline void setSubData(GLintptr offset, const T(&data)[size]) { + template Buffer* setSubData(GLintptr offset, const T(&data)[size]) { setSubData(offset, size*sizeof(T), data); + return this; } /** * @brief Set buffer subdata * @param offset Offset in the buffer * @param data Vector with data + * @return Pointer to self (for method chaining) * * @see setSubData(GLintptr, GLsizeiptr, const GLvoid*) */ - template inline void setSubData(GLintptr offset, const std::vector& data) { + template Buffer* setSubData(GLintptr offset, const std::vector& data) { setSubData(offset, data.size()*sizeof(T), data.data()); + return this; } /** @overload */ - template inline void setSubData(GLintptr offset, const std::array& data) { + template Buffer* setSubData(GLintptr offset, const std::array& data) { setSubData(offset, data.size()*sizeof(T), data.data()); + return this; } #ifndef MAGNUM_TARGET_GLES /** * @brief Invalidate buffer data + * @return Pointer to self (for method chaining) * * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} * is not available, this function does nothing. * @see @ref MapFlag "MapFlag::InvalidateBuffer", @fn_gl{InvalidateBufferData} */ - inline void invalidateData() { + Buffer* invalidateData() { (this->*invalidateImplementation)(); + return this; } /** * @brief Invalidate buffer subdata * @param offset Offset into the buffer * @param length Length of the invalidated range + * @return Pointer to self (for method chaining) * * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} * is not available, this function does nothing. * @see @ref MapFlag "MapFlag::InvalidateRange", @fn_gl{InvalidateBufferData} */ - inline void invalidateSubData(GLintptr offset, GLsizeiptr length) { + Buffer* invalidateSubData(GLintptr offset, GLsizeiptr length) { (this->*invalidateSubImplementation)(offset, length); + return this; } #endif @@ -644,7 +710,7 @@ class MAGNUM_EXPORT Buffer { * OpenGL ES 2.0, use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * in OpenGL ES 3.0 instead. */ - inline void* map(MapAccess access) { + void* map(MapAccess access) { return (this->*mapImplementation)(access); } #endif @@ -665,7 +731,7 @@ class MAGNUM_EXPORT Buffer { * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} */ - inline void* map(GLintptr offset, GLsizeiptr length, MapFlags flags) { + void* map(GLintptr offset, GLsizeiptr length, MapFlags flags) { return (this->*mapRangeImplementation)(offset, length, flags); } @@ -673,6 +739,7 @@ class MAGNUM_EXPORT Buffer { * @brief Flush mapped range * @param offset Offset relative to start of mapped range * @param length Length of the flushed memory + * @return Pointer to self (for method chaining) * * Flushes specified subsection of mapped range. Use only if you called * map() with @ref MapFlag "MapFlag::FlushExplicit" flag. See @@ -686,8 +753,9 @@ class MAGNUM_EXPORT Buffer { * @requires_gl30 %Extension @extension{ARB,map_buffer_range} * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} */ - inline void flushMappedRange(GLintptr offset, GLsizeiptr length) { + Buffer* flushMappedRange(GLintptr offset, GLsizeiptr length) { (this->*flushMappedRangeImplementation)(offset, length); + return this; } /** @@ -704,7 +772,7 @@ class MAGNUM_EXPORT Buffer { * @fn_gl_extension{UnmapNamedBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension{OES,mapbuffer} */ - inline bool unmap() { + bool unmap() { return (this->*unmapImplementation)(); } @@ -723,19 +791,33 @@ class MAGNUM_EXPORT Buffer { static CopyImplementation copyImplementation; #endif - typedef void(Buffer::*SetDataImplementation)(GLsizeiptr, const GLvoid*, Usage); - void MAGNUM_LOCAL setDataImplementationDefault(GLsizeiptr size, const GLvoid* data, Usage usage); + typedef void(Buffer::*GetParameterImplementation)(GLenum, GLint*); + 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 MAGNUM_LOCAL GetSubDataImplementation getSubDataImplementation; + #endif + + typedef void(Buffer::*DataImplementation)(GLsizeiptr, const GLvoid*, Usage); + void MAGNUM_LOCAL dataImplementationDefault(GLsizeiptr size, const GLvoid* data, Usage usage); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL setDataImplementationDSA(GLsizeiptr size, const GLvoid* data, Usage usage); + void MAGNUM_LOCAL dataImplementationDSA(GLsizeiptr size, const GLvoid* data, Usage usage); #endif - static SetDataImplementation setDataImplementation; + static DataImplementation dataImplementation; - typedef void(Buffer::*SetSubDataImplementation)(GLintptr, GLsizeiptr, const GLvoid*); - void MAGNUM_LOCAL setSubDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data); + 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 setSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data); + void MAGNUM_LOCAL subDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data); #endif - static SetSubDataImplementation setSubDataImplementation; + static SubDataImplementation subDataImplementation; typedef void(Buffer::*InvalidateImplementation)(); void MAGNUM_LOCAL invalidateImplementationNoOp(); diff --git a/src/BufferImage.cpp b/src/BufferImage.cpp index db8d13069..4de6bbb6c 100644 --- a/src/BufferImage.cpp +++ b/src/BufferImage.cpp @@ -27,16 +27,18 @@ namespace Magnum { #ifndef MAGNUM_TARGET_GLES2 -template void BufferImage::setData(const typename DimensionTraits::VectorType& size, Format format, Type type, const GLvoid* data, Buffer::Usage usage) { +template void BufferImage::setData(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, const void* data, Buffer::Usage usage) { _format = format; _type = type; _size = size; - _buffer.setData(pixelSize(format, type)*size.product(), data, usage); + _buffer.setData(pixelSize()*size.product(), data, usage); } -template class BufferImage<1>; -template class BufferImage<2>; -template class BufferImage<3>; +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_EXPORT BufferImage<1>; +template class MAGNUM_EXPORT BufferImage<2>; +template class MAGNUM_EXPORT BufferImage<3>; +#endif #endif } diff --git a/src/BufferImage.h b/src/BufferImage.h index ae4910eca..d49462817 100644 --- a/src/BufferImage.h +++ b/src/BufferImage.h @@ -58,15 +58,15 @@ template class MAGNUM_EXPORT BufferImage: public Abstrac * Dimensions and buffer are empty, call setData() to fill the image * with data. */ - inline explicit BufferImage(Format format, Type type): AbstractImage(format, type) { + explicit BufferImage(ImageFormat format, ImageType type): AbstractImage(format, type) { _buffer.setTargetHint(Buffer::Target::PixelPack); } /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + typename DimensionTraits::VectorType size() const { return _size; } /** @brief %Image buffer */ - inline Buffer* buffer() { return &_buffer; } + Buffer* buffer() { return &_buffer; } /** * @brief Set image data @@ -81,7 +81,7 @@ template class MAGNUM_EXPORT BufferImage: public Abstrac * * @see Buffer::setData() */ - void setData(const typename DimensionTraits::VectorType& size, Format format, Type type, const GLvoid* data, Buffer::Usage usage); + void setData(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, const void* data, Buffer::Usage usage); private: Math::Vector _size; diff --git a/src/BufferTexture.cpp b/src/BufferTexture.cpp index c06e62ec6..55231f970 100644 --- a/src/BufferTexture.cpp +++ b/src/BufferTexture.cpp @@ -43,24 +43,23 @@ void BufferTexture::initializeContextBasedFunctionality(Context* context) { } } -void BufferTexture::setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer) { +void BufferTexture::setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer) { bindInternal(); glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id()); } -void BufferTexture::setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer) { +void BufferTexture::setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer* buffer) { glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id()); } -void BufferTexture::setBufferRangeImplementationDefault(InternalFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) { +void BufferTexture::setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) { bindInternal(); glTexBufferRange(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id(), offset, size); } -void BufferTexture::setBufferRangeImplementationDSA(InternalFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) { +void BufferTexture::setBufferRangeImplementationDSA(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) { glTextureBufferRangeEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id(), offset, size); } - } #endif diff --git a/src/BufferTexture.h b/src/BufferTexture.h index 38adaa430..6f41e922e 100644 --- a/src/BufferTexture.h +++ b/src/BufferTexture.h @@ -26,7 +26,7 @@ #ifndef MAGNUM_TARGET_GLES /** @file - * @brief Class Magnum::BufferTexture + * @brief Class Magnum::BufferTexture, enum Magnum::BufferTextureFormat */ #endif @@ -56,7 +56,7 @@ Example usage: @code Buffer* buffer; BufferTexture texture; -texture.setBuffer(buffer); +texture.setBuffer(BufferTextureFormat::RGB32F, buffer); constexpr static Vector3 data[] = { // ... @@ -65,9 +65,10 @@ buffer.setData(data, Buffer::Usage::StaticDraw); @endcode The texture is bound to layer specified by shader via bind(). In shader, the -texture is used via `samplerBuffer`. Unlike in classic textures, coordinates -for buffer textures are integer coordinates passed to `texelFetch()`. See also -AbstractShaderProgram documentation for more information. +texture is used via `samplerBuffer`, `isamplerBuffer` or `usamplerBuffer`. +Unlike in classic textures, coordinates for buffer textures are integer +coordinates passed to `texelFetch()`. See also AbstractShaderProgram +documentation for more information. @section BufferTexture-performance-optimization Performance optimizations If extension @extension{EXT,direct_state_access} is available, setBuffer() @@ -76,6 +77,7 @@ functions use DSA to avoid unnecessary calls to @fn_gl{ActiveTexture} and "relevant section in AbstractTexture documentation" and respective function documentation for more information. +@see Texture, CubeMapTexture, CubeMapTextureArray @requires_gl31 %Extension @extension{ARB,texture_buffer_object} @requires_gl Texture buffers are not available in OpenGL ES. */ @@ -88,171 +90,171 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture { BufferTexture& operator=(BufferTexture&&) = delete; public: + explicit BufferTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {} + + /** @copydoc AbstractTexture::bind() */ + void bind(Int layer) { AbstractTexture::bind(layer); } + /** - * @brief Internal format + * @brief Set texture buffer + * @param internalFormat Internal format + * @param buffer %Buffer with data * - * @see setBuffer() + * Binds given buffer to this texture. The buffer itself can be then + * filled with data of proper format at any time using Buffer own data + * setting functions. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer} + * or @fn_gl_extension{TextureBuffer,EXT,direct_state_access} */ - enum class InternalFormat: GLenum { - /** Red component, normalized unsigned byte. */ - R8 = GL_R8, - - /** Red and green component, each normalized unsigned byte. */ - RG8 = GL_RG8, + void setBuffer(BufferTextureFormat internalFormat, Buffer* buffer) { + (this->*setBufferImplementation)(internalFormat, buffer); + } - /** RGBA, each component normalized unsigned byte. */ - RGBA8 = GL_RGBA8, + /** + * @brief Set texture buffer + * @param internalFormat Internal format + * @param buffer %Buffer + * @param offset Offset + * @param size Data size + * + * Binds range of given buffer to this texture. The buffer itself can + * be then filled with data of proper format at any time using Buffer + * own data setting functions. + * @requires_gl43 %Extension @extension{ARB,texture_buffer_range} + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBufferRange} + * or @fn_gl_extension{TextureBufferRange,EXT,direct_state_access} + */ + void setBuffer(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) { + (this->*setBufferRangeImplementation)(internalFormat, buffer, offset, size); + } - /** Red component, normalized unsigned short. */ - R16 = GL_R16, + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); - /** Red and green component, each normalized unsigned short. */ - RG16 = GL_RG16, + 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; - /** RGBA, each component normalized unsigned short. */ - RGBA16 = GL_RGBA16, + 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; +}; - /** Red component, non-normalized unsigned byte. */ - R8UI = GL_R8UI, +/** +@brief Internal buffer texture format - /** Red and green component, each non-normalized unsigned byte. */ - RG8UI = GL_RG8UI, +@see BufferTexture +*/ +enum class BufferTextureFormat: GLenum { + /** Red component, normalized unsigned byte. */ + R8 = GL_R8, - /** RGBA, each component non-normalized unsigned byte. */ - RGBA8UI = GL_RGBA8UI, + /** Red and green component, each normalized unsigned byte. */ + RG8 = GL_RG8, - /** Red component, non-normalized signed byte. */ - R8I = GL_R8I, + /** RGBA, each component normalized unsigned byte. */ + RGBA8 = GL_RGBA8, - /** Red and green component, each non-normalized signed byte. */ - RG8I = GL_RG8I, + /** Red component, normalized unsigned short. */ + R16 = GL_R16, - /** RGBA, each component non-normalized signed byte. */ - RGBA8I = GL_RGBA8I, + /** Red and green component, each normalized unsigned short. */ + RG16 = GL_RG16, - /** Red component, non-normalized unsigned short. */ - R16UI = GL_R16UI, + /** RGBA, each component normalized unsigned short. */ + RGBA16 = GL_RGBA16, - /** Red and green component, each non-normalized unsigned short. */ - RG16UI = GL_RG16UI, + /** Red component, non-normalized unsigned byte. */ + R8UI = GL_R8UI, - /** RGBA, each component non-normalized unsigned short. */ - RGBA16UI = GL_RGBA16UI, + /** Red and green component, each non-normalized unsigned byte. */ + RG8UI = GL_RG8UI, - /** Red component, non-normalized signed short. */ - R16I = GL_R16I, + /** RGBA, each component non-normalized unsigned byte. */ + RGBA8UI = GL_RGBA8UI, - /** Red and green component, each non-normalized signed short. */ - RG16I = GL_RG16I, + /** Red component, non-normalized signed byte. */ + R8I = GL_R8I, - /** RGBA, each component non-normalized signed short. */ - RGBA16I = GL_RGBA16I, + /** Red and green component, each non-normalized signed byte. */ + RG8I = GL_RG8I, - /** Red component, non-normalized unsigned int. */ - R32UI = GL_R32UI, + /** RGBA, each component non-normalized signed byte. */ + RGBA8I = GL_RGBA8I, - /** Red and green component, each non-normalized unsigned int. */ - RG32UI = GL_RG32UI, + /** Red component, non-normalized unsigned short. */ + R16UI = GL_R16UI, - /** - * RGB, each component non-normalized unsigned int. - * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} - */ - RGB32UI = GL_RGB32UI, + /** Red and green component, each non-normalized unsigned short. */ + RG16UI = GL_RG16UI, - /** RGBA, each component non-normalized unsigned int. */ - RGBA32UI = GL_RGBA32UI, + /** RGBA, each component non-normalized unsigned short. */ + RGBA16UI = GL_RGBA16UI, - /** Red component, non-normalized signed int. */ - R32I = GL_R32I, + /** Red component, non-normalized signed short. */ + R16I = GL_R16I, - /** Red and green component, each non-normalized signed int. */ - RG32I = GL_RG32I, + /** Red and green component, each non-normalized signed short. */ + RG16I = GL_RG16I, - /** - * RGB, each component non-normalized signed int. - * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} - */ - RGB32I = GL_RGB32I, + /** RGBA, each component non-normalized signed short. */ + RGBA16I = GL_RGBA16I, - /** RGBA, each component non-normalized signed int. */ - RGBA32I = GL_RGBA32I, + /** Red component, non-normalized unsigned int. */ + R32UI = GL_R32UI, - /** Red component, half float. */ - R16F = GL_R16F, + /** Red and green component, each non-normalized unsigned int. */ + RG32UI = GL_RG32UI, - /** Red and green component, each half float. */ - RG16F = GL_RG16F, + /** + * RGB, each component non-normalized unsigned int. + * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} + */ + RGB32UI = GL_RGB32UI, - /** RGBA, each component half float. */ - RGBA16F = GL_RGBA16F, + /** RGBA, each component non-normalized unsigned int. */ + RGBA32UI = GL_RGBA32UI, - /** Red component, float. */ - R32F = GL_R32F, + /** Red component, non-normalized signed int. */ + R32I = GL_R32I, - /** Red and green component, each float. */ - RG32F = GL_RG32F, + /** Red and green component, each non-normalized signed int. */ + RG32I = GL_RG32I, - /** - * RGB, each component float. - * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} - */ - RGB32F = GL_RGB32F, + /** + * RGB, each component non-normalized signed int. + * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} + */ + RGB32I = GL_RGB32I, - /** RGBA, each component float. */ - RGBA32F = GL_RGBA32F - }; + /** RGBA, each component non-normalized signed int. */ + RGBA32I = GL_RGBA32I, - inline explicit BufferTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {} + /** Red component, half float. */ + R16F = GL_R16F, - /** @copydoc AbstractTexture::bind() */ - inline void bind(Int layer) { AbstractTexture::bind(layer); } + /** Red and green component, each half float. */ + RG16F = GL_RG16F, - /** - * @brief Set texture buffer - * @param internalFormat Internal format - * @param buffer %Buffer with data - * - * Binds given buffer to this texture. The buffer itself can be then - * filled with data of proper format at any time using Buffer own data - * setting functions. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer} - * or @fn_gl_extension{TextureBuffer,EXT,direct_state_access} - */ - inline void setBuffer(InternalFormat internalFormat, Buffer* buffer) { - (this->*setBufferImplementation)(internalFormat, buffer); - } + /** RGBA, each component half float. */ + RGBA16F = GL_RGBA16F, - /** - * @brief Set texture buffer - * @param internalFormat Internal format - * @param buffer %Buffer - * @param offset Offset - * @param size Data size - * - * Binds range of given buffer to this texture. The buffer itself can - * be then filled with data of proper format at any time using Buffer - * own data setting functions. - * @requires_gl43 %Extension @extension{ARB,texture_buffer_range} - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer} - * or @fn_gl_extension{TextureBufferRange,EXT,direct_state_access} - */ - inline void setBuffer(InternalFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) { - (this->*setBufferRangeImplementation)(internalFormat, buffer, offset, size); - } + /** Red component, float. */ + R32F = GL_R32F, - private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + /** Red and green component, each float. */ + RG32F = GL_RG32F, - typedef void(BufferTexture::*SetBufferImplementation)(InternalFormat, Buffer*); - void MAGNUM_LOCAL setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer); - void MAGNUM_LOCAL setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer); - static SetBufferImplementation setBufferImplementation; + /** + * RGB, each component float. + * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} + */ + RGB32F = GL_RGB32F, - typedef void(BufferTexture::*SetBufferRangeImplementation)(InternalFormat, Buffer*, GLintptr, GLsizeiptr); - void MAGNUM_LOCAL setBufferRangeImplementationDefault(InternalFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size); - void MAGNUM_LOCAL setBufferRangeImplementationDSA(InternalFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size); - static SetBufferRangeImplementation setBufferRangeImplementation; + /** RGBA, each component float. */ + RGBA32F = GL_RGBA32F }; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39dc033cb..c0f9a965a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,16 +56,20 @@ set(Magnum_SRCS DefaultFramebuffer.cpp Framebuffer.cpp Image.cpp + ImageFormat.cpp Mesh.cpp OpenGL.cpp Query.cpp Renderbuffer.cpp + Renderer.cpp Resource.cpp + Sampler.cpp Shader.cpp Timeline.cpp Implementation/BufferState.cpp Implementation/State.cpp + Implementation/TextureState.cpp Trade/AbstractImageConverter.cpp Trade/AbstractImporter.cpp @@ -108,18 +112,22 @@ set(Magnum_HEADERS Extensions.h Framebuffer.h Image.h + ImageFormat.h ImageWrapper.h Magnum.h Mesh.h OpenGL.h Query.h Renderbuffer.h + RenderbufferFormat.h Renderer.h Resource.h ResourceManager.h + Sampler.h Shader.h Swizzle.h Texture.h + TextureFormat.h Timeline.h Types.h @@ -140,14 +148,8 @@ endif() # Files shared between main library and math unit test library set(MagnumMath_SRCS - Math/Angle.cpp - Math/Complex.cpp - Math/DualComplex.cpp - Math/DualQuaternion.cpp Math/Functions.cpp - Math/Quaternion.cpp - Math/RectangularMatrix.cpp - Math/Vector.cpp) + Math/instantiation.cpp) # Set shared library flags for the objects, as they will be part of shared lib # TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well @@ -194,10 +196,6 @@ if(WITH_MESHTOOLS) add_subdirectory(MeshTools) endif() -if(WITH_PHYSICS) - add_subdirectory(Physics) -endif() - if(WITH_PRIMITIVES) add_subdirectory(Primitives) endif() @@ -210,6 +208,10 @@ if(WITH_SHADERS) add_subdirectory(Shaders) endif() +if(WITH_SHAPES) + add_subdirectory(Shapes) +endif() + if(WITH_TEXT) add_subdirectory(Text) endif() diff --git a/src/Color.h b/src/Color.h index 6625e4c0c..fe7971a39 100644 --- a/src/Color.h +++ b/src/Color.h @@ -36,11 +36,10 @@ namespace Magnum { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { /* Convert color from HSV */ -template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { +template typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { Math::Deg hue; T saturation, value; std::tie(hue, saturation, value) = hsv; @@ -133,7 +132,6 @@ template inline constexpr typename std::enable_if:: } } -#endif /** @brief Three-component (RGB) color @@ -174,11 +172,11 @@ class Color3: public Math::Vector3 { * * Hue can overflow the range @f$ [0.0, 360.0] @f$. */ - inline constexpr static Color3 fromHSV(HSV hsv) { + constexpr static Color3 fromHSV(HSV hsv) { return Implementation::fromHSV(hsv); } /** @overload */ - inline constexpr static Color3 fromHSV(Math::Deg hue, FloatingPointType saturation, FloatingPointType value) { + constexpr static Color3 fromHSV(Math::Deg hue, FloatingPointType saturation, FloatingPointType value) { return fromHSV(std::make_tuple(hue, saturation, value)); } @@ -187,13 +185,13 @@ class Color3: public Math::Vector3 { * * All components are set to zero. */ - inline constexpr /*implicit*/ Color3() {} + constexpr /*implicit*/ Color3() {} /** * @brief Gray constructor * @param rgb RGB value */ - inline constexpr explicit Color3(T rgb): Math::Vector3(rgb) {} + constexpr explicit Color3(T rgb): Math::Vector3(rgb) {} /** * @brief Constructor @@ -201,20 +199,20 @@ class Color3: public Math::Vector3 { * @param g G value * @param b B value */ - inline constexpr /*implicit*/ Color3(T r, T g, T b): Math::Vector3(r, g, b) {} + constexpr /*implicit*/ Color3(T r, T g, T b): Math::Vector3(r, g, b) {} /** @copydoc Math::Vector::Vector(const Vector&) */ - template inline constexpr explicit Color3(const Math::Vector<3, U>& other): Math::Vector3(other) {} + template constexpr explicit Color3(const Math::Vector<3, U>& other): Math::Vector3(other) {} /** @brief Copy constructor */ - inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3(other) {} + constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3(other) {} - inline T& r() { return Math::Vector3::x(); } /**< @brief R component */ - inline constexpr T r() const { return Math::Vector3::x(); } /**< @overload */ - inline T& g() { return Math::Vector3::y(); } /**< @brief G component */ - inline constexpr T g() const { return Math::Vector3::y(); } /**< @overload */ - inline T& b() { return Math::Vector3::z(); } /**< @brief B component */ - inline constexpr T b() const { return Math::Vector3::z(); } /**< @overload */ + T& r() { return Math::Vector3::x(); } /**< @brief R component */ + constexpr T r() const { return Math::Vector3::x(); } /**< @overload */ + T& g() { return Math::Vector3::y(); } /**< @brief G component */ + constexpr T g() const { return Math::Vector3::y(); } /**< @overload */ + T& b() { return Math::Vector3::z(); } /**< @brief B component */ + constexpr T b() const { return Math::Vector3::z(); } /**< @overload */ /** * @brief Convert to HSV @@ -227,7 +225,7 @@ class Color3: public Math::Vector3 { * * @see hue(), saturation(), value(), fromHSV() */ - inline constexpr HSV toHSV() const { + constexpr HSV toHSV() const { return Implementation::toHSV(*this); } @@ -237,7 +235,7 @@ class Color3: public Math::Vector3 { * * @see saturation(), value(), toHSV(), fromHSV() */ - inline constexpr Math::Deg hue() const { + constexpr Math::Deg hue() const { return Math::Deg(Implementation::hue(*this)); } @@ -247,7 +245,7 @@ class Color3: public Math::Vector3 { * * @see hue(), value(), toHSV(), fromHSV() */ - inline constexpr FloatingPointType saturation() const { + constexpr FloatingPointType saturation() const { return Implementation::saturation(*this); } @@ -257,7 +255,7 @@ class Color3: public Math::Vector3 { * * @see hue(), saturation(), toHSV(), fromHSV() */ - inline constexpr FloatingPointType value() const { + constexpr FloatingPointType value() const { return Implementation::value(*this); } @@ -291,11 +289,11 @@ class Color4: public Math::Vector4 { * @param a Alpha value, defaults to 1.0 for floating-point types * and maximum positive value for integral types. */ - inline constexpr static Color4 fromHSV(HSV hsv, T a = Implementation::defaultAlpha()) { + constexpr static Color4 fromHSV(HSV hsv, T a = Implementation::defaultAlpha()) { return Color4(Implementation::fromHSV(hsv), a); } /** @overload */ - inline constexpr static Color4 fromHSV(Math::Deg hue, FloatingPointType saturation, FloatingPointType value, T alpha) { + constexpr static Color4 fromHSV(Math::Deg hue, FloatingPointType saturation, FloatingPointType value, T alpha) { return fromHSV(std::make_tuple(hue, saturation, value), alpha); } @@ -305,14 +303,14 @@ class Color4: public Math::Vector4 { * RGB components are set to zero, A component is set to 1.0 for * floating-point types and maximum positive value for integral types. */ - inline constexpr /*implicit*/ Color4(): Math::Vector4(T(0), T(0), T(0), Implementation::defaultAlpha()) {} + constexpr /*implicit*/ Color4(): Math::Vector4(T(0), T(0), T(0), Implementation::defaultAlpha()) {} /** * @copydoc Color3::Color3(T) * @param alpha Alpha value, defaults to 1.0 for floating-point types * and maximum positive value for integral types. */ - inline constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha()): Math::Vector4(rgb, rgb, rgb, alpha) {} + constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha()): Math::Vector4(rgb, rgb, rgb, alpha) {} /** * @brief Constructor @@ -322,7 +320,7 @@ class Color4: public Math::Vector4 { * @param a A value, defaults to 1.0 for floating-point types and * maximum positive value for integral types. */ - inline constexpr /*implicit*/ Color4(T r, T g, T b, T a = Implementation::defaultAlpha()): Math::Vector4(r, g, b, a) {} + constexpr /*implicit*/ Color4(T r, T g, T b, T a = Implementation::defaultAlpha()): Math::Vector4(r, g, b, a) {} /** * @brief Constructor @@ -331,22 +329,22 @@ class Color4: public Math::Vector4 { */ /* Not marked as explicit, because conversion from Color3 to Color4 is fairly common, nearly always with A set to 1 */ - inline constexpr /*implicit*/ Color4(const Math::Vector3& rgb, T a = Implementation::defaultAlpha()): Math::Vector4(rgb[0], rgb[1], rgb[2], a) {} + constexpr /*implicit*/ Color4(const Math::Vector3& rgb, T a = Implementation::defaultAlpha()): Math::Vector4(rgb[0], rgb[1], rgb[2], a) {} /** @copydoc Math::Vector::Vector(const Vector&) */ - template inline constexpr explicit Color4(const Math::Vector<4, U>& other): Math::Vector4(other) {} + template constexpr explicit Color4(const Math::Vector<4, U>& other): Math::Vector4(other) {} /** @brief Copy constructor */ - inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4(other) {} + constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4(other) {} - inline T& r() { return Math::Vector4::x(); } /**< @brief R component */ - inline constexpr T r() const { return Math::Vector4::x(); } /**< @overload */ - inline T& g() { return Math::Vector4::y(); } /**< @brief G component */ - inline constexpr T g() const { return Math::Vector4::y(); } /**< @overload */ - inline T& b() { return Math::Vector4::z(); } /**< @brief B component */ - inline constexpr T b() const { return Math::Vector4::z(); } /**< @overload */ - inline T& a() { return Math::Vector4::w(); } /**< @brief A component */ - inline constexpr T a() const { return Math::Vector4::w(); } /**< @overload */ + T& r() { return Math::Vector4::x(); } /**< @brief R component */ + constexpr T r() const { return Math::Vector4::x(); } /**< @overload */ + T& g() { return Math::Vector4::y(); } /**< @brief G component */ + constexpr T g() const { return Math::Vector4::y(); } /**< @overload */ + T& b() { return Math::Vector4::z(); } /**< @brief B component */ + constexpr T b() const { return Math::Vector4::z(); } /**< @overload */ + T& a() { return Math::Vector4::w(); } /**< @brief A component */ + constexpr T a() const { return Math::Vector4::w(); } /**< @overload */ /** * @brief RGB part of the vector @@ -354,26 +352,26 @@ class Color4: public Math::Vector4 { * * @see swizzle() */ - inline Color3& rgb() { return Color3::from(Math::Vector4::data()); } - inline constexpr Color3 rgb() const { return Color3::from(Math::Vector4::data()); } /**< @overload */ + Color3& rgb() { return Color3::from(Math::Vector4::data()); } + constexpr Color3 rgb() const { return Color3::from(Math::Vector4::data()); } /**< @overload */ /** @copydoc Color3::toHSV() */ - inline constexpr HSV toHSV() const { + constexpr HSV toHSV() const { return Implementation::toHSV(rgb()); } /** @copydoc Color3::hue() */ - inline constexpr Math::Deg hue() const { + constexpr Math::Deg hue() const { return Implementation::hue(rgb()); } /** @copydoc Color3::saturation() */ - inline constexpr FloatingPointType saturation() const { + constexpr FloatingPointType saturation() const { return Implementation::saturation(rgb()); } /** @copydoc Color3::value() */ - inline constexpr FloatingPointType value() const { + constexpr FloatingPointType value() const { return Implementation::value(rgb()); } diff --git a/src/Context.cpp b/src/Context.cpp index 9eb74c126..c91bf90a5 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -40,6 +40,7 @@ #include "Framebuffer.h" #include "Mesh.h" #include "Renderbuffer.h" +#include "Renderer.h" #include "Implementation/State.h" @@ -79,6 +80,7 @@ const std::vector& Extension::extensions(Version version) { 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,EXT,texture_filter_anisotropic), // done _extension(GL,EXT,direct_state_access), _extension(GL,GREMEDY,string_marker)}; // done @@ -208,8 +210,10 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,EXT,texture_format_BGRA8888), _extension(GL,EXT,read_format_bgra), _extension(GL,EXT,debug_marker), + _extension(GL,EXT,disjoint_timer_query), _extension(GL,EXT,separate_shader_objects), _extension(GL,EXT,sRGB), + _extension(GL,EXT,robustness), _extension(GL,NV,read_buffer_front), _extension(GL,NV,read_stencil), _extension(GL,NV,texture_border_clamp), // done @@ -220,6 +224,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,OES,texture_3D)}; static const std::vector extensionsES300{ _extension(GL,ANGLE,framebuffer_blit), + _extension(GL,ANGLE,framebuffer_multisample), _extension(GL,ANGLE,depth_texture), // done _extension(GL,APPLE,framebuffer_multisample), _extension(GL,ARM,rgba8), @@ -235,6 +240,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,NV,read_depth), _extension(GL,NV,read_depth_stencil), _extension(GL,NV,framebuffer_blit), // done + _extension(GL,NV,framebuffer_multisample), _extension(GL,OES,depth24), _extension(GL,OES,element_index_uint), _extension(GL,OES,rgb8_rgba8), @@ -245,6 +251,7 @@ 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,vertex_array_object), _extension(GL,OES,required_internalformat)}; #endif @@ -285,6 +292,16 @@ Context::Context() { #endif _version = static_cast(_majorVersion*100+_minorVersion*10); + /* Context flags are supported since GL 3.0 */ + #ifndef MAGNUM_TARGET_GLES + /** + * @todo According to KHR_debug specs this should be also present in ES2 + * if KHR_debug is available, but in headers it is nowhere to be found + */ + if(isVersionSupported(Version::GL300)) + glGetIntegerv(GL_CONTEXT_FLAGS, reinterpret_cast(&_flags)); + #endif + /* Get first future (not supported) version */ std::vector versions{ #ifndef MAGNUM_TARGET_GLES @@ -317,29 +334,35 @@ Context::Context() { } /* Check for presence of extensions in future versions */ - #ifndef MAGNUM_TARGET_GLES - if(isVersionSupported(Version::GL300)) { - #else - if(isVersionSupported(Version::GLES300)) { + #ifndef MAGNUM_TARGET_GLES2 + GLint extensionCount = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount); + #ifndef MAGNUM_TARGET_GLES3 + if(extensionCount || isVersionSupported(Version::GL300)) #endif - #ifndef MAGNUM_TARGET_GLES2 - GLuint index = 0; - const char* extension; - while((extension = reinterpret_cast(glGetStringi(GL_EXTENSIONS, index++)))) { + { + _supportedExtensions.reserve(extensionCount); + for(GLint i = 0; i != extensionCount; ++i) { + const std::string extension(reinterpret_cast(glGetStringi(GL_EXTENSIONS, i))); auto found = futureExtensions.find(extension); if(found != futureExtensions.end()) { _supportedExtensions.push_back(found->second); extensionStatus.set(found->second._index); } } - #endif + } + #ifndef MAGNUM_TARGET_GLES3 + else + #endif + #endif + #ifndef MAGNUM_TARGET_GLES3 /* OpenGL 2.1 / OpenGL ES 2.0 doesn't have glGetStringi() */ - } else { + { /* Don't crash when glGetString() returns nullptr */ const char* e = reinterpret_cast(glGetString(GL_EXTENSIONS)); if(e) { - std::vector extensions = Corrade::Utility::String::split(e, ' '); + std::vector extensions = Utility::String::split(e, ' '); for(auto it = extensions.begin(); it != extensions.end(); ++it) { auto found = futureExtensions.find(*it); if(found != futureExtensions.end()) { @@ -349,6 +372,7 @@ Context::Context() { } } } + #endif /* Set this context as current */ CORRADE_ASSERT(!_current, "Context: Another context currently active", ); @@ -370,6 +394,7 @@ Context::Context() { Framebuffer::initializeContextBasedFunctionality(this); Mesh::initializeContextBasedFunctionality(this); Renderbuffer::initializeContextBasedFunctionality(this); + Renderer::initializeContextBasedFunctionality(this); } Context::~Context() { @@ -378,6 +403,26 @@ Context::~Context() { _current = nullptr; } +std::vector Context::shadingLanguageVersionStrings() const { + #ifndef MAGNUM_TARGET_GLES + GLint versionCount = 0; + glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &versionCount); + + /* The implementation doesn't yet support this query (< OpenGL 4.3) */ + if(!versionCount) + return {shadingLanguageVersionString()}; + + /* Get all of them */ + std::vector versions; + versions.reserve(versionCount); + for(GLint i = 0; i != versionCount; ++i) + versions.push_back(reinterpret_cast(glGetStringi(GL_SHADING_LANGUAGE_VERSION, i))); + return std::move(versions); + #else + return {shadingLanguageVersionString()}; + #endif +} + Version Context::supportedVersion(std::initializer_list versions) const { for(auto it = versions.begin(); it != versions.end(); ++it) if(isVersionSupported(*it)) return *it; diff --git a/src/Context.h b/src/Context.h index ce52c4e13..5e42b8620 100644 --- a/src/Context.h +++ b/src/Context.h @@ -30,6 +30,7 @@ #include #include +#include #include "Magnum.h" #include "OpenGL.h" @@ -37,11 +38,9 @@ namespace Magnum { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { struct State; } -#endif /** @brief OpenGL version @@ -110,13 +109,13 @@ class MAGNUM_EXPORT Extension { static const std::vector& extensions(Version version); /** @brief Minimal version required by this extension */ - inline constexpr Version requiredVersion() const { return _requiredVersion; } + constexpr Version requiredVersion() const { return _requiredVersion; } /** @brief Version in which this extension was adopted to core */ - inline constexpr Version coreVersion() const { return _coreVersion; } + constexpr Version coreVersion() const { return _coreVersion; } /** @brief %Extension string */ - inline constexpr const char* string() const { return _string; } + constexpr const char* string() const { return _string; } private: /* GCC 4.6 doesn't like const members, as std::vector doesn't have @@ -126,7 +125,7 @@ class MAGNUM_EXPORT Extension { Version _coreVersion; const char* _string; - inline constexpr Extension(std::size_t index, Version requiredVersion, Version coreVersion, const char* string): _index(index), _requiredVersion(requiredVersion), _coreVersion(coreVersion), _string(string) {} + constexpr Extension(std::size_t index, Version requiredVersion, Version coreVersion, const char* string): _index(index), _requiredVersion(requiredVersion), _coreVersion(coreVersion), _string(string) {} }; /** @@ -146,12 +145,51 @@ class MAGNUM_EXPORT Context { Context& operator=(Context&&) = delete; public: + /** + * @brief Context flag + * + * @see Flags, flags() + */ + enum class Flag: GLint { + #ifndef MAGNUM_TARGET_GLES3 + /** + * Debug context + * @requires_gl43 %Extension @es_extension{KHR,debug} + * @requires_es_extension %Extension @es_extension{KHR,debug} + */ + #ifndef MAGNUM_TARGET_GLES + Debug = GL_CONTEXT_FLAG_DEBUG_BIT, + #else + Debug = GL_CONTEXT_FLAG_DEBUG_BIT_KHR, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Context with robust buffer access + * @requires_extension %Extension @extension{EXT,robustness} + * @requires_es_extension %Extension @es_extension{EXT,robustness} + * @todo In ES available under glGetIntegerv(CONTEXT_ROBUST_ACCESS_EXT), + * how to make it compatible? + */ + Robustness = GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB + #endif + }; + + /** + * @brief Context flags + * + * @see flags() + */ + typedef Containers::EnumSet Flags; + /** * @brief Constructor * * Constructed automatically, see class documentation for more * information. * @see @fn_gl{Get} with @def_gl{MAJOR_VERSION}, @def_gl{MINOR_VERSION}, + * @def_gl{CONTEXT_FLAGS}, @def_gl{NUM_EXTENSIONS}, * @fn_gl{GetString} with @def_gl{EXTENSIONS} */ explicit Context(); @@ -159,7 +197,7 @@ class MAGNUM_EXPORT Context { ~Context(); /** @brief Current context */ - inline static Context* current() { return _current; } + static Context* current() { return _current; } /** * @brief OpenGL version @@ -167,7 +205,7 @@ class MAGNUM_EXPORT Context { * @see majorVersion(), minorVersion(), versionString(), * shadingLanguageVersionString() */ - inline Version version() const { return _version; } + Version version() const { return _version; } /** * @brief Major OpenGL version (e.g. `4`) @@ -175,7 +213,7 @@ class MAGNUM_EXPORT Context { * @see minorVersion(), version(), versionString(), * shadingLanguageVersionString() */ - inline Int majorVersion() const { return _majorVersion; } + Int majorVersion() const { return _majorVersion; } /** * @brief Minor OpenGL version (e.g. `3`) @@ -183,46 +221,67 @@ class MAGNUM_EXPORT Context { * @see majorVersion(), version(), versionString(), * shadingLanguageVersionString() */ - inline Int minorVersion() const { return _minorVersion; } + Int minorVersion() const { return _minorVersion; } /** * @brief Vendor string * + * The result is *not* cached, repeated queries will result in repeated + * OpenGL calls. * @see rendererString(), @fn_gl{GetString} with @def_gl{VENDOR} */ - inline std::string vendorString() const { + std::string vendorString() const { return reinterpret_cast(glGetString(GL_VENDOR)); } /** * @brief %Renderer string * + * The result is *not* cached, repeated queries will result in repeated + * OpenGL calls. * @see vendorString(), @fn_gl{GetString} with @def_gl{RENDERER} */ - inline std::string rendererString() const { + std::string rendererString() const { return reinterpret_cast(glGetString(GL_RENDERER)); } /** * @brief Version string * + * The result is *not* cached, repeated queries will result in repeated + * OpenGL calls. * @see shadingLanguageVersionString(), version(), @fn_gl{GetString} * with @def_gl{VERSION} */ - inline std::string versionString() const { + std::string versionString() const { return reinterpret_cast(glGetString(GL_VERSION)); } /** * @brief Shading language version string * + * The result is *not* cached, repeated queries will result in repeated + * OpenGL calls. * @see versionString(), version(), @fn_gl{GetString} with * @def_gl{SHADING_LANGUAGE_VERSION} */ - inline std::string shadingLanguageVersionString() const { + std::string shadingLanguageVersionString() const { return reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); } + /** + * @brief Shading language version strings + * + * The result is *not* cached, repeated queries will result in repeated + * OpenGL calls. + * @see versionString(), version(), @fn_gl{Get} with @def_gl{NUM_SHADING_LANGUAGE_VERSIONS}, + * @fn_gl{GetString} with @def_gl{SHADING_LANGUAGE_VERSION} + */ + std::vector shadingLanguageVersionStrings() const; + + /** @brief Context flags */ + Flags flags() const { return _flags; } + /** * @brief Supported extensions * @@ -231,7 +290,7 @@ class MAGNUM_EXPORT Context { * * @see isExtensionSupported(), Extension::extensions() */ - inline const std::vector& supportedExtensions() const { + const std::vector& supportedExtensions() const { return _supportedExtensions; } @@ -240,7 +299,7 @@ class MAGNUM_EXPORT Context { * * @see supportedVersion(), MAGNUM_ASSERT_VERSION_SUPPORTED() */ - inline bool isVersionSupported(Version version) const { + bool isVersionSupported(Version version) const { #ifndef CORRADE_GCC44_COMPATIBILITY return _version >= version; #else @@ -280,7 +339,7 @@ class MAGNUM_EXPORT Context { * @see isExtensionSupported(const Extension&) const, * MAGNUM_ASSERT_EXTENSION_SUPPORTED() */ - template inline bool isExtensionSupported() const { + template bool isExtensionSupported() const { return isVersionSupported(T::coreVersion()) || (isVersionSupported(T::requiredVersion()) && extensionStatus[T::Index]); } @@ -294,12 +353,12 @@ class MAGNUM_EXPORT Context { * @see supportedExtensions(), Extension::extensions(), * MAGNUM_ASSERT_EXTENSION_SUPPORTED() */ - inline bool isExtensionSupported(const Extension& extension) const { + bool isExtensionSupported(const Extension& extension) const { return isVersionSupported(extension._coreVersion) || (isVersionSupported(extension._requiredVersion) && extensionStatus[extension._index]); } #ifndef DOXYGEN_GENERATING_OUTPUT - inline Implementation::State* state() { return _state; } + Implementation::State* state() { return _state; } #endif private: @@ -308,6 +367,7 @@ class MAGNUM_EXPORT Context { Version _version; Int _majorVersion; Int _minorVersion; + Flags _flags; std::bitset<128> extensionStatus; std::vector _supportedExtensions; @@ -337,7 +397,7 @@ MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); #else #define MAGNUM_ASSERT_VERSION_SUPPORTED(version) \ do { \ - if(!Context::current()->isVersionSupported(version)) { \ + if(!Magnum::Context::current()->isVersionSupported(version)) { \ Corrade::Utility::Error() << "Magnum: required version" << version << "is not supported"; \ std::exit(-3); \ } \ @@ -367,7 +427,7 @@ MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); #else #define MAGNUM_ASSERT_EXTENSION_SUPPORTED(extension) \ do { \ - if(!Context::current()->isExtensionSupported()) { \ + if(!Magnum::Context::current()->isExtensionSupported()) { \ Corrade::Utility::Error() << "Magnum: required extension" << extension::string() << "is not supported"; \ std::exit(-3); \ } \ diff --git a/src/CubeMapTexture.h b/src/CubeMapTexture.h index 2a515c686..b9f99ba88 100644 --- a/src/CubeMapTexture.h +++ b/src/CubeMapTexture.h @@ -54,30 +54,32 @@ See Texture documentation for introduction. Common usage is to fully configure all texture parameters and then set the data from e.g. set of Image objects: @code -Image2D positiveX({256, 256}, Image2D::Components::RGBA, Image2D::ComponentType::UnsignedByte, dataPositiveX); +Image2D positiveX({256, 256}, ImageFormat::RGBA, ImageType::UnsignedByte, dataPositiveX); // ... CubeMapTexture texture; -texture.setMagnificationFilter(Texture2D::Filter::Linear) +texture.setMagnificationFilter(Sampler::Filter::Linear) // ... - ->setStorage(Math::log2(256)+1, Texture2D::Format::RGBA8, {256, 256}) + ->setStorage(Math::log2(256)+1, TextureFormat::RGBA8, {256, 256}) ->setSubImage(CubeMapTexture::Coordinate::PositiveX, 0, {}, &positiveX) ->setSubImage(CubeMapTexture::Coordinate::NegativeX, 0, {}, &negativeX) // ... @endcode The texture is bound to layer specified by shader via bind(). In shader, the -texture is used via `samplerCube`. 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 -AbstractShaderProgram for more information. - -@see CubeMapTextureArray +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 AbstractShaderProgram for more +information about usage in shaders. + +@see @ref Renderer::Feature "Renderer::Feature::SeamlessCubeMapTexture", + CubeMapTextureArray, Texture, BufferTexture */ class CubeMapTexture: public AbstractTexture { public: /** @brief Cube map coordinate */ - enum Coordinate: GLenum { + enum class Coordinate: GLenum { PositiveX = GL_TEXTURE_CUBE_MAP_POSITIVE_X, /**< +X cube side */ NegativeX = GL_TEXTURE_CUBE_MAP_NEGATIVE_X, /**< -X cube side */ PositiveY = GL_TEXTURE_CUBE_MAP_POSITIVE_Y, /**< +Y cube side */ @@ -86,35 +88,20 @@ class CubeMapTexture: public AbstractTexture { NegativeZ = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z /**< -Z cube side */ }; - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Enable/disable seamless cube map textures - * - * Initially disabled on desktop OpenGL. - * @see @fn_gl{Enable}/@fn_gl{Disable} with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS} - * @requires_gl32 %Extension @extension{ARB,seamless_cube_map} - * @requires_gl Not available in OpenGL ES 2.0, always enabled in - * OpenGL ES 3.0. - */ - inline static void setSeamless(bool enabled) { - enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - } - #endif - /** * @brief Constructor * * Creates one cube map OpenGL texture. * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP} */ - inline explicit CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} + explicit CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} /** * @brief Set wrapping * * See Texture::setWrapping() for more information. */ - inline CubeMapTexture* setWrapping(const Array3D& wrapping) { + CubeMapTexture* setWrapping(const Array3D& wrapping) { DataHelper<3>::setWrapping(this, wrapping); return this; } @@ -128,7 +115,7 @@ class CubeMapTexture: public AbstractTexture { * See Texture::imageSize() for more information. * @requires_gl %Texture image queries are not available in OpenGL ES. */ - inline Vector2i imageSize(Coordinate coordinate, Int level) { + Vector2i imageSize(Coordinate coordinate, Int level) { return DataHelper<2>::imageSize(this, static_cast(coordinate), level); } #endif @@ -138,11 +125,41 @@ class CubeMapTexture: public AbstractTexture { * * See Texture::setStorage() for more information. */ - inline CubeMapTexture* setStorage(Int levels, InternalFormat internalFormat, const Vector2i& size) { + CubeMapTexture* setStorage(Int levels, TextureFormat internalFormat, const Vector2i& size) { DataHelper<2>::setStorage(this, _target, levels, internalFormat, size); return this; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Read given mip level of texture to image + * @param coordinate Coordinate + * @param level Mip level + * @param image %Image where to put the data + * + * See Texture::image(Int, Image*) for more information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + void image(Coordinate coordinate, Int level, Image2D* image) { + AbstractTexture::image<2>(GLenum(coordinate), level, image); + } + + /** + * @brief Read given mip level of texture to buffer image + * @param coordinate Coordinate + * @param level Mip level + * @param image %Buffer image where to put the data + * @param usage %Buffer usage + * + * See Texture::image(Int, BufferImage*, Buffer::Usage) for more + * information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + void image(Coordinate coordinate, Int level, BufferImage2D* image, Buffer::Usage usage) { + AbstractTexture::image<2>(GLenum(coordinate), level, image, usage); + } + #endif + /** * @brief Set image data * @param coordinate Coordinate @@ -154,8 +171,8 @@ class CubeMapTexture: public AbstractTexture { * * See Texture::setImage() for more information. */ - template inline CubeMapTexture* setImage(Coordinate coordinate, Int level, InternalFormat internalFormat, Image* image) { - DataHelper<2>::set(this, static_cast(coordinate), level, internalFormat, image); + template CubeMapTexture* setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, Image* image) { + DataHelper<2>::setImage(this, static_cast(coordinate), level, internalFormat, image); return this; } @@ -170,8 +187,8 @@ class CubeMapTexture: public AbstractTexture { * * See Texture::setSubImage() for more information. */ - template inline CubeMapTexture* setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, const Image* image) { - DataHelper<2>::setSub(this, static_cast(coordinate), level, offset, image); + template CubeMapTexture* setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, const Image* image) { + DataHelper<2>::setSubImage(this, static_cast(coordinate), level, offset, image); return this; } @@ -187,31 +204,31 @@ class CubeMapTexture: public AbstractTexture { * * See Texture::invalidateSubImage() for more information. */ - inline void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { - DataHelper<3>::invalidateSub(this, level, offset, size); + void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { + DataHelper<3>::invalidateSubImage(this, level, offset, size); } /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline CubeMapTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base) { + CubeMapTexture* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); return this; } - inline CubeMapTexture* setMagnificationFilter(Filter filter) { + CubeMapTexture* setMagnificationFilter(Sampler::Filter filter) { AbstractTexture::setMagnificationFilter(filter); return this; } #ifndef MAGNUM_TARGET_GLES3 - inline CubeMapTexture* setBorderColor(const Color4<>& color) { + CubeMapTexture* setBorderColor(const Color4<>& color) { AbstractTexture::setBorderColor(color); return this; } - inline CubeMapTexture* setMaxAnisotropy(Float anisotropy) { + CubeMapTexture* setMaxAnisotropy(Float anisotropy) { AbstractTexture::setMaxAnisotropy(anisotropy); return this; } #endif - inline CubeMapTexture* generateMipmap() { + CubeMapTexture* generateMipmap() { AbstractTexture::generateMipmap(); return this; } diff --git a/src/CubeMapTextureArray.h b/src/CubeMapTextureArray.h index 859621176..e4e443a2d 100644 --- a/src/CubeMapTextureArray.h +++ b/src/CubeMapTextureArray.h @@ -48,16 +48,16 @@ calling setStorage() or by passing properly sized empty Image to setImage(). Example: array with 16 layers of cube map faces, each face consisting of six 64x64 images: @code -Image3D dummy({64, 64, 16*6}, Image3D::Components::RGBA, Image3D::ComponentType::UnsignedByte, nullptr); +Image3D dummy({64, 64, 16*6}, ImageFormat::RGBA, ImageType::UnsignedByte, nullptr); CubeMapTextureArray texture; -texture.setMagnificationFilter(CubeMapTextureArray::Filter::Linear) +texture.setMagnificationFilter(Sampler::Filter::Linear) // ... - ->setStorage(Math::log2(64)+1, CubeMapTextureArray::Format::RGBA8, {64, 64, 16}); + ->setStorage(Math::log2(64)+1, TextureFormat::RGBA8, {64, 64, 16}); for(std::size_t i = 0; i != 16; ++i) { void* dataPositiveX = ...; - Image2D imagePositiveX({64, 64}, Image3D::Components::RGBA, Image3D::ComponentType::UnsignedByte, imagePositiveX); + Image2D imagePositiveX({64, 64}, ImageFormat::RGBA, ImageType::UnsignedByte, imagePositiveX); // ... texture->setSubImage(i, CubeMapTextureArray::Coordinate::PositiveX, 0, {}, imagePositiveX); texture->setSubImage(i, CubeMapTextureArray::Coordinate::NegativeX, 0, {}, imageNegativeX); @@ -68,20 +68,22 @@ for(std::size_t i = 0; i != 16; ++i) { @endcode The texture is bound to layer specified by shader via bind(). In shader, the -texture is used via `samplerCubeArray`. 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 AbstractShaderProgram for more information. +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 +AbstractShaderProgram for more information about usage in shaders. -@see CubeMapTexture::setSeamless() +@see @ref Renderer::Feature "Renderer::Feature::SeamlessCubeMapTexture", + CubeMapTexture, Texture, BufferTexture @requires_gl40 %Extension @extension{ARB,texture_cube_map_array} @requires_gl Cube map texture arrays are not available in OpenGL ES. */ class CubeMapTextureArray: public AbstractTexture { public: /** @brief Cube map coordinate */ - enum Coordinate: GLsizei { + enum class Coordinate: GLsizei { PositiveX = 0, /**< +X cube side */ NegativeX = 1, /**< -X cube side */ PositiveY = 2, /**< +Y cube side */ @@ -96,14 +98,14 @@ class CubeMapTextureArray: public AbstractTexture { * Creates one cube map OpenGL texture. * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP} */ - inline explicit CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} + explicit CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} /** * @brief Set wrapping * * See Texture::setWrapping() for more information. */ - inline CubeMapTextureArray* setWrapping(const Array3D& wrapping) { + CubeMapTextureArray* setWrapping(const Array3D& wrapping) { DataHelper<3>::setWrapping(this, wrapping); return this; } @@ -115,7 +117,7 @@ class CubeMapTextureArray: public AbstractTexture { * * See Texture::imageSize() for more information. */ - inline Vector3i imageSize(Coordinate coordinate, Int level) { + Vector3i imageSize(Coordinate coordinate, Int level) { return DataHelper<3>::imageSize(this, GL_TEXTURE_CUBE_MAP_POSITIVE_X + static_cast(coordinate), level); } @@ -124,11 +126,41 @@ class CubeMapTextureArray: public AbstractTexture { * * See Texture::setStorage() for more information. */ - inline CubeMapTextureArray* setStorage(Int levels, InternalFormat internalFormat, const Vector3i& size) { + CubeMapTextureArray* setStorage(Int levels, TextureFormat internalFormat, const Vector3i& size) { DataHelper<3>::setStorage(this, _target, levels, internalFormat, size); return this; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Read given mip level of texture to image + * @param coordinate Coordinate + * @param level Mip level + * @param image %Image where to put the data + * + * See Texture::image(Int, Image*) for more information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + void image(Coordinate coordinate, Int level, Image3D* image) { + AbstractTexture::image<3>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(coordinate), level, image); + } + + /** + * @brief Read given mip level of texture to buffer image + * @param coordinate Coordinate + * @param level Mip level + * @param image %Buffer image where to put the data + * @param usage %Buffer usage + * + * See Texture::image(Int, BufferImage*, Buffer::Usage) for more + * information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + void image(Coordinate coordinate, Int level, BufferImage3D* image, Buffer::Usage usage) { + AbstractTexture::image<3>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(coordinate), level, image, usage); + } + #endif + /** * @brief Set image data * @param level Mip level @@ -143,8 +175,8 @@ class CubeMapTextureArray: public AbstractTexture { * * See Texture::setImage() for more information. */ - template inline CubeMapTextureArray* setImage(Int level, InternalFormat internalFormat, T* image) { - DataHelper<3>::set(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); + template CubeMapTextureArray* setImage(Int level, TextureFormat internalFormat, T* image) { + DataHelper<3>::setImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); return this; } @@ -167,8 +199,8 @@ class CubeMapTextureArray: public AbstractTexture { * * @see setSubImage(Int, Coordinate, Int, const Math::Vector<2, Int>&, const Image*) */ - template inline CubeMapTextureArray* setSubImage(Int level, const Vector3i& offset, const Image* image) { - DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image, Vector3i(Math::Vector())); + template CubeMapTextureArray* setSubImage(Int level, const Vector3i& offset, const Image* image) { + DataHelper<3>::setSubImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image, Vector3i(Math::Vector())); return this; } @@ -186,8 +218,8 @@ class CubeMapTextureArray: public AbstractTexture { * * @see setSubImage(Int, const Math::Vector<3, Int>&, const Image*) */ - template inline CubeMapTextureArray* setSubImage(Int layer, Coordinate coordinate, Int level, const Vector2i& offset, const Image* image) { - DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, Vector3i(offset, layer*6+static_cast(coordinate)), image, Vector2i(Math::Vector())); + template CubeMapTextureArray* setSubImage(Int layer, Coordinate coordinate, Int level, const Vector2i& offset, const Image* image) { + DataHelper<3>::setSubImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, Vector3i(offset, layer*6+static_cast(coordinate)), image, Vector2i(Math::Vector())); return this; } @@ -203,31 +235,31 @@ class CubeMapTextureArray: public AbstractTexture { * * See Texture::invalidateSubImage() for more information. */ - inline void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { - DataHelper<3>::invalidateSub(this, level, offset, size); + void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { + DataHelper<3>::invalidateSubImage(this, level, offset, size); } /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline CubeMapTextureArray* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base) { + CubeMapTextureArray* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); return this; } - inline CubeMapTextureArray* setMagnificationFilter(Filter filter) { + CubeMapTextureArray* setMagnificationFilter(Sampler::Filter filter) { AbstractTexture::setMagnificationFilter(filter); return this; } #ifndef MAGNUM_TARGET_GLES3 - inline CubeMapTextureArray* setBorderColor(const Color4<>& color) { + CubeMapTextureArray* setBorderColor(const Color4<>& color) { AbstractTexture::setBorderColor(color); return this; } - inline CubeMapTextureArray* setMaxAnisotropy(Float anisotropy) { + CubeMapTextureArray* setMaxAnisotropy(Float anisotropy) { AbstractTexture::setMaxAnisotropy(anisotropy); return this; } #endif - inline CubeMapTextureArray* generateMipmap() { + CubeMapTextureArray* generateMipmap() { AbstractTexture::generateMipmap(); return this; } diff --git a/src/DebugMarker.h b/src/DebugMarker.h index 3429c3c53..04bf3625a 100644 --- a/src/DebugMarker.h +++ b/src/DebugMarker.h @@ -53,7 +53,7 @@ class MAGNUM_EXPORT DebugMarker { DebugMarker() = delete; /** @brief Put string mark into OpenGL command stream */ - inline static void mark(const std::string& string) { + static void mark(const std::string& string) { markImplementation(string); } diff --git a/src/DebugTools/CMakeLists.txt b/src/DebugTools/CMakeLists.txt index bbad443ce..8295748fe 100644 --- a/src/DebugTools/CMakeLists.txt +++ b/src/DebugTools/CMakeLists.txt @@ -55,10 +55,10 @@ endif() target_link_libraries(MagnumDebugTools Magnum MagnumMeshTools - MagnumPhysics MagnumPrimitives MagnumSceneGraph - MagnumShaders) + MagnumShaders + MagnumShapes) install(TARGETS MagnumDebugTools DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumDebugTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/DebugTools) diff --git a/src/DebugTools/ForceRenderer.cpp b/src/DebugTools/ForceRenderer.cpp index 618f97f9a..e0998962c 100644 --- a/src/DebugTools/ForceRenderer.cpp +++ b/src/DebugTools/ForceRenderer.cpp @@ -28,7 +28,7 @@ #include "Mesh.h" #include "DebugTools/ResourceManager.h" #include "SceneGraph/AbstractCamera.h" -#include "Shaders/FlatShader.h" +#include "Shaders/Flat.h" #include "DebugTools/Implementation/ForceRendererTransformation.h" @@ -66,8 +66,8 @@ const std::array indices{{ template ForceRenderer::ForceRenderer(SceneGraph::AbstractObject* object, const typename DimensionTraits::VectorType& forcePosition, const typename DimensionTraits::VectorType* force, ResourceKey options, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable(object, drawables), forcePosition(forcePosition), force(force), options(ResourceManager::instance()->get(options)) { /* Shader */ - shader = ResourceManager::instance()->get>(shaderKey()); - if(!shader) ResourceManager::instance()->set(shader.key(), new Shaders::FlatShader); + shader = ResourceManager::instance()->get>(shaderKey()); + if(!shader) ResourceManager::instance()->set(shader.key(), new Shaders::Flat); /* Mesh and vertex buffer */ mesh = ResourceManager::instance()->get("force"); @@ -89,7 +89,7 @@ template ForceRenderer::ForceRenderer(SceneG mesh->setPrimitive(Mesh::Primitive::Lines) ->setIndexCount(indices.size()) ->addVertexBuffer(vertexBuffer, 0, - typename Shaders::FlatShader::Position(Shaders::FlatShader::Position::Components::Two)) + typename Shaders::Flat::Position(Shaders::Flat::Position::Components::Two)) ->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, positions.size()); ResourceManager::instance()->set(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); } diff --git a/src/DebugTools/ForceRenderer.h b/src/DebugTools/ForceRenderer.h index 7af657909..f0af13d9b 100644 --- a/src/DebugTools/ForceRenderer.h +++ b/src/DebugTools/ForceRenderer.h @@ -44,10 +44,10 @@ See ForceRenderer documentation for more information. */ class ForceRendererOptions { public: - inline constexpr ForceRendererOptions(): _color(1.0f), _size(1.0f) {} + constexpr ForceRendererOptions(): _color(1.0f), _size(1.0f) {} /** @brief Color of rendered arrow */ - inline constexpr Color4<> color() const { return _color; } + constexpr Color4<> color() const { return _color; } /** * @brief Set color of rendered arrow @@ -55,13 +55,13 @@ class ForceRendererOptions { * * Default is 100% opaque white. */ - inline ForceRendererOptions* setColor(const Color4<>& color) { + ForceRendererOptions* setColor(const Color4<>& color) { _color = color; return this; } /** @brief Scale of rendered arrow */ - inline constexpr Float scale() const { return _size; } + constexpr Float scale() const { return _size; } /** * @brief Set scale of rendered arrow @@ -69,7 +69,7 @@ class ForceRendererOptions { * * Default is `1.0f`. */ - inline ForceRendererOptions* setSize(Float size) { + ForceRendererOptions* setSize(Float size) { _size = size; return this; } @@ -128,7 +128,7 @@ template class MAGNUM_DEBUGTOOLS_EXPORT ForceRenderer: p const typename DimensionTraits::VectorType* const force; Resource options; - Resource> shader; + Resource> shader; Resource mesh; Resource vertexBuffer, indexBuffer; }; diff --git a/src/DebugTools/Implementation/AbstractShapeRenderer.cpp b/src/DebugTools/Implementation/AbstractShapeRenderer.cpp index b976cb576..c11985bd5 100644 --- a/src/DebugTools/Implementation/AbstractShapeRenderer.cpp +++ b/src/DebugTools/Implementation/AbstractShapeRenderer.cpp @@ -29,7 +29,7 @@ #include "Mesh.h" #include "DebugTools/ResourceManager.h" #include "MeshTools/CompressIndices.h" -#include "Shaders/FlatShader.h" +#include "Shaders/Flat.h" #include "Trade/MeshData2D.h" #include "Trade/MeshData3D.h" @@ -53,7 +53,7 @@ template<> void create<2>(Trade::MeshData2D& data, Resource& meshResource, Mesh* mesh = new Mesh; mesh->setPrimitive(data.primitive()) ->setVertexCount(data.positions(0)->size()) - ->addVertexBuffer(buffer, 0, Shaders::FlatShader2D::Position()); + ->addVertexBuffer(buffer, 0, Shaders::Flat2D::Position()); ResourceManager::instance()->set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); /* Index buffer, if needed, if not, resource key doesn't have to be set */ @@ -75,7 +75,7 @@ template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, Mesh* mesh = new Mesh; mesh->setPrimitive(data.primitive()) ->setVertexCount(data.positions(0)->size()) - ->addVertexBuffer(vertexBuffer, 0, Shaders::FlatShader3D::Position()); + ->addVertexBuffer(vertexBuffer, 0, Shaders::Flat3D::Position()); ResourceManager::instance()->set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); /* Index buffer, if needed, if not, resource key doesn't have to be set */ @@ -90,13 +90,13 @@ template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, } template AbstractShapeRenderer::AbstractShapeRenderer(ResourceKey meshKey, ResourceKey vertexBufferKey, ResourceKey indexBufferKey) { - wireframeShader = ResourceManager::instance()->get>(shaderKey()); + wireframeShader = ResourceManager::instance()->get>(shaderKey()); wireframeMesh = ResourceManager::instance()->get(meshKey); vertexBuffer = ResourceManager::instance()->get(vertexBufferKey); indexBuffer = ResourceManager::instance()->get(indexBufferKey); if(!wireframeShader) ResourceManager::instance()->set(shaderKey(), - new Shaders::FlatShader, ResourceDataState::Final, ResourcePolicy::Resident); + new Shaders::Flat, ResourceDataState::Final, ResourcePolicy::Resident); } template AbstractShapeRenderer::~AbstractShapeRenderer() {} diff --git a/src/DebugTools/Implementation/AbstractShapeRenderer.h b/src/DebugTools/Implementation/AbstractShapeRenderer.h index 25105f6c4..bbc96185b 100644 --- a/src/DebugTools/Implementation/AbstractShapeRenderer.h +++ b/src/DebugTools/Implementation/AbstractShapeRenderer.h @@ -31,9 +31,15 @@ #include "Shaders/Shaders.h" #include "Trade/Trade.h" -namespace Magnum { namespace DebugTools { namespace Implementation { +namespace Magnum { -template struct MeshData; +namespace Shapes { namespace Implementation { + template struct AbstractShape; +}} + +namespace DebugTools { namespace Implementation { + +template struct MeshData; template<> struct MeshData<2> { typedef Trade::MeshData2D Type; }; template<> struct MeshData<3> { typedef Trade::MeshData3D Type; }; @@ -49,7 +55,7 @@ template class AbstractShapeRenderer { /* Call only if the mesh resource isn't already present */ void createResources(typename MeshData::Type data); - Resource> wireframeShader; + Resource> wireframeShader; Resource wireframeMesh; private: diff --git a/src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp index 4072650b5..faaf5cb5c 100644 --- a/src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp +++ b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp @@ -26,17 +26,17 @@ #include "Mesh.h" #include "DebugTools/ShapeRenderer.h" -#include "Physics/AxisAlignedBox.h" -#include "Shaders/FlatShader.h" +#include "Shapes/AxisAlignedBox.h" +#include "Shaders/Flat.h" namespace Magnum { namespace DebugTools { namespace Implementation { -template AxisAlignedBoxRenderer::AxisAlignedBoxRenderer(Physics::AxisAlignedBox& axisAlignedBox): axisAlignedBox(axisAlignedBox) {} +template AxisAlignedBoxRenderer::AxisAlignedBoxRenderer(const Shapes::Implementation::AbstractShape* axisAlignedBox): axisAlignedBox(static_cast>*>(axisAlignedBox)->shape) {} template void AxisAlignedBoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix* - DimensionTraits::MatrixType::translation((axisAlignedBox.transformedMin()+axisAlignedBox.transformedMax())/2)* - DimensionTraits::MatrixType::scaling(axisAlignedBox.transformedMax()-axisAlignedBox.transformedMin())) + DimensionTraits::MatrixType::translation((axisAlignedBox.min()+axisAlignedBox.max())/2)* + DimensionTraits::MatrixType::scaling(axisAlignedBox.max()-axisAlignedBox.min())) ->setColor(options->color()) ->use(); this->wireframeMesh->draw(); diff --git a/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h index 9247fa2a1..2af4617cd 100644 --- a/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h +++ b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h @@ -26,7 +26,7 @@ #include "AbstractBoxRenderer.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" #include "corradeCompatibility.h" @@ -34,12 +34,12 @@ namespace Magnum { namespace DebugTools { namespace Implementation { template class AxisAlignedBoxRenderer: public AbstractBoxRenderer { public: - AxisAlignedBoxRenderer(Physics::AxisAlignedBox& axisAlignedBox); + AxisAlignedBoxRenderer(const Shapes::Implementation::AbstractShape* axisAlignedBox); void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; private: - Physics::AxisAlignedBox& axisAlignedBox; + const Shapes::AxisAlignedBox& axisAlignedBox; }; }}} diff --git a/src/DebugTools/Implementation/BoxRenderer.cpp b/src/DebugTools/Implementation/BoxRenderer.cpp index 4e0bcb9fd..87b64ae26 100644 --- a/src/DebugTools/Implementation/BoxRenderer.cpp +++ b/src/DebugTools/Implementation/BoxRenderer.cpp @@ -26,15 +26,15 @@ #include "Mesh.h" #include "DebugTools/ShapeRenderer.h" -#include "Physics/Box.h" -#include "Shaders/FlatShader.h" +#include "Shapes/Box.h" +#include "Shaders/Flat.h" namespace Magnum { namespace DebugTools { namespace Implementation { -template BoxRenderer::BoxRenderer(Physics::Box& box): box(box) {} +template BoxRenderer::BoxRenderer(const Shapes::Implementation::AbstractShape* box): box(static_cast>*>(box)->shape) {} template void BoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { - this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*box.transformedTransformation()) + this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*box.transformation()) ->setColor(options->color()) ->use(); this->wireframeMesh->draw(); diff --git a/src/DebugTools/Implementation/BoxRenderer.h b/src/DebugTools/Implementation/BoxRenderer.h index 90b459113..20afc7ee9 100644 --- a/src/DebugTools/Implementation/BoxRenderer.h +++ b/src/DebugTools/Implementation/BoxRenderer.h @@ -26,7 +26,7 @@ #include "AbstractBoxRenderer.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" #include "corradeCompatibility.h" @@ -34,12 +34,12 @@ namespace Magnum { namespace DebugTools { namespace Implementation { template class BoxRenderer: public AbstractBoxRenderer { public: - BoxRenderer(Physics::Box& box); + BoxRenderer(const Shapes::Implementation::AbstractShape* box); void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; private: - Physics::Box& box; + const Shapes::Box& box; }; }}} diff --git a/src/DebugTools/Implementation/ForceRendererTransformation.h b/src/DebugTools/Implementation/ForceRendererTransformation.h index 067df4960..13cf870e7 100644 --- a/src/DebugTools/Implementation/ForceRendererTransformation.h +++ b/src/DebugTools/Implementation/ForceRendererTransformation.h @@ -37,7 +37,7 @@ template<> inline Matrix3 forceRendererTransformation<2>(const Vector2& forcePos return Matrix3::from({force, Vector2(-force.y(), force.x())}, forcePosition); } -template<> inline Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, const Vector3& force) { +template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, const Vector3& force) { const Matrix4 translation = Matrix4::translation(forcePosition); const Float forceLength = force.length(); diff --git a/src/DebugTools/Implementation/LineSegmentRenderer.cpp b/src/DebugTools/Implementation/LineSegmentRenderer.cpp index 900b96055..4436c3064 100644 --- a/src/DebugTools/Implementation/LineSegmentRenderer.cpp +++ b/src/DebugTools/Implementation/LineSegmentRenderer.cpp @@ -26,9 +26,9 @@ #include "Mesh.h" #include "DebugTools/ShapeRenderer.h" -#include "Physics/Line.h" +#include "Shapes/LineSegment.h" #include "Primitives/Line.h" -#include "Shaders/FlatShader.h" +#include "Shaders/Flat.h" #include "Trade/MeshData2D.h" #include "Trade/MeshData3D.h" @@ -50,13 +50,13 @@ namespace { template<> inline Trade::MeshData3D meshData<3>() { return Primitives::Line3D::wireframe(); } } -template LineSegmentRenderer::LineSegmentRenderer(Physics::Line& line): AbstractShapeRenderer(meshKey(), vertexBufferKey(), {}), line(line) { +template LineSegmentRenderer::LineSegmentRenderer(const Shapes::Implementation::AbstractShape* line): AbstractShapeRenderer(meshKey(), vertexBufferKey(), {}), line(static_cast>*>(line)->shape) { if(!this->wireframeMesh) this->createResources(meshData()); } template void LineSegmentRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix* - Implementation::lineSegmentRendererTransformation(line.transformedA(), line.transformedB())) + Implementation::lineSegmentRendererTransformation(line.a(), line.b())) ->setColor(options->color()) ->use(); this->wireframeMesh->draw(); diff --git a/src/DebugTools/Implementation/LineSegmentRenderer.h b/src/DebugTools/Implementation/LineSegmentRenderer.h index a67208825..550557dc9 100644 --- a/src/DebugTools/Implementation/LineSegmentRenderer.h +++ b/src/DebugTools/Implementation/LineSegmentRenderer.h @@ -26,7 +26,7 @@ #include "AbstractShapeRenderer.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" #include "corradeCompatibility.h" @@ -34,12 +34,12 @@ namespace Magnum { namespace DebugTools { namespace Implementation { template class LineSegmentRenderer: public AbstractShapeRenderer { public: - LineSegmentRenderer(Physics::Line& line); + LineSegmentRenderer(const Shapes::Implementation::AbstractShape* line); void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; private: - Physics::Line& line; + const Shapes::LineSegment& line; }; }}} diff --git a/src/DebugTools/Implementation/PointRenderer.cpp b/src/DebugTools/Implementation/PointRenderer.cpp index 31283541a..7827ca856 100644 --- a/src/DebugTools/Implementation/PointRenderer.cpp +++ b/src/DebugTools/Implementation/PointRenderer.cpp @@ -26,9 +26,9 @@ #include "Mesh.h" #include "DebugTools/ShapeRenderer.h" -#include "Physics/Point.h" +#include "Shapes/Point.h" #include "Primitives/Crosshair.h" -#include "Shaders/FlatShader.h" +#include "Shaders/Flat.h" #include "Trade/MeshData2D.h" #include "Trade/MeshData3D.h" @@ -48,14 +48,14 @@ namespace { template<> inline Trade::MeshData3D meshData<3>() { return Primitives::Crosshair3D::wireframe(); } } -template PointRenderer::PointRenderer(Physics::Point& point): AbstractShapeRenderer(meshKey(), vertexBufferKey(), {}), point(point) { +template PointRenderer::PointRenderer(const Shapes::Implementation::AbstractShape* point): AbstractShapeRenderer(meshKey(), vertexBufferKey(), {}), point(static_cast>*>(point)->shape) { if(!this->wireframeMesh) this->createResources(meshData()); } template void PointRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { /* Half scale, because the point is 2x2(x2) */ this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix* - DimensionTraits::MatrixType::translation(point.transformedPosition())* + DimensionTraits::MatrixType::translation(point.position())* DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->pointSize()/2))) ->setColor(options->color()) ->use(); diff --git a/src/DebugTools/Implementation/PointRenderer.h b/src/DebugTools/Implementation/PointRenderer.h index 4ac4c78c7..a017c1649 100644 --- a/src/DebugTools/Implementation/PointRenderer.h +++ b/src/DebugTools/Implementation/PointRenderer.h @@ -26,7 +26,7 @@ #include "AbstractShapeRenderer.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" #include "corradeCompatibility.h" @@ -34,12 +34,12 @@ namespace Magnum { namespace DebugTools { namespace Implementation { template class PointRenderer: public AbstractShapeRenderer { public: - PointRenderer(Physics::Point& point); + PointRenderer(const Shapes::Implementation::AbstractShape* point); void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; private: - Physics::Point& point; + const Shapes::Point& point; }; }}} diff --git a/src/DebugTools/Implementation/SphereRenderer.cpp b/src/DebugTools/Implementation/SphereRenderer.cpp index be6f8d2f5..3649d05b0 100644 --- a/src/DebugTools/Implementation/SphereRenderer.cpp +++ b/src/DebugTools/Implementation/SphereRenderer.cpp @@ -26,9 +26,9 @@ #include "Mesh.h" #include "DebugTools/ShapeRenderer.h" -#include "Physics/Sphere.h" +#include "Shapes/Sphere.h" #include "Primitives/Circle.h" -#include "Shaders/FlatShader.h" +#include "Shaders/Flat.h" #include "Trade/MeshData2D.h" namespace Magnum { namespace DebugTools { namespace Implementation { @@ -37,12 +37,12 @@ AbstractSphereRenderer<2>::AbstractSphereRenderer(): AbstractShapeRenderer<2>("s if(!wireframeMesh) createResources(Primitives::Circle::wireframe(40)); } -template SphereRenderer::SphereRenderer(Physics::Sphere& sphere): sphere(sphere) {} +template SphereRenderer::SphereRenderer(const Shapes::Implementation::AbstractShape* sphere): sphere(static_cast>*>(sphere)->shape) {} template void SphereRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix* - DimensionTraits::MatrixType::translation(sphere.transformedPosition())* - DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(sphere.transformedRadius()))) + DimensionTraits::MatrixType::translation(sphere.position())* + DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(sphere.radius()))) ->setColor(options->color()) ->use(); this->wireframeMesh->draw(); diff --git a/src/DebugTools/Implementation/SphereRenderer.h b/src/DebugTools/Implementation/SphereRenderer.h index e7cf52922..3c1a89649 100644 --- a/src/DebugTools/Implementation/SphereRenderer.h +++ b/src/DebugTools/Implementation/SphereRenderer.h @@ -26,7 +26,7 @@ #include "AbstractShapeRenderer.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" #include "corradeCompatibility.h" @@ -41,12 +41,12 @@ template<> class AbstractSphereRenderer<2>: public AbstractShapeRenderer<2> { template class SphereRenderer: public AbstractSphereRenderer { public: - SphereRenderer(Physics::Sphere& sphere); + SphereRenderer(const Shapes::Implementation::AbstractShape* sphere); void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; private: - Physics::Sphere& sphere; + const Shapes::Sphere& sphere; }; }}} diff --git a/src/DebugTools/ObjectRenderer.cpp b/src/DebugTools/ObjectRenderer.cpp index 240febe45..ed5cc13ab 100644 --- a/src/DebugTools/ObjectRenderer.cpp +++ b/src/DebugTools/ObjectRenderer.cpp @@ -28,7 +28,7 @@ #include "DebugTools/ResourceManager.h" #include "MeshTools/Interleave.h" #include "SceneGraph/AbstractCamera.h" -#include "Shaders/VertexColorShader.h" +#include "Shaders/VertexColor.h" namespace Magnum { namespace DebugTools { @@ -37,10 +37,10 @@ namespace { template struct Renderer; template<> struct Renderer<2> { - inline static ResourceKey shader() { return {"VertexColorShader2D"}; } - inline static ResourceKey vertexBuffer() { return {"object2d-vertices"}; } - inline static ResourceKey indexBuffer() { return {"object2d-indices"}; } - inline static ResourceKey mesh() { return {"object2d"}; } + static ResourceKey shader() { return {"VertexColorShader2D"}; } + static ResourceKey vertexBuffer() { return {"object2d-vertices"}; } + static ResourceKey indexBuffer() { return {"object2d-indices"}; } + static ResourceKey mesh() { return {"object2d"}; } static const std::array positions; static const std::array, 8> colors; @@ -82,10 +82,10 @@ const std::array Renderer<2>::indices{{ }}; template<> struct Renderer<3> { - inline static ResourceKey shader() { return {"VertexColorShader3D"}; } - inline static ResourceKey vertexBuffer() { return {"object3d-vertices"}; } - inline static ResourceKey indexBuffer() { return {"object3d-indices"}; } - inline static ResourceKey mesh() { return {"object3d"}; } + static ResourceKey shader() { return {"VertexColorShader3D"}; } + static ResourceKey vertexBuffer() { return {"object3d-vertices"}; } + static ResourceKey indexBuffer() { return {"object3d-indices"}; } + static ResourceKey mesh() { return {"object3d"}; } static const std::array positions; static const std::array, 12> colors; @@ -144,8 +144,8 @@ const std::array Renderer<3>::indices{{ template ObjectRenderer::ObjectRenderer(SceneGraph::AbstractObject* object, ResourceKey options, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable(object, drawables), options(ResourceManager::instance()->get(options)) { /* Shader */ - shader = ResourceManager::instance()->get>(Renderer::shader()); - if(!shader) ResourceManager::instance()->set(shader.key(), new Shaders::VertexColorShader); + shader = ResourceManager::instance()->get>(Renderer::shader()); + if(!shader) ResourceManager::instance()->set(shader.key(), new Shaders::VertexColor); /* Mesh and vertex buffer */ mesh = ResourceManager::instance()->get(Renderer::mesh()); @@ -167,8 +167,8 @@ template ObjectRenderer::ObjectRenderer(Scen mesh->setPrimitive(Mesh::Primitive::Lines) ->setIndexCount(Renderer::indices.size()) ->addInterleavedVertexBuffer(vertexBuffer, 0, - typename Shaders::VertexColorShader::Position(), - typename Shaders::VertexColorShader::Color()) + typename Shaders::VertexColor::Position(), + typename Shaders::VertexColor::Color()) ->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, Renderer::positions.size()); ResourceManager::instance()->set(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); } diff --git a/src/DebugTools/ObjectRenderer.h b/src/DebugTools/ObjectRenderer.h index cbafafd98..1c3c77f26 100644 --- a/src/DebugTools/ObjectRenderer.h +++ b/src/DebugTools/ObjectRenderer.h @@ -43,10 +43,10 @@ See ObjectRenderer documentation for more information. */ class ObjectRendererOptions { public: - inline constexpr ObjectRendererOptions(): _size(1.0f) {} + constexpr ObjectRendererOptions(): _size(1.0f) {} /** @brief Size of the rendered axes */ - inline constexpr Float size() const { return _size; } + constexpr Float size() const { return _size; } /** * @brief Set size of the rendered axes @@ -54,7 +54,7 @@ class ObjectRendererOptions { * * Default is `1.0f`. */ - inline ObjectRendererOptions* setSize(Float size) { + ObjectRendererOptions* setSize(Float size) { _size = size; return this; } @@ -104,7 +104,7 @@ template class MAGNUM_DEBUGTOOLS_EXPORT ObjectRenderer: private: Resource options; - Resource> shader; + Resource> shader; Resource mesh; Resource vertexBuffer, indexBuffer; }; diff --git a/src/DebugTools/Profiler.h b/src/DebugTools/Profiler.h index 47818ddb1..d1a64e9dc 100644 --- a/src/DebugTools/Profiler.h +++ b/src/DebugTools/Profiler.h @@ -115,9 +115,7 @@ class MAGNUM_DEBUGTOOLS_EXPORT Profiler { */ static const Section otherSection = 0; - #ifndef DOXYGEN_GENERATING_OUTPUT explicit Profiler(): enabled(false), measureDuration(60), currentFrame(0), frameCount(0), sections{"Other"}, currentSection(otherSection) {} - #endif /** * @brief Set measure duration @@ -174,7 +172,7 @@ class MAGNUM_DEBUGTOOLS_EXPORT Profiler { * Same as calling `start(Profiler::otherSection)`. * @note Does nothing if profiling is disabled. */ - inline void start() { start(otherSection); } + void start() { start(otherSection); } /** * @brief Stop profiling diff --git a/src/DebugTools/ResourceManager.h b/src/DebugTools/ResourceManager.h index 3820cbcea..ccf907718 100644 --- a/src/DebugTools/ResourceManager.h +++ b/src/DebugTools/ResourceManager.h @@ -36,7 +36,7 @@ #include "../ResourceManager.h" #include "SceneGraph/SceneGraph.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" #include "DebugTools.h" #include "magnumDebugToolsVisibility.h" diff --git a/src/DebugTools/ShapeRenderer.cpp b/src/DebugTools/ShapeRenderer.cpp index 51a58f93c..459b25724 100644 --- a/src/DebugTools/ShapeRenderer.cpp +++ b/src/DebugTools/ShapeRenderer.cpp @@ -25,14 +25,8 @@ #include "ShapeRenderer.h" #include "ResourceManager.h" -#include "Physics/AbstractShape.h" -#include "Physics/AxisAlignedBox.h" -#include "Physics/Box.h" -#include "Physics/ObjectShape.h" -#include "Physics/LineSegment.h" -#include "Physics/Point.h" -#include "Physics/ShapeGroup.h" -#include "Physics/Sphere.h" +#include "Shapes/Composition.h" +#include "Shapes/Shape.h" #include "SceneGraph/AbstractCamera.h" #include "Implementation/AxisAlignedBoxRenderer.h" @@ -43,54 +37,55 @@ namespace Magnum { namespace DebugTools { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { -template<> void createDebugMesh(ShapeRenderer<2>* renderer, Physics::AbstractShape<2>* shape) { +template<> void createDebugMesh(ShapeRenderer<2>* renderer, const Shapes::Implementation::AbstractShape<2>* shape) { switch(shape->type()) { - case Physics::AbstractShape2D::Type::AxisAlignedBox: - renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<2>(*static_cast(shape))); + case Shapes::AbstractShape2D::Type::AxisAlignedBox: + renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<2>(shape)); break; - case Physics::AbstractShape2D::Type::Box: - renderer->renderers.push_back(new Implementation::BoxRenderer<2>(*static_cast(shape))); + case Shapes::AbstractShape2D::Type::Box: + renderer->renderers.push_back(new Implementation::BoxRenderer<2>(shape)); break; - case Physics::AbstractShape2D::Type::LineSegment: - renderer->renderers.push_back(new Implementation::LineSegmentRenderer<2>(*static_cast(shape))); + case Shapes::AbstractShape2D::Type::LineSegment: + renderer->renderers.push_back(new Implementation::LineSegmentRenderer<2>(shape)); break; - case Physics::AbstractShape2D::Type::Point: - renderer->renderers.push_back(new Implementation::PointRenderer<2>(*static_cast(shape))); + case Shapes::AbstractShape2D::Type::Point: + renderer->renderers.push_back(new Implementation::PointRenderer<2>(shape)); break; - case Physics::AbstractShape2D::Type::ShapeGroup: { - Physics::ShapeGroup2D* group = static_cast(shape); - if(group->first()) createDebugMesh(renderer, group->first()); - if(group->second()) createDebugMesh(renderer, group->second()); + case Shapes::AbstractShape2D::Type::Composition: { + const Shapes::Composition2D& composition = + static_cast*>(shape)->shape; + for(std::size_t i = 0; i != composition.size(); ++i) + createDebugMesh(renderer, Shapes::Implementation::getAbstractShape(composition, i)); } break; - case Physics::AbstractShape2D::Type::Sphere: - renderer->renderers.push_back(new Implementation::SphereRenderer<2>(*static_cast(shape))); + case Shapes::AbstractShape2D::Type::Sphere: + renderer->renderers.push_back(new Implementation::SphereRenderer<2>(shape)); break; default: Warning() << "DebugTools::ShapeRenderer2D::createShapeRenderer(): type" << shape->type() << "not implemented"; } } -template<> void createDebugMesh(ShapeRenderer<3>* renderer, Physics::AbstractShape<3>* shape) { +template<> void createDebugMesh(ShapeRenderer<3>* renderer, const Shapes::Implementation::AbstractShape<3>* shape) { switch(shape->type()) { - case Physics::AbstractShape3D::Type::AxisAlignedBox: - renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<3>(*static_cast(shape))); + case Shapes::AbstractShape3D::Type::AxisAlignedBox: + renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<3>(shape)); break; - case Physics::AbstractShape3D::Type::Box: - renderer->renderers.push_back(new Implementation::BoxRenderer<3>(*static_cast(shape))); + case Shapes::AbstractShape3D::Type::Box: + renderer->renderers.push_back(new Implementation::BoxRenderer<3>(shape)); break; - case Physics::AbstractShape3D::Type::LineSegment: - renderer->renderers.push_back(new Implementation::LineSegmentRenderer<3>(*static_cast(shape))); + case Shapes::AbstractShape3D::Type::LineSegment: + renderer->renderers.push_back(new Implementation::LineSegmentRenderer<3>(shape)); break; - case Physics::AbstractShape3D::Type::Point: - renderer->renderers.push_back(new Implementation::PointRenderer<3>(*static_cast(shape))); + case Shapes::AbstractShape3D::Type::Point: + renderer->renderers.push_back(new Implementation::PointRenderer<3>(shape)); break; - case Physics::AbstractShape3D::Type::ShapeGroup: { - Physics::ShapeGroup3D* group = static_cast(shape); - if(group->first()) createDebugMesh(renderer, group->first()); - if(group->second()) createDebugMesh(renderer, group->second()); + case Shapes::AbstractShape3D::Type::Composition: { + const Shapes::Composition3D& composition = + static_cast*>(shape)->shape; + for(std::size_t i = 0; i != composition.size(); ++i) + createDebugMesh(renderer, Shapes::Implementation::getAbstractShape(composition, i)); } break; default: Warning() << "DebugTools::ShapeRenderer3D::createShapeRenderer(): type" << shape->type() << "not implemented"; @@ -98,11 +93,9 @@ template<> void createDebugMesh(ShapeRenderer<3>* renderer, Physics::AbstractSha } } -#endif -template ShapeRenderer::ShapeRenderer(Physics::ObjectShape* shape, ResourceKey options, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable(shape->object(), drawables), options(ResourceManager::instance()->get(options)) { - CORRADE_ASSERT(shape->shape() != nullptr, "DebugTools::ShapeRenderer: cannot create renderer for empty shape", ); - Implementation::createDebugMesh(this, shape->shape()); +template ShapeRenderer::ShapeRenderer(Shapes::AbstractShape* shape, ResourceKey options, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable(shape->object(), drawables), options(ResourceManager::instance()->get(options)) { + Implementation::createDebugMesh(this, Shapes::Implementation::getAbstractShape(shape)); } template ShapeRenderer::~ShapeRenderer() { diff --git a/src/DebugTools/ShapeRenderer.h b/src/DebugTools/ShapeRenderer.h index 35c062915..a237cab71 100644 --- a/src/DebugTools/ShapeRenderer.h +++ b/src/DebugTools/ShapeRenderer.h @@ -31,7 +31,8 @@ #include "Color.h" #include "Resource.h" #include "SceneGraph/Drawable.h" -#include "Physics/Physics.h" +#include "Shapes/Shapes.h" +#include "Shapes/shapeImplementation.h" #include "magnumDebugToolsVisibility.h" @@ -42,13 +43,11 @@ namespace Magnum { namespace DebugTools { template class ShapeRenderer; #endif -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class AbstractShapeRenderer; - template void createDebugMesh(ShapeRenderer* renderer, Physics::AbstractShape* shape); + template void createDebugMesh(ShapeRenderer* renderer, const Shapes::Implementation::AbstractShape* shape); } -#endif /** @brief Shape renderer options @@ -67,10 +66,10 @@ class ShapeRendererOptions { Solid }; - inline constexpr ShapeRendererOptions(): _color(1.0f), _pointSize(0.25f), _renderMode(RenderMode::Wireframe) {} + constexpr ShapeRendererOptions(): _color(1.0f), _pointSize(0.25f), _renderMode(RenderMode::Wireframe) {} /** @brief Shape rendering mode */ - inline constexpr RenderMode renderMode() const { return _renderMode; } + constexpr RenderMode renderMode() const { return _renderMode; } /** * @brief Set shape rendering mode @@ -78,13 +77,13 @@ class ShapeRendererOptions { * * Default is @ref RenderMode "RenderMode::Wireframe". */ - inline ShapeRendererOptions* setRenderMode(RenderMode mode) { + ShapeRendererOptions* setRenderMode(RenderMode mode) { _renderMode = mode; return this; } /** @brief Color of rendered shape */ - inline constexpr Color4<> color() const { return _color; } + constexpr Color4<> color() const { return _color; } /** * @brief Set color of rendered shape @@ -92,22 +91,22 @@ class ShapeRendererOptions { * * Default is 100% opaque white. */ - inline ShapeRendererOptions* setColor(const Color4<>& color) { + ShapeRendererOptions* setColor(const Color4<>& color) { _color = color; return this; } /** @brief Point size */ - inline constexpr Float pointSize() const { return _pointSize; } + constexpr Float pointSize() const { return _pointSize; } /** * @brief Set point size * @return Pointer to self (for method chaining) * - * Size of rendered crosshairs, representing Physics::Point shapes. + * Size of rendered crosshairs, representing Shapes::Point shapes. * Default is `0.25f`. */ - inline ShapeRendererOptions* setPointSize(Float size) { + ShapeRendererOptions* setPointSize(Float size) { _pointSize = size; return this; } @@ -133,32 +132,29 @@ DebugTools::ResourceManager::instance()->set("red", (new DebugTools::ShapeRender ->setColor({1.0f, 0.0f, 0.0f})); // Create debug renderer for given shape, use "red" options for it -Physics::ObjectShape2D* shape; +Shapes::AbstractShape2D* shape; new DebugTools::ShapeRenderer2D(shape, "red", debugDrawables); @endcode @see ShapeRenderer2D, ShapeRenderer3D */ template class MAGNUM_DEBUGTOOLS_EXPORT ShapeRenderer: public SceneGraph::Drawable { - #ifndef DOXYGEN_GENERATING_OUTPUT - friend void Implementation::createDebugMesh<>(ShapeRenderer*, Physics::AbstractShape*); - #endif + friend void Implementation::createDebugMesh<>(ShapeRenderer*, const Shapes::Implementation::AbstractShape*); public: /** * @brief Constructor - * @param shape Object for which to create debug renderer + * @param shape Shape for which to create debug renderer * @param options Options resource key. See * @ref ShapeRenderer-usage "class documentation" for more * information. * @param drawables Drawable group * * The renderer is automatically added to shape's object features, - * @p shape must be available for the whole lifetime of the renderer. - * - * @attention Passed object must have assigned shape. + * @p shape must be available for the whole lifetime of the renderer + * and if it is group, it must not change its internal structure. */ - explicit ShapeRenderer(Physics::ObjectShape* shape, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); + explicit ShapeRenderer(Shapes::AbstractShape* shape, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); ~ShapeRenderer(); diff --git a/src/DebugTools/Test/ForceRendererTest.cpp b/src/DebugTools/Test/ForceRendererTest.cpp index 5dcf4022c..e02d3ce7d 100644 --- a/src/DebugTools/Test/ForceRendererTest.cpp +++ b/src/DebugTools/Test/ForceRendererTest.cpp @@ -28,7 +28,7 @@ namespace Magnum { namespace DebugTools { namespace Implementation { namespace Test { -class ForceRendererTest: public Corrade::TestSuite::Tester { +class ForceRendererTest: public TestSuite::Tester { public: explicit ForceRendererTest(); diff --git a/src/DebugTools/Test/LineSegmentRendererTest.cpp b/src/DebugTools/Test/LineSegmentRendererTest.cpp index 5e0a056bc..c87f992d3 100644 --- a/src/DebugTools/Test/LineSegmentRendererTest.cpp +++ b/src/DebugTools/Test/LineSegmentRendererTest.cpp @@ -31,7 +31,7 @@ namespace Magnum { namespace DebugTools { namespace Test { -class LineSegmentRendererTest: public Corrade::TestSuite::Tester { +class LineSegmentRendererTest: public TestSuite::Tester { public: explicit LineSegmentRendererTest(); diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index c7ae2effc..8f0a38148 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -311,7 +311,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ - inline DefaultFramebuffer* mapForDraw(DrawAttachment attachment) { + DefaultFramebuffer* mapForDraw(DrawAttachment attachment) { (this->*drawBufferImplementation)(static_cast(attachment)); return this; } @@ -329,7 +329,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - inline DefaultFramebuffer* mapForRead(ReadAttachment attachment) { + DefaultFramebuffer* mapForRead(ReadAttachment attachment) { (this->*readBufferImplementation)(static_cast(attachment)); return this; } @@ -367,7 +367,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline DefaultFramebuffer* setViewport(const Rectanglei& rectangle) { + DefaultFramebuffer* setViewport(const Rectanglei& rectangle) { AbstractFramebuffer::setViewport(rectangle); return this; } diff --git a/src/Extensions.h b/src/Extensions.h index de1d5c285..ea74900da 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -120,6 +120,7 @@ namespace GL { _extension(GL,ARB,shader_precision, GL400, GL410) // #98 _extension(GL,ARB,vertex_attrib_64bit, GL300, GL410) // #99 _extension(GL,ARB,viewport_array, GL210, GL410) // #100 + _extension(GL,ARB,robustness, GL210, None) // #105 _extension(GL,ARB,base_instance, GL210, GL420) // #107 _extension(GL,ARB,shading_language_420pack, GL300, GL420) // #108 _extension(GL,ARB,transform_feedback_instanced, GL210, GL420) // #109 @@ -186,6 +187,7 @@ namespace GL { #line 1 namespace ANGLE { _extension(GL,ANGLE,framebuffer_blit, GLES200, GLES300) // #83 + _extension(GL,ANGLE,framebuffer_multisample, GLES200, GLES300) // #84 _extension(GL,ANGLE,depth_texture, GLES200, GLES300) // #138 } namespace APPLE { _extension(GL,APPLE,framebuffer_multisample, GLES200, GLES300) // #78 @@ -204,8 +206,10 @@ namespace GL { _extension(GL,EXT,separate_shader_objects, GLES200, None) // #101 _extension(GL,EXT,texture_rg, GLES200, GLES300) // #103 _extension(GL,EXT,sRGB, GLES200, None) // #105 + _extension(GL,EXT,robustness, GLES200, None) // #105 _extension(GL,EXT,texture_storage, GLES200, GLES300) // #108 _extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121 + _extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150 } namespace NV { _extension(GL,NV,draw_buffers, GLES200, GLES300) // #91 _extension(GL,NV,read_buffer, GLES200, GLES300) // #93 @@ -214,6 +218,7 @@ namespace GL { _extension(GL,NV,read_stencil, GLES200, None) // #94 _extension(GL,NV,read_depth_stencil, GLES200, GLES300) // #94 _extension(GL,NV,framebuffer_blit, GLES200, GLES300) // #142 + _extension(GL,NV,framebuffer_multisample, GLES200, GLES300) // #143 _extension(GL,NV,texture_border_clamp, GLES200, None) // #149 } namespace OES { _extension(GL,OES,depth24, GLES200, GLES300) // #24 @@ -231,6 +236,7 @@ namespace GL { _extension(GL,OES,vertex_half_float, GLES200, GLES300) // #38 _extension(GL,OES,packed_depth_stencil, GLES200, GLES300) // #43 _extension(GL,OES,depth_texture, GLES200, GLES300) // #44 + _extension(GL,OES,standard_derivatives, GLES200, GLES300) // #45 _extension(GL,OES,vertex_array_object, GLES200, GLES300) // #71 _extension(GL,OES,required_internalformat, GLES200, GLES300) // #? } diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 581b6211b..7991cc029 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -114,13 +114,13 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @brief Constructor * @param id Color attachment id */ - inline constexpr explicit ColorAttachment(UnsignedInt id): attachment(GL_COLOR_ATTACHMENT0 + id) {} + constexpr explicit ColorAttachment(UnsignedInt id): attachment(GL_COLOR_ATTACHMENT0 + id) {} #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef CORRADE_GCC44_COMPATIBILITY - inline constexpr explicit operator GLenum() const { return attachment; } + constexpr explicit operator GLenum() const { return attachment; } #else - inline constexpr operator GLenum() const { return attachment; } + constexpr operator GLenum() const { return attachment; } #endif #endif @@ -139,18 +139,18 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { static const DrawAttachment None; /** @brief Color attachment */ - inline constexpr /*implicit*/ DrawAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} + constexpr /*implicit*/ DrawAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef CORRADE_GCC44_COMPATIBILITY - inline constexpr explicit operator GLenum() const { return attachment; } + constexpr explicit operator GLenum() const { return attachment; } #else - inline constexpr operator GLenum() const { return attachment; } + constexpr operator GLenum() const { return attachment; } #endif #endif private: - inline constexpr explicit DrawAttachment(GLenum attachment): attachment(attachment) {} + constexpr explicit DrawAttachment(GLenum attachment): attachment(attachment) {} GLenum attachment; }; @@ -180,18 +180,18 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { #endif /** @brief Color buffer */ - inline constexpr /*implicit*/ BufferAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} + constexpr /*implicit*/ BufferAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef CORRADE_GCC44_COMPATIBILITY - inline constexpr explicit operator GLenum() const { return attachment; } + constexpr explicit operator GLenum() const { return attachment; } #else - inline constexpr operator GLenum() const { return attachment; } + constexpr operator GLenum() const { return attachment; } #endif #endif private: - inline constexpr explicit BufferAttachment(GLenum attachment): attachment(attachment) {} + constexpr explicit BufferAttachment(GLenum attachment): attachment(attachment) {} GLenum attachment; }; @@ -212,18 +212,18 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { static const InvalidationAttachment Stencil; /** @brief Invalidate color buffer */ - inline constexpr /*implicit*/ InvalidationAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} + constexpr /*implicit*/ InvalidationAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef CORRADE_GCC44_COMPATIBILITY - inline constexpr explicit operator GLenum() const { return attachment; } + constexpr explicit operator GLenum() const { return attachment; } #else - inline constexpr operator GLenum() const { return attachment; } + constexpr operator GLenum() const { return attachment; } #endif #endif private: - inline constexpr explicit InvalidationAttachment(GLenum attachment): attachment(attachment) {} + constexpr explicit InvalidationAttachment(GLenum attachment): attachment(attachment) {} GLenum attachment; }; @@ -282,7 +282,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @fn_gl{DrawBuffers} in OpenGL ES 3.0 * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ - inline Framebuffer* mapForDraw(DrawAttachment attachment) { + Framebuffer* mapForDraw(DrawAttachment attachment) { (this->*drawBufferImplementation)(GLenum(attachment)); return this; } @@ -330,7 +330,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - inline Framebuffer* mapForRead(ColorAttachment attachment) { + Framebuffer* mapForRead(ColorAttachment attachment) { (this->*readBufferImplementation)(GLenum(attachment)); return this; } @@ -347,7 +347,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or * @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} */ - inline Framebuffer* attachRenderbuffer(BufferAttachment attachment, Renderbuffer* renderbuffer) { + Framebuffer* attachRenderbuffer(BufferAttachment attachment, Renderbuffer* renderbuffer) { (this->*renderbufferImplementation)(attachment, renderbuffer); return this; } @@ -367,7 +367,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ - inline Framebuffer* attachTexture1D(BufferAttachment attachment, Texture1D* texture, Int level) { + Framebuffer* attachTexture1D(BufferAttachment attachment, Texture1D* texture, Int level) { (this->*texture1DImplementation)(attachment, texture, level); return this; } @@ -402,7 +402,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - inline Framebuffer* attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, Int level) { + Framebuffer* attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, Int level) { (this->*texture2DImplementation)(attachment, GLenum(coordinate), texture->id(), level); return this; } @@ -422,7 +422,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ - inline Framebuffer* attachTexture3D(BufferAttachment attachment, Texture3D* texture, Int level, Int layer) { + Framebuffer* attachTexture3D(BufferAttachment attachment, Texture3D* texture, Int level, Int layer) { /** @todo Check for texture target compatibility */ (this->*texture3DImplementation)(attachment, texture, level, layer); return this; @@ -430,7 +430,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline Framebuffer* setViewport(const Rectanglei& rectangle) { + Framebuffer* setViewport(const Rectanglei& rectangle) { AbstractFramebuffer::setViewport(rectangle); return this; } diff --git a/src/Image.cpp b/src/Image.cpp index a1c67a30a..71c5b1a7c 100644 --- a/src/Image.cpp +++ b/src/Image.cpp @@ -26,7 +26,7 @@ namespace Magnum { -template void Image::setData(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data) { +template void Image::setData(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, void* data) { delete[] _data; _format = format; _type = type; @@ -34,8 +34,10 @@ template void Image::setData(const typename _data = reinterpret_cast(data); } -template class Image<1>; -template class Image<2>; -template class Image<3>; +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_EXPORT Image<1>; +template class MAGNUM_EXPORT Image<2>; +template class MAGNUM_EXPORT Image<3>; +#endif } diff --git a/src/Image.h b/src/Image.h index f0de0ad67..54712ae18 100644 --- a/src/Image.h +++ b/src/Image.h @@ -55,7 +55,7 @@ template class Image: public AbstractImage { * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - inline explicit Image(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} + explicit Image(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, void* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} /** * @brief Constructor @@ -65,17 +65,17 @@ template class Image: public AbstractImage { * Dimensions and data pointer are set to zero, call setData() to fill * the image with data. */ - inline explicit Image(Format format, Type type): AbstractImage(format, type), _data(nullptr) {} + explicit Image(ImageFormat format, ImageType type): AbstractImage(format, type), _data(nullptr) {} /** @brief Destructor */ - inline ~Image() { delete[] _data; } + ~Image() { delete[] _data; } /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + typename DimensionTraits::VectorType size() const { return _size; } /** @brief Pointer to raw data */ - inline unsigned char* data() { return _data; } - inline const unsigned char* data() const { return _data; } /**< @overload */ + unsigned char* data() { return _data; } + const unsigned char* data() const { return _data; } /**< @overload */ /** * @brief Set image data @@ -87,19 +87,13 @@ template class Image: public AbstractImage { * Deletes previous data and replaces them with new. Note that the * data are not copied, but they are deleted on destruction. */ - void setData(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data); + void setData(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, void* data); private: Math::Vector _size; unsigned char* _data; }; -#ifndef DOXYGEN_GENERATING_OUTPUT -extern template class MAGNUM_EXPORT Image<1>; -extern template class MAGNUM_EXPORT Image<2>; -extern template class MAGNUM_EXPORT Image<3>; -#endif - /** @brief One-dimensional image */ typedef Image<1> Image1D; diff --git a/src/ImageFormat.cpp b/src/ImageFormat.cpp new file mode 100644 index 000000000..014cf25eb --- /dev/null +++ b/src/ImageFormat.cpp @@ -0,0 +1,128 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "ImageFormat.h" + +#include + +namespace Magnum { + +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, ImageFormat value) { + switch(value) { + #define _c(value) case ImageFormat::value: return debug << "ImageFormat::" #value; + _c(Red) + #ifndef MAGNUM_TARGET_GLES + _c(Green) + _c(Blue) + #endif + _c(RG) + _c(RGB) + _c(RGBA) + #ifndef MAGNUM_TARGET_GLES + _c(BGR) + #endif + #ifndef MAGNUM_TARGET_GLES3 + _c(BGRA) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(RedInteger) + #ifndef MAGNUM_TARGET_GLES + _c(GreenInteger) + _c(BlueInteger) + #endif + _c(RGInteger) + _c(RGBInteger) + _c(RGBAInteger) + #ifndef MAGNUM_TARGET_GLES + _c(BGRInteger) + _c(BGRAInteger) + #endif + #endif + _c(DepthComponent) + #ifndef MAGNUM_TARGET_GLES3 + _c(StencilIndex) + #endif + _c(DepthStencil) + #undef _c + } + + return debug << "ImageFormat::(invalid)"; +} + +Debug operator<<(Debug debug, ImageType value) { + switch(value) { + #define _c(value) case ImageType::value: return debug << "ImageType::" #value; + _c(UnsignedByte) + #ifndef MAGNUM_TARGET_GLES2 + _c(Byte) + #endif + _c(UnsignedShort) + #ifndef MAGNUM_TARGET_GLES2 + _c(Short) + #endif + _c(UnsignedInt) + #ifndef MAGNUM_TARGET_GLES2 + _c(Int) + #endif + _c(HalfFloat) + _c(Float) + #ifndef MAGNUM_TARGET_GLES + _c(UnsignedByte332) + _c(UnsignedByte233Rev) + #endif + _c(UnsignedShort565) + #ifndef MAGNUM_TARGET_GLES + _c(UnsignedShort565Rev) + #endif + _c(UnsignedShort4444) + #ifndef MAGNUM_TARGET_GLES3 + _c(UnsignedShort4444Rev) + #endif + _c(UnsignedShort5551) + #ifndef MAGNUM_TARGET_GLES3 + _c(UnsignedShort1555Rev) + #endif + #ifndef MAGNUM_TARGET_GLES + _c(UnsignedInt8888) + _c(UnsignedInt8888Rev) + _c(UnsignedInt1010102) + #endif + _c(UnsignedInt2101010Rev) + #ifndef MAGNUM_TARGET_GLES2 + _c(UnsignedInt10F11F11FRev) + _c(UnsignedInt5999Rev) + #endif + _c(UnsignedInt248) + #ifndef MAGNUM_TARGET_GLES2 + _c(Float32UnsignedInt248Rev) + #endif + #undef _c + } + + return debug << "ImageType::(invalid)"; +} +#endif + +} diff --git a/src/ImageFormat.h b/src/ImageFormat.h new file mode 100644 index 000000000..23b2a58f8 --- /dev/null +++ b/src/ImageFormat.h @@ -0,0 +1,454 @@ +#ifndef Magnum_ImageFormat_h +#define Magnum_ImageFormat_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Enum Magnum::ImageFormat, Magnum::ImageType + */ + +#include "Magnum.h" +#include "OpenGL.h" +#include "magnumVisibility.h" + +namespace Magnum { + +/** +@brief Format of image data + +Note that some formats can be used only for framebuffer reading (using +AbstractFramebuffer::read()) and some only for texture data (using Texture::setImage() +and others). +@see Image, ImageWrapper, BufferImage, Trade::ImageData +*/ +enum class ImageFormat: 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}. + */ + #ifndef MAGNUM_TARGET_GLES2 + Red = GL_RED, + #else + Red = GL_RED_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Floating-point green channel. + * @requires_gl Only @ref Magnum::ImageFormat "ImageFormat::Red" is + * available in OpenGL ES. + */ + Green = GL_GREEN, + + /** + * Floating-point blue channel. + * @requires_gl Only @ref Magnum::ImageFormat "ImageFormat::Red" is + * available in OpenGL ES. + */ + Blue = GL_BLUE, + + /** @todo GL_ALPHA? */ + #endif + + /** + * 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_es_extension For framebuffer reading, extension @es_extension{EXT,texture_rg}. + */ + #ifndef MAGNUM_TARGET_GLES2 + RG = GL_RG, + #else + RG = GL_RG_EXT, + #endif + + /** + * Floating-point RGB. + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + */ + RGB = GL_RGB, + + /** Floating-point RGBA. */ + RGBA = GL_RGBA, + + #ifndef MAGNUM_TARGET_GLES + /** + * Floating-point BGR. + * @requires_gl Only RGB component ordering is available in OpenGL ES. + */ + BGR = GL_BGR, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * Floating-point BGRA. + * @requires_es_extension %Extension @es_extension{EXT,read_format_bgra} + * for framebuffer reading, extension @es_extension{APPLE,texture_format_BGRA8888} + * or @es_extension{EXT,texture_format_BGRA8888} for texture data. + */ + #ifndef MAGNUM_TARGET_GLES + BGRA = GL_BGRA, + #else + BGRA = GL_BGRA_EXT, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Integer red channel. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only floating-point image data are available in OpenGL + * ES 2.0. + */ + RedInteger = GL_RED_INTEGER, + + #ifndef MAGNUM_TARGET_GLES + /** + * Integer green channel. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gl Only @ref Magnum::ImageFormat "ImageFormat::RedInteger" + * is available in OpenGL ES 3.0, only floating-point image data are + * available in OpenGL ES 2.0. + */ + GreenInteger = GL_GREEN_INTEGER, + + /** + * Integer blue channel. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gl Only @ref Magnum::ImageFormat "ImageFormat::RedInteger" is + * available in OpenGL ES 3.0, only floating-point image data are + * available in OpenGL ES 2.0. + */ + BlueInteger = GL_BLUE_INTEGER, + #endif + + /** + * Integer red and green channel. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + * @requires_gles30 For texture data only, only floating-point image data + * are available in OpenGL ES 2.0. + */ + RGInteger = GL_RG_INTEGER, + + /** + * Integer RGB. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + * @requires_gles30 For texture data only, only floating-point image data + * are available in OpenGL ES 2.0. + */ + RGBInteger = GL_RGB_INTEGER, + + /** + * Integer RGBA. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only floating-point image data are available in OpenGL + * ES 2.0. + */ + RGBAInteger = GL_RGBA_INTEGER, + + #ifndef MAGNUM_TARGET_GLES + /** + * Integer BGR. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gl Only @ref Magnum::ImageFormat "ImageFormat::RGBInteger" is + * available in OpenGL ES 3.0, only floating-point image data are + * available in OpenGL ES 2.0. + */ + BGRInteger = GL_BGR_INTEGER, + + /** + * Integer BGRA. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gl Only @ref Magnum::ImageFormat "ImageFormat::RGBAInteger" is + * available in OpenGL ES 3.0, only floating-point image data are + * available in OpenGL ES 2.0. + */ + BGRAInteger = GL_BGRA_INTEGER, + #endif + #endif + + /** + * Depth component. + * @requires_gles30 For texture data only, extension @es_extension{ANGLE,depth_texture}. + * @requires_es_extension For framebuffer reading only, extension + * @es_extension2{NV,read_depth,GL_NV_read_depth_stencil}. + */ + DepthComponent = GL_DEPTH_COMPONENT, + + #ifndef MAGNUM_TARGET_GLES3 + /** + * Stencil index. For framebuffer reading only. + * @requires_es_extension %Extension @es_extension2{NV,read_stencil,GL_NV_read_depth_stencil} + * @todo Where to get GL_STENCIL_INDEX in ES? + */ + #ifndef MAGNUM_TARGET_GLES + StencilIndex = GL_STENCIL_INDEX, + #else + StencilIndex = 0x1901, + #endif + #endif + + /** + * Depth and stencil. + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. + * @requires_es_extension For framebuffer reading only, extension + * @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil}. + */ + #ifndef MAGNUM_TARGET_GLES2 + DepthStencil = GL_DEPTH_STENCIL + #else + DepthStencil = GL_DEPTH_STENCIL_OES + #endif +}; + +/** +@brief Type of image data + +Note that some formats can be used only for framebuffer reading (using +AbstractFramebuffer::read()) and some only for texture data (using Texture::setImage() +and others). +@see Image, ImageWrapper, BufferImage, Trade::ImageData + */ +enum class ImageType: GLenum { + /** Each component unsigned byte. */ + UnsignedByte = GL_UNSIGNED_BYTE, + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Each component signed byte. + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + * @requires_gles30 For texture data only, only @ref Magnum::ImageType "ImageType::UnsignedByte" + * is available in OpenGL ES 2.0. + */ + Byte = GL_BYTE, + #endif + + /** + * 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}. + */ + UnsignedShort = GL_UNSIGNED_SHORT, + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Each component signed short. + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + * @requires_gles30 For texture data only, only @ref Magnum::ImageType "ImageType::UnsignedShort" + * is available in OpenGL ES 2.0. + */ + Short = GL_SHORT, + #endif + + /** + * 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}. + */ + UnsignedInt = GL_UNSIGNED_INT, + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Each component signed int. + * @requires_gles30 Only @ref Magnum::ImageType "ImageType::UnsignedInt" + * is available in OpenGL ES 2.0. + */ + Int = GL_INT, + #endif + + /** + * 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}. + */ + #ifndef MAGNUM_TARGET_GLES2 + HalfFloat = GL_HALF_FLOAT, + #else + HalfFloat = GL_HALF_FLOAT_OES, + #endif + + /** + * Each component float. + * @requires_gles30 For texture data only, extension @es_extension{OES,texture_float}. + */ + Float = GL_FLOAT, + + #ifndef MAGNUM_TARGET_GLES + /** + * RGB, unsigned byte, red and green component 3bit, blue component 2bit. + * @requires_gl Packed 12bit types are not available in OpenGL ES. + */ + UnsignedByte332 = GL_UNSIGNED_BYTE_3_3_2, + + /** + * BGR, unsigned byte, red and green component 3bit, blue component 2bit. + * @requires_gl Packed 12bit types are not available in OpenGL ES. + */ + UnsignedByte233Rev = GL_UNSIGNED_BYTE_2_3_3_REV, + #endif + + /** + * RGB, unsigned byte, red and blue component 5bit, green 6bit. + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + */ + UnsignedShort565 = GL_UNSIGNED_SHORT_5_6_5, + + #ifndef MAGNUM_TARGET_GLES + /** + * BGR, unsigned short, red and blue 5bit, green 6bit. + * @requires_gl Only @ref Magnum::ImageType "ImageType::RGB565" is + * available in OpenGL ES. + */ + UnsignedShort565Rev = GL_UNSIGNED_SHORT_5_6_5_REV, + #endif + + /** + * RGBA, unsigned short, each component 4bit. + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + */ + UnsignedShort4444 = GL_UNSIGNED_SHORT_4_4_4_4, + + #ifndef MAGNUM_TARGET_GLES3 + /** + * ABGR, unsigned short, each component 4bit. + * @requires_es_extension For framebuffer reading only, extension + * @es_extension{EXT,read_format_bgra}. + */ + #ifndef MAGNUM_TARGET_GLES + UnsignedShort4444Rev = GL_UNSIGNED_SHORT_4_4_4_4_REV, + #else + UnsignedShort4444Rev = GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, + #endif + #endif + + /** + * RGBA, unsigned short, each RGB component 5bit, alpha component 1bit. + * @requires_gl Can't be used for framebuffer reading in OpenGL ES. + */ + UnsignedShort5551 = GL_UNSIGNED_SHORT_5_5_5_1, + + #ifndef MAGNUM_TARGET_GLES3 + /** + * ABGR, unsigned short, each RGB component 5bit, alpha component 1bit. + * @requires_es_extension For framebuffer reading only, extension + * @es_extension{EXT,read_format_bgra}. + */ + #ifndef MAGNUM_TARGET_GLES + UnsignedShort1555Rev = GL_UNSIGNED_SHORT_1_5_5_5_REV, + #else + UnsignedShort1555Rev = GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * RGBA, unsigned int, each component 8bit. + * @requires_gl Use @ref Magnum::ImageType "ImageType::UnsignedByte" in + * OpenGL ES instead. + */ + UnsignedInt8888 = GL_UNSIGNED_INT_8_8_8_8, + + /** + * ABGR, unsigned int, each component 8bit. + * @requires_gl Only RGBA component ordering is available in OpenGL ES, see + * @ref Magnum::ImageType "ImageType::UnsignedInt8888" for more + * information. + */ + UnsignedInt8888Rev = GL_UNSIGNED_INT_8_8_8_8_REV, + + /** + * RGBA, unsigned int, each RGB component 10bit, alpha component 2bit. + * @requires_gl Only @ref Magnum::ImageType "ImageType::UnsignedInt2101010Rev" + * is available in OpenGL ES. + */ + UnsignedInt1010102 = GL_UNSIGNED_INT_10_10_10_2, + #endif + + /** + * 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}. + */ + #ifndef MAGNUM_TARGET_GLES2 + UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, + #else + UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * BGR, unsigned int, red and green 11bit float, blue 10bit float. + * @requires_gl30 %Extension @extension{EXT,packed_float} + * @requires_gles30 Floating-point types are not available in OpenGL ES + * 2.0. + */ + UnsignedInt10F11F11FRev = GL_UNSIGNED_INT_10F_11F_11F_REV, + + /** + * BGR, unsigned int, each component 9bit + 5bit exponent. + * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} + * @requires_gles30 Only 8bit and 16bit types are available in OpenGL ES + * 2.0. + */ + UnsignedInt5999Rev = GL_UNSIGNED_INT_5_9_9_9_REV, + #endif + + /** + * Unsigned int, depth component 24bit, stencil index 8bit. + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. + */ + #ifdef MAGNUM_TARGET_GLES2 + UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES + #else + UnsignedInt248 = GL_UNSIGNED_INT_24_8, + + /** + * Float + unsigned int, depth component 32bit float, 24bit gap, stencil + * index 8bit. + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 For texture data only, only @ref Magnum::ImageType "ImageType::UnsignedInt248" + * is available in OpenGL ES 2.0. + */ + Float32UnsignedInt248Rev = GL_FLOAT_32_UNSIGNED_INT_24_8_REV + #endif +}; + +/** @debugoperator{ImageFormat} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, ImageFormat value); + +/** @debugoperator{ImageFormat} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, ImageType value); + +} + +#endif diff --git a/src/ImageWrapper.h b/src/ImageWrapper.h index e9e0b7f1d..8acbd16ac 100644 --- a/src/ImageWrapper.h +++ b/src/ImageWrapper.h @@ -62,7 +62,7 @@ template class ImageWrapper: public AbstractImage { * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - inline explicit ImageWrapper(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} + explicit ImageWrapper(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, void* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} /** * @brief Constructor @@ -73,14 +73,14 @@ template class ImageWrapper: public AbstractImage { * Data pointer is set to zero, call setData() to fill the image with * data. */ - inline explicit ImageWrapper(const typename DimensionTraits::VectorType& size, Format format, Type type): AbstractImage(format, type), _size(size), _data(nullptr) {} + explicit ImageWrapper(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type): AbstractImage(format, type), _size(size), _data(nullptr) {} /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + typename DimensionTraits::VectorType size() const { return _size; } /** @brief Pointer to raw data */ - inline unsigned char* data() { return _data; } - inline const unsigned char* data() const { return _data; } /**< @overload */ + unsigned char* data() { return _data; } + const unsigned char* data() const { return _data; } /**< @overload */ /** * @brief Set image data @@ -90,7 +90,7 @@ template class ImageWrapper: public AbstractImage { * passed in constructor. The data are not copied nor deleted on * destruction. */ - inline void setData(GLvoid* data) { + void setData(void* data) { _data = reinterpret_cast(data); } diff --git a/src/Implementation/BufferState.h b/src/Implementation/BufferState.h index 0378d8d6b..5c69f7201 100644 --- a/src/Implementation/BufferState.h +++ b/src/Implementation/BufferState.h @@ -43,7 +43,7 @@ struct BufferState { static std::size_t indexForTarget(Buffer::Target target); static const Buffer::Target targetForIndex[TargetCount-1]; - inline constexpr BufferState(): bindings() {} + constexpr BufferState(): bindings() {} /* Currently bound buffer for all targets */ GLuint bindings[TargetCount]; diff --git a/src/Implementation/FramebufferState.h b/src/Implementation/FramebufferState.h index df7464cff..f8c2d5ba4 100644 --- a/src/Implementation/FramebufferState.h +++ b/src/Implementation/FramebufferState.h @@ -26,11 +26,12 @@ #include "Math/Geometry/Rectangle.h" #include "Magnum.h" +#include "OpenGL.h" namespace Magnum { namespace Implementation { struct FramebufferState { - inline constexpr FramebufferState(): readBinding(0), drawBinding(0), renderbufferBinding(0) {} + constexpr FramebufferState(): readBinding(0), drawBinding(0), renderbufferBinding(0) {} GLuint readBinding, drawBinding, renderbufferBinding; Rectanglei viewport; diff --git a/src/Implementation/MeshState.h b/src/Implementation/MeshState.h index b12b1c5ae..e7c79ca6c 100644 --- a/src/Implementation/MeshState.h +++ b/src/Implementation/MeshState.h @@ -29,7 +29,7 @@ namespace Magnum { namespace Implementation { struct MeshState { - inline constexpr MeshState(): currentVAO(0) {} + constexpr MeshState(): currentVAO(0) {} GLuint currentVAO; }; diff --git a/src/SceneGraph/DualComplexTransformation.cpp b/src/Implementation/RendererState.h similarity index 74% rename from src/SceneGraph/DualComplexTransformation.cpp rename to src/Implementation/RendererState.h index 56a1f0af5..3092f9165 100644 --- a/src/SceneGraph/DualComplexTransformation.cpp +++ b/src/Implementation/RendererState.h @@ -1,3 +1,5 @@ +#ifndef Magnum_Implementation_RendererState_h +#define Magnum_Implementation_RendererState_h /* This file is part of Magnum. @@ -22,14 +24,22 @@ DEALINGS IN THE SOFTWARE. */ -#include "DualComplexTransformation.h" +#include "Renderer.h" -#include "Object.hpp" +namespace Magnum { namespace Implementation { -namespace Magnum { namespace SceneGraph { +struct RendererState { + constexpr RendererState() + #ifndef MAGNUM_TARGET_GLES3 + : resetNotificationStrategy() + #endif + {} -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Object>; -#endif + #ifndef MAGNUM_TARGET_GLES3 + Renderer::ResetNotificationStrategy resetNotificationStrategy; + #endif +}; }} + +#endif diff --git a/src/Implementation/ShaderProgramState.h b/src/Implementation/ShaderProgramState.h index 5313d7d6c..a3c02205d 100644 --- a/src/Implementation/ShaderProgramState.h +++ b/src/Implementation/ShaderProgramState.h @@ -24,12 +24,12 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum.h" +#include "OpenGL.h" namespace Magnum { namespace Implementation { struct ShaderProgramState { - inline constexpr ShaderProgramState(): current(0), maxSupportedVertexAttributeCount(0) {} + constexpr ShaderProgramState(): current(0), maxSupportedVertexAttributeCount(0) {} /* Currently used program */ GLuint current; diff --git a/src/Implementation/State.cpp b/src/Implementation/State.cpp index c4d00e811..a218a3f46 100644 --- a/src/Implementation/State.cpp +++ b/src/Implementation/State.cpp @@ -27,6 +27,7 @@ #include "BufferState.h" #include "FramebufferState.h" #include "MeshState.h" +#include "RendererState.h" #include "ShaderProgramState.h" #include "TextureState.h" @@ -36,12 +37,14 @@ State::State(): buffer(new BufferState), framebuffer(new FramebufferState), mesh(new MeshState), + renderer(new RendererState), shaderProgram(new ShaderProgramState), texture(new TextureState) {} State::~State() { delete texture; delete shaderProgram; + delete renderer; delete mesh; delete framebuffer; delete buffer; diff --git a/src/Implementation/State.h b/src/Implementation/State.h index 16b5b59c9..17a31f398 100644 --- a/src/Implementation/State.h +++ b/src/Implementation/State.h @@ -29,6 +29,7 @@ namespace Magnum { namespace Implementation { struct BufferState; struct FramebufferState; struct MeshState; +struct RendererState; struct ShaderProgramState; struct TextureState; @@ -39,6 +40,7 @@ struct State { BufferState* const buffer; FramebufferState* const framebuffer; MeshState* const mesh; + RendererState* const renderer; ShaderProgramState* const shaderProgram; TextureState* const texture; }; diff --git a/src/SceneGraph/MatrixTransformation2D.cpp b/src/Implementation/TextureState.cpp similarity index 84% rename from src/SceneGraph/MatrixTransformation2D.cpp rename to src/Implementation/TextureState.cpp index c546bd302..7524d218b 100644 --- a/src/SceneGraph/MatrixTransformation2D.cpp +++ b/src/Implementation/TextureState.cpp @@ -22,14 +22,12 @@ DEALINGS IN THE SOFTWARE. */ -#include "MatrixTransformation2D.h" +#include "TextureState.h" -#include "Object.hpp" +namespace Magnum { namespace Implementation { -namespace Magnum { namespace SceneGraph { +TextureState::TextureState(): maxSupportedLayerCount(0), maxSupportedAnisotropy(0.0f), currentLayer(0) {} -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Object>; -#endif +TextureState::~TextureState() = default; }} diff --git a/src/Implementation/TextureState.h b/src/Implementation/TextureState.h index 25d0d0500..2e53176c1 100644 --- a/src/Implementation/TextureState.h +++ b/src/Implementation/TextureState.h @@ -26,12 +26,13 @@ #include -#include "Magnum.h" +#include "OpenGL.h" namespace Magnum { namespace Implementation { struct TextureState { - inline TextureState(): maxSupportedLayerCount(0), maxSupportedAnisotropy(0.0f), currentLayer(0) {} + explicit TextureState(); + ~TextureState(); GLint maxSupportedLayerCount; GLfloat maxSupportedAnisotropy; diff --git a/src/Magnum.h b/src/Magnum.h index 8ff0d3064..016ff51ea 100644 --- a/src/Magnum.h +++ b/src/Magnum.h @@ -34,6 +34,10 @@ #include "Types.h" #include "magnumConfigure.h" +#ifndef DOXYGEN_GENERATING_OUTPUT +typedef unsigned int GLenum; /* Needed for *Format and *Type enums */ +#endif + namespace Corrade { namespace Utility { class Debug; @@ -59,6 +63,9 @@ namespace Math { #endif } +/* Bring whole Corrade namespace */ +using namespace Corrade; + /* Bring debugging facility from Corrade::Utility namespace */ using Corrade::Utility::Debug; using Corrade::Utility::Warning; @@ -325,7 +332,11 @@ using Math::operator "" _radf; /** @todoc Remove `ifndef` when Doxygen is sane again */ #ifndef DOXYGEN_GENERATING_OUTPUT /* Forward declarations for all types in root namespace */ + +/* FramebufferClear[Mask], FramebufferBlit[Mask], FramebufferBlitFilter, + FramebufferTarget enums used only directly with framebuffer instance */ class AbstractFramebuffer; + class AbstractImage; class AbstractShaderProgram; class AbstractTexture; @@ -346,6 +357,7 @@ typedef BufferImage<3> BufferImage3D; #ifndef MAGNUM_TARGET_GLES class BufferTexture; +enum class BufferTextureFormat: GLenum; #endif template class Color3; @@ -373,14 +385,23 @@ typedef Image<1> Image1D; typedef Image<2> Image2D; typedef Image<3> Image3D; +enum class ImageFormat: GLenum; +enum class ImageType: GLenum; + template class ImageWrapper; typedef ImageWrapper<1> ImageWrapper1D; typedef ImageWrapper<2> ImageWrapper2D; typedef ImageWrapper<3> ImageWrapper3D; class Mesh; -class Query; + +/* AbstractQuery is not used directly */ +class PrimitiveQuery; +class SampleQuery; +class TimeQuery; + class Renderbuffer; +enum class RenderbufferFormat: GLenum; #ifndef CORRADE_GCC45_COMPATIBILITY enum class ResourceState: UnsignedByte; @@ -391,6 +412,7 @@ template class Resource; class ResourceKey; template class ResourceManager; +class Sampler; class Shader; template class Texture; @@ -400,6 +422,8 @@ typedef Texture<1> Texture1D; typedef Texture<2> Texture2D; typedef Texture<3> Texture3D; +enum class TextureFormat: GLenum; + class Timeline; #endif diff --git a/src/Math/Algorithms/Svd.h b/src/Math/Algorithms/Svd.h index e86d68265..186970969 100644 --- a/src/Math/Algorithms/Svd.h +++ b/src/Math/Algorithms/Svd.h @@ -35,7 +35,6 @@ namespace Magnum { namespace Math { namespace Algorithms { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template T pythagoras(T a, T b) { @@ -50,13 +49,12 @@ template T pythagoras(T a, T b) { } template constexpr T smallestDelta(); -template<> inline constexpr Float smallestDelta() { return 1.0e-32; } +template<> constexpr Float smallestDelta() { return 1.0e-32; } #ifndef MAGNUM_TARGET_GLES -template<> inline constexpr Double smallestDelta() { return 1.0e-64; } +template<> constexpr Double smallestDelta() { return 1.0e-64; } #endif } -#endif /** @brief Singular Value Decomposition diff --git a/src/Math/Angle.h b/src/Math/Angle.h index fa68945f6..1f0b8c150 100644 --- a/src/Math/Angle.h +++ b/src/Math/Angle.h @@ -124,16 +124,16 @@ std::sin(Float(Rad(angleInDegrees)); // required explicit conversion hint template class Deg: public Unit { public: /** @brief Default constructor */ - inline constexpr /*implicit*/ Deg() {} + constexpr /*implicit*/ Deg() {} /** @brief Explicit constructor from unitless type */ - inline constexpr explicit Deg(T value): Unit(value) {} + constexpr explicit Deg(T value): Unit(value) {} /** @brief Copy constructor */ - inline constexpr /*implicit*/ Deg(Unit value): Unit(value) {} + constexpr /*implicit*/ Deg(Unit value): Unit(value) {} /** @brief Construct from another underlying type */ - template inline constexpr explicit Deg(Unit value): Unit(value) {} + template constexpr explicit Deg(Unit value): Unit(value) {} /** * @brief Construct degrees from radians @@ -143,7 +143,7 @@ template class Deg: public Unit { * deg = 180 \frac {rad} \pi * @f] */ - inline constexpr /*implicit*/ Deg(Unit value); + constexpr /*implicit*/ Deg(Unit value); }; #ifndef CORRADE_GCC46_COMPATIBILITY @@ -160,7 +160,7 @@ Double cosine = Math::cos(1.047_rad); // cosine = 0.5 @note Not available on GCC < 4.7. Use Deg::Deg(T) instead. @requires_gl Only single-precision types are available in OpenGL ES. */ -inline constexpr Deg operator "" _deg(long double value) { return Deg(value); } +constexpr Deg operator "" _deg(long double value) { return Deg(value); } #endif /** @relates Deg @@ -175,7 +175,7 @@ Float tangent = Math::tan(1.047_radf); // tangent = 1.732f @note Not available on GCC < 4.7. Use Deg::Deg(T) instead. @requires_gl Only single-precision types are available in OpenGL ES. */ -inline constexpr Deg operator "" _degf(long double value) { return Deg(value); } +constexpr Deg operator "" _degf(long double value) { return Deg(value); } #endif /** @@ -187,16 +187,16 @@ See Deg for more information. template class Rad: public Unit { public: /** @brief Default constructor */ - inline constexpr /*implicit*/ Rad() {} + constexpr /*implicit*/ Rad() {} /** @brief Construct from unitless type */ - inline constexpr explicit Rad(T value): Unit(value) {} + constexpr explicit Rad(T value): Unit(value) {} /** @brief Copy constructor */ - inline constexpr /*implicit*/ Rad(Unit value): Unit(value) {} + constexpr /*implicit*/ Rad(Unit value): Unit(value) {} /** @brief Construct from another underlying type */ - template inline constexpr explicit Rad(Unit value): Unit(value) {} + template constexpr explicit Rad(Unit value): Unit(value) {} /** * @brief Construct radians from degrees @@ -206,7 +206,7 @@ template class Rad: public Unit { * rad = deg \frac \pi 180 * @f] */ - inline constexpr /*implicit*/ Rad(Unit value); + constexpr /*implicit*/ Rad(Unit value); }; #ifndef CORRADE_GCC46_COMPATIBILITY @@ -218,7 +218,7 @@ See operator""_rad() for more information. @see Magnum::operator""_rad(), operator""_radf(), operator""_deg() @note Not available on GCC < 4.7. Use Rad::Rad(T) instead. */ -inline constexpr Rad operator "" _rad(long double value) { return Rad(value); } +constexpr Rad operator "" _rad(long double value) { return Rad(value); } #endif /** @relates Rad @@ -228,11 +228,11 @@ See operator""_degf() for more information. @see Magnum::operator""_radf(), operator""_rad(), operator""_degf() @note Not available on GCC < 4.7. Use Rad::Rad(T) instead. */ -inline constexpr Rad operator "" _radf(long double value) { return Rad(value); } +constexpr Rad operator "" _radf(long double value) { return Rad(value); } #endif -template inline constexpr Deg::Deg(Unit value): Unit(T(180)*value.toUnderlyingType()/Math::Constants::pi()) {} -template inline constexpr Rad::Rad(Unit value): Unit(value.toUnderlyingType()*Math::Constants::pi()/T(180)) {} +template constexpr Deg::Deg(Unit value): Unit(T(180)*value.toUnderlyingType()/Math::Constants::pi()) {} +template constexpr Rad::Rad(Unit value): Unit(value.toUnderlyingType()*Math::Constants::pi()/T(180)) {} /** @debugoperator{Magnum::Math::Rad} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit& value) { diff --git a/src/Math/BoolVector.h b/src/Math/BoolVector.h index bb1433091..9866ee114 100644 --- a/src/Math/BoolVector.h +++ b/src/Math/BoolVector.h @@ -35,10 +35,11 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { + /** @todo C++14: use std::make_index_sequence and std::integer_sequence */ template struct Sequence {}; + #ifndef DOXYGEN_GENERATING_OUTPUT /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ template struct GenerateSequence: GenerateSequence {}; @@ -46,10 +47,10 @@ namespace Implementation { template struct GenerateSequence<0, sequence...> { typedef Sequence Type; }; + #endif - template inline constexpr T repeat(T value, std::size_t) { return value; } + template constexpr T repeat(T value, std::size_t) { return value; } } -#endif /** @brief %Vector storing boolean values @@ -68,7 +69,7 @@ template class BoolVector { static const std::size_t DataSize = (size-1)/8+1; /**< @brief %Vector storage size */ /** @brief Construct zero-filled boolean vector */ - inline constexpr BoolVector(): _data() {} + constexpr BoolVector(): _data() {} /** * @brief Construct boolean vector from segment values @@ -76,9 +77,9 @@ template class BoolVector { * @param next Values for next Bbit segments */ #ifdef DOXYGEN_GENERATING_OUTPUT - template inline constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next); + template constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next); #else - template::type> inline constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next): _data{first, UnsignedByte(next)...} {} + template::type> constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next): _data{first, UnsignedByte(next)...} {} #endif /** @brief Construct boolean vector with one value for all fields */ @@ -86,19 +87,19 @@ template class BoolVector { inline explicit BoolVector(T value); #else #ifndef CORRADE_GCC46_COMPATIBILITY - template::value && size != 1, bool>::type> inline constexpr explicit BoolVector(T value): BoolVector(typename Implementation::GenerateSequence::Type(), value ? FullSegmentMask : 0) {} + template::value && size != 1, bool>::type> constexpr explicit BoolVector(T value): BoolVector(typename Implementation::GenerateSequence::Type(), value ? FullSegmentMask : 0) {} #else - template::value && size != 1, bool>::type> inline explicit BoolVector(T value) { + template::value && size != 1, bool>::type> explicit BoolVector(T value) { *this = BoolVector(typename Implementation::GenerateSequence::Type(), value ? FullSegmentMask : 0); } #endif #endif /** @brief Copy constructor */ - inline constexpr BoolVector(const BoolVector&) = default; + constexpr BoolVector(const BoolVector&) = default; /** @brief Copy assignment */ - inline BoolVector& operator=(const BoolVector&) = default; + BoolVector& operator=(const BoolVector&) = default; /** * @brief Raw data @@ -106,84 +107,46 @@ template class BoolVector { * * @see operator[](), set() */ - inline UnsignedByte* data() { return _data; } - inline constexpr const UnsignedByte* data() const { return _data; } /**< @overload */ + UnsignedByte* data() { return _data; } + constexpr const UnsignedByte* data() const { return _data; } /**< @overload */ /** @brief Bit at given position */ - inline constexpr bool operator[](std::size_t i) const { + constexpr bool operator[](std::size_t i) const { return (_data[i/8] >> i%8) & 0x01; } /** @brief Set bit at given position */ - inline BoolVector& set(std::size_t i, bool value) { + BoolVector& set(std::size_t i, bool value) { _data[i/8] |= ((value & 0x01) << i%8); return *this; } /** @brief Equality comparison */ - inline bool operator==(const BoolVector& other) const { - for(std::size_t i = 0; i != size/8; ++i) - if(_data[i] != other._data[i]) return false; - - /* Check last segment */ - if(size%8 && (_data[DataSize-1] & LastSegmentMask) != (other._data[DataSize-1] & LastSegmentMask)) - return false; - - return true; - } + bool operator==(const BoolVector& other) const; /** @brief Non-equality comparison */ - inline bool operator!=(const BoolVector& other) const { + bool operator!=(const BoolVector& other) const { return !operator==(other); } /** @brief Whether all bits are set */ - bool all() const { - /* Check all full segments */ - for(std::size_t i = 0; i != size/8; ++i) - if(_data[i] != FullSegmentMask) return false; - - /* Check last segment */ - if(size%8 && (_data[DataSize-1] & LastSegmentMask) != LastSegmentMask) - return false; - - return true; - } + bool all() const; /** @brief Whether no bits are set */ - bool none() const { - /* Check all full segments */ - for(std::size_t i = 0; i != size/8; ++i) - if(_data[i]) return false; - - /* Check last segment */ - if(size%8 && (_data[DataSize-1] & LastSegmentMask)) - return false; - - return true; - } + bool none() const; /** @brief Whether any bit is set */ - inline bool any() const { - return !none(); - } + bool any() const { return !none(); } /** @brief Bitwise inversion */ - inline BoolVector operator~() const { - BoolVector out; - - for(std::size_t i = 0; i != DataSize; ++i) - out._data[i] = ~_data[i]; - - return out; - } + BoolVector operator~() const; /** * @brief Bitwise AND and assign * * The computation is done in-place. */ - inline BoolVector& operator&=(const BoolVector& other) { + BoolVector& operator&=(const BoolVector& other) { for(std::size_t i = 0; i != DataSize; ++i) _data[i] &= other._data[i]; @@ -195,7 +158,7 @@ template class BoolVector { * * @see operator&=() */ - inline BoolVector operator&(const BoolVector& other) const { + BoolVector operator&(const BoolVector& other) const { return BoolVector(*this) &= other; } @@ -204,7 +167,7 @@ template class BoolVector { * * The computation is done in-place. */ - inline BoolVector& operator|=(const BoolVector& other) { + BoolVector& operator|=(const BoolVector& other) { for(std::size_t i = 0; i != DataSize; ++i) _data[i] |= other._data[i]; @@ -216,7 +179,7 @@ template class BoolVector { * * @see operator|=() */ - inline BoolVector operator|(const BoolVector& other) const { + BoolVector operator|(const BoolVector& other) const { return BoolVector(*this) |= other; } @@ -225,7 +188,7 @@ template class BoolVector { * * The computation is done in-place. */ - inline BoolVector& operator^=(const BoolVector& other) { + BoolVector& operator^=(const BoolVector& other) { for(std::size_t i = 0; i != DataSize; ++i) _data[i] ^= other._data[i]; @@ -237,7 +200,7 @@ template class BoolVector { * * @see operator^=() */ - inline BoolVector operator^(const BoolVector& other) const { + BoolVector operator^(const BoolVector& other) const { return BoolVector(*this) ^= other; } @@ -248,7 +211,7 @@ template class BoolVector { }; /* Implementation for Vector::Vector(U) */ - template inline constexpr explicit BoolVector(Implementation::Sequence, UnsignedByte value): _data{Implementation::repeat(value, sequence)...} {} + template constexpr explicit BoolVector(Implementation::Sequence, UnsignedByte value): _data{Implementation::repeat(value, sequence)...} {} UnsignedByte _data[(size-1)/8+1]; }; @@ -266,6 +229,50 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility:: return debug; } +template inline bool BoolVector::operator==(const BoolVector< size >& other) const { + for(std::size_t i = 0; i != size/8; ++i) + if(_data[i] != other._data[i]) return false; + + /* Check last segment */ + if(size%8 && (_data[DataSize-1] & LastSegmentMask) != (other._data[DataSize-1] & LastSegmentMask)) + return false; + + return true; +} + +template inline bool BoolVector::all() const { + /* Check all full segments */ + for(std::size_t i = 0; i != size/8; ++i) + if(_data[i] != FullSegmentMask) return false; + + /* Check last segment */ + if(size%8 && (_data[DataSize-1] & LastSegmentMask) != LastSegmentMask) + return false; + + return true; +} + +template inline bool BoolVector::none() const { + /* Check all full segments */ + for(std::size_t i = 0; i != size/8; ++i) + if(_data[i]) return false; + + /* Check last segment */ + if(size%8 && (_data[DataSize-1] & LastSegmentMask)) + return false; + + return true; +} + +template inline BoolVector BoolVector::operator~() const { + BoolVector out; + + for(std::size_t i = 0; i != DataSize; ++i) + out._data[i] = ~_data[i]; + + return out; +} + }} #endif diff --git a/src/Math/Complex.cpp b/src/Math/Complex.cpp deleted file mode 100644 index 0b234116c..000000000 --- a/src/Math/Complex.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "Complex.h" - -namespace Magnum { namespace Math { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Complex&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Complex&); -#endif -#endif - -}} diff --git a/src/Math/Complex.h b/src/Math/Complex.h index c423fc3fa..4788c5e5a 100644 --- a/src/Math/Complex.h +++ b/src/Math/Complex.h @@ -37,14 +37,13 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - /* No assertions fired, for internal use */ - template inline static Complex complexFromMatrix(const Matrix<2, T>& matrix) { + /* No assertions fired, for internal use. Not private member because used + from outside the class. */ + template constexpr static Complex complexFromMatrix(const Matrix<2, T>& matrix) { return {matrix[0][0], matrix[0][1]}; } } -#endif /** @brief %Complex number @@ -65,7 +64,7 @@ template class Complex { * @f] * @see dot() const */ - inline static T dot(const Complex& a, const Complex& b) { + static T dot(const Complex& a, const Complex& b) { return a._real*b._real + a._imaginary*b._imaginary; } @@ -77,7 +76,7 @@ template class Complex { * @f] * @see isNormalized(), Quaternion::angle(), Vector::angle() */ - inline static Rad angle(const Complex& normalizedA, const Complex& normalizedB) { + static Rad angle(const Complex& normalizedA, const Complex& normalizedB) { CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), "Math::Complex::angle(): complex numbers must be normalized", Rad(std::numeric_limits::quiet_NaN())); return Rad(std::acos(normalizedA._real*normalizedB._real + normalizedA._imaginary*normalizedB._imaginary)); @@ -92,7 +91,7 @@ template class Complex { * @f] * @see angle(), Matrix3::rotation(), Quaternion::rotation() */ - inline static Complex rotation(Rad angle) { + static Complex rotation(Rad angle) { return {std::cos(angle.toUnderlyingType()), std::sin(angle.toUnderlyingType())}; } @@ -102,7 +101,7 @@ template class Complex { * Expects that the matrix is orthogonal (i.e. pure rotation). * @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal() */ - inline static Complex fromMatrix(const Matrix<2, T>& matrix) { + static Complex fromMatrix(const Matrix<2, T>& matrix) { CORRADE_ASSERT(matrix.isOrthogonal(), "Math::Complex::fromMatrix(): the matrix is not orthogonal", {}); return Implementation::complexFromMatrix(matrix); @@ -115,7 +114,7 @@ template class Complex { * c = 1 + i0 * @f] */ - inline constexpr /*implicit*/ Complex(): _real(T(1)), _imaginary(T(0)) {} + constexpr /*implicit*/ Complex(): _real(T(1)), _imaginary(T(0)) {} /** * @brief Construct complex number from real and imaginary part @@ -124,7 +123,7 @@ template class Complex { * c = a + ib * @f] */ - inline constexpr /*implicit*/ Complex(T real, T imaginary): _real(real), _imaginary(imaginary) {} + constexpr /*implicit*/ Complex(T real, T imaginary): _real(real), _imaginary(imaginary) {} /** * @brief Construct complex number from vector @@ -134,16 +133,16 @@ template class Complex { * @f] * @see operator Vector2(), transformVector() */ - inline constexpr explicit Complex(const Vector2& vector): _real(vector.x()), _imaginary(vector.y()) {} + constexpr explicit Complex(const Vector2& vector): _real(vector.x()), _imaginary(vector.y()) {} /** @brief Equality comparison */ - inline bool operator==(const Complex& other) const { + bool operator==(const Complex& other) const { return TypeTraits::equals(_real, other._real) && TypeTraits::equals(_imaginary, other._imaginary); } /** @brief Non-equality comparison */ - inline bool operator!=(const Complex& other) const { + bool operator!=(const Complex& other) const { return !operator==(other); } @@ -155,15 +154,15 @@ template class Complex { * @f] * @see dot(), normalized() */ - inline bool isNormalized() const { + bool isNormalized() const { return Implementation::isNormalizedSquared(dot()); } /** @brief Real part */ - inline constexpr T real() const { return _real; } + constexpr T real() const { return _real; } /** @brief Imaginary part */ - inline constexpr T imaginary() const { return _imaginary; } + constexpr T imaginary() const { return _imaginary; } /** * @brief Convert complex number to vector @@ -173,9 +172,9 @@ template class Complex { * @f] */ #ifndef CORRADE_GCC44_COMPATIBILITY - inline constexpr explicit operator Vector2() const { + constexpr explicit operator Vector2() const { #else - inline constexpr operator Vector2() const { + constexpr operator Vector2() const { #endif return {_real, _imaginary}; } @@ -188,7 +187,7 @@ template class Complex { * @f] * @see rotation() */ - inline Rad angle() const { + Rad angle() const { return Rad(std::atan2(_imaginary, _real)); } @@ -216,7 +215,7 @@ template class Complex { * c_0 + c_1 = (a_0 + a_1) + i(b_0 + b_1) * @f] */ - inline Complex& operator+=(const Complex& other) { + Complex& operator+=(const Complex& other) { _real += other._real; _imaginary += other._imaginary; return *this; @@ -227,7 +226,7 @@ template class Complex { * * @see operator+=() */ - inline Complex operator+(const Complex& other) const { + Complex operator+(const Complex& other) const { return Complex(*this) += other; } @@ -238,7 +237,7 @@ template class Complex { * -c = -a -ib * @f] */ - inline Complex operator-() const { + Complex operator-() const { return {-_real, -_imaginary}; } @@ -249,7 +248,7 @@ template class Complex { * c_0 - c_1 = (a_0 - a_1) + i(b_0 - b_1) * @f] */ - inline Complex& operator-=(const Complex& other) { + Complex& operator-=(const Complex& other) { _real -= other._real; _imaginary -= other._imaginary; return *this; @@ -260,7 +259,7 @@ template class Complex { * * @see operator-=() */ - inline Complex operator-(const Complex& other) const { + Complex operator-(const Complex& other) const { return Complex(*this) -= other; } @@ -271,7 +270,7 @@ template class Complex { * c \cdot t = ta + itb * @f] */ - inline Complex& operator*=(T scalar) { + Complex& operator*=(T scalar) { _real *= scalar; _imaginary *= scalar; return *this; @@ -282,7 +281,7 @@ template class Complex { * * @see operator*=(T) */ - inline Complex operator*(T scalar) const { + Complex operator*(T scalar) const { return Complex(*this) *= scalar; } @@ -293,7 +292,7 @@ template class Complex { * \frac c t = \frac a t + i \frac b t * @f] */ - inline Complex& operator/=(T scalar) { + Complex& operator/=(T scalar) { _real /= scalar; _imaginary /= scalar; return *this; @@ -304,7 +303,7 @@ template class Complex { * * @see operator/=(T) */ - inline Complex operator/(T scalar) const { + Complex operator/(T scalar) const { return Complex(*this) /= scalar; } @@ -315,7 +314,7 @@ template class Complex { * c_0 c_1 = (a_0 + ib_0)(a_1 + ib_1) = (a_0 a_1 - b_0 b_1) + i(a_1 b_0 + a_0 b_1) * @f] */ - inline Complex operator*(const Complex& other) const { + Complex operator*(const Complex& other) const { return {_real*other._real - _imaginary*other._imaginary, _imaginary*other._real + _real*other._imaginary}; } @@ -329,7 +328,7 @@ template class Complex { * @f] * @see dot(const Complex&, const Complex&), isNormalized() */ - inline T dot() const { + T dot() const { return dot(*this, *this); } @@ -342,7 +341,7 @@ template class Complex { * @f] * @see isNormalized() */ - inline T length() const { + T length() const { /** @todo Remove when NaCl's newlib has this fixed */ #ifndef CORRADE_TARGET_NACL_NEWLIB return std::hypot(_real, _imaginary); @@ -356,7 +355,7 @@ template class Complex { * * @see isNormalized() */ - inline Complex normalized() const { + Complex normalized() const { return (*this)/length(); } @@ -367,7 +366,7 @@ template class Complex { * c^* = a - ib * @f] */ - inline Complex conjugated() const { + Complex conjugated() const { return {_real, -_imaginary}; } @@ -379,7 +378,7 @@ template class Complex { * c^{-1} = \frac{c^*}{|c|^2} = \frac{c^*}{c \cdot c} * @f] */ - inline Complex inverted() const { + Complex inverted() const { return conjugated()/dot(); } @@ -392,7 +391,7 @@ template class Complex { * @f] * @see isNormalized(), inverted() */ - inline Complex invertedNormalized() const { + Complex invertedNormalized() const { CORRADE_ASSERT(isNormalized(), "Math::Complex::invertedNormalized(): complex number must be normalized", Complex(std::numeric_limits::quiet_NaN(), {})); @@ -407,7 +406,7 @@ template class Complex { * @f] * @see Complex(const Vector2&), operator Vector2(), Matrix3::transformVector() */ - inline Vector2 transformVector(const Vector2& vector) const { + Vector2 transformVector(const Vector2& vector) const { return Vector2((*this)*Complex(vector)); } diff --git a/src/Math/Constants.h b/src/Math/Constants.h index d4c232677..a2bc5a7b6 100644 --- a/src/Math/Constants.h +++ b/src/Math/Constants.h @@ -47,10 +47,10 @@ template struct Constants { * * @see Deg, Rad */ - static inline constexpr T pi(); + static constexpr T pi(); - static inline constexpr T sqrt2(); /**< @brief Square root of 2 */ - static inline constexpr T sqrt3(); /**< @brief Square root of 3 */ + static constexpr T sqrt2(); /**< @brief Square root of 2 */ + static constexpr T sqrt3(); /**< @brief Square root of 3 */ #endif }; @@ -59,17 +59,17 @@ template struct Constants { template<> struct Constants { Constants() = delete; - static inline constexpr Double pi() { return 3.141592653589793; } - static inline constexpr Double sqrt2() { return 1.414213562373095; } - static inline constexpr Double sqrt3() { return 1.732050807568877; } + static constexpr Double pi() { return 3.141592653589793; } + static constexpr Double sqrt2() { return 1.414213562373095; } + static constexpr Double sqrt3() { return 1.732050807568877; } }; #endif template<> struct Constants { Constants() = delete; - static inline constexpr Float pi() { return 3.141592654f; } - static inline constexpr Float sqrt2() { return 1.414213562f; } - static inline constexpr Float sqrt3() { return 1.732050808f; } + static constexpr Float pi() { return 3.141592654f; } + static constexpr Float sqrt2() { return 1.414213562f; } + static constexpr Float sqrt3() { return 1.732050808f; } }; #endif diff --git a/src/Math/Dual.h b/src/Math/Dual.h index 630a6f736..5d5e4948a 100644 --- a/src/Math/Dual.h +++ b/src/Math/Dual.h @@ -50,7 +50,7 @@ template class Dual { * * Both parts are default-constructed. */ - inline constexpr /*implicit*/ Dual(): _real(), _dual() {} + constexpr /*implicit*/ Dual(): _real(), _dual() {} /** * @brief Construct dual number from real and dual part @@ -59,24 +59,24 @@ template class Dual { * \hat a = a_0 + \epsilon a_\epsilon * @f] */ - inline constexpr /*implicit*/ Dual(const T& real, const T& dual = T()): _real(real), _dual(dual) {} + constexpr /*implicit*/ Dual(const T& real, const T& dual = T()): _real(real), _dual(dual) {} /** @brief Equality comparison */ - inline bool operator==(const Dual& other) const { + bool operator==(const Dual& other) const { return TypeTraits::equals(_real, other._real) && TypeTraits::equals(_dual, other._dual); } /** @brief Non-equality comparison */ - inline bool operator!=(const Dual& other) const { + bool operator!=(const Dual& other) const { return !operator==(other); } /** @brief Real part */ - inline constexpr T real() const { return _real; } + constexpr T real() const { return _real; } /** @brief %Dual part */ - inline constexpr T dual() const { return _dual; } + constexpr T dual() const { return _dual; } /** * @brief Add and assign dual number @@ -85,7 +85,7 @@ template class Dual { * \hat a + \hat b = a_0 + b_0 + \epsilon (a_\epsilon + b_\epsilon) * @f] */ - inline Dual& operator+=(const Dual& other) { + Dual& operator+=(const Dual& other) { _real += other._real; _dual += other._dual; return *this; @@ -96,7 +96,7 @@ template class Dual { * * @see operator+=() */ - inline Dual operator+(const Dual& other) const { + Dual operator+(const Dual& other) const { return Dual(*this)+=other; } @@ -107,7 +107,7 @@ template class Dual { * -\hat a = -a_0 - \epsilon a_\epsilon * @f] */ - inline Dual operator-() const { + Dual operator-() const { return {-_real, -_dual}; } @@ -118,7 +118,7 @@ template class Dual { * \hat a - \hat b = a_0 - b_0 + \epsilon (a_\epsilon - b_\epsilon) * @f] */ - inline Dual& operator-=(const Dual& other) { + Dual& operator-=(const Dual& other) { _real -= other._real; _dual -= other._dual; return *this; @@ -129,7 +129,7 @@ template class Dual { * * @see operator-=() */ - inline Dual operator-(const Dual& other) const { + Dual operator-(const Dual& other) const { return Dual(*this)-=other; } @@ -140,7 +140,7 @@ template class Dual { * \hat a \hat b = a_0 b_0 + \epsilon (a_0 b_\epsilon + a_\epsilon b_0) * @f] */ - template inline Dual operator*(const Dual& other) const { + template Dual operator*(const Dual& other) const { return {_real*other._real, _real*other._dual + _dual*other._real}; } @@ -151,7 +151,7 @@ template class Dual { * \frac{\hat a}{\hat b} = \frac{a_0}{b_0} + \epsilon \frac{a_\epsilon b_0 - a_0 b_\epsilon}{b_0^2} * @f] */ - template inline Dual operator/(const Dual& other) const { + template Dual operator/(const Dual& other) const { return {_real/other._real, (_dual*other._real - _real*other._dual)/(other._real*other._real)}; } @@ -162,7 +162,7 @@ template class Dual { * \overline{\hat a} = a_0 - \epsilon a_\epsilon * @f] */ - inline Dual conjugated() const { + Dual conjugated() const { return {_real, -_dual}; } @@ -172,27 +172,27 @@ template class Dual { #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying) \ - inline Type operator-() const { \ + Type operator-() const { \ return Dual>::operator-(); \ } \ - inline Type& operator+=(const Dual>& other) { \ + Type& operator+=(const Dual>& other) { \ Dual>::operator+=(other); \ return *this; \ } \ - inline Type operator+(const Dual>& other) const { \ + Type operator+(const Dual>& other) const { \ return Dual>::operator+(other); \ } \ - inline Type& operator-=(const Dual>& other) { \ + Type& operator-=(const Dual>& other) { \ Dual>::operator-=(other); \ return *this; \ } \ - inline Type operator-(const Dual>& other) const { \ + Type operator-(const Dual>& other) const { \ return Dual>::operator-(other); \ } \ - template inline Type operator*(const Dual& other) const { \ + template Type operator*(const Dual& other) const { \ return Dual>::operator*(other); \ } \ - template inline Type operator/(const Dual& other) const { \ + template Type operator/(const Dual& other) const { \ return Dual>::operator/(other); \ } #endif diff --git a/src/Math/DualComplex.cpp b/src/Math/DualComplex.cpp deleted file mode 100644 index 9b18e9abc..000000000 --- a/src/Math/DualComplex.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "DualComplex.h" - -namespace Magnum { namespace Math { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualComplex&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualComplex&); -#endif -#endif - -}} diff --git a/src/Math/DualComplex.h b/src/Math/DualComplex.h index 648f9f6bc..024563d2f 100644 --- a/src/Math/DualComplex.h +++ b/src/Math/DualComplex.h @@ -58,7 +58,7 @@ template class DualComplex: public Dual> { * @see angle(), Complex::rotation(), Matrix3::rotation(), * DualQuaternion::rotation() */ - inline static DualComplex rotation(Rad angle) { + static DualComplex rotation(Rad angle) { return {Complex::rotation(angle), {{}, {}}}; } @@ -72,7 +72,7 @@ template class DualComplex: public Dual> { * @see translation() const, Matrix3::translation(const Vector2&), * DualQuaternion::translation(), Vector2::xAxis(), Vector2::yAxis() */ - inline static DualComplex translation(const Vector2& vector) { + static DualComplex translation(const Vector2& vector) { return {{}, {vector.x(), vector.y()}}; } @@ -83,7 +83,7 @@ template class DualComplex: public Dual> { * @see toMatrix(), Complex::fromMatrix(), * Matrix3::isRigidTransformation() */ - inline static DualComplex fromMatrix(const Matrix3& matrix) { + static DualComplex fromMatrix(const Matrix3& matrix) { CORRADE_ASSERT(matrix.isRigidTransformation(), "Math::DualComplex::fromMatrix(): the matrix doesn't represent rigid transformation", {}); return {Implementation::complexFromMatrix(matrix.rotationScaling()), Complex(matrix.translation())}; @@ -98,9 +98,9 @@ template class DualComplex: public Dual> { * @todoc Remove workaround when Doxygen is predictable */ #ifdef DOXYGEN_GENERATING_OUTPUT - inline constexpr /*implicit*/ DualComplex(); + constexpr /*implicit*/ DualComplex(); #else - inline constexpr /*implicit*/ DualComplex(): Dual>({}, {T(0), T(0)}) {} + constexpr /*implicit*/ DualComplex(): Dual>({}, {T(0), T(0)}) {} #endif /** @@ -110,7 +110,7 @@ template class DualComplex: public Dual> { * \hat c = c_0 + \epsilon c_\epsilon * @f] */ - inline constexpr /*implicit*/ DualComplex(const Complex& real, const Complex& dual = Complex(T(0), T(0))): Dual>(real, dual) {} + constexpr /*implicit*/ DualComplex(const Complex& real, const Complex& dual = Complex(T(0), T(0))): Dual>(real, dual) {} /** * @brief Construct dual complex number from vector @@ -121,9 +121,9 @@ template class DualComplex: public Dual> { * @todoc Remove workaround when Doxygen is predictable */ #ifdef DOXYGEN_GENERATING_OUTPUT - inline constexpr explicit DualComplex(const Vector2& vector); + constexpr explicit DualComplex(const Vector2& vector); #else - inline constexpr explicit DualComplex(const Vector2& vector): Dual>({}, Complex(vector)) {} + constexpr explicit DualComplex(const Vector2& vector): Dual>({}, Complex(vector)) {} #endif /** @@ -134,7 +134,7 @@ template class DualComplex: public Dual> { * @f] * @see Complex::dot(), normalized() */ - inline bool isNormalized() const { + bool isNormalized() const { return Implementation::isNormalizedSquared(lengthSquared()); } @@ -143,7 +143,7 @@ template class DualComplex: public Dual> { * * @see Complex::angle() */ - inline constexpr Complex rotation() const { + constexpr Complex rotation() const { return this->real(); } @@ -155,7 +155,7 @@ template class DualComplex: public Dual> { * @f] * @see translation(const Vector2&) */ - inline Vector2 translation() const { + Vector2 translation() const { return Vector2(this->dual()); } @@ -164,7 +164,7 @@ template class DualComplex: public Dual> { * * @see fromMatrix(), Complex::toMatrix() */ - inline Matrix3 toMatrix() const { + Matrix3 toMatrix() const { return Matrix3::from(this->real().toMatrix(), translation()); } @@ -176,7 +176,7 @@ template class DualComplex: public Dual> { * @f] * @todo can this be done similarly to dual quaternions? */ - inline DualComplex operator*(const DualComplex& other) const { + DualComplex operator*(const DualComplex& other) const { return {this->real()*other.real(), this->real()*other.dual() + this->dual()}; } @@ -188,7 +188,7 @@ template class DualComplex: public Dual> { * @f] * @see dualConjugated(), conjugated(), Complex::conjugated() */ - inline DualComplex complexConjugated() const { + DualComplex complexConjugated() const { return {this->real().conjugated(), this->dual().conjugated()}; } @@ -200,7 +200,7 @@ template class DualComplex: public Dual> { * @f] * @see complexConjugated(), conjugated(), Dual::conjugated() */ - inline DualComplex dualConjugated() const { + DualComplex dualConjugated() const { return Dual>::conjugated(); } @@ -213,7 +213,7 @@ template class DualComplex: public Dual> { * @see complexConjugated(), dualConjugated(), Complex::conjugated(), * Dual::conjugated() */ - inline DualComplex conjugated() const { + DualComplex conjugated() const { return {this->real().conjugated(), {-this->dual().real(), this->dual().imaginary()}}; } @@ -226,7 +226,7 @@ template class DualComplex: public Dual> { * @f] * @todo Can this be done similarly to dual quaternins? */ - inline T lengthSquared() const { + T lengthSquared() const { return this->real().dot(); } @@ -239,7 +239,7 @@ template class DualComplex: public Dual> { * @f] * @todo can this be done similarly to dual quaternions? */ - inline T length() const { + T length() const { return this->real().length(); } @@ -252,7 +252,7 @@ template class DualComplex: public Dual> { * @see isNormalized() * @todo can this be done similarly to dual quaternions? */ - inline DualComplex normalized() const { + DualComplex normalized() const { return {this->real()/length(), this->dual()}; } @@ -265,7 +265,7 @@ template class DualComplex: public Dual> { * @f] * @todo can this be done similarly to dual quaternions? */ - inline DualComplex inverted() const { + DualComplex inverted() const { return DualComplex(this->real().inverted(), {{}, {}})*DualComplex({}, -this->dual()); } @@ -278,7 +278,7 @@ template class DualComplex: public Dual> { * @see isNormalized(), inverted() * @todo can this be done similarly to dual quaternions? */ - inline DualComplex invertedNormalized() const { + DualComplex invertedNormalized() const { return DualComplex(this->real().invertedNormalized(), {{}, {}})*DualComplex({}, -this->dual()); } @@ -292,35 +292,35 @@ template class DualComplex: public Dual> { * @see DualComplex(const Vector2&), dual(), Matrix3::transformPoint(), * Complex::transformVector(), DualQuaternion::transformPoint() */ - inline Vector2 transformPoint(const Vector2& vector) const { + Vector2 transformPoint(const Vector2& vector) const { return Vector2(((*this)*DualComplex(vector)).dual()); } /* Verbatim copy of DUAL_SUBCLASS_IMPLEMENTATION(), as we need to hide Dual's operator*() and operator/() */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline DualComplex operator-() const { + DualComplex operator-() const { return Dual>::operator-(); } - inline DualComplex& operator+=(const Dual>& other) { + DualComplex& operator+=(const Dual>& other) { Dual>::operator+=(other); return *this; } - inline DualComplex operator+(const Dual>& other) const { + DualComplex operator+(const Dual>& other) const { return Dual>::operator+(other); } - inline DualComplex& operator-=(const Dual>& other) { + DualComplex& operator-=(const Dual>& other) { Dual>::operator-=(other); return *this; } - inline DualComplex operator-(const Dual>& other) const { + DualComplex operator-(const Dual>& other) const { return Dual>::operator-(other); } #endif private: /* Used by Dual operators and dualConjugated() */ - inline constexpr DualComplex(const Dual>& other): Dual>(other) {} + constexpr DualComplex(const Dual>& other): Dual>(other) {} /* Just to be sure nobody uses this, as it wouldn't probably work with our operator*() */ diff --git a/src/Math/DualQuaternion.cpp b/src/Math/DualQuaternion.cpp deleted file mode 100644 index 0070e50ac..000000000 --- a/src/Math/DualQuaternion.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "DualQuaternion.h" - -namespace Magnum { namespace Math { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualQuaternion&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualQuaternion&); -#endif -#endif - -}} diff --git a/src/Math/DualQuaternion.h b/src/Math/DualQuaternion.h index 8d4837aac..6411c9fa7 100644 --- a/src/Math/DualQuaternion.h +++ b/src/Math/DualQuaternion.h @@ -58,7 +58,7 @@ template class DualQuaternion: public Dual> { * DualComplex::rotation(), Vector3::xAxis(), Vector3::yAxis(), * Vector3::zAxis(), Vector::isNormalized() */ - inline static DualQuaternion rotation(Rad angle, const Vector3& normalizedAxis) { + static DualQuaternion rotation(Rad angle, const Vector3& normalizedAxis) { return {Quaternion::rotation(angle, normalizedAxis), {{}, T(0)}}; } @@ -75,7 +75,7 @@ template class DualQuaternion: public Dual> { * DualComplex::translation(), Vector3::xAxis(), Vector3::yAxis(), * Vector3::zAxis() */ - inline static DualQuaternion translation(const Vector3& vector) { + static DualQuaternion translation(const Vector3& vector) { return {{}, {vector/T(2), T(0)}}; } @@ -86,7 +86,7 @@ template class DualQuaternion: public Dual> { * @see toMatrix(), Quaternion::fromMatrix(), * Matrix4::isRigidTransformation() */ - inline static DualQuaternion fromMatrix(const Matrix4& matrix) { + static DualQuaternion fromMatrix(const Matrix4& matrix) { CORRADE_ASSERT(matrix.isRigidTransformation(), "Math::DualQuaternion::fromMatrix(): the matrix doesn't represent rigid transformation", {}); @@ -103,9 +103,9 @@ template class DualQuaternion: public Dual> { * @todoc Remove workaround when Doxygen is predictable */ #ifdef DOXYGEN_GENERATING_OUTPUT - inline constexpr /*implicit*/ DualQuaternion(); + constexpr /*implicit*/ DualQuaternion(); #else - inline constexpr /*implicit*/ DualQuaternion(): Dual>({}, {{}, T(0)}) {} + constexpr /*implicit*/ DualQuaternion(): Dual>({}, {{}, T(0)}) {} #endif /** @@ -115,7 +115,7 @@ template class DualQuaternion: public Dual> { * \hat q = q_0 + \epsilon q_\epsilon * @f] */ - inline constexpr /*implicit*/ DualQuaternion(const Quaternion& real, const Quaternion& dual = Quaternion({}, T(0))): Dual>(real, dual) {} + constexpr /*implicit*/ DualQuaternion(const Quaternion& real, const Quaternion& dual = Quaternion({}, T(0))): Dual>(real, dual) {} /** * @brief Construct dual quaternion from vector @@ -127,9 +127,9 @@ template class DualQuaternion: public Dual> { * @todoc Remove workaround when Doxygen is predictable */ #ifdef DOXYGEN_GENERATING_OUTPUT - inline constexpr explicit DualQuaternion(const Vector3& vector); + constexpr explicit DualQuaternion(const Vector3& vector); #else - inline constexpr explicit DualQuaternion(const Vector3& vector): Dual>({}, {vector, T(0)}) {} + constexpr explicit DualQuaternion(const Vector3& vector): Dual>({}, {vector, T(0)}) {} #endif /** @@ -140,7 +140,7 @@ template class DualQuaternion: public Dual> { * @f] * @see lengthSquared(), normalized() */ - inline bool isNormalized() const { + bool isNormalized() const { /* Comparing dual part classically, as comparing sqrt() of it would lead to overly strict precision */ Dual a = lengthSquared(); @@ -153,7 +153,7 @@ template class DualQuaternion: public Dual> { * * @see Quaternion::angle(), Quaternion::axis() */ - inline constexpr Quaternion rotation() const { + constexpr Quaternion rotation() const { return this->real(); } @@ -165,7 +165,7 @@ template class DualQuaternion: public Dual> { * @f] * @see translation(const Vector3&) */ - inline Vector3 translation() const { + Vector3 translation() const { return (this->dual()*this->real().conjugated()).vector()*T(2); } @@ -186,7 +186,7 @@ template class DualQuaternion: public Dual> { * @f] * @see dualConjugated(), conjugated(), Quaternion::conjugated() */ - inline DualQuaternion quaternionConjugated() const { + DualQuaternion quaternionConjugated() const { return {this->real().conjugated(), this->dual().conjugated()}; } @@ -198,7 +198,7 @@ template class DualQuaternion: public Dual> { * @f] * @see quaternionConjugated(), conjugated(), Dual::conjugated() */ - inline DualQuaternion dualConjugated() const { + DualQuaternion dualConjugated() const { return Dual>::conjugated(); } @@ -211,7 +211,7 @@ template class DualQuaternion: public Dual> { * @see quaternionConjugated(), dualConjugated(), Quaternion::conjugated(), * Dual::conjugated() */ - inline DualQuaternion conjugated() const { + DualQuaternion conjugated() const { return {this->real().conjugated(), {this->dual().vector(), -this->dual().scalar()}}; } @@ -223,7 +223,7 @@ template class DualQuaternion: public Dual> { * |\hat q|^2 = \sqrt{\hat q^* \hat q}^2 = q_0 \cdot q_0 + \epsilon 2 (q_0 \cdot q_\epsilon) * @f] */ - inline Dual lengthSquared() const { + Dual lengthSquared() const { return {this->real().dot(), T(2)*Quaternion::dot(this->real(), this->dual())}; } @@ -235,7 +235,7 @@ template class DualQuaternion: public Dual> { * |\hat q| = \sqrt{\hat q^* \hat q} = |q_0| + \epsilon \frac{q_0 \cdot q_\epsilon}{|q_0|} * @f] */ - inline Dual length() const { + Dual length() const { return Math::sqrt(lengthSquared()); } @@ -244,7 +244,7 @@ template class DualQuaternion: public Dual> { * * @see isNormalized() */ - inline DualQuaternion normalized() const { + DualQuaternion normalized() const { return (*this)/length(); } @@ -256,7 +256,7 @@ template class DualQuaternion: public Dual> { * \hat q^{-1} = \frac{\hat q^*}{|\hat q|^2} * @f] */ - inline DualQuaternion inverted() const { + DualQuaternion inverted() const { return quaternionConjugated()/lengthSquared(); } @@ -269,7 +269,7 @@ template class DualQuaternion: public Dual> { * @f] * @see isNormalized(), inverted() */ - inline DualQuaternion invertedNormalized() const { + DualQuaternion invertedNormalized() const { CORRADE_ASSERT(isNormalized(), "Math::DualQuaternion::invertedNormalized(): dual quaternion must be normalized", {}); return quaternionConjugated(); @@ -285,7 +285,7 @@ template class DualQuaternion: public Dual> { * @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(), * Quaternion::transformVector(), DualComplex::transformPoint() */ - inline Vector3 transformPoint(const Vector3& vector) const { + Vector3 transformPoint(const Vector3& vector) const { return ((*this)*DualQuaternion(vector)*inverted().dualConjugated()).dual().vector(); } @@ -300,7 +300,7 @@ template class DualQuaternion: public Dual> { * Matrix4::transformPoint(), Quaternion::transformVectorNormalized(), * DualComplex::transformPointNormalized() */ - inline Vector3 transformPointNormalized(const Vector3& vector) const { + Vector3 transformPointNormalized(const Vector3& vector) const { CORRADE_ASSERT(isNormalized(), "Math::DualQuaternion::transformPointNormalized(): dual quaternion must be normalized", Vector3(std::numeric_limits::quiet_NaN())); @@ -311,7 +311,7 @@ template class DualQuaternion: public Dual> { private: /* Used by Dual operators and dualConjugated() */ - inline constexpr DualQuaternion(const Dual>& other): Dual>(other) {} + constexpr DualQuaternion(const Dual>& other): Dual>(other) {} }; /** @debugoperator{Magnum::Math::DualQuaternion} */ diff --git a/src/Math/Functions.h b/src/Math/Functions.h index c05f41087..63c161c3f 100644 --- a/src/Math/Functions.h +++ b/src/Math/Functions.h @@ -38,29 +38,27 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Pow { Pow() = delete; - template inline constexpr static T pow(T base) { + template constexpr static T pow(T base) { return base*Pow::pow(base); } }; template<> struct Pow<0> { Pow() = delete; - template inline constexpr static T pow(T) { return 1; } + template constexpr static T pow(T) { return 1; } }; } -#endif /** * @brief Integral power * * Returns integral power of base to the exponent. */ -template inline constexpr T pow(T base) { +template constexpr T pow(T base) { return Implementation::Pow::pow(base); } @@ -142,6 +140,14 @@ template inline Vector min(const Vector inline T min(std::initializer_list list) { + T out(*list.begin()); + for(auto it = list.begin()+1; it != list.end(); ++it) + out = min(out, *it); + return out; +} + /** @brief Maximum @@ -161,6 +167,14 @@ template Vector max(const Vector& a } #endif +/** @overload */ +template inline T max(std::initializer_list list) { + T out(*list.begin()); + for(auto it = list.begin()+1; it != list.end(); ++it) + out = max(out, *it); + return out; +} + /** @brief Sign diff --git a/src/Math/Geometry/Distance.h b/src/Math/Geometry/Distance.h index f4868a601..c5aa422a9 100644 --- a/src/Math/Geometry/Distance.h +++ b/src/Math/Geometry/Distance.h @@ -29,7 +29,6 @@ */ #include "Math/Functions.h" -#include "Math/Matrix.h" #include "Math/Vector3.h" namespace Magnum { namespace Math { namespace Geometry { @@ -46,14 +45,15 @@ class Distance { * @param point Point * * The distance *d* is computed from point **p** and line defined by **a** - * and **b** using @ref Matrix::determinant() "determinant": @f[ - * d = \frac{|det(b - a a - point)|} {|b - a|} + * and **b** using @ref Vector2::cross() "perp-dot product": @f[ + * d = \frac{|(\boldsymbol b - \boldsymbol a)_\bot \cdot (\boldsymbol a - \boldsymbol p)|} {|\boldsymbol b - \boldsymbol a|} * @f] * Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html * @see linePointSquared(const Vector2&, const Vector2&, const Vector2&) */ - template inline static T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { - return std::abs(Matrix<2, T>(b - a, a - point).determinant())/(b - a).length(); + template static T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 bMinusA = b - a; + return std::abs(Vector2::cross(bMinusA, a - point))/bMinusA.length(); } /** @@ -66,9 +66,9 @@ class Distance { * for comparing distance with other values, because it doesn't * compute the square root. */ - template inline static T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { - Vector2 bMinusA = b - a; - return Math::pow<2>(Matrix<2, T>(bMinusA, a - point).determinant())/bMinusA.dot(); + template static T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 bMinusA = b - a; + return Math::pow<2>(Vector2::cross(bMinusA, a - point))/bMinusA.dot(); } /** @@ -85,7 +85,7 @@ class Distance { * Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html * @see linePointSquared(const Vector3&, const Vector3&, const Vector3&) */ - template inline static T linePoint(const Vector3& a, const Vector3& b, const Vector3& point) { + template static T linePoint(const Vector3& a, const Vector3& b, const Vector3& point) { return std::sqrt(linePointSquared(a, b, point)); } @@ -126,25 +126,7 @@ class Distance { * * @see lineSegmentPointSquared() */ - template inline static T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point) { - Vector2 pointMinusA = point - a; - Vector2 pointMinusB = point - b; - Vector2 bMinusA = b - a; - T pointDistanceA = pointMinusA.dot(); - T pointDistanceB = pointMinusB.dot(); - T bDistanceA = bMinusA.dot(); - - /* Point is before A */ - if(pointDistanceB > bDistanceA + pointDistanceA) - return std::sqrt(pointDistanceA); - - /* Point is after B */ - if(pointDistanceA > bDistanceA + pointDistanceB) - return std::sqrt(pointDistanceB); - - /* Between A and B */ - return std::abs(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA); - } + template static T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point); /** * @brief %Distance of point from line segment in 2D, squared @@ -152,25 +134,7 @@ class Distance { * More efficient than lineSegmentPoint() for comparing distance with * other values, because it doesn't compute the square root. */ - template static T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { - Vector2 pointMinusA = point - a; - Vector2 pointMinusB = point - b; - Vector2 bMinusA = b - a; - T pointDistanceA = pointMinusA.dot(); - T pointDistanceB = pointMinusB.dot(); - T bDistanceA = bMinusA.dot(); - - /* Point is before A */ - if(pointDistanceB > bDistanceA + pointDistanceA) - return pointDistanceA; - - /* Point is after B */ - if(pointDistanceA > bDistanceA + pointDistanceB) - return pointDistanceB; - - /* Between A and B */ - return Math::pow<2>(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/bDistanceA; - } + template static T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point); /** * @brief %Dístance of point from line segment in 3D @@ -183,7 +147,7 @@ class Distance { * * @see lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&) */ - template inline static T lineSegmentPoint(const Vector3& a, const Vector3& b, const Vector3& point) { + template static T lineSegmentPoint(const Vector3& a, const Vector3& b, const Vector3& point) { return std::sqrt(lineSegmentPointSquared(a, b, point)); } @@ -193,26 +157,86 @@ class Distance { * More efficient than lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) for comparing distance with * other values, because it doesn't compute the square root. */ - template static T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { - Vector3 pointMinusA = point - a; - Vector3 pointMinusB = point - b; - T pointDistanceA = pointMinusA.dot(); - T pointDistanceB = pointMinusB.dot(); - T bDistanceA = (b - a).dot(); - - /* Point is before A */ - if(pointDistanceB > bDistanceA + pointDistanceA) - return pointDistanceA; - - /* Point is after B */ - if(pointDistanceA > bDistanceA + pointDistanceB) - return pointDistanceB; - - /* Between A and B */ - return Vector3::cross(pointMinusA, pointMinusB).dot()/bDistanceA; - } + template static T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point); }; +/** @todoc Remove workaround when Doxygen is sane */ +#ifdef DOXYGEN_GENERATING_OUTPUT +template static +#else +template +#endif +T Distance::lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 pointMinusA = point - a; + const Vector2 pointMinusB = point - b; + const Vector2 bMinusA = b - a; + const T pointDistanceA = pointMinusA.dot(); + const T pointDistanceB = pointMinusB.dot(); + const T bDistanceA = bMinusA.dot(); + + /* Point is before A */ + if(pointDistanceB > bDistanceA + pointDistanceA) + return std::sqrt(pointDistanceA); + + /* Point is after B */ + if(pointDistanceA > bDistanceA + pointDistanceB) + return std::sqrt(pointDistanceB); + + /* Between A and B */ + return std::abs(Vector2::cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA); +} + +/** @todoc Remove workaround when Doxygen is sane */ +#ifdef DOXYGEN_GENERATING_OUTPUT +template static +#else +template +#endif +T Distance::lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 pointMinusA = point - a; + const Vector2 pointMinusB = point - b; + const Vector2 bMinusA = b - a; + const T pointDistanceA = pointMinusA.dot(); + const T pointDistanceB = pointMinusB.dot(); + const T bDistanceA = bMinusA.dot(); + + /* Point is before A */ + if(pointDistanceB > bDistanceA + pointDistanceA) + return pointDistanceA; + + /* Point is after B */ + if(pointDistanceA > bDistanceA + pointDistanceB) + return pointDistanceB; + + /* Between A and B */ + return Math::pow<2>(Vector2::cross(bMinusA, -pointMinusA))/bDistanceA; +} + +/** @todoc Remove workaround when Doxygen is sane */ +#ifdef DOXYGEN_GENERATING_OUTPUT +template static +#else +template +#endif +T Distance::lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { + const Vector3 pointMinusA = point - a; + const Vector3 pointMinusB = point - b; + const T pointDistanceA = pointMinusA.dot(); + const T pointDistanceB = pointMinusB.dot(); + const T bDistanceA = (b - a).dot(); + + /* Point is before A */ + if(pointDistanceB > bDistanceA + pointDistanceA) + return pointDistanceA; + + /* Point is after B */ + if(pointDistanceA > bDistanceA + pointDistanceB) + return pointDistanceB; + + /* Between A and B */ + return Vector3::cross(pointMinusA, pointMinusB).dot()/bDistanceA; +} + }}} #endif diff --git a/src/Math/Geometry/Rectangle.h b/src/Math/Geometry/Rectangle.h index 6211bd8b7..ad8ef7b20 100644 --- a/src/Math/Geometry/Rectangle.h +++ b/src/Math/Geometry/Rectangle.h @@ -51,7 +51,7 @@ template class Rectangle { * @param bottomLeft Bottom left rectangle corner * @param size %Rectangle size */ - inline static Rectangle fromSize(const Vector2& bottomLeft, const Vector2& size) { + static Rectangle fromSize(const Vector2& bottomLeft, const Vector2& size) { return {bottomLeft, bottomLeft+size}; } @@ -60,10 +60,10 @@ template class Rectangle { * * Construct zero-area rectangle positioned at origin. */ - inline constexpr Rectangle() {} + constexpr Rectangle() {} /** @brief Construct rectangle from two corners */ - inline constexpr Rectangle(const Vector2& bottomLeft, const Vector2& topRight): _bottomLeft(bottomLeft), _topRight(topRight) {} + constexpr Rectangle(const Vector2& bottomLeft, const Vector2& topRight): _bottomLeft(bottomLeft), _topRight(topRight) {} /** * @brief Construct rectangle from another of different type @@ -75,64 +75,62 @@ template class Rectangle { * Rectangle integral(floatingPoint); // {{1, 2}, {-15, 7}} * @endcode */ - template inline constexpr explicit Rectangle(const Rectangle& other): _bottomLeft(other._bottomLeft), _topRight(other._topRight) {} + template constexpr explicit Rectangle(const Rectangle& other): _bottomLeft(other._bottomLeft), _topRight(other._topRight) {} /** @brief Copy constructor */ - inline constexpr Rectangle(const Rectangle&) = default; + constexpr Rectangle(const Rectangle&) = default; /** @brief Assignment operator */ - inline Rectangle& operator=(const Rectangle&) = default; + Rectangle& operator=(const Rectangle&) = default; /** @brief Equality operator */ - inline constexpr bool operator==(const Rectangle& other) const { + constexpr bool operator==(const Rectangle& other) const { return _bottomLeft == other._bottomLeft && _topRight == other._topRight; } /** @brief Non-equality operator */ - inline constexpr bool operator!=(const Rectangle& other) const { + constexpr bool operator!=(const Rectangle& other) const { return !operator==(other); } /** @brief Bottom left corner */ - inline Vector2& bottomLeft() { return _bottomLeft; } - inline constexpr Vector2 bottomLeft() const { return _bottomLeft; } /**< @overload */ + Vector2& bottomLeft() { return _bottomLeft; } + constexpr Vector2 bottomLeft() const { return _bottomLeft; } /**< @overload */ /** @brief Bottom right corner */ - inline constexpr Vector2 bottomRight() const { return {_topRight.x(), _bottomLeft.y()}; } /**< @overload */ + constexpr Vector2 bottomRight() const { return {_topRight.x(), _bottomLeft.y()}; } /**< @overload */ /** @brief Top left corner */ - inline constexpr Vector2 topLeft() const { return {_bottomLeft.x(), _topRight.y()}; } /**< @overload */ + constexpr Vector2 topLeft() const { return {_bottomLeft.x(), _topRight.y()}; } /**< @overload */ /** @brief Top right corner */ - inline Vector2& topRight() { return _topRight; } - inline constexpr Vector2 topRight() const { return _topRight; } /**< @overload */ + Vector2& topRight() { return _topRight; } + constexpr Vector2 topRight() const { return _topRight; } /**< @overload */ /** @brief Bottom edge */ - inline T& bottom() { return _bottomLeft.y(); } - inline constexpr T bottom() const { return _bottomLeft.y(); } /**< @overload */ + T& bottom() { return _bottomLeft.y(); } + constexpr T bottom() const { return _bottomLeft.y(); } /**< @overload */ /** @brief Top edge */ - inline T& top() { return _topRight.y(); } - inline constexpr T top() const { return _topRight.y(); } /**< @overload */ + T& top() { return _topRight.y(); } + constexpr T top() const { return _topRight.y(); } /**< @overload */ /** @brief Left edge */ - inline T& left() { return _bottomLeft.x(); } - inline constexpr T left() const { return _bottomLeft.x(); } /**< @overload */ + T& left() { return _bottomLeft.x(); } + constexpr T left() const { return _bottomLeft.x(); } /**< @overload */ /** @brief Right edge */ - inline T& right() { return _topRight.x(); } - inline constexpr T right() const { return _topRight.x(); } /**< @overload */ + T& right() { return _topRight.x(); } + constexpr T right() const { return _topRight.x(); } /**< @overload */ /** @brief %Rectangle size */ - inline constexpr Vector2 size() const { - return _topRight-_bottomLeft; - } + constexpr Vector2 size() const { return _topRight-_bottomLeft; } /** @brief %Rectangle width */ - inline constexpr T width() const { return _topRight.x() - _bottomLeft.x(); } + constexpr T width() const { return _topRight.x() - _bottomLeft.x(); } /** @brief %Rectangle height */ - inline constexpr T height() const { return _topRight.y() - _bottomLeft.y(); } + constexpr T height() const { return _topRight.y() - _bottomLeft.y(); } private: Vector2 _bottomLeft; diff --git a/src/Math/Geometry/Test/DistanceTest.cpp b/src/Math/Geometry/Test/DistanceTest.cpp index 3170265e7..f60c94931 100644 --- a/src/Math/Geometry/Test/DistanceTest.cpp +++ b/src/Math/Geometry/Test/DistanceTest.cpp @@ -56,14 +56,18 @@ void DistanceTest::linePoint2D() { Vector2 b(1.0f); /* Point on the line */ - CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(0.25f))), 0.0f); + CORRADE_COMPARE(Distance::linePoint(a, b, Vector2(0.25f)), + 0.0f); /* The distance should be the same for all equidistant points */ - CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(1.0f, 0.0f))), 1.0f/Constants::sqrt2()); - CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(1.0f, 0.0f)+Vector2(100.0f))), 1.0f/Constants::sqrt2()); + CORRADE_COMPARE(Distance::linePoint(a, b, Vector2(1.0f, 0.0f)), + 1.0f/Constants::sqrt2()); + CORRADE_COMPARE(Distance::linePoint(a, b, Vector2(1.0f, 0.0f) + Vector2(100.0f)), + 1.0f/Constants::sqrt2()); /* Be sure that *Squared() works the same, as it has slightly different implementation */ - CORRADE_COMPARE((Distance::linePointSquared(a, b, Vector2(1.0f, 0.0f))), 0.5f); + CORRADE_COMPARE(Distance::linePointSquared(a, b, Vector2(1.0f, 0.0f)), + 0.5f); } void DistanceTest::linePoint3D() { @@ -71,11 +75,17 @@ void DistanceTest::linePoint3D() { Vector3 b(1.0f); /* Point on the line */ - CORRADE_COMPARE((Distance::linePoint(a, b, Vector3(0.25f))), 0.0f); + CORRADE_COMPARE(Distance::linePoint(a, b, Vector3(0.25f)), 0.0f); /* The distance should be the same for all equidistant points */ - CORRADE_COMPARE((Distance::linePoint(a, b, Vector3(1.0f, 0.0f, 1.0f))), Constants::sqrt2()/Constants::sqrt3()); - CORRADE_COMPARE((Distance::linePoint(a, b, Vector3(1.0f, 0.0f, 1.0f)+Vector3(100.0f))), Constants::sqrt2()/Constants::sqrt3()); + CORRADE_COMPARE(Distance::linePoint(a, b, Vector3(1.0f, 0.0f, 1.0f)), + Constants::sqrt2()/Constants::sqrt3()); + CORRADE_COMPARE(Distance::linePoint(a, b, Vector3(1.0f, 0.0f, 1.0f) + Vector3(100.0f)), + Constants::sqrt2()/Constants::sqrt3()); + + /* Check that 3D implementation gives the same result as 2D implementation */ + CORRADE_COMPARE(Distance::linePoint(a, {1.0f, 1.0f, 0.0f}, Vector3(1.0f, 0.0f, 0.0f)), + 1.0f/Constants::sqrt2()); } void DistanceTest::lineSegmentPoint2D() { @@ -83,28 +93,39 @@ void DistanceTest::lineSegmentPoint2D() { Vector2 b(1.0f); /* Point on the line segment */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(0.25f))), 0.0f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector2(0.25f)), + 0.0f); /* Point on the line, outside the segment, closer to A */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(-1.0f))), Constants::sqrt2()); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector2(-1.0f)), + Constants::sqrt2()); /* Be sure that *Squared() works the same, as it has slightly different implementation */ - CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(-1.0f))), 2.0f); + CORRADE_COMPARE(Distance::lineSegmentPointSquared(a, b, Vector2(-1.0f)), + 2.0f); /* Point on the line, outside the segment, closer to B */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f+1.0f/Constants::sqrt2()))), 1.0f); - CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f+1.0f/Constants::sqrt2()))), 1.0f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector2(1.0f + 1.0f/Constants::sqrt2())), + 1.0f); + CORRADE_COMPARE(Distance::lineSegmentPointSquared(a, b, Vector2(1.0f + 1.0f/Constants::sqrt2())), + 1.0f); /* Point next to the line segment */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f))), 1.0f/Constants::sqrt2()); - CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f))), 0.5f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, {1.0f, 0.0f}), + 1.0f/Constants::sqrt2()); + CORRADE_COMPARE(Distance::lineSegmentPointSquared(a, b, {1.0f, 0.0f}), + 0.5f); /* Point outside the line segment, closer to A */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f)-Vector2(1.0f, 0.5f))), 0.5f); - CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f)-Vector2(1.0f, 0.5f))), 0.25f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f) - Vector2(1.0f, 0.5f)), + 0.5f); + CORRADE_COMPARE(Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f) - Vector2(1.0f, 0.5f)), + 0.25f); /* Point outside the line segment, closer to B */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f)+Vector2(0.5f, 1.0f))), 0.5f); - CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f)+Vector2(0.5f, 1.0f))), 0.25f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f) + Vector2(0.5f, 1.0f)), + 0.5f); + CORRADE_COMPARE(Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f) + Vector2(0.5f, 1.0f)), + 0.25f); } void DistanceTest::lineSegmentPoint3D() { @@ -112,22 +133,28 @@ void DistanceTest::lineSegmentPoint3D() { Vector3 b(1.0f); /* Point on the line segment */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector3(0.25f))), 0.0f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector3(0.25f)), + 0.0f); /* Point on the line, outside the segment, closer to A */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector3(-1.0f))), Constants::sqrt3()); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector3(-1.0f)), + Constants::sqrt3()); /* Point on the line, outside the segment, closer to B */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector3(1.0f+1.0f/Constants::sqrt3()))), 1.0f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector3(1.0f + 1.0f/Constants::sqrt3())), + 1.0f); /* Point next to the line segment */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector3(1.0f, 0.0f, 1.0f))), Constants::sqrt2()/Constants::sqrt3()); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, {1.0f, 0.0f, 1.0f}), + Constants::sqrt2()/Constants::sqrt3()); /* Point outside the line segment, closer to A */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector3(1.0f, 0.0f, 1.0f)-Vector3(1.0f))), 1.0f); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector3(1.0f, 0.0f, 1.0f) - Vector3(1.0f)), + 1.0f); /* Point outside the line segment, closer to B */ - CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector3(1.0f, 0.0f, 1.0f)+Vector3(1.0f))), Constants::sqrt2()); + CORRADE_COMPARE(Distance::lineSegmentPoint(a, b, Vector3(1.0f, 0.0f, 1.0f) + Vector3(1.0f)), + Constants::sqrt2()); } }}}} diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 1db788d34..e5db427ea 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -32,11 +32,9 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class MatrixDeterminant; } -#endif /** @brief Square matrix @@ -60,7 +58,7 @@ template class Matrix: public RectangularMatrix class Matrix: public RectangularMatrix class Matrix: public RectangularMatrix inline constexpr /*implicit*/ Matrix(const Vector& first, const U&... next): RectangularMatrix(first, next...) {} + template constexpr /*implicit*/ Matrix(const Vector& first, const U&... next): RectangularMatrix(first, next...) {} /** * @brief Construct matrix from another of different type @@ -97,10 +95,13 @@ template class Matrix: public RectangularMatrix inline constexpr explicit Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} + template constexpr explicit Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} + + /** @brief Construct matrix from external representation */ + template::from(std::declval()))> constexpr explicit Matrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter::from(other)) {} /** @brief Copy constructor */ - inline constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} + constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} /** * @brief Whether the matrix is orthogonal @@ -111,19 +112,7 @@ template class Matrix: public RectangularMatrix::dot((*this)[i], (*this)[j]) > TypeTraits::epsilon()) - return false; - - return true; - } + bool isOrthogonal() const; /** * @brief Trace of the matrix @@ -132,21 +121,10 @@ template class Matrix: public RectangularMatrixdiagonal().sum(); - } + T trace() const { return this->diagonal().sum(); } /** @brief %Matrix without given column and row */ - Matrix ij(std::size_t skipCol, std::size_t skipRow) const { - Matrix out(Matrix::Zero); - - for(std::size_t col = 0; col != size-1; ++col) - for(std::size_t row = 0; row != size-1; ++row) - out[col][row] = (*this)[col + (col >= skipCol)] - [row + (row >= skipRow)]; - - return out; - } + Matrix ij(std::size_t skipCol, std::size_t skipRow) const; /** * @brief Determinant @@ -159,7 +137,7 @@ template class Matrix: public RectangularMatrix()(*this); } + T determinant() const { return Implementation::MatrixDeterminant()(*this); } /** * @brief Inverted matrix @@ -170,17 +148,7 @@ template class Matrix: public RectangularMatrix inverted() const { - Matrix out(Zero); - - T _determinant = determinant(); - - for(std::size_t col = 0; col != size; ++col) - for(std::size_t row = 0; row != size; ++row) - out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant; - - return out; - } + Matrix inverted() const; /** * @brief Inverted orthogonal matrix @@ -191,7 +159,7 @@ template class Matrix: public RectangularMatrix invertedOrthogonal() const { + Matrix invertedOrthogonal() const { CORRADE_ASSERT(isOrthogonal(), "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {}); return this->transposed(); @@ -199,13 +167,13 @@ template class Matrix: public RectangularMatrix operator*(const Matrix& other) const { + Matrix operator*(const Matrix& other) const { return RectangularMatrix::operator*(other); } - template inline RectangularMatrix operator*(const RectangularMatrix& other) const { + template RectangularMatrix operator*(const RectangularMatrix& other) const { return RectangularMatrix::operator*(other); } - inline Vector operator*(const Vector& other) const { + Vector operator*(const Vector& other) const { return RectangularMatrix::operator*(other); } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) @@ -231,29 +199,29 @@ template inline Corrade::Utility::Debug operator<<(Co #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ - inline VectorType& operator[](std::size_t col) { \ + VectorType& operator[](std::size_t col) { \ return static_cast&>(Matrix::operator[](col)); \ } \ - inline constexpr const VectorType operator[](std::size_t col) const { \ + constexpr const VectorType operator[](std::size_t col) const { \ return VectorType(Matrix::operator[](col)); \ } \ - inline VectorType row(std::size_t row) const { \ + VectorType row(std::size_t row) const { \ return VectorType(Matrix::row(row)); \ } \ \ - inline Type operator*(const Matrix& other) const { \ + Type operator*(const Matrix& other) const { \ return Matrix::operator*(other); \ } \ - template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ + template RectangularMatrix operator*(const RectangularMatrix& other) const { \ return Matrix::operator*(other); \ } \ - inline VectorType operator*(const Vector& other) const { \ + VectorType operator*(const Vector& other) const { \ return Matrix::operator*(other); \ } \ \ - inline Type transposed() const { return Matrix::transposed(); } \ - inline Type inverted() const { return Matrix::inverted(); } \ - inline Type invertedOrthogonal() const { \ + Type transposed() const { return Matrix::transposed(); } \ + Type inverted() const { return Matrix::inverted(); } \ + Type invertedOrthogonal() const { \ return Matrix::invertedOrthogonal(); \ } @@ -272,26 +240,28 @@ namespace Implementation { template class MatrixDeterminant { public: - T operator()(const Matrix& m) { - T out(0); + T operator()(const Matrix& m); +}; - for(std::size_t col = 0; col != size; ++col) - out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant(); +template T MatrixDeterminant::operator()(const Matrix& m) { + T out(0); - return out; - } -}; + for(std::size_t col = 0; col != size; ++col) + out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant(); + + return out; +} template class MatrixDeterminant<2, T> { public: - inline constexpr T operator()(const Matrix<2, T>& m) { + constexpr T operator()(const Matrix<2, T>& m) { return m[0][0]*m[1][1] - m[1][0]*m[0][1]; } }; template class MatrixDeterminant<1, T> { public: - inline constexpr T operator()(const Matrix<1, T>& m) { + constexpr T operator()(const Matrix<1, T>& m) { return m[0][0]; } }; @@ -299,6 +269,43 @@ template class MatrixDeterminant<1, T> { } #endif +template bool Matrix::isOrthogonal() const { + /* Normality */ + for(std::size_t i = 0; i != size; ++i) + if(!(*this)[i].isNormalized()) return false; + + /* Orthogonality */ + for(std::size_t i = 0; i != size-1; ++i) + for(std::size_t j = i+1; j != size; ++j) + if(Vector::dot((*this)[i], (*this)[j]) > TypeTraits::epsilon()) + return false; + + return true; +} + +template Matrix Matrix::ij(const std::size_t skipCol, const std::size_t skipRow) const { + Matrix out(Matrix::Zero); + + for(std::size_t col = 0; col != size-1; ++col) + for(std::size_t row = 0; row != size-1; ++row) + out[col][row] = (*this)[col + (col >= skipCol)] + [row + (row >= skipRow)]; + + return out; +} + +template Matrix Matrix::inverted() const { + Matrix out(Zero); + + const T _determinant = determinant(); + + for(std::size_t col = 0; col != size; ++col) + for(std::size_t row = 0; row != size; ++row) + out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant; + + return out; +} + }} namespace Corrade { namespace Utility { diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 2b43e83b0..ac2bae462 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -53,7 +53,7 @@ template class Matrix3: public Matrix<3, T> { * Matrix4::translation(const Vector3&), Vector2::xAxis(), * Vector2::yAxis() */ - inline constexpr static Matrix3 translation(const Vector2& vector) { + constexpr static Matrix3 translation(const Vector2& vector) { return {{ T(1), T(0), T(0)}, { T(0), T(1), T(0)}, {vector.x(), vector.y(), T(1)}}; @@ -66,7 +66,7 @@ template class Matrix3: public Matrix<3, T> { * @see rotationScaling() const, Matrix4::scaling(const Vector3&), * Vector2::xScale(), Vector2::yScale() */ - inline constexpr static Matrix3 scaling(const Vector2& vector) { + constexpr static Matrix3 scaling(const Vector2& vector) { return {{vector.x(), T(0), T(0)}, { T(0), vector.y(), T(0)}, { T(0), T(0), T(1)}}; @@ -79,14 +79,7 @@ template class Matrix3: public Matrix<3, T> { * @see rotation() const, Complex::rotation(), DualComplex::rotation(), * Matrix4::rotation(Rad, const Vector3&) */ - static Matrix3 rotation(Rad angle) { - T sine = std::sin(angle.toUnderlyingType()); - T cosine = std::cos(angle.toUnderlyingType()); - - return {{ cosine, sine, T(0)}, - { -sine, cosine, T(0)}, - { T(0), T(0), T(1)}}; - } + static Matrix3 rotation(Rad angle); /** * @brief 2D reflection matrix @@ -120,14 +113,14 @@ template class Matrix3: public Matrix<3, T> { * * @see rotationScaling() const, translation() const */ - inline constexpr static Matrix3 from(const Matrix<2, T>& rotationScaling, const Vector2& translation) { + constexpr static Matrix3 from(const Matrix<2, T>& rotationScaling, const Vector2& translation) { return {{rotationScaling[0], T(0)}, {rotationScaling[1], T(0)}, { translation, T(1)}}; } /** @copydoc Matrix::Matrix(ZeroType) */ - inline constexpr explicit Matrix3(typename Matrix<3, T>::ZeroType): Matrix<3, T>(Matrix<3, T>::Zero) {} + constexpr explicit Matrix3(typename Matrix<3, T>::ZeroType): Matrix<3, T>(Matrix<3, T>::Zero) {} /** * @brief Default constructor @@ -137,20 +130,23 @@ template class Matrix3: public Matrix<3, T> { * @p value allows you to specify value on diagonal. * @todo Use constexpr implementation in Matrix, when done */ - inline constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>( + constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>( Vector<3, T>(value, T(0), T(0)), Vector<3, T>( T(0), value, T(0)), Vector<3, T>( T(0), T(0), value) ) {} /** @brief %Matrix from column vectors */ - inline constexpr /*implicit*/ Matrix3(const Vector3& first, const Vector3& second, const Vector3& third): Matrix<3, T>(first, second, third) {} + constexpr /*implicit*/ Matrix3(const Vector3& first, const Vector3& second, const Vector3& third): Matrix<3, T>(first, second, third) {} /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ - template inline constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other): Matrix<3, T>(other) {} + template constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other): Matrix<3, T>(other) {} + + /** @brief Construct matrix from external representation */ + template::from(std::declval()))> constexpr explicit Matrix3(const U& other): Matrix<3, T>(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(other)) {} /** @brief Copy constructor */ - inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} + constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} /** * @brief Check whether the matrix represents rigid transformation @@ -159,7 +155,7 @@ template class Matrix3: public Matrix<3, T> { * no scaling or projection). * @see isOrthogonal() */ - inline bool isRigidTransformation() const { + bool isRigidTransformation() const { return rotationScaling().isOrthogonal() && row(2) == Vector3(T(0), T(0), T(1)); } @@ -169,8 +165,9 @@ template class Matrix3: public Matrix<3, T> { * Upper-left 2x2 part of the matrix. * @see from(const Matrix<2, T>&, const Vector2&), rotation() const, * rotation(T), Matrix4::rotationScaling() const + * @todo extract rotation with assert for no scaling */ - inline constexpr Matrix<2, T> rotationScaling() const { + constexpr Matrix<2, T> rotationScaling() const { return {(*this)[0].xy(), (*this)[1].xy()}; } @@ -182,7 +179,7 @@ template class Matrix3: public Matrix<3, T> { * @see rotationScaling() const, rotation(T), Matrix4::rotation() const * @todo assert uniform scaling (otherwise this would be garbage) */ - inline Matrix<2, T> rotation() const { + Matrix<2, T> rotation() const { return {(*this)[0].xy().normalized(), (*this)[1].xy().normalized()}; } @@ -195,8 +192,8 @@ template class Matrix3: public Matrix<3, T> { * First two elements of first column. * @see up(), Vector2::xAxis(), Matrix4::right() */ - inline Vector2& right() { return (*this)[0].xy(); } - inline constexpr Vector2 right() const { return (*this)[0].xy(); } /**< @overload */ + Vector2& right() { return (*this)[0].xy(); } + constexpr Vector2 right() const { return (*this)[0].xy(); } /**< @overload */ /** * @brief Up-pointing 2D vector @@ -204,8 +201,8 @@ template class Matrix3: public Matrix<3, T> { * First two elements of second column. * @see right(), Vector2::yAxis(), Matrix4::up() */ - inline Vector2& up() { return (*this)[1].xy(); } - inline constexpr Vector2 up() const { return (*this)[1].xy(); } /**< @overload */ + Vector2& up() { return (*this)[1].xy(); } + constexpr Vector2 up() const { return (*this)[1].xy(); } /**< @overload */ /** * @brief 2D translation part of the matrix @@ -214,8 +211,8 @@ template class Matrix3: public Matrix<3, T> { * @see from(const Matrix<2, T>&, const Vector2&), * translation(const Vector2&), Matrix4::translation() */ - inline Vector2& translation() { return (*this)[2].xy(); } - inline constexpr Vector2 translation() const { return (*this)[2].xy(); } /**< @overload */ + Vector2& translation() { return (*this)[2].xy(); } + constexpr Vector2 translation() const { return (*this)[2].xy(); } /**< @overload */ /** * @brief Inverted rigid transformation matrix @@ -225,13 +222,7 @@ template class Matrix3: public Matrix<3, T> { * @see isRigidTransformation(), invertedOrthogonal(), * rotationScaling() const, translation() const */ - inline Matrix3 invertedRigid() const { - CORRADE_ASSERT(isRigidTransformation(), - "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {}); - - Matrix<2, T> inverseRotation = rotationScaling().transposed(); - return from(inverseRotation, inverseRotation*-translation()); - } + Matrix3 invertedRigid() const; /** * @brief Transform 2D vector with the matrix @@ -243,7 +234,7 @@ template class Matrix3: public Matrix<3, T> { * @see Complex::transformVector(), Matrix4::transformVector() * @todo extract 2x2 matrix and multiply directly? (benchmark that) */ - inline Vector2 transformVector(const Vector2& vector) const { + Vector2 transformVector(const Vector2& vector) const { /* Workaround for GCC 4.4 strict-aliasing fascism */ #ifndef CORRADE_GCC44_COMPATIBILITY return ((*this)*Vector3(vector, T(0))).xy(); @@ -262,7 +253,7 @@ template class Matrix3: public Matrix<3, T> { * @f] * @see DualComplex::transformPoint(), Matrix4::transformPoint() */ - inline Vector2 transformPoint(const Vector2& vector) const { + Vector2 transformPoint(const Vector2& vector) const { /* Workaround for GCC 4.4 strict-aliasing fascism */ #ifndef CORRADE_GCC44_COMPATIBILITY return ((*this)*Vector3(vector, T(1))).xy(); @@ -283,6 +274,23 @@ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::De return debug << static_cast&>(value); } +template Matrix3 Matrix3::rotation(const Rad angle) { + const T sine = std::sin(angle.toUnderlyingType()); + const T cosine = std::cos(angle.toUnderlyingType()); + + return {{ cosine, sine, T(0)}, + { -sine, cosine, T(0)}, + { T(0), T(0), T(1)}}; +} + +template inline Matrix3 Matrix3::invertedRigid() const { + CORRADE_ASSERT(isRigidTransformation(), + "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {}); + + Matrix<2, T> inverseRotation = rotationScaling().transposed(); + return from(inverseRotation, inverseRotation*-translation()); +} + }} namespace Corrade { namespace Utility { diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 8fb0484ce..bb3ed6c31 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -58,7 +58,7 @@ template class Matrix4: public Matrix<4, T> { * Matrix3::translation(const Vector2&), Vector3::xAxis(), * Vector3::yAxis(), Vector3::zAxis() */ - inline constexpr static Matrix4 translation(const Vector3& vector) { + constexpr static Matrix4 translation(const Vector3& vector) { return {{ T(1), T(0), T(0), T(0)}, { T(0), T(1), T(0), T(0)}, { T(0), T(0), T(1), T(0)}, @@ -72,7 +72,7 @@ template class Matrix4: public Matrix<4, T> { * @see rotationScaling() const, Matrix3::scaling(const Vector2&), * Vector3::xScale(), Vector3::yScale(), Vector3::zScale() */ - inline constexpr static Matrix4 scaling(const Vector3& vector) { + constexpr static Matrix4 scaling(const Vector3& vector) { return {{vector.x(), T(0), T(0), T(0)}, { T(0), vector.y(), T(0), T(0)}, { T(0), T(0), vector.z(), T(0)}, @@ -90,37 +90,7 @@ template class Matrix4: public Matrix<4, T> { * Matrix3::rotation(Rad), Vector3::xAxis(), Vector3::yAxis(), * Vector3::zAxis(), Vector::isNormalized() */ - static Matrix4 rotation(Rad angle, const Vector3& normalizedAxis) { - CORRADE_ASSERT(normalizedAxis.isNormalized(), - "Math::Matrix4::rotation(): axis must be normalized", {}); - - T sine = std::sin(angle.toUnderlyingType()); - T cosine = std::cos(angle.toUnderlyingType()); - T oneMinusCosine = T(1) - cosine; - - T xx = normalizedAxis.x()*normalizedAxis.x(); - T xy = normalizedAxis.x()*normalizedAxis.y(); - T xz = normalizedAxis.x()*normalizedAxis.z(); - T yy = normalizedAxis.y()*normalizedAxis.y(); - T yz = normalizedAxis.y()*normalizedAxis.z(); - T zz = normalizedAxis.z()*normalizedAxis.z(); - - return { - {cosine + xx*oneMinusCosine, - xy*oneMinusCosine + normalizedAxis.z()*sine, - xz*oneMinusCosine - normalizedAxis.y()*sine, - T(0)}, - {xy*oneMinusCosine - normalizedAxis.z()*sine, - cosine + yy*oneMinusCosine, - yz*oneMinusCosine + normalizedAxis.x()*sine, - T(0)}, - {xz*oneMinusCosine + normalizedAxis.y()*sine, - yz*oneMinusCosine - normalizedAxis.x()*sine, - cosine + zz*oneMinusCosine, - T(0)}, - {T(0), T(0), T(0), T(1)} - }; - } + static Matrix4 rotation(Rad angle, const Vector3& normalizedAxis); /** * @brief 3D rotation around X axis @@ -130,15 +100,7 @@ template class Matrix4: public Matrix<4, T> { * @see rotation(Rad, const Vector3&), rotationY(), rotationZ(), * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) */ - static Matrix4 rotationX(Rad angle) { - T sine = std::sin(angle.toUnderlyingType()); - T cosine = std::cos(angle.toUnderlyingType()); - - return {{T(1), T(0), T(0), T(0)}, - {T(0), cosine, sine, T(0)}, - {T(0), -sine, cosine, T(0)}, - {T(0), T(0), T(0), T(1)}}; - } + static Matrix4 rotationX(Rad angle); /** * @brief 3D rotation around Y axis @@ -148,15 +110,7 @@ template class Matrix4: public Matrix<4, T> { * @see rotation(Rad, const Vector3&), rotationX(), rotationZ(), * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) */ - static Matrix4 rotationY(Rad angle) { - T sine = std::sin(angle.toUnderlyingType()); - T cosine = std::cos(angle.toUnderlyingType()); - - return {{cosine, T(0), -sine, T(0)}, - { T(0), T(1), T(0), T(0)}, - { sine, T(0), cosine, T(0)}, - { T(0), T(0), T(0), T(1)}}; - } + static Matrix4 rotationY(Rad angle); /** * @brief 3D rotation matrix around Z axis @@ -166,15 +120,7 @@ template class Matrix4: public Matrix<4, T> { * @see rotation(Rad, const Vector3&), rotationX(), rotationY(), * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) */ - static Matrix4 rotationZ(Rad angle) { - T sine = std::sin(angle.toUnderlyingType()); - T cosine = std::cos(angle.toUnderlyingType()); - - return {{cosine, sine, T(0), T(0)}, - { -sine, cosine, T(0), T(0)}, - { T(0), T(0), T(1), T(0)}, - { T(0), T(0), T(0), T(1)}}; - } + static Matrix4 rotationZ(Rad angle); /** * @brief 3D reflection matrix @@ -183,11 +129,7 @@ template class Matrix4: public Matrix<4, T> { * Expects that the normal is normalized. * @see Matrix3::reflection(), Vector::isNormalized() */ - static Matrix4 reflection(const Vector3& normal) { - CORRADE_ASSERT(normal.isNormalized(), - "Math::Matrix4::reflection(): normal must be normalized", {}); - return from(Matrix<3, T>() - T(2)*normal*RectangularMatrix<1, 3, T>(normal).transposed(), {}); - } + static Matrix4 reflection(const Vector3& normal); /** * @brief 3D orthographic projection matrix @@ -197,15 +139,7 @@ template class Matrix4: public Matrix<4, T> { * * @see perspectiveProjection(), Matrix3::projection() */ - static Matrix4 orthographicProjection(const Vector2& size, T near, T far) { - Vector2 xyScale = T(2.0)/size; - T zScale = T(2.0)/(near-far); - - return {{xyScale.x(), T(0), T(0), T(0)}, - { T(0), xyScale.y(), T(0), T(0)}, - { T(0), T(0), zScale, T(0)}, - { T(0), T(0), near*zScale-T(1), T(1)}}; - } + static Matrix4 orthographicProjection(const Vector2& size, T near, T far); /** * @brief 3D perspective projection matrix @@ -215,15 +149,7 @@ template class Matrix4: public Matrix<4, T> { * * @see orthographicProjection(), Matrix3::projection() */ - static Matrix4 perspectiveProjection(const Vector2& size, T near, T far) { - Vector2 xyScale = 2*near/size; - T zScale = T(1.0)/(near-far); - - return {{xyScale.x(), T(0), T(0), T(0)}, - { T(0), xyScale.y(), T(0), T(0)}, - { T(0), T(0), (far+near)*zScale, T(-1)}, - { T(0), T(0), T(2)*far*near*zScale, T(0)}}; - } + static Matrix4 perspectiveProjection(const Vector2& size, T near, T far); /** * @brief 3D perspective projection matrix @@ -235,8 +161,7 @@ template class Matrix4: public Matrix<4, T> { * @see orthographicProjection(), Matrix3::projection() */ static Matrix4 perspectiveProjection(Rad fov, T aspectRatio, T near, T far) { - T xyScale = 2*std::tan(fov.toUnderlyingType()/2)*near; - + const T xyScale = 2*std::tan(fov.toUnderlyingType()/2)*near; return perspectiveProjection(Vector2(xyScale, xyScale/aspectRatio), near, far); } @@ -249,7 +174,7 @@ template class Matrix4: public Matrix<4, T> { * * @see rotationScaling() const, translation() const */ - inline constexpr static Matrix4 from(const Matrix<3, T>& rotationScaling, const Vector3& translation) { + constexpr static Matrix4 from(const Matrix<3, T>& rotationScaling, const Vector3& translation) { return {{rotationScaling[0], T(0)}, {rotationScaling[1], T(0)}, {rotationScaling[2], T(0)}, @@ -257,7 +182,7 @@ template class Matrix4: public Matrix<4, T> { } /** @copydoc Matrix::Matrix(ZeroType) */ - inline constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {} + constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {} /** * @brief Default constructor @@ -267,7 +192,7 @@ template class Matrix4: public Matrix<4, T> { * @p value allows you to specify value on diagonal. * @todo Use constexpr implementation in Matrix, when done */ - inline constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>( + constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>( Vector<4, T>(value, T(0), T(0), T(0)), Vector<4, T>( T(0), value, T(0), T(0)), Vector<4, T>( T(0), T(0), value, T(0)), @@ -275,13 +200,16 @@ template class Matrix4: public Matrix<4, T> { ) {} /** @brief %Matrix from column vectors */ - inline constexpr /*implicit*/ Matrix4(const Vector4& first, const Vector4& second, const Vector4& third, const Vector4& fourth): Matrix<4, T>(first, second, third, fourth) {} + constexpr /*implicit*/ Matrix4(const Vector4& first, const Vector4& second, const Vector4& third, const Vector4& fourth): Matrix<4, T>(first, second, third, fourth) {} /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ - template inline constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other): Matrix<4, T>(other) {} + template constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other): Matrix<4, T>(other) {} + + /** @brief Construct matrix from external representation */ + template::from(std::declval()))> constexpr explicit Matrix4(const U& other): Matrix<4, T>(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(other)) {} /** @brief Copy constructor */ - inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} + constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} /** * @brief Check whether the matrix represents rigid transformation @@ -290,7 +218,7 @@ template class Matrix4: public Matrix<4, T> { * no scaling or projection). * @see isOrthogonal() */ - inline bool isRigidTransformation() const { + bool isRigidTransformation() const { return rotationScaling().isOrthogonal() && row(3) == Vector4(T(0), T(0), T(0), T(1)); } @@ -300,9 +228,10 @@ template class Matrix4: public Matrix<4, T> { * Upper-left 3x3 part of the matrix. * @see from(const Matrix<3, T>&, const Vector3&), rotation() const, * rotation(T, const Vector3&), Matrix3::rotationScaling() const + * @todo extract rotation with assert for no scaling */ - inline constexpr Matrix<3, T> rotationScaling() const { - /* Not Matrix3, because it is for affine 2D transformations */ + /* Not Matrix3, because it is for affine 2D transformations */ + constexpr Matrix<3, T> rotationScaling() const { return {(*this)[0].xyz(), (*this)[1].xyz(), (*this)[2].xyz()}; @@ -316,12 +245,8 @@ template class Matrix4: public Matrix<4, T> { * Matrix3::rotation() const * @todo assert uniform scaling (otherwise this would be garbage) */ - inline Matrix<3, T> rotation() const { - /* Not Matrix3, because it is for affine 2D transformations */ - return {(*this)[0].xyz().normalized(), - (*this)[1].xyz().normalized(), - (*this)[2].xyz().normalized()}; - } + /* Not Matrix3, because it is for affine 2D transformations */ + Matrix<3, T> rotation() const; /** @todo uniform scaling extraction */ @@ -331,8 +256,8 @@ template class Matrix4: public Matrix<4, T> { * First three elements of first column. * @see up(), backward(), Vector3::xAxis(), Matrix3::right() */ - inline Vector3& right() { return (*this)[0].xyz(); } - inline constexpr Vector3 right() const { return (*this)[0].xyz(); } /**< @overload */ + Vector3& right() { return (*this)[0].xyz(); } + constexpr Vector3 right() const { return (*this)[0].xyz(); } /**< @overload */ /** * @brief Up-pointing 3D vector @@ -340,8 +265,8 @@ template class Matrix4: public Matrix<4, T> { * First three elements of second column. * @see right(), backward(), Vector3::yAxis(), Matrix3::up() */ - inline Vector3& up() { return (*this)[1].xyz(); } - inline constexpr Vector3 up() const { return (*this)[1].xyz(); } /**< @overload */ + Vector3& up() { return (*this)[1].xyz(); } + constexpr Vector3 up() const { return (*this)[1].xyz(); } /**< @overload */ /** * @brief Backward-pointing 3D vector @@ -349,8 +274,8 @@ template class Matrix4: public Matrix<4, T> { * First three elements of third column. * @see right(), up(), Vector3::yAxis() */ - inline Vector3& backward() { return (*this)[2].xyz(); } - inline constexpr Vector3 backward() const { return (*this)[2].xyz(); } /**< @overload */ + Vector3& backward() { return (*this)[2].xyz(); } + constexpr Vector3 backward() const { return (*this)[2].xyz(); } /**< @overload */ /** * @brief 3D translation part of the matrix @@ -359,8 +284,8 @@ template class Matrix4: public Matrix<4, T> { * @see from(const Matrix<3, T>&, const Vector3&), * translation(const Vector3&), Matrix3::translation() */ - inline Vector3& translation() { return (*this)[3].xyz(); } - inline constexpr Vector3 translation() const { return (*this)[3].xyz(); } /**< @overload */ + Vector3& translation() { return (*this)[3].xyz(); } + constexpr Vector3 translation() const { return (*this)[3].xyz(); } /**< @overload */ /** * @brief Inverted rigid transformation matrix @@ -370,13 +295,7 @@ template class Matrix4: public Matrix<4, T> { * @see isRigidTransformation(), invertedOrthogonal(), * rotationScaling() const, translation() const */ - inline Matrix4 invertedRigid() const { - CORRADE_ASSERT(isRigidTransformation(), - "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {}); - - Matrix<3, T> inverseRotation = rotationScaling().transposed(); - return from(inverseRotation, inverseRotation*-translation()); - } + Matrix4 invertedRigid() const; /** * @brief Transform 3D vector with the matrix @@ -388,7 +307,7 @@ template class Matrix4: public Matrix<4, T> { * @see Quaternion::transformVector(), Matrix3::transformVector() * @todo extract 3x3 matrix and multiply directly? (benchmark that) */ - inline Vector3 transformVector(const Vector3& vector) const { + Vector3 transformVector(const Vector3& vector) const { /* Workaround for GCC 4.4 strict-aliasing fascism */ #ifndef CORRADE_GCC44_COMPATIBILITY return ((*this)*Vector4(vector, T(0))).xyz(); @@ -407,7 +326,7 @@ template class Matrix4: public Matrix<4, T> { * @f] * @see DualQuaternion::transformPoint(), Matrix3::transformPoint() */ - inline Vector3 transformPoint(const Vector3& vector) const { + Vector3 transformPoint(const Vector3& vector) const { /* Workaround for GCC 4.4 strict-aliasing fascism */ #ifndef CORRADE_GCC44_COMPATIBILITY return ((*this)*Vector4(vector, T(1))).xyz(); @@ -428,6 +347,108 @@ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::De return debug << static_cast&>(value); } +template Matrix4 Matrix4::rotation(const Rad angle, const Vector3& normalizedAxis) { + CORRADE_ASSERT(normalizedAxis.isNormalized(), + "Math::Matrix4::rotation(): axis must be normalized", {}); + + const T sine = std::sin(angle.toUnderlyingType()); + const T cosine = std::cos(angle.toUnderlyingType()); + const T oneMinusCosine = T(1) - cosine; + + const T xx = normalizedAxis.x()*normalizedAxis.x(); + const T xy = normalizedAxis.x()*normalizedAxis.y(); + const T xz = normalizedAxis.x()*normalizedAxis.z(); + const T yy = normalizedAxis.y()*normalizedAxis.y(); + const T yz = normalizedAxis.y()*normalizedAxis.z(); + const T zz = normalizedAxis.z()*normalizedAxis.z(); + + return { + {cosine + xx*oneMinusCosine, + xy*oneMinusCosine + normalizedAxis.z()*sine, + xz*oneMinusCosine - normalizedAxis.y()*sine, + T(0)}, + {xy*oneMinusCosine - normalizedAxis.z()*sine, + cosine + yy*oneMinusCosine, + yz*oneMinusCosine + normalizedAxis.x()*sine, + T(0)}, + {xz*oneMinusCosine + normalizedAxis.y()*sine, + yz*oneMinusCosine - normalizedAxis.x()*sine, + cosine + zz*oneMinusCosine, + T(0)}, + {T(0), T(0), T(0), T(1)} + }; +} + +template Matrix4 Matrix4::rotationX(const Rad angle) { + const T sine = std::sin(angle.toUnderlyingType()); + const T cosine = std::cos(angle.toUnderlyingType()); + + return {{T(1), T(0), T(0), T(0)}, + {T(0), cosine, sine, T(0)}, + {T(0), -sine, cosine, T(0)}, + {T(0), T(0), T(0), T(1)}}; +} + +template Matrix4 Matrix4::rotationY(const Rad angle) { + const T sine = std::sin(angle.toUnderlyingType()); + const T cosine = std::cos(angle.toUnderlyingType()); + + return {{cosine, T(0), -sine, T(0)}, + { T(0), T(1), T(0), T(0)}, + { sine, T(0), cosine, T(0)}, + { T(0), T(0), T(0), T(1)}}; +} + +template Matrix4 Matrix4::rotationZ(const Rad angle) { + const T sine = std::sin(angle.toUnderlyingType()); + const T cosine = std::cos(angle.toUnderlyingType()); + + return {{cosine, sine, T(0), T(0)}, + { -sine, cosine, T(0), T(0)}, + { T(0), T(0), T(1), T(0)}, + { T(0), T(0), T(0), T(1)}}; +} + +template Matrix4 Matrix4::reflection(const Vector3& normal) { + CORRADE_ASSERT(normal.isNormalized(), + "Math::Matrix4::reflection(): normal must be normalized", {}); + return from(Matrix<3, T>() - T(2)*normal*RectangularMatrix<1, 3, T>(normal).transposed(), {}); +} + +template Matrix4 Matrix4::orthographicProjection(const Vector2& size, const T near, const T far) { + const Vector2 xyScale = T(2.0)/size; + const T zScale = T(2.0)/(near-far); + + return {{xyScale.x(), T(0), T(0), T(0)}, + { T(0), xyScale.y(), T(0), T(0)}, + { T(0), T(0), zScale, T(0)}, + { T(0), T(0), near*zScale-T(1), T(1)}}; +} + +template Matrix4 Matrix4::perspectiveProjection(const Vector2& size, const T near, const T far) { + Vector2 xyScale = 2*near/size; + T zScale = T(1.0)/(near-far); + + return {{xyScale.x(), T(0), T(0), T(0)}, + { T(0), xyScale.y(), T(0), T(0)}, + { T(0), T(0), (far+near)*zScale, T(-1)}, + { T(0), T(0), T(2)*far*near*zScale, T(0)}}; +} + +template inline Matrix<3, T> Matrix4::rotation() const { + return {(*this)[0].xyz().normalized(), + (*this)[1].xyz().normalized(), + (*this)[2].xyz().normalized()}; +} + +template Matrix4 Matrix4::invertedRigid() const { + CORRADE_ASSERT(isRigidTransformation(), + "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {}); + + Matrix<3, T> inverseRotation = rotationScaling().transposed(); + return from(inverseRotation, inverseRotation*-translation()); +} + }} namespace Corrade { namespace Utility { diff --git a/src/Math/Quaternion.cpp b/src/Math/Quaternion.cpp deleted file mode 100644 index 8ec3c0b13..000000000 --- a/src/Math/Quaternion.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "Quaternion.h" - -namespace Magnum { namespace Math { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quaternion&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quaternion&); -#endif -#endif - -}} diff --git a/src/Math/Quaternion.h b/src/Math/Quaternion.h index 644f81029..5e246c849 100644 --- a/src/Math/Quaternion.h +++ b/src/Math/Quaternion.h @@ -38,45 +38,6 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - -/* No assertions fired, for internal use */ -template inline Quaternion quaternionFromMatrix(const Matrix<3, T>& m) { - const Vector<3, T> diagonal = m.diagonal(); - const T trace = diagonal.sum(); - - /* Diagonal is positive */ - if(trace > T(0)) { - const T s = std::sqrt(trace + T(1)); - const T t = T(0.5)/s; - return {Vector3(m[1][2] - m[2][1], - m[2][0] - m[0][2], - m[0][1] - m[1][0])*t, s*T(0.5)}; - } - - /* Diagonal is negative */ - std::size_t i = 0; - if(diagonal[1] > diagonal[0]) i = 1; - if(diagonal[2] > diagonal[i]) i = 2; - - const std::size_t j = (i + 1) % 3; - const std::size_t k = (i + 2) % 3; - - const T s = std::sqrt(diagonal[i] - diagonal[j] - diagonal[k] + T(1)); - const T t = (s == T(0) ? T(0) : T(0.5)/s); - - Vector3 vec; - vec[i] = s*T(0.5); - vec[j] = (m[i][j] + m[j][i])*t; - vec[k] = (m[i][k] + m[k][i])*t; - - return {vec, (m[j][k] - m[k][j])*t}; -} - -} -#endif - /** @brief %Quaternion @tparam T Underlying data type @@ -96,7 +57,7 @@ template class Quaternion { * @f] * @see dot() const */ - inline static T dot(const Quaternion& a, const Quaternion& b) { + static T dot(const Quaternion& a, const Quaternion& b) { /** @todo Use four-component SIMD implementation when available */ return Vector3::dot(a.vector(), b.vector()) + a.scalar()*b.scalar(); } @@ -109,11 +70,7 @@ template class Quaternion { * @f] * @see isNormalized(), Complex::angle(), Vector::angle() */ - inline static Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Quaternion::angle(): quaternions must be normalized", Rad(std::numeric_limits::quiet_NaN())); - return Rad(angleInternal(normalizedA, normalizedB)); - } + static Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB); /** * @brief Linear interpolation of two quaternions @@ -126,12 +83,7 @@ template class Quaternion { * @f] * @see isNormalized(), slerp(), Math::lerp() */ - inline static Quaternion lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Quaternion::lerp(): quaternions must be normalized", - Quaternion({}, std::numeric_limits::quiet_NaN())); - return ((T(1) - t)*normalizedA + t*normalizedB).normalized(); - } + static Quaternion lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t); /** * @brief Spherical linear interpolation of two quaternions @@ -146,13 +98,7 @@ template class Quaternion { * @f] * @see isNormalized(), lerp() */ - inline static Quaternion slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Quaternion::slerp(): quaternions must be normalized", - Quaternion({}, std::numeric_limits::quiet_NaN())); - T a = angleInternal(normalizedA, normalizedB); - return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a); - } + static Quaternion slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, T t); /** * @brief Rotation quaternion @@ -166,12 +112,7 @@ template class Quaternion { * Matrix4::rotation(), Complex::rotation(), Vector3::xAxis(), * Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized() */ - inline static Quaternion rotation(Rad angle, const Vector3& normalizedAxis) { - CORRADE_ASSERT(normalizedAxis.isNormalized(), - "Math::Quaternion::rotation(): axis must be normalized", {}); - - return {normalizedAxis*std::sin(angle.toUnderlyingType()/2), std::cos(angle.toUnderlyingType()/2)}; - } + static Quaternion rotation(Rad angle, const Vector3& normalizedAxis); /** * @brief Create quaternion from rotation matrix @@ -179,11 +120,7 @@ template class Quaternion { * Expects that the matrix is orthogonal (i.e. pure rotation). * @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal() */ - inline static Quaternion fromMatrix(const Matrix<3, T>& matrix) { - CORRADE_ASSERT(matrix.isOrthogonal(), - "Math::Quaternion::fromMatrix(): the matrix is not orthogonal", {}); - return Implementation::quaternionFromMatrix(matrix); - } + static Quaternion fromMatrix(const Matrix<3, T>& matrix); /** * @brief Default constructor @@ -192,7 +129,7 @@ template class Quaternion { * q = [\boldsymbol 0, 1] * @f] */ - inline constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {} + constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {} /** * @brief Construct quaternion from vector and scalar @@ -201,7 +138,7 @@ template class Quaternion { * q = [\boldsymbol v, s] * @f] */ - inline constexpr /*implicit*/ Quaternion(const Vector3& vector, T scalar): _vector(vector), _scalar(scalar) {} + constexpr /*implicit*/ Quaternion(const Vector3& vector, T scalar): _vector(vector), _scalar(scalar) {} /** * @brief Construct quaternion from vector @@ -211,15 +148,15 @@ template class Quaternion { * @f] * @see transformVector(), transformVectorNormalized() */ - inline constexpr explicit Quaternion(const Vector3& vector): _vector(vector), _scalar(T(0)) {} + constexpr explicit Quaternion(const Vector3& vector): _vector(vector), _scalar(T(0)) {} /** @brief Equality comparison */ - inline bool operator==(const Quaternion& other) const { + bool operator==(const Quaternion& other) const { return _vector == other._vector && TypeTraits::equals(_scalar, other._scalar); } /** @brief Non-equality comparison */ - inline bool operator!=(const Quaternion& other) const { + bool operator!=(const Quaternion& other) const { return !operator==(other); } @@ -231,15 +168,15 @@ template class Quaternion { * @f] * @see dot(), normalized() */ - inline bool isNormalized() const { + bool isNormalized() const { return Implementation::isNormalizedSquared(dot()); } /** @brief %Vector part */ - inline constexpr Vector3 vector() const { return _vector; } + constexpr Vector3 vector() const { return _vector; } /** @brief %Scalar part */ - inline constexpr T scalar() const { return _scalar; } + constexpr T scalar() const { return _scalar; } /** * @brief Rotation angle of unit quaternion @@ -249,12 +186,7 @@ template class Quaternion { * @f] * @see isNormalized(), axis(), rotation() */ - inline Rad angle() const { - CORRADE_ASSERT(isNormalized(), - "Math::Quaternion::angle(): quaternion must be normalized", - Rad(std::numeric_limits::quiet_NaN())); - return Rad(T(2)*std::acos(_scalar)); - } + Rad angle() const; /** * @brief Rotation axis of unit quaternion @@ -266,12 +198,7 @@ template class Quaternion { * @f] * @see isNormalized(), angle(), rotation() */ - inline Vector3 axis() const { - CORRADE_ASSERT(isNormalized(), - "Math::Quaternion::axis(): quaternion must be normalized", - {}); - return _vector/std::sqrt(1-pow2(_scalar)); - } + Vector3 axis() const; /** * @brief Convert quaternion to rotation matrix @@ -279,19 +206,7 @@ template class Quaternion { * @see fromMatrix(), DualQuaternion::toMatrix(), * Matrix4::from(const Matrix<3, T>&, const Vector3&) */ - Matrix<3, T> toMatrix() const { - return { - Vector<3, T>(T(1) - 2*pow2(_vector.y()) - 2*pow2(_vector.z()), - 2*_vector.x()*_vector.y() + 2*_vector.z()*_scalar, - 2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar), - Vector<3, T>(2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar, - T(1) - 2*pow2(_vector.x()) - 2*pow2(_vector.z()), - 2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar), - Vector<3, T>(2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar, - 2*_vector.y()*_vector.z() - 2*_vector.x()*_scalar, - T(1) - 2*pow2(_vector.x()) - 2*pow2(_vector.y())) - }; - } + Matrix<3, T> toMatrix() const; /** * @brief Add and assign quaternion @@ -300,7 +215,7 @@ template class Quaternion { * p + q = [\boldsymbol p_V + \boldsymbol q_V, p_S + q_S] * @f] */ - inline Quaternion& operator+=(const Quaternion& other) { + Quaternion& operator+=(const Quaternion& other) { _vector += other._vector; _scalar += other._scalar; return *this; @@ -311,7 +226,7 @@ template class Quaternion { * * @see operator+=() */ - inline Quaternion operator+(const Quaternion& other) const { + Quaternion operator+(const Quaternion& other) const { return Quaternion(*this) += other; } @@ -322,9 +237,7 @@ template class Quaternion { * -q = [-\boldsymbol q_V, -q_S] * @f] */ - inline Quaternion operator-() const { - return {-_vector, -_scalar}; - } + Quaternion operator-() const { return {-_vector, -_scalar}; } /** * @brief Subtract and assign quaternion @@ -333,7 +246,7 @@ template class Quaternion { * p - q = [\boldsymbol p_V - \boldsymbol q_V, p_S - q_S] * @f] */ - inline Quaternion& operator-=(const Quaternion& other) { + Quaternion& operator-=(const Quaternion& other) { _vector -= other._vector; _scalar -= other._scalar; return *this; @@ -344,7 +257,7 @@ template class Quaternion { * * @see operator-=() */ - inline Quaternion operator-(const Quaternion& other) const { + Quaternion operator-(const Quaternion& other) const { return Quaternion(*this) -= other; } @@ -355,7 +268,7 @@ template class Quaternion { * q \cdot a = [\boldsymbol q_V \cdot a, q_S \cdot a] * @f] */ - inline Quaternion& operator*=(T scalar) { + Quaternion& operator*=(T scalar) { _vector *= scalar; _scalar *= scalar; return *this; @@ -366,7 +279,7 @@ template class Quaternion { * * @see operator*=(T) */ - inline Quaternion operator*(T scalar) const { + Quaternion operator*(T scalar) const { return Quaternion(*this) *= scalar; } @@ -377,7 +290,7 @@ template class Quaternion { * \frac q a = [\frac {\boldsymbol q_V} a, \frac {q_S} a] * @f] */ - inline Quaternion& operator/=(T scalar) { + Quaternion& operator/=(T scalar) { _vector /= scalar; _scalar /= scalar; return *this; @@ -388,7 +301,7 @@ template class Quaternion { * * @see operator/=(T) */ - inline Quaternion operator/(T scalar) const { + Quaternion operator/(T scalar) const { return Quaternion(*this) /= scalar; } @@ -400,10 +313,7 @@ template class Quaternion { * p_S q_S - \boldsymbol p_V \cdot \boldsymbol q_V] * @f] */ - inline Quaternion operator*(const Quaternion& other) const { - return {_scalar*other._vector + other._scalar*_vector + Vector3::cross(_vector, other._vector), - _scalar*other._scalar - Vector3::dot(_vector, other._vector)}; - } + Quaternion operator*(const Quaternion& other) const; /** * @brief Dot product of the quaternion @@ -414,9 +324,7 @@ template class Quaternion { * @f] * @see isNormalized(), dot(const Quaternion&, const Quaternion&) */ - inline T dot() const { - return dot(*this, *this); - } + T dot() const { return dot(*this, *this); } /** * @brief %Quaternion length @@ -427,18 +335,14 @@ template class Quaternion { * @f] * @see isNormalized() */ - inline T length() const { - return std::sqrt(dot()); - } + T length() const { return std::sqrt(dot()); } /** * @brief Normalized quaternion (of unit length) * * @see isNormalized() */ - inline Quaternion normalized() const { - return (*this)/length(); - } + Quaternion normalized() const { return (*this)/length(); } /** * @brief Conjugated quaternion @@ -447,9 +351,7 @@ template class Quaternion { * q^* = [-\boldsymbol q_V, q_S] * @f] */ - inline Quaternion conjugated() const { - return {-_vector, _scalar}; - } + Quaternion conjugated() const { return {-_vector, _scalar}; } /** * @brief Inverted quaternion @@ -459,9 +361,7 @@ template class Quaternion { * q^{-1} = \frac{q^*}{|q|^2} = \frac{q^*}{q \cdot q} * @f] */ - inline Quaternion inverted() const { - return conjugated()/dot(); - } + Quaternion inverted() const { return conjugated()/dot(); } /** * @brief Inverted normalized quaternion @@ -472,12 +372,7 @@ template class Quaternion { * @f] * @see isNormalized(), inverted() */ - inline Quaternion invertedNormalized() const { - CORRADE_ASSERT(isNormalized(), - "Math::Quaternion::invertedNormalized(): quaternion must be normalized", - Quaternion({}, std::numeric_limits::quiet_NaN())); - return conjugated(); - } + Quaternion invertedNormalized() const; /** * @brief Rotate vector with quaternion @@ -489,7 +384,7 @@ template class Quaternion { * @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(), * DualQuaternion::transformPoint(), Complex::transformVector() */ - inline Vector3 transformVector(const Vector3& vector) const { + Vector3 transformVector(const Vector3& vector) const { return ((*this)*Quaternion(vector)*inverted()).vector(); } @@ -503,21 +398,16 @@ template class Quaternion { * @see isNormalized(), Quaternion(const Vector3&), vector(), Matrix4::transformVector(), * DualQuaternion::transformPointNormalized(), Complex::transformVector() */ - inline Vector3 transformVectorNormalized(const Vector3& vector) const { - CORRADE_ASSERT(isNormalized(), - "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized", - Vector3(std::numeric_limits::quiet_NaN())); - return ((*this)*Quaternion(vector)*conjugated()).vector(); - } + Vector3 transformVectorNormalized(const Vector3& vector) const; private: /* Used to avoid including Functions.h */ - inline constexpr static T pow2(T value) { + constexpr static T pow2(T value) { return value*value; } /* Used in angle() and slerp() (no assertions) */ - inline static T angleInternal(const Quaternion& normalizedA, const Quaternion& normalizedB) { + static T angleInternal(const Quaternion& normalizedA, const Quaternion& normalizedB) { return std::acos(dot(normalizedA, normalizedB)); } @@ -563,6 +453,116 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit #endif #endif +namespace Implementation { + +/* No assertions fired, for internal use. Not private member because used from + outside the class. */ +template Quaternion quaternionFromMatrix(const Matrix<3, T>& m) { + const Vector<3, T> diagonal = m.diagonal(); + const T trace = diagonal.sum(); + + /* Diagonal is positive */ + if(trace > T(0)) { + const T s = std::sqrt(trace + T(1)); + const T t = T(0.5)/s; + return {Vector3(m[1][2] - m[2][1], + m[2][0] - m[0][2], + m[0][1] - m[1][0])*t, s*T(0.5)}; + } + + /* Diagonal is negative */ + std::size_t i = 0; + if(diagonal[1] > diagonal[0]) i = 1; + if(diagonal[2] > diagonal[i]) i = 2; + + const std::size_t j = (i + 1) % 3; + const std::size_t k = (i + 2) % 3; + + const T s = std::sqrt(diagonal[i] - diagonal[j] - diagonal[k] + T(1)); + const T t = (s == T(0) ? T(0) : T(0.5)/s); + + Vector3 vec; + vec[i] = s*T(0.5); + vec[j] = (m[i][j] + m[j][i])*t; + vec[k] = (m[i][k] + m[k][i])*t; + + return {vec, (m[j][k] - m[k][j])*t}; +} + +} + +template inline Rad Quaternion::angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::Quaternion::angle(): quaternions must be normalized", Rad(std::numeric_limits::quiet_NaN())); + return Rad(angleInternal(normalizedA, normalizedB)); +} + +template inline Quaternion Quaternion::lerp(const Quaternion& normalizedA, const Quaternion& normalizedB, const T t) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::Quaternion::lerp(): quaternions must be normalized", Quaternion({}, std::numeric_limits::quiet_NaN())); + return ((T(1) - t)*normalizedA + t*normalizedB).normalized(); +} + +template inline Quaternion Quaternion::slerp(const Quaternion& normalizedA, const Quaternion& normalizedB, const T t) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::Quaternion::slerp(): quaternions must be normalized", Quaternion({}, std::numeric_limits::quiet_NaN())); + const T a = angleInternal(normalizedA, normalizedB); + return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a); +} + +template inline Quaternion Quaternion::rotation(const Rad angle, const Vector3& normalizedAxis) { + CORRADE_ASSERT(normalizedAxis.isNormalized(), + "Math::Quaternion::rotation(): axis must be normalized", {}); + return {normalizedAxis*std::sin(angle.toUnderlyingType()/2), std::cos(angle.toUnderlyingType()/2)}; +} + +template inline Quaternion Quaternion::fromMatrix(const Matrix<3, T>& matrix) { + CORRADE_ASSERT(matrix.isOrthogonal(), "Math::Quaternion::fromMatrix(): the matrix is not orthogonal", {}); + return Implementation::quaternionFromMatrix(matrix); +} + +template inline Rad Quaternion::angle() const { + CORRADE_ASSERT(isNormalized(), "Math::Quaternion::angle(): quaternion must be normalized", + Rad(std::numeric_limits::quiet_NaN())); + return Rad(T(2)*std::acos(_scalar)); +} + +template inline Vector3 Quaternion::axis() const { + CORRADE_ASSERT(isNormalized(), "Math::Quaternion::axis(): quaternion must be normalized", {}); + return _vector/std::sqrt(1-pow2(_scalar)); +} + +template Matrix<3, T> Quaternion::toMatrix() const { + return { + Vector<3, T>(T(1) - 2*pow2(_vector.y()) - 2*pow2(_vector.z()), + 2*_vector.x()*_vector.y() + 2*_vector.z()*_scalar, + 2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar), + Vector<3, T>(2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar, + T(1) - 2*pow2(_vector.x()) - 2*pow2(_vector.z()), + 2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar), + Vector<3, T>(2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar, + 2*_vector.y()*_vector.z() - 2*_vector.x()*_scalar, + T(1) - 2*pow2(_vector.x()) - 2*pow2(_vector.y())) + }; +} + +template inline Quaternion Quaternion::operator*(const Quaternion& other) const { + return {_scalar*other._vector + other._scalar*_vector + Vector3::cross(_vector, other._vector), + _scalar*other._scalar - Vector3::dot(_vector, other._vector)}; +} + +template inline Quaternion Quaternion::invertedNormalized() const { + CORRADE_ASSERT(isNormalized(), "Math::Quaternion::invertedNormalized(): quaternion must be normalized", + Quaternion({}, std::numeric_limits::quiet_NaN())); + return conjugated(); +} + +template inline Vector3 Quaternion::transformVectorNormalized(const Vector3< T >& vector) const { + CORRADE_ASSERT(isNormalized(), "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized", + Vector3(std::numeric_limits::quiet_NaN())); + return ((*this)*Quaternion(vector)*conjugated()).vector(); +} + }} #endif diff --git a/src/Math/RectangularMatrix.cpp b/src/Math/RectangularMatrix.cpp deleted file mode 100644 index 7fcd9a6c7..000000000 --- a/src/Math/RectangularMatrix.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "RectangularMatrix.h" - -namespace Magnum { namespace Math { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 2, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 3, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 4, Float>&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 2, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 3, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 4, Double>&); -#endif - -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 3, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 2, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 4, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 2, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 4, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 3, Float>&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 3, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 2, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 4, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 2, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 4, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 3, Double>&); -#endif -#endif - -}} - -namespace Corrade { namespace Utility { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#ifndef MAGNUM_TARGET_GLES -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#endif - -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#ifndef MAGNUM_TARGET_GLES -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#endif -#endif - -}} diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index a2d4f944f..6bc335b16 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -32,6 +32,10 @@ namespace Magnum { namespace Math { +namespace Implementation { + template struct RectangularMatrixConverter; +} + /** @brief Rectangular matrix @tparam cols Column count @@ -73,11 +77,11 @@ template class RectangularMatrix { * @attention Use with caution, the function doesn't check whether the * array is long enough. */ - inline constexpr static RectangularMatrix& from(T* data) { + constexpr static RectangularMatrix& from(T* data) { return *reinterpret_cast*>(data); } /** @overload */ - inline constexpr static const RectangularMatrix& from(const T* data) { + constexpr static const RectangularMatrix& from(const T* data) { return *reinterpret_cast*>(data); } @@ -87,14 +91,7 @@ template class RectangularMatrix { * @see diagonal() * @todo make this constexpr */ - inline static RectangularMatrix fromDiagonal(const Vector& diagonal) { - RectangularMatrix out; - - for(std::size_t i = 0; i != DiagonalSize; ++i) - out[i][i] = diagonal[i]; - - return out; - } + static RectangularMatrix fromDiagonal(const Vector& diagonal); /** * @brief Construct matrix from vector @@ -103,12 +100,12 @@ template class RectangularMatrix { * vector will make first column of resulting matrix. * @see toVector() */ - inline static RectangularMatrix fromVector(const Vector& vector) { + static RectangularMatrix fromVector(const Vector& vector) { return *reinterpret_cast*>(vector.data()); } /** @brief Construct zero-filled matrix */ - inline constexpr /*implicit*/ RectangularMatrix() {} + constexpr /*implicit*/ RectangularMatrix() {} /** * @brief Construct matrix from column vectors @@ -118,9 +115,9 @@ template class RectangularMatrix { * @todo Creating matrix from arbitrary combination of matrices with n rows */ #ifndef CORRADE_GCC45_COMPATIBILITY - template inline constexpr /*implicit*/ RectangularMatrix(const Vector& first, const U&... next): _data{first, next...} { + template constexpr /*implicit*/ RectangularMatrix(const Vector& first, const U&... next): _data{first, next...} { #else - template inline /*implicit*/ RectangularMatrix(const Vector& first, const U&... next): _data() { + template /*implicit*/ RectangularMatrix(const Vector& first, const U&... next): _data() { constructInternal({first, next...}); #endif static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to RectangularMatrix constructor"); @@ -138,18 +135,33 @@ template class RectangularMatrix { * @endcode */ #ifndef CORRADE_GCC46_COMPATIBILITY - template inline constexpr explicit RectangularMatrix(const RectangularMatrix& other): RectangularMatrix(typename Implementation::GenerateSequence::Type(), other) {} + template constexpr explicit RectangularMatrix(const RectangularMatrix& other): RectangularMatrix(typename Implementation::GenerateSequence::Type(), other) {} #else - template inline explicit RectangularMatrix(const RectangularMatrix& other) { + template explicit RectangularMatrix(const RectangularMatrix& other) { *this = RectangularMatrix(typename Implementation::GenerateSequence::Type(), other); } #endif + /** @brief Construct matrix from external representation */ + #ifndef CORRADE_GCC46_COMPATIBILITY + template::from(std::declval()))> constexpr explicit RectangularMatrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter::from(other)) {} + #else + template::from(std::declval()))> explicit RectangularMatrix(const U& other) { + *this = Implementation::RectangularMatrixConverter::from(other); + } + #endif + /** @brief Copy constructor */ - inline constexpr RectangularMatrix(const RectangularMatrix&) = default; + constexpr RectangularMatrix(const RectangularMatrix&) = default; /** @brief Assignment operator */ - inline RectangularMatrix& operator=(const RectangularMatrix&) = default; + RectangularMatrix& operator=(const RectangularMatrix&) = default; + + /** @brief Convert matrix to external representation */ + template::to(std::declval>()))> constexpr explicit operator U() const { + /** @bug Why this is not constexpr under GCC 4.6? */ + return Implementation::RectangularMatrixConverter::to(*this); + } /** * @brief Raw data @@ -158,8 +170,8 @@ template class RectangularMatrix { * * @see operator[] */ - inline T* data() { return _data[0].data(); } - inline constexpr const T* data() const { return _data[0].data(); } /**< @overload */ + T* data() { return _data[0].data(); } + constexpr const T* data() const { return _data[0].data(); } /**< @overload */ /** * @brief %Matrix column @@ -172,13 +184,8 @@ template class RectangularMatrix { * * @see row(), data() */ - inline Vector& operator[](std::size_t col) { - return _data[col]; - } - /** @overload */ - inline constexpr const Vector& operator[](std::size_t col) const { - return _data[col]; - } + Vector& operator[](std::size_t col) { return _data[col]; } + constexpr const Vector& operator[](std::size_t col) const { return _data[col]; } /**< @overload */ /** * @brief %Matrix row @@ -187,17 +194,10 @@ template class RectangularMatrix { * is slower than accessing columns due to the way the matrix is stored. * @see operator[]() */ - inline Vector row(std::size_t row) const { - Vector out; - - for(std::size_t i = 0; i != cols; ++i) - out[i] = _data[i][row]; - - return out; - } + Vector row(std::size_t row) const; /** @brief Equality comparison */ - inline bool operator==(const RectangularMatrix& other) const { + bool operator==(const RectangularMatrix& other) const { for(std::size_t i = 0; i != cols; ++i) if(_data[i] != other._data[i]) return false; @@ -210,10 +210,19 @@ template class RectangularMatrix { * @see Vector::operator<(), Vector::operator<=(), Vector::operator>=(), * Vector::operator>() */ - inline bool operator!=(const RectangularMatrix& other) const { + bool operator!=(const RectangularMatrix& other) const { return !operator==(other); } + /** + * @brief Negated matrix + * + * The computation is done column-wise. @f[ + * \boldsymbol B_j = -\boldsymbol A_j + * @f] + */ + RectangularMatrix operator-() const; + /** * @brief Add and assign matrix * @@ -233,26 +242,10 @@ template class RectangularMatrix { * * @see operator+=() */ - inline RectangularMatrix operator+(const RectangularMatrix& other) const { + RectangularMatrix operator+(const RectangularMatrix& other) const { return RectangularMatrix(*this)+=other; } - /** - * @brief Negated matrix - * - * The computation is done column-wise in-place. @f[ - * \boldsymbol A_j = -\boldsymbol A_j - * @f] - */ - RectangularMatrix operator-() const { - RectangularMatrix out; - - for(std::size_t i = 0; i != cols; ++i) - out._data[i] = -_data[i]; - - return out; - } - /** * @brief Subtract and assign matrix * @@ -272,7 +265,7 @@ template class RectangularMatrix { * * @see operator-=() */ - inline RectangularMatrix operator-(const RectangularMatrix& other) const { + RectangularMatrix operator-(const RectangularMatrix& other) const { return RectangularMatrix(*this)-=other; } @@ -302,7 +295,7 @@ template class RectangularMatrix { #ifndef DOXYGEN_GENERATING_OUTPUT template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number) const { #else - template inline RectangularMatrix operator*(U number) const { + template RectangularMatrix operator*(U number) const { #endif return RectangularMatrix(*this)*=number; } @@ -333,7 +326,7 @@ template class RectangularMatrix { #ifndef DOXYGEN_GENERATING_OUTPUT template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number) const { #else - template inline RectangularMatrix operator/(U number) const { + template RectangularMatrix operator/(U number) const { #endif return RectangularMatrix(*this)/=number; } @@ -345,16 +338,7 @@ template class RectangularMatrix { * (\boldsymbol {AB})_{ji} = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol B_{jk} * @f] */ - template RectangularMatrix operator*(const RectangularMatrix& other) const { - RectangularMatrix out; - - for(std::size_t col = 0; col != size; ++col) - for(std::size_t row = 0; row != rows; ++row) - for(std::size_t pos = 0; pos != cols; ++pos) - out[col][row] += _data[pos][row]*other._data[col][pos]; - - return out; - } + template RectangularMatrix operator*(const RectangularMatrix& other) const; /** * @brief Multiply vector @@ -373,29 +357,15 @@ template class RectangularMatrix { * * @see row() */ - RectangularMatrix transposed() const { - RectangularMatrix out; - - for(std::size_t col = 0; col != cols; ++col) - for(std::size_t row = 0; row != rows; ++row) - out[row][col] = _data[col][row]; - - return out; - } + RectangularMatrix transposed() const; /** * @brief Values on diagonal * * @see fromDiagonal() + * @todo constexpr */ - Vector diagonal() const { - Vector out; - - for(std::size_t i = 0; i != DiagonalSize; ++i) - out[i] = _data[i][i]; - - return out; - } + Vector diagonal() const; /** * @brief Convert matrix to vector @@ -406,23 +376,23 @@ template class RectangularMatrix { * summing the elements etc.). * @see fromVector() */ - inline Vector toVector() const { + Vector toVector() const { return *reinterpret_cast*>(data()); } private: /* Implementation for RectangularMatrix::RectangularMatrix(const RectangularMatrix&) */ #ifndef CORRADE_GCC45_COMPATIBILITY - template inline constexpr explicit RectangularMatrix(Implementation::Sequence, const RectangularMatrix& matrix): _data{Vector(matrix[sequence])...} {} + template constexpr explicit RectangularMatrix(Implementation::Sequence, const RectangularMatrix& matrix): _data{Vector(matrix[sequence])...} {} #else - template inline explicit RectangularMatrix(Implementation::Sequence, const RectangularMatrix& matrix): _data() { + template explicit RectangularMatrix(Implementation::Sequence, const RectangularMatrix& matrix): _data() { constructInternal({Vector(matrix[sequence])...}); } #endif #ifdef CORRADE_GCC45_COMPATIBILITY /* GCC < 4.6 workaround for "error: bad array initializer" */ - inline void constructInternal(std::initializer_list> data) { + void constructInternal(std::initializer_list> data) { for(std::size_t i = 0; i != data.size(); ++i) _data[i] = *(data.begin() + i); } @@ -453,9 +423,9 @@ The computation is done column-wise. @f[ @see RectangularMatrix::operator/(U) const */ #ifdef DOXYGEN_GENERATING_OUTPUT -template RectangularMatrix operator/(U number, const RectangularMatrix& matrix) { +template inline RectangularMatrix operator/(U number, const RectangularMatrix& matrix) { #else -template typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { +template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { #endif RectangularMatrix out; @@ -522,51 +492,108 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit #endif #define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \ - inline constexpr static __VA_ARGS__& from(T* data) { \ + constexpr static __VA_ARGS__& from(T* data) { \ return *reinterpret_cast<__VA_ARGS__*>(data); \ } \ - inline constexpr static const __VA_ARGS__& from(const T* data) { \ + constexpr static const __VA_ARGS__& from(const T* data) { \ return *reinterpret_cast(data); \ } \ \ - inline __VA_ARGS__& operator=(const Math::RectangularMatrix& other) { \ + __VA_ARGS__& operator=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator=(other); \ return *this; \ } \ \ - inline __VA_ARGS__ operator-() const { \ + __VA_ARGS__ operator-() const { \ return Math::RectangularMatrix::operator-(); \ } \ - inline __VA_ARGS__& operator+=(const Math::RectangularMatrix& other) { \ + __VA_ARGS__& operator+=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator+=(other); \ return *this; \ } \ - inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ + __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ return Math::RectangularMatrix::operator+(other); \ } \ - inline __VA_ARGS__& operator-=(const Math::RectangularMatrix& other) { \ + __VA_ARGS__& operator-=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator-=(other); \ return *this; \ } \ - inline __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ + __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ return Math::RectangularMatrix::operator-(other); \ } \ - template inline typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ + template typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ - template inline typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ + template typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ return Math::RectangularMatrix::operator*(number); \ } \ - template inline typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ + template typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ Math::RectangularMatrix::operator/=(number); \ return *this; \ } \ - template inline typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ + template typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ return Math::RectangularMatrix::operator/(number); \ } #endif +template inline RectangularMatrix RectangularMatrix::fromDiagonal(const Vector& diagonal) { + RectangularMatrix out; + + for(std::size_t i = 0; i != DiagonalSize; ++i) + out[i][i] = diagonal[i]; + + return out; +} + +template inline Vector RectangularMatrix::row(std::size_t row) const { + Vector out; + + for(std::size_t i = 0; i != cols; ++i) + out[i] = _data[i][row]; + + return out; +} + +template inline RectangularMatrix RectangularMatrix::operator-() const { + RectangularMatrix out; + + for(std::size_t i = 0; i != cols; ++i) + out._data[i] = -_data[i]; + + return out; +} + +template template inline RectangularMatrix RectangularMatrix::operator*(const RectangularMatrix& other) const { + RectangularMatrix out; + + for(std::size_t col = 0; col != size; ++col) + for(std::size_t row = 0; row != rows; ++row) + for(std::size_t pos = 0; pos != cols; ++pos) + out[col][row] += _data[pos][row]*other._data[col][pos]; + + return out; +} + +template inline RectangularMatrix RectangularMatrix::transposed() const { + RectangularMatrix out; + + for(std::size_t col = 0; col != cols; ++col) + for(std::size_t row = 0; row != rows; ++row) + out[row][col] = _data[col][row]; + + return out; +} + +template auto RectangularMatrix::diagonal() const -> Vector { + Vector out; + + for(std::size_t i = 0; i != DiagonalSize; ++i) + out[i] = _data[i][i]; + + return out; +} + }} namespace Corrade { namespace Utility { diff --git a/src/Math/Swizzle.h b/src/Math/Swizzle.h index a36234206..1ac9746b3 100644 --- a/src/Math/Swizzle.h +++ b/src/Math/Swizzle.h @@ -32,12 +32,11 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct ComponentAtPosition { static_assert(size > position, "Swizzle parameter out of range of base vector"); - template inline constexpr static T value(const Math::Vector& vector) { return vector[position]; } + template constexpr static T value(const Math::Vector& vector) { return vector[position]; } }; template struct Component {}; @@ -46,13 +45,12 @@ namespace Implementation { template struct Component: public ComponentAtPosition {}; template struct Component: public ComponentAtPosition {}; template struct Component { - template inline constexpr static T value(const Math::Vector&) { return T(0); } + template constexpr static T value(const Math::Vector&) { return T(0); } }; template struct Component { - template inline constexpr static T value(const Math::Vector&) { return T(1); } + template constexpr static T value(const Math::Vector&) { return T(1); } }; } -#endif /** @brief Swizzle Vector components @@ -74,7 +72,7 @@ present in this lightweight implementation for Math namespace. @see @ref matrix-vector-component-access, Vector4::xyz(), Vector4::xy(), Vector3::xy() */ -template inline constexpr Vector swizzle(const Vector& vector) { +template constexpr Vector swizzle(const Vector& vector) { return {Implementation::Component::value(vector)...}; } diff --git a/src/Math/Test/FunctionsTest.cpp b/src/Math/Test/FunctionsTest.cpp index 25e519f92..3f48d5ff3 100644 --- a/src/Math/Test/FunctionsTest.cpp +++ b/src/Math/Test/FunctionsTest.cpp @@ -34,7 +34,9 @@ class FunctionsTest: public Corrade::TestSuite::Tester { FunctionsTest(); void min(); + void minList(); void max(); + void maxList(); void sign(); void abs(); void sqrt(); @@ -68,7 +70,9 @@ typedef Math::Vector3 Vector3i; FunctionsTest::FunctionsTest() { addTests({&FunctionsTest::min, + &FunctionsTest::minList, &FunctionsTest::max, + &FunctionsTest::maxList, &FunctionsTest::sign, &FunctionsTest::abs, &FunctionsTest::sqrt, @@ -97,11 +101,25 @@ void FunctionsTest::min() { CORRADE_COMPARE(Math::min(Vector3i(5, -3, 2), Vector3i(9, -5, 18)), Vector3i(5, -5, 2)); } +void FunctionsTest::minList() { + CORRADE_COMPARE(Math::min({5, -2, 9}), -2); + CORRADE_COMPARE(Math::min({Vector3i(5, -3, 2), + Vector3i(-2, 14, 7), + Vector3i(9, -5, 18)}), Vector3i(-2, -5, 2)); +} + void FunctionsTest::max() { CORRADE_COMPARE(Math::max(5, 9), 9); CORRADE_COMPARE(Math::max(Vector3i(5, -3, 2), Vector3i(9, -5, 18)), Vector3i(9, -3, 18)); } +void FunctionsTest::maxList() { + CORRADE_COMPARE(Math::max({5, -2, 9}), 9); + CORRADE_COMPARE(Math::max({Vector3i(5, -3, 2), + Vector3i(-2, 14, 7), + Vector3i(9, -5, 18)}), Vector3i(9, 14, 18)); +} + void FunctionsTest::sign() { CORRADE_COMPARE(Math::sign(3516), 1); CORRADE_COMPARE(Math::sign(0.0f), 0.0f); diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index 5ff187c9a..7546434ca 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -28,7 +28,32 @@ #include "Math/Matrix3.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat3 { + float a[9]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<3, 3, float, Mat3> { + constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) { + return RectangularMatrix<3, 3, Float>( + Vector<3, Float>(other.a[0], other.a[1], other.a[2]), + Vector<3, Float>(other.a[3], other.a[4], other.a[5]), + Vector<3, Float>(other.a[6], other.a[7], other.a[8])); + } + + constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) { + return Mat3{{other[0][0], other[0][1], other[0][2], + other[1][0], other[1][1], other[1][2], + other[2][0], other[2][1], other[2][2]}}; + } +}; + +} + +namespace Test { class Matrix3Test: public Corrade::TestSuite::Tester { public: @@ -40,6 +65,8 @@ class Matrix3Test: public Corrade::TestSuite::Tester { void constructConversion(); void constructCopy(); + void convert(); + void isRigidTransformation(); void translation(); @@ -62,6 +89,7 @@ typedef Math::Deg Deg; typedef Math::Matrix3 Matrix3; typedef Math::Matrix3 Matrix3i; typedef Math::Matrix<2, Float> Matrix2; +typedef Math::Vector3 Vector3; typedef Math::Vector2 Vector2; Matrix3Test::Matrix3Test() { @@ -71,6 +99,8 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::constructConversion, &Matrix3Test::constructCopy, + &Matrix3Test::convert, + &Matrix3Test::isRigidTransformation, &Matrix3Test::translation, @@ -150,6 +180,29 @@ void Matrix3Test::constructCopy() { {7.9f, -1.0f, 8.0f})); } +void Matrix3Test::convert() { + constexpr Mat3 a{{1.5f, 2.0f, -3.5f, + 2.0f, -3.1f, 0.4f, + 9.5f, -1.5f, 0.1f}}; + constexpr Matrix3 b(Vector3(1.5f, 2.0f, -3.5f), + Vector3(2.0f, -3.1f, 0.4f), + Vector3(9.5f, -1.5f, 0.1f)); + + constexpr Matrix3 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat3 d(b); + for(std::size_t i = 0; i != 9; ++i) + CORRADE_COMPARE(d.a[0], a.a[0]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void Matrix3Test::isRigidTransformation() { CORRADE_VERIFY(!Matrix3({1.0f, 0.0f, 0.0f}, {0.1f, 1.0f, 0.0f}, diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index a00d5c781..d5bbfa70b 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -28,7 +28,34 @@ #include "Math/Matrix4.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat4 { + float a[16]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<4, 4, float, Mat4> { + constexpr static RectangularMatrix<4, 4, Float> from(const Mat4& other) { + return RectangularMatrix<4, 4, Float>( + Vector<4, Float>(other.a[0], other.a[1], other.a[2], other.a[3]), + Vector<4, Float>(other.a[4], other.a[5], other.a[6], other.a[7]), + Vector<4, Float>(other.a[8], other.a[9], other.a[10], other.a[11]), + Vector<4, Float>(other.a[12], other.a[13], other.a[14], other.a[15])); + } + + constexpr static Mat4 to(const RectangularMatrix<4, 4, Float>& other) { + return Mat4{{other[0][0], other[0][1], other[0][2], other[0][3], + other[1][0], other[1][1], other[1][2], other[1][3], + other[2][0], other[2][1], other[2][2], other[2][3], + other[3][0], other[3][1], other[3][2], other[3][3]}}; + } +}; + +} + +namespace Test { class Matrix4Test: public Corrade::TestSuite::Tester { public: @@ -40,6 +67,8 @@ class Matrix4Test: public Corrade::TestSuite::Tester { void constructConversion(); void constructCopy(); + void convert(); + void isRigidTransformation(); void translation(); @@ -77,6 +106,8 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::constructConversion, &Matrix4Test::constructCopy, + &Matrix4Test::convert, + &Matrix4Test::isRigidTransformation, &Matrix4Test::translation, @@ -171,6 +202,31 @@ void Matrix4Test::constructCopy() { {7.9f, -1.0f, 8.0f, -1.5f})); } +void Matrix4Test::convert() { + constexpr Mat4 a{{3.0f, 5.0f, 8.0f, -3.0f, + 4.5f, 4.0f, 7.0f, 2.0f, + 1.0f, 2.0f, 3.0f, -1.0f, + 7.9f, -1.0f, 8.0f, -1.5f}}; + constexpr Matrix4 b({3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}); + + constexpr Matrix4 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat4 d(b); + for(std::size_t i = 0; i != 16; ++i) + CORRADE_COMPARE(d.a[i], a.a[i]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void Matrix4Test::isRigidTransformation() { CORRADE_VERIFY(!Matrix4({1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index 92061d41d..9dfa54457 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -28,7 +28,32 @@ #include "Math/Matrix.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat3 { + float a[9]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<3, 3, float, Mat3> { + constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) { + return RectangularMatrix<3, 3, Float>( + Vector<3, Float>(other.a[0], other.a[1], other.a[2]), + Vector<3, Float>(other.a[3], other.a[4], other.a[5]), + Vector<3, Float>(other.a[6], other.a[7], other.a[8])); + } + + constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) { + return Mat3{{other[0][0], other[0][1], other[0][2], + other[1][0], other[1][1], other[1][2], + other[2][0], other[2][1], other[2][2]}}; + } +}; + +} + +namespace Test { class MatrixTest: public Corrade::TestSuite::Tester { public: @@ -40,6 +65,8 @@ class MatrixTest: public Corrade::TestSuite::Tester { void constructConversion(); void constructCopy(); + void convert(); + void isOrthogonal(); void trace(); @@ -67,6 +94,8 @@ MatrixTest::MatrixTest() { &MatrixTest::constructConversion, &MatrixTest::constructCopy, + &MatrixTest::convert, + &MatrixTest::isOrthogonal, &MatrixTest::trace, @@ -149,6 +178,29 @@ void MatrixTest::constructCopy() { Vector4(7.9f, -1.0f, 8.0f, -1.5f))); } +void MatrixTest::convert() { + constexpr Mat3 a{{1.5f, 2.0f, -3.5f, + 2.0f, -3.1f, 0.4f, + 9.5f, -1.5f, 0.1f}}; + constexpr Matrix3 b(Vector3(1.5f, 2.0f, -3.5f), + Vector3(2.0f, -3.1f, 0.4f), + Vector3(9.5f, -1.5f, 0.1f)); + + constexpr Matrix3 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat3 d(b); + for(std::size_t i = 0; i != 9; ++i) + CORRADE_COMPARE(d.a[i], a.a[i]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void MatrixTest::isOrthogonal() { CORRADE_VERIFY(!Matrix3(Vector3(1.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f), diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index ab25a608c..1062015b9 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -28,7 +28,30 @@ #include "Math/RectangularMatrix.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat2x3 { + float a[6]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<2, 3, float, Mat2x3> { + constexpr static RectangularMatrix<2, 3, Float> from(const Mat2x3& other) { + return RectangularMatrix<2, 3, Float>( + Vector<3, Float>(other.a[0], other.a[1], other.a[2]), + Vector<3, Float>(other.a[3], other.a[4], other.a[5])); + } + + constexpr static Mat2x3 to(const RectangularMatrix<2, 3, Float>& other) { + return Mat2x3{{other[0][0], other[0][1], other[0][2], + other[1][0], other[1][1], other[1][2]}}; + } +}; + +} + +namespace Test { class RectangularMatrixTest: public Corrade::TestSuite::Tester { public: @@ -41,6 +64,7 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void constructFromDiagonal(); void constructCopy(); + void convert(); void data(); void row(); @@ -77,6 +101,7 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::constructFromDiagonal, &RectangularMatrixTest::constructCopy, + &RectangularMatrixTest::convert, &RectangularMatrixTest::data, &RectangularMatrixTest::row, @@ -168,6 +193,31 @@ void RectangularMatrixTest::constructCopy() { Vector4(9.0f, 10.0f, 11.0f, 12.0f))); } +void RectangularMatrixTest::convert() { + typedef RectangularMatrix<2, 3, Float> Matrix2x3; + constexpr Mat2x3 a{{1.5f, 2.0f, -3.5f, + 2.0f, -3.1f, 0.4f}}; + constexpr Matrix2x3 b(Vector3(1.5f, 2.0f, -3.5f), + Vector3(2.0f, -3.1f, 0.4f)); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Matrix2x3 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat2x3 d(b); + for(std::size_t i = 0; i != 5; ++i) + CORRADE_COMPARE(d.a[i], a.a[i]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void RectangularMatrixTest::data() { Matrix3x4 m; Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); diff --git a/src/Math/Test/Vector2Test.cpp b/src/Math/Test/Vector2Test.cpp index 6364b2e71..5dd0ee28d 100644 --- a/src/Math/Test/Vector2Test.cpp +++ b/src/Math/Test/Vector2Test.cpp @@ -37,11 +37,11 @@ namespace Magnum { namespace Math { namespace Implementation { template<> struct VectorConverter<2, float, Vec2> { - inline constexpr static Vector<2, float> from(const Vec2& other) { + constexpr static Vector<2, float> from(const Vec2& other) { return {other.x, other.y}; } - inline constexpr static Vec2 to(const Vector<2, float>& other) { + constexpr static Vec2 to(const Vector<2, float>& other) { return {other[0], other[1]}; } }; diff --git a/src/Math/Test/Vector3Test.cpp b/src/Math/Test/Vector3Test.cpp index 5cf8ffd32..fdd68abb0 100644 --- a/src/Math/Test/Vector3Test.cpp +++ b/src/Math/Test/Vector3Test.cpp @@ -37,11 +37,11 @@ namespace Magnum { namespace Math { namespace Implementation { template<> struct VectorConverter<3, float, Vec3> { - inline constexpr static Vector<3, Float> from(const Vec3& other) { + constexpr static Vector<3, Float> from(const Vec3& other) { return {other.x, other.y, other.z}; } - inline constexpr static Vec3 to(const Vector<3, Float>& other) { + constexpr static Vec3 to(const Vector<3, Float>& other) { return {other[0], other[1], other[2]}; } }; diff --git a/src/Math/Test/Vector4Test.cpp b/src/Math/Test/Vector4Test.cpp index 98617f9c1..059e936d1 100644 --- a/src/Math/Test/Vector4Test.cpp +++ b/src/Math/Test/Vector4Test.cpp @@ -37,11 +37,11 @@ namespace Magnum { namespace Math { namespace Implementation { template<> struct VectorConverter<4, float, Vec4> { - inline constexpr static Vector<4, Float> from(const Vec4& other) { + constexpr static Vector<4, Float> from(const Vec4& other) { return {other.x, other.y, other.z, other.w}; } - inline constexpr static Vec4 to(const Vector<4, Float>& other) { + constexpr static Vec4 to(const Vector<4, Float>& other) { return {other[0], other[1], other[2], other[3]}; } }; diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 4fa7e93ae..9feddec5b 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -37,11 +37,11 @@ namespace Magnum { namespace Math { namespace Implementation { template<> struct VectorConverter<3, float, Vec3> { - inline constexpr static Vector<3, Float> from(const Vec3& other) { + constexpr static Vector<3, Float> from(const Vec3& other) { return {other.x, other.y, other.z}; } - inline constexpr static Vec3 to(const Vector<3, Float>& other) { + constexpr static Vec3 to(const Vector<3, Float>& other) { return {other[0], other[1], other[2]}; } }; @@ -80,6 +80,7 @@ class VectorTest: public Corrade::TestSuite::Tester { void length(); void lengthInverted(); void normalized(); + void resized(); void sum(); void product(); @@ -126,6 +127,7 @@ VectorTest::VectorTest() { &VectorTest::length, &VectorTest::lengthInverted, &VectorTest::normalized, + &VectorTest::resized, &VectorTest::sum, &VectorTest::product, @@ -322,7 +324,15 @@ void VectorTest::lengthInverted() { } void VectorTest::normalized() { - CORRADE_COMPARE(Vector4(1.0f, 1.0f, 1.0f, 1.0f).normalized(), Vector4(0.5f, 0.5f, 0.5f, 0.5f)); + const auto vec = Vector4(1.0f, 1.0f, 1.0f, 1.0f).normalized(); + CORRADE_COMPARE(vec, Vector4(0.5f, 0.5f, 0.5f, 0.5f)); + CORRADE_COMPARE(vec.length(), 1.0f); +} + +void VectorTest::resized() { + const auto vec = Vector4(2.0f, 2.0f, 0.0f, 1.0f).resized(9.0f); + CORRADE_COMPARE(vec, Vector4(6.0f, 6.0f, 0.0f, 3.0f)); + CORRADE_COMPARE(vec.length(), 9.0f); } void VectorTest::sum() { diff --git a/src/Math/TypeTraits.h b/src/Math/TypeTraits.h index 1904036ee..130bae4a7 100644 --- a/src/Math/TypeTraits.h +++ b/src/Math/TypeTraits.h @@ -53,17 +53,15 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct TypeTraitsDefault { TypeTraitsDefault() = delete; - inline constexpr static bool equals(T a, T b) { + constexpr static bool equals(T a, T b) { return a == b; } }; } -#endif /** @brief Traits class for numeric types @@ -96,7 +94,7 @@ template struct TypeTraits: Implementation::TypeTraitsDefault { * inequal. Returns 1 for integer types and reasonably small value for * floating-point types. Not implemented for arbitrary types. */ - inline constexpr static T epsilon(); + constexpr static T epsilon(); /** * @brief Fuzzy compare @@ -116,14 +114,14 @@ template struct TypeTraits: Implementation::TypeTraitsDefault { * http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */ -#ifndef DOXYGEN_GENERATING_OUTPUT /* Integral scalar types */ namespace Implementation { template struct TypeTraitsIntegral: TypeTraitsDefault { - inline constexpr static T epsilon() { return T(1); } + constexpr static T epsilon() { return T(1); } }; } +#ifndef DOXYGEN_GENERATING_OUTPUT template<> struct TypeTraits: Implementation::TypeTraitsIntegral { typedef Float FloatingPointType; }; @@ -162,7 +160,7 @@ namespace Implementation { template struct TypeTraitsFloatingPoint { TypeTraitsFloatingPoint() = delete; - inline static bool equals(T a, T b) { + static bool equals(T a, T b) { return std::abs(a - b) < TypeTraits::epsilon(); } }; @@ -171,19 +169,19 @@ namespace Implementation { template<> struct TypeTraits: Implementation::TypeTraitsFloatingPoint { typedef Float FloatingPointType; - inline constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; } + constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; } }; #ifndef MAGNUM_TARGET_GLES template<> struct TypeTraits: Implementation::TypeTraitsFloatingPoint { typedef Double FloatingPointType; - inline constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; } + constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; } }; #endif template<> struct TypeTraits: Implementation::TypeTraitsFloatingPoint { typedef long double FloatingPointType; - inline constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; } + constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; } }; /* Comparing squared length to 1 is not sufficient to compare within range diff --git a/src/Math/Unit.h b/src/Math/Unit.h index 9e6a8746b..ab2449ecb 100644 --- a/src/Math/Unit.h +++ b/src/Math/Unit.h @@ -45,103 +45,103 @@ template class Derived, class T> class Unit { typedef T Type; /**< @brief Underlying data type */ /** @brief Default constructor */ - inline constexpr /*implicit*/ Unit(): value(T(0)) {} + constexpr /*implicit*/ Unit(): value(T(0)) {} /** @brief Explicit conversion from unitless type */ - inline constexpr explicit Unit(T value): value(value) {} + constexpr explicit Unit(T value): value(value) {} /** @brief Construct from another underlying type */ - template inline constexpr explicit Unit(Unit value): value(value.value) {} + template constexpr explicit Unit(Unit value): value(value.value) {} /** @brief Explicit conversion to underlying type */ - inline constexpr T toUnderlyingType() const { return value; } + constexpr T toUnderlyingType() const { return value; } /** @brief Explicit conversion to underlying type */ #ifndef CORRADE_GCC44_COMPATIBILITY - inline constexpr explicit operator T() const { return value; } + constexpr explicit operator T() const { return value; } #endif /** @brief Equality comparison */ - inline constexpr bool operator==(Unit other) const { + constexpr bool operator==(Unit other) const { return TypeTraits::equals(value, other.value); } /** @brief Non-equality comparison */ - inline constexpr bool operator!=(Unit other) const { + constexpr bool operator!=(Unit other) const { return !operator==(other); } /** @brief Less than comparison */ - inline constexpr bool operator<(Unit other) const { + constexpr bool operator<(Unit other) const { return value < other.value; } /** @brief Greater than comparison */ - inline constexpr bool operator>(Unit other) const { + constexpr bool operator>(Unit other) const { return value > other.value; } /** @brief Less than or equal comparison */ - inline constexpr bool operator<=(Unit other) const { + constexpr bool operator<=(Unit other) const { return !operator>(other); } /** @brief Greater than or equal comparison */ - inline constexpr bool operator>=(Unit other) const { + constexpr bool operator>=(Unit other) const { return !operator<(other); } /** @brief Negated value */ - inline constexpr Unit operator-() const { + constexpr Unit operator-() const { return Unit(-value); } /** @brief Add and assign value */ - inline Unit& operator+=(Unit other) { + Unit& operator+=(Unit other) { value += other.value; return *this; } /** @brief Add value */ - inline constexpr Unit operator+(Unit other) const { + constexpr Unit operator+(Unit other) const { return Unit(value + other.value); } /** @brief Subtract and assign value */ - inline Unit& operator-=(Unit other) { + Unit& operator-=(Unit other) { value -= other.value; return *this; } /** @brief Subtract value */ - inline constexpr Unit operator-(Unit other) const { + constexpr Unit operator-(Unit other) const { return Unit(value - other.value); } /** @brief Multiply with number and assign */ - inline Unit& operator*=(T number) { + Unit& operator*=(T number) { value *= number; return *this; } /** @brief Multiply with number */ - inline constexpr Unit operator*(T number) const { + constexpr Unit operator*(T number) const { return Unit(value*number); } /** @brief Divide with number and assign */ - inline Unit& operator/=(T number) { + Unit& operator/=(T number) { value /= number; return *this; } /** @brief Divide with number */ - inline constexpr Unit operator/(T number) const { + constexpr Unit operator/(T number) const { return Unit(value/number); } /** @brief Ratio of two values */ - inline constexpr T operator/(Unit other) const { + constexpr T operator/(Unit other) const { return value/other.value; } @@ -152,7 +152,7 @@ template class Derived, class T> class Unit { /** @relates Unit @brief Multiply number with value */ -template class Derived, class T> inline constexpr Unit operator*(typename std::common_type::type number, const Unit& value) { +template class Derived, class T> constexpr Unit operator*(typename std::common_type::type number, const Unit& value) { return value*number; } diff --git a/src/Math/Vector.cpp b/src/Math/Vector.cpp deleted file mode 100644 index 615eeba28..000000000 --- a/src/Math/Vector.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "Vector.h" - -namespace Magnum { namespace Math { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<2, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<3, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<4, Float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<2, Int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<3, Int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<4, Int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<2, UnsignedInt>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<3, UnsignedInt>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<4, UnsignedInt>&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<2, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<3, Double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<4, Double>&); -#endif -#endif - -}} - -namespace Corrade { namespace Utility { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#ifndef MAGNUM_TARGET_GLES -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#endif -#endif - -}} - diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 2796af1cd..086336a81 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -42,11 +42,9 @@ namespace Magnum { namespace Math { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct VectorConverter; } -#endif /** @brief %Vector @@ -73,11 +71,11 @@ template class Vector { * @attention Use with caution, the function doesn't check whether the * array is long enough. */ - inline constexpr static Vector& from(T* data) { + constexpr static Vector& from(T* data) { return *reinterpret_cast*>(data); } /** @overload */ - inline constexpr static const Vector& from(const T* data) { + constexpr static const Vector& from(const T* data) { return *reinterpret_cast*>(data); } @@ -91,7 +89,7 @@ template class Vector { * @f] * @see dot() const, operator-(), Vector2::perpendicular() */ - inline static T dot(const Vector& a, const Vector& b) { + static T dot(const Vector& a, const Vector& b) { return (a*b).sum(); } @@ -103,11 +101,7 @@ template class Vector { * @f] * @see isNormalized(), Quaternion::angle(), Complex::angle() */ - inline static Rad angle(const Vector& normalizedA, const Vector& normalizedB) { - CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), - "Math::Vector::angle(): vectors must be normalized", Rad(std::numeric_limits::quiet_NaN())); - return Rad(std::acos(dot(normalizedA, normalizedB))); - } + static Rad angle(const Vector& normalizedA, const Vector& normalizedB); /** * @brief Default constructor @@ -116,7 +110,7 @@ template class Vector { * \boldsymbol v = \boldsymbol 0 * @f] */ - inline constexpr /*implicit*/ Vector(): _data() {} + constexpr /*implicit*/ Vector(): _data() {} /** @todo Creating Vector from combination of vector and scalar types */ @@ -126,19 +120,19 @@ template class Vector { * @param next Next values */ #ifdef DOXYGEN_GENERATING_OUTPUT - template inline constexpr /*implicit*/ Vector(T first, U... next); + template constexpr /*implicit*/ Vector(T first, U... next); #else - template::type> inline constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} {} + template::type> constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} {} #endif /** @brief Construct vector with one value for all fields */ #ifdef DOXYGEN_GENERATING_OUTPUT - inline explicit Vector(T value); + constexpr explicit Vector(T value); #else #ifndef CORRADE_GCC46_COMPATIBILITY - template::value && size != 1, T>::type> inline constexpr explicit Vector(U value): Vector(typename Implementation::GenerateSequence::Type(), value) {} + template::value && size != 1, T>::type> constexpr explicit Vector(U value): Vector(typename Implementation::GenerateSequence::Type(), value) {} #else - template::value && size != 1, T>::type> inline explicit Vector(U value) { + template::value && size != 1, T>::type> explicit Vector(U value) { *this = Vector(typename Implementation::GenerateSequence::Type(), value); } #endif @@ -156,37 +150,37 @@ template class Vector { * @endcode */ #ifndef CORRADE_GCC46_COMPATIBILITY - template inline constexpr explicit Vector(const Vector& other): Vector(typename Implementation::GenerateSequence::Type(), other) {} + template constexpr explicit Vector(const Vector& other): Vector(typename Implementation::GenerateSequence::Type(), other) {} #else - template inline explicit Vector(const Vector& other) { + template explicit Vector(const Vector& other) { *this = Vector(typename Implementation::GenerateSequence::Type(), other); } #endif /** @brief Construct vector from external representation */ #ifndef CORRADE_GCC46_COMPATIBILITY - template::from(std::declval()))> inline constexpr explicit Vector(const U& other): Vector(Implementation::VectorConverter::from(other)) {} + template::from(std::declval()))> constexpr explicit Vector(const U& other): Vector(Implementation::VectorConverter::from(other)) {} #else #ifndef CORRADE_GCC44_COMPATIBILITY - template::from(std::declval()))> inline explicit Vector(const U& other) { + template::from(std::declval()))> explicit Vector(const U& other) { #else - template::from(*static_cast(nullptr)))> inline explicit Vector(const U& other) { + template::from(*static_cast(nullptr)))> explicit Vector(const U& other) { #endif *this = Implementation::VectorConverter::from(other); } #endif /** @brief Copy constructor */ - inline constexpr Vector(const Vector&) = default; + constexpr Vector(const Vector&) = default; /** @brief Assignment operator */ - inline Vector& operator=(const Vector&) = default; + Vector& operator=(const Vector&) = default; /** @brief Convert vector to external representation */ #ifndef CORRADE_GCC44_COMPATIBILITY - template::to(std::declval>()))> inline constexpr explicit operator U() const { + template::to(std::declval>()))> constexpr explicit operator U() const { #else - template::to(*static_cast*>(nullptr)))> inline constexpr operator U() const { + template::to(*static_cast*>(nullptr)))> constexpr operator U() const { #endif /** @bug Why this is not constexpr under GCC 4.6? */ return Implementation::VectorConverter::to(*this); @@ -198,19 +192,19 @@ template class Vector { * * @see operator[]() */ - inline T* data() { return _data; } - inline constexpr const T* data() const { return _data; } /**< @overload */ + T* data() { return _data; } + constexpr const T* data() const { return _data; } /**< @overload */ /** * @brief Value at given position * * @see data() */ - inline T& operator[](std::size_t pos) { return _data[pos]; } - inline constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ + T& operator[](std::size_t pos) { return _data[pos]; } + constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ /** @brief Equality comparison */ - inline bool operator==(const Vector& other) const { + bool operator==(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) if(!TypeTraits::equals(_data[i], other._data[i])) return false; @@ -218,49 +212,21 @@ template class Vector { } /** @brief Non-equality comparison */ - inline bool operator!=(const Vector& other) const { + bool operator!=(const Vector& other) const { return !operator==(other); } /** @brief Component-wise less than */ - inline BoolVector operator<(const Vector& other) const { - BoolVector out; - - for(std::size_t i = 0; i != size; ++i) - out.set(i, _data[i] < other._data[i]); - - return out; - } + BoolVector operator<(const Vector& other) const; /** @brief Component-wise less than or equal */ - inline BoolVector operator<=(const Vector& other) const { - BoolVector out; - - for(std::size_t i = 0; i != size; ++i) - out.set(i, _data[i] <= other._data[i]); - - return out; - } + BoolVector operator<=(const Vector& other) const; /** @brief Component-wise greater than or equal */ - inline BoolVector operator>=(const Vector& other) const { - BoolVector out; - - for(std::size_t i = 0; i != size; ++i) - out.set(i, _data[i] >= other._data[i]); - - return out; - } + BoolVector operator>=(const Vector& other) const; /** @brief Component-wise greater than */ - inline BoolVector operator>(const Vector& other) const { - BoolVector out; - - for(std::size_t i = 0; i != size; ++i) - out.set(i, _data[i] > other._data[i]); - - return out; - } + BoolVector operator>(const Vector& other) const; /** * @brief Whether the vector is normalized @@ -270,26 +236,19 @@ template class Vector { * @f] * @see dot(), normalized() */ - inline bool isNormalized() const { + bool isNormalized() const { return Implementation::isNormalizedSquared(dot()); } /** * @brief Negated vector * - * The computation is done in-place. @f[ - * \boldsymbol a_i = -\boldsymbol a_i + * @f[ + * \boldsymbol b_i = -\boldsymbol a_i * @f] * @see Vector2::perpendicular() */ - Vector operator-() const { - Vector out; - - for(std::size_t i = 0; i != size; ++i) - out._data[i] = -_data[i]; - - return out; - } + Vector operator-() const; /** * @brief Add and assign vector @@ -310,7 +269,7 @@ template class Vector { * * @see operator+=(), sum() */ - inline Vector operator+(const Vector& other) const { + Vector operator+(const Vector& other) const { return Vector(*this) += other; } @@ -333,7 +292,7 @@ template class Vector { * * @see operator-=() */ - inline Vector operator-(const Vector& other) const { + Vector operator-(const Vector& other) const { return Vector(*this) -= other; } @@ -347,7 +306,7 @@ template class Vector { #ifdef DOXYGEN_GENERATING_OUTPUT template Vector& operator*=(U number) { #else - template inline typename std::enable_if::value, Vector&>::type operator*=(U number) { + template typename std::enable_if::value, Vector&>::type operator*=(U number) { #endif for(std::size_t i = 0; i != size; ++i) _data[i] *= number; @@ -361,9 +320,9 @@ template class Vector { * @see operator*=(U), operator*(U, const Vector&) */ #ifdef DOXYGEN_GENERATING_OUTPUT - template inline Vector operator*(U number) const { + template Vector operator*(U number) const { #else - template inline typename std::enable_if::value, Vector>::type operator*(U number) const { + template typename std::enable_if::value, Vector>::type operator*(U number) const { #endif return Vector(*this) *= number; } @@ -378,7 +337,7 @@ template class Vector { #ifdef DOXYGEN_GENERATING_OUTPUT template Vector& operator/=(U number) { #else - template inline typename std::enable_if::value, Vector&>::type operator/=(U number) { + template typename std::enable_if::value, Vector&>::type operator/=(U number) { #endif for(std::size_t i = 0; i != size; ++i) _data[i] /= number; @@ -392,9 +351,9 @@ template class Vector { * @see operator/=(), operator/(U, const Vector&) */ #ifdef DOXYGEN_GENERATING_OUTPUT - template inline Vector operator/(U number) const { + template Vector operator/(U number) const { #else - template inline typename std::enable_if::value, Vector>::type operator/(U number) const { + template typename std::enable_if::value, Vector>::type operator/(U number) const { #endif return Vector(*this) /= number; } @@ -418,7 +377,7 @@ template class Vector { * * @see operator*=(const Vector&), product() */ - template inline Vector operator*(const Vector& other) const { + template Vector operator*(const Vector& other) const { return Vector(*this) *= other; } @@ -441,7 +400,7 @@ template class Vector { * * @see operator/=(const Vector&) */ - template inline Vector operator/(const Vector& other) const { + template Vector operator/(const Vector& other) const { return Vector(*this) /= other; } @@ -454,9 +413,7 @@ template class Vector { * @f] * @see dot(const Vector&, const Vector&), isNormalized() */ - inline T dot() const { - return dot(*this, *this); - } + T dot() const { return dot(*this, *this); } /** * @brief %Vector length @@ -465,12 +422,10 @@ template class Vector { * values. @f[ * |\boldsymbol a| = \sqrt{\boldsymbol a \cdot \boldsymbol a} * @f] - * @see lengthInverted(), Math::sqrt(), normalized() + * @see lengthInverted(), Math::sqrt(), normalized(), resized() * @todo something like std::hypot() for possibly better precision? */ - inline T length() const { - return std::sqrt(dot()); - } + T length() const { return std::sqrt(dot()); } /** * @brief Inverse vector length @@ -478,19 +433,30 @@ template class Vector { * @f[ * \frac{1}{|\boldsymbol a|} = \frac{1}{\sqrt{\boldsymbol a \cdot \boldsymbol a}} * @f] - * @see length(), Math::sqrtInverted(), normalized() + * @see length(), Math::sqrtInverted(), normalized(), resized() */ - inline T lengthInverted() const { - return T(1)/length(); - } + T lengthInverted() const { return T(1)/length(); } /** * @brief Normalized vector (of unit length) * - * @see isNormalized() + * @see isNormalized(), lengthInverted(), resized() */ - inline Vector normalized() const { - return *this*lengthInverted(); + Vector normalized() const { return *this*lengthInverted(); } + + /** + * @brief Resized vector + * + * Convenience equivalent to the following code. Due to operation order + * this function is faster than the obvious way of sizing normalized() + * vector. + * @code + * vec*(vec.lengthInverted()*length) // the brackets are important + * @endcode + * @see normalized() + */ + Vector resized(T length) const { + return *this*(lengthInverted()*length); } /** @@ -501,7 +467,7 @@ template class Vector { * @f] * @see dot(), projectedOntoNormalized() */ - inline Vector projected(const Vector& line) const { + Vector projected(const Vector& line) const { return line*dot(*this, line)/line.dot(); } @@ -515,73 +481,42 @@ template class Vector { * @f] * @see dot() */ - inline Vector projectedOntoNormalized(const Vector& line) const { - CORRADE_ASSERT(line.isNormalized(), "Math::Vector::projectedOntoNormalized(): line must be normalized", (Vector(std::numeric_limits::quiet_NaN()))); - return line*dot(*this, line); - } + Vector projectedOntoNormalized(const Vector& line) const; /** * @brief Sum of values in the vector * * @see operator+() */ - T sum() const { - T out(_data[0]); - - for(std::size_t i = 1; i != size; ++i) - out += _data[i]; - - return out; - } + T sum() const; /** * @brief Product of values in the vector * * @see operator*(const Vector&) */ - T product() const { - T out(_data[0]); - - for(std::size_t i = 1; i != size; ++i) - out *= _data[i]; - - return out; - } + T product() const; /** * @brief Minimal value in the vector * * @see Math::min() */ - T min() const { - T out(_data[0]); - - for(std::size_t i = 1; i != size; ++i) - out = std::min(out, _data[i]); - - return out; - } + T min() const; /** * @brief Maximal value in the vector * * @see Math::max() */ - T max() const { - T out(_data[0]); - - for(std::size_t i = 1; i != size; ++i) - out = std::max(out, _data[i]); - - return out; - } + T max() const; private: /* Implementation for Vector::Vector(const Vector&) */ - template inline constexpr explicit Vector(Implementation::Sequence, const Vector& vector): _data{T(vector._data[sequence])...} {} + template constexpr explicit Vector(Implementation::Sequence, const Vector& vector): _data{T(vector._data[sequence])...} {} /* Implementation for Vector::Vector(U) */ - template inline constexpr explicit Vector(Implementation::Sequence, T value): _data{Implementation::repeat(value, sequence)...} {} + template constexpr explicit Vector(Implementation::Sequence, T value): _data{Implementation::repeat(value, sequence)...} {} T _data[size]; }; @@ -653,66 +588,71 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Type, size) \ - inline constexpr static Type& from(T* data) { \ + constexpr static Type& from(T* data) { \ return *reinterpret_cast*>(data); \ } \ - inline constexpr static const Type& from(const T* data) { \ + constexpr static const Type& from(const T* data) { \ return *reinterpret_cast*>(data); \ } \ \ - inline Type& operator=(const Type& other) { \ + Type& operator=(const Type& other) { \ Math::Vector::operator=(other); \ return *this; \ } \ \ - inline Type operator-() const { \ + Type operator-() const { \ return Math::Vector::operator-(); \ } \ - inline Type& operator+=(const Math::Vector& other) { \ + Type& operator+=(const Math::Vector& other) { \ Math::Vector::operator+=(other); \ return *this; \ } \ - inline Type operator+(const Math::Vector& other) const { \ + Type operator+(const Math::Vector& other) const { \ return Math::Vector::operator+(other); \ } \ - inline Type& operator-=(const Math::Vector& other) { \ + Type& operator-=(const Math::Vector& other) { \ Math::Vector::operator-=(other); \ return *this; \ } \ - inline Type operator-(const Math::Vector& other) const { \ + Type operator-(const Math::Vector& other) const { \ return Math::Vector::operator-(other); \ } \ - template inline typename std::enable_if::value, Type&>::type operator*=(U number) { \ + template typename std::enable_if::value, Type&>::type operator*=(U number) { \ Math::Vector::operator*=(number); \ return *this; \ } \ - template inline typename std::enable_if::value, Type>::type operator*(U number) const { \ + template typename std::enable_if::value, Type>::type operator*(U number) const { \ return Math::Vector::operator*(number); \ } \ - template inline typename std::enable_if::value, Type&>::type operator/=(U number) { \ + template typename std::enable_if::value, Type&>::type operator/=(U number) { \ Math::Vector::operator/=(number); \ return *this; \ } \ - template inline typename std::enable_if::value, Type>::type operator/(U number) const { \ + template typename std::enable_if::value, Type>::type operator/(U number) const { \ return Math::Vector::operator/(number); \ } \ - template inline Type& operator*=(const Math::Vector& other) { \ + template Type& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ - template inline Type operator*(const Math::Vector& other) const { \ + template Type operator*(const Math::Vector& other) const { \ return Math::Vector::operator*(other); \ } \ - template inline Type& operator/=(const Math::Vector& other) { \ + template Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ } \ - template inline Type operator/(const Math::Vector& other) const { \ + template Type operator/(const Math::Vector& other) const { \ return Math::Vector::operator/(other); \ } \ \ - inline Type normalized() const { return Math::Vector::normalized(); } \ - inline Type projected(const Math::Vector& other) const { \ + Type normalized() const { \ + return Math::Vector::normalized(); \ + } \ + Type resized(T length) const { \ + return Math::Vector::resized(length); \ + } \ + Type projected(const Math::Vector& other) const { \ return Math::Vector::projected(other); \ } @@ -725,6 +665,99 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit } #endif +template inline Rad Vector::angle(const Vector& normalizedA, const Vector& normalizedB) { + CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), + "Math::Vector::angle(): vectors must be normalized", Rad(std::numeric_limits::quiet_NaN())); + return Rad(std::acos(dot(normalizedA, normalizedB))); +} + +template inline BoolVector Vector::operator<(const Vector& other) const { + BoolVector out; + + for(std::size_t i = 0; i != size; ++i) + out.set(i, _data[i] < other._data[i]); + + return out; +} + +template inline BoolVector Vector::operator<=(const Vector& other) const { + BoolVector out; + + for(std::size_t i = 0; i != size; ++i) + out.set(i, _data[i] <= other._data[i]); + + return out; +} + +template inline BoolVector Vector::operator>=(const Vector& other) const { + BoolVector out; + + for(std::size_t i = 0; i != size; ++i) + out.set(i, _data[i] >= other._data[i]); + + return out; +} + +template inline BoolVector Vector::operator>(const Vector& other) const { + BoolVector out; + + for(std::size_t i = 0; i != size; ++i) + out.set(i, _data[i] > other._data[i]); + + return out; +} + +template inline Vector Vector::operator-() const { + Vector out; + + for(std::size_t i = 0; i != size; ++i) + out._data[i] = -_data[i]; + + return out; +} + +template inline Vector Vector::projectedOntoNormalized(const Vector& line) const { + CORRADE_ASSERT(line.isNormalized(), "Math::Vector::projectedOntoNormalized(): line must be normalized", + (Vector(std::numeric_limits::quiet_NaN()))); + return line*dot(*this, line); +} + +template inline T Vector::sum() const { + T out(_data[0]); + + for(std::size_t i = 1; i != size; ++i) + out += _data[i]; + + return out; +} + +template inline T Vector::product() const { + T out(_data[0]); + + for(std::size_t i = 1; i != size; ++i) + out *= _data[i]; + + return out; +} + +template inline T Vector::min() const { + T out(_data[0]); + + for(std::size_t i = 1; i != size; ++i) + out = std::min(out, _data[i]); + + return out; +} + +template inline T Vector::max() const { + T out(_data[0]); + + for(std::size_t i = 1; i != size; ++i) + out = std::max(out, _data[i]); + + return out; +} + }} namespace Corrade { namespace Utility { diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index a503b0dfa..fd885aa02 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -51,7 +51,7 @@ template class Vector2: public Vector<2, T> { * @endcode * @see yAxis(), xScale(), Matrix3::right() */ - inline constexpr static Vector2 xAxis(T length = T(1)) { return Vector2(length, T()); } + constexpr static Vector2 xAxis(T length = T(1)) { return Vector2(length, T()); } /** * @brief %Vector in direction of Y axis (up) @@ -59,7 +59,7 @@ template class Vector2: public Vector<2, T> { * See xAxis() for more information. * @see yScale(), Matrix3::up() */ - inline constexpr static Vector2 yAxis(T length = T(1)) { return Vector2(T(), length); } + constexpr static Vector2 yAxis(T length = T(1)) { return Vector2(T(), length); } /** * @brief Scaling vector in direction of X axis (width) @@ -70,7 +70,7 @@ template class Vector2: public Vector<2, T> { * @endcode * @see yScale(), xAxis() */ - inline constexpr static Vector2 xScale(T scale) { return Vector2(scale, T(1)); } + constexpr static Vector2 xScale(T scale) { return Vector2(scale, T(1)); } /** * @brief Scaling vector in direction of Y axis (height) @@ -78,7 +78,7 @@ template class Vector2: public Vector<2, T> { * See xScale() for more information. * @see yAxis() */ - inline constexpr static Vector2 yScale(T scale) { return Vector2(T(1), scale); } + constexpr static Vector2 yScale(T scale) { return Vector2(T(1), scale); } /** * @brief 2D cross product @@ -87,19 +87,19 @@ template class Vector2: public Vector<2, T> { * equivalent to calling Vector3::cross() with Z coordinate set to `0` * and extracting only Z coordinate from the result (X and Y * coordinates are always zero). @f[ - * \boldsymbol a \times \boldsymbol b = \boldsymbol a_\perp \cdot \boldsymbol b = a_xb_y - a_yb_x + * \boldsymbol a \times \boldsymbol b = \boldsymbol a_\bot \cdot \boldsymbol b = a_xb_y - a_yb_x * @f] * @see perpendicular(), dot(const Vector&, const Vector&) */ - inline static T cross(const Vector2& a, const Vector2& b) { + static T cross(const Vector2& a, const Vector2& b) { return Vector<2, T>::dot(a.perpendicular(), b); } /** @copydoc Vector::Vector() */ - inline constexpr /*implicit*/ Vector2() {} + constexpr /*implicit*/ Vector2() {} /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector2(T value): Vector<2, T>(value) {} + constexpr explicit Vector2(T value): Vector<2, T>(value) {} /** * @brief Constructor @@ -108,35 +108,35 @@ template class Vector2: public Vector<2, T> { * \boldsymbol v = \begin{pmatrix} x \\ y \end{pmatrix} * @f] */ - inline constexpr /*implicit*/ Vector2(T x, T y): Vector<2, T>(x, y) {} + constexpr /*implicit*/ Vector2(T x, T y): Vector<2, T>(x, y) {} /** @copydoc Vector::Vector(const Vector&) */ - template inline constexpr explicit Vector2(const Vector<2, U>& other): Vector<2, T>(other) {} + template constexpr explicit Vector2(const Vector<2, U>& other): Vector<2, T>(other) {} /** @brief Construct vector from external representation */ #ifndef CORRADE_GCC44_COMPATIBILITY - template::from(std::declval()))> inline constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {} + template::from(std::declval()))> constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {} #else - template::from(*static_cast(nullptr)))> inline constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {} + template::from(*static_cast(nullptr)))> constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {} #endif /** @brief Copy constructor */ - inline constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {} + constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {} - inline T& x() { return (*this)[0]; } /**< @brief X component */ - inline constexpr T x() const { return (*this)[0]; } /**< @overload */ - inline T& y() { return (*this)[1]; } /**< @brief Y component */ - inline constexpr T y() const { return (*this)[1]; } /**< @overload */ + T& x() { return (*this)[0]; } /**< @brief X component */ + constexpr T x() const { return (*this)[0]; } /**< @overload */ + T& y() { return (*this)[1]; } /**< @brief Y component */ + constexpr T y() const { return (*this)[1]; } /**< @overload */ /** * @brief Perpendicular vector * * Returns vector rotated 90° counterclockwise. @f[ - * \boldsymbol v_\perp = \begin{pmatrix} -v_y \\ v_x \end{pmatrix} + * \boldsymbol v_\bot = \begin{pmatrix} -v_y \\ v_x \end{pmatrix} * @f] * @see cross(), dot(const Vector&, const Vector&), operator-() const */ - inline Vector2 perpendicular() const { return {-y(), x()}; } + Vector2 perpendicular() const { return {-y(), x()}; } MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2) }; diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index e936efb8c..f9ce2e5f9 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -53,7 +53,7 @@ template class Vector3: public Vector<3, T> { * @endcode * @see yAxis(), zAxis(), xScale(), Matrix4::right() */ - inline constexpr static Vector3 xAxis(T length = T(1)) { return Vector3(length, T(), T()); } + constexpr static Vector3 xAxis(T length = T(1)) { return Vector3(length, T(), T()); } /** * @brief %Vector in direction of Y axis (up) @@ -61,7 +61,7 @@ template class Vector3: public Vector<3, T> { * See xAxis() for more information. * @see yScale(), Matrix4::up() */ - inline constexpr static Vector3 yAxis(T length = T(1)) { return Vector3(T(), length, T()); } + constexpr static Vector3 yAxis(T length = T(1)) { return Vector3(T(), length, T()); } /** * @brief %Vector in direction of Z axis (backward) @@ -69,7 +69,7 @@ template class Vector3: public Vector<3, T> { * See xAxis() for more information. * @see zScale(), Matrix4::backward() */ - inline constexpr static Vector3 zAxis(T length = T(1)) { return Vector3(T(), T(), length); } + constexpr static Vector3 zAxis(T length = T(1)) { return Vector3(T(), T(), length); } /** * @brief Scaling vector in direction of X axis (width) @@ -80,7 +80,7 @@ template class Vector3: public Vector<3, T> { * @endcode * @see yScale(), zScale(), xAxis() */ - inline constexpr static Vector3 xScale(T scale) { return Vector3(scale, T(1), T(1)); } + constexpr static Vector3 xScale(T scale) { return Vector3(scale, T(1), T(1)); } /** * @brief Scaling vector in direction of Y axis (height) @@ -88,7 +88,7 @@ template class Vector3: public Vector<3, T> { * See xScale() for more information. * @see yAxis() */ - inline constexpr static Vector3 yScale(T scale) { return Vector3(T(1), scale, T(1)); } + constexpr static Vector3 yScale(T scale) { return Vector3(T(1), scale, T(1)); } /** * @brief Scaling vector in direction of Z axis (depth) @@ -96,7 +96,7 @@ template class Vector3: public Vector<3, T> { * See xScale() for more information. * @see zAxis() */ - inline constexpr static Vector3 zScale(T scale) { return Vector3(T(1), T(1), scale); } + constexpr static Vector3 zScale(T scale) { return Vector3(T(1), T(1), scale); } /** * @brief Cross product @@ -107,16 +107,16 @@ template class Vector3: public Vector<3, T> { * @f] * @see Vector2::cross() */ - inline static Vector3 cross(const Vector3& a, const Vector3& b) { + static Vector3 cross(const Vector3& a, const Vector3& b) { return swizzle<'y', 'z', 'x'>(a)*swizzle<'z', 'x', 'y'>(b) - swizzle<'z', 'x', 'y'>(a)*swizzle<'y', 'z', 'x'>(b); } /** @copydoc Vector::Vector() */ - inline constexpr /*implicit*/ Vector3() {} + constexpr /*implicit*/ Vector3() {} /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector3(T value): Vector<3, T>(value) {} + constexpr explicit Vector3(T value): Vector<3, T>(value) {} /** * @brief Constructor @@ -125,7 +125,7 @@ template class Vector3: public Vector<3, T> { * \boldsymbol v = \begin{pmatrix} x \\ y \\ z \end{pmatrix} * @f] */ - inline constexpr /*implicit*/ Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {} + constexpr /*implicit*/ Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {} /** * @brief Constructor @@ -134,27 +134,27 @@ template class Vector3: public Vector<3, T> { * \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ z \end{pmatrix} * @f] */ - inline constexpr /*implicit*/ Vector3(const Vector2& xy, T z): Vector<3, T>(xy[0], xy[1], z) {} + constexpr /*implicit*/ Vector3(const Vector2& xy, T z): Vector<3, T>(xy[0], xy[1], z) {} /** @copydoc Vector::Vector(const Vector&) */ - template inline constexpr explicit Vector3(const Vector<3, U>& other): Vector<3, T>(other) {} + template constexpr explicit Vector3(const Vector<3, U>& other): Vector<3, T>(other) {} /** @brief Construct vector from external representation */ #ifndef CORRADE_GCC44_COMPATIBILITY - template::from(std::declval()))> inline constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {} + template::from(std::declval()))> constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {} #else - template::from(*static_cast(nullptr)))> inline constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {} + template::from(*static_cast(nullptr)))> constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {} #endif /** @brief Copy constructor */ - inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {} + constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {} - inline T& x() { return (*this)[0]; } /**< @brief X component */ - inline constexpr T x() const { return (*this)[0]; } /**< @overload */ - inline T& y() { return (*this)[1]; } /**< @brief Y component */ - inline constexpr T y() const { return (*this)[1]; } /**< @overload */ - inline T& z() { return (*this)[2]; } /**< @brief Z component */ - inline constexpr T z() const { return (*this)[2]; } /**< @overload */ + T& x() { return (*this)[0]; } /**< @brief X component */ + constexpr T x() const { return (*this)[0]; } /**< @overload */ + T& y() { return (*this)[1]; } /**< @brief Y component */ + constexpr T y() const { return (*this)[1]; } /**< @overload */ + T& z() { return (*this)[2]; } /**< @brief Z component */ + constexpr T z() const { return (*this)[2]; } /**< @overload */ /** * @brief XY part of the vector @@ -162,8 +162,8 @@ template class Vector3: public Vector<3, T> { * * @see swizzle() */ - inline Vector2& xy() { return Vector2::from(Vector<3, T>::data()); } - inline constexpr const Vector2 xy() const { return {x(), y()}; } /**< @overload */ + Vector2& xy() { return Vector2::from(Vector<3, T>::data()); } + constexpr const Vector2 xy() const { return {x(), y()}; } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) }; diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index a54e9372a..cd7ea5b07 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -43,10 +43,10 @@ See @ref matrix-vector for brief introduction. template class Vector4: public Vector<4, T> { public: /** @copydoc Vector::Vector() */ - inline constexpr /*implicit*/ Vector4() {} + constexpr /*implicit*/ Vector4() {} /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector4(T value): Vector<4, T>(value) {} + constexpr explicit Vector4(T value): Vector<4, T>(value) {} /** * @brief Constructor @@ -55,7 +55,7 @@ template class Vector4: public Vector<4, T> { * \boldsymbol v = \begin{pmatrix} x \\ y \\ z \\ w \end{pmatrix} * @f] */ - inline constexpr /*implicit*/ Vector4(T x, T y, T z, T w): Vector<4, T>(x, y, z, w) {} + constexpr /*implicit*/ Vector4(T x, T y, T z, T w): Vector<4, T>(x, y, z, w) {} /** * @brief Constructor @@ -64,29 +64,29 @@ template class Vector4: public Vector<4, T> { * \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ v_z \\ w \end{pmatrix} * @f] */ - inline constexpr /*implicit*/ Vector4(const Vector3& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {} + constexpr /*implicit*/ Vector4(const Vector3& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {} /** @copydoc Vector::Vector(const Vector&) */ - template inline constexpr explicit Vector4(const Vector<4, U>& other): Vector<4, T>(other) {} + template constexpr explicit Vector4(const Vector<4, U>& other): Vector<4, T>(other) {} /** @brief Construct vector from external representation */ #ifndef CORRADE_GCC44_COMPATIBILITY - template::from(std::declval()))> inline constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {} + template::from(std::declval()))> constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {} #else - template::from(*static_cast(nullptr)))> inline constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {} + template::from(*static_cast(nullptr)))> constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {} #endif /** @brief Copy constructor */ - inline constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {} + constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {} - inline T& x() { return (*this)[0]; } /**< @brief X component */ - inline constexpr T x() const { return (*this)[0]; } /**< @overload */ - inline T& y() { return (*this)[1]; } /**< @brief Y component */ - inline constexpr T y() const { return (*this)[1]; } /**< @overload */ - inline T& z() { return (*this)[2]; } /**< @brief Z component */ - inline constexpr T z() const { return (*this)[2]; } /**< @overload */ - inline T& w() { return (*this)[3]; } /**< @brief W component */ - inline constexpr T w() const { return (*this)[3]; } /**< @overload */ + T& x() { return (*this)[0]; } /**< @brief X component */ + constexpr T x() const { return (*this)[0]; } /**< @overload */ + T& y() { return (*this)[1]; } /**< @brief Y component */ + constexpr T y() const { return (*this)[1]; } /**< @overload */ + T& z() { return (*this)[2]; } /**< @brief Z component */ + constexpr T z() const { return (*this)[2]; } /**< @overload */ + T& w() { return (*this)[3]; } /**< @brief W component */ + constexpr T w() const { return (*this)[3]; } /**< @overload */ /** * @brief XYZ part of the vector @@ -94,8 +94,8 @@ template class Vector4: public Vector<4, T> { * * @see swizzle() */ - inline Vector3& xyz() { return Vector3::from(Vector<4, T>::data()); } - inline constexpr const Vector3 xyz() const { return {x(), y(), z()}; } /**< @overload */ + Vector3& xyz() { return Vector3::from(Vector<4, T>::data()); } + constexpr const Vector3 xyz() const { return {x(), y(), z()}; } /**< @overload */ /** * @brief XY part of the vector @@ -103,8 +103,8 @@ template class Vector4: public Vector<4, T> { * * @see swizzle() */ - inline Vector2& xy() { return Vector2::from(Vector<4, T>::data()); } - inline constexpr const Vector2 xy() const { return {x(), y()}; } /**< @overload */ + Vector2& xy() { return Vector2::from(Vector<4, T>::data()); } + constexpr const Vector2 xy() const { return {x(), y()}; } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) }; diff --git a/src/Math/instantiation.cpp b/src/Math/instantiation.cpp new file mode 100644 index 000000000..99a20d760 --- /dev/null +++ b/src/Math/instantiation.cpp @@ -0,0 +1,144 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Math/DualComplex.h" +#include "Math/DualQuaternion.h" + +namespace Corrade { namespace Utility { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#endif + +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#endif + +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#endif +#endif + +}} + +namespace Magnum { namespace Math { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Complex&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Complex&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualComplex&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualComplex&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualQuaternion&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const DualQuaternion&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quaternion&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quaternion&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, Float>&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, Double>&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, Float>&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, Double>&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); +#endif + +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<2, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<3, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<4, Float>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<2, Int>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<3, Int>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<4, Int>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<2, UnsignedInt>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<3, UnsignedInt>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<4, UnsignedInt>&); +#ifndef MAGNUM_TARGET_GLES +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<2, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<3, Double>&); +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Vector<4, Double>&); +#endif +#endif + +}} + diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 19c8cee0e..6ab0159d8 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -343,12 +343,21 @@ Debug operator<<(Debug debug, Mesh::Primitive value) { switch(value) { #define _c(value) case Mesh::Primitive::value: return debug << "Mesh::Primitive::" #value; _c(Points) - _c(Lines) _c(LineStrip) _c(LineLoop) - _c(Triangles) + _c(Lines) + #ifndef MAGNUM_TARGET_GLES + _c(LineStripAdjacency) + _c(LinesAdjacency) + #endif _c(TriangleStrip) _c(TriangleFan) + _c(Triangles) + #ifndef MAGNUM_TARGET_GLES + _c(TriangleStripAdjacency) + _c(TrianglesAdjacency) + _c(Patches) + #endif #undef _c } @@ -376,12 +385,21 @@ std::string ConfigurationValue::toString(Magnum::Mesh:: switch(value) { #define _c(value) case Magnum::Mesh::Primitive::value: return #value; _c(Points) - _c(Lines) _c(LineStrip) _c(LineLoop) - _c(Triangles) + _c(Lines) + #ifndef MAGNUM_TARGET_GLES + _c(LineStripAdjacency) + _c(LinesAdjacency) + #endif _c(TriangleStrip) _c(TriangleFan) + _c(Triangles) + #ifndef MAGNUM_TARGET_GLES + _c(TriangleStripAdjacency) + _c(TrianglesAdjacency) + _c(Patches) + #endif #undef _c } @@ -390,12 +408,21 @@ std::string ConfigurationValue::toString(Magnum::Mesh:: Magnum::Mesh::Primitive ConfigurationValue::fromString(const std::string& stringValue, ConfigurationValueFlags) { #define _c(value) if(stringValue == #value) return Magnum::Mesh::Primitive::value; - _c(Lines) _c(LineStrip) _c(LineLoop) - _c(Triangles) + _c(Lines) + #ifndef MAGNUM_TARGET_GLES + _c(LineStripAdjacency) + _c(LinesAdjacency) + #endif _c(TriangleStrip) _c(TriangleFan) + _c(Triangles) + #ifndef MAGNUM_TARGET_GLES + _c(TriangleStripAdjacency) + _c(TrianglesAdjacency) + _c(Patches) + #endif #undef _c return Magnum::Mesh::Primitive::Points; diff --git a/src/Mesh.h b/src/Mesh.h index a2b3489e5..2db8523d9 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -244,237 +244,78 @@ class MAGNUM_EXPORT Mesh { Mesh& operator=(const Mesh&) = delete; public: - /** @name Polygon drawing settings */ - - /** - * @brief Front facing polygon winding - * - * @see setFrontFace() - */ - enum FrontFace: GLenum { - /** @brief Counterclockwise polygons are front facing (default). */ - CounterClockWise = GL_CCW, - - /** @brief Clockwise polygons are front facing. */ - ClockWise = GL_CW - }; - - /** - * @brief Set front-facing polygon winding - * - * Initial value is `FrontFace::%CounterClockWise`. - * @see @fn_gl{FrontFace} - */ - inline static void setFrontFace(FrontFace mode) { - glFrontFace(static_cast(mode)); - } - - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Provoking vertex - * - * @see setProvokingVertex() - * @requires_gl32 %Extension @extension{ARB,provoking_vertex}. Older - * versions behave always like - * @ref Magnum::Mesh::ProvokingVertex "ProvokingVertex::LastVertexConvention". - * @requires_gl OpenGL ES behaves always like - * @ref Magnum::Mesh::ProvokingVertex "ProvokingVertex::LastVertexConvention". - */ - enum class ProvokingVertex: GLenum { - /** @brief Use first vertex of each polygon. */ - FirstVertexConvention = GL_FIRST_VERTEX_CONVENTION, - - /** @brief Use last vertex of each polygon (default). */ - LastVertexConvention = GL_LAST_VERTEX_CONVENTION - }; - /** - * @brief Set provoking vertex + * @brief Primitive type * - * Initial value is @ref ProvokingVertex "ProvokingVertex::LastVertexConvention". - * @see @fn_gl{ProvokingVertex} - * @requires_gl32 %Extension @extension{ARB,provoking_vertex}. Older - * versions behave always like the default. - * @requires_gl OpenGL ES behaves always like the default. + * @see primitive(), setPrimitive() */ - inline static void setProvokingVertex(ProvokingVertex mode) { - glProvokingVertex(static_cast(mode)); - } - #endif + enum class Primitive: GLenum { + /** Single points. */ + Points = GL_POINTS, - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Polygon mode - * - * @see setPolygonMode() - * @requires_gl OpenGL ES behaves always like @ref Magnum::Mesh::PolygonMode "PolygonMode::Fill". - * See setPrimitive() for possible workaround. - */ - enum class PolygonMode: GLenum { /** - * Interior of the polygon is filled (default). + * First two vertices define first line segment, each following + * vertex defines another segment. */ - Fill = GL_FILL, + LineStrip = GL_LINE_STRIP, - /** - * Boundary edges are filled. See also setLineWidth(). - */ - Line = GL_LINE, + /** Line strip, last and first vertex are connected together. */ + LineLoop = GL_LINE_LOOP, /** - * Starts of boundary edges are drawn as points. See also - * setPointSize(). + * Each pair of vertices defines a single line, lines aren't + * connected together. */ - Point = GL_POINT - }; - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Set polygon drawing mode - * - * Initial value is @ref PolygonMode "PolygonMode::Fill". - * @see @fn_gl{PolygonMode} - * @requires_gl OpenGL ES behaves always like the default. See - * setPrimitive() for possible workaround. - */ - inline static void setPolygonMode(PolygonMode mode) { - glPolygonMode(GL_FRONT_AND_BACK, static_cast(mode)); - } - #endif - - /** - * @brief Mode affected by polygon offset - * - * @see setPolygonOffsetMode(), setPolygonOffset() - */ - enum class PolygonOffsetMode: GLenum { - /** Offset filled polygons. */ - Fill = GL_POLYGON_OFFSET_FILL + Lines = GL_LINES, #ifndef MAGNUM_TARGET_GLES - , - /** - * Offset lines. - * @requires_gl Only @ref Magnum::Mesh::PolygonOffsetMode "PolygonOffsetMode::Fill" - * is available in OpenGL ES. + * Line strip with adjacency information. + * @requires_gl32 %Extension @extension{ARB,geometry_shader4} */ - Line = GL_POLYGON_OFFSET_LINE, + LineStripAdjacency = GL_LINE_STRIP_ADJACENCY, /** - * Offset points. - * @requires_gl Only @ref Magnum::Mesh::PolygonOffsetMode "PolygonOffsetMode::Fill" - * is available in OpenGL ES. + * Lines with adjacency information. + * @requires_gl32 %Extension @extension{ARB,geometry_shader4} */ - Point = GL_POLYGON_OFFSET_POINT + LinesAdjacency = GL_LINES_ADJACENCY, #endif - }; - - /** - * @brief Enable/disable polygon offset for given mode - * - * Initially disabled for all modes. - * @see setPolygonOffset(), @fn_gl{Enable}/@fn_gl{Disable} - */ - inline static void setPolygonOffsetMode(PolygonOffsetMode mode, bool enabled) { - enabled ? glEnable(static_cast(mode)) : glDisable(static_cast(mode)); - } - - /** - * @brief Set polygon offset - * @param factor Scale factor - * @param units Offset units - * - * @attention You have to call setPolygonOffsetMode() to enable - * polygon offset for desired polygon modes. - * @see @fn_gl{PolygonOffset} - */ - inline static void setPolygonOffset(Float factor, Float units) { - glPolygonOffset(factor, units); - } - - /** - * @brief Set line width - * - * Initial value is `1.0f`. - * @see @fn_gl{LineWidth} - */ - inline static void setLineWidth(Float width) { - glLineWidth(width); - } - - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Set point size - * - * Initial value is `1.0f`. - * @see setProgramPointSize(), @fn_gl{PointSize} - * @requires_gl Set directly in vertex shader using @c gl_PointSize - * builtin variable. - */ - inline static void setPointSize(Float size) { - glPointSize(size); - } - - /** - * @brief Enable/disable programmable point size - * - * If enabled, the point size is taken from vertex/geometry shader - * builtin `gl_PointSize`. Initially disabled on desktop OpenGL. - * @see setPointSize(), @fn_gl{Enable}/@fn_gl{Disable} with @def_gl{PROGRAM_POINT_SIZE} - * @requires_gl Always enabled on OpenGL ES. - */ - inline static void setProgramPointSize(bool enabled) { - enabled ? glEnable(GL_PROGRAM_POINT_SIZE) : glDisable(GL_PROGRAM_POINT_SIZE); - } - #endif - - /*@}*/ - - /** - * @brief Primitive type - * - * @see primitive(), setPrimitive() - */ - enum class Primitive: GLenum { - /** - * Single points - */ - Points = GL_POINTS, /** - * Each pair of vertices defines a single line, lines aren't - * connected together. + * First three vertices define first triangle, each following + * vertex defines another triangle. */ - Lines = GL_LINES, + TriangleStrip = GL_TRIANGLE_STRIP, /** - * Polyline + * First vertex is center, each following vertex is connected to + * previous and center vertex. */ - LineStrip = GL_LINE_STRIP, + TriangleFan = GL_TRIANGLE_FAN, - /** - * Polyline, last vertex is connected to first. - */ - LineLoop = GL_LINE_LOOP, + /** Each three vertices define one triangle. */ + Triangles = GL_TRIANGLES, + #ifndef MAGNUM_TARGET_GLES /** - * Each three vertices define one triangle. + * Triangle strip with adjacency information. + * @requires_gl32 %Extension @extension{ARB,geometry_shader4} */ - Triangles = GL_TRIANGLES, + TriangleStripAdjacency = GL_TRIANGLE_STRIP_ADJACENCY, /** - * First three vertices define first triangle, each following - * vertex defines another triangle. + * Triangles with adjacency information. + * @requires_gl32 %Extension @extension{ARB,geometry_shader4} */ - TriangleStrip = GL_TRIANGLE_STRIP, + TrianglesAdjacency = GL_TRIANGLES_ADJACENCY, /** - * First vertex is center, each following vertex is connected to - * previous and center vertex. + * Patches. + * @requires_gl40 %Extension @extension{ARB,tessellation_shader} */ - TriangleFan = GL_TRIANGLE_FAN + Patches = GL_PATCHES + #endif }; /** @@ -521,7 +362,7 @@ class MAGNUM_EXPORT Mesh { Mesh& operator=(Mesh&& other); /** @brief Primitive type */ - inline Primitive primitive() const { return _primitive; } + Primitive primitive() const { return _primitive; } /** * @brief Set primitive type @@ -531,13 +372,13 @@ class MAGNUM_EXPORT Mesh { * @see setVertexCount(), addVertexBuffer(), * addInterleavedVertexBuffer(), addVertexBufferStride() */ - inline Mesh* setPrimitive(Primitive primitive) { + Mesh* setPrimitive(Primitive primitive) { _primitive = primitive; return this; } /** @brief Vertex count */ - inline Int vertexCount() const { return _vertexCount; } + Int vertexCount() const { return _vertexCount; } /** * @brief Set vertex count @@ -547,13 +388,13 @@ class MAGNUM_EXPORT Mesh { * @see setPrimitive(), addVertexBuffer(), addInterleavedVertexBuffer(), * addVertexBufferStride(), MeshTools::interleave() */ - inline Mesh* setVertexCount(Int vertexCount) { + Mesh* setVertexCount(Int vertexCount) { _vertexCount = vertexCount; return this; } /** @brief Index count */ - inline Int indexCount() const { return _indexCount; } + Int indexCount() const { return _indexCount; } /** * @brief Set index count @@ -562,7 +403,7 @@ class MAGNUM_EXPORT Mesh { * Default is zero. * @see setIndexBuffer(), MeshTools::compressIndices() */ - inline Mesh* setIndexCount(Int count) { + Mesh* setIndexCount(Int count) { _indexCount = count; return this; } @@ -616,13 +457,7 @@ class MAGNUM_EXPORT Mesh { * @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access} * if @extension{APPLE,vertex_array_object} is available */ - template inline Mesh* addVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) { - CORRADE_ASSERT(sizeof...(attributes) == 1 || _vertexCount != 0, - "Mesh::addVertexBuffer(): vertex count must be set before binding attributes", this); - - addVertexBufferInternal(buffer, offset, attributes...); - return this; - } + template Mesh* addVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes); /** * @brief Add buffer with interleaved vertex attributes for use with given shader @@ -733,7 +568,7 @@ class MAGNUM_EXPORT Mesh { * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if * @extension{APPLE,vertex_array_object} is available) */ - inline Mesh* setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type) { + Mesh* setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type) { return setIndexBuffer(buffer, offset, type, 0, 0); } @@ -948,6 +783,15 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::Primitive value); /** @debugoperator{Magnum::Mesh} */ Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::IndexType value); +template inline Mesh* Mesh::addVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) { + CORRADE_ASSERT(sizeof...(attributes) == 1 || _vertexCount != 0, + "Mesh::addVertexBuffer(): vertex count must be set before binding attributes", this); + + addVertexBufferInternal(buffer, offset, attributes...); + return this; +} + + } namespace Corrade { namespace Utility { diff --git a/src/MeshTools/CMakeLists.txt b/src/MeshTools/CMakeLists.txt index fc0b2cd15..3ed711ac5 100644 --- a/src/MeshTools/CMakeLists.txt +++ b/src/MeshTools/CMakeLists.txt @@ -33,12 +33,13 @@ set(MagnumMeshTools_GracefulAssert_SRCS GenerateFlatNormals.cpp) set(MagnumMeshTools_HEADERS - Clean.h CombineIndexedArrays.h CompressIndices.h + Duplicate.h FlipNormals.h GenerateFlatNormals.h Interleave.h + RemoveDuplicates.h Subdivide.h Tipsify.h Transform.h diff --git a/src/MeshTools/Clean.h b/src/MeshTools/Clean.h deleted file mode 100644 index cc4504e08..000000000 --- a/src/MeshTools/Clean.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef Magnum_MeshTools_Clean_h -#define Magnum_MeshTools_Clean_h -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/** @file - * @brief Function Magnum::MeshTools::clean() - */ - -#include -#include -#include - -#include "Math/Vector.h" - -namespace Magnum { namespace MeshTools { - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - -template class Clean { - public: - inline Clean(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} - - void operator()(typename Vertex::Type epsilon = Math::TypeTraits::epsilon()) { - if(indices.empty()) return; - - /* Get mesh bounds */ - Vertex min, max; - for(std::size_t i = 0; i != Vertex::Size; ++i) { - min[i] = std::numeric_limits::max(); - max[i] = std::numeric_limits::min(); - } - for(auto it = vertices.cbegin(); it != vertices.cend(); ++it) - for(std::size_t i = 0; i != vertexSize; ++i) - if((*it)[i] < min[i]) - min[i] = (*it)[i]; - else if((*it)[i] > max[i]) - max[i] = (*it)[i]; - - /* Make epsilon so large that std::size_t can index all vertices - inside mesh bounds. */ - Vertex size = max-min; - for(std::size_t i = 0; i != Vertex::Size; ++i) - if(static_cast(size[i]/std::numeric_limits::max()) > epsilon) - epsilon = static_cast(size[i]/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] = (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()); - auto result = table.insert(std::pair, HashedVertex>(Math::Vector::from(index), v)); - *it = result.first->second.newIndex; - } - - /* 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); - - /* Move vertex coordinates by epsilon/2 in next direction */ - if(moving != Vertex::Size) { - moved = Vertex(); - moved[moving] = epsilon/2; - } - } - } - - private: - class IndexHash { - public: - inline std::size_t operator()(const Math::Vector& data) const { - /* GCC 4.4 thinks reinterpret_cast will break strict aliasing, doing it with bit cast instead */ - return Corrade::Utility::bitCast(Corrade::Utility::MurmurHash2()(reinterpret_cast(&data), sizeof(data))); - } - }; - - struct HashedVertex { - UnsignedInt oldIndex, newIndex; - - HashedVertex(UnsignedInt oldIndex, UnsignedInt newIndex): oldIndex(oldIndex), newIndex(newIndex) {} - }; - - std::vector& indices; - std::vector& vertices; -}; - -} -#endif - -/** -@brief %Clean 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. - -@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 -*/ -template inline void clean(std::vector& indices, std::vector& vertices, typename Vertex::Type epsilon = Math::TypeTraits::epsilon()) { - Implementation::Clean(indices, vertices)(epsilon); -} - -}} - -#endif diff --git a/src/MeshTools/CombineIndexedArrays.h b/src/MeshTools/CombineIndexedArrays.h index 1650b443d..59fa27c87 100644 --- a/src/MeshTools/CombineIndexedArrays.h +++ b/src/MeshTools/CombineIndexedArrays.h @@ -33,11 +33,10 @@ #include #include "Math/Vector.h" -#include "MeshTools/Clean.h" +#include "MeshTools/RemoveDuplicates.h" namespace Magnum { namespace MeshTools { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { class CombineIndexedArrays { @@ -56,7 +55,7 @@ class CombineIndexedArrays { writeCombinedIndices(indexCombinations, std::get<0>(indexedArrays)...); /* Make the combinations unique */ - MeshTools::clean(result, indexCombinations); + MeshTools::removeDuplicates(result, indexCombinations); /* Write combined arrays */ writeCombinedArrays(indexCombinations, std::get<1>(indexedArrays)...); @@ -65,7 +64,7 @@ class CombineIndexedArrays { } private: - template inline static std::size_t indexCount(const std::vector& first, const std::vector&... next) { + 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); return first.size(); @@ -90,13 +89,12 @@ class CombineIndexedArrays { } /* Terminator functions for recursive calls */ - inline static std::size_t indexCount() { return 0; } - template inline static void writeCombinedIndices(std::vector>&) {} - template inline static void writeCombinedArrays(const std::vector>&) {} + static std::size_t indexCount() { return 0; } + template static void writeCombinedIndices(std::vector>&) {} + template static void writeCombinedArrays(const std::vector>&) {} }; } -#endif /** @brief Combine indexed arrays diff --git a/src/MeshTools/CompressIndices.cpp b/src/MeshTools/CompressIndices.cpp index 2506fb346..2d765bafc 100644 --- a/src/MeshTools/CompressIndices.cpp +++ b/src/MeshTools/CompressIndices.cpp @@ -31,13 +31,12 @@ namespace Magnum { namespace MeshTools { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace { template constexpr Mesh::IndexType indexType(); -template<> inline constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedByte; } -template<> inline constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedShort; } -template<> inline constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedInt; } +template<> constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedByte; } +template<> constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedShort; } +template<> constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedInt; } template inline std::tuple compress(const std::vector& indices) { char* buffer = new char[indices.size()*sizeof(T)]; @@ -65,7 +64,6 @@ std::tuple compressIndicesInternal(const st } } -#endif std::tuple compressIndices(const std::vector& indices) { return compressIndicesInternal(indices, *std::max_element(indices.begin(), indices.end())); diff --git a/src/MeshTools/Duplicate.h b/src/MeshTools/Duplicate.h new file mode 100644 index 000000000..f35549990 --- /dev/null +++ b/src/MeshTools/Duplicate.h @@ -0,0 +1,54 @@ +#ifndef Magnum_MeshTools_Duplicate_h +#define Magnum_MeshTools_Duplicate_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Function Magnum::MeshTools::duplicate() + */ + +#include + +#include "Types.h" + +namespace Magnum { namespace MeshTools { + +/** +@brief Duplicate vertices using index array + +Converts indexed array to non-indexed, for example vertices `{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() +*/ +template std::vector duplicate(const std::vector& indices, const std::vector& vertices) { + std::vector out; + out.reserve(indices.size()); + for(const UnsignedInt index: indices) + out.push_back(vertices[index]); + return std::move(out); +} + +}} + +#endif diff --git a/src/MeshTools/GenerateFlatNormals.cpp b/src/MeshTools/GenerateFlatNormals.cpp index 64e152d1c..e9703b124 100644 --- a/src/MeshTools/GenerateFlatNormals.cpp +++ b/src/MeshTools/GenerateFlatNormals.cpp @@ -25,7 +25,7 @@ #include "GenerateFlatNormals.h" #include "Math/Vector3.h" -#include "MeshTools/Clean.h" +#include "MeshTools/RemoveDuplicates.h" namespace Magnum { namespace MeshTools { @@ -48,9 +48,9 @@ std::tuple, std::vector> generateFlatNormals(c normals.push_back(normal); } - /* Clean duplicate normals and return */ - MeshTools::clean(normalIndices, normals); - return std::make_tuple(normalIndices, normals); + /* Remove duplicate normals and return */ + MeshTools::removeDuplicates(normalIndices, normals); + return std::make_tuple(std::move(normalIndices), std::move(normals)); } }} diff --git a/src/MeshTools/Interleave.h b/src/MeshTools/Interleave.h index 42c907cdc..8745a5da3 100644 --- a/src/MeshTools/Interleave.h +++ b/src/MeshTools/Interleave.h @@ -38,12 +38,11 @@ namespace Magnum { namespace MeshTools { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { class Interleave { public: - inline Interleave(): _attributeCount(0), _stride(0), _data(nullptr) {} + Interleave(): _attributeCount(0), _stride(0), _data(nullptr) {} template std::tuple operator()(const T&... attributes) { /* Compute buffer size and stride */ @@ -76,30 +75,30 @@ class Interleave { buffer->setData(attribute, usage); } - template inline static typename std::enable_if::value, std::size_t>::type attributeCount(const T& first, const U&... next) { + template static typename std::enable_if::value, std::size_t>::type attributeCount(const T& first, const U&... next) { CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size() || attributeCount(next...) == ~std::size_t(0), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.", 0); return first.size(); } - template inline static std::size_t attributeCount(std::size_t, const T&... next) { + template static std::size_t attributeCount(std::size_t, const T&... next) { return attributeCount(next...); } - template inline static std::size_t attributeCount(std::size_t) { + template static std::size_t attributeCount(std::size_t) { return ~std::size_t(0); } - template inline static typename std::enable_if::value, std::size_t>::type stride(const T&, const U&... next) { + template static typename std::enable_if::value, std::size_t>::type stride(const T&, const U&... next) { return sizeof(typename T::value_type) + stride(next...); } - template inline static std::size_t stride(std::size_t gap, const T&... next) { + template static std::size_t stride(std::size_t gap, const T&... next) { return gap + stride(next...); } private: - template inline void write(char* startingOffset, const T& first, const U&... next) { + template void write(char* startingOffset, const T& first, const U&... next) { write(startingOffset+writeOne(startingOffset, first), next...); } @@ -123,9 +122,9 @@ class Interleave { } /* Terminator functions for recursive calls */ - inline static std::size_t attributeCount() { return 0; } - inline static std::size_t stride() { return 0; } - inline void write(char*) {} + static std::size_t attributeCount() { return 0; } + static std::size_t stride() { return 0; } + void write(char*) {} std::size_t _attributeCount; std::size_t _stride; @@ -133,7 +132,6 @@ class Interleave { }; } -#endif /** @brief %Interleave vertex attributes diff --git a/src/MeshTools/RemoveDuplicates.h b/src/MeshTools/RemoveDuplicates.h new file mode 100644 index 000000000..10cb132c7 --- /dev/null +++ b/src/MeshTools/RemoveDuplicates.h @@ -0,0 +1,154 @@ +#ifndef Magnum_MeshTools_RemoveDuplicates_h +#define Magnum_MeshTools_RemoveDuplicates_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Function Magnum::MeshTools::removeDuplicates() + */ + +#include +#include +#include +#include + +#include "Math/Functions.h" +#include "Magnum.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; + + HashedVertex(UnsignedInt oldIndex, UnsignedInt newIndex): oldIndex(oldIndex), newIndex(newIndex) {} + }; + + std::vector& indices; + std::vector& vertices; +}; + +} + +/** +@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 +*/ +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(const auto& v: vertices) { + 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] = (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()); + auto result = table.insert(std::pair, HashedVertex>(Math::Vector::from(index), v)); + *it = result.first->second.newIndex; + } + + /* 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); + + /* Move vertex coordinates by epsilon/2 in next direction */ + if(moving != Vertex::Size) { + moved = Vertex(); + moved[moving] = epsilon/2; + } + } +} + +} + +}} + +#endif diff --git a/src/MeshTools/Subdivide.h b/src/MeshTools/Subdivide.h index 371aeca24..33b8f8517 100644 --- a/src/MeshTools/Subdivide.h +++ b/src/MeshTools/Subdivide.h @@ -33,46 +33,13 @@ namespace Magnum { namespace MeshTools { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class Subdivide { public: - inline Subdivide(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} - - void operator()(Interpolator interpolator) { - CORRADE_ASSERT(!(indices.size()%3), "MeshTools::subdivide(): index count is not divisible by 3!", ); - - std::size_t indexCount = indices.size(); - indices.reserve(indices.size()*4); - - /* Subdivide each face to four new */ - for(std::size_t i = 0; i != indexCount; i += 3) { - /* Interpolate each side */ - UnsignedInt newVertices[3]; - for(int j = 0; j != 3; ++j) - newVertices[j] = addVertex(interpolator(vertices[indices[i+j]], vertices[indices[i+(j+1)%3]])); - - /* - * Add three new faces (0, 1, 3) and update original (2) - * - * orig 0 - * / \ - * / 0 \ - * / \ - * new 0 ----- new 2 - * / \ / \ - * / 1 \ 2 / 3 \ - * / \ / \ - * orig 1 ----- new 1 ---- orig 2 - */ - addFace(indices[i], newVertices[0], newVertices[2]); - addFace(newVertices[0], indices[i+1], newVertices[1]); - addFace(newVertices[2], newVertices[1], indices[i+2]); - for(std::size_t j = 0; j != 3; ++j) - indices[i+j] = newVertices[j]; - } - } + Subdivide(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} + + void operator()(Interpolator interpolator); private: std::vector& indices; @@ -91,7 +58,6 @@ template class Subdivide { }; } -#endif /** @brief %Subdivide the mesh @@ -102,13 +68,51 @@ template class Subdivide { @param interpolator Functor or function pointer which interpolates two adjacent vertices: `Vertex interpolator(Vertex a, Vertex b)` -Goes through all triangle faces and subdivides them into four new. Cleaning +Goes through all triangle faces and subdivides them into four new. Removing duplicate vertices in the mesh is up to user. */ template inline void subdivide(std::vector& indices, std::vector& vertices, Interpolator interpolator) { Implementation::Subdivide(indices, vertices)(interpolator); } +namespace Implementation { + +template void Subdivide::operator()(Interpolator interpolator) { + CORRADE_ASSERT(!(indices.size()%3), "MeshTools::subdivide(): index count is not divisible by 3!", ); + + std::size_t indexCount = indices.size(); + indices.reserve(indices.size()*4); + + /* Subdivide each face to four new */ + for(std::size_t i = 0; i != indexCount; i += 3) { + /* Interpolate each side */ + UnsignedInt newVertices[3]; + for(int j = 0; j != 3; ++j) + newVertices[j] = addVertex(interpolator(vertices[indices[i+j]], vertices[indices[i+(j+1)%3]])); + + /* + * Add three new faces (0, 1, 3) and update original (2) + * + * orig 0 + * / \ + * / 0 \ + * / \ + * new 0 ----- new 2 + * / \ / \ + * / 1 \ 2 / 3 \ + * / \ / \ + * orig 1 ----- new 1 ---- orig 2 + */ + addFace(indices[i], newVertices[0], newVertices[2]); + addFace(newVertices[0], indices[i+1], newVertices[1]); + addFace(newVertices[2], newVertices[1], indices[i+2]); + for(std::size_t j = 0; j != 3; ++j) + indices[i+j] = newVertices[j]; + } +} + +} + }} #endif diff --git a/src/MeshTools/Test/CMakeLists.txt b/src/MeshTools/Test/CMakeLists.txt index a0a5626e5..bf0b06919 100644 --- a/src/MeshTools/Test/CMakeLists.txt +++ b/src/MeshTools/Test/CMakeLists.txt @@ -22,14 +22,15 @@ # DEALINGS IN THE SOFTWARE. # -corrade_add_test(MeshToolsCleanTest CleanTest.cpp) corrade_add_test(MeshToolsCombineIndexedArraysTest CombineIndexedArraysTest.cpp) 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(MeshToolsSubdivideTest SubdivideTest.cpp) -# corrade_add_test(MeshToolsSubdivideCleanBenchmark SubdivideCleanBenchmark.h SubdivideCleanBenchmark.cpp MagnumPrimitives) +# corrade_add_test(MeshToolsSubdivideRemoveDuplicatesBenchmark SubdivideRemoveDuplicatesBenchmark.h SubdivideRemoveDuplicatesBenchmark.cpp MagnumPrimitives) corrade_add_test(MeshToolsTipsifyTest TipsifyTest.cpp LIBRARIES MagnumMeshTools) corrade_add_test(MeshToolsTransformTest TransformTest.cpp LIBRARIES MagnumMeshTools) diff --git a/src/MeshTools/Test/CombineIndexedArraysTest.cpp b/src/MeshTools/Test/CombineIndexedArraysTest.cpp index 9473a4123..cf9cd103b 100644 --- a/src/MeshTools/Test/CombineIndexedArraysTest.cpp +++ b/src/MeshTools/Test/CombineIndexedArraysTest.cpp @@ -22,6 +22,7 @@ DEALINGS IN THE SOFTWARE. */ +#include #include #include @@ -30,7 +31,7 @@ namespace Magnum { namespace MeshTools { namespace Test { -class CombineIndexedArraysTest: public Corrade::TestSuite::Tester { +class CombineIndexedArraysTest: public TestSuite::Tester { public: CombineIndexedArraysTest(); @@ -46,24 +47,29 @@ CombineIndexedArraysTest::CombineIndexedArraysTest() { void CombineIndexedArraysTest::wrongIndexCount() { std::stringstream ss; Error::setOutput(&ss); + std::vector a{0, 1, 0}; + std::vector b{3, 4}; std::vector array; std::vector result = MeshTools::combineIndexedArrays( - std::tuple&, std::vector&>(std::vector{0, 1, 0}, array), - std::tuple&, std::vector&>(std::vector{3, 4}, array)); + std::make_tuple(std::cref(a), std::ref(array)), + std::make_tuple(std::cref(b), std::ref(array))); CORRADE_COMPARE(result.size(), 0); CORRADE_COMPARE(ss.str(), "MeshTools::combineIndexedArrays(): index arrays don't have the same length, nothing done.\n"); } void CombineIndexedArraysTest::combine() { + std::vector a{0, 1, 0}; + std::vector b{3, 4, 3}; + std::vector c{6, 7, 6}; std::vector array1{ 0, 1 }; std::vector array2{ 0, 1, 2, 3, 4 }; std::vector array3{ 0, 1, 2, 3, 4, 5, 6, 7 }; std::vector result = MeshTools::combineIndexedArrays( - std::tuple&, std::vector&>(std::vector{0, 1, 0}, array1), - std::tuple&, std::vector&>(std::vector{3, 4, 3}, array2), - std::tuple&, std::vector&>(std::vector{6, 7, 6}, array3)); + 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))); CORRADE_COMPARE(result, (std::vector{0, 1, 0})); CORRADE_COMPARE(array1, (std::vector{0, 1})); diff --git a/src/MeshTools/Test/CompressIndicesTest.cpp b/src/MeshTools/Test/CompressIndicesTest.cpp index a433c1413..e4a7b0f1d 100644 --- a/src/MeshTools/Test/CompressIndicesTest.cpp +++ b/src/MeshTools/Test/CompressIndicesTest.cpp @@ -27,11 +27,9 @@ #include "MeshTools/CompressIndices.h" -using Corrade::Utility::Endianness; - namespace Magnum { namespace MeshTools { namespace Test { -class CompressIndicesTest: public Corrade::TestSuite::Tester { +class CompressIndicesTest: public TestSuite::Tester { public: CompressIndicesTest(); @@ -70,7 +68,7 @@ void CompressIndicesTest::compressShort() { CORRADE_COMPARE(indexCount, 4); CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedShort); - if(!Endianness::isBigEndian()) { + if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), (std::vector{ 0x01, 0x00, 0x00, 0x01, @@ -97,7 +95,7 @@ void CompressIndicesTest::compressInt() { CORRADE_COMPARE(indexCount, 3); CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedInt); - if(!Endianness::isBigEndian()) { + if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), (std::vector{ 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, diff --git a/src/MeshTools/Test/DuplicateTest.cpp b/src/MeshTools/Test/DuplicateTest.cpp new file mode 100644 index 000000000..9fe06065f --- /dev/null +++ b/src/MeshTools/Test/DuplicateTest.cpp @@ -0,0 +1,50 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include "MeshTools/Duplicate.h" +#include "Magnum.h" + +namespace Magnum { namespace MeshTools { namespace Test { + +class DuplicateTest: public TestSuite::Tester { + public: + explicit DuplicateTest(); + + void duplicate(); +}; + +DuplicateTest::DuplicateTest() { + addTests({&DuplicateTest::duplicate}); +} + +void DuplicateTest::duplicate() { + CORRADE_COMPARE(MeshTools::duplicate({1, 1, 0, 3, 2, 2}, std::vector{-7, 35, 12, -18}), + (std::vector{35, 35, -7, -18, 12, 12})); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::DuplicateTest) diff --git a/src/MeshTools/Test/FlipNormalsTest.cpp b/src/MeshTools/Test/FlipNormalsTest.cpp index 47c648827..fb6106f47 100644 --- a/src/MeshTools/Test/FlipNormalsTest.cpp +++ b/src/MeshTools/Test/FlipNormalsTest.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace MeshTools { namespace Test { -class FlipNormalsTest: public Corrade::TestSuite::Tester { +class FlipNormalsTest: public TestSuite::Tester { public: FlipNormalsTest(); diff --git a/src/MeshTools/Test/GenerateFlatNormalsTest.cpp b/src/MeshTools/Test/GenerateFlatNormalsTest.cpp index cbac567da..6e6b22eba 100644 --- a/src/MeshTools/Test/GenerateFlatNormalsTest.cpp +++ b/src/MeshTools/Test/GenerateFlatNormalsTest.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace MeshTools { namespace Test { -class GenerateFlatNormalsTest: public Corrade::TestSuite::Tester { +class GenerateFlatNormalsTest: public TestSuite::Tester { public: GenerateFlatNormalsTest(); diff --git a/src/MeshTools/Test/InterleaveTest.cpp b/src/MeshTools/Test/InterleaveTest.cpp index fe525edda..d987be6ee 100644 --- a/src/MeshTools/Test/InterleaveTest.cpp +++ b/src/MeshTools/Test/InterleaveTest.cpp @@ -29,8 +29,6 @@ #include "Utility/Debug.h" #include "MeshTools/Interleave.h" -using Corrade::Utility::Endianness; - namespace Magnum { namespace MeshTools { namespace Test { class InterleaveTest: public Corrade::TestSuite::Tester { @@ -95,7 +93,7 @@ void InterleaveTest::write() { CORRADE_COMPARE(attributeCount, std::size_t(3)); CORRADE_COMPARE(stride, std::size_t(7)); std::size_t size = attributeCount*stride; - if(!Endianness::isBigEndian()) { + if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data, data+size), (std::vector{ 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, @@ -124,7 +122,7 @@ void InterleaveTest::writeGaps() { CORRADE_COMPARE(attributeCount, std::size_t(3)); CORRADE_COMPARE(stride, std::size_t(12)); std::size_t size = attributeCount*stride; - if(!Endianness::isBigEndian()) { + if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data, data+size), (std::vector{ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, diff --git a/src/MeshTools/Test/CleanTest.cpp b/src/MeshTools/Test/RemoveDuplicatesTest.cpp similarity index 68% rename from src/MeshTools/Test/CleanTest.cpp rename to src/MeshTools/Test/RemoveDuplicatesTest.cpp index 8e15281c9..2f40c9038 100644 --- a/src/MeshTools/Test/CleanTest.cpp +++ b/src/MeshTools/Test/RemoveDuplicatesTest.cpp @@ -24,41 +24,27 @@ #include -#include "MeshTools/Clean.h" +#include "MeshTools/RemoveDuplicates.h" namespace Magnum { namespace MeshTools { namespace Test { -class CleanTest: public Corrade::TestSuite::Tester { +class RemoveDuplicatesTest: public TestSuite::Tester { public: - CleanTest(); + RemoveDuplicatesTest(); void cleanMesh(); }; -class Vector1 { - public: - static const std::size_t Size = 1; - typedef Int Type; - - Vector1(): data(0) {} - Vector1(Type i): data(i) {} - Type operator[](std::size_t) const { return data; } - Type& operator[](std::size_t) { return data; } - bool operator==(Vector1 i) const { return i.data == data; } - Vector1 operator-(Vector1 i) const { return data-i.data; } - - private: - Type data; -}; +typedef Math::Vector<1, int> Vector1; -CleanTest::CleanTest() { - addTests({&CleanTest::cleanMesh}); +RemoveDuplicatesTest::RemoveDuplicatesTest() { + addTests({&RemoveDuplicatesTest::cleanMesh}); } -void CleanTest::cleanMesh() { +void RemoveDuplicatesTest::cleanMesh() { std::vector positions{1, 2, 1, 4}; std::vector indices{0, 1, 2, 1, 2, 3}; - MeshTools::clean(indices, positions); + MeshTools::removeDuplicates(indices, positions); /* Verify cleanup */ CORRADE_VERIFY(positions == (std::vector{1, 2, 4})); @@ -67,4 +53,4 @@ void CleanTest::cleanMesh() { }}} -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CleanTest) +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::RemoveDuplicatesTest) diff --git a/src/MeshTools/Test/SubdivideCleanBenchmark.cpp b/src/MeshTools/Test/SubdivideRemoveDuplicatesBenchmark.cpp similarity index 77% rename from src/MeshTools/Test/SubdivideCleanBenchmark.cpp rename to src/MeshTools/Test/SubdivideRemoveDuplicatesBenchmark.cpp index 01f3ebd36..87025a70d 100644 --- a/src/MeshTools/Test/SubdivideCleanBenchmark.cpp +++ b/src/MeshTools/Test/SubdivideRemoveDuplicatesBenchmark.cpp @@ -22,19 +22,19 @@ DEALINGS IN THE SOFTWARE. */ -#include "SubdivideCleanBenchmark.h" +#include "SubdivideRemoveDuplicatesBenchmark.h" #include #include "Primitives/Icosphere.h" -#include "MeshTools/Clean.h" +#include "MeshTools/RemoveDuplicates.h" #include "MeshTools/Subdivide.h" -QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::SubdivideCleanBenchmark) +QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::SubdivideRemoveDuplicatesBenchmark) namespace Magnum { namespace MeshTools { namespace Test { -void SubdivideCleanBenchmark::subdivide() { +void SubdivideRemoveDuplicatesBenchmark::subdivide() { QBENCHMARK { Primitives::Icosphere<0> icosphere; @@ -47,7 +47,7 @@ void SubdivideCleanBenchmark::subdivide() { } } -void SubdivideCleanBenchmark::subdivideAndCleanMeshAfter() { +void SubdivideRemoveDuplicatesBenchmark::subdivideAndRemoveDuplicatesMeshAfter() { QBENCHMARK { Primitives::Icosphere<0> icosphere; @@ -58,25 +58,25 @@ void SubdivideCleanBenchmark::subdivideAndCleanMeshAfter() { MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); - MeshTools::clean(*icosphere.indices(), *icosphere.positions(0)); + MeshTools::removeDuplicates(*icosphere.indices(), *icosphere.positions(0)); } } -void SubdivideCleanBenchmark::subdivideAndCleanMeshBetween() { +void SubdivideRemoveDuplicatesBenchmark::subdivideAndRemoveDuplicatesMeshBetween() { QBENCHMARK { Primitives::Icosphere<0> icosphere; /* Subdivide 5 times */ MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); - MeshTools::clean(*icosphere.indices(), *icosphere.positions(0)); + MeshTools::removeDuplicates(*icosphere.indices(), *icosphere.positions(0)); MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); - MeshTools::clean(*icosphere.indices(), *icosphere.positions(0)); + MeshTools::removeDuplicates(*icosphere.indices(), *icosphere.positions(0)); MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); - MeshTools::clean(*icosphere.indices(), *icosphere.positions(0)); + MeshTools::removeDuplicates(*icosphere.indices(), *icosphere.positions(0)); MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); - MeshTools::clean(*icosphere.indices(), *icosphere.positions(0)); + MeshTools::removeDuplicates(*icosphere.indices(), *icosphere.positions(0)); MeshTools::subdivide(*icosphere.indices(), *icosphere.positions(0), interpolator); - MeshTools::clean(*icosphere.indices(), *icosphere.positions(0)); + MeshTools::removeDuplicates(*icosphere.indices(), *icosphere.positions(0)); } } diff --git a/src/MeshTools/Test/SubdivideCleanBenchmark.h b/src/MeshTools/Test/SubdivideRemoveDuplicatesBenchmark.h similarity index 78% rename from src/MeshTools/Test/SubdivideCleanBenchmark.h rename to src/MeshTools/Test/SubdivideRemoveDuplicatesBenchmark.h index fe3af344e..c82cf4ddf 100644 --- a/src/MeshTools/Test/SubdivideCleanBenchmark.h +++ b/src/MeshTools/Test/SubdivideRemoveDuplicatesBenchmark.h @@ -1,5 +1,5 @@ -#ifndef Magnum_MeshTools_Test_SubdivideCleanBenchmark_h -#define Magnum_MeshTools_Test_SubdivideCleanBenchmark_h +#ifndef Magnum_MeshTools_Test_SubdivideRemoveDuplicatesBenchmark_h +#define Magnum_MeshTools_Test_SubdivideRemoveDuplicatesBenchmark_h /* This file is part of Magnum. @@ -30,16 +30,16 @@ namespace Magnum { namespace MeshTools { namespace Test { -class SubdivideCleanBenchmark: public QObject { +class SubdivideRemoveDuplicatesBenchmark: public QObject { Q_OBJECT private slots: void subdivide(); - void subdivideAndCleanMeshAfter(); - void subdivideAndCleanMeshBetween(); + void subdivideAndRemoveDuplicatesMeshAfter(); + void subdivideAndRemoveDuplicatesMeshBetween(); private: - static inline Magnum::Vector4 interpolator(const Magnum::Vector4& a, const Magnum::Vector4& b) { + static Magnum::Vector4 interpolator(const Magnum::Vector4& a, const Magnum::Vector4& b) { return (a+b).xyz().normalized(); } }; diff --git a/src/MeshTools/Test/SubdivideTest.cpp b/src/MeshTools/Test/SubdivideTest.cpp index 9271e3d60..2114b70c6 100644 --- a/src/MeshTools/Test/SubdivideTest.cpp +++ b/src/MeshTools/Test/SubdivideTest.cpp @@ -25,37 +25,26 @@ #include #include -#include "MeshTools/Clean.h" +#include "MeshTools/RemoveDuplicates.h" #include "MeshTools/Subdivide.h" namespace Magnum { namespace MeshTools { namespace Test { -class SubdivideTest: public Corrade::TestSuite::Tester { +class SubdivideTest: public TestSuite::Tester { public: SubdivideTest(); void wrongIndexCount(); void subdivide(); +}; - private: - class Vector1 { - public: - static const std::size_t Size = 1; - typedef Int Type; +namespace { - Vector1(): data(0) {} - Vector1(Type i): data(i) {} - Type operator[](std::size_t) const { return data; } - Type& operator[](std::size_t) { return data; } - bool operator==(Vector1 i) const { return i.data == data; } - Vector1 operator-(Vector1 i) const { return data-i.data; } +typedef Math::Vector<1, Int> Vector1; - private: - Type data; - }; +inline Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; } - inline static Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; } -}; +} SubdivideTest::SubdivideTest() { addTests({&SubdivideTest::wrongIndexCount, @@ -82,7 +71,7 @@ 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::clean(indices, positions); + MeshTools::removeDuplicates(indices, positions); /* Positions 0, 1, 2, 3, 4, 5, 6, 7, 8 */ CORRADE_COMPARE(positions.size(), 9); diff --git a/src/MeshTools/Test/TipsifyTest.cpp b/src/MeshTools/Test/TipsifyTest.cpp index 096b2fe2e..61da9fd17 100644 --- a/src/MeshTools/Test/TipsifyTest.cpp +++ b/src/MeshTools/Test/TipsifyTest.cpp @@ -24,11 +24,12 @@ #include +#include "Magnum.h" #include "MeshTools/Tipsify.h" namespace Magnum { namespace MeshTools { namespace Test { -class TipsifyTest: public Corrade::TestSuite::Tester { +class TipsifyTest: public TestSuite::Tester { public: TipsifyTest(); diff --git a/src/MeshTools/Test/TransformTest.cpp b/src/MeshTools/Test/TransformTest.cpp index 8c2569a7c..975ffd049 100644 --- a/src/MeshTools/Test/TransformTest.cpp +++ b/src/MeshTools/Test/TransformTest.cpp @@ -31,7 +31,7 @@ namespace Magnum { namespace MeshTools { namespace Test { -class TransformTest: public Corrade::TestSuite::Tester { +class TransformTest: public TestSuite::Tester { public: explicit TransformTest(); diff --git a/src/MeshTools/Tipsify.cpp b/src/MeshTools/Tipsify.cpp index e1f222a92..67afd09c3 100644 --- a/src/MeshTools/Tipsify.cpp +++ b/src/MeshTools/Tipsify.cpp @@ -26,7 +26,6 @@ #include -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Magnum { namespace MeshTools { namespace Implementation { void Tipsify::operator()(std::size_t cacheSize) { @@ -158,4 +157,3 @@ void Tipsify::buildAdjacency(std::vector& liveTriangleCount, std::v } }}} -#endif diff --git a/src/MeshTools/Tipsify.h b/src/MeshTools/Tipsify.h index 057b76b96..e167cfd4c 100644 --- a/src/MeshTools/Tipsify.h +++ b/src/MeshTools/Tipsify.h @@ -35,12 +35,11 @@ namespace Magnum { namespace MeshTools { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { class MAGNUM_MESHTOOLS_EXPORT Tipsify { public: - inline Tipsify(std::vector& indices, UnsignedInt vertexCount): indices(indices), vertexCount(vertexCount) {} + Tipsify(std::vector& indices, UnsignedInt vertexCount): indices(indices), vertexCount(vertexCount) {} void operator()(std::size_t cacheSize); @@ -59,7 +58,6 @@ class MAGNUM_MESHTOOLS_EXPORT Tipsify { }; } -#endif /** @brief %Tipsify the mesh diff --git a/src/OpenGL.cpp b/src/OpenGL.cpp index 7a0dbeee2..91c48b7a9 100644 --- a/src/OpenGL.cpp +++ b/src/OpenGL.cpp @@ -29,6 +29,7 @@ namespace Magnum { +/* Verify types */ static_assert(std::is_same::value, "GLubyte is not the same as UnsignedByte"); static_assert(std::is_same::value, "GLbyte is not the same as Byte"); static_assert(std::is_same::value, "GLushort is not the same as UnsignedShort"); @@ -41,4 +42,8 @@ static_assert(std::is_same::value, "GLfloat is not the same as F static_assert(std::is_same::value, "GLdouble is not the same as Double"); #endif +/* Verify boolean values */ +static_assert(GL_FALSE == false, "GL_FALSE is not the same as false"); +static_assert(GL_TRUE == true, "GL_TRUE is not the same as true"); + } diff --git a/src/Physics/AbstractShape.h b/src/Physics/AbstractShape.h deleted file mode 100644 index 19385bccc..000000000 --- a/src/Physics/AbstractShape.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef Magnum_Physics_AbstractShape_h -#define Magnum_Physics_AbstractShape_h -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/** @file - * @brief Class Magnum::Physics::AbstractShape, typedef Magnum::Physics::AbstractShape2D, Magnum::Physics::AbstractShape3D - */ - -#include "Magnum.h" -#include "DimensionTraits.h" - -#include "magnumPhysicsVisibility.h" - -namespace Magnum { namespace Physics { - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - template struct ShapeDimensionTraits {}; - - template<> struct ShapeDimensionTraits<2> { - enum class Type { - Point, - Line, - LineSegment, - Sphere, - Capsule, - AxisAlignedBox, - Box, - ShapeGroup - }; - }; - - template<> struct ShapeDimensionTraits<3> { - enum class Type { - Point, - Line, - LineSegment, - Sphere, - Capsule, - AxisAlignedBox, - Box, - ShapeGroup, - Plane - }; - }; - - Debug MAGNUM_PHYSICS_EXPORT operator<<(Debug debug, ShapeDimensionTraits<2>::Type value); - Debug MAGNUM_PHYSICS_EXPORT operator<<(Debug debug, ShapeDimensionTraits<3>::Type value); -} -#endif - -/** -@brief Base class for shapes - -See @ref collision-detection for brief introduction. -@see AbstractShape2D, AbstractShape3D -*/ -template class MAGNUM_PHYSICS_EXPORT AbstractShape { - public: - /** @brief Dimension count */ - static const UnsignedInt Dimensions = dimensions; - - /** - * @brief Shape type - * - * @internal Sorted by complexity, so the shape which is later in - * the list provides collision detection for previous shapes, not - * the other way around. - */ - #ifdef DOXYGEN_GENERATING_OUTPUT - enum class Type { - Point, /**< Point */ - Line, /**< Line */ - LineSegment, /**< @ref LineSegment "Line segment" */ - Sphere, /**< Sphere */ - Capsule, /**< Capsule */ - AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ - Box, /**< Box */ - ShapeGroup, /**< @ref ShapeGroup "Shape group" */ - Plane /**< Plane (3D only) */ - }; - #else - typedef typename Implementation::ShapeDimensionTraits::Type Type; - #endif - - explicit AbstractShape(); - virtual inline ~AbstractShape() {} - - /** @brief Shape type */ - virtual Type type() const = 0; - - /** - * @brief Apply transformation matrix - * - * Applies transformation matrix to user-defined shape properties and - * caches them for later usage in collision detection. - */ - virtual void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) = 0; - - /** - * @brief Detect collision with other shape - * - * Default implementation returns false. - * - * @internal If other shape is more complex than this, returns - * `other->collides(this)`. - */ - virtual bool collides(const AbstractShape* other) const; -}; - -template inline AbstractShape::AbstractShape() = default; - -/** @brief Abstract two-dimensional shape */ -typedef AbstractShape<2> AbstractShape2D; - -/** @brief Abstract three-dimensional shape */ -typedef AbstractShape<3> AbstractShape3D; - -#ifdef DOXYGEN_GENERATING_OUTPUT -/** @debugoperator{Magnum::Physics::AbstractShape} */ -template Debug operator<<(Debug debug, typename AbstractShape::Type value); -#endif - -}} - -#endif diff --git a/src/Physics/ObjectShape.cpp b/src/Physics/ObjectShape.cpp deleted file mode 100644 index a5eb93791..000000000 --- a/src/Physics/ObjectShape.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "ObjectShape.h" - -#include - -#include "AbstractShape.h" -#include "ObjectShapeGroup.h" - -namespace Magnum { namespace Physics { - -template ObjectShape::ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group), _shape(nullptr) { - this->setCachedTransformations(SceneGraph::AbstractFeature::CachedTransformation::Absolute); -} - -template ObjectShape::~ObjectShape() { - delete _shape; -} - -template ObjectShapeGroup* ObjectShape::group() { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); -} - -template const ObjectShapeGroup* ObjectShape::group() const { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); -} - -template void ObjectShape::markDirty() { - group()->setDirty(); -} - -template void ObjectShape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { - if(_shape) _shape->applyTransformationMatrix(absoluteTransformationMatrix); -} - -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT ObjectShape<2>; -template class MAGNUM_PHYSICS_EXPORT ObjectShape<3>; -#endif - -}} diff --git a/src/Physics/ObjectShape.h b/src/Physics/ObjectShape.h deleted file mode 100644 index b940c23e1..000000000 --- a/src/Physics/ObjectShape.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef Magnum_Physics_ObjectShape_h -#define Magnum_Physics_ObjectShape_h -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/** @file - * @brief Class Magnum::Physics::ObjectShape, typedef Magnum::Physics::ObjectShape2D, Magnum::Physics::ObjectShape3D - */ - -#include "SceneGraph/AbstractGroupedFeature.h" -#include "Physics/Physics.h" - -#include "magnumPhysicsVisibility.h" - -namespace Magnum { namespace Physics { - -/** -@brief Object shape - -Adds shape for collision detection to object. Each %ObjectShape is part of -some ObjectShapeGroup, which essentially maintains a set of objects which can -collide with each other. - -@section ObjectShape-usage Usage - -Add the feature to the object and some shape group (you can also use -ObjectShapeGroup::add() and ObjectShapeGroup::remove() later) and then set -desired object shape using setShape(). -@code -Physics::ObjectShapeGroup3D shapes; - -Object3D* object; -auto shape = new Physics::ObjectShape3D(object, &shapes); -shape->setShape(Physics::Sphere3D({}, 0.75f) || Physics::AxisAlignedBox3D({}, {3.0f, 1.5f, 2.0f})); -@endcode - -@see @ref scenegraph, ObjectShape2D, ObjectShape3D, ObjectShapeGroup2D, - ObjectShapeGroup3D, DebugTools::ShapeRenderer -*/ -template class MAGNUM_PHYSICS_EXPORT ObjectShape: public SceneGraph::AbstractGroupedFeature> { - public: - /** - * @brief Constructor - * @param object Object holding this feature - * @param group Group this shape belongs to - * - * Creates empty object shape. - * @see setShape() - */ - explicit ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr); - - /** - * @brief Destructor - * - * Deletes associated shape. - */ - ~ObjectShape(); - - /** @brief Shape */ - inline AbstractShape* shape() { return _shape; } - inline const AbstractShape* shape() const { return _shape; } /**< @overload */ - - /** - * @brief Set shape - * @return Pointer to self (for method chaining) - */ - inline ObjectShape* setShape(AbstractShape* shape) { - _shape = shape; - this->object()->setDirty(); - return this; - } - - /** - * @brief Set shape - * @return Pointer to self (for method chaining) - * - * Convenience overload for setShape(AbstractShape*), allowing you to - * use e.g. ShapeGroup operators: - * @code - * Physics::ObjectShape3D* shape; - * shape->setShape(Physics::Sphere3D({}, 0.75f) || Physics::AxisAlignedBox3D({}, {3.0f, 1.5f, 2.0f})); - * @endcode - */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template inline ObjectShape* setShape(T&& shape) { - #else - template inline typename std::enable_if, T>::value, ObjectShape*>::type setShape(T&& shape) { - #endif - return setShape(new T(std::move(shape))); - } - - /** - * @brief Object shape group containing this shape - * - * If the shape doesn't belong to any group, returns `nullptr`. - */ - ObjectShapeGroup* group(); - const ObjectShapeGroup* group() const; /**< @overload */ - - protected: - /** Marks also the group as dirty */ - void markDirty() override; - - /** Applies transformation to associated shape. */ - void clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) override; - - private: - AbstractShape* _shape; -}; - -/** @brief Two-dimensional object shape */ -typedef ObjectShape<2> ObjectShape2D; - -/** @brief Three-dimensional object shape */ -typedef ObjectShape<3> ObjectShape3D; - -}} - -#endif diff --git a/src/Physics/ShapeGroup.cpp b/src/Physics/ShapeGroup.cpp deleted file mode 100644 index 5d6777c4b..000000000 --- a/src/Physics/ShapeGroup.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "ShapeGroup.h" - -namespace Magnum { namespace Physics { - -template ShapeGroup::ShapeGroup(ShapeGroup&& other): operation(other.operation), a(other.a), b(other.b) { - other.operation = Implementation::GroupOperation::AlwaysFalse; - other.a = nullptr; - other.b = nullptr; -} - -template ShapeGroup::~ShapeGroup() { - if(!(operation & Implementation::GroupOperation::RefA)) delete a; - if(!(operation & Implementation::GroupOperation::RefB)) delete b; -} - -template ShapeGroup& ShapeGroup::operator=(ShapeGroup&& other) { - if(!(operation & Implementation::GroupOperation::RefA)) delete a; - if(!(operation & Implementation::GroupOperation::RefB)) delete b; - - operation = other.operation; - a = other.a; - b = other.b; - - other.operation = Implementation::GroupOperation::AlwaysFalse; - other.a = nullptr; - other.b = nullptr; - - return *this; -} - -template void ShapeGroup::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - if(a) a->applyTransformationMatrix(matrix); - if(b) b->applyTransformationMatrix(matrix); -} - -template bool ShapeGroup::collides(const AbstractShape* other) const { - switch(operation & ~Implementation::GroupOperation::RefAB) { - case Implementation::GroupOperation::And: return a->collides(other) && b->collides(other); - case Implementation::GroupOperation::Or: return a->collides(other) || b->collides(other); - case Implementation::GroupOperation::Not: return !a->collides(other); - case Implementation::GroupOperation::FirstObjectOnly: return a->collides(other); - - default: - return false; - } -} - -template class ShapeGroup<2>; -template class ShapeGroup<3>; - -}} diff --git a/src/Physics/ShapeGroup.h b/src/Physics/ShapeGroup.h deleted file mode 100644 index b546d60ba..000000000 --- a/src/Physics/ShapeGroup.h +++ /dev/null @@ -1,251 +0,0 @@ -#ifndef Magnum_Physics_ShapeGroup_h -#define Magnum_Physics_ShapeGroup_h -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/** @file - * @brief Class Magnum::Physics::ShapeGroup, typedef Magnum::Physics::ShapeGroup2D, Magnum::Physics::ShapeGroup3D - */ - -#include "AbstractShape.h" - -#include -#include -#include - -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - enum GroupOperation { - RefA = 0x01, - RefB = 0x02, - RefAB = 0x03, -// Complement = 1 << 2, -// Union = 2 << 2, -// Intersection = 3 << 2, -// Difference = 4 << 2, -// Xor = 5 << 2, - And = 6 << 2, - Or = 7 << 2, - Not = 8 << 2, - FirstObjectOnly = 9 << 2, - AlwaysFalse = 10 << 2 - }; -} -#define enableIfIsBaseType typename std::enable_if, T>::value, ShapeGroup>::type -#define enableIfAreBaseType typename std::enable_if, T>::value && std::is_base_of, U>::value, ShapeGroup>::type -#endif - -/** -@brief Shape group - -Result of logical operations on shapes. -See @ref collision-detection for brief introduction. -@see ShapeGroup2D, ShapeGroup3D -*/ -template class MAGNUM_PHYSICS_EXPORT ShapeGroup: public AbstractShape { - #ifndef DOXYGEN_GENERATING_OUTPUT -// template friend constexpr operator~(const T& a) -> enableIfIsBaseType; -// template friend constexpr operator~(T&& a) -> enableIfIsBaseType; -// template friend constexpr operator~(T& a) -> enableIfIsBaseType; - template friend constexpr auto operator!(const T& a) -> enableIfIsBaseType; - template friend constexpr auto operator!(T&& a) -> enableIfIsBaseType; - template friend constexpr auto operator!(T& a) -> enableIfIsBaseType; - - #define friendOp(char) \ - template friend constexpr auto operator char(const T& a, const U& b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(const T& a, U&& b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(T&& a, const U& b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(T&& a, U&& b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(const T& a, std::reference_wrapper b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(T&& a, std::reference_wrapper b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(std::reference_wrapper a, const U& b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(std::reference_wrapper a, U&& b) -> enableIfAreBaseType; \ - template friend constexpr auto operator char(std::reference_wrapper a, std::reference_wrapper b) -> enableIfAreBaseType; -// friendOp(|) -// friendOp(&) -// friendOp(-) -// friendOp(^) - friendOp(&&) - friendOp(||) - #undef friendOp - #endif - - ShapeGroup(const ShapeGroup&) = delete; - ShapeGroup& operator=(const ShapeGroup&) = delete; - - public: - /** @brief Default constructor */ - inline explicit ShapeGroup(): operation(Implementation::GroupOperation::AlwaysFalse), a(nullptr), b(nullptr) {} - - /** @brief Move constructor */ - ShapeGroup(ShapeGroup&& other); - - /** @brief Destructor */ - ~ShapeGroup(); - - /** @brief Move assignment */ - ShapeGroup& operator=(ShapeGroup&& other); - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::ShapeGroup; - } - - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; - - bool collides(const AbstractShape* other) const override; - - /** - * @brief First object in the group - * - * If there is no such object, returns `nullptr`. - */ - inline AbstractShape* first() { return a; } - - /** - * @brief Second object in the group - * - * If there is no such object, returns `nullptr`. - */ - inline AbstractShape* second() { return b; } - - private: - inline ShapeGroup(int operation, AbstractShape* a, AbstractShape* b): operation(operation), a(a), b(b) {} - - int operation; - AbstractShape* a; - AbstractShape* b; -}; - -/** @brief Two-dimensional shape group */ -typedef ShapeGroup<2> ShapeGroup2D; - -/** @brief Three-dimensional shape group */ -typedef ShapeGroup<3> ShapeGroup3D; - -// /* @brief Complement of shape */ -// template inline constexpr enableIfIsBaseType operator~(const T& a) { -// return ShapeGroup(ShapeGroup::Complement, new T(a), nullptr); -// } -// #ifndef DOXYGEN_GENERATING_OUTPUT -// template inline constexpr enableIfIsBaseType operator~(T&& a) { -// return ShapeGroup(ShapeGroup::Complement, new T(std::forward(a)), nullptr); -// } -// template inline constexpr enableIfIsBaseType operator~(T& a) { -// return ShapeGroup(ShapeGroup::Complement|ShapeGroup::RefA, &a.get(), nullptr); -// } -// #endif - -/** @relates ShapeGroup -@brief Logical NOT of shape -*/ -template inline constexpr auto operator!(const T& a) -> enableIfIsBaseType { - return ShapeGroup(Implementation::GroupOperation::Not, new T(a), nullptr); -} -#ifndef DOXYGEN_GENERATING_OUTPUT -template inline constexpr auto operator!(T&& a) -> enableIfIsBaseType { - return ShapeGroup(Implementation::GroupOperation::Not, new T(std::forward(a)), nullptr); -} -template inline constexpr auto operator!(T& a) -> enableIfIsBaseType { - return ShapeGroup(Implementation::GroupOperation::Not|Implementation::GroupOperation::RefA, &a.get(), nullptr); -} -#endif - -#ifdef DOXYGEN_GENERATING_OUTPUT -// /* @brief Union of two shapes */ -// template inline constexpr ShapeGroup operator&(T a, U b); -// -// /* @brief Intersection of two shapes */ -// template inline constexpr ShapeGroup operator&(T a, U b); -// -// /* @brief Difference of two shapes */ -// template inline constexpr ShapeGroup operator-(T a, U b); -// -// /* @brief XOR of two shapes */ -// template inline constexpr ShapeGroup operator^(T a, U b); -/** @relates ShapeGroup -@brief Logical AND of two shapes - -[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) -is used here, so this operation can be used for providing simplified shape -version, because collision with @p b is computed only if @p a collides. -See @ref collision-detection-shape-simplification for an example. -*/ -template inline constexpr ShapeGroup operator&&(T a, U b); - -/** @relates ShapeGroup -@brief Logical OR of two shapes - -[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) -is used, so if collision with @p a is detected, collision with @p b is not -computed. -*/ -template inline constexpr ShapeGroup operator||(T a, U b); -#else -#define op(type, char) \ -template inline constexpr auto operator char(const T& a, const U& b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type, new T(a), new U(b)); \ -} \ -template inline constexpr auto operator char(const T& a, U&& b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type, new T(a), new U(std::forward(b))); \ -} \ -template inline constexpr auto operator char(T&& a, const U& b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type, new T(std::forward(a)), new U(b)); \ -} \ -template inline constexpr auto operator char(T&& a, U&& b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type, new T(std::forward(a)), new U(std::forward(b))); \ -} \ -template inline constexpr auto operator char(const T& a, std::reference_wrapper b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type|Implementation::GroupOperation::RefB, new T(a), &b.get()); \ -} \ -template inline constexpr auto operator char(T&& a, std::reference_wrapper b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type|Implementation::GroupOperation::RefB, new T(std::forward(a)), &b.get()); \ -} \ -template inline constexpr auto operator char(std::reference_wrapper a, const U& b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type|Implementation::GroupOperation::RefA, &a.get(), new U(b)); \ -} \ -template inline constexpr auto operator char(std::reference_wrapper a, U&& b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type|Implementation::GroupOperation::RefA, &a.get(), new U(std::forward(b))); \ -} \ -template inline constexpr auto operator char(std::reference_wrapper a, std::reference_wrapper b) -> enableIfAreBaseType { \ - return ShapeGroup(Implementation::GroupOperation::type|Implementation::GroupOperation::RefAB, &a.get(), &b.get()); \ -} -// op(Union, |) -// op(Intersection, &) -// op(Difference, -) -// op(Xor, ^) -op(And, &&) -op(Or, ||) -#undef op -#endif - -#undef enableIfIsBaseType -#undef enableIfAreBaseType - -}} - -#endif diff --git a/src/Physics/Test/ShapeGroupTest.cpp b/src/Physics/Test/ShapeGroupTest.cpp deleted file mode 100644 index b4f559a8d..000000000 --- a/src/Physics/Test/ShapeGroupTest.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include - -#include - -#include "Math/Matrix4.h" -#include "Physics/Point.h" -#include "Physics/LineSegment.h" -#include "Physics/ShapeGroup.h" - -namespace Magnum { namespace Physics { namespace Test { - -class ShapeGroupTest: public Corrade::TestSuite::Tester { - public: - ShapeGroupTest(); - - void copy(); - void reference(); -}; - -ShapeGroupTest::ShapeGroupTest() { - addTests({&ShapeGroupTest::copy, - &ShapeGroupTest::reference}); -} - -void ShapeGroupTest::copy() { - ShapeGroup3D group; - { - Physics::Point3D point({1.0f, 2.0f, 3.0f}); - Physics::LineSegment3D segment({2.0f, 1.0f, 30.0f}, {1.0f, -20.0f, 3.0f}); - - group = !(point || segment); - } - - /* Just to test that it doesn't crash */ - group.applyTransformationMatrix(Matrix4::translation(Vector3::xAxis(1.0f))); - - CORRADE_VERIFY(true); -} - -void ShapeGroupTest::reference() { - Physics::Point3D point({1.0f, 2.0f, 3.0f}); - Physics::LineSegment3D segment({2.0f, 1.0f, 30.0f}, {1.0f, -20.0f, 3.0f}); - - ShapeGroup3D group = !(std::ref(point) || std::ref(segment)); - - group.applyTransformationMatrix(Matrix4::translation(Vector3(1.0f))); - - CORRADE_VERIFY((point.transformedPosition() == Vector3(2.0f, 3.0f, 4.0f))); - CORRADE_VERIFY((segment.transformedA() == Vector3(3.0f, 2.0f, 31.0f))); -} - -}}} - -CORRADE_TEST_MAIN(Magnum::Physics::Test::ShapeGroupTest) diff --git a/src/Physics/Test/ShapeTestBase.h b/src/Physics/Test/ShapeTestBase.h deleted file mode 100644 index 66ead8d97..000000000 --- a/src/Physics/Test/ShapeTestBase.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef Magnum_Physics_Test_ShapeTestBase_h -#define Magnum_Physics_Test_ShapeTestBase_h -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include - -#include "Math/Matrix4.h" -#include "Magnum.h" - -namespace Magnum { namespace Physics { namespace Test { - -class ShapeTestBase { - protected: - template void randomTransformation(T& shape) { - shape.applyTransformationMatrix(Matrix4::translation(Vector3(7.0f, 8.0f, -9.0f))); - } -}; - -#define VERIFY_COLLIDES(a, b) \ - CORRADE_VERIFY(a % b); \ - CORRADE_VERIFY(b % a); \ - CORRADE_VERIFY(a.collides(&b)); \ - CORRADE_VERIFY(b.collides(&a)); - -#define VERIFY_NOT_COLLIDES(a, b) \ - CORRADE_VERIFY(!(a % b)); \ - CORRADE_VERIFY(!(b % a)); \ - CORRADE_VERIFY(!(a.collides(&b))); \ - CORRADE_VERIFY(!(b.collides(&a))); - -}}} - -#endif diff --git a/src/Platform/AbstractContextHandler.h b/src/Platform/AbstractContextHandler.h index da4ec7e0c..d638e1917 100644 --- a/src/Platform/AbstractContextHandler.h +++ b/src/Platform/AbstractContextHandler.h @@ -63,7 +63,7 @@ template class AbstractContextHandl * * Default is to disable. */ - virtual inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const { + virtual ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const { return ExtensionWrangler::ExperimentalFeatures::Disable; } diff --git a/src/Platform/AbstractXApplication.cpp b/src/Platform/AbstractXApplication.cpp index 80e6e7215..6a38ad9ec 100644 --- a/src/Platform/AbstractXApplication.cpp +++ b/src/Platform/AbstractXApplication.cpp @@ -159,7 +159,7 @@ int AbstractXApplication::exec() { if(flags & Flag::Redraw) { flags &= ~Flag::Redraw; drawEvent(); - } else Corrade::Utility::sleep(5); + } else Utility::sleep(5); } return 0; diff --git a/src/Platform/AbstractXApplication.h b/src/Platform/AbstractXApplication.h index 4913d03bb..ac0710785 100644 --- a/src/Platform/AbstractXApplication.h +++ b/src/Platform/AbstractXApplication.h @@ -89,13 +89,6 @@ class AbstractXApplication { */ explicit AbstractXApplication(AbstractContextHandler* contextHandler, const Arguments& arguments, Configuration* configuration); - /** - * @brief Destructor - * - * Deletes context and destroys the window. - */ - virtual ~AbstractXApplication() = 0; - /** * @brief Execute main loop * @return Value for returning from `main()`. @@ -103,9 +96,18 @@ class AbstractXApplication { int exec(); /** @brief Exit application main loop */ - inline void exit() { flags |= Flag::Exit; } + void exit() { flags |= Flag::Exit; } protected: + /** + * @brief Destructor + * + * Deletes context and destroys the window. + */ + /* Nobody will need to have (and delete) AbstractXApplication*, thus + this is faster than public pure virtual destructor */ + ~AbstractXApplication(); + /** @copydoc GlutApplication::createContext() */ void createContext(Configuration* configuration); @@ -118,10 +120,10 @@ class AbstractXApplication { virtual void drawEvent() = 0; /** @copydoc GlutApplication::swapBuffers() */ - inline void swapBuffers() { contextHandler->swapBuffers(); } + void swapBuffers() { contextHandler->swapBuffers(); } /** @copydoc GlutApplication::redraw() */ - inline void redraw() { flags |= Flag::Redraw; } + void redraw() { flags |= Flag::Redraw; } /*@}*/ @@ -154,7 +156,7 @@ class AbstractXApplication { Exit = 1 << 1 }; - typedef Corrade::Containers::EnumSet Flags; + typedef Containers::EnumSet Flags; CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) Display* display; @@ -178,6 +180,7 @@ CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Flags) Double-buffered OpenGL context. @see AbstractXApplication(), createContext() +@todo GLX_ARB_create_context_robustness/EGL_EXT_create_context_robustness */ class AbstractXApplication::Configuration { Configuration(const Configuration&) = delete; @@ -190,7 +193,7 @@ class AbstractXApplication::Configuration { ~Configuration(); /** @brief Window title */ - inline std::string title() const { return _title; } + std::string title() const { return _title; } /** * @brief Set window title @@ -198,13 +201,13 @@ class AbstractXApplication::Configuration { * * Default is `"Magnum X Application"`. */ - inline Configuration* setTitle(std::string title) { + Configuration* setTitle(std::string title) { _title = std::move(title); return this; } /** @brief Window size */ - inline Vector2i size() const { return _size; } + Vector2i size() const { return _size; } /** * @brief Set window size @@ -212,7 +215,7 @@ class AbstractXApplication::Configuration { * * Default is `{800, 600}`. */ - inline Configuration* setSize(const Vector2i& size) { + Configuration* setSize(const Vector2i& size) { _size = size; return this; } @@ -260,22 +263,22 @@ class AbstractXApplication::InputEvent { * * @see modifiers() */ - typedef Corrade::Containers::EnumSet Modifiers; - - inline virtual ~InputEvent() {} + typedef Containers::EnumSet Modifiers; /** @copydoc GlutApplication::InputEvent::setAccepted() */ - inline void setAccepted(bool accepted = true) { _accepted = accepted; } + void setAccepted(bool accepted = true) { _accepted = accepted; } /** @copydoc GlutApplication::InputEvent::isAccepted() */ - inline bool isAccepted() { return _accepted; } + constexpr bool isAccepted() const { return _accepted; } /** @brief Modifiers */ - inline Modifiers modifiers() const { return _modifiers; } + constexpr Modifiers modifiers() const { return _modifiers; } #ifndef DOXYGEN_GENERATING_OUTPUT protected: - inline InputEvent(Modifiers modifiers): _modifiers(modifiers), _accepted(false) {} + constexpr InputEvent(Modifiers modifiers): _modifiers(modifiers), _accepted(false) {} + + ~InputEvent() = default; #endif private: @@ -373,13 +376,13 @@ class AbstractXApplication::KeyEvent: public AbstractXApplication::InputEvent { }; /** @brief Key */ - inline Key key() const { return _key; } + constexpr Key key() const { return _key; } /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline KeyEvent(Key key, Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _key(key), _position(position) {} + constexpr KeyEvent(Key key, Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _key(key), _position(position) {} const Key _key; const Vector2i _position; @@ -408,13 +411,13 @@ class AbstractXApplication::MouseEvent: public AbstractXApplication::InputEvent }; /** @brief Button */ - inline Button button() const { return _button; } + constexpr Button button() const { return _button; } /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline MouseEvent(Button button, Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _button(button), _position(position) {} + constexpr MouseEvent(Button button, Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _button(button), _position(position) {} const Button _button; const Vector2i _position; @@ -430,10 +433,10 @@ class AbstractXApplication::MouseMoveEvent: public AbstractXApplication::InputEv public: /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline MouseMoveEvent(Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _position(position) {} + constexpr MouseMoveEvent(Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _position(position) {} const Vector2i _position; }; diff --git a/src/Platform/EglContextHandler.cpp b/src/Platform/EglContextHandler.cpp index 75a1f05d4..56dd92cd1 100644 --- a/src/Platform/EglContextHandler.cpp +++ b/src/Platform/EglContextHandler.cpp @@ -99,7 +99,7 @@ void EglContextHandler::createContext(EGLNativeWindowType window) { Error() << "Cannot create EGL context:" << errorString(eglGetError()); std::exit(1); } - if(!(surface = eglCreateWindowSurface(display, config, window, NULL))) { + if(!(surface = eglCreateWindowSurface(display, config, window, nullptr))) { Error() << "Cannot create window surface:" << errorString(eglGetError()); std::exit(1); } diff --git a/src/Platform/EglContextHandler.h b/src/Platform/EglContextHandler.h index a67d709e0..6c1869b7c 100644 --- a/src/Platform/EglContextHandler.h +++ b/src/Platform/EglContextHandler.h @@ -66,11 +66,11 @@ class EglContextHandler: public AbstractContextHandler(cursor)); } /** @brief Warp mouse cursor to given coordinates */ - inline void warpMouseCursor(const Vector2i& position) { + void warpMouseCursor(const Vector2i& position) { glutWarpPointer(position.x(), position.y()); } @@ -250,7 +248,7 @@ class GlutApplication { private: void initialize(int& argc, char** argv); - inline static void staticViewportEvent(int x, int y) { + static void staticViewportEvent(int x, int y) { instance->viewportEvent({x, y}); } @@ -260,7 +258,7 @@ class GlutApplication { static void staticMouseMoveEvent(int x, int y); - inline static void staticDrawEvent() { + static void staticDrawEvent() { instance->drawEvent(); } @@ -286,7 +284,7 @@ class GlutApplication::Configuration { ~Configuration(); /** @brief Window title */ - inline std::string title() const { return _title; } + std::string title() const { return _title; } /** * @brief Set window title @@ -294,13 +292,13 @@ class GlutApplication::Configuration { * * Default is `"Magnum GLUT Application"`. */ - inline Configuration* setTitle(std::string title) { + Configuration* setTitle(std::string title) { _title = std::move(title); return this; } /** @brief Window size */ - inline Vector2i size() const { return _size; } + Vector2i size() const { return _size; } /** * @brief Set window size @@ -308,13 +306,13 @@ class GlutApplication::Configuration { * * Default is `{800, 600}`. */ - inline Configuration* setSize(const Vector2i& size) { + Configuration* setSize(const Vector2i& size) { _size = size; return this; } /** @brief Sample count */ - inline Int sampleCount() const { return _sampleCount; } + Int sampleCount() const { return _sampleCount; } /** * @brief Set sample count @@ -324,7 +322,7 @@ class GlutApplication::Configuration { * ignored, GLUT either enables it or disables. See also * @ref Renderer::Feature "Renderer::Feature::Multisampling". */ - inline Configuration* setSampleCount(Int count) { + Configuration* setSampleCount(Int count) { _sampleCount = count; return this; } @@ -348,23 +346,21 @@ class GlutApplication::InputEvent { InputEvent& operator=(InputEvent&&) = delete; public: - inline virtual ~InputEvent() {} - /** * @brief Set event as accepted * * If the event is ignored (i.e., not set as accepted), it might be * propagated elsewhere. By default is each event ignored. */ - inline void setAccepted(bool accepted = true) { _accepted = accepted; } + void setAccepted(bool accepted = true) { _accepted = accepted; } /** @brief Whether the event is accepted */ - inline bool isAccepted() { return _accepted; } + constexpr bool isAccepted() const { return _accepted; } - #ifndef DOXYGEN_GENERATING_OUTPUT protected: - inline InputEvent(): _accepted(false) {} - #endif + constexpr InputEvent(): _accepted(false) {} + + ~InputEvent() = default; private: bool _accepted; @@ -408,13 +404,13 @@ class GlutApplication::KeyEvent: public GlutApplication::InputEvent { }; /** @brief Key */ - inline Key key() const { return _key; } + constexpr Key key() const { return _key; } /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline KeyEvent(Key key, const Vector2i& position): _key(key), _position(position) {} + constexpr KeyEvent(Key key, const Vector2i& position): _key(key), _position(position) {} const Key _key; const Vector2i _position; @@ -443,13 +439,13 @@ class GlutApplication::MouseEvent: public GlutApplication::InputEvent { }; /** @brief Button */ - inline Button button() const { return _button; } + constexpr Button button() const { return _button; } /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline MouseEvent(Button button, const Vector2i& position): _button(button), _position(position) {} + constexpr MouseEvent(Button button, const Vector2i& position): _button(button), _position(position) {} const Button _button; const Vector2i _position; @@ -465,10 +461,10 @@ class GlutApplication::MouseMoveEvent: public GlutApplication::InputEvent { public: /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline MouseMoveEvent(const Vector2i& position): _position(position) {} + constexpr MouseMoveEvent(const Vector2i& position): _position(position) {} const Vector2i _position; }; diff --git a/src/Platform/GlxApplication.h b/src/Platform/GlxApplication.h index d7a0dee80..d48975e01 100644 --- a/src/Platform/GlxApplication.h +++ b/src/Platform/GlxApplication.h @@ -57,10 +57,15 @@ to simplify porting. class GlxApplication: public AbstractXApplication { public: /** @copydoc GlutApplication::GlutApplication(const Arguments&) */ - inline explicit GlxApplication(const Arguments& arguments): AbstractXApplication(new GlxContextHandler, arguments) {} + explicit GlxApplication(const Arguments& arguments): AbstractXApplication(new GlxContextHandler, arguments) {} /** @copydoc GlutApplication::GlutApplication(const Arguments&, Configuration*) */ - inline explicit GlxApplication(const Arguments& arguments, Configuration* configuration): AbstractXApplication(new GlxContextHandler, arguments, configuration) {} + explicit GlxApplication(const Arguments& arguments, Configuration* configuration): AbstractXApplication(new GlxContextHandler, arguments, configuration) {} + + protected: + /* Nobody will need to have (and delete) GlxApplication*, thus this is + faster than public pure virtual destructor */ + ~GlxApplication() = default; }; /** @hideinitializer diff --git a/src/Platform/GlxContextHandler.h b/src/Platform/GlxContextHandler.h index 60494e0f9..4f53efcfa 100644 --- a/src/Platform/GlxContextHandler.h +++ b/src/Platform/GlxContextHandler.h @@ -56,17 +56,15 @@ class GlxContextHandler: public AbstractContextHandlerflags |= Flag::MouseLocked; } -NaClApplication::Configuration::Configuration(): _size(640, 480), _sampleCount(0) {} -NaClApplication::Configuration::~Configuration() = default; - }} diff --git a/src/Platform/NaClApplication.h b/src/Platform/NaClApplication.h index ac7e119f2..09772f9a8 100644 --- a/src/Platform/NaClApplication.h +++ b/src/Platform/NaClApplication.h @@ -102,8 +102,6 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public */ explicit NaClApplication(const Arguments& arguments, Configuration* configuration); - ~NaClApplication(); - /** @brief Whether the application runs fullscreen */ bool isFullscreen(); @@ -118,6 +116,10 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public bool setFullscreen(bool enabled); protected: + /* Nobody will need to have (and delete) NaClApplication*, thus this is + faster than public pure virtual destructor */ + ~NaClApplication(); + /** @copydoc GlutApplication::createContext() */ void createContext(Configuration* configuration); @@ -136,7 +138,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public void swapBuffers(); /** @copydoc GlutApplication::redraw() */ - inline void redraw() { flags |= Flag::Redraw; } + void redraw() { flags |= Flag::Redraw; } /*@}*/ @@ -166,9 +168,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public public: /** @brief Whether mouse is locked */ - inline bool isMouseLocked() const { - return flags & Flag::MouseLocked; - } + bool isMouseLocked() const { return flags & Flag::MouseLocked; } /** * @brief Enable or disable mouse locking @@ -218,13 +218,13 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public WillBeFullscreen = 1 << 4, MouseLocked = 1 << 5 }; - typedef Corrade::Containers::EnumSet Flags; + typedef Containers::EnumSet Flags; - inline void Graphics3DContextLost() override { + void Graphics3DContextLost() override { CORRADE_ASSERT(false, "NaClApplication: context unexpectedly lost", ); } - inline void MouseLockLost() override { + void MouseLockLost() override { flags &= ~Flag::MouseLocked; } @@ -257,11 +257,10 @@ class NaClApplication::Configuration { Configuration& operator=(Configuration&&) = delete; public: - explicit Configuration(); - ~Configuration(); + constexpr explicit Configuration(): _size(640, 480), _sampleCount(0) {} /** @brief Window size */ - inline Vector2i size() const { return _size; } + Vector2i size() const { return _size; } /** * @brief Set window size @@ -269,13 +268,13 @@ class NaClApplication::Configuration { * * Default is `{640, 480}`. */ - inline Configuration* setSize(const Vector2i& size) { + Configuration* setSize(const Vector2i& size) { _size = size; return this; } /** @brief Sample count */ - inline Int sampleCount() const { return _sampleCount; } + Int sampleCount() const { return _sampleCount; } /** * @brief Set sample count @@ -284,7 +283,7 @@ class NaClApplication::Configuration { * Default is `0`, thus no multisampling. See also * @ref Renderer::Feature "Renderer::Feature::Multisampling". */ - inline Configuration* setSampleCount(Int count) { + Configuration* setSampleCount(Int count) { _sampleCount = count; return this; } @@ -334,12 +333,10 @@ class NaClApplication::InputEvent { * * @see modifiers() */ - typedef Corrade::Containers::EnumSet Modifiers; - - inline virtual ~InputEvent() {} + typedef Containers::EnumSet Modifiers; /** @brief Modifiers */ - inline Modifiers modifiers() const { return _modifiers; } + constexpr Modifiers modifiers() const { return _modifiers; } /** * @brief Set event as accepted @@ -348,14 +345,16 @@ class NaClApplication::InputEvent { * propagated elsewhere (e.g. to the browser). By default is each * event ignored. */ - inline void setAccepted(bool accepted = true) { _accepted = accepted; } + void setAccepted(bool accepted = true) { _accepted = accepted; } /** @brief Whether the event is accepted */ - inline bool isAccepted() { return _accepted; } + constexpr bool isAccepted() const { return _accepted; } #ifndef DOXYGEN_GENERATING_OUTPUT protected: - inline InputEvent(Modifiers modifiers): _accepted(false), _modifiers(modifiers) {} + constexpr InputEvent(Modifiers modifiers): _accepted(false), _modifiers(modifiers) {} + + ~InputEvent() = default; #endif private: @@ -450,10 +449,10 @@ class NaClApplication::KeyEvent: public NaClApplication::InputEvent { }; /** @brief Key */ - inline Key key() const { return _key; } + constexpr Key key() const { return _key; } private: - inline KeyEvent(Key key, Modifiers modifiers): InputEvent(modifiers), _key(key) {} + constexpr KeyEvent(Key key, Modifiers modifiers): InputEvent(modifiers), _key(key) {} const Key _key; }; @@ -480,13 +479,13 @@ class NaClApplication::MouseEvent: public NaClApplication::InputEvent { }; /** @brief Button */ - inline Button button() const { return _button; } + constexpr Button button() const { return _button; } /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } private: - inline MouseEvent(Button button, const Vector2i& position, Modifiers modifiers): InputEvent(modifiers), _button(button), _position(position) {} + constexpr MouseEvent(Button button, const Vector2i& position, Modifiers modifiers): InputEvent(modifiers), _button(button), _position(position) {} const Button _button; const Vector2i _position; @@ -503,41 +502,37 @@ class NaClApplication::MouseMoveEvent: public NaClApplication::InputEvent { public: /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } /** * @brief Relative position * * Position relative to previous event. */ - inline Vector2i relativePosition() const { return _relativePosition; } + constexpr Vector2i relativePosition() const { return _relativePosition; } private: - inline MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition, Modifiers modifiers): InputEvent(modifiers), _position(position), _relativePosition(relativePosition) {} + constexpr MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition, Modifiers modifiers): InputEvent(modifiers), _position(position), _relativePosition(relativePosition) {} const Vector2i _position, _relativePosition; }; CORRADE_ENUMSET_OPERATORS(NaClApplication::Flags) -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class NaClModule: public pp::Module { public: - inline ~NaClModule() { - glTerminatePPAPI(); - } + ~NaClModule() { glTerminatePPAPI(); } - inline bool Init() override { + bool Init() override { return glInitializePPAPI(get_browser_interface()); } - inline pp::Instance* CreateInstance(PP_Instance instance) { + pp::Instance* CreateInstance(PP_Instance instance) { return new Application(instance); } }; } -#endif /** @hideinitializer @brief Entry point for NaCl application diff --git a/src/Platform/Sdl2Application.cpp b/src/Platform/Sdl2Application.cpp index 2470d6639..803928ece 100644 --- a/src/Platform/Sdl2Application.cpp +++ b/src/Platform/Sdl2Application.cpp @@ -24,8 +24,6 @@ #include "Sdl2Application.h" -#include - #include "Context.h" #include "ExtensionWrangler.h" @@ -127,57 +125,60 @@ Sdl2Application::~Sdl2Application() { } int Sdl2Application::exec() { - while(!(flags & Flag::Exit)) { - SDL_Event event; - - while(SDL_PollEvent(&event)) { - switch(event.type) { - case SDL_WINDOWEVENT: - switch(event.window.event) { - case SDL_WINDOWEVENT_RESIZED: - viewportEvent({event.window.data1, event.window.data2}); - flags |= Flag::Redraw; - break; - case SDL_WINDOWEVENT_EXPOSED: - flags |= Flag::Redraw; - break; - } break; - - case SDL_KEYDOWN: - case SDL_KEYUP: { - KeyEvent e(static_cast(event.key.keysym.sym), fixedModifiers(event.key.keysym.mod)); - event.type == SDL_KEYDOWN ? keyPressEvent(e) : keyReleaseEvent(e); - } break; + while(!(flags & Flag::Exit)) mainLoop(); + return 0; +} - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: { - MouseEvent e(static_cast(event.button.button), {event.button.x, event.button.y}); - event.type == SDL_MOUSEBUTTONDOWN ? mousePressEvent(e) : mouseReleaseEvent(e); +void Sdl2Application::mainLoop() { + SDL_Event event; + + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_WINDOWEVENT: + switch(event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + viewportEvent({event.window.data1, event.window.data2}); + flags |= Flag::Redraw; + break; + case SDL_WINDOWEVENT_EXPOSED: + flags |= Flag::Redraw; + break; } break; - case SDL_MOUSEWHEEL: - if(event.wheel.y != 0) { - MouseEvent e(event.wheel.y < 0 ? MouseEvent::Button::WheelUp : MouseEvent::Button::WheelDown, {event.wheel.x, event.wheel.y}); - mousePressEvent(e); - } break; - - case SDL_MOUSEMOTION: { - MouseMoveEvent e({event.motion.x, event.motion.y}, {event.motion.xrel, event.motion.yrel}); - mouseMoveEvent(e); - break; - } + case SDL_KEYDOWN: + case SDL_KEYUP: { + KeyEvent e(static_cast(event.key.keysym.sym), fixedModifiers(event.key.keysym.mod)); + event.type == SDL_KEYDOWN ? keyPressEvent(e) : keyReleaseEvent(e); + } break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { + MouseEvent e(static_cast(event.button.button), {event.button.x, event.button.y}); + event.type == SDL_MOUSEBUTTONDOWN ? mousePressEvent(e) : mouseReleaseEvent(e); + } break; + + case SDL_MOUSEWHEEL: + if(event.wheel.y != 0) { + MouseEvent e(event.wheel.y < 0 ? MouseEvent::Button::WheelUp : MouseEvent::Button::WheelDown, {event.wheel.x, event.wheel.y}); + mousePressEvent(e); + } break; - case SDL_QUIT: return 0; + case SDL_MOUSEMOTION: { + MouseMoveEvent e({event.motion.x, event.motion.y}, {event.motion.xrel, event.motion.yrel}); + mouseMoveEvent(e); + break; } - } - if(flags & Flag::Redraw) { - flags &= ~Flag::Redraw; - drawEvent(); - } else Corrade::Utility::sleep(5); + case SDL_QUIT: + flags |= Flag::Exit; + return; + } } - return 0; + if(flags & Flag::Redraw) { + flags &= ~Flag::Redraw; + drawEvent(); + } else SDL_WaitEvent(nullptr); } void Sdl2Application::setMouseLocked(bool enabled) { diff --git a/src/Platform/Sdl2Application.h b/src/Platform/Sdl2Application.h index 10733d3cb..06c5319db 100644 --- a/src/Platform/Sdl2Application.h +++ b/src/Platform/Sdl2Application.h @@ -34,8 +34,8 @@ #ifdef _WIN32 /* Windows version of SDL2 redefines main(), we don't want that */ #define SDL_MAIN_HANDLED #endif -#include -#include +#include +#include #include namespace Magnum { @@ -86,15 +86,17 @@ class Sdl2Application { /** @copydoc GlutApplication::GlutApplication(const Arguments&, Configuration*) */ explicit Sdl2Application(const Arguments& arguments, Configuration* configuration); - virtual ~Sdl2Application(); - /** @copydoc GlutApplication::exec() */ int exec(); /** @brief Exit application main loop */ - inline void exit() { flags |= Flag::Exit; } + void exit() { flags |= Flag::Exit; } protected: + /* Nobody will need to have (and delete) Sdl2Application*, thus this is + faster than public pure virtual destructor */ + virtual ~Sdl2Application(); + /** @copydoc GlutApplication::createContext() */ void createContext(Configuration* configuration); @@ -110,10 +112,10 @@ class Sdl2Application { virtual void drawEvent() = 0; /** @copydoc GlutApplication::swapBuffers() */ - inline void swapBuffers() { SDL_GL_SwapWindow(window); } + void swapBuffers() { SDL_GL_SwapWindow(window); } /** @copydoc GlutApplication::redraw() */ - inline void redraw() { flags |= Flag::Redraw; } + void redraw() { flags |= Flag::Redraw; } /*@}*/ @@ -135,9 +137,7 @@ class Sdl2Application { public: /** @brief Whether mouse is locked */ - inline bool isMouseLocked() const { - return SDL_GetRelativeMouseMode(); - } + bool isMouseLocked() const { return SDL_GetRelativeMouseMode(); } /** * @brief Enable or disable mouse locking @@ -170,10 +170,11 @@ class Sdl2Application { Exit = 1 << 1 }; - typedef Corrade::Containers::EnumSet Flags; + typedef Containers::EnumSet Flags; CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) void initialize(); + void mainLoop(); SDL_Window* window; SDL_GLContext context; @@ -218,7 +219,7 @@ class Sdl2Application::Configuration { * * @see setFlags() */ - typedef Corrade::Containers::EnumSet Flags; @@ -226,7 +227,7 @@ class Sdl2Application::Configuration { ~Configuration(); /** @brief Window title */ - inline std::string title() const { return _title; } + std::string title() const { return _title; } /** * @brief Set window title @@ -234,13 +235,13 @@ class Sdl2Application::Configuration { * * Default is `"Magnum SDL2 Application"`. */ - inline Configuration* setTitle(std::string title) { + Configuration* setTitle(std::string title) { _title = std::move(title); return this; } /** @brief Window size */ - inline Vector2i size() const { return _size; } + Vector2i size() const { return _size; } /** * @brief Set window size @@ -248,13 +249,13 @@ class Sdl2Application::Configuration { * * Default is `{800, 600}`. */ - inline Configuration* setSize(const Vector2i& size) { + Configuration* setSize(const Vector2i& size) { _size = size; return this; } /** @brief Window flags */ - inline Flags flags() const { return _flags; } + Flags flags() const { return _flags; } /** * @brief Set window flags @@ -262,13 +263,13 @@ class Sdl2Application::Configuration { * * Default is @ref Flag "Flag::Resizable". */ - inline Configuration* setFlags(const Flags flags) { + Configuration* setFlags(const Flags flags) { _flags = flags; return this; } /** @brief Sample count */ - inline Int sampleCount() const { return _sampleCount; } + Int sampleCount() const { return _sampleCount; } /** * @brief Set sample count @@ -277,7 +278,7 @@ class Sdl2Application::Configuration { * Default is `0`, thus no multisampling. See also * @ref Renderer::Feature "Renderer::Feature::Multisampling". */ - inline Configuration* setSampleCount(Int count) { + Configuration* setSampleCount(Int count) { _sampleCount = count; return this; } @@ -326,19 +327,19 @@ class Sdl2Application::InputEvent { * @see KeyEvent::modifiers(), MouseEvent::modifiers(), * MouseMoveEvent::modifiers() */ - typedef Corrade::Containers::EnumSet Modifiers; - - inline virtual ~InputEvent() {} + typedef Containers::EnumSet Modifiers; /** @copydoc GlutApplication::InputEvent::setAccepted() */ - inline void setAccepted(bool accepted = true) { _accepted = accepted; } + void setAccepted(bool accepted = true) { _accepted = accepted; } /** @copydoc GlutApplication::InputEvent::isAccepted() */ - inline bool isAccepted() { return _accepted; } + constexpr bool isAccepted() const { return _accepted; } #ifndef DOXYGEN_GENERATING_OUTPUT protected: - inline InputEvent(): _accepted(false) {} + constexpr explicit InputEvent(): _accepted(false) {} + + ~InputEvent() = default; #endif private: @@ -433,13 +434,13 @@ class Sdl2Application::KeyEvent: public Sdl2Application::InputEvent { }; /** @brief Key */ - inline Key key() const { return _key; } + constexpr Key key() const { return _key; } /** @brief Modifiers */ - inline Modifiers modifiers() const { return _modifiers; } + constexpr Modifiers modifiers() const { return _modifiers; } private: - inline KeyEvent(Key key, Modifiers modifiers): _key(key), _modifiers(modifiers) {} + constexpr KeyEvent(Key key, Modifiers modifiers): _key(key), _modifiers(modifiers) {} const Key _key; const Modifiers _modifiers; @@ -468,10 +469,10 @@ class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { }; /** @brief Button */ - inline Button button() const { return _button; } + constexpr Button button() const { return _button; } /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } /** * @brief Modifiers @@ -481,7 +482,7 @@ class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - inline MouseEvent(Button button, const Vector2i& position): _button(button), _position(position), modifiersLoaded(false) {} + constexpr MouseEvent(Button button, const Vector2i& position): _button(button), _position(position), modifiersLoaded(false) {} const Button _button; const Vector2i _position; @@ -499,14 +500,14 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { public: /** @brief Position */ - inline Vector2i position() const { return _position; } + constexpr Vector2i position() const { return _position; } /** * @brief Relative position * * Position relative to previous event. */ - inline Vector2i relativePosition() const { return _relativePosition; } + constexpr Vector2i relativePosition() const { return _relativePosition; } /** * @brief Modifiers @@ -516,7 +517,7 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - inline MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition): _position(position), _relativePosition(relativePosition), modifiersLoaded(false) {} + constexpr MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition): _position(position), _relativePosition(relativePosition), modifiersLoaded(false) {} const Vector2i _position, _relativePosition; bool modifiersLoaded; diff --git a/src/Platform/WindowlessGlxApplication.h b/src/Platform/WindowlessGlxApplication.h index c38cfb5a6..df11f2dda 100644 --- a/src/Platform/WindowlessGlxApplication.h +++ b/src/Platform/WindowlessGlxApplication.h @@ -79,8 +79,6 @@ class WindowlessGlxApplication { /** @copydoc GlutApplication::GlutApplication(const Arguments&, Configuration*) */ explicit WindowlessGlxApplication(const Arguments& arguments, Configuration* configuration); - ~WindowlessGlxApplication(); - /** * @brief Execute application * @return Value for returning from `main()`. @@ -88,6 +86,10 @@ class WindowlessGlxApplication { virtual int exec() = 0; protected: + /* Nobody will need to have (and delete) WindowlessGlxApplication*, + thus this is faster than public pure virtual destructor */ + ~WindowlessGlxApplication(); + /** @copydoc GlutApplication::createContext() */ void createContext(Configuration* configuration); diff --git a/src/Platform/XEglApplication.h b/src/Platform/XEglApplication.h index 2e4c07d98..c2c708b4e 100644 --- a/src/Platform/XEglApplication.h +++ b/src/Platform/XEglApplication.h @@ -57,10 +57,15 @@ to simplify porting. class XEglApplication: public AbstractXApplication { public: /** @copydoc GlutApplication::GlutApplication(const Arguments&) */ - inline explicit XEglApplication(const Arguments& arguments): AbstractXApplication(new EglContextHandler, arguments) {} + explicit XEglApplication(const Arguments& arguments): AbstractXApplication(new EglContextHandler, arguments) {} /** @copydoc GlutApplication::GlutApplication(const Arguments&, Configuration*) */ - inline explicit XEglApplication(const Arguments& arguments, Configuration* configuration): AbstractXApplication(new EglContextHandler, arguments, configuration) {} + explicit XEglApplication(const Arguments& arguments, Configuration* configuration): AbstractXApplication(new EglContextHandler, arguments, configuration) {} + + protected: + /* Nobody will need to have (and delete) XEglApplication*, thus this is + faster than public pure virtual destructor */ + ~XEglApplication() = default; }; /** @hideinitializer diff --git a/src/Platform/magnum-info.cpp b/src/Platform/magnum-info.cpp index 887adeb94..bba8a1687 100644 --- a/src/Platform/magnum-info.cpp +++ b/src/Platform/magnum-info.cpp @@ -34,7 +34,7 @@ class MagnumInfo: public Platform::WindowlessGlxApplication { public: explicit MagnumInfo(const Arguments& arguments); - inline int exec() override { return 0; } + int exec() override { return 0; } }; MagnumInfo::MagnumInfo(const Arguments& arguments): WindowlessGlxApplication(arguments) { @@ -89,7 +89,12 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): WindowlessGlxApplication(arg Debug() << "Vendor:" << c->vendorString(); Debug() << "Renderer:" << c->rendererString(); Debug() << "OpenGL version:" << c->version() << '(' + c->versionString() + ')'; - Debug() << "GLSL version:" << c->version() << '(' + c->shadingLanguageVersionString() + ')'; + + Debug() << "Supported GLSL versions:"; + const std::vector shadingLanguageVersions = c->shadingLanguageVersionStrings(); + for(const auto& version: shadingLanguageVersions) + Debug() << " " << version; + Debug() << ""; /* Get first future (not supported) version */ diff --git a/src/Primitives/Cylinder.h b/src/Primitives/Cylinder.h index ed38da5ae..0a08fcf2b 100644 --- a/src/Primitives/Cylinder.h +++ b/src/Primitives/Cylinder.h @@ -30,6 +30,7 @@ #include +#include "Magnum.h" #include "Primitives/magnumPrimitivesVisibility.h" #include "Trade/Trade.h" @@ -53,7 +54,7 @@ class MAGNUM_PRIMITIVES_EXPORT Cylinder { }; /** @brief %Flags */ - typedef Corrade::Containers::EnumSet Flags; + typedef Containers::EnumSet Flags; /** * @brief Solid cylinder diff --git a/src/Primitives/Icosphere.h b/src/Primitives/Icosphere.h index 76a8197a4..2a1158be2 100644 --- a/src/Primitives/Icosphere.h +++ b/src/Primitives/Icosphere.h @@ -29,8 +29,8 @@ */ #include "Math/Vector3.h" +#include "MeshTools/RemoveDuplicates.h" #include "MeshTools/Subdivide.h" -#include "MeshTools/Clean.h" #include "Trade/MeshData3D.h" #include "Primitives/magnumPrimitivesVisibility.h" @@ -70,7 +70,7 @@ template class Icosphere { for(std::size_t i = 0; i != subdivisions; ++i) MeshTools::subdivide(*indices(), *normals(0), interpolator); - MeshTools::clean(*indices(), *normals(0)); + MeshTools::removeDuplicates(*indices(), *normals(0)); positions(0)->assign(normals(0)->begin(), normals(0)->end()); } diff --git a/src/Primitives/Test/CapsuleTest.cpp b/src/Primitives/Test/CapsuleTest.cpp index 56b5bc569..33b3da9f2 100644 --- a/src/Primitives/Test/CapsuleTest.cpp +++ b/src/Primitives/Test/CapsuleTest.cpp @@ -32,11 +32,9 @@ #include "Trade/MeshData3D.h" #include "Primitives/Capsule.h" -using Corrade::TestSuite::Compare::Container; - namespace Magnum { namespace Primitives { namespace Test { -class CapsuleTest: public Corrade::TestSuite::Tester { +class CapsuleTest: public TestSuite::Tester { public: CapsuleTest(); @@ -76,7 +74,7 @@ void CapsuleTest::withoutTextureCoords() { {-0.612372f, 1.20711f, -0.353553f}, {0.0f, 1.5f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*capsule.normals(0), (std::vector{ {0.0f, -1.0f, 0.0f}, @@ -102,7 +100,7 @@ void CapsuleTest::withoutTextureCoords() { {-0.612372f, 0.707107f, -0.353553f}, {0.0f, 1.0f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*capsule.indices(), (std::vector{ 0, 2, 1, 0, 3, 2, 0, 1, 3, @@ -111,7 +109,7 @@ void CapsuleTest::withoutTextureCoords() { 7, 8, 11, 7, 11, 10, 8, 9, 12, 8, 12, 11, 9, 7, 10, 9, 10, 12, 10, 11, 14, 10, 14, 13, 11, 12, 15, 11, 15, 14, 12, 10, 13, 12, 13, 15, 13, 14, 16, 14, 15, 16, 15, 13, 16 - }), Container); + }), TestSuite::Compare::Container); } void CapsuleTest::withTextureCoords() { @@ -146,7 +144,7 @@ void CapsuleTest::withTextureCoords() { {0.0f, 1.20711f, 0.707107f}, {0.0f, 1.5f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*capsule.textureCoords2D(0), (std::vector{ {0.5f, 0.0f}, @@ -177,7 +175,7 @@ void CapsuleTest::withTextureCoords() { {1.0f, 0.833333f}, {0.5f, 1.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*capsule.indices(), (std::vector{ 0, 2, 1, 0, 3, 2, 0, 4, 3, @@ -186,7 +184,7 @@ void CapsuleTest::withTextureCoords() { 9, 10, 14, 9, 14, 13, 10, 11, 15, 10, 15, 14, 11, 12, 16, 11, 16, 15, 13, 14, 18, 13, 18, 17, 14, 15, 19, 14, 19, 18, 15, 16, 20, 15, 20, 19, 17, 18, 21, 18, 19, 21, 19, 20, 21 - }), Container); + }), TestSuite::Compare::Container); } }}} diff --git a/src/Primitives/Test/CircleTest.cpp b/src/Primitives/Test/CircleTest.cpp index da396522f..58c763af2 100644 --- a/src/Primitives/Test/CircleTest.cpp +++ b/src/Primitives/Test/CircleTest.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace Primitives { namespace Test { -class CircleTest: public Corrade::TestSuite::Tester { +class CircleTest: public TestSuite::Tester { public: explicit CircleTest(); diff --git a/src/Primitives/Test/CylinderTest.cpp b/src/Primitives/Test/CylinderTest.cpp index ef861c206..f999cde89 100644 --- a/src/Primitives/Test/CylinderTest.cpp +++ b/src/Primitives/Test/CylinderTest.cpp @@ -29,11 +29,9 @@ #include "Primitives/Cylinder.h" #include "Trade/MeshData3D.h" -using Corrade::TestSuite::Compare::Container; - namespace Magnum { namespace Primitives { namespace Test { -class CylinderTest: public Corrade::TestSuite::Tester { +class CylinderTest: public TestSuite::Tester { public: CylinderTest(); @@ -61,7 +59,7 @@ void CylinderTest::withoutAnything() { {0.0f, 1.5f, 1.0f}, {0.866025f, 1.5f, -0.5f}, {-0.866025f, 1.5f, -0.5f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*cylinder.normals(0), (std::vector{ {0.0f, 0.0f, 1.0f}, @@ -75,12 +73,12 @@ void CylinderTest::withoutAnything() { {0.0f, 0.0f, 1.0f}, {0.866025f, 0.0f, -0.5f}, {-0.866025f, 0.0f, -0.5f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*cylinder.indices(), (std::vector{ 0, 1, 4, 0, 4, 3, 1, 2, 5, 1, 5, 4, 2, 0, 3, 2, 3, 5, 3, 4, 7, 3, 7, 6, 4, 5, 8, 4, 8, 7, 5, 3, 6, 5, 6, 8 - }), Container); + }), TestSuite::Compare::Container); } void CylinderTest::withTextureCoordsAndCaps() { @@ -115,7 +113,7 @@ void CylinderTest::withTextureCoordsAndCaps() { {0.0f, 1.5f, 1.0f}, {0.0f, 1.5f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*cylinder.normals(0), (std::vector{ {0.0f, -1.0f, 0.0f}, @@ -146,7 +144,7 @@ void CylinderTest::withTextureCoordsAndCaps() { {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*cylinder.textureCoords2D(0), (std::vector{ {0.5f, 0.0f}, @@ -177,14 +175,14 @@ void CylinderTest::withTextureCoordsAndCaps() { {1.0f, 0.8f}, {0.5f, 1.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*cylinder.indices(), (std::vector{ 0, 2, 1, 0, 3, 2, 0, 4, 3, 1, 2, 6, 1, 6, 5, 2, 3, 7, 2, 7, 6, 3, 4, 8, 3, 8, 7, 5, 6, 10, 5, 10, 9, 6, 7, 11, 6, 11, 10, 7, 8, 12, 7, 12, 11, 17, 18, 21, 18, 19, 21, 19, 20, 21 - }), Container); + }), TestSuite::Compare::Container); } }}} diff --git a/src/Primitives/Test/UVSphereTest.cpp b/src/Primitives/Test/UVSphereTest.cpp index 93cb2ff1f..9403d79ff 100644 --- a/src/Primitives/Test/UVSphereTest.cpp +++ b/src/Primitives/Test/UVSphereTest.cpp @@ -29,11 +29,9 @@ #include "Primitives/UVSphere.h" #include "Trade/MeshData3D.h" -using Corrade::TestSuite::Compare::Container; - namespace Magnum { namespace Primitives { namespace Test { -class UVSphereTest: public Corrade::TestSuite::Tester { +class UVSphereTest: public TestSuite::Tester { public: UVSphereTest(); @@ -61,7 +59,7 @@ void UVSphereTest::withoutTextureCoords() { {-0.75f, 0.5f, -0.433013f}, {0.0f, 1.0f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*sphere.normals(0), (std::vector{ {0.0f, -1.0f, 0.0f}, @@ -75,13 +73,13 @@ void UVSphereTest::withoutTextureCoords() { {-0.75f, 0.5f, -0.433013f}, {0.0f, 1.0f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*sphere.indices(), (std::vector{ 0, 2, 1, 0, 3, 2, 0, 1, 3, 1, 2, 5, 1, 5, 4, 2, 3, 6, 2, 6, 5, 3, 1, 4, 3, 4, 6, 4, 5, 7, 5, 6, 7, 6, 4, 7 - }), Container); + }), TestSuite::Compare::Container); } void UVSphereTest::withTextureCoords() { @@ -101,7 +99,7 @@ void UVSphereTest::withTextureCoords() { {0.0f, 0.5f, 0.866025f}, {0.0f, 1.0f, 0.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*sphere.textureCoords2D(0), (std::vector{ {0.5f, 0.0f}, @@ -117,13 +115,13 @@ void UVSphereTest::withTextureCoords() { {1.0f, 0.666667f}, {0.5f, 1.0f} - }), Container); + }), TestSuite::Compare::Container); CORRADE_COMPARE_AS(*sphere.indices(), (std::vector{ 0, 2, 1, 0, 3, 2, 0, 4, 3, 1, 2, 6, 1, 6, 5, 2, 3, 7, 2, 7, 6, 3, 4, 8, 3, 8, 7, 5, 6, 9, 6, 7, 9, 7, 8, 9 - }), Container); + }), TestSuite::Compare::Container); } }}} diff --git a/src/Query.cpp b/src/Query.cpp index c53d02fc9..ac0f251fa 100644 --- a/src/Query.cpp +++ b/src/Query.cpp @@ -24,12 +24,17 @@ #include "Query.h" +#include + namespace Magnum { -AbstractQuery::AbstractQuery() { +AbstractQuery::AbstractQuery(): target() { /** @todo Get some extension wrangler instead to avoid undeclared glGenQueries() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glGenQueries(1, &_id); + #else + CORRADE_INTERNAL_ASSERT(false); + //glGenQueriesEXT(1, &_id); #endif } @@ -37,106 +42,124 @@ AbstractQuery::~AbstractQuery() { /** @todo Get some extension wrangler instead to avoid undeclared glGenQueries() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glDeleteQueries(1, &_id); + #else + CORRADE_INTERNAL_ASSERT(false); + //glDeleteQueriesEXT(1, &_id); #endif } bool AbstractQuery::resultAvailable() { + CORRADE_ASSERT(!target, "AbstractQuery::resultAvailable(): the query is currently running", false); + /** @todo Re-enable when extension wrangler is available for ES */ - #ifndef MAGNUM_TARGET_GLES2 GLuint result; + #ifndef MAGNUM_TARGET_GLES2 glGetQueryObjectuiv(_id, GL_QUERY_RESULT_AVAILABLE, &result); - return result == GL_TRUE; #else - return false; + CORRADE_INTERNAL_ASSERT(false); + //glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT_AVAILABLE, &result); #endif + return result == GL_TRUE; } +#ifndef DOXYGEN_GENERATING_OUTPUT template<> bool AbstractQuery::result() { + CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {}); + /** @todo Re-enable when extension wrangler is available for ES */ - #ifndef MAGNUM_TARGET_GLES2 GLuint result; + #ifndef MAGNUM_TARGET_GLES2 glGetQueryObjectuiv(_id, GL_QUERY_RESULT, &result); - return result == GL_TRUE; #else - return false; + CORRADE_INTERNAL_ASSERT(false); + //glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT, &result); #endif + return result == GL_TRUE; } template<> UnsignedInt AbstractQuery::result() { + CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {}); + /** @todo Re-enable when extension wrangler is available for ES */ - #ifndef MAGNUM_TARGET_GLES2 UnsignedInt result; + #ifndef MAGNUM_TARGET_GLES2 glGetQueryObjectuiv(_id, GL_QUERY_RESULT, &result); - return result; #else - return 0; + CORRADE_INTERNAL_ASSERT(false); + //glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT, &result); #endif + return result; } -#ifndef MAGNUM_TARGET_GLES +#ifndef MAGNUM_TARGET_GLES3 template<> Int AbstractQuery::result() { + CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {}); + + /** @todo Re-enable when extension wrangler is available for ES */ Int result; + #ifndef MAGNUM_TARGET_GLES2 glGetQueryObjectiv(_id, GL_QUERY_RESULT, &result); + #else + CORRADE_INTERNAL_ASSERT(false); + //glGetQueryObjectivEXT(_id, GL_QUERY_RESULT, &result); + #endif return result; } template<> UnsignedLong AbstractQuery::result() { + CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {}); + + /** @todo Re-enable when extension wrangler is available for ES */ UnsignedLong result; + #ifndef MAGNUM_TARGET_GLES2 glGetQueryObjectui64v(_id, GL_QUERY_RESULT, &result); + #else + CORRADE_INTERNAL_ASSERT(false); + //glGetQueryObjectui64vEXT(_id, GL_QUERY_RESULT, &result); + #endif return result; } template<> Long AbstractQuery::result() { + CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {}); + + /** @todo Re-enable when extension wrangler is available for ES */ Long result; + #ifndef MAGNUM_TARGET_GLES2 glGetQueryObjecti64v(_id, GL_QUERY_RESULT, &result); + #else + CORRADE_INTERNAL_ASSERT(false); + //glGetQueryObjecti64vEXT(_id, GL_QUERY_RESULT, &result); + #endif return result; } #endif - -#ifndef MAGNUM_TARGET_GLES2 -Query::Query(): target(nullptr) {} - -Query::~Query() { delete target; } - -void Query::begin(Query::Target target) { - glBeginQuery(static_cast(target), id()); - this->target = new Target(target); -} - -void Query::end() { - if(!target) return; - - glEndQuery(static_cast(*target)); - delete target; - target = nullptr; -} #endif -SampleQuery::SampleQuery(): target(nullptr) {} +void AbstractQuery::begin(GLenum target) { + CORRADE_ASSERT(!this->target, "AbstractQuery::begin(): the query is already running", ); -SampleQuery::~SampleQuery() { delete target; } - -void SampleQuery::begin(SampleQuery::Target target) { /** @todo Re-enable when extension wrangler is available for ES */ #ifndef MAGNUM_TARGET_GLES2 - glBeginQuery(static_cast(target), id()); + glBeginQuery(this->target = target, id()); + #else + CORRADE_INTERNAL_ASSERT(false); + static_cast(target); + //glBeginQueryEXT(this->target = target, id()); #endif - this->target = new Target(target); } -void SampleQuery::end() { - if(!target) return; +void AbstractQuery::end() { + CORRADE_ASSERT(target, "AbstractQuery::end(): the query is not running", ); /** @todo Re-enable when extension wrangler is available for ES */ #ifndef MAGNUM_TARGET_GLES2 - glEndQuery(static_cast(*target)); + glEndQuery(target); + #else + CORRADE_INTERNAL_ASSERT(false); + //glEndQueryEXT(target); #endif - delete target; - target = nullptr; + target = {}; } -#ifndef MAGNUM_TARGET_GLES -TimeQuery::TimeQuery() = default; -#endif - } diff --git a/src/Query.h b/src/Query.h index 11f597ff9..7433d30fe 100644 --- a/src/Query.h +++ b/src/Query.h @@ -25,11 +25,14 @@ */ /** @file - * @brief Class Magnum::AbstractQuery, Magnum::Query, Magnum::SampleQuery, Magnum::TimeQuery + * @brief Class Magnum::AbstractQuery, Magnum::PrimitiveQuery, Magnum::SampleQuery, Magnum::TimeQuery */ -#include "Magnum.h" +#include + #include "OpenGL.h" +#include "Types.h" +#include "magnumConfigure.h" #include "magnumVisibility.h" namespace Magnum { @@ -37,12 +40,14 @@ namespace Magnum { /** @brief Base class for queries -See Query, SampleQuery, TimeQuery documentation for more information. +See PrimitiveQuery, SampleQuery and TimeQuery documentation for more +information. @todo Support for AMD's query buffer (@extension{AMD,query_buffer_object}) @requires_gles30 %Extension @es_extension{EXT,occlusion_query_boolean} */ class MAGNUM_EXPORT AbstractQuery { public: + #ifdef DOXYGEN_GENERATING_OUTPUT /** * @brief Constructor * @@ -57,10 +62,11 @@ class MAGNUM_EXPORT AbstractQuery { * Deletes assigned OpenGL query. * @see @fn_gl{DeleteQueries} */ - virtual ~AbstractQuery() = 0; + ~AbstractQuery(); + #endif /** @brief OpenGL query ID */ - inline GLuint id() const { return _id; } + GLuint id() const { return _id; } /** * @brief Whether the result is available @@ -80,20 +86,38 @@ class MAGNUM_EXPORT AbstractQuery { * @requires_gl33 %Extension @extension{ARB,timer_query} (result type * @ref Magnum::UnsignedInt "UnsignedInt" and @ref Magnum::Long * "Long") - * @requires_gl Result types @ref Magnum::Int "Int", @ref Magnum::UnsignedLong "UnsignedLong" - * and @ref Magnum::Long "Long" are not available in OpenGL ES. + * @requires_es_extension %Extension @es_extension{EXT,disjoint_timer_query} + * for result types @ref Magnum::Int "Int", @ref Magnum::UnsignedLong "UnsignedLong" + * @ref Magnum::Long "Long". */ template T result(); + /** + * @brief End query + * + * The result can be then retrieved by calling result(). + * @see @fn_gl{EndQuery} + */ + void end(); + + protected: + #ifndef DOXYGEN_GENERATING_OUTPUT + explicit AbstractQuery(); + ~AbstractQuery(); + #endif + + void begin(GLenum target); + private: GLuint _id; + GLenum target; }; #ifndef DOXYGEN_GENERATING_OUTPUT template<> bool MAGNUM_EXPORT AbstractQuery::result(); template<> UnsignedInt MAGNUM_EXPORT AbstractQuery::result(); -#ifndef MAGNUM_TARGET_GLES +#ifndef MAGNUM_TARGET_GLES3 template<> Int MAGNUM_EXPORT AbstractQuery::result(); template<> UnsignedLong MAGNUM_EXPORT AbstractQuery::result(); template<> Long MAGNUM_EXPORT AbstractQuery::result(); @@ -102,7 +126,7 @@ template<> Long MAGNUM_EXPORT AbstractQuery::result(); #ifndef MAGNUM_TARGET_GLES2 /** -@brief %Query for primitives and elapsed time +@brief Query for primitives and elapsed time Queries count of generated primitives from vertex shader, geometry shader or transform feedback and elapsed time. Example usage: @@ -122,10 +146,11 @@ UnsignedInt primitiveCount = q.result(); @endcode @requires_gl30 %Extension @extension{EXT,transform_feedback} @requires_gles30 Only sample queries are available on OpenGL ES 2.0. +@todo glBeginQueryIndexed */ -class MAGNUM_EXPORT Query: public AbstractQuery { +class PrimitiveQuery: public AbstractQuery { public: - /** @brief %Query target */ + /** @brief Query target */ enum Target: GLenum { #ifndef MAGNUM_TARGET_GLES /** @@ -139,47 +164,22 @@ class MAGNUM_EXPORT Query: public AbstractQuery { /** Count of primitives written to transform feedback buffer. */ TransformFeedbackPrimitivesWritten = GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN - - #ifndef MAGNUM_TARGET_GLES - , - - /** - * Elapsed time - * @requires_gl33 %Extension @extension{ARB,timer_query} - * @requires_gl Only transform feedback query is available in - * OpenGL ES. - */ - TimeElapsed = GL_TIME_ELAPSED - #endif }; - explicit Query(); - - ~Query(); - /** * @brief Begin query * * Begins counting of given @p target until end() is called. * @see @fn_gl{BeginQuery} */ - void begin(Target target); - - /** - * @brief End query - * - * The result can be then retrieved by calling result(). - * @see @fn_gl{EndQuery} - */ - void end(); - - private: - Target* target; + void begin(Target target) { + AbstractQuery::begin(GLenum(target)); + } }; #endif /** -@brief %Query for samples +@brief Query for samples Queries count of samples passed from fragment shader or boolean value indicating whether any samples passed. Can be used for example for conditional @@ -214,9 +214,9 @@ q.endConditionalRender(); @endcode @requires_gles30 %Extension @es_extension{EXT,occlusion_query_boolean} */ -class MAGNUM_EXPORT SampleQuery: public AbstractQuery { +class SampleQuery: public AbstractQuery { public: - /** @brief %Query target */ + /** @brief Query target */ enum Target: GLenum { #ifndef MAGNUM_TARGET_GLES /** @@ -284,15 +284,10 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { }; #endif - explicit SampleQuery(); - - ~SampleQuery(); - - /** @copydoc Query::begin() */ - void begin(Target target); - - /** @copydoc Query::end() */ - void end(); + /** @copydoc PrimitiveQuery::begin() */ + void begin(Target target) { + AbstractQuery::begin(GLenum(target)); + } #ifndef MAGNUM_TARGET_GLES /** @@ -302,7 +297,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { * @requires_gl30 %Extension @extension{NV,conditional_render} * @requires_gl Conditional rendering is not available in OpenGL ES. */ - inline void beginConditionalRender(ConditionalRenderMode mode) { + void beginConditionalRender(ConditionalRenderMode mode) { glBeginConditionalRender(id(), static_cast(mode)); } @@ -313,25 +308,21 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { * @requires_gl30 %Extension @extension{NV,conditional_render} * @requires_gl Conditional rendering is not available in OpenGL ES. */ - inline void endConditionalRender() { + void endConditionalRender() { glEndConditionalRender(); } #endif - - private: - Target* target; }; -#ifndef MAGNUM_TARGET_GLES +#ifndef MAGNUM_TARGET_GLES3 /** -@brief %Query for elapsed time +@brief Query for elapsed time -Queries timestamp after all previous OpenGL calls have been processed. It is -similar to @ref Query::Target "Query::Target::TimeElapsed" query, but this -query just retrieves timestamp, not time duration between Query::begin() and -Query::end() calls. Example usage, compared to @ref Query::Target "Query::Target::TimeElapsed": +Queries timestamp after all previous OpenGL calls have been processed. It can +query either duration of sequence of commands or absolute timestamp. Example +usage of both methods: @code -Query q1, q2; +TimeQuery q1, q2; q1.begin(Query::Target::TimeElapsed); // rendering... q1.end(); @@ -352,22 +343,42 @@ UnsignedInt tmp = q2.result(); UnsignedInt timeElapsed1 = tmp-q1.result(); UnsignedInt timeElapsed2 = q3.result()-tmp; @endcode -Using this query results in fewer OpenGL calls when doing more measures. +Using the latter results in fewer OpenGL calls when doing more measures. @requires_gl33 %Extension @extension{ARB,timer_query} -@requires_gl Timer query is not available in OpenGL ES. +@requires_es_extension %Extension @es_extension{EXT,disjoint_timer_query} @todo timestamp with glGet + example usage +@todo @es_extension{EXT,disjoint_timer_query} -- GL_GPU_DISJOINT_EXT support? where? */ class TimeQuery: public AbstractQuery { public: - explicit TimeQuery(); + /** @brief Query target */ + enum class Target: GLenum { + /** Elapsed time */ + #ifndef MAGNUM_TARGET_GLES + TimeElapsed = GL_TIME_ELAPSED + #else + TimeElapsed = GL_TIME_ELAPSED_EXT + #endif + }; /** * @brief Query timestamp * * @see @fn_gl{QueryCounter} with @def_gl{TIMESTAMP} */ - inline void timestamp() { + void timestamp() { + /** @todo Enable when extension wrangler for ES is available */ + #ifndef MAGNUM_TARGET_GLES glQueryCounter(id(), GL_TIMESTAMP); + #else + //glQueryCounterEXT(id(), GL_TIMESTAMP); + CORRADE_INTERNAL_ASSERT(false); + #endif + } + + /** @copydoc PrimitiveQuery::begin() */ + void begin(Target target) { + AbstractQuery::begin(GLenum(target)); } }; #endif diff --git a/src/Renderbuffer.cpp b/src/Renderbuffer.cpp index 0ca1a724c..36237aa0b 100644 --- a/src/Renderbuffer.cpp +++ b/src/Renderbuffer.cpp @@ -33,6 +33,12 @@ namespace Magnum { Renderbuffer::StorageImplementation Renderbuffer::storageImplementation = &Renderbuffer::storageImplementationDefault; +Renderbuffer::StorageMultisampleImplementation Renderbuffer::storageMultisampleImplementation = + #ifndef MAGNUM_TARGET_GLES2 + &Renderbuffer::storageMultisampleImplementationDefault; + #else + nullptr; + #endif Renderbuffer::~Renderbuffer() { /* If bound, remove itself from state */ @@ -57,21 +63,57 @@ void Renderbuffer::initializeContextBasedFunctionality(Context* context) { 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(Renderbuffer::InternalFormat internalFormat, const Vector2i& size) { +void Renderbuffer::storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size) { bind(); glRenderbufferStorage(GL_RENDERBUFFER, GLenum(internalFormat), size.x(), size.y()); } #ifndef MAGNUM_TARGET_GLES -void Renderbuffer::storageImplementationDSA(Renderbuffer::InternalFormat internalFormat, const Vector2i& size) { +void Renderbuffer::storageImplementationDSA(RenderbufferFormat internalFormat, const Vector2i& size) { glNamedRenderbufferStorageEXT(_id, GLenum(internalFormat), size.x(), size.y()); } #endif +/** @todo Enable when extension wrangler for ES is done */ + +#ifndef MAGNUM_TARGET_GLES2 +void Renderbuffer::storageMultisampleImplementationDefault(const GLsizei samples, const RenderbufferFormat internalFormat, const Vector2i& size) { + bind(); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GLenum(internalFormat), size.x(), size.y()); +} +#else +void Renderbuffer::storageMultisampleImplementationANGLE(GLsizei, RenderbufferFormat, const Vector2i&) { + CORRADE_INTERNAL_ASSERT(false); + //glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, samples, internalFormat, size.x(), size.y()); +} + +void Renderbuffer::storageMultisampleImplementationNV(GLsizei, RenderbufferFormat, const Vector2i&) { + CORRADE_INTERNAL_ASSERT(false); + //glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, samples, internalFormat, size.x(), size.y()); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void Renderbuffer::storageMultisampleImplementationDSA(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size) { + glNamedRenderbufferStorageMultisampleEXT(_id, samples, GLenum(internalFormat), size.x(), size.y()); +} +#endif + } diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index 58f1bcd3e..f35ac0bac 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -60,485 +60,13 @@ class MAGNUM_EXPORT Renderbuffer { Renderbuffer& operator=(Renderbuffer&&) = delete; public: - /** - * @brief Internal format - * - * @see setStorage() - * @todo RGB, RGB8 ES only (ES3 + @es_extension{OES,rgb8_rgba8}) - */ - enum class InternalFormat: GLenum { - #ifndef MAGNUM_TARGET_GLES - /** - * Red component, normalized unsigned, size implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::Renderbuffer::InternalFormat "InternalFormat::R8". - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Use exactly specified format in OpenGL ES instead. - */ - Red = GL_RED, - #endif - - /** - * Red component, normalized unsigned byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} - */ - #ifndef MAGNUM_TARGET_GLES2 - R8 = GL_R8, - #else - R8 = GL_R8_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Red and green component, normalized unsigned, size - * implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::Renderbuffer::InternalFormat "InternalFormat::RG8". - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Use exactly specified format in OpenGL ES instead. - */ - RG = GL_RG, - #endif - - /** - * Red and green component, each normalized unsigned byte. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} - */ - #ifndef MAGNUM_TARGET_GLES2 - RG8 = GL_RG8, - #else - RG8 = GL_RG8_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * RGBA, normalized unsigned, size implementation-dependent. - * @deprecated Prefer to use the exactly specified version of this - * format, e.g. @ref Magnum::Renderbuffer::InternalFormat "InternalFormat::RGBA8". - * @requires_gl Use exactly specified format in OpenGL ES 2.0 - * instead. - */ - RGBA = GL_RGBA, - #endif - - /** - * RGBA, each component normalized unsigned byte. - * @requires_gles30 %Extension @es_extension{ARM,rgba8} or - * @es_extension{OES,rgb8_rgba8} - */ - #ifndef MAGNUM_TARGET_GLES2 - RGBA8 = GL_RGBA8, - #else - RGBA8 = GL_RGBA8_OES, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Red component, normalized unsigned short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - R16 = GL_R16, - - /** - * Red and green component, each normalized unsigned short. - * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RG16 = GL_RG16, - - /** - * RGB, each component normalized unsigned short. - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RGB16 = GL_RGB16, - - /** - * RGBA, each component normalized unsigned short. - * @requires_gl Only byte-sized normalized formats are available - * in OpenGL ES. - */ - RGBA16 = GL_RGBA16, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Red component, non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R8UI = GL_R8UI, - - /** - * Red and green component, each non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG8UI = GL_RG8UI, - - /** - * RGBA, each component non-normalized unsigned byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA8UI = GL_RGBA8UI, - - /** - * Red component, non-normalized signed byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R8I = GL_R8I, - - /** - * Red and green component, each non-normalized signed byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG8I = GL_RG8I, - - /** - * RGBA, each component non-normalized signed byte. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA8I = GL_RGBA8I, - - /** - * Red component, non-normalized unsigned short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R16UI = GL_R16UI, - - /** - * Red and green component, each non-normalized unsigned short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG16UI = GL_RG16UI, - - /** - * RGBA, each component non-normalized unsigned short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA16UI = GL_RGBA16UI, - - /** - * Red component, non-normalized signed short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R16I = GL_R16I, - - /** - * Red and green component, each non-normalized signed short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG16I = GL_RG16I, - - /** - * RGBA, each component non-normalized signed short. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA16I = GL_RGBA16I, - - /** - * Red component, non-normalized unsigned int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R32UI = GL_R32UI, - - /** - * Red and green component, each non-normalized unsigned int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG32UI = GL_RG32UI, - - /** - * RGBA, each component non-normalized unsigned int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA32UI = GL_RGBA32UI, - - /** - * Red component, non-normalized signed int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - R32I = GL_R32I, - - /** - * Red and green component, each non-normalized signed int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RG32I = GL_RG32I, - - /** - * RGBA, each component non-normalized signed int. - * @requires_gl30 %Extension @extension{EXT,texture_integer} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGBA32I = GL_RGBA32I, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Red component, half float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gl Only (non)normalized integral formats are - * available in OpenGL ES. - */ - R16F = GL_R16F, - - /** - * Red and green component, each half float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gl Only (non)normalized integral formats are - * available in OpenGL ES. - */ - RG16F = GL_RG16F, - - /** - * RGBA, each component half float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gl Only (non)normalized integral formats are - * available in OpenGL ES. - */ - RGBA16F = GL_RGBA16F, - - /** - * Red component, float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gl Only (non)normalized integral formats are - * available in OpenGL ES. - */ - R32F = GL_R32F, - - /** - * Red and green component, each float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gl Only (non)normalized integral formats are - * available in OpenGL ES. - */ - RG32F = GL_RG32F, - - /** - * RGBA, each component float. - * @requires_gl30 %Extension @extension{ARB,texture_float} - * @requires_gl Only (non)normalized integral formats are - * available in OpenGL ES. - */ - RGBA32F = GL_RGBA32F, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * RGBA, normalized unsigned, each RGB component 10bit, alpha 2bit. - * @requires_gles30 Usable only as internal texture format in OpenGL - * ES 2.0, see @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::RGB10A2". - */ - RGB10A2 = GL_RGB10_A2, - - /** - * RGBA, non-normalized unsigned, each RGB component 10bit, alpha 2bit. - * @requires_gl33 %Extension @extension{ARB,texture_rgb10_a2ui} - * @requires_gles30 Only normalized integral formats are available - * in OpenGL ES 2.0. - */ - RGB10A2UI = GL_RGB10_A2UI, - #endif - - /** RGBA, normalized unsigned, each RGB component 5bit, alpha 1bit. */ - RGB5A1 = GL_RGB5_A1, - - /** RGBA, normalized unsigned, each component 4bit. */ - RGBA4 = GL_RGBA4, - - #ifndef MAGNUM_TARGET_GLES - /** - * RGB, float, red and green 11bit, blue 10bit. - * @requires_gl30 %Extension @extension{EXT,packed_float} - * @requires_gl Usable only as internal texture format in OpenGL - * ES, see @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::R11FG11FB10F". - */ - R11FG11FB10F = GL_R11F_G11F_B10F, - #endif - - /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is - GL_ARB_ES2_compatibility */ - #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT) - /** RGB, normalized unsigned, red and blue 5bit, green 6bit. */ - RGB565 = GL_RGB565, - #endif - - /** - * sRGBA, each component normalized unsigned byte. - * @requires_gles30 %Extension @es_extension{EXT,sRGB} - */ - #ifndef MAGNUM_TARGET_GLES2 - SRGB8Alpha8 = GL_SRGB8_ALPHA8, - #else - SRGB8Alpha8 = GL_SRGB8_ALPHA8_EXT, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Depth component, size implementation-dependent. - * @todo is this allowed in core? - * @deprecated Prefer to use exactly specified version of this - * format, e.g. @ref Magnum::Renderbuffer::InternalFormat "InternalFormat::DepthComponent16". - * @requires_gl Use exactly specified format in OpenGL ES instead. - */ - DepthComponent = GL_DEPTH_COMPONENT, - #endif - - /** Depth component, 16bit. */ - DepthComponent16 = GL_DEPTH_COMPONENT16, - - /** - * Depth component, 24bit. - * @requires_gles30 %Extension @es_extension{OES,depth24} - */ - #ifndef MAGNUM_TARGET_GLES2 - DepthComponent24 = GL_DEPTH_COMPONENT24, - #else - DepthComponent24 = GL_DEPTH_COMPONENT24_OES, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * Depth component, 32bit. - * @requires_es_extension %Extension @es_extension{OES,depth32} - */ - #ifndef MAGNUM_TARGET_GLES - DepthComponent32 = GL_DEPTH_COMPONENT32, - #else - DepthComponent32 = GL_DEPTH_COMPONENT32_OES, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * Depth component, 32bit float. - * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} - * @requires_gles30 Only integral depth textures are available in - * OpenGL ES 2.0. - */ - DepthComponent32F = GL_DEPTH_COMPONENT32F, - #endif - - #ifndef MAGNUM_TARGET_GLES - /** - * Stencil index, size implementation-dependent. - * @deprecated Prefer to use exactly specified version of this - * format, e.g. @ref Magnum::Renderbuffer::InternalFormat "InternalFormat::StencilIndex8". - * @requires_gl Use exactly specified format in OpenGL ES instead. - */ - StencilIndex = GL_STENCIL_INDEX, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * 1-bit stencil index. - * @requires_es_extension %Extension @es_extension{OES,stencil1} - */ - #ifndef MAGNUM_TARGET_GLES - StencilIndex1 = GL_STENCIL_INDEX1, - #else - StencilIndex1 = GL_STENCIL_INDEX1_OES, - #endif - - /** - * 4-bit stencil index. - * @requires_es_extension %Extension @es_extension{OES,stencil4} - */ - #ifndef MAGNUM_TARGET_GLES - StencilIndex4 = GL_STENCIL_INDEX4, - #else - StencilIndex4 = GL_STENCIL_INDEX4_OES, - #endif - #endif - - /** 8-bit stencil index. */ - StencilIndex8 = GL_STENCIL_INDEX8, - - #ifndef MAGNUM_TARGET_GLES - /** - * 16-bit stencil index. - * @requires_gl At most 8bit stencil index is available in OpenGL - * ES. - */ - StencilIndex16 = GL_STENCIL_INDEX16, - - /** - * Depth and stencil component, size implementation-dependent. - * @deprecated Prefer to use exactly specified version of this - * format, e.g. @ref Magnum::Renderbuffer::InternalFormat "InternalFormat::Depth24Stencil8". - * @requires_gl Use exactly specified format in OpenGL ES instead. - */ - DepthStencil = GL_DEPTH_STENCIL, - #endif - - /** - * 24bit depth and 8bit stencil component. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} - * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} - */ - #ifdef MAGNUM_TARGET_GLES2 - Depth24Stencil8 = GL_DEPTH24_STENCIL8_OES - #else - Depth24Stencil8 = GL_DEPTH24_STENCIL8, - - /** - * 32bit float depth component and 8bit stencil component. - * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} - * @requires_gles30 Only integral depth textures are available in - * OpenGL ES 2.0. - */ - Depth32FStencil8 = GL_DEPTH32F_STENCIL8 - #endif - }; - /** * @brief Constructor * * Generates new OpenGL renderbuffer. * @see @fn_gl{GenRenderbuffers} */ - inline explicit Renderbuffer() { - glGenRenderbuffers(1, &_id); - } + explicit Renderbuffer() { glGenRenderbuffers(1, &_id); } /** * @brief Destructor @@ -549,12 +77,12 @@ class MAGNUM_EXPORT Renderbuffer { ~Renderbuffer(); /** @brief OpenGL internal renderbuffer ID */ - inline GLuint id() const { return _id; } + GLuint id() const { return _id; } /** * @brief Set renderbuffer storage * @param internalFormat Internal format - * @param size Renderbuffer size + * @param size %Renderbuffer size * * If @extension{EXT,direct_state_access} is not available and the * framebufferbuffer is not currently bound, it is bound before the @@ -562,20 +90,52 @@ class MAGNUM_EXPORT Renderbuffer { * @see @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} or * @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} */ - inline void setStorage(InternalFormat internalFormat, const Vector2i& size) { + void setStorage(RenderbufferFormat internalFormat, const Vector2i& size) { (this->*storageImplementation)(internalFormat, size); } + /** + * @brief Set multisample renderbuffer storage + * @param samples Sample count + * @param internalFormat Internal format + * @param size %Renderbuffer size + * + * 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{BindRenderbuffer}, @fn_gl{RenderbufferStorage} or + * @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} + * @requires_gl30 %Extension @extension{EXT,framebuffer_multisample} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample} + * or @es_extension{NV,framebuffer_multisample} + * @todo How about @es_extension{APPLE,framebuffer_multisample}? + */ + void setStorageMultisample(Int samples, RenderbufferFormat internalFormat, const Vector2i& size) { + (this->*storageMultisampleImplementation)(samples, internalFormat, size); + } + private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); - typedef void(Renderbuffer::*StorageImplementation)(InternalFormat, const Vector2i&); - void MAGNUM_LOCAL storageImplementationDefault(InternalFormat internalFormat, const Vector2i& size); + typedef void(Renderbuffer::*StorageImplementation)(RenderbufferFormat, const Vector2i&); + void MAGNUM_LOCAL storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL storageImplementationDSA(InternalFormat internalFormat, const Vector2i& size); + 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); + #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(); GLuint _id; diff --git a/src/RenderbufferFormat.h b/src/RenderbufferFormat.h new file mode 100644 index 000000000..f0d3de92f --- /dev/null +++ b/src/RenderbufferFormat.h @@ -0,0 +1,504 @@ +#ifndef Magnum_RenderbufferFormat_h +#define Magnum_RenderbufferFormat_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Enum Magnum::RenderbufferFormat + */ + +#include "OpenGL.h" + +namespace Magnum { + +/** +@brief Internal renderbuffer format + +@see Renderbuffer +@todo RGB, RGB8 ES only (ES3 + @es_extension{OES,rgb8_rgba8}) + */ +enum class RenderbufferFormat: GLenum { + #ifndef MAGNUM_TARGET_GLES + /** + * Red component, normalized unsigned, size implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::RenderbufferFormat "RenderbufferFormat::R8". + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Use exactly specified format in OpenGL ES instead. + */ + Red = GL_RED, + #endif + + /** + * Red component, normalized unsigned byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + */ + #ifndef MAGNUM_TARGET_GLES2 + R8 = GL_R8, + #else + R8 = GL_R8_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Red and green component, normalized unsigned, size + * implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::RenderbufferFormat "RenderbufferFormat::RG8". + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Use exactly specified format in OpenGL ES instead. + */ + RG = GL_RG, + #endif + + /** + * Red and green component, each normalized unsigned byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + */ + #ifndef MAGNUM_TARGET_GLES2 + RG8 = GL_RG8, + #else + RG8 = GL_RG8_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * RGBA, normalized unsigned, size implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::RenderbufferFormat "RenderbufferFormat::RGBA8". + * @requires_gl Use exactly specified format in OpenGL ES 2.0 instead. + */ + RGBA = GL_RGBA, + #endif + + /** + * RGBA, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{ARM,rgba8} or @es_extension{OES,rgb8_rgba8} + */ + #ifndef MAGNUM_TARGET_GLES2 + RGBA8 = GL_RGBA8, + #else + RGBA8 = GL_RGBA8_OES, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Red component, normalized unsigned short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + R16 = GL_R16, + + /** + * Red and green component, each normalized unsigned short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RG16 = GL_RG16, + + /** + * RGB, each component normalized unsigned short. + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RGB16 = GL_RGB16, + + /** + * RGBA, each component normalized unsigned short. + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RGBA16 = GL_RGBA16, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Red component, non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R8UI = GL_R8UI, + + /** + * Red and green component, each non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG8UI = GL_RG8UI, + + /** + * RGBA, each component non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA8UI = GL_RGBA8UI, + + /** + * Red component, non-normalized signed byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R8I = GL_R8I, + + /** + * Red and green component, each non-normalized signed byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG8I = GL_RG8I, + + /** + * RGBA, each component non-normalized signed byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA8I = GL_RGBA8I, + + /** + * Red component, non-normalized unsigned short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R16UI = GL_R16UI, + + /** + * Red and green component, each non-normalized unsigned short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG16UI = GL_RG16UI, + + /** + * RGBA, each component non-normalized unsigned short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA16UI = GL_RGBA16UI, + + /** + * Red component, non-normalized signed short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R16I = GL_R16I, + + /** + * Red and green component, each non-normalized signed short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG16I = GL_RG16I, + + /** + * RGBA, each component non-normalized signed short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA16I = GL_RGBA16I, + + /** + * Red component, non-normalized unsigned int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R32UI = GL_R32UI, + + /** + * Red and green component, each non-normalized unsigned int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG32UI = GL_RG32UI, + + /** + * RGBA, each component non-normalized unsigned int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA32UI = GL_RGBA32UI, + + /** + * Red component, non-normalized signed int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R32I = GL_R32I, + + /** + * Red and green component, each non-normalized signed int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG32I = GL_RG32I, + + /** + * RGBA, each component non-normalized signed int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA32I = GL_RGBA32I, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Red component, half float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gl Only (non)normalized integral formats are available in + * OpenGL ES. + */ + R16F = GL_R16F, + + /** + * Red and green component, each half float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gl Only (non)normalized integral formats are available in + * OpenGL ES. + */ + RG16F = GL_RG16F, + + /** + * RGBA, each component half float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gl Only (non)normalized integral formats are available in + * OpenGL ES. + */ + RGBA16F = GL_RGBA16F, + + /** + * Red component, float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gl Only (non)normalized integral formats are available in + * OpenGL ES. + */ + R32F = GL_R32F, + + /** + * Red and green component, each float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gl Only (non)normalized integral formats are available in + * OpenGL ES. + */ + RG32F = GL_RG32F, + + /** + * RGBA, each component float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gl Only (non)normalized integral formats are available in + * OpenGL ES. + */ + RGBA32F = GL_RGBA32F, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * RGBA, normalized unsigned, each RGB component 10bit, alpha 2bit. + * @requires_gles30 Usable only as internal texture format in OpenGL ES + * 2.0, see @ref Magnum::TextureFormat "TextureFormat::RGB10A2". + */ + RGB10A2 = GL_RGB10_A2, + + /** + * RGBA, non-normalized unsigned, each RGB component 10bit, alpha 2bit. + * @requires_gl33 %Extension @extension{ARB,texture_rgb10_a2ui} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB10A2UI = GL_RGB10_A2UI, + #endif + + /** RGBA, normalized unsigned, each RGB component 5bit, alpha 1bit. */ + RGB5A1 = GL_RGB5_A1, + + /** RGBA, normalized unsigned, each component 4bit. */ + RGBA4 = GL_RGBA4, + + #ifndef MAGNUM_TARGET_GLES + /** + * RGB, float, red and green 11bit, blue 10bit. + * @requires_gl30 %Extension @extension{EXT,packed_float} + * @requires_gl Usable only as internal texture format in OpenGL ES, see + * @ref Magnum::TextureFormat "TextureFormat::R11FG11FB10F". + */ + R11FG11FB10F = GL_R11F_G11F_B10F, + #endif + + /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is + GL_ARB_ES2_compatibility */ + #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT) + /** RGB, normalized unsigned, red and blue 5bit, green 6bit. */ + RGB565 = GL_RGB565, + #endif + + /** + * sRGBA, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{EXT,sRGB} + */ + #ifndef MAGNUM_TARGET_GLES2 + SRGB8Alpha8 = GL_SRGB8_ALPHA8, + #else + SRGB8Alpha8 = GL_SRGB8_ALPHA8_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Depth component, size implementation-dependent. + * @todo is this allowed in core? + * @deprecated Prefer to use exactly specified version of this format, e.g. + * @ref Magnum::RenderbufferFormat "RenderbufferFormat::DepthComponent16". + * @requires_gl Use exactly specified format in OpenGL ES instead. + */ + DepthComponent = GL_DEPTH_COMPONENT, + #endif + + /** Depth component, 16bit. */ + DepthComponent16 = GL_DEPTH_COMPONENT16, + + /** + * Depth component, 24bit. + * @requires_gles30 %Extension @es_extension{OES,depth24} + */ + #ifndef MAGNUM_TARGET_GLES2 + DepthComponent24 = GL_DEPTH_COMPONENT24, + #else + DepthComponent24 = GL_DEPTH_COMPONENT24_OES, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * Depth component, 32bit. + * @requires_es_extension %Extension @es_extension{OES,depth32} + */ + #ifndef MAGNUM_TARGET_GLES + DepthComponent32 = GL_DEPTH_COMPONENT32, + #else + DepthComponent32 = GL_DEPTH_COMPONENT32_OES, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Depth component, 32bit float. + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 Only integral depth textures are available in OpenGL ES + * 2.0. + */ + DepthComponent32F = GL_DEPTH_COMPONENT32F, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Stencil index, size implementation-dependent. + * @deprecated Prefer to use exactly specified version of this format, e.g. + * @ref Magnum::RenderbufferFormat "RenderbufferFormat::StencilIndex8". + * @requires_gl Use exactly specified format in OpenGL ES instead. + */ + StencilIndex = GL_STENCIL_INDEX, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * 1-bit stencil index. + * @requires_es_extension %Extension @es_extension{OES,stencil1} + */ + #ifndef MAGNUM_TARGET_GLES + StencilIndex1 = GL_STENCIL_INDEX1, + #else + StencilIndex1 = GL_STENCIL_INDEX1_OES, + #endif + + /** + * 4-bit stencil index. + * @requires_es_extension %Extension @es_extension{OES,stencil4} + */ + #ifndef MAGNUM_TARGET_GLES + StencilIndex4 = GL_STENCIL_INDEX4, + #else + StencilIndex4 = GL_STENCIL_INDEX4_OES, + #endif + #endif + + /** 8-bit stencil index. */ + StencilIndex8 = GL_STENCIL_INDEX8, + + #ifndef MAGNUM_TARGET_GLES + /** + * 16-bit stencil index. + * @requires_gl At most 8bit stencil index is available in OpenGL ES. + */ + StencilIndex16 = GL_STENCIL_INDEX16, + + /** + * Depth and stencil component, size implementation-dependent. + * @deprecated Prefer to use exactly specified version of this format, e.g. + * @ref Magnum::RenderbufferFormat "RenderbufferFormat::Depth24Stencil8". + * @requires_gl Use exactly specified format in OpenGL ES instead. + */ + DepthStencil = GL_DEPTH_STENCIL, + #endif + + /** + * 24bit depth and 8bit stencil component. + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} + */ + #ifdef MAGNUM_TARGET_GLES2 + Depth24Stencil8 = GL_DEPTH24_STENCIL8_OES + #else + Depth24Stencil8 = GL_DEPTH24_STENCIL8, + + /** + * 32bit float depth component and 8bit stencil component. + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 Only integral depth textures are available in OpenGL ES + * 2.0. + */ + Depth32FStencil8 = GL_DEPTH32F_STENCIL8 + #endif +}; + +} + +#endif diff --git a/src/Renderer.cpp b/src/Renderer.cpp new file mode 100644 index 000000000..df9b41313 --- /dev/null +++ b/src/Renderer.cpp @@ -0,0 +1,236 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Renderer.h" + +#include "Color.h" +#include "Math/Geometry/Rectangle.h" +#include "Context.h" +#include "Extensions.h" +#include "Implementation/State.h" +#include "Implementation/RendererState.h" + +namespace Magnum { + +#ifndef MAGNUM_TARGET_GLES +Renderer::ClearDepthfImplementation Renderer::clearDepthfImplementation = &Renderer::clearDepthfImplementationDefault; +#else +Renderer::ClearDepthfImplementation Renderer::clearDepthfImplementation = &Renderer::clearDepthfImplementationES; +#endif +#ifndef MAGNUM_TARGET_GLES3 +Renderer::GraphicsResetStatusImplementation Renderer::graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationDefault; +#endif + +void Renderer::setFeature(const Feature feature, const bool enabled) { + enabled ? glEnable(GLenum(feature)) : glDisable(GLenum(feature)); +} + +void Renderer::setHint(const Hint target, const HintMode mode) { + glHint(GLenum(target), GLenum(mode)); +} + +void Renderer::setClearColor(const Color4<>& color) { + glClearColor(color.r(), color.g(), color.b(), color.a()); +} + +#ifndef MAGNUM_TARGET_GLES +void Renderer::setClearDepth(const Double depth) { + glClearDepth(depth); +} +#endif + +void Renderer::setClearStencil(const Int stencil) { + glClearStencil(stencil); +} + +void Renderer::setFrontFace(const FrontFace mode) { + glFrontFace(GLenum(mode)); +} + +void Renderer::setFaceCullingMode(const PolygonFacing mode) { + glCullFace(GLenum(mode)); +} + +#ifndef MAGNUM_TARGET_GLES +void Renderer::setProvokingVertex(const ProvokingVertex mode) { + glProvokingVertex(GLenum(mode)); +} + +void Renderer::setPolygonMode(const PolygonMode mode) { + glPolygonMode(GL_FRONT_AND_BACK, GLenum(mode)); +} +#endif + +void Renderer::setPolygonOffset(const Float factor, const Float units) { + glPolygonOffset(factor, units); +} + +void Renderer::setLineWidth(const Float width) { + glLineWidth(width); +} + +#ifndef MAGNUM_TARGET_GLES +void Renderer::setPointSize(const Float size) { + glPointSize(size); +} +#endif + +void Renderer::setScissor(const Rectanglei& rectangle) { + glScissor(rectangle.left(), rectangle.bottom(), rectangle.width(), rectangle.height()); +} + +void Renderer::setStencilFunction(const PolygonFacing facing, const StencilFunction function, const Int referenceValue, const UnsignedInt mask) { + glStencilFuncSeparate(GLenum(facing), GLenum(function), referenceValue, mask); +} + +void Renderer::setStencilFunction(const StencilFunction function, const Int referenceValue, const UnsignedInt mask) { + glStencilFunc(GLenum(function), referenceValue, mask); +} + +void Renderer::setStencilOperation(const PolygonFacing facing, const StencilOperation stencilFail, const StencilOperation depthFail, const StencilOperation depthPass) { + glStencilOpSeparate(GLenum(facing), GLenum(stencilFail), GLenum(depthFail), GLenum(depthPass)); +} + +void Renderer::setStencilOperation(const StencilOperation stencilFail, const StencilOperation depthFail, const StencilOperation depthPass) { + glStencilOp(GLenum(stencilFail), GLenum(depthFail), GLenum(depthPass)); +} + +void Renderer::setDepthFunction(const DepthFunction function) { + glDepthFunc(GLenum(function)); +} + +void Renderer::setColorMask(const GLboolean allowRed, const GLboolean allowGreen, const GLboolean allowBlue, const GLboolean allowAlpha) { + glColorMask(allowRed, allowGreen, allowBlue, allowAlpha); +} + +void Renderer::setDepthMask(const GLboolean allow) { + glDepthMask(allow); +} + +void Renderer::setStencilMask(const PolygonFacing facing, const UnsignedInt allowBits) { + glStencilMaskSeparate(GLenum(facing), allowBits); +} + +void Renderer::setStencilMask(const UnsignedInt allowBits) { + glStencilMask(allowBits); +} + +void Renderer::setBlendEquation(const BlendEquation equation) { + glBlendEquation(GLenum(equation)); +} + +void Renderer::setBlendEquation(const BlendEquation rgb, const BlendEquation alpha) { + glBlendEquationSeparate(GLenum(rgb), GLenum(alpha)); +} + +void Renderer::setBlendFunction(const BlendFunction source, const BlendFunction destination) { + glBlendFunc(GLenum(source), GLenum(destination)); +} + +void Renderer::setBlendFunction(const BlendFunction sourceRgb, const BlendFunction destinationRgb, const BlendFunction sourceAlpha, const BlendFunction destinationAlpha) { + glBlendFuncSeparate(GLenum(sourceRgb), GLenum(destinationRgb), GLenum(sourceAlpha), GLenum(destinationAlpha)); +} + +void Renderer::setBlendColor(const Color4<>& color) { + glBlendColor(color.r(), color.g(), color.b(), color.a()); +} + +#ifndef MAGNUM_TARGET_GLES +void Renderer::setLogicOperation(const LogicOperation operation) { + glLogicOp(GLenum(operation)); +} +#endif + +#ifndef MAGNUM_TARGET_GLES3 +Renderer::ResetNotificationStrategy Renderer::resetNotificationStrategy() { + ResetNotificationStrategy& strategy = Context::current()->state()->renderer->resetNotificationStrategy; + + if(strategy == ResetNotificationStrategy()) { + #ifndef MAGNUM_TARGET_GLES + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, reinterpret_cast(&strategy)); + #else + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_EXT, reinterpret_cast(&strategy)); + #endif + } + + return strategy; +} +#endif + +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_GLES3 + #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; + } + #else + static_cast(context); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void Renderer::clearDepthfImplementationDefault(const GLfloat depth) { + glClearDepth(depth); +} +#endif + +void Renderer::clearDepthfImplementationES(const GLfloat depth) { + glClearDepthf(depth); +} + +#ifndef MAGNUM_TARGET_GLES3 +Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationDefault() { + return GraphicsResetStatus::NoError; +} + +Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationRobustness() { + /** @todo Enable when extension wrangler for ES is available */ + #ifndef MAGNUM_TARGET_GLES + return GraphicsResetStatus(glGetGraphicsResetStatusARB()); + #else + //return GraphicsResetStatus(glGetGraphicsResetStatusEXT()); + CORRADE_INTERNAL_ASSERT(false); + #endif +} +#endif + +} diff --git a/src/Renderer.h b/src/Renderer.h index 06f65be9b..0ff490450 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -30,11 +30,9 @@ #include -#include "AbstractImage.h" -#include "Buffer.h" -#include "CubeMapTexture.h" -#include "Color.h" -#include "Renderbuffer.h" +#include "Magnum.h" +#include "OpenGL.h" +#include "magnumVisibility.h" namespace Magnum { @@ -45,6 +43,8 @@ Access to global renderer configuration. @todo @extension{ARB,viewport_array} */ class MAGNUM_EXPORT Renderer { + friend class Context; + public: Renderer() = delete; @@ -67,7 +67,7 @@ class MAGNUM_EXPORT Renderer { /** * @brief Features * - * If not specified otherwise, all features are disabled by default. + * All features are disabled by default unless specified otherwise. * @see setFeature() */ enum class Feature: GLenum { @@ -77,10 +77,28 @@ class MAGNUM_EXPORT Renderer { */ Blending = GL_BLEND, - DepthTest = GL_DEPTH_TEST, /**< Depth test */ - Dithering = GL_DITHER, /**< Dithering (enabled by default) */ + #ifndef MAGNUM_TARGET_GLES + /** + * Depth clamping. If enabled, ignores near and far clipping plane. + * @requires_gl32 %Extension @extension{ARB,depth_clamp} + * @requires_gl Depth clamping is not available in OpenGL ES. + */ + DepthClamp = GL_DEPTH_CLAMP, + #endif + + /** + * Depth test + * @see setClearDepth(), setDepthFunction(), setDepthMask() + */ + DepthTest = GL_DEPTH_TEST, - FaceCulling = GL_CULL_FACE, /**< Back face culling */ + Dithering = GL_DITHER, /**< Dithering. Enabled by default. */ + + /** + * Back face culling + * @see setFrontFace() + */ + FaceCulling = GL_CULL_FACE, #ifndef MAGNUM_TARGET_GLES /** @@ -94,19 +112,52 @@ class MAGNUM_EXPORT Renderer { #ifndef MAGNUM_TARGET_GLES /** - * Multisampling (enabled by default) + * Multisampling. Enabled by default. Note that the actual presence + * of this feature in default framebuffer depends on context + * configuration, see for example Platform::GlutApplication::Configuration::setSampleCount(). * @requires_gl Always enabled in OpenGL ES. */ Multisampling = GL_MULTISAMPLE, #endif + /** + * Offset filled polygons + * @see @ref Magnum::Renderer::Feature "Feature::PolygonOffsetLine", + * @ref Magnum::Renderer::Feature "Feature::PolygonOffsetPoint", + * setPolygonOffset() + */ + PolygonOffsetFill = GL_POLYGON_OFFSET_FILL, + #ifndef MAGNUM_TARGET_GLES /** - * Depth clamping. If enabled, ignores near and far clipping plane. - * @requires_gl32 %Extension @extension{ARB,depth_clamp} - * @requires_gl Depth clamping is not available in OpenGL ES. + * Offset lines + * @see @ref Magnum::Renderer::Feature "Feature::PolygonOffsetFill", + * @ref Magnum::Renderer::Feature "Feature::PolygonOffsetPoint", + * setPolygonOffset() + * @requires_gl Only @ref Magnum::Renderer::Feature "Feature::PolygonOffsetFill" + * is available in OpenGL ES. */ - DepthClamp = GL_DEPTH_CLAMP, + PolygonOffsetLine = GL_POLYGON_OFFSET_LINE, + + /** + * Offset points + * @see @ref Magnum::Renderer::Feature "Feature::PolygonOffsetFill", + * @ref Magnum::Renderer::Feature "Feature::PolygonOffsetLine", + * setPolygonOffset() + * @requires_gl Only @ref Magnum::Renderer::Feature "Feature::PolygonOffsetFill" + * is available in OpenGL ES. + */ + PolygonOffsetPoint = GL_POLYGON_OFFSET_POINT, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Programmable point size. If enabled, the point size is taken + * from vertex/geometry shader builtin `gl_PointSize`. + * @see setPointSize() + * @requires_gl Always enabled on OpenGL ES. + */ + ProgramPointSize = GL_PROGRAM_POINT_SIZE, #endif /** @@ -115,7 +166,23 @@ class MAGNUM_EXPORT Renderer { */ ScissorTest = GL_SCISSOR_TEST, - StencilTest = GL_STENCIL_TEST /**< Stencil test */ + #ifndef MAGNUM_TARGET_GLES + /** + * Seamless cube map texture. + * @see CubeMapTexture, CubeMapTextureArray + * @requires_gl32 %Extension @extension{ARB,seamless_cube_map} + * @requires_gl Not available in OpenGL ES 2.0, always enabled in + * OpenGL ES 3.0. + */ + SeamlessCubeMapTexture = GL_TEXTURE_CUBE_MAP_SEAMLESS, + #endif + + /** + * Stencil test + * @see setClearStencil(), setStencilFunction(), + * setStencilOperation(), setStencilMask() + */ + StencilTest = GL_STENCIL_TEST }; /** @@ -123,21 +190,43 @@ class MAGNUM_EXPORT Renderer { * * @see @fn_gl{Enable}/@fn_gl{Disable} */ - inline static void setFeature(Feature feature, bool enabled) { - enabled ? glEnable(static_cast(feature)) : glDisable(static_cast(feature)); - } + static void setFeature(Feature feature, bool enabled); /** - * @brief Which polygon facing to cull + * @brief Hint * - * Initial value is `PolygonFacing::Back`. If set to both front and - * back, only points and lines are drawn. - * @attention You have to also enable face culling with setFeature(). - * @see @fn_gl{CullFace} + * @see setHint() */ - inline static void setFaceCullingMode(PolygonFacing mode) { - glCullFace(static_cast(mode)); - } + enum class Hint: GLenum { + /** + * Accuracy of derivative calculation in fragment shader. + * @requires_gles30 %Extension @es_extension{OES,standard_derivatives} + */ + #ifndef MAGNUM_TARGET_GLES2 + FragmentShaderDerivative = GL_FRAGMENT_SHADER_DERIVATIVE_HINT + #else + FragmentShaderDerivative = GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES + #endif + }; + + /** + * @brief Hint mode + * + * @see setHint() + */ + enum class HintMode: GLenum { + Fastest = GL_FASTEST, /**< Most efficient option. */ + Nicest = GL_NICEST, /**< Most correct or highest quality option. */ + DontCare = GL_DONT_CARE /**< No preference. */ + }; + + /** + * @brief Set hint + * + * Initial value is @ref HintMode "HintMode::DontCare" for all targets. + * @see @fn_gl{Hint} + */ + static void setHint(Hint target, HintMode mode); /*@}*/ @@ -146,40 +235,175 @@ class MAGNUM_EXPORT Renderer { /** * @brief Set clear color * - * Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`. + * Initial value is fully opaque black. * @see @fn_gl{ClearColor} */ - inline static void setClearColor(const Color4<>& color) { - glClearColor(color.r(), color.g(), color.b(), color.a()); - } + static void setClearColor(const Color4<>& color); #ifndef MAGNUM_TARGET_GLES /** * @brief Set clear depth * * Initial value is `1.0`. - * @see @fn_gl{ClearDepth} + * @see @ref Feature "Feature::DepthTest", @fn_gl{ClearDepth} * @requires_gl See setClearDepth(Float), which is available in OpenGL ES. */ - inline static void setClearDepth(Double depth) { glClearDepth(depth); } + static void setClearDepth(Double depth); #endif /** * @overload * - * @see @fn_gl{ClearDepth} - * @requires_gl41 %Extension @extension{ARB,ES2_compatibility} - * @todo Call double version if the extension is not available + * @see @ref Feature "Feature::DepthTest", @fn_gl{ClearDepth} + * If OpenGL ES, OpenGL 4.1 or extension @extension{ARB,ES2_compatibility} + * is not available, this function behaves exactly as setClearDepth(Double). */ - inline static void setClearDepth(Float depth) { glClearDepthf(depth); } + static void setClearDepth(Float depth) { + clearDepthfImplementation(depth); + } /** * @brief Set clear stencil * * Initial value is `0`. - * @see @fn_gl{ClearStencil} + * @see @ref Feature "Feature::StencilTest", @fn_gl{ClearStencil} */ - inline static void setClearStencil(Int stencil) { glClearStencil(stencil); } + static void setClearStencil(Int stencil); + + /*@}*/ + + /** @name Polygon drawing settings */ + + /** + * @brief Front facing polygon winding + * + * @see setFrontFace() + */ + enum FrontFace: GLenum { + /** @brief Counterclockwise polygons are front facing (default). */ + CounterClockWise = GL_CCW, + + /** @brief Clockwise polygons are front facing. */ + ClockWise = GL_CW + }; + + /** + * @brief Set front-facing polygon winding + * + * Initial value is `FrontFace::%CounterClockWise`. + * @see setFaceCullingMode(), @fn_gl{FrontFace} + */ + static void setFrontFace(FrontFace mode); + + /** + * @brief Which polygon facing to cull + * + * Initial value is @ref PolygonFacing "PolygonFacing::Back". If set to + * both front and back, only points and lines are drawn. + * @see @ref Feature "Feature::FaceCulling", setFrontFace(), + * @fn_gl{CullFace} + */ + static void setFaceCullingMode(PolygonFacing mode); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Provoking vertex + * + * @see setProvokingVertex() + * @requires_gl32 %Extension @extension{ARB,provoking_vertex}. Older + * versions behave always like + * @ref Magnum::Renderer::ProvokingVertex "ProvokingVertex::LastVertexConvention". + * @requires_gl OpenGL ES behaves always like + * @ref Magnum::Renderer::ProvokingVertex "ProvokingVertex::LastVertexConvention". + */ + enum class ProvokingVertex: GLenum { + /** @brief Use first vertex of each polygon. */ + FirstVertexConvention = GL_FIRST_VERTEX_CONVENTION, + + /** @brief Use last vertex of each polygon (default). */ + LastVertexConvention = GL_LAST_VERTEX_CONVENTION + }; + + /** + * @brief Set provoking vertex + * + * Initial value is @ref ProvokingVertex "ProvokingVertex::LastVertexConvention". + * @see @fn_gl{ProvokingVertex} + * @requires_gl32 %Extension @extension{ARB,provoking_vertex}. Older + * versions behave always like the default. + * @requires_gl OpenGL ES behaves always like the default. + */ + static void setProvokingVertex(ProvokingVertex mode); + + /** + * @brief Polygon mode + * + * @see setPolygonMode() + * @requires_gl OpenGL ES behaves always like @ref Magnum::Renderer::PolygonMode "PolygonMode::Fill". + * See @ref Magnum::Mesh::setPrimitive() "Mesh::setPrimitive()" + * for possible workaround. + */ + enum class PolygonMode: GLenum { + /** + * Interior of the polygon is filled (default). + */ + Fill = GL_FILL, + + /** + * Boundary edges are filled. See also setLineWidth(). + */ + Line = GL_LINE, + + /** + * Starts of boundary edges are drawn as points. See also + * setPointSize(). + */ + Point = GL_POINT + }; + + /** + * @brief Set polygon drawing mode + * + * Initial value is @ref PolygonMode "PolygonMode::Fill". + * @see @fn_gl{PolygonMode} + * @requires_gl OpenGL ES behaves always like the default. See + * @ref Magnum::Mesh::setPrimitive() "Mesh::setPrimitive()" for + * possible workaround. + */ + static void setPolygonMode(PolygonMode mode); + #endif + + /** + * @brief Set polygon offset + * @param factor Scale factor + * @param units Offset units + * + * @see @ref Feature "Feature::PolygonOffsetFill", + * @ref Feature "Feature::PolygonOffsetLine", + * @ref Feature "Feature::PolygonOffsetPoint", + * @fn_gl{PolygonOffset} + */ + static void setPolygonOffset(Float factor, Float units); + + /** + * @brief Set line width + * + * Initial value is `1.0f`. + * @see @fn_gl{LineWidth} + */ + static void setLineWidth(Float width); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Set point size + * + * Initial value is `1.0f`. + * @see @ref Feature "Feature::ProgramPointSize", @fn_gl{PointSize} + * @requires_gl In OpenGL ES use `gl_PointSize` builtin vertex shader + * variable. + */ + static void setPointSize(Float size); + #endif /*@}*/ @@ -187,17 +411,10 @@ class MAGNUM_EXPORT Renderer { /** * @brief Set scissor rectangle - * @param bottomLeft Bottom left corner. Initial value is `(0, 0)`. - * @param size Scissor rectangle size. Initial value is - * size of the window when the context is first attached to a - * window. * - * @attention You have to enable scissoring with setFeature() first. - * @see @fn_gl{Scissor} + * @see @ref Feature "Feature::ScissorTest", @fn_gl{Scissor} */ - inline static void setScissor(const Vector2i& bottomLeft, const Vector2i& size) { - glScissor(bottomLeft.x(), bottomLeft.y(), size.x(), size.y()); - } + static void setScissor(const Rectanglei& rectangle); /*@}*/ @@ -206,7 +423,7 @@ class MAGNUM_EXPORT Renderer { /** * @brief Stencil function * - * @see setStencilFunction() + * @see setStencilFunction(), @ref DepthFunction */ enum class StencilFunction: GLenum { Never = GL_NEVER, /**< Never pass the test. */ @@ -268,29 +485,27 @@ class MAGNUM_EXPORT Renderer { * @brief Set stencil function * @param facing Affected polygon facing * @param function Stencil function. Initial value is - * `StencilFunction::Always`. + * @ref StencilFunction "StencilFunction::Always". * @param referenceValue Reference value. Initial value is `0`. * @param mask Mask for both reference and buffer value. * Initial value is all `1`s. * - * @attention You have to enable stencil test with setFeature() first. - * @see setStencilFunction(StencilFunction, Int, UnsignedInt), + * @see @ref Feature "Feature::StencilTest", + * setStencilFunction(StencilFunction, Int, UnsignedInt), + * setStencilOperation(), * @fn_gl{StencilFuncSeparate} */ - inline static void setStencilFunction(PolygonFacing facing, StencilFunction function, Int referenceValue, UnsignedInt mask) { - glStencilFuncSeparate(static_cast(facing), static_cast(function), referenceValue, mask); - } + static void setStencilFunction(PolygonFacing facing, StencilFunction function, Int referenceValue, UnsignedInt mask); /** * @brief Set stencil function * * The same as setStencilFunction(PolygonFacing, StencilFunction, Int, UnsignedInt) - * with `facing` set to `PolygonFacing::FrontAndBack`. - * @see @fn_gl{StencilFunc} + * with @p facing set to @ref PolygonFacing "PolygonFacing::FrontAndBack". + * @see @ref Feature "Feature::StencilTest", setStencilOperation(), + * @fn_gl{StencilFunc} */ - inline static void setStencilFunction(StencilFunction function, Int referenceValue, UnsignedInt mask) { - glStencilFunc(static_cast(function), referenceValue, mask); - } + static void setStencilFunction(StencilFunction function, Int referenceValue, UnsignedInt mask); /** * @brief Set stencil operation @@ -301,25 +516,22 @@ class MAGNUM_EXPORT Renderer { * @param depthPass Action when both stencil and depth test * pass * - * Initial value for all fields is `StencilOperation::Keep`. - * @attention You have to enable stencil test with setFeature() first. - * @see setStencilOperation(StencilOperation, StencilOperation, StencilOperation), - * @fn_gl{StencilOpSeparate} + * Initial value for all fields is @ref StencilOperation "StencilOperation::Keep". + * @see @ref Feature "Feature::StencilTest", + * setStencilOperation(StencilOperation, StencilOperation, StencilOperation), + * setStencilFunction(), @fn_gl{StencilOpSeparate} */ - inline static void setStencilOperation(PolygonFacing facing, StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) { - glStencilOpSeparate(static_cast(facing), static_cast(stencilFail), static_cast(depthFail), static_cast(depthPass)); - } + static void setStencilOperation(PolygonFacing facing, StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass); /** * @brief Set stencil operation * * The same as setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation) - * with `facing` set to `PolygonFacing::FrontAndBack`. - * @see @fn_gl{StencilOp} + * with @p facing set to @ref PolygonFacing "PolygonFacing::FrontAndBack". + * @see @ref Feature "Feature::StencilTest", setStencilFunction(), + * @fn_gl{StencilOp} */ - inline static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) { - glStencilOp(static_cast(stencilFail), static_cast(depthFail), static_cast(depthPass)); - } + static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass); /*@}*/ @@ -335,13 +547,10 @@ class MAGNUM_EXPORT Renderer { /** * @brief Set depth function * - * Initial value is `DepthFunction::Less`. - * @attention You have to enable depth test with setFeature() first. - * @see @fn_gl{DepthFunc} + * Initial value is @ref DepthFunction "DepthFunction::Less". + * @see @ref Feature "Feature::DepthTest", @fn_gl{DepthFunc} */ - inline static void setDepthFunction(DepthFunction function) { - glDepthFunc(static_cast(function)); - } + static void setDepthFunction(DepthFunction function); /*@}*/ @@ -352,45 +561,38 @@ class MAGNUM_EXPORT Renderer { * * Set to `false` to disallow writing to given color channel. Initial * values are all `true`. - * @see @fn_gl{ColorMask} + * @see setDepthMask(), setStencilMask(), @fn_gl{ColorMask} * @todo Masking only given draw buffer */ - inline static void setColorMask(GLboolean allowRed, GLboolean allowGreen, GLboolean allowBlue, GLboolean allowAlpha) { - glColorMask(allowRed, allowGreen, allowBlue, allowAlpha); - } + static void setColorMask(GLboolean allowRed, GLboolean allowGreen, GLboolean allowBlue, GLboolean allowAlpha); /** * @brief Mask depth writes * * Set to `false` to disallow writing to depth buffer. Initial value * is `true`. - * @see @fn_gl{DepthMask} + * @see setColorMask(), setStencilMask(), @fn_gl{DepthMask} */ - inline static void setDepthMask(GLboolean allow) { - glDepthMask(allow); - } + static void setDepthMask(GLboolean allow); /** * @brief Mask stencil writes * * Set given bit to `0` to disallow writing stencil value for given * faces to it. Initial value is all `1`s. - * @see setStencilMask(UnsignedInt), @fn_gl{StencilMaskSeparate} + * @see setStencilMask(UnsignedInt), setColorMask(), setDepthMask(), + * @fn_gl{StencilMaskSeparate} */ - inline static void setStencilMask(PolygonFacing facing, UnsignedInt allowBits) { - glStencilMaskSeparate(static_cast(facing), allowBits); - } + static void setStencilMask(PolygonFacing facing, UnsignedInt allowBits); /** * @brief Mask stencil writes * - * The same as setStencilMask(PolygonFacing, UnsignedInt) with `facing` set - * to `PolygonFacing::FrontAndBack`. + * The same as calling setStencilMask(PolygonFacing, UnsignedInt) with + * `facing` set to @ref PolygonFacing "PolygonFacing::FrontAndBack". * @see @fn_gl{StencilMask} */ - inline static void setStencilMask(UnsignedInt allowBits) { - glStencilMask(allowBits); - } + static void setStencilMask(UnsignedInt allowBits); /*@}*/ @@ -559,67 +761,55 @@ class MAGNUM_EXPORT Renderer { * @brief Set blend equation * * How to combine source color (pixel value) with destination color - * (framebuffer). Initial value is `BlendEquation::Add`. - * @attention You have to enable blending with setFeature() first. - * @see setBlendEquation(BlendEquation, BlendEquation), - * @fn_gl{BlendEquation} + * (framebuffer). Initial value is @ref BlendEquation "BlendEquation::Add". + * @see @ref Feature "Feature::Blending", setBlendEquation(BlendEquation, BlendEquation), + * setBlendFunction(), setBlendColor(), @fn_gl{BlendEquation} */ - inline static void setBlendEquation(BlendEquation equation) { - glBlendEquation(static_cast(equation)); - } + static void setBlendEquation(BlendEquation equation); /** * @brief Set blend equation separately for RGB and alpha components * * See setBlendEquation(BlendEquation) for more information. - * @attention You have to enable blending with setFeature() first. - * @see @fn_gl{BlendEquationSeparate} + * @see @ref Feature "Feature::Blending", setBlendFunction(), + * setBlendColor(), @fn_gl{BlendEquationSeparate} */ - inline static void setBlendEquation(BlendEquation rgb, BlendEquation alpha) { - glBlendEquationSeparate(static_cast(rgb), static_cast(alpha)); - } + static void setBlendEquation(BlendEquation rgb, BlendEquation alpha); /** * @brief Set blend function * @param source How the source blending factor is computed - * from pixel value. Initial value is `BlendFunction::One`. + * from pixel value. Initial value is @ref BlendFunction "BlendFunction::One". * @param destination How the destination blending factor is - * computed from framebuffer. Initial value is - * `BlendFunction::Zero`. + * computed from framebuffer. Initial value is @ref BlendFunction "BlendFunction::Zero". * - * @attention You have to enable blending with setFeature() first. - * @see setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction), - * @fn_gl{BlendFunc} + * @see @ref Feature "Feature::Blending", + * setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction), + * setBlendEquation(), setBlendColor(), @fn_gl{BlendFunc} */ - inline static void setBlendFunction(BlendFunction source, BlendFunction destination) { - glBlendFunc(static_cast(source), static_cast(destination)); - } + static void setBlendFunction(BlendFunction source, BlendFunction destination); /** * @brief Set blend function separately for RGB and alpha components * * See setBlendFunction(BlendFunction, BlendFunction) for more information. - * @attention You have to enable blending with setFeature() first. - * @see @fn_gl{BlendFuncSeparate} + * @see @ref Feature "Feature::Blending", setBlendEquation(), + * setBlendColor(), @fn_gl{BlendFuncSeparate} */ - inline static void setBlendFunction(BlendFunction sourceRgb, BlendFunction destinationRgb, BlendFunction sourceAlpha, BlendFunction destinationAlpha) { - glBlendFuncSeparate(static_cast(sourceRgb), static_cast(destinationRgb), static_cast(sourceAlpha), static_cast(destinationAlpha)); - } + static void setBlendFunction(BlendFunction sourceRgb, BlendFunction destinationRgb, BlendFunction sourceAlpha, BlendFunction destinationAlpha); /** * @brief Set blend color * * Sets constant color used in setBlendFunction() by - * `BlendFunction::ConstantColor`, - * `BlendFunction::OneMinusConstantColor`, - * `BlendFunction::ConstantAlpha` and - * `BlendFunction::OneMinusConstantAlpha`. - * @attention You have to enable blending with setFeature() first. - * @see @fn_gl{BlendColor} - */ - inline static void setBlendColor(const Color4<>& color) { - glBlendColor(color.r(), color.g(), color.b(), color.a()); - } + * @ref BlendFunction "BlendFunction::ConstantColor", + * @ref BlendFunction "BlendFunction::OneMinusConstantColor", + * @ref BlendFunction "BlendFunction::ConstantAlpha" and + * @ref BlendFunction "BlendFunction::OneMinusConstantAlpha". + * @see @ref Feature "Feature::Blending", setBlendEquation(), + * setBlendFunction(), @fn_gl{BlendColor} + */ + static void setBlendColor(const Color4<>& color); /*@}*/ @@ -655,14 +845,11 @@ class MAGNUM_EXPORT Renderer { /** * @brief Set logical operation * - * @attention You have to enable logical operation with setFeature() first. - * @see @fn_gl{LogicOp} + * @see @ref Feature "Feature::LogicOperation", @fn_gl{LogicOp} * @requires_gl Logical operations on framebuffer are not available in * OpenGL ES. */ - inline static void setLogicOperation(LogicOperation operation) { - glLogicOp(static_cast(operation)); - } + static void setLogicOperation(LogicOperation operation); /*@}*/ #endif @@ -674,9 +861,7 @@ class MAGNUM_EXPORT Renderer { * * @see finish(), @fn_gl{Flush} */ - inline static void flush() { - glFlush(); - } + static void flush() { glFlush(); } /** * @brief Finish the pipeline @@ -684,11 +869,115 @@ class MAGNUM_EXPORT Renderer { * Blocks until all commands in the pipeline are finished. * @see flush(), @fn_gl{Finish} */ - inline static void finish() { - glFinish(); + static void finish() { glFinish(); } + + #ifndef MAGNUM_TARGET_GLES3 + /** + * @brief Graphics reset notification strategy + * + * @see resetNotificationStrategy() + * @requires_extension %Extension @extension{ARB,robustness} + * @requires_es_extension %Extension @es_extension{EXT,robustness} + */ + enum class ResetNotificationStrategy: GLint { + /** + * No reset notification, thus graphicsResetStatus() will always + * return @ref GraphicsResetStatus "GraphicsResetStatus::NoError". + * However this doesn't mean that the context cannot be lost. + */ + #ifndef MAGNUM_TARGET_GLES + NoResetNotification = GL_NO_RESET_NOTIFICATION_ARB, + #else + NoResetNotification = GL_NO_RESET_NOTIFICATION_EXT, + #endif + + /** + * Graphics reset will result in context loss, cause of the reset + * can be queried with graphicsResetStatus(). + */ + #ifndef MAGNUM_TARGET_GLES + LoseContextOnReset = GL_LOSE_CONTEXT_ON_RESET_ARB + #else + LoseContextOnReset = GL_LOSE_CONTEXT_ON_RESET_EXT + #endif + }; + + /** + * @brief Graphics reset notification strategy + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If OpenGL extension @extension{ARB,robustness} or ES + * extension @es_extension{EXT,robustness} is not available, this + * function always returns @ref ResetNotificationStrategy "ResetNotificationStrategy::NoResetNotification". + * @see graphicsResetStatus(), @fn_gl{Get} with @def_gl{RESET_NOTIFICATION_STRATEGY_ARB} + */ + static ResetNotificationStrategy resetNotificationStrategy(); + + /** + * @brief Graphics reset status + * + * @see resetNotificationStrategy(), graphicsResetStatus() + * @requires_extension %Extension @extension{ARB,robustness} + * @requires_es_extension %Extension @es_extension{EXT,robustness} + */ + enum class GraphicsResetStatus: GLenum { + /** No reset occured since last call. */ + NoError = GL_NO_ERROR, + + /** Reset attributable to the current context has been detected. */ + #ifndef MAGNUM_TARGET_GLES + GuiltyContextReset = GL_GUILTY_CONTEXT_RESET_ARB, + #else + GuiltyContextReset = GL_GUILTY_CONTEXT_RESET_EXT, + #endif + + /** Reset not attributable to the current context has been detected. */ + #ifndef MAGNUM_TARGET_GLES + InnocentContextReset = GL_INNOCENT_CONTEXT_RESET_ARB, + #else + InnocentContextReset = GL_INNOCENT_CONTEXT_RESET_EXT, + #endif + + /** Reset with unknown cause has been detected. */ + #ifndef MAGNUM_TARGET_GLES + UnknownContextReset = GL_UNKNOWN_CONTEXT_RESET_ARB + #else + UnknownContextReset = GL_UNKNOWN_CONTEXT_RESET_EXT + #endif + }; + + /** + * @brief Check graphics reset status + * + * Reset causes all context state to be lost. If OpenGL extension + * @extension{ARB,robustness} or ES extension @es_extension{EXT,robustness} + * is not available, this function always returns + * @ref GraphicsResetStatus "GraphicsResetStatus::NoError". + * @see resetNotificationStrategy(), @fn_gl_extension{GetGraphicsResetStatus,ARB,robustness} + */ + static GraphicsResetStatus graphicsResetStatus() { + return graphicsResetStatusImplementation(); } + #endif /*@}*/ + + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + 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; + + #ifndef MAGNUM_TARGET_GLES3 + typedef GraphicsResetStatus(*GraphicsResetStatusImplementation)(); + static GraphicsResetStatus MAGNUM_LOCAL graphicsResetStatusImplementationDefault(); + static GraphicsResetStatus MAGNUM_LOCAL graphicsResetStatusImplementationRobustness(); + static GraphicsResetStatusImplementation graphicsResetStatusImplementation; + #endif }; } diff --git a/src/Resource.h b/src/Resource.h index 6848bbb12..cf71f7998 100644 --- a/src/Resource.h +++ b/src/Resource.h @@ -78,7 +78,7 @@ See ResourceManager for more information. @see ResourceManager::referenceCount(), ResourceManager::state(), ResourceManager::get(), ResourceManager::set(), Resource::key() */ -class ResourceKey: public Corrade::Utility::MurmurHash2::Digest { +class ResourceKey: public Utility::MurmurHash2::Digest { public: /** * @brief Default constructor @@ -86,38 +86,36 @@ class ResourceKey: public Corrade::Utility::MurmurHash2::Digest { * Creates zero key. Note that it is not the same as calling other * constructors with empty string. */ - inline constexpr ResourceKey() {} + constexpr ResourceKey() {} /** @brief Constructor */ - inline ResourceKey(const std::string& key): Corrade::Utility::MurmurHash2::Digest(Corrade::Utility::MurmurHash2()(key)) {} + ResourceKey(const std::string& key): Utility::MurmurHash2::Digest(Utility::MurmurHash2()(key)) {} /** * @brief Constructor * @todo constexpr */ - template inline constexpr ResourceKey(const char(&key)[size]): Corrade::Utility::MurmurHash2::Digest(Corrade::Utility::MurmurHash2()(key)) {} + template constexpr ResourceKey(const char(&key)[size]): Utility::MurmurHash2::Digest(Utility::MurmurHash2()(key)) {} }; /** @debugoperator{Magnum::ResourceKey} */ inline Debug operator<<(Debug debug, const ResourceKey& value) { - return debug << static_cast&>(value); + return debug << static_cast&>(value); } -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class ResourceManagerData; } -#endif /** @brief %Resource reference See ResourceManager for more information. */ -#ifndef DOXYGEN_GENERATING_OUTPUT -template -#else +#ifdef DOXYGEN_GENERATING_OUTPUT template +#else +template #endif class Resource { friend class Implementation::ResourceManagerData; @@ -129,60 +127,39 @@ class Resource { * Creates empty resource. Resources are acquired from the manager by * calling ResourceManager::get(). */ - inline explicit Resource(): manager(nullptr), lastCheck(0), _state(ResourceState::Final), data(nullptr) {} + explicit Resource(): manager(nullptr), lastCheck(0), _state(ResourceState::Final), data(nullptr) {} /** @brief Copy constructor */ - inline Resource(const Resource& other): manager(other.manager), _key(other._key), lastCheck(other.lastCheck), _state(other._state), data(other.data) { + Resource(const Resource& other): manager(other.manager), _key(other._key), lastCheck(other.lastCheck), _state(other._state), data(other.data) { if(manager) manager->incrementReferenceCount(_key); } /** @brief Move constructor */ - inline Resource(Resource&& other): manager(other.manager), _key(other._key), lastCheck(other.lastCheck), _state(other._state), data(other.data) { + Resource(Resource&& other): manager(other.manager), _key(other._key), lastCheck(other.lastCheck), _state(other._state), data(other.data) { + /** @brief Make other's state well-defined */ other.manager = nullptr; } /** @brief Destructor */ - inline ~Resource() { + ~Resource() { if(manager) manager->decrementReferenceCount(_key); } - /** @brief Assignment operator */ - Resource& operator=(const Resource& other) { - if(manager) manager->decrementReferenceCount(_key); - - manager = other.manager; - _key = other._key; - lastCheck = other.lastCheck; - _state = other._state; - data = other.data; - - if(manager) manager->incrementReferenceCount(_key); - return *this; - } - - /** @brief Assignment move operator */ - Resource& operator=(Resource&& other) { - if(manager) manager->decrementReferenceCount(_key); - - manager = other.manager; - _key = other._key; - lastCheck = other.lastCheck; - _state = other._state; - data = other.data; + /** @brief Copy assignment */ + Resource& operator=(const Resource& other); - other.manager = nullptr; - return *this; - } + /** @brief Move assignment */ + Resource& operator=(Resource&& other); /** @brief Resource key */ - inline ResourceKey key() const { return _key; } + ResourceKey key() const { return _key; } /** * @brief %Resource state * * @see operator bool(), ResourceManager::state() */ - inline ResourceState state() { + ResourceState state() { acquire(); return _state; } @@ -195,7 +172,7 @@ class Resource { * @ref ResourceState "ResourceState::Loading" or * @ref ResourceState "ResourceState::NotFound"), true otherwise. */ - inline operator bool() { + operator bool() { acquire(); return data; } @@ -206,61 +183,32 @@ class Resource { * The resource must be loaded before accessing it. Use boolean * conversion operator or state() for testing whether it is loaded. */ - inline operator U*() { + operator U*() { acquire(); CORRADE_ASSERT(data, "Resource: accessing not loaded data with key" << key(), nullptr); return static_cast(data); } /** @overload */ - inline U* operator->() { + U* operator->() { acquire(); CORRADE_ASSERT(data, "Resource: accessing not loaded data with key" << key(), nullptr); return static_cast(data); } /** @overload */ - inline U& operator*() { + U& operator*() { acquire(); CORRADE_ASSERT(data, "Resource: accessing not loaded data with key" << key(), *static_cast(data)); return *static_cast(data); } private: - inline Resource(Implementation::ResourceManagerData* manager, ResourceKey key): manager(manager), _key(key), lastCheck(0), _state(ResourceState::NotLoaded), data(nullptr) { + Resource(Implementation::ResourceManagerData* manager, ResourceKey key): manager(manager), _key(key), lastCheck(0), _state(ResourceState::NotLoaded), data(nullptr) { manager->incrementReferenceCount(key); } - void acquire() { - /* The data are already final, nothing to do */ - if(_state == ResourceState::Final) return; - - /* Nothing changed since last check */ - if(manager->lastChange() < lastCheck) return; - - /* Acquire new data and save last check time */ - const typename Implementation::ResourceManagerData::Data& d = manager->data(_key); - lastCheck = manager->lastChange(); - - /* Try to get the data */ - data = d.data; - _state = static_cast(d.state); - - /* Data are not available */ - if(!data) { - /* Fallback found, add *Fallback to state */ - if((data = manager->fallback())) { - if(_state == ResourceState::Loading) - _state = ResourceState::LoadingFallback; - else if(_state == ResourceState::NotFound) - _state = ResourceState::NotFoundFallback; - else _state = ResourceState::NotLoadedFallback; - - /* Fallback not found and loading didn't start yet */ - } else if(_state != ResourceState::Loading && _state != ResourceState::NotFound) - _state = ResourceState::NotLoaded; - } - } + void acquire(); Implementation::ResourceManagerData* manager; ResourceKey _key; @@ -269,6 +217,64 @@ class Resource { T* data; }; +template Resource& Resource::operator=(const Resource& other) { + if(manager) manager->decrementReferenceCount(_key); + + manager = other.manager; + _key = other._key; + lastCheck = other.lastCheck; + _state = other._state; + data = other.data; + + if(manager) manager->incrementReferenceCount(_key); + return *this; +} + +template Resource& Resource::operator=(Resource&& other) { + /** @todo Just swap the values */ + if(manager) manager->decrementReferenceCount(_key); + + manager = other.manager; + _key = other._key; + lastCheck = other.lastCheck; + _state = other._state; + data = other.data; + + other.manager = nullptr; + return *this; +} + +template void Resource::acquire() { + /* The data are already final, nothing to do */ + if(_state == ResourceState::Final) return; + + /* Nothing changed since last check */ + if(manager->lastChange() < lastCheck) return; + + /* Acquire new data and save last check time */ + const typename Implementation::ResourceManagerData::Data& d = manager->data(_key); + lastCheck = manager->lastChange(); + + /* Try to get the data */ + data = d.data; + _state = static_cast(d.state); + + /* Data are not available */ + if(!data) { + /* Fallback found, add *Fallback to state */ + if((data = manager->fallback())) { + if(_state == ResourceState::Loading) + _state = ResourceState::LoadingFallback; + else if(_state == ResourceState::NotFound) + _state = ResourceState::NotFoundFallback; + else _state = ResourceState::NotLoadedFallback; + + /* Fallback not found and loading didn't start yet */ + } else if(_state != ResourceState::Loading && _state != ResourceState::NotFound) + _state = ResourceState::NotLoaded; + } +} + } /* Make the definition complete */ diff --git a/src/ResourceManager.h b/src/ResourceManager.h index ac49cd889..cfef61a7a 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -29,6 +29,7 @@ */ #include +#include #include "Resource.h" @@ -89,199 +90,72 @@ enum class ResourcePolicy: UnsignedByte { template class AbstractResourceLoader; -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - struct ResourceKeyHash { - inline std::size_t operator()(ResourceKey key) const { - /* GCC 4.4 thinks reinterpret_cast will break strict aliasing, doing it with bit cast instead */ - return Corrade::Utility::bitCast(key); + +struct ResourceKeyHash { + std::size_t operator()(ResourceKey key) const { + /* GCC 4.4 thinks reinterpret_cast will break strict aliasing, doing it with bit cast instead */ + return Corrade::Utility::bitCast(key); + } +}; + +template class ResourceManagerData { + template friend class Magnum::Resource; + friend class AbstractResourceLoader; + + ResourceManagerData(const ResourceManagerData&) = delete; + ResourceManagerData(ResourceManagerData&&) = delete; + ResourceManagerData& operator=(const ResourceManagerData&) = delete; + ResourceManagerData& operator=(ResourceManagerData&&) = delete; + + public: + virtual ~ResourceManagerData(); + + std::size_t lastChange() const { return _lastChange; } + + std::size_t count() const { return _data.size(); } + + std::size_t referenceCount(ResourceKey key) const; + + ResourceState state(ResourceKey key) const; + + template Resource get(ResourceKey key); + + void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy); + + T* fallback() { return _fallback; } + const T* fallback() const { return _fallback; } + + void setFallback(T* data); + + void free(); + + AbstractResourceLoader* loader() { return _loader; } + const AbstractResourceLoader* loader() const { return _loader; } + + void setLoader(AbstractResourceLoader* loader); + + protected: + ResourceManagerData(): _fallback(nullptr), _loader(nullptr), _lastChange(0) {} + + private: + struct Data; + + const Data& data(ResourceKey key) { return _data[key]; } + + void incrementReferenceCount(ResourceKey key) { + ++_data[key].referenceCount; } - }; - - template class ResourceManagerData { - template friend class Magnum::Resource; - friend class AbstractResourceLoader; - - ResourceManagerData(const ResourceManagerData&) = delete; - ResourceManagerData(ResourceManagerData&&) = delete; - ResourceManagerData& operator=(const ResourceManagerData&) = delete; - ResourceManagerData& operator=(ResourceManagerData&&) = delete; - - public: - inline virtual ~ResourceManagerData() { - delete _fallback; - - if(_loader) { - _loader->manager = nullptr; - delete _loader; - } - } - - inline std::size_t lastChange() const { return _lastChange; } - - inline std::size_t count() const { return _data.size(); } - - std::size_t referenceCount(ResourceKey key) const { - auto it = _data.find(key); - if(it == _data.end()) return 0; - return it->second.referenceCount; - } - - ResourceState state(ResourceKey key) const { - auto it = _data.find(key); - - /* Resource not loaded */ - if(it == _data.end() || !it->second.data) { - /* Fallback found, add *Fallback to state */ - if(_fallback) { - if(it != _data.end() && it->second.state == ResourceDataState::Loading) - return ResourceState::LoadingFallback; - else if(it != _data.end() && it->second.state == ResourceDataState::NotFound) - return ResourceState::NotFoundFallback; - else return ResourceState::NotLoadedFallback; - } - - /* Fallback not found, loading didn't start yet */ - if(it == _data.end() || (it->second.state != ResourceDataState::Loading && it->second.state != ResourceDataState::NotFound)) - return ResourceState::NotLoaded; - } - - /* Loading / NotFound without fallback, Mutable / Final */ - return static_cast(it->second.state); - } - - template inline Resource get(ResourceKey key) { - /* Ask loader for the data, if they aren't there yet */ - if(_loader && _data.find(key) == _data.end()) - _loader->load(key); - - return Resource(this, key); - } - - void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { - auto it = _data.find(key); - - /* NotFound / Loading state shouldn't have any data */ - CORRADE_ASSERT((data == nullptr) == (state == ResourceDataState::NotFound || state == ResourceDataState::Loading), - "ResourceManager::set(): data should be null if and only if state is NotFound or Loading", ); - - /* Cannot change resource with already final state */ - CORRADE_ASSERT(it == _data.end() || it->second.state != ResourceDataState::Final, - "ResourceManager::set(): cannot change already final resource" << key, ); - - /* If nothing is referencing reference-counted resource, we're done */ - if(policy == ResourcePolicy::ReferenceCounted && (it == _data.end() || it->second.referenceCount == 0)) { - Corrade::Utility::Warning() << "ResourceManager: Reference-counted resource with key" << key << "isn't referenced from anywhere, deleting it immediately"; - delete data; - - /* Delete also already present resource (it could be here - because previous policy could be other than - ReferenceCounted) */ - if(it != _data.end()) _data.erase(it); - - return; - - /* Insert it, if not already here */ - } else if(it == _data.end()) - it = _data.insert(std::make_pair(key, Data())).first; - - /* Replace previous data */ - delete it->second.data; - it->second.data = data; - it->second.state = state; - it->second.policy = policy; - ++_lastChange; - } - - inline T* fallback() { return _fallback; } - inline const T* fallback() const { return _fallback; } - - inline void setFallback(T* data) { - delete _fallback; - _fallback = data; - } - - void free() { - /* Delete all non-referenced non-resident resources */ - for(auto it = _data.begin(); it != _data.end(); ) { - if(it->second.policy != ResourcePolicy::Resident && !it->second.referenceCount) - it = _data.erase(it); - else ++it; - } - } - - inline AbstractResourceLoader* loader() { return _loader; } - inline const AbstractResourceLoader* loader() const { return _loader; } - - inline void setLoader(AbstractResourceLoader* loader) { - /* Delete previous loader */ - delete _loader; - - /* Add new loader */ - _loader = loader; - if(_loader) _loader->manager = this; - } - - protected: - inline ResourceManagerData(): _fallback(nullptr), _loader(nullptr), _lastChange(0) {} - - private: - struct Data { - Data& operator=(const Data&) = delete; - Data& operator=(Data&&) = delete; - - inline Data(): data(nullptr), state(ResourceDataState::Mutable), policy(ResourcePolicy::Manual), referenceCount(0) {} - - /* Fugly hack for GCC 4.5, because std::pair doesn't have move constructor yet */ - #ifndef CORRADE_GCC45_COMPATIBILITY - Data(const Data&) = delete; - #else - Data(const Data& other): data(other.data), state(other.state), policy(other.policy), referenceCount(other.referenceCount) { - const_cast(other).data = nullptr; - const_cast(other).referenceCount = 0; - } - #endif - - inline Data(Data&& other): data(other.data), state(other.state), policy(other.policy), referenceCount(other.referenceCount) { - other.data = nullptr; - other.referenceCount = 0; - } - - inline ~Data() { - CORRADE_ASSERT(referenceCount == 0, - "ResourceManager::~ResourceManager(): destroyed while data are still referenced", ); - delete data; - } - - T* data; - ResourceDataState state; - ResourcePolicy policy; - std::size_t referenceCount; - }; - - inline const Data& data(ResourceKey key) { - return _data[key]; - } - - inline void incrementReferenceCount(ResourceKey key) { - ++_data[key].referenceCount; - } - - inline void decrementReferenceCount(ResourceKey key) { - auto it = _data.find(key); - - /* Free the resource if it is reference counted */ - if(--it->second.referenceCount == 0 && it->second.policy == ResourcePolicy::ReferenceCounted) - _data.erase(it); - } - - std::unordered_map _data; - T* _fallback; - AbstractResourceLoader* _loader; - std::size_t _lastChange; - }; + + void decrementReferenceCount(ResourceKey key); + + std::unordered_map _data; + T* _fallback; + AbstractResourceLoader* _loader; + std::size_t _lastChange; +}; + } -#endif /** @brief %Resource manager @@ -354,10 +228,7 @@ cube->draw(); template class ResourceManager: private Implementation::ResourceManagerData... { public: /** @brief Global instance */ - inline static ResourceManager* instance() { - CORRADE_ASSERT(internalInstance(), "ResourceManager::instance(): no instance exists", nullptr); - return internalInstance(); - } + static ResourceManager* instance(); /** * @brief Constructor @@ -367,10 +238,7 @@ template class ResourceManager: private Implementation::Resource * created. * @see instance() */ - inline ResourceManager() { - CORRADE_ASSERT(!internalInstance(), "ResourceManager::ResourceManager(): another instance is already created", ); - internalInstance() = this; - } + explicit ResourceManager(); /** * @brief Destructor @@ -378,13 +246,10 @@ template class ResourceManager: private Implementation::Resource * Sets global instance pointer to `nullptr`. * @see instance() */ - inline ~ResourceManager() { - CORRADE_INTERNAL_ASSERT(internalInstance() == this); - internalInstance() = nullptr; - } + ~ResourceManager(); /** @brief Count of resources of given type */ - template inline std::size_t count() { + template std::size_t count() { return this->Implementation::ResourceManagerData::count(); } @@ -400,7 +265,7 @@ template class ResourceManager: private Implementation::Resource * Resource shader = manager->get("shader"); * @endcode */ - template inline Resource get(ResourceKey key) { + template Resource get(ResourceKey key) { return this->Implementation::ResourceManagerData::template get(key); } @@ -409,7 +274,7 @@ template class ResourceManager: private Implementation::Resource * * @see set() */ - template inline std::size_t referenceCount(ResourceKey key) const { + template std::size_t referenceCount(ResourceKey key) const { return this->Implementation::ResourceManagerData::referenceCount(key); } @@ -418,12 +283,13 @@ template class ResourceManager: private Implementation::Resource * * @see set(), Resource::state() */ - template inline ResourceState state(ResourceKey key) const { + template ResourceState state(ResourceKey key) const { return this->Implementation::ResourceManagerData::state(key); } /** * @brief Set resource data + * @return Pointer to self (for method chaining) * * If @p policy is set to `ResourcePolicy::ReferenceCounted`, there * must be already at least one reference to given resource, otherwise @@ -440,70 +306,87 @@ template class ResourceManager: private Implementation::Resource * subsequent updates are not possible. * @see referenceCount(), state() */ - template inline void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { + template ResourceManager* set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { this->Implementation::ResourceManagerData::set(key, data, state, policy); + return this; } /** * @brief Set resource data + * @return Pointer to self (for method chaining) * * Same as above function with state set to @ref ResourceDataState "ResourceDataState::Final" * and policy to @ref ResourcePolicy "ResourcePolicy::Resident". */ - template inline void set(ResourceKey key, T* data) { + template ResourceManager* set(ResourceKey key, T* data) { this->Implementation::ResourceManagerData::set(key, data, ResourceDataState::Final, ResourcePolicy::Resident); + return this; } /** @brief Fallback for not found resources */ - template inline T* fallback() { + template T* fallback() { return this->Implementation::ResourceManagerData::fallback(); } /** @overload */ - template inline const T* fallback() const { + template const T* fallback() const { return this->Implementation::ResourceManagerData::fallback(); } - /** @brief Set fallback for not found resources */ - template inline void setFallback(T* data) { - return this->Implementation::ResourceManagerData::setFallback(data); + /** + * @brief Set fallback for not found resources + * @return Pointer to self (for method chaining) + */ + template ResourceManager* setFallback(T* data) { + this->Implementation::ResourceManagerData::setFallback(data); + return this; } - /** @brief Free all resources of given type which are not referenced */ - template inline void free() { - return this->Implementation::ResourceManagerData::free(); + /** + * @brief Free all resources of given type which are not referenced + * @return Pointer to self (for method chaining) + */ + template ResourceManager* free() { + this->Implementation::ResourceManagerData::free(); + return this; } - /** @brief Free all resources which are not referenced */ - inline void free() { + /** + * @brief Free all resources which are not referenced + * @return Pointer to self (for method chaining) + */ + ResourceManager* free() { freeInternal(std::common_type()...); + return this; } /** @brief Loader for given type of resources */ - template inline AbstractResourceLoader* loader() { + template AbstractResourceLoader* loader() { return this->Implementation::ResourceManagerData::loader(); } /** @overload */ - template inline const AbstractResourceLoader* loader() const { + template const AbstractResourceLoader* loader() const { return this->Implementation::ResourceManagerData::loader(); } /** * @brief Set loader for given type of resources + * @return Pointer to self (for method chaining) * * See AbstractResourceLoader documentation for more information. */ - template inline void setLoader(AbstractResourceLoader* loader) { - return this->Implementation::ResourceManagerData::setLoader(loader); + template ResourceManager* setLoader(AbstractResourceLoader* loader) { + this->Implementation::ResourceManagerData::setLoader(loader); + return this; } private: - template inline void freeInternal(std::common_type, std::common_type... t) { + template void freeInternal(std::common_type, std::common_type... t) { free(); freeInternal(t...); } - inline void freeInternal() const {} + void freeInternal() const {} static ResourceManager*& internalInstance(); }; @@ -515,6 +398,171 @@ template ResourceManager*& ResourceManager:: } #endif +namespace Implementation { + +template ResourceManagerData::~ResourceManagerData() { + delete _fallback; + + if(_loader) { + _loader->manager = nullptr; + delete _loader; + } +} + +template std::size_t ResourceManagerData::referenceCount(const ResourceKey key) const { + auto it = _data.find(key); + if(it == _data.end()) return 0; + return it->second.referenceCount; +} + +template ResourceState ResourceManagerData::state(const ResourceKey key) const { + const auto it = _data.find(key); + + /* Resource not loaded */ + if(it == _data.end() || !it->second.data) { + /* Fallback found, add *Fallback to state */ + if(_fallback) { + if(it != _data.end() && it->second.state == ResourceDataState::Loading) + return ResourceState::LoadingFallback; + else if(it != _data.end() && it->second.state == ResourceDataState::NotFound) + return ResourceState::NotFoundFallback; + else return ResourceState::NotLoadedFallback; + } + + /* Fallback not found, loading didn't start yet */ + if(it == _data.end() || (it->second.state != ResourceDataState::Loading && it->second.state != ResourceDataState::NotFound)) + return ResourceState::NotLoaded; + } + + /* Loading / NotFound without fallback, Mutable / Final */ + return static_cast(it->second.state); +} + +template template Resource ResourceManagerData::get(ResourceKey key) { + /* Ask loader for the data, if they aren't there yet */ + if(_loader && _data.find(key) == _data.end()) + _loader->load(key); + + return Resource(this, key); +} + +template void ResourceManagerData::set(const ResourceKey key, T* const data, const ResourceDataState state, const ResourcePolicy policy) { + auto it = _data.find(key); + + /* NotFound / Loading state shouldn't have any data */ + CORRADE_ASSERT((data == nullptr) == (state == ResourceDataState::NotFound || state == ResourceDataState::Loading), + "ResourceManager::set(): data should be null if and only if state is NotFound or Loading", ); + + /* Cannot change resource with already final state */ + CORRADE_ASSERT(it == _data.end() || it->second.state != ResourceDataState::Final, + "ResourceManager::set(): cannot change already final resource" << key, ); + + /* If nothing is referencing reference-counted resource, we're done */ + if(policy == ResourcePolicy::ReferenceCounted && (it == _data.end() || it->second.referenceCount == 0)) { + Warning() << "ResourceManager: Reference-counted resource with key" << key << "isn't referenced from anywhere, deleting it immediately"; + delete data; + + /* Delete also already present resource (it could be here + because previous policy could be other than + ReferenceCounted) */ + if(it != _data.end()) _data.erase(it); + + return; + + /* Insert it, if not already here */ + } else if(it == _data.end()) + it = _data.insert(std::make_pair(key, Data())).first; + + /* Replace previous data */ + delete it->second.data; + it->second.data = data; + it->second.state = state; + it->second.policy = policy; + ++_lastChange; +} + +template void ResourceManagerData::setFallback(T* const data) { + delete _fallback; + _fallback = data; +} + +template void ResourceManagerData::free() { + /* Delete all non-referenced non-resident resources */ + for(auto it = _data.begin(); it != _data.end(); ) { + if(it->second.policy != ResourcePolicy::Resident && !it->second.referenceCount) + it = _data.erase(it); + else ++it; + } +} + +template void ResourceManagerData::setLoader(AbstractResourceLoader* const loader) { + /* Delete previous loader */ + delete _loader; + + /* Add new loader */ + if((_loader = loader)) _loader->manager = this; +} + +template void ResourceManagerData::decrementReferenceCount(ResourceKey key) { + auto it = _data.find(key); + + /* Free the resource if it is reference counted */ + if(--it->second.referenceCount == 0 && it->second.policy == ResourcePolicy::ReferenceCounted) + _data.erase(it); +} + +template struct ResourceManagerData::Data { + Data& operator=(const Data&) = delete; + Data& operator=(Data&&) = delete; + + Data(): data(nullptr), state(ResourceDataState::Mutable), policy(ResourcePolicy::Manual), referenceCount(0) {} + + /* Fugly hack for GCC 4.5, because std::pair doesn't have move constructor yet */ + #ifndef CORRADE_GCC45_COMPATIBILITY + Data(const Data&) = delete; + #else + Data(const Data& other): data(other.data), state(other.state), policy(other.policy), referenceCount(other.referenceCount) { + const_cast(other).data = nullptr; + const_cast(other).referenceCount = 0; + } + #endif + + Data(Data&& other): data(other.data), state(other.state), policy(other.policy), referenceCount(other.referenceCount) { + other.data = nullptr; + other.referenceCount = 0; + } + + ~Data(); + + T* data; + ResourceDataState state; + ResourcePolicy policy; + std::size_t referenceCount; +}; + +template inline ResourceManagerData::Data::~Data() { + CORRADE_ASSERT(referenceCount == 0, + "ResourceManager::~ResourceManager(): destroyed while data are still referenced", ); + delete data; +} + +} + +template ResourceManager* ResourceManager::instance() { + CORRADE_ASSERT(internalInstance(), "ResourceManager::instance(): no instance exists", nullptr); + return internalInstance(); +} + +template ResourceManager::ResourceManager() { + CORRADE_ASSERT(!internalInstance(), "ResourceManager::ResourceManager(): another instance is already created", ); + internalInstance() = this; +} + +template ResourceManager::~ResourceManager() { + CORRADE_INTERNAL_ASSERT(internalInstance() == this); + internalInstance() = nullptr; +} + } /* Make the definition complete */ diff --git a/src/Sampler.cpp b/src/Sampler.cpp new file mode 100644 index 000000000..43160854e --- /dev/null +++ b/src/Sampler.cpp @@ -0,0 +1,61 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Sampler.h" + +#include "Context.h" +#include "Implementation/State.h" +#include "Implementation/TextureState.h" + +namespace Magnum { + +/* Check correctness of binary OR in setMinificationFilter(). If nobody fucks + anything up, this assert should produce the same results on all dimensions, + thus testing only on AbstractTexture. */ +#define filter_or(filter, mipmap) (GLint(Sampler::Filter::filter)|GLint(Sampler::Mipmap::mipmap)) +static_assert((filter_or(Nearest, Base) == GL_NEAREST) && + (filter_or(Nearest, Nearest) == GL_NEAREST_MIPMAP_NEAREST) && + (filter_or(Nearest, Linear) == GL_NEAREST_MIPMAP_LINEAR) && + (filter_or(Linear, Base) == GL_LINEAR) && + (filter_or(Linear, Nearest) == GL_LINEAR_MIPMAP_NEAREST) && + (filter_or(Linear, Linear) == GL_LINEAR_MIPMAP_LINEAR), + "Unsupported constants for GL texture filtering"); +#undef filter_or + +#ifndef MAGNUM_TARGET_GLES3 +Float Sampler::maxSupportedAnisotropy() { + GLfloat& value = Context::current()->state()->texture->maxSupportedAnisotropy; + + /** @todo Re-enable when extension header is available */ + #ifndef MAGNUM_TARGET_GLES + /* Get the value, if not already cached */ + if(value == 0.0f) + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value); + #endif + + return value; +} +#endif + +} diff --git a/src/Sampler.h b/src/Sampler.h new file mode 100644 index 000000000..83d390aca --- /dev/null +++ b/src/Sampler.h @@ -0,0 +1,139 @@ +#ifndef Magnum_Sampler_h +#define Magnum_Sampler_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Sampler + */ + +#include "Types.h" +#include "OpenGL.h" + +namespace Magnum { + +/** +@brief %Texture sampler + +@see Texture, CubeMapTexture, CubeMapTextureArray +*/ +class Sampler { + public: + /** + * @brief %Texture filtering + * + * @see setMagnificationFilter() and setMinificationFilter() + */ + enum class Filter: GLint { + Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ + + /** + * Linear interpolation filtering. + * @requires_gles30 %Extension @es_extension{OES,texture_float_linear} / + * @es_extension2{OES,texture_half_float_linear,OES_texture_float_linear} + * for linear interpolation of textures with + * @ref Magnum::TextureFormat "TextureFormat::HalfFloat" / + * @ref Magnum::TextureFormat "TextureFormat::Float" in OpenGL + * ES 2.0. + */ + Linear = GL_LINEAR + }; + + /** + * @brief Mip level selection + * + * @see setMinificationFilter() + */ + enum class Mipmap: GLint { + Base = GL_NEAREST & ~GL_NEAREST, /**< Select base mip level */ + + /** + * Select nearest mip level. **Unavailable on rectangle textures.** + */ + Nearest = GL_NEAREST_MIPMAP_NEAREST & ~GL_NEAREST, + + /** + * Linear interpolation of nearest mip levels. **Unavailable on + * rectangle textures.** + * @requires_gles30 %Extension @es_extension{OES,texture_float_linear} / + * @es_extension2{OES,texture_half_float_linear,OES_texture_float_linear} + * for linear interpolation of textures with + * @ref Magnum::TextureFormat "TextureFormat::HalfFloat" / + * @ref Magnum::TextureFormat "TextureFormat::Float" in OpenGL + * ES 2.0. + */ + Linear = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST + }; + + /** + * @brief %Texture wrapping + * + * @see setWrapping() + */ + enum class Wrapping: GLint { + /** Repeat texture. **Unavailable on rectangle textures.** */ + Repeat = GL_REPEAT, + + /** + * Repeat mirrored texture. **Unavailable on rectangle textures.** + */ + MirroredRepeat = GL_MIRRORED_REPEAT, + + /** + * Clamp to edge. Coordinates out of the range will be clamped to + * first / last column / row in given direction. + */ + ClampToEdge = GL_CLAMP_TO_EDGE, + + #ifndef MAGNUM_TARGET_GLES3 + /** + * Clamp to border color. Coordinates out of range will be clamped + * to border color (set with setBorderColor()). + * @requires_es_extension %Extension @es_extension{NV,texture_border_clamp} + */ + #ifndef MAGNUM_TARGET_GLES + ClampToBorder = GL_CLAMP_TO_BORDER + #else + ClampToBorder = GL_CLAMP_TO_BORDER_NV + #endif + #endif + }; + + #ifndef MAGNUM_TARGET_GLES3 + /** + * @brief Max supported anisotropy + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. + * @see setMaxAnisotropy(), @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT} + * @requires_extension %Extension @extension{EXT,texture_filter_anisotropic} + * @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic} + */ + static Float maxSupportedAnisotropy(); + #endif +}; + +} + +#endif diff --git a/src/SceneGraph/AbstractCamera.h b/src/SceneGraph/AbstractCamera.h index f1128651a..43287ba10 100644 --- a/src/SceneGraph/AbstractCamera.h +++ b/src/SceneGraph/AbstractCamera.h @@ -36,7 +36,7 @@ namespace Magnum { namespace SceneGraph { -/** @relates AbstractCamera +/** @brief Camera aspect ratio policy @see AbstractCamera::setAspectRatioPolicy() @@ -47,11 +47,9 @@ enum class AspectRatioPolicy: UnsignedByte { Clip /**< Clip on smaller side of view */ }; -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template typename DimensionTraits::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2& projectionScale, const Vector2i& viewport); } -#endif /** @brief Base for cameras @@ -90,7 +88,7 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature::MatrixType cameraMatrix() { + typename DimensionTraits::MatrixType cameraMatrix() { AbstractFeature::object()->setClean(); return _cameraMatrix; } @@ -116,7 +114,7 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature::MatrixType projectionMatrix() const { return _projectionMatrix; } + typename DimensionTraits::MatrixType projectionMatrix() const { return _projectionMatrix; } /** * @brief Size of (near) XY plane in current projection @@ -124,12 +122,12 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature projectionSize() const { + Math::Vector2 projectionSize() const { return {T(2.0)/_projectionMatrix[0].x(), T(2.0)/_projectionMatrix[1].y()}; } /** @brief Viewport size */ - inline Vector2i viewport() const { return _viewport; } + Vector2i viewport() const { return _viewport; } /** * @brief Set viewport size @@ -149,12 +147,12 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature::MatrixType& invertedAbsoluteTransformationMatrix) override { + void cleanInverted(const typename DimensionTraits::MatrixType& invertedAbsoluteTransformationMatrix) override { _cameraMatrix = invertedAbsoluteTransformationMatrix; } #ifndef DOXYGEN_GENERATING_OUTPUT - inline void fixAspectRatio() { + void fixAspectRatio() { _projectionMatrix = Implementation::aspectRatioFix(_aspectRatioPolicy, {rawProjectionMatrix[0].x(), rawProjectionMatrix[1].y()}, _viewport)*rawProjectionMatrix; } diff --git a/src/SceneGraph/AbstractCamera.hpp b/src/SceneGraph/AbstractCamera.hpp index f2ecd960b..413cc4b86 100644 --- a/src/SceneGraph/AbstractCamera.hpp +++ b/src/SceneGraph/AbstractCamera.hpp @@ -36,20 +36,19 @@ using namespace std; namespace Magnum { namespace SceneGraph { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class Camera {}; template class Camera<2, T> { public: - inline constexpr static Math::Matrix3 aspectRatioScale(const Math::Vector2& scale) { + constexpr static Math::Matrix3 aspectRatioScale(const Math::Vector2& scale) { return Math::Matrix3::scaling({scale.x(), scale.y()}); } }; template class Camera<3, T> { public: - inline constexpr static Math::Matrix4 aspectRatioScale(const Math::Vector2& scale) { + constexpr static Math::Matrix4 aspectRatioScale(const Math::Vector2& scale) { return Math::Matrix4::scaling({scale.x(), scale.y(), 1.0f}); } }; @@ -70,10 +69,9 @@ template typename DimensionTraits AbstractCamera::AbstractCamera(AbstractObject* object): AbstractFeature(object), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) { - AbstractFeature::setCachedTransformations(AbstractFeature::CachedTransformation::InvertedAbsolute); + AbstractFeature::setCachedTransformations(CachedTransformation::InvertedAbsolute); } template AbstractCamera::~AbstractCamera() {} @@ -90,7 +88,7 @@ template void AbstractCamera::se } template void AbstractCamera::draw(DrawableGroup& group) { - AbstractObject* scene = AbstractFeature::object()->sceneObject(); + AbstractObject* scene = AbstractFeature::object()->scene(); CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", ); /* Compute camera matrix */ diff --git a/src/SceneGraph/AbstractFeature.h b/src/SceneGraph/AbstractFeature.h index e77137611..ea421e132 100644 --- a/src/SceneGraph/AbstractFeature.h +++ b/src/SceneGraph/AbstractFeature.h @@ -25,7 +25,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractFeature, alias Magnum::SceneGraph::AbstractFeature2D, Magnum::SceneGraph::AbstractFeature3D + * @brief Class Magnum::SceneGraph::AbstractFeature, alias Magnum::SceneGraph::AbstractFeature2D, Magnum::SceneGraph::AbstractFeature3D, enum Magnum::SceneGraph::CachedTransformation, enum set Magnum::SceneGraph::CachedTransformations */ #include @@ -36,18 +36,41 @@ namespace Magnum { namespace SceneGraph { -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - enum class FeatureCachedTransformation: UnsignedByte { - Absolute = 1 << 0, - InvertedAbsolute = 1 << 1 - }; +/** +@brief Which transformation to cache in given feature + +@see @ref scenegraph-caching, CachedTransformations, + AbstractFeature::setCachedTransformations(), AbstractFeature::clean(), + AbstractFeature::cleanInverted() +@todo Provide also simpler representations from which could benefit + other transformation implementations, as they won't need to + e.g. create transformation matrix from quaternion? + */ +enum class CachedTransformation: UnsignedByte { + /** + * Absolute transformation is cached. + * + * If enabled, clean() is called when cleaning object. + */ + Absolute = 1 << 0, + + /** + * Inverted absolute transformation is cached. + * + * If enabled, cleanInverted() is called when cleaning object. + */ + InvertedAbsolute = 1 << 1 +}; - typedef Corrade::Containers::EnumSet FeatureCachedTransformations; +/** +@brief Which transformations to cache in this feature - CORRADE_ENUMSET_OPERATORS(FeatureCachedTransformations) -} -#endif +@see @ref scenegraph-caching, AbstractFeature::setCachedTransformations(), + AbstractFeature::clean(), AbstractFeature::cleanInverted() +*/ +typedef Containers::EnumSet CachedTransformations; + +CORRADE_ENUMSET_OPERATORS(CachedTransformations) /** @brief Base for object features @@ -110,7 +133,7 @@ parameter: @code class TransformingFeature: public SceneGraph::AbstractFeature3D<> { public: - template inline TransformingFeature(SceneGraph::Object* object): + template TransformingFeature(SceneGraph::Object* object): SceneGraph::AbstractFeature3D<>(object), transformation(object) {} private: @@ -125,16 +148,26 @@ which is derived from @ref AbstractTranslationRotation3D "AbstractTranslationRotation3D<>", which is automatically extracted from the pointer in our constructor. +@section AbstractFeature-explicit-specializations Explicit template specializations + +The following specialization are explicitly compiled into %SceneGraph library. +For other specializations (e.g. using Double type) you have to use +AbstractFeature.hpp implementation file to avoid linker errors. See also +@ref compilation-speedup-hpp for more information. + + - @ref AbstractFeature "AbstractFeature<2, Float>" + - @ref AbstractFeature "AbstractFeature<3, Float>" + @see AbstractFeature2D, AbstractFeature3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template class AbstractFeature: private Corrade::Containers::LinkedListItem, AbstractObject> +template class MAGNUM_SCENEGRAPH_EXPORT AbstractFeature: private Containers::LinkedListItem, AbstractObject> #else template class AbstractFeature #endif { - friend class Corrade::Containers::LinkedList>; - friend class Corrade::Containers::LinkedListItem, AbstractObject>; + friend class Containers::LinkedList>; + friend class Containers::LinkedListItem, AbstractObject>; template friend class Object; public: @@ -142,40 +175,38 @@ template class AbstractFeature * @brief Constructor * @param object %Object holding this feature */ - inline explicit AbstractFeature(AbstractObject* object) { - object->Corrade::Containers::template LinkedList>::insert(this); - } + explicit AbstractFeature(AbstractObject* object); virtual ~AbstractFeature() = 0; /** @brief %Object holding this feature */ - inline AbstractObject* object() { - return Corrade::Containers::LinkedListItem, AbstractObject>::list(); + AbstractObject* object() { + return Containers::LinkedListItem, AbstractObject>::list(); } /** @overload */ - inline const AbstractObject* object() const { - return Corrade::Containers::LinkedListItem, AbstractObject>::list(); + const AbstractObject* object() const { + return Containers::LinkedListItem, AbstractObject>::list(); } /** @brief Previous feature or `nullptr`, if this is first feature */ - inline AbstractFeature* previousFeature() { - return Corrade::Containers::LinkedListItem, AbstractObject>::previous(); + AbstractFeature* previousFeature() { + return Containers::LinkedListItem, AbstractObject>::previous(); } /** @overload */ - inline const AbstractFeature* previousFeature() const { - return Corrade::Containers::LinkedListItem, AbstractObject>::previous(); + const AbstractFeature* previousFeature() const { + return Containers::LinkedListItem, AbstractObject>::previous(); } /** @brief Next feature or `nullptr`, if this is last feature */ - inline AbstractFeature* nextFeature() { - return Corrade::Containers::LinkedListItem, AbstractObject>::next(); + AbstractFeature* nextFeature() { + return Containers::LinkedListItem, AbstractObject>::next(); } /** @overload */ - inline const AbstractFeature* nextFeature() const { - return Corrade::Containers::LinkedListItem, AbstractObject>::next(); + const AbstractFeature* nextFeature() const { + return Containers::LinkedListItem, AbstractObject>::next(); } /** @@ -184,53 +215,14 @@ template class AbstractFeature * See @ref scenegraph-caching for more information. */ - /** - * @brief Which transformation to cache in this feature - * - * @see @ref scenegraph-caching, CachedTransformations, - * setCachedTransformations(), clean(), cleanInverted() - * @todo Provide also simpler representations from which could benefit - * other transformation implementations, as they won't need to - * e.g. create transformation matrix from quaternion? - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - typedef Implementation::FeatureCachedTransformation CachedTransformation; - #else - enum class CachedTransformation: UnsignedByte { - /** - * Absolute transformation is cached. - * - * If enabled, clean() is called when cleaning object. - */ - Absolute = 1 << 0, - - /** - * Inverted absolute transformation is cached. - * - * If enabled, cleanInverted() is called when cleaning object. - */ - InvertedAbsolute = 1 << 1 - }; - #endif - - /** - * @brief Which transformations to cache in this feature - * - * @see @ref scenegraph-caching, setCachedTransformations(), clean(), - * cleanInverted() - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - typedef Implementation::FeatureCachedTransformations CachedTransformations; - #else - typedef Corrade::Containers::EnumSet CachedTransformations; - #endif - /** * @brief Which transformations are cached * * @see @ref scenegraph-caching, clean(), cleanInverted() */ - inline CachedTransformations cachedTransformations() const { return _cachedTransformations; } + CachedTransformations cachedTransformations() const { + return _cachedTransformations; + } protected: /** @@ -243,7 +235,9 @@ template class AbstractFeature * Nothing is enabled by default. * @see @ref scenegraph-caching */ - inline void setCachedTransformations(CachedTransformations transformations) { _cachedTransformations = transformations; } + void setCachedTransformations(CachedTransformations transformations) { + _cachedTransformations = transformations; + } /** * @brief Mark feature as dirty @@ -255,7 +249,7 @@ template class AbstractFeature * Default implementation does nothing. * @see @ref scenegraph-caching */ - inline virtual void markDirty() {} + virtual void markDirty(); /** * @brief Clean data based on absolute transformation @@ -290,10 +284,6 @@ template class AbstractFeature CachedTransformations _cachedTransformations; }; -template inline AbstractFeature::~AbstractFeature() {} -template inline void AbstractFeature::clean(const typename DimensionTraits::MatrixType&) {} -template inline void AbstractFeature::cleanInverted(const typename DimensionTraits::MatrixType&) {} - #ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base for two-dimensional features diff --git a/src/SceneGraph/AbstractFeature.hpp b/src/SceneGraph/AbstractFeature.hpp new file mode 100644 index 000000000..f0da6915e --- /dev/null +++ b/src/SceneGraph/AbstractFeature.hpp @@ -0,0 +1,49 @@ +#ifndef Magnum_SceneGraph_AbstractFeature_hpp +#define Magnum_SceneGraph_AbstractFeature_hpp +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief @ref compilation-speedup-hpp "Template implementation" for AbstractFeature.h + */ + +#include "AbstractFeature.h" + +namespace Magnum { namespace SceneGraph { + +template AbstractFeature::AbstractFeature(AbstractObject* object) { + object->Containers::template LinkedList>::insert(this); +} + +template AbstractFeature::~AbstractFeature() = default; + +template void AbstractFeature::markDirty() {} + +template void AbstractFeature::clean(const typename DimensionTraits::MatrixType&) {} + +template void AbstractFeature::cleanInverted(const typename DimensionTraits::MatrixType&) {} + +}} + +#endif diff --git a/src/SceneGraph/AbstractGroupedFeature.h b/src/SceneGraph/AbstractGroupedFeature.h index e0273d3a0..8b636c885 100644 --- a/src/SceneGraph/AbstractGroupedFeature.h +++ b/src/SceneGraph/AbstractGroupedFeature.h @@ -28,7 +28,6 @@ * @brief Class Magnum::SceneGraph::AbstractGroupedFeature, alias Magnum::SceneGraph::AbstractGroupedFeature2D, Magnum::SceneGraph::AbstractGroupedFeature3D */ -#include #include #include "AbstractFeature.h" @@ -53,6 +52,16 @@ class Drawable: public SceneGraph::AbstractGroupedFeature3D { typedef SceneGraph::FeatureGroup3D DrawableGroup; @endcode +@section AbstractGroupedFeature-explicit-specializations Explicit template specializations + +The following specialization are explicitly compiled into %SceneGraph library. +For other specializations (e.g. using Double type) you have to use +AbstractGroupedFeature.hpp implementation file to avoid linker errors. See also +@ref compilation-speedup-hpp for more information. + + - @ref AbstractFeatureGroup "AbstractFeatureGroup<2, Float>" + - @ref AbstractFeatureGroup "AbstractFeatureGroup<3, Float>" + @see @ref scenegraph, AbstractGroupedFeature2D, AbstractGroupedFeature3D, FeatureGroup, FeatureGroup2D, FeatureGroup3D */ @@ -73,7 +82,7 @@ class AbstractGroupedFeature: public AbstractFeature { * Adds the feature to the object and to group, if specified. * @see FeatureGroup::add() */ - inline explicit AbstractGroupedFeature(AbstractObject* object, FeatureGroup* group = nullptr): AbstractFeature(object), _group(nullptr) { + explicit AbstractGroupedFeature(AbstractObject* object, FeatureGroup* group = nullptr): AbstractFeature(object), _group(nullptr) { if(group) group->add(static_cast(this)); } @@ -83,17 +92,17 @@ class AbstractGroupedFeature: public AbstractFeature { * Removes the feature from object and from group, if it belongs to * any. */ - inline ~AbstractGroupedFeature() { + ~AbstractGroupedFeature() { if(_group) _group->remove(static_cast(this)); } /** @brief Group this feature belongs to */ - inline FeatureGroup* group() { + FeatureGroup* group() { return _group; } /** @overload */ - inline const FeatureGroup* group() const { + const FeatureGroup* group() const { return _group; } diff --git a/src/SceneGraph/AbstractObject.h b/src/SceneGraph/AbstractObject.h index 41c751230..d7e572cb3 100644 --- a/src/SceneGraph/AbstractObject.h +++ b/src/SceneGraph/AbstractObject.h @@ -56,17 +56,20 @@ for(AbstractFeature* feature = o->firstFeature(); feature; feature = feature->ne @see AbstractObject2D, AbstractObject3D */ -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT AbstractObject: private Corrade::Containers::LinkedList> -#else +#ifdef DOXYGEN_GENERATING_OUTPUT template class AbstractObject +#else +template class MAGNUM_SCENEGRAPH_EXPORT AbstractObject: private Containers::LinkedList> #endif { - friend class Corrade::Containers::LinkedList>; - friend class Corrade::Containers::LinkedListItem, AbstractObject>; + friend class Containers::LinkedList>; + friend class Containers::LinkedListItem, AbstractObject>; friend class AbstractFeature; public: + /** @brief Matrix type */ + typedef typename DimensionTraits::MatrixType MatrixType; + /** @brief Feature object type */ typedef AbstractFeature FeatureType; @@ -74,42 +77,38 @@ template class AbstractObject virtual ~AbstractObject(); /** @brief Whether this object has features */ - inline bool hasFeatures() const { - return !Corrade::Containers::LinkedList>::isEmpty(); + bool hasFeatures() const { + return !Containers::LinkedList>::isEmpty(); } /** @brief First object feature or `nullptr`, if this object has no features */ - inline FeatureType* firstFeature() { - return Corrade::Containers::LinkedList>::first(); + FeatureType* firstFeature() { + return Containers::LinkedList>::first(); } /** @overload */ - inline const FeatureType* firstFeature() const { - return Corrade::Containers::LinkedList>::first(); + const FeatureType* firstFeature() const { + return Containers::LinkedList>::first(); } /** @brief Last object feature or `nullptr`, if this object has no features */ - inline FeatureType* lastFeature() { - return Corrade::Containers::LinkedList>::last(); + FeatureType* lastFeature() { + return Containers::LinkedList>::last(); } /** @overload */ - inline const FeatureType* lastFeature() const { - return Corrade::Containers::LinkedList>::last(); + const FeatureType* lastFeature() const { + return Containers::LinkedList>::last(); } /** - * @brief %Scene object - * @return Root object which is also scene or `nullptr`, if the object - * is not part of any scene. - * - * @todo Rename to scene() when I fully understand and fix covariant - * return issues. + * @brief %Scene + * @return %Scene or `nullptr`, if the object is not part of any scene. */ - virtual AbstractObject* sceneObject() = 0; + AbstractObject* scene() { return doScene(); } /** @overload */ - virtual const AbstractObject* sceneObject() const = 0; + const AbstractObject* scene() const { return doScene(); } /** @{ @name Object transformation */ @@ -118,14 +117,18 @@ template class AbstractObject * * @see Object::transformation() */ - virtual typename DimensionTraits::MatrixType transformationMatrix() const = 0; + MatrixType transformationMatrix() const { + return doTransformationMatrix(); + } /** * @brief Transformation matrix relative to root object * * @see Object::absoluteTransformation() */ - virtual typename DimensionTraits::MatrixType absoluteTransformationMatrix() const = 0; + MatrixType absoluteTransformationMatrix() const { + return doAbsoluteTransformationMatrix(); + } /** * @brief Transformation matrices of given set of objects relative to this object @@ -133,10 +136,12 @@ 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::transformations() when + * Object type, use typesafe Object::transformationMatrices() when * possible. */ - virtual std::vector::MatrixType> transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix = (typename DimensionTraits::MatrixType())) const = 0; + std::vector transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const { + return doTransformationMatrices(objects, initialTransformationMatrix); + } /*@}*/ @@ -146,6 +151,18 @@ template class AbstractObject * See @ref scenegraph-caching for more information. */ + /** + * @brief Clean absolute transformations of given set of objects + * + * 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. + */ + static void setClean(const std::vector*>& objects) { + if(objects.empty()) return; + objects.front()->doSetClean(objects); + } + /** * @brief Whether absolute transformation is dirty * @@ -156,7 +173,7 @@ template class AbstractObject * * @see @ref scenegraph-caching */ - virtual bool isDirty() const = 0; + bool isDirty() const { return doIsDirty(); } /** * @brief Set object absolute transformation as dirty @@ -167,7 +184,7 @@ template class AbstractObject * function does nothing. * @see @ref scenegraph-caching, setClean(), isDirty() */ - virtual void setDirty() = 0; + void setDirty() { doSetDirty(); } /** * @brief Clean object absolute transformation @@ -182,19 +199,22 @@ template class AbstractObject * each object individually. * @see @ref scenegraph-caching, setDirty(), isDirty() */ - virtual void setClean() = 0; - - /** - * @brief Clean absolute transformations of given set of objects - * - * 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(const std::vector& objects) when - * possible. - */ - virtual void setClean(const std::vector*>& objects) const = 0; + void setClean() { doSetClean(); } /*@}*/ + + private: + virtual AbstractObject* doScene() = 0; + virtual const AbstractObject* doScene() const = 0; + + virtual MatrixType doTransformationMatrix() const = 0; + virtual MatrixType doAbsoluteTransformationMatrix() 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; }; #ifndef CORRADE_GCC46_COMPATIBILITY diff --git a/src/SceneGraph/AbstractTransformation.h b/src/SceneGraph/AbstractTransformation.h index 1717d576f..5f828a7a1 100644 --- a/src/SceneGraph/AbstractTransformation.h +++ b/src/SceneGraph/AbstractTransformation.h @@ -142,7 +142,18 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractTransformation { * @brief Reset object transformation * @return Pointer to self (for method chaining) */ - virtual AbstractTransformation* resetTransformation() = 0; + AbstractTransformation* resetTransformation() { + doResetTransformation(); + return this; + } + + #ifdef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + /** @brief Polymorphic implementation for resetTransformation() */ + virtual void doResetTransformation() = 0; }; /** @brief Transformation type */ diff --git a/src/SceneGraph/AbstractTranslationRotation2D.h b/src/SceneGraph/AbstractTranslationRotation2D.h index 612c08cbb..ad8336a70 100644 --- a/src/SceneGraph/AbstractTranslationRotation2D.h +++ b/src/SceneGraph/AbstractTranslationRotation2D.h @@ -54,7 +54,10 @@ class AbstractTranslationRotation2D: public AbstractTransformation<2, T> { * * @see Vector2::xAxis(), Vector2::yAxis() */ - virtual AbstractTranslationRotation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) = 0; + AbstractTranslationRotation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { + doTranslate(vector, type); + return this; + } /** * @brief Rotate object @@ -62,7 +65,29 @@ class AbstractTranslationRotation2D: public AbstractTransformation<2, T> { * @param type Transformation type * @return Pointer to self (for method chaining) */ - virtual AbstractTranslationRotation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) = 0; + AbstractTranslationRotation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { + doRotate(angle, type); + return this; + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + AbstractTranslationRotation2D* resetTransformation() { + AbstractTransformation<2, T>::resetTransformation(); + return this; + } + #endif + + #ifdef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + /** @brief Polymorphic implementation for translate() */ + virtual void doTranslate(const Math::Vector2& vector, TransformationType type) = 0; + + /** @brief Polymorphic implementation for rotate() */ + virtual void doRotate(Math::Rad angle, TransformationType type) = 0; }; template inline AbstractTranslationRotation2D::AbstractTranslationRotation2D() = default; diff --git a/src/SceneGraph/AbstractTranslationRotation3D.h b/src/SceneGraph/AbstractTranslationRotation3D.h index f2816ee24..7cc28b8c5 100644 --- a/src/SceneGraph/AbstractTranslationRotation3D.h +++ b/src/SceneGraph/AbstractTranslationRotation3D.h @@ -55,7 +55,10 @@ class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { * * @see Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis() */ - virtual AbstractTranslationRotation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) = 0; + AbstractTranslationRotation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { + doTranslate(vector, type); + return this; + } /** * @brief Rotate object @@ -67,7 +70,10 @@ class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { * @see rotateX(), rotateY(), rotateZ(), Vector3::xAxis(), * Vector3::yAxis(), Vector3::zAxis() */ - virtual AbstractTranslationRotation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) = 0; + AbstractTranslationRotation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { + doRotate(angle, normalizedAxis, type); + return this; + } /** * @brief Rotate object around X axis @@ -78,8 +84,9 @@ class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { * In some implementations faster than calling * `rotate(angle, Vector3::xAxis())`. */ - virtual AbstractTranslationRotation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { - return rotate(angle, Math::Vector3::xAxis(), type); + AbstractTranslationRotation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { + doRotateX(angle, type); + return this; } /** @@ -91,8 +98,9 @@ class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { * In some implementations faster than calling * `rotate(angle, Vector3::yAxis())`. */ - virtual AbstractTranslationRotation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { - return rotate(angle, Math::Vector3::yAxis(), type); + AbstractTranslationRotation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { + doRotateX(angle, type); + return this; } /** @@ -104,8 +112,55 @@ class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { * In some implementations faster than calling * `rotate(angle, Vector3::zAxis())`. */ - virtual AbstractTranslationRotation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { - return rotate(angle, Math::Vector3::zAxis(), type); + AbstractTranslationRotation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { + doRotateZ(angle, type); + return this; + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + AbstractTranslationRotation3D* resetTransformation() { + AbstractTransformation<3, T>::resetTransformation(); + return this; + } + #endif + + #ifdef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + /** @brief Polymorphic implementation for translate() */ + virtual void doTranslate(const Math::Vector3& vector, TransformationType type) = 0; + + /** @brief Polymorphic implementation for rotate() */ + virtual void doRotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type) = 0; + + /** + * @brief Polymorphic implementation for rotateX() + * + * Default implementation calls rotate() with Math::Vector3::xAxis(). + */ + virtual void doRotateX(Math::Rad angle, TransformationType type) { + rotate(angle, Math::Vector3::xAxis(), type); + } + + /** + * @brief Polymorphic implementation for rotateY() + * + * Default implementation calls rotate() with Math::Vector3::yAxis(). + */ + virtual void doRotateY(Math::Rad angle, TransformationType type) { + rotate(angle, Math::Vector3::yAxis(), type); + } + + /** + * @brief Polymorphic implementation for rotateZ() + * + * Default implementation calls rotate() with Math::Vector3::zAxis(). + */ + virtual void doRotateZ(Math::Rad angle, TransformationType type) { + rotate(angle, Math::Vector3::zAxis(), type); } }; diff --git a/src/SceneGraph/AbstractTranslationRotationScaling2D.h b/src/SceneGraph/AbstractTranslationRotationScaling2D.h index 8ea233cf8..8e39d16ad 100644 --- a/src/SceneGraph/AbstractTranslationRotationScaling2D.h +++ b/src/SceneGraph/AbstractTranslationRotationScaling2D.h @@ -54,7 +54,34 @@ class AbstractTranslationRotationScaling2D: public AbstractTranslationRotation2D * * @see Vector2::xScale(), Vector2::yScale() */ - virtual AbstractTranslationRotationScaling2D* scale(const Math::Vector2& vector, TransformationType type = TransformationType::Global) = 0; + AbstractTranslationRotationScaling2D* scale(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { + doScale(vector, type); + return this; + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + AbstractTranslationRotationScaling2D* resetTransformation() { + AbstractTranslationRotation2D::resetTransformation(); + return this; + } + AbstractTranslationRotationScaling2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation2D::translate(vector, type); + return this; + } + AbstractTranslationRotationScaling2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation2D::rotate(angle, type); + return this; + } + #endif + + #ifdef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + /** @brief Polymorphic implementation for scale() */ + virtual void doScale(const Math::Vector2& vector, TransformationType type) = 0; }; template inline AbstractTranslationRotationScaling2D::AbstractTranslationRotationScaling2D() = default; diff --git a/src/SceneGraph/AbstractTranslationRotationScaling3D.h b/src/SceneGraph/AbstractTranslationRotationScaling3D.h index 31e6fb5f6..18f814978 100644 --- a/src/SceneGraph/AbstractTranslationRotationScaling3D.h +++ b/src/SceneGraph/AbstractTranslationRotationScaling3D.h @@ -54,7 +54,46 @@ class AbstractTranslationRotationScaling3D: public AbstractTranslationRotation3D * * @see Vector3::xScale(), Vector3::yScale(), Vector3::zScale() */ - virtual AbstractTranslationRotationScaling3D* scale(const Math::Vector3& vector, TransformationType type = TransformationType::Global) = 0; + AbstractTranslationRotationScaling3D* scale(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { + doScale(vector, type); + return this; + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + AbstractTranslationRotationScaling3D* resetTransformation() { + AbstractTranslationRotation3D::resetTransformation(); + return this; + } + AbstractTranslationRotationScaling3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation3D::translate(vector, type); + return this; + } + AbstractTranslationRotationScaling3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation3D::rotate(angle, normalizedAxis, type); + return this; + } + AbstractTranslationRotationScaling3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation3D::rotateX(angle, type); + return this; + } + AbstractTranslationRotationScaling3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation3D::rotateY(angle, type); + return this; + } + AbstractTranslationRotationScaling3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { + AbstractTranslationRotation3D::rotateZ(angle, type); + return this; + } + #endif + + #ifdef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + /** @brief Polymorphic implementation for scale() */ + virtual void doScale(const Math::Vector3& vector, TransformationType type) = 0; }; template inline AbstractTranslationRotationScaling3D::AbstractTranslationRotationScaling3D() = default; diff --git a/src/SceneGraph/Animable.cpp b/src/SceneGraph/Animable.cpp index a424ef9bd..1087f8371 100644 --- a/src/SceneGraph/Animable.cpp +++ b/src/SceneGraph/Animable.cpp @@ -27,10 +27,10 @@ namespace Magnum { namespace SceneGraph { #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Animable<2>; -template class MAGNUM_SCENEGRAPH_EXPORT Animable<3>; -template class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup<2>; -template class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup<3>; +template class MAGNUM_SCENEGRAPH_EXPORT Animable<2, Float>; +template class MAGNUM_SCENEGRAPH_EXPORT Animable<3, Float>; +template class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup<2, Float>; +template class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup<3, Float>; #endif Debug operator<<(Debug debug, AnimationState value) { diff --git a/src/SceneGraph/Animable.h b/src/SceneGraph/Animable.h index 1d5cba5a9..207f4edf8 100644 --- a/src/SceneGraph/Animable.h +++ b/src/SceneGraph/Animable.h @@ -162,10 +162,10 @@ class MAGNUM_SCENEGRAPH_EXPORT Animable: public AbstractGroupedFeature* setRepeated(bool repeated) { + Animable* setRepeated(bool repeated) { _repeated = repeated; return this; } @@ -204,7 +204,7 @@ class MAGNUM_SCENEGRAPH_EXPORT Animable: public AbstractGroupedFeature* setRepeatCount(UnsignedShort count) { + Animable* setRepeatCount(UnsignedShort count) { _repeatCount = count; return this; } @@ -236,7 +236,7 @@ class MAGNUM_SCENEGRAPH_EXPORT Animable: public AbstractGroupedFeature* setDuration(Float duration) { + Animable* setDuration(Float duration) { _duration = duration; return this; } @@ -274,7 +274,7 @@ class MAGNUM_SCENEGRAPH_EXPORT Animable: public AbstractGroupedFeature ${MagnumSceneGraph_GracefulAssert_SRCS}) set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumSceneGraph_EXPORTS") - target_link_libraries(MagnumSceneGraphTestLib Magnum) + target_link_libraries(MagnumSceneGraphTestLib MagnumMathTestLib) add_subdirectory(Test) endif() diff --git a/src/SceneGraph/Camera2D.h b/src/SceneGraph/Camera2D.h index 68fea359e..ad52e41b6 100644 --- a/src/SceneGraph/Camera2D.h +++ b/src/SceneGraph/Camera2D.h @@ -82,7 +82,7 @@ class MAGNUM_SCENEGRAPH_EXPORT Camera2D: public AbstractCamera<2, T> { /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline Camera2D* setAspectRatioPolicy(AspectRatioPolicy policy) { + Camera2D* setAspectRatioPolicy(AspectRatioPolicy policy) { AbstractCamera<2, T>::setAspectRatioPolicy(policy); return this; } diff --git a/src/SceneGraph/Camera3D.h b/src/SceneGraph/Camera3D.h index bb040ebab..6885037df 100644 --- a/src/SceneGraph/Camera3D.h +++ b/src/SceneGraph/Camera3D.h @@ -108,14 +108,14 @@ class MAGNUM_SCENEGRAPH_EXPORT Camera3D: public AbstractCamera<3, T> { Camera3D* setPerspective(Math::Rad fov, T aspectRatio, T near, T far); /** @brief Near clipping plane */ - inline T near() const { return _near; } + T near() const { return _near; } /** @brief Far clipping plane */ - inline T far() const { return _far; } + T far() const { return _far; } /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline Camera3D* setAspectRatioPolicy(AspectRatioPolicy policy) { + Camera3D* setAspectRatioPolicy(AspectRatioPolicy policy) { AbstractCamera<3, T>::setAspectRatioPolicy(policy); return this; } diff --git a/src/SceneGraph/Drawable.h b/src/SceneGraph/Drawable.h index be31aad84..5afb8b80d 100644 --- a/src/SceneGraph/Drawable.h +++ b/src/SceneGraph/Drawable.h @@ -131,7 +131,7 @@ class Drawable: public AbstractGroupedFeature* object, DrawableGroup* drawables = nullptr): AbstractGroupedFeature, T>(object, drawables) {} + explicit Drawable(AbstractObject* object, DrawableGroup* drawables = nullptr): AbstractGroupedFeature, T>(object, drawables) {} /** * @brief Draw the object using given camera diff --git a/src/SceneGraph/DualComplexTransformation.h b/src/SceneGraph/DualComplexTransformation.h index 797719948..0a9e008cd 100644 --- a/src/SceneGraph/DualComplexTransformation.h +++ b/src/SceneGraph/DualComplexTransformation.h @@ -52,23 +52,23 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { typedef Math::DualComplex DataType; #ifndef DOXYGEN_GENERATING_OUTPUT - inline static Math::DualComplex fromMatrix(const Math::Matrix3& matrix) { + static Math::DualComplex fromMatrix(const Math::Matrix3& matrix) { return Math::DualComplex::fromMatrix(matrix); } - inline constexpr static Math::Matrix3 toMatrix(const Math::DualComplex& transformation) { + constexpr static Math::Matrix3 toMatrix(const Math::DualComplex& transformation) { return transformation.toMatrix(); } - inline static Math::DualComplex compose(const Math::DualComplex& parent, const Math::DualComplex& child) { + static Math::DualComplex compose(const Math::DualComplex& parent, const Math::DualComplex& child) { return parent*child; } - inline static Math::DualComplex inverted(const Math::DualComplex& transformation) { + static Math::DualComplex inverted(const Math::DualComplex& transformation) { return transformation.invertedNormalized(); } - inline Math::DualComplex transformation() const { + Math::DualComplex transformation() const { return _transformation; } #endif @@ -81,9 +81,9 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { * the object subsequently. * @see DualComplex::normalized() */ - DualComplexTransformation* normalizeRotation() { + Object>* normalizeRotation() { setTransformationInternal(_transformation.normalized()); - return this; + return static_cast>*>(this); } /** @@ -93,16 +93,18 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { * Expects that the dual complex number is normalized. * @see DualComplex::isNormalized() */ - DualComplexTransformation* setTransformation(const Math::DualComplex& transformation) { + Object>* setTransformation(const Math::DualComplex& transformation) { CORRADE_ASSERT(transformation.isNormalized(), - "SceneGraph::DualComplexTransformation::setTransformation(): the dual complex number is not normalized", this); + "SceneGraph::DualComplexTransformation::setTransformation(): the dual complex number is not normalized", + static_cast>*>(this)); setTransformationInternal(transformation); - return this; + return static_cast>*>(this); } - inline DualComplexTransformation* resetTransformation() override { + /** @copydoc AbstractTranslationRotationScaling2D::resetTransformation() */ + Object>* resetTransformation() { setTransformationInternal({}); - return this; + return static_cast>*>(this); } /** @@ -114,20 +116,21 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { * Expects that the dual complex number is normalized. * @see DualComplex::isNormalized() */ - inline DualComplexTransformation* transform(const Math::DualComplex& transformation, TransformationType type = TransformationType::Global) { + Object>* transform(const Math::DualComplex& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isNormalized(), - "SceneGraph::DualComplexTransformation::transform(): the dual complex number is not normalized", this); + "SceneGraph::DualComplexTransformation::transform(): the dual complex number is not normalized", + static_cast>*>(this)); transformInternal(transformation, type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling2D::translate() * Same as calling transform() with DualComplex::translation(). */ - inline DualComplexTransformation* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + Object>* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { transformInternal(Math::DualComplex::translation(vector), type); - return this; + return static_cast>*>(this); } /** @@ -139,9 +142,9 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { * Same as calling transform() with DualComplex::rotation(). * @see normalizeRotation() */ - inline DualComplexTransformation* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { transformInternal(Math::DualComplex::rotation(angle), type); - return this; + return static_cast>*>(this); } /** @@ -150,9 +153,9 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { * if you want to move it above all. * @return Pointer to self (for method chaining) */ - inline DualComplexTransformation* move(Object>* under) { - static_cast*>(this)->Corrade::Containers::template LinkedList>>::move(this, under); - return this; + Object>* move(Object>* under) { + static_cast*>(this)->Containers::template LinkedList>>::move(this, under); + return static_cast>*>(this); } protected: @@ -160,8 +163,18 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { explicit DualComplexTransformation(); private: + void doResetTransformation() override final { resetTransformation(); } + + void doTranslate(const Math::Vector2& vector, TransformationType type) override final { + translate(vector, type); + } + + void doRotate(Math::Rad angle, TransformationType type) override final { + doRotate(angle, type); + } + /* No assertions fired, for internal use */ - inline void setTransformationInternal(const Math::DualComplex& transformation) { + void setTransformationInternal(const Math::DualComplex& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -172,7 +185,7 @@ class DualComplexTransformation: public AbstractTranslationRotation2D { } /* No assertions fired, for internal use */ - inline void transformInternal(const Math::DualComplex& transformation, TransformationType type) { + void transformInternal(const Math::DualComplex& transformation, TransformationType type) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); } diff --git a/src/SceneGraph/DualQuaternionTransformation.h b/src/SceneGraph/DualQuaternionTransformation.h index 58bcd6c63..4db82fe78 100644 --- a/src/SceneGraph/DualQuaternionTransformation.h +++ b/src/SceneGraph/DualQuaternionTransformation.h @@ -52,25 +52,25 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { typedef Math::DualQuaternion DataType; #ifndef DOXYGEN_GENERATING_OUTPUT - inline static Math::DualQuaternion fromMatrix(const Math::Matrix4& matrix) { + static Math::DualQuaternion fromMatrix(const Math::Matrix4& matrix) { CORRADE_ASSERT(matrix.isRigidTransformation(), "SceneGraph::DualQuaternionTransformation::fromMatrix(): the matrix doesn't represent rigid transformation", {}); return Math::DualQuaternion::fromMatrix(matrix); } - inline constexpr static Math::Matrix4 toMatrix(const Math::DualQuaternion& transformation) { + constexpr static Math::Matrix4 toMatrix(const Math::DualQuaternion& transformation) { return transformation.toMatrix(); } - inline static Math::DualQuaternion compose(const Math::DualQuaternion& parent, const Math::DualQuaternion& child) { + static Math::DualQuaternion compose(const Math::DualQuaternion& parent, const Math::DualQuaternion& child) { return parent*child; } - inline static Math::DualQuaternion inverted(const Math::DualQuaternion& transformation) { + static Math::DualQuaternion inverted(const Math::DualQuaternion& transformation) { return transformation.invertedNormalized(); } - inline Math::DualQuaternion transformation() const { + Math::DualQuaternion transformation() const { return _transformation; } #endif @@ -83,9 +83,9 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { * the object subsequently. * @see DualQuaternion::normalized() */ - DualQuaternionTransformation* normalizeRotation() { + Object>* normalizeRotation() { setTransformation(_transformation.normalized()); - return this; + return static_cast>*>(this); } /** @@ -95,16 +95,18 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { * Expects that the dual quaternion is normalized. * @see DualQuaternion::isNormalized() */ - DualQuaternionTransformation* setTransformation(const Math::DualQuaternion& transformation) { + Object>* setTransformation(const Math::DualQuaternion& transformation) { CORRADE_ASSERT(transformation.isNormalized(), - "SceneGraph::DualQuaternionTransformation::setTransformation(): the dual quaternion is not normalized", this); + "SceneGraph::DualQuaternionTransformation::setTransformation(): the dual quaternion is not normalized", + static_cast>*>(this)); setTransformationInternal(transformation); - return this; + return static_cast>*>(this); } - inline DualQuaternionTransformation* resetTransformation() override { + /** @copydoc AbstractTranslationRotationScaling3D::resetTransformation() */ + Object>* resetTransformation() { setTransformation({}); - return this; + return static_cast>*>(this); } /** @@ -116,20 +118,21 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { * Expects that the dual quaternion is normalized. * @see DualQuaternion::isNormalized() */ - inline DualQuaternionTransformation* transform(const Math::DualQuaternion& transformation, TransformationType type = TransformationType::Global) { + Object>* transform(const Math::DualQuaternion& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isNormalized(), - "SceneGraph::DualQuaternionTransformation::transform(): the dual quaternion is not normalized", this); + "SceneGraph::DualQuaternionTransformation::transform(): the dual quaternion is not normalized", + static_cast>*>(this)); transformInternal(transformation, type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling3D::translate() * Same as calling transform() with DualQuaternion::translation(). */ - inline DualQuaternionTransformation* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + Object>* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { transformInternal(Math::DualQuaternion::translation(vector), type); - return this; + return static_cast>*>(this); } /** @@ -143,24 +146,21 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { * @see Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), * normalizeRotation() */ - inline DualQuaternionTransformation* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { + Object>* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { transformInternal(Math::DualQuaternion::rotation(angle, normalizedAxis), type); - return this; + return static_cast>*>(this); } /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline DualQuaternionTransformation* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) override { - AbstractTranslationRotation3D::rotateX(angle, type); - return this; + Object>* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { + return rotate(angle, Math::Vector3::xAxis(), type); } - inline DualQuaternionTransformation* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { - AbstractTranslationRotation3D::rotateY(angle, type); - return this; + Object>* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { + return rotate(angle, Math::Vector3::yAxis(), type); } - inline DualQuaternionTransformation* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { - AbstractTranslationRotation3D::rotateZ(angle, type); - return this; + Object>* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { + return rotate(angle, Math::Vector3::zAxis(), type); } #endif @@ -169,8 +169,18 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { explicit DualQuaternionTransformation(); private: + void doResetTransformation() override final { resetTransformation(); } + + void doTranslate(const Math::Vector3& vector, TransformationType type) override final { + translate(vector, type); + } + + void doRotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type) override final { + rotate(angle, normalizedAxis, type); + } + /* No assertions fired, for internal use */ - inline void setTransformationInternal(const Math::DualQuaternion& transformation) { + void setTransformationInternal(const Math::DualQuaternion& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -181,7 +191,7 @@ class DualQuaternionTransformation: public AbstractTranslationRotation3D { } /* No assertions fired, for internal use */ - inline void transformInternal(const Math::DualQuaternion& transformation, TransformationType type) { + void transformInternal(const Math::DualQuaternion& transformation, TransformationType type) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); } diff --git a/src/SceneGraph/FeatureGroup.h b/src/SceneGraph/FeatureGroup.h index fd0d18d96..328809097 100644 --- a/src/SceneGraph/FeatureGroup.h +++ b/src/SceneGraph/FeatureGroup.h @@ -28,14 +28,36 @@ * @brief Class Magnum::SceneGraph::FeatureGroup, alias Magnum::SceneGraph::FeatureGroup2D, Magnum::SceneGraph::FeatureGroup3D */ -#include #include #include -#include "SceneGraph.h" +#include "SceneGraph/SceneGraph.h" +#include "SceneGraph/magnumSceneGraphVisibility.h" namespace Magnum { namespace SceneGraph { +/** +@brief Base for group of features + +See FeatureGroup. +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class MAGNUM_SCENEGRAPH_EXPORT AbstractFeatureGroup { + template friend class FeatureGroup; + + explicit AbstractFeatureGroup(); + ~AbstractFeatureGroup(); + + void add(AbstractFeature* feature); + void remove(AbstractFeature* feature); + + std::vector*> features; +}; + /** @brief Group of features @@ -47,7 +69,7 @@ template #else template #endif -class FeatureGroup { +class FeatureGroup: public AbstractFeatureGroup { friend class AbstractGroupedFeature; public: @@ -58,25 +80,22 @@ class FeatureGroup { * * Removes all features belonging to this group, but not deletes them. */ - inline virtual ~FeatureGroup() { - for(auto it = features.begin(); it != features.end(); ++it) - (*it)->_group = nullptr; - } + virtual ~FeatureGroup(); /** @brief Whether the group is empty */ - inline bool isEmpty() const { return features.empty(); } + bool isEmpty() const { return this->features.empty(); } /** @brief Count of features in the group */ - inline std::size_t size() const { return features.size(); } + std::size_t size() const { return this->features.size(); } /** @brief Feature at given index */ - inline Feature* operator[](std::size_t index) { - return features[index]; + Feature* operator[](std::size_t index) { + return static_cast(this->features[index]); } /** @overload */ - inline const Feature* operator[](std::size_t index) const { - return features[index]; + const Feature* operator[](std::size_t index) const { + return static_cast(this->features[index]); } /** @@ -86,16 +105,7 @@ class FeatureGroup { * If the features is part of another group, it is removed from it. * @see remove(), AbstractGroupedFeature::AbstractGroupedFeature() */ - FeatureGroup* add(Feature* feature) { - /* Remove from previous group */ - if(feature->_group) - feature->_group->remove(feature); - - /* Crossreference the feature and group together */ - features.push_back(feature); - feature->_group = this; - return this; - } + FeatureGroup* add(Feature* feature); /** * @brief Remove feature from the group @@ -104,18 +114,7 @@ class FeatureGroup { * The feature must be part of the group. * @see add() */ - FeatureGroup* remove(Feature* feature) { - CORRADE_ASSERT(feature->_group == this, - "SceneGraph::AbstractFeatureGroup::remove(): feature is not part of this group", this); - - /* Remove the feature and reset group pointer */ - features.erase(std::find(features.begin(), features.end(), feature)); - feature->_group = nullptr; - return this; - } - - private: - std::vector features; + FeatureGroup* remove(Feature* feature); }; template inline FeatureGroup::FeatureGroup() = default; @@ -154,6 +153,31 @@ template using FeatureGroup3D = FeatureGroup<3, Feature, T>; #endif +template FeatureGroup::~FeatureGroup() { + for(auto it = this->features.begin(); it != this->features.end(); ++it) + static_cast(*it)->_group = nullptr; +} + +template FeatureGroup* FeatureGroup::add(Feature* feature) { + /* Remove from previous group */ + if(feature->_group) + feature->_group->remove(feature); + + /* Crossreference the feature and group together */ + AbstractFeatureGroup::add(feature); + feature->_group = this; + return this; +} + +template FeatureGroup* FeatureGroup::remove(Feature* feature) { + CORRADE_ASSERT(feature->_group == this, + "SceneGraph::AbstractFeatureGroup::remove(): feature is not part of this group", this); + + AbstractFeatureGroup::remove(feature); + feature->_group = nullptr; + return this; +} + }} #endif diff --git a/src/SceneGraph/MatrixTransformation3D.cpp b/src/SceneGraph/FeatureGroup.hpp similarity index 60% rename from src/SceneGraph/MatrixTransformation3D.cpp rename to src/SceneGraph/FeatureGroup.hpp index d2e7e82b3..0f2cd1f1f 100644 --- a/src/SceneGraph/MatrixTransformation3D.cpp +++ b/src/SceneGraph/FeatureGroup.hpp @@ -1,3 +1,5 @@ +#ifndef Magnum_SceneGraph_FeatureGroup_hpp +#define Magnum_SceneGraph_FeatureGroup_hpp /* This file is part of Magnum. @@ -22,14 +24,27 @@ DEALINGS IN THE SOFTWARE. */ -#include "MatrixTransformation3D.h" +/** @file + * @brief @ref compilation-speedup-hpp "Template implementation" for FeatureGroup.h + */ -#include "Object.hpp" +#include "FeatureGroup.h" + +#include namespace Magnum { namespace SceneGraph { -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Object>; -#endif +template AbstractFeatureGroup::AbstractFeatureGroup() = default; +template AbstractFeatureGroup::~AbstractFeatureGroup() = default; + +template void AbstractFeatureGroup::add(AbstractFeature* feature) { + features.push_back(feature); +} + +template void AbstractFeatureGroup::remove(AbstractFeature* feature) { + features.erase(std::find(features.begin(), features.end(), feature)); +} }} + +#endif diff --git a/src/SceneGraph/MatrixTransformation2D.h b/src/SceneGraph/MatrixTransformation2D.h index 92590079a..da52ad415 100644 --- a/src/SceneGraph/MatrixTransformation2D.h +++ b/src/SceneGraph/MatrixTransformation2D.h @@ -51,23 +51,23 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { typedef Math::Matrix3 DataType; #ifndef DOXYGEN_GENERATING_OUTPUT - inline constexpr static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { + constexpr static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { return matrix; } - inline constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { + constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { return transformation; } - inline static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { + static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { return parent*child; } - inline static Math::Matrix3 inverted(const Math::Matrix3& transformation) { + static Math::Matrix3 inverted(const Math::Matrix3& transformation) { return transformation.inverted(); } - inline Math::Matrix3 transformation() const { + Math::Matrix3 transformation() const { return _transformation; } #endif @@ -76,7 +76,7 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { * @brief Set transformation * @return Pointer to self (for method chaining) */ - MatrixTransformation2D* setTransformation(const Math::Matrix3& transformation) { + Object>* setTransformation(const Math::Matrix3& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -85,7 +85,7 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { static_cast>*>(this)->setDirty(); } - return this; + return static_cast>*>(this); } /** @@ -94,42 +94,43 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { * @param type Transformation type * @return Pointer to self (for method chaining) */ - inline MatrixTransformation2D* transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { + Object>* transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); - return this; + return static_cast>*>(this); } - inline MatrixTransformation2D* resetTransformation() override { + /** @copydoc AbstractTranslationRotationScaling2D::resetTransformation() */ + Object>* resetTransformation() { setTransformation({}); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling2D::translate() * Same as calling transform() with Matrix3::translation(). */ - inline MatrixTransformation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + Object>* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { transform(Math::Matrix3::translation(vector), type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling2D::rotate() * Same as calling transform() with Matrix3::rotation(). */ - inline MatrixTransformation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { transform(Math::Matrix3::rotation(angle), type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling2D::scale() * Same as calling transform() with Matrix3::scaling(). */ - inline MatrixTransformation2D* scale(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + Object>* scale(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { transform(Math::Matrix3::scaling(vector), type); - return this; + return static_cast>*>(this); } /** @@ -141,9 +142,9 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { * * Same as calling transform() with Matrix3::reflection(). */ - inline MatrixTransformation2D* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { + Object>* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { transform(Math::Matrix3::reflection(normal), type); - return this; + return static_cast>*>(this); } /** @@ -152,9 +153,9 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { * if you want to move it above all. * @return Pointer to self (for method chaining) */ - inline MatrixTransformation2D* move(Object>* under) { - static_cast*>(this)->Corrade::Containers::template LinkedList>>::move(this, under); - return this; + Object>* move(Object>* under) { + static_cast*>(this)->Containers::template LinkedList>>::move(this, under); + return static_cast>*>(this); } protected: @@ -162,6 +163,20 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { explicit MatrixTransformation2D(); private: + void doResetTransformation() override final { resetTransformation(); } + + void doTranslate(const Math::Vector2& vector, TransformationType type) override final { + translate(vector, type); + } + + void doRotate(Math::Rad angle, TransformationType type) override final { + doRotate(angle, type); + } + + void doScale(const Math::Vector2& vector, TransformationType type) override final { + scale(vector, type); + } + Math::Matrix3 _transformation; }; diff --git a/src/SceneGraph/MatrixTransformation3D.h b/src/SceneGraph/MatrixTransformation3D.h index a7742fc4a..c0fe352f9 100644 --- a/src/SceneGraph/MatrixTransformation3D.h +++ b/src/SceneGraph/MatrixTransformation3D.h @@ -51,23 +51,23 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { typedef Math::Matrix4 DataType; #ifndef DOXYGEN_GENERATING_OUTPUT - inline constexpr static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { + constexpr static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { return matrix; } - inline constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { + constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { return transformation; } - inline static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { + static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { return parent*child; } - inline static Math::Matrix4 inverted(const Math::Matrix4& transformation) { + static Math::Matrix4 inverted(const Math::Matrix4& transformation) { return transformation.inverted(); } - inline Math::Matrix4 transformation() const { + Math::Matrix4 transformation() const { return _transformation; } #endif @@ -76,7 +76,7 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * @brief Set transformation * @return Pointer to self (for method chaining) */ - MatrixTransformation3D* setTransformation(const Math::Matrix4& transformation) { + Object>* setTransformation(const Math::Matrix4& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -85,12 +85,13 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { static_cast>*>(this)->setDirty(); } - return this; + return static_cast>*>(this); } - inline MatrixTransformation3D* resetTransformation() override { + /** @copydoc AbstractTranslationRotationScaling3D::resetTransformation() */ + Object>* resetTransformation() { setTransformation({}); - return this; + return static_cast>*>(this); } /** @@ -99,28 +100,28 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * @param type Transformation type * @return Pointer to self (for method chaining) */ - inline MatrixTransformation3D* transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { + Object>* transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling3D::translate() * Same as calling transform() with Matrix4::translation(). */ - inline MatrixTransformation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + Object>* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::translation(vector), type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling3D::rotate() * Same as calling transform() with Matrix4::rotation(). */ - inline MatrixTransformation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { + Object>* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::rotation(angle, normalizedAxis), type); - return this; + return static_cast>*>(this); } /** @@ -131,9 +132,9 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * * Same as calling transform() with Matrix4::rotationX(). */ - inline MatrixTransformation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::rotationX(angle), type); - return this; + return static_cast>*>(this); } /** @@ -144,9 +145,9 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * * Same as calling transform() with Matrix4::rotationY(). */ - inline MatrixTransformation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::rotationY(angle), type); - return this; + return static_cast>*>(this); } /** @@ -157,18 +158,18 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * * Same as calling transform() with Matrix4::rotationZ(). */ - inline MatrixTransformation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::rotationZ(angle), type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling3D::scale() * Same as calling transform() with Matrix4::scaling(). */ - inline MatrixTransformation3D* scale(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + Object>* scale(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::scaling(vector), type); - return this; + return static_cast>*>(this); } /** @@ -180,9 +181,9 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * * Same as calling transform() with Matrix4::reflection(). */ - inline MatrixTransformation3D* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { + Object>* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { transform(Math::Matrix4::reflection(normal), type); - return this; + return static_cast>*>(this); } protected: @@ -190,6 +191,32 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { explicit MatrixTransformation3D(); private: + void doResetTransformation() override final { resetTransformation(); } + + void doTranslate(const Math::Vector3& vector, TransformationType type) override final { + translate(vector, type); + } + + void doRotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type) override final { + rotate(angle, normalizedAxis, type); + } + + void doRotateX(Math::Rad angle, TransformationType type) override final { + rotateX(angle, type); + } + + void doRotateY(Math::Rad angle, TransformationType type) override final { + rotateY(angle, type); + } + + void doRotateZ(Math::Rad angle, TransformationType type) override final { + rotateZ(angle, type); + } + + void doScale(const Math::Vector3& vector, TransformationType type) override final { + scale(vector, type); + } + Math::Matrix4 _transformation; }; diff --git a/src/SceneGraph/Object.cpp b/src/SceneGraph/Object.cpp deleted file mode 100644 index 0a4c679c8..000000000 --- a/src/SceneGraph/Object.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "Object.hpp" - -namespace Magnum { namespace SceneGraph { - -template class AbstractObject<2>; -template class AbstractObject<3>; -template class AbstractTransformation<2>; -template class AbstractTransformation<3>; - -}} diff --git a/src/SceneGraph/Object.h b/src/SceneGraph/Object.h index d53e36843..eccadac90 100644 --- a/src/SceneGraph/Object.h +++ b/src/SceneGraph/Object.h @@ -37,7 +37,6 @@ namespace Magnum { namespace SceneGraph { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { enum class ObjectFlag: UnsignedByte { Dirty = 1 << 0, @@ -45,11 +44,10 @@ namespace Implementation { Joint = 1 << 2 }; - typedef Corrade::Containers::EnumSet ObjectFlags; + typedef Containers::EnumSet ObjectFlags; CORRADE_ENUMSET_OPERATORS(ObjectFlags) } -#endif /** @brief %Object @@ -92,11 +90,11 @@ See @ref compilation-speedup-hpp for more information. */ template class MAGNUM_SCENEGRAPH_EXPORT Object: public AbstractObject, public Transformation #ifndef DOXYGEN_GENERATING_OUTPUT - , private Corrade::Containers::LinkedList>, private Corrade::Containers::LinkedListItem, Object> + , private Containers::LinkedList>, private Containers::LinkedListItem, Object> #endif { - friend class Corrade::Containers::LinkedList>; - friend class Corrade::Containers::LinkedListItem, Object>; + friend class Containers::LinkedList>; + friend class Containers::LinkedListItem, Object>; #ifndef DOXYGEN_GENERATING_OUTPUT Object(const Object&) = delete; @@ -106,20 +104,14 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs #endif public: - /** - * @brief Clean absolute transformations of given set of objects - * - * Only dirty objects in the list are cleaned. - * @see setClean(), AbstractObject::setClean() - */ - /* `objects` passed by copy intentionally (to avoid copy internally) */ - static void setClean(std::vector*> objects); + /** @brief Matrix type */ + typedef typename DimensionTraits::MatrixType MatrixType; /** * @brief Constructor * @param parent Parent object */ - inline explicit Object(Object* parent = nullptr): counter(0xFFFFu), flags(Flag::Dirty) { + explicit Object(Object* parent = nullptr): counter(0xFFFFu), flags(Flag::Dirty) { setParent(parent); } @@ -129,7 +121,7 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs * Removes itself from parent's children list and destroys all own * children. */ - inline virtual ~Object() {} + ~Object(); /** * @{ @name Scene hierarchy @@ -137,88 +129,101 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs * See @ref scenegraph-hierarchy for more information. */ - /** @brief Whether this object is scene */ - virtual inline bool isScene() const { return false; } - - /** - * @brief %Scene - * @return %Scene or `nullptr`, if the object is not part of any scene. - */ + /** @copydoc AbstractObject::scene() */ Scene* scene(); - - /** @overload */ - const Scene* scene() const; + const Scene* scene() const; /**< @overload */ /** @brief Parent object or `nullptr`, if this is root object */ - inline Object* parent() { - return Corrade::Containers::LinkedListItem, Object>::list(); + Object* parent() { + return Containers::LinkedListItem, Object>::list(); } /** @overload */ - inline const Object* parent() const { - return Corrade::Containers::LinkedListItem, Object>::list(); + const Object* parent() const { + return Containers::LinkedListItem, Object>::list(); } /** @brief Previous sibling object or `nullptr`, if this is first object */ - inline Object* previousSibling() { - return Corrade::Containers::LinkedListItem, Object>::previous(); + Object* previousSibling() { + return Containers::LinkedListItem, Object>::previous(); } /** @overload */ - inline const Object* previousSibling() const { - return Corrade::Containers::LinkedListItem, Object>::previous(); + const Object* previousSibling() const { + return Containers::LinkedListItem, Object>::previous(); } /** @brief Next sibling object or `nullptr`, if this is last object */ - inline Object* nextSibling() { - return Corrade::Containers::LinkedListItem, Object>::next(); + Object* nextSibling() { + return Containers::LinkedListItem, Object>::next(); } /** @overload */ - inline const Object* nextSibling() const { - return Corrade::Containers::LinkedListItem, Object>::next(); + const Object* nextSibling() const { + return Containers::LinkedListItem, Object>::next(); } /** @brief Whether this object has children */ - inline bool hasChildren() const { - return !Corrade::Containers::LinkedList>::isEmpty(); + bool hasChildren() const { + return !Containers::LinkedList>::isEmpty(); } /** @brief First child object or `nullptr`, if this object has no children */ - inline Object* firstChild() { - return Corrade::Containers::LinkedList>::first(); + Object* firstChild() { + return Containers::LinkedList>::first(); } /** @overload */ - inline const Object* firstChild() const { - return Corrade::Containers::LinkedList>::first(); + const Object* firstChild() const { + return Containers::LinkedList>::first(); } /** @brief Last child object or `nullptr`, if this object has no children */ - inline Object* lastChild() { - return Corrade::Containers::LinkedList>::last(); + Object* lastChild() { + return Containers::LinkedList>::last(); } /** @overload */ - inline const Object* lastChild() const { - return Corrade::Containers::LinkedList>::last(); + const Object* lastChild() const { + return Containers::LinkedList>::last(); } /** * @brief Set parent object * @return Pointer to self (for method chaining) + * + * @see setParentKeepTransformation() */ Object* setParent(Object* parent); + /** + * @brief Set parent object and keep absolute transformation + * @return Pointer to self (for method chaining) + * + * While setParent() preserves only relative transformation of the + * object, this funcition preserves absolute transformation. + */ + Object* setParentKeepTransformation(Object* parent); + /*@}*/ /** @{ @name Object transformation */ - inline typename DimensionTraits::MatrixType transformationMatrix() const override { + /** + * @brief Transformation matrix + * + * @see transformation() + */ + MatrixType transformationMatrix() const { return Transformation::toMatrix(Transformation::transformation()); } - inline typename DimensionTraits::MatrixType absoluteTransformationMatrix() const override { + /** + * @brief Transformation matrix relative to root object + * + * @see absoluteTransformation() + */ + MatrixType absoluteTransformationMatrix() const { return Transformation::toMatrix(absoluteTransformation()); } @@ -229,12 +234,21 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs */ typename Transformation::DataType absoluteTransformation() const; + /** + * @brief Transformation matrices of given set of objects relative to this object + * + * All transformations are premultiplied with @p initialTransformationMatrix, + * if specified. + * @see transformations() + */ + std::vector transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + /** * @brief Transformations of given group of objects relative to this object * * All transformations can be premultiplied with @p initialTransformation, * if specified. - * @see AbstractObject::transformationMatrices() + * @see transformationMatrices() */ /* `objects` passed by copy intentionally (to allow move from transformationMatrices() and avoid copy in the function itself) */ @@ -242,9 +256,36 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs /*@}*/ - inline bool isDirty() const override { return !!(flags & Flag::Dirty); } - void setDirty() override; - void setClean() override; + /** + * @{ @name Transformation caching + * + * See @ref scenegraph-caching for more information. + */ + + /** + * @brief Clean absolute transformations of given set of objects + * + * Only dirty objects in the list are cleaned. + * @see setClean() + */ + /* `objects` passed by copy intentionally (to avoid copy internally) */ + static void setClean(std::vector*> objects); + + /** @copydoc AbstractObject::isDirty() */ + bool isDirty() const { return !!(flags & Flag::Dirty); } + + /** @copydoc AbstractObject::setDirty() */ + void setDirty(); + + /** @copydoc AbstractObject::setClean() */ + void setClean(); + + /*@}*/ + + #ifndef DOXYGEN_GENERATING_OUTPUT + public: + virtual bool isScene() const { return false; } + #endif private: /* GCC 4.4 doesn't support lambda functions */ @@ -254,14 +295,24 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs }; #endif - Object* sceneObject() override; - const Object* sceneObject() const override; + Object* doScene() override final; + const Object* doScene() const override final; + + MatrixType MAGNUM_SCENEGRAPH_LOCAL doTransformationMatrix() const override final { + return transformationMatrix(); + } + MatrixType MAGNUM_SCENEGRAPH_LOCAL doAbsoluteTransformationMatrix() const override final { + return absoluteTransformationMatrix(); + } - std::vector::MatrixType> transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix = (typename DimensionTraits::MatrixType())) const override; + 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; - void setClean(const std::vector*>& objects) const override; + 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 MAGNUM_SCENEGRAPH_LOCAL setClean(const typename Transformation::DataType& absoluteTransformation); diff --git a/src/SceneGraph/Object.hpp b/src/SceneGraph/Object.hpp index 87c93e520..2db462f65 100644 --- a/src/SceneGraph/Object.hpp +++ b/src/SceneGraph/Object.hpp @@ -41,27 +41,29 @@ namespace Magnum { namespace SceneGraph { template AbstractObject::AbstractObject() {} template AbstractObject::~AbstractObject() {} -template inline AbstractTransformation::AbstractTransformation() {} -template inline AbstractTransformation::~AbstractTransformation() {} +template AbstractTransformation::AbstractTransformation() {} +template AbstractTransformation::~AbstractTransformation() {} + +template Object::~Object() = default; template Scene* Object::scene() { - return static_cast*>(sceneObject()); + Object* p(this); + while(p && !p->isScene()) p = p->parent(); + return static_cast*>(p); } template const Scene* Object::scene() const { - return static_cast*>(sceneObject()); + const Object* p(this); + while(p && !p->isScene()) p = p->parent(); + return static_cast*>(p); } -template Object* Object::sceneObject() { - Object* p(this); - while(p && !p->isScene()) p = p->parent(); - return p; +template Object* Object::doScene() { + return scene(); } -template const Object* Object::sceneObject() const { - const Object* p(this); - while(p && !p->isScene()) p = p->parent(); - return p; +template const Object* Object::doScene() const { + return scene(); } template Object* Object::setParent(Object* parent) { @@ -78,15 +80,26 @@ template Object* Object::s } /* Remove the object from old parent children list */ - if(this->parent()) this->parent()->Corrade::Containers::template LinkedList>::cut(this); + if(this->parent()) this->parent()->Containers::template LinkedList>::cut(this); /* Add the object to list of new parent */ - if(parent) parent->Corrade::Containers::LinkedList>::insert(this); + if(parent) parent->Containers::LinkedList>::insert(this); setDirty(); return this; } +template Object* Object::setParentKeepTransformation(Object* parent) { + CORRADE_ASSERT(scene() == parent->scene(), "SceneGraph::Object::setParentKeepTransformation(): both parents must be in the same scene", this); + + const auto transformation = Transformation::compose( + Transformation::inverted(parent->absoluteTransformation()), absoluteTransformation()); + setParent(parent); + this->setTransformation(transformation); + + return this; +} + template typename Transformation::DataType Object::absoluteTransformation() const { if(!parent()) return Transformation::transformation(); return Transformation::compose(parent()->absoluteTransformation(), Transformation::transformation()); @@ -148,14 +161,18 @@ template void Object::setClean() { } } -template std::vector::MatrixType> Object::transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix) const { +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) /** @todo Ensure this doesn't crash, somehow */ castObjects[i] = static_cast*>(objects[i]); - std::vector transformations = this->transformations(std::move(castObjects), Transformation::fromMatrix(initialTransformationMatrix)); - std::vector::MatrixType> transformationMatrices(transformations.size()); + return transformationMatrices(std::move(castObjects), initialTransformationMatrix); +} + +template auto Object::transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { + std::vector transformations = this->transformations(std::move(objects), Transformation::fromMatrix(initialTransformationMatrix)); + std::vector transformationMatrices(transformations.size()); for(std::size_t i = 0; i != objects.size(); ++i) transformationMatrices[i] = Transformation::toMatrix(transformations[i]); @@ -306,7 +323,7 @@ template typename Transformation::DataType Object void Object::setClean(const std::vector*>& objects) const { +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 */ @@ -357,10 +374,8 @@ template void Object::setClean(std::vector template void Object::setClean(const typename Transformation::DataType& absoluteTransformation) { /* "Lazy storage" for transformation matrix and inverted transformation matrix */ - typedef typename AbstractFeature::CachedTransformation CachedTransformation; - typename AbstractFeature::CachedTransformations cached; - typename DimensionTraits::MatrixType - matrix, invertedMatrix; + CachedTransformations cached; + MatrixType matrix, invertedMatrix; /* Clean all features */ for(AbstractFeature* i = this->firstFeature(); i; i = i->nextFeature()) { diff --git a/src/SceneGraph/RigidMatrixTransformation2D.cpp b/src/SceneGraph/RigidMatrixTransformation2D.cpp deleted file mode 100644 index a6e7506e9..000000000 --- a/src/SceneGraph/RigidMatrixTransformation2D.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "RigidMatrixTransformation2D.h" - -#include "Object.hpp" - -namespace Magnum { namespace SceneGraph { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Object>; -#endif - -}} diff --git a/src/SceneGraph/RigidMatrixTransformation2D.h b/src/SceneGraph/RigidMatrixTransformation2D.h index 2a9801404..6386df859 100644 --- a/src/SceneGraph/RigidMatrixTransformation2D.h +++ b/src/SceneGraph/RigidMatrixTransformation2D.h @@ -54,25 +54,25 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { typedef Math::Matrix3 DataType; #ifndef DOXYGEN_GENERATING_OUTPUT - inline static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { + static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { CORRADE_ASSERT(matrix.isRigidTransformation(), "SceneGraph::RigidMatrixTransformation2D::fromMatrix(): the matrix doesn't represent rigid transformation", {}); return matrix; } - inline constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { + constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { return transformation; } - inline static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { + static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { return parent*child; } - inline static Math::Matrix3 inverted(const Math::Matrix3& transformation) { + static Math::Matrix3 inverted(const Math::Matrix3& transformation) { return transformation.invertedRigid(); } - inline Math::Matrix3 transformation() const { + Math::Matrix3 transformation() const { return _transformation; } #endif @@ -84,11 +84,11 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * Normalizes the rotation part using Math::Algorithms::gramSchmidt() * to prevent rounding errors when rotating the object subsequently. */ - RigidMatrixTransformation2D* normalizeRotation() { + Object>* normalizeRotation() { setTransformationInternal(Math::Matrix3::from( Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), _transformation.translation())); - return this; + return static_cast>*>(this); } /** @@ -98,16 +98,18 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * Expects that the matrix represents rigid transformation. * @see Matrix3::isRigidTransformation() */ - RigidMatrixTransformation2D* setTransformation(const Math::Matrix3& transformation) { + Object>* setTransformation(const Math::Matrix3& transformation) { CORRADE_ASSERT(transformation.isRigidTransformation(), - "SceneGraph::RigidMatrixTransformation2D::setTransformation(): the matrix doesn't represent rigid transformation", this); + "SceneGraph::RigidMatrixTransformation2D::setTransformation(): the matrix doesn't represent rigid transformation", + static_cast>*>(this)); setTransformationInternal(transformation); - return this; + return static_cast>*>(this); } - inline RigidMatrixTransformation2D* resetTransformation() override { + /** @copydoc AbstractTranslationRotationScaling2D::resetTransformation() */ + Object>* resetTransformation() { setTransformationInternal({}); - return this; + return static_cast>*>(this); } /** @@ -119,20 +121,21 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * Expects that the matrix represents rigid transformation. * @see Matrix3::isRigidTransformation() */ - inline RigidMatrixTransformation2D* transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { + Object>* transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isRigidTransformation(), - "SceneGraph::RigidMatrixTransformation2D::transform(): the matrix doesn't represent rigid transformation", this); + "SceneGraph::RigidMatrixTransformation2D::transform(): the matrix doesn't represent rigid transformation", + static_cast>*>(this)); transformInternal(transformation, type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling2D::translate() * Same as calling transform() with Matrix3::translation(). */ - inline RigidMatrixTransformation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + Object>* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix3::translation(vector), type); - return this; + return static_cast>*>(this); } /** @@ -144,9 +147,9 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * Same as calling transform() with Matrix3::rotation(). * @see normalizeRotation() */ - inline RigidMatrixTransformation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix3::rotation(angle), type); - return this; + return static_cast>*>(this); } /** @@ -158,9 +161,9 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * * Same as calling transform() with Matrix3::reflection(). */ - inline RigidMatrixTransformation2D* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { + Object>* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix3::reflection(normal), type); - return this; + return static_cast>*>(this); } /** @@ -169,9 +172,9 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * if you want to move it above all. * @return Pointer to self (for method chaining) */ - inline RigidMatrixTransformation2D* move(Object>* under) { - static_cast*>(this)->Corrade::Containers::template LinkedList>>::move(this, under); - return this; + Object>* move(Object>* under) { + static_cast*>(this)->Containers::template LinkedList>>::move(this, under); + return static_cast>*>(this); } protected: @@ -179,8 +182,18 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { explicit RigidMatrixTransformation2D(); private: + void doResetTransformation() override final { resetTransformation(); } + + void doTranslate(const Math::Vector2& vector, TransformationType type) override final { + translate(vector, type); + } + + void doRotate(Math::Rad angle, TransformationType type) override final { + doRotate(angle, type); + } + /* No assertions fired, for internal use */ - inline void setTransformationInternal(const Math::Matrix3& transformation) { + void setTransformationInternal(const Math::Matrix3& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -191,7 +204,7 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { } /* No assertions fired, for internal use */ - inline void transformInternal(const Math::Matrix3& transformation, TransformationType type) { + void transformInternal(const Math::Matrix3& transformation, TransformationType type) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); } diff --git a/src/SceneGraph/RigidMatrixTransformation3D.cpp b/src/SceneGraph/RigidMatrixTransformation3D.cpp deleted file mode 100644 index 008f5fb5d..000000000 --- a/src/SceneGraph/RigidMatrixTransformation3D.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include "RigidMatrixTransformation3D.h" - -#include "Object.hpp" - -namespace Magnum { namespace SceneGraph { - -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Object>; -#endif - -}} diff --git a/src/SceneGraph/RigidMatrixTransformation3D.h b/src/SceneGraph/RigidMatrixTransformation3D.h index 563127511..b0c60572e 100644 --- a/src/SceneGraph/RigidMatrixTransformation3D.h +++ b/src/SceneGraph/RigidMatrixTransformation3D.h @@ -54,25 +54,25 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { typedef Math::Matrix4 DataType; #ifndef DOXYGEN_GENERATING_OUTPUT - inline static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { + static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { CORRADE_ASSERT(matrix.isRigidTransformation(), "SceneGraph::RigidMatrixTransformation3D::fromMatrix(): the matrix doesn't represent rigid transformation", {}); return matrix; } - inline constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { + constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { return transformation; } - inline static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { + static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { return parent*child; } - inline static Math::Matrix4 inverted(const Math::Matrix4& transformation) { + static Math::Matrix4 inverted(const Math::Matrix4& transformation) { return transformation.invertedRigid(); } - inline Math::Matrix4 transformation() const { + Math::Matrix4 transformation() const { return _transformation; } #endif @@ -84,11 +84,11 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * Normalizes the rotation part using Math::Algorithms::gramSchmidt() * to prevent rounding errors when rotating the object subsequently. */ - RigidMatrixTransformation3D* normalizeRotation() { + Object>* normalizeRotation() { setTransformation(Math::Matrix4::from( Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), _transformation.translation())); - return this; + return static_cast>*>(this); } /** @@ -98,16 +98,18 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * Expects that the matrix represents rigid transformation. * @see Matrix4::isRigidTransformation() */ - RigidMatrixTransformation3D* setTransformation(const Math::Matrix4& transformation) { + Object>* setTransformation(const Math::Matrix4& transformation) { CORRADE_ASSERT(transformation.isRigidTransformation(), - "SceneGraph::RigidMatrixTransformation3D::setTransformation(): the matrix doesn't represent rigid transformation", this); + "SceneGraph::RigidMatrixTransformation3D::setTransformation(): the matrix doesn't represent rigid transformation", + static_cast>*>(this)); setTransformationInternal(transformation); - return this; + return static_cast>*>(this); } - inline RigidMatrixTransformation3D* resetTransformation() override { + /** @copydoc AbstractTranslationRotationScaling3D::resetTransformation() */ + Object>* resetTransformation() { setTransformation({}); - return this; + return static_cast>*>(this); } /** @@ -119,20 +121,21 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * Expects that the matrix represents rigid transformation. * @see Matrix4::isRigidTransformation() */ - inline RigidMatrixTransformation3D* transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { + Object>* transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isRigidTransformation(), - "SceneGraph::RigidMatrixTransformation3D::transform(): the matrix doesn't represent rigid transformation", this); + "SceneGraph::RigidMatrixTransformation3D::transform(): the matrix doesn't represent rigid transformation", + static_cast>*>(this)); transformInternal(transformation, type); - return this; + return static_cast>*>(this); } /** * @copydoc AbstractTranslationRotationScaling3D::translate() * Same as calling transform() with Matrix4::translation(). */ - inline RigidMatrixTransformation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + Object>* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix4::translation(vector), type); - return this; + return static_cast>*>(this); } /** @@ -146,9 +149,9 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * @see rotateX(), rotateY(), rotateZ(), Vector3::xAxis(), * Vector3::yAxis(), Vector3::zAxis(), normalizeRotation() */ - inline RigidMatrixTransformation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { + Object>* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix4::rotation(angle, normalizedAxis), type); - return this; + return static_cast>*>(this); } /** @@ -160,9 +163,9 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * Same as calling transform() with Matrix4::rotationX(). * @see normalizeRotation() */ - inline RigidMatrixTransformation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix4::rotationX(angle), type); - return this; + return static_cast>*>(this); } /** @@ -174,9 +177,9 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * Same as calling transform() with Matrix4::rotationY(). * @see normalizeRotation() */ - inline RigidMatrixTransformation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix4::rotationY(angle), type); - return this; + return static_cast>*>(this); } /** @@ -188,9 +191,9 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * Same as calling transform() with Matrix4::rotationZ(). * @see normalizeRotation() */ - inline RigidMatrixTransformation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { + Object>* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix4::rotationZ(angle), type); - return this; + return static_cast>*>(this); } /** @@ -202,9 +205,9 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * * Same as calling transform() with Matrix4::reflection(). */ - inline RigidMatrixTransformation3D* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { + Object>* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { transformInternal(Math::Matrix4::reflection(normal), type); - return this; + return static_cast>*>(this); } protected: @@ -212,8 +215,30 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { explicit RigidMatrixTransformation3D(); private: + void doResetTransformation() override final { resetTransformation(); } + + void doTranslate(const Math::Vector3& vector, TransformationType type) override final { + translate(vector, type); + } + + void doRotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type) override final { + rotate(angle, normalizedAxis, type); + } + + void doRotateX(Math::Rad angle, TransformationType type) override final { + rotateX(angle, type); + } + + void doRotateY(Math::Rad angle, TransformationType type) override final { + rotateY(angle, type); + } + + void doRotateZ(Math::Rad angle, TransformationType type) override final { + rotateZ(angle, type); + } + /* No assertions fired, for internal use */ - inline void setTransformationInternal(const Math::Matrix4& transformation) { + void setTransformationInternal(const Math::Matrix4& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -224,7 +249,7 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { } /* No assertions fired, for internal use */ - inline void transformInternal(const Math::Matrix4& transformation, TransformationType type) { + void transformInternal(const Math::Matrix4& transformation, TransformationType type) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); } diff --git a/src/SceneGraph/Scene.h b/src/SceneGraph/Scene.h index d27822e27..1f5689d64 100644 --- a/src/SceneGraph/Scene.h +++ b/src/SceneGraph/Scene.h @@ -42,7 +42,8 @@ template class Scene: public Object { public: explicit Scene(); - inline bool isScene() const { return true; } + private: + bool isScene() const override final { return true; } }; template inline Scene::Scene() = default; diff --git a/src/SceneGraph/SceneGraph.h b/src/SceneGraph/SceneGraph.h index 6c7b42a04..2298a9924 100644 --- a/src/SceneGraph/SceneGraph.h +++ b/src/SceneGraph/SceneGraph.h @@ -46,12 +46,20 @@ template using AbstractCamera2D = AbstractCamera<2, T>; template using AbstractCamera3D = AbstractCamera<3, T>; #endif +/* Enum CachedTransformation and CachedTransformations used only directly */ + template class AbstractFeature; #ifndef CORRADE_GCC46_COMPATIBILITY template using AbstractFeature2D = AbstractFeature<2, T>; template using AbstractFeature3D = AbstractFeature<3, T>; #endif +template class AbstractFeatureGroup; +#ifndef CORRADE_GCC46_COMPATIBILITY +template using AbstractFeatureGroup2D = AbstractFeatureGroup<2, T>; +template using AbstractFeatureGroup3D = AbstractFeatureGroup<3, T>; +#endif + template class AbstractGroupedFeature; #ifndef CORRADE_GCC46_COMPATIBILITY template using AbstractGroupedFeature2D = AbstractGroupedFeature<2, Derived, T>; diff --git a/src/SceneGraph/Test/AnimableTest.cpp b/src/SceneGraph/Test/AnimableTest.cpp index fb0ebb643..3f6e02adf 100644 --- a/src/SceneGraph/Test/AnimableTest.cpp +++ b/src/SceneGraph/Test/AnimableTest.cpp @@ -31,7 +31,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { -class AnimableTest: public Corrade::TestSuite::Tester { +class AnimableTest: public TestSuite::Tester { public: AnimableTest(); diff --git a/src/SceneGraph/Test/CameraTest.cpp b/src/SceneGraph/Test/CameraTest.cpp index 8c0c91e9e..c31da6842 100644 --- a/src/SceneGraph/Test/CameraTest.cpp +++ b/src/SceneGraph/Test/CameraTest.cpp @@ -34,7 +34,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { -class CameraTest: public Corrade::TestSuite::Tester { +class CameraTest: public TestSuite::Tester { public: CameraTest(); @@ -160,7 +160,7 @@ void CameraTest::projectionSizeViewport() { void CameraTest::draw() { class Drawable: public SceneGraph::Drawable<3> { public: - inline Drawable(AbstractObject<3>* object, DrawableGroup<3>* group, Matrix4& result): SceneGraph::Drawable<3>(object, group), result(result) {} + Drawable(AbstractObject<3>* object, DrawableGroup<3>* group, Matrix4& result): SceneGraph::Drawable<3>(object, group), result(result) {} protected: void draw(const Matrix4& transformationMatrix, AbstractCamera<3>*) { diff --git a/src/SceneGraph/Test/DualComplexTransformationTest.cpp b/src/SceneGraph/Test/DualComplexTransformationTest.cpp index d9c71d1c9..853051f58 100644 --- a/src/SceneGraph/Test/DualComplexTransformationTest.cpp +++ b/src/SceneGraph/Test/DualComplexTransformationTest.cpp @@ -33,7 +33,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef Object> Object2D; typedef Scene> Scene2D; -class DualComplexTransformationTest: public Corrade::TestSuite::Tester { +class DualComplexTransformationTest: public TestSuite::Tester { public: explicit DualComplexTransformationTest(); diff --git a/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp b/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp index 6de60f080..bfacea1a6 100644 --- a/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp +++ b/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp @@ -33,7 +33,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef Object> Object3D; typedef Scene> Scene3D; -class DualQuaternionTransformationTest: public Corrade::TestSuite::Tester { +class DualQuaternionTransformationTest: public TestSuite::Tester { public: explicit DualQuaternionTransformationTest(); diff --git a/src/SceneGraph/Test/MatrixTransformation2DTest.cpp b/src/SceneGraph/Test/MatrixTransformation2DTest.cpp index 91576e87f..f000e4742 100644 --- a/src/SceneGraph/Test/MatrixTransformation2DTest.cpp +++ b/src/SceneGraph/Test/MatrixTransformation2DTest.cpp @@ -32,7 +32,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef Object> Object2D; typedef Scene> Scene2D; -class MatrixTransformation2DTest: public Corrade::TestSuite::Tester { +class MatrixTransformation2DTest: public TestSuite::Tester { public: explicit MatrixTransformation2DTest(); diff --git a/src/SceneGraph/Test/MatrixTransformation3DTest.cpp b/src/SceneGraph/Test/MatrixTransformation3DTest.cpp index 651d8101d..955775572 100644 --- a/src/SceneGraph/Test/MatrixTransformation3DTest.cpp +++ b/src/SceneGraph/Test/MatrixTransformation3DTest.cpp @@ -32,7 +32,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef Object> Object3D; typedef Scene> Scene3D; -class MatrixTransformation3DTest: public Corrade::TestSuite::Tester { +class MatrixTransformation3DTest: public TestSuite::Tester { public: explicit MatrixTransformation3DTest(); diff --git a/src/SceneGraph/Test/ObjectTest.cpp b/src/SceneGraph/Test/ObjectTest.cpp index a54acdd43..2ec5848ae 100644 --- a/src/SceneGraph/Test/ObjectTest.cpp +++ b/src/SceneGraph/Test/ObjectTest.cpp @@ -30,12 +30,13 @@ namespace Magnum { namespace SceneGraph { namespace Test { -class ObjectTest: public Corrade::TestSuite::Tester { +class ObjectTest: public TestSuite::Tester { public: ObjectTest(); void parenting(); void scene(); + void setParentKeepTransformation(); void absoluteTransformation(); void transformations(); void transformationsRelative(); @@ -51,7 +52,7 @@ typedef SceneGraph::Scene> Scene3D; class CachingObject: public Object3D, AbstractFeature<3> { public: - inline CachingObject(Object3D* parent = nullptr): Object3D(parent), AbstractFeature<3>(this) { + CachingObject(Object3D* parent = nullptr): Object3D(parent), AbstractFeature<3>(this) { setCachedTransformations(CachedTransformation::Absolute); } @@ -66,6 +67,7 @@ class CachingObject: public Object3D, AbstractFeature<3> { ObjectTest::ObjectTest() { addTests({&ObjectTest::parenting, &ObjectTest::scene, + &ObjectTest::setParentKeepTransformation, &ObjectTest::absoluteTransformation, &ObjectTest::transformations, &ObjectTest::transformationsRelative, @@ -120,6 +122,31 @@ void ObjectTest::scene() { CORRADE_VERIFY(childOfOrphan->scene() == nullptr); } +void ObjectTest::setParentKeepTransformation() { + Object3D root; + root.rotateZ(Deg(35.0f)); + + Object3D* childOne = new Object3D(&root); + Object3D* childTwo = new Object3D(&root); + + childOne->translate(Vector3::xAxis(2.0f)); + childTwo->rotateY(Deg(90.0f)); + + /* Old parent and new parent must share the same scene */ + std::ostringstream o; + Error::setOutput(&o); + Scene3D scene; + childOne->setParentKeepTransformation(&scene); + CORRADE_COMPARE(o.str(), "SceneGraph::Object::setParentKeepTransformation(): both parents must be in the same scene\n"); + CORRADE_COMPARE(childOne->parent(), &root); + + /* Reparent to another and keep absolute transformation */ + auto transformation = childOne->absoluteTransformation(); + childOne->setParentKeepTransformation(childTwo); + CORRADE_VERIFY(childOne->parent() == childTwo); + CORRADE_COMPARE(childOne->absoluteTransformation(), transformation); +} + void ObjectTest::absoluteTransformation() { Scene3D s; diff --git a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp index dccefa1b3..31d3625c9 100644 --- a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp +++ b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp @@ -33,7 +33,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef Object> Object2D; typedef Scene> Scene2D; -class RigidMatrixTransformation2DTest: public Corrade::TestSuite::Tester { +class RigidMatrixTransformation2DTest: public TestSuite::Tester { public: explicit RigidMatrixTransformation2DTest(); diff --git a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp index 2d14c3bab..7c9495a2d 100644 --- a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp +++ b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp @@ -33,7 +33,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { typedef Object> Object3D; typedef Scene> Scene3D; -class RigidMatrixTransformation3DTest: public Corrade::TestSuite::Tester { +class RigidMatrixTransformation3DTest: public TestSuite::Tester { public: explicit RigidMatrixTransformation3DTest(); diff --git a/src/SceneGraph/Test/SceneTest.cpp b/src/SceneGraph/Test/SceneTest.cpp index d3731a11d..a2a725504 100644 --- a/src/SceneGraph/Test/SceneTest.cpp +++ b/src/SceneGraph/Test/SceneTest.cpp @@ -29,7 +29,7 @@ namespace Magnum { namespace SceneGraph { namespace Test { -class SceneTest: public Corrade::TestSuite::Tester { +class SceneTest: public TestSuite::Tester { public: SceneTest(); diff --git a/src/SceneGraph/Camera.cpp b/src/SceneGraph/instantiation.cpp similarity index 50% rename from src/SceneGraph/Camera.cpp rename to src/SceneGraph/instantiation.cpp index 982d76a01..b3db08d88 100644 --- a/src/SceneGraph/Camera.cpp +++ b/src/SceneGraph/instantiation.cpp @@ -22,16 +22,42 @@ DEALINGS IN THE SOFTWARE. */ -#include "Camera2D.hpp" -#include "Camera3D.hpp" +#include "SceneGraph/AbstractFeature.hpp" +#include "SceneGraph/Camera2D.hpp" +#include "SceneGraph/Camera3D.hpp" +#include "SceneGraph/DualComplexTransformation.h" +#include "SceneGraph/DualQuaternionTransformation.h" +#include "SceneGraph/FeatureGroup.hpp" +#include "SceneGraph/MatrixTransformation2D.h" +#include "SceneGraph/MatrixTransformation3D.h" +#include "SceneGraph/Object.hpp" +#include "SceneGraph/RigidMatrixTransformation2D.h" +#include "SceneGraph/RigidMatrixTransformation3D.h" namespace Magnum { namespace SceneGraph { #ifndef DOXYGEN_GENERATING_OUTPUT +template class AbstractObject<2, Float>; +template class AbstractObject<3, Float>; +template class AbstractTransformation<2, Float>; +template class AbstractTransformation<3, Float>; + +template class MAGNUM_SCENEGRAPH_EXPORT AbstractFeature<2, Float>; +template class MAGNUM_SCENEGRAPH_EXPORT AbstractFeature<3, Float>; +template class AbstractFeatureGroup<2, Float>; +template class AbstractFeatureGroup<3, Float>; + template class AbstractCamera<2, Float>; template class AbstractCamera<3, Float>; template class Camera2D; template class Camera3D; + +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +template class MAGNUM_SCENEGRAPH_EXPORT Object>; #endif }} diff --git a/src/Shader.cpp b/src/Shader.cpp index 64e3679e5..bdcb748fd 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -27,8 +27,6 @@ #include #include -#define COMPILER_MESSAGE_MAX_LENGTH 1024 - /* libgles-omap3-dev_4.03.00.02-r15.6 on BeagleBoard/Ångström linux 2011.3 doesn't have GLchar */ #ifdef MAGNUM_TARGET_GLES typedef char GLchar; @@ -36,23 +34,42 @@ typedef char GLchar; namespace Magnum { -Shader::Shader(Version version, Type type): _type(type), _state(State::Initialized), shader(0) { - shader = glCreateShader(static_cast(_type)); +namespace { + +std::string shaderName(const Shader::Type type) { + switch(type) { + case Shader::Type::Vertex: return "vertex"; + #ifndef MAGNUM_TARGET_GLES + case Shader::Type::Geometry: return "geometry"; + case Shader::Type::TessellationControl: return "tessellation control"; + case Shader::Type::TessellationEvaluation: return "tessellation evaluation"; + case Shader::Type::Compute: return "compute"; + #endif + case Shader::Type::Fragment: return "fragment"; + } + + CORRADE_ASSERT_UNREACHABLE(); +} + +} + +Shader::Shader(const Version version, const Type type): _type(type), _id(0) { + _id = glCreateShader(static_cast(_type)); switch(version) { #ifndef MAGNUM_TARGET_GLES - case Version::GL210: addSource("#version 120\n"); return; - case Version::GL300: addSource("#version 130\n"); return; - case Version::GL310: addSource("#version 140\n"); return; - case Version::GL320: addSource("#version 150\n"); return; - case Version::GL330: addSource("#version 330\n"); return; - case Version::GL400: addSource("#version 400\n"); return; - case Version::GL410: addSource("#version 410\n"); return; - case Version::GL420: addSource("#version 420\n"); return; - case Version::GL430: addSource("#version 430\n"); return; + case Version::GL210: sources.push_back("#version 120\n"); return; + case Version::GL300: sources.push_back("#version 130\n"); return; + case Version::GL310: sources.push_back("#version 140\n"); return; + case Version::GL320: sources.push_back("#version 150\n"); return; + case Version::GL330: sources.push_back("#version 330\n"); return; + case Version::GL400: sources.push_back("#version 400\n"); return; + case Version::GL410: sources.push_back("#version 410\n"); return; + case Version::GL420: sources.push_back("#version 420\n"); return; + case Version::GL430: sources.push_back("#version 430\n"); return; #else - case Version::GLES200: addSource("#version 100\n"); return; - case Version::GLES300: addSource("#version 300\n"); return; + case Version::GLES200: sources.push_back("#version 100\n"); return; + case Version::GLES300: sources.push_back("#version 300\n"); return; #endif case Version::None: @@ -62,54 +79,59 @@ Shader::Shader(Version version, Type type): _type(type), _state(State::Initializ CORRADE_ASSERT_UNREACHABLE(); } -Shader::Shader(Shader&& other): _type(other._type), _state(other._state), sources(other.sources), shader(other.shader) { - other.shader = 0; +Shader::Shader(Shader&& other): _type(other._type), _id(other._id), sources(std::move(other.sources)) { + other._id = 0; +} + +Shader::~Shader() { + if(_id) glDeleteShader(_id); } Shader& Shader::operator=(Shader&& other) { - glDeleteShader(shader); + glDeleteShader(_id); _type = other._type; - _state = other._state; - sources = other.sources; - shader = other.shader; + sources = std::move(other.sources); + _id = other._id; - other.shader = 0; + other._id = 0; return *this; } -bool Shader::addFile(const std::string& filename) { +Shader& Shader::addSource(std::string source) { + if(!source.empty()) { + /* Fix line numbers, so line 41 of third added file is marked as 3(41). + Source 0 is the #version string added in constructor. */ + sources.push_back("#line 1 " + std::to_string((sources.size()+1)/2) + '\n'); + sources.push_back(std::move(source)); + } + + return *this; +} + +Shader& Shader::addFile(const std::string& filename) { /* Open file */ std::ifstream file(filename.c_str()); - if(!file.good()) { - file.close(); - - Error() << "Shader file " << '\'' + filename + '\'' << " cannot be opened."; - return false; - } + CORRADE_ASSERT(file.good(), "Shader file " << '\'' + filename + '\'' << " cannot be opened.", *this); /* Get size of shader and initialize buffer */ file.seekg(0, std::ios::end); - std::size_t size = file.tellg(); - char* source = new char[size+1]; - source[size] = '\0'; + std::string source(file.tellg(), '\0'); /* Read data, close */ file.seekg(0, std::ios::beg); - file.read(source, size); + file.read(&source[0], source.size()); file.close(); - /* Add to sources and free the buffer */ - addSource(source); - delete[] source; + /* Move to sources */ + addSource(std::move(source)); - return true; + return *this; } -GLuint Shader::compile() { - /* Already compiled, return */ - if(_state != State::Initialized) return shader; +bool Shader::compile() { + CORRADE_ASSERT(sources.size() > 1, "Shader::compile(): no files added", false); /* Array of sources */ const GLchar** _sources = new const GLchar*[sources.size()]; @@ -117,54 +139,45 @@ GLuint Shader::compile() { _sources[i] = static_cast(sources[i].c_str()); /* Create shader and set its source */ - glShaderSource(shader, sources.size(), _sources, nullptr); + glShaderSource(_id, sources.size(), _sources, nullptr); /* Compile shader */ - glCompileShader(shader); + glCompileShader(_id); delete _sources; /* Check compilation status */ - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - - /* Display errors or warnings */ - char message[COMPILER_MESSAGE_MAX_LENGTH]; - glGetShaderInfoLog(shader, COMPILER_MESSAGE_MAX_LENGTH, nullptr, message); - - if(status == GL_FALSE || message[0] != 0) { - Error err; - err << "Shader:"; - - switch(_type) { - case Type::Vertex: err << "vertex"; break; - #ifndef MAGNUM_TARGET_GLES - case Type::Geometry: err << "geometry"; break; - case Type::TessellationControl: err << "tessellation control"; break; - case Type::TessellationEvaluation: err << "tessellation evaluation"; break; - case Type::Compute: err << "compute"; break; - #endif - case Type::Fragment: err << "fragment"; break; - } - - /* Show error log and delete shader */ - if(status == GL_FALSE) { - err << "shader failed to compile with the following message:\n" - << message; - - /* Or just warnings, if there are any */ - } else if(message[0] != 0) { - err << "shader was successfully compiled with the following message:\n" - << message; - } + GLint success, logLength; + glGetShaderiv(_id, GL_COMPILE_STATUS, &success); + glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength); + + /* Error or warning message. The string is returned null-terminated, scrap + the \0 at the end afterwards */ + std::string message(logLength, '\0'); + if(!message.empty()) { + glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]); + message.resize(logLength-1); } - if(status == GL_FALSE) { - _state = State::Failed; - return 0; - } else { - _state = State::Compiled; - return shader; + /* Show error log */ + if(!success) { + Error out; + out.setFlag(Debug::NewLineAtTheEnd, false); + out.setFlag(Debug::SpaceAfterEachValue, false); + out << "Shader: " << shaderName(_type) + << " shader failed to compile with the following message:\n" + << message; + + /* Or just message, if any */ + } else if(!message.empty()) { + Error out; + out.setFlag(Debug::NewLineAtTheEnd, false); + out.setFlag(Debug::SpaceAfterEachValue, false); + out << "Shader: " << shaderName(_type) + << " shader was successfully compiled with the following message:\n" + << message; } + + return success; } } diff --git a/src/Shader.h b/src/Shader.h index 944ca2ff2..838671e70 100644 --- a/src/Shader.h +++ b/src/Shader.h @@ -41,8 +41,7 @@ namespace Magnum { /** @brief %Shader -Allows loading and compiling the shader from file or directly from source -string. See AbstractShaderProgram for more information. +See AbstractShaderProgram for more information. */ class MAGNUM_EXPORT Shader { Shader(const Shader&) = delete; @@ -86,55 +85,6 @@ class MAGNUM_EXPORT Shader { Fragment = GL_FRAGMENT_SHADER /**< Fragment shader */ }; - /** @brief %Shader state */ - enum class State { - Initialized, /**< %Shader is loaded */ - Compiled, /**< %Shader is compiled */ - Failed /**< Compilation failed */ - }; - - /** - * @brief Load shader from source - * @param version Target version - * @param type %Shader type - * @param source %Shader source - * @return Shader instance - * - * Loads the shader from one source. Shorthand for - * @code - * Shader s(version, type); - * s.addData(data); - * @endcode - * Note that it is also possible to create shader from more than one - * source. - */ - inline static Shader fromData(Version version, Type type, const std::string& source) { - Shader s(version, type); - s.addSource(source); - return s; - } - - /** - * @brief Load shader from file - * @param version Target version - * @param type %Shader type - * @param filename Source filename - * @return Shader instance - * - * Loads the shader from from one file. Shorthand for - * @code - * Shader s(version, type); - * s.addFile(filename); - * @endcode - * Note that it is also possible to create shader from more than one - * source. - */ - inline static Shader fromFile(Version version, Type type, const char* filename) { - Shader s(version, type); - s.addFile(filename); - return s; - } - /** * @brief Constructor * @param version Target version @@ -142,7 +92,7 @@ class MAGNUM_EXPORT Shader { * * Creates empty OpenGL shader and adds @c \#version directive at the * beginning. Sources can be added with addSource() or addFile(). - * @see fromData(), fromFile(), @fn_gl{CreateShader} + * @see @fn_gl{CreateShader} */ explicit Shader(Version version, Type type); @@ -152,7 +102,7 @@ class MAGNUM_EXPORT Shader { * Deletes associated OpenGL shader. * @see @fn_gl{DeleteShader} */ - inline ~Shader() { if(shader) glDeleteShader(shader); } + ~Shader(); /** @brief Move constructor */ Shader(Shader&& other); @@ -160,63 +110,47 @@ class MAGNUM_EXPORT Shader { /** @brief Move assignment operator */ Shader& operator=(Shader&& other); - /** - * @brief %Shader type - * - * Set in constructor. - */ - inline Type type() const { return _type; } - - /** - * @brief Compilation state - * - * Changes after calling compile(). - */ - inline State state() const { return _state; } + /** @brief OpenGL shader ID */ + GLuint id() const { return _id; } /** * @brief Add shader source * @param source String with shader source + * @return Reference to self (for method chaining) * - * If the shader is not compiled already, adds given source to source - * list. Note that it is possible to compile shader from more than - * one source. + * Adds given source to source list, preceeded with @c \#line directive + * marking first line of the source as `n(1)` where n is number of + * added source. If passed string is empty, the function does nothing. * @see addFile() */ - inline void addSource(const std::string& source) { - if(_state == State::Initialized) sources.push_back(source); - } + Shader& addSource(std::string source); /** * @brief Add source file * @param filename Name of source file to read from - * @return False if reading the file fails, true otherwise. + * @return Reference to self (for method chaining) * - * @see addSource() + * The file must exist and must be readable. Calls addSource() with + * the contents. */ - bool addFile(const std::string& filename); + Shader& addFile(const std::string& filename); /** * @brief Compile shader - * @return Compiled shader or 0 if compilation failed. * - * If the shader has any sources present and hasn't been compiled - * before, it tries to compile it. If compilation fails or no sources - * are present, returns 0. If the shader was compiled already, returns - * already existing shader. - * @see state(), @fn_gl{ShaderSource}, @fn_gl{CompileShader}, - * @fn_gl{GetShader} with @def_gl{COMPILE_STATUS}, + * Returns `false` if compilation failed, `true` otherwise. Compiler + * message (if any) is printed to error output. + * @see @fn_gl{ShaderSource}, @fn_gl{CompileShader}, @fn_gl{GetShader} + * with @def_gl{COMPILE_STATUS} and @def_gl{INFO_LOG_LENGTH}, * @fn_gl{GetShaderInfoLog} */ - GLuint compile(); + bool compile(); private: Type _type; - State _state; + GLuint _id; std::vector sources; - - GLuint shader; }; } diff --git a/src/Shaders/AbstractVectorShader.h b/src/Shaders/AbstractVector.h similarity index 74% rename from src/Shaders/AbstractVectorShader.h rename to src/Shaders/AbstractVector.h index 75d2f6e23..1337e7ae0 100644 --- a/src/Shaders/AbstractVectorShader.h +++ b/src/Shaders/AbstractVector.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Shaders_AbstractVectorShader_h -#define Magnum_Shaders_AbstractVectorShader_h +#ifndef Magnum_Shaders_AbstractVector_h +#define Magnum_Shaders_AbstractVector_h /* This file is part of Magnum. @@ -25,7 +25,7 @@ */ /** @file - * @brief Class Magnum::Shaders::AbstractVectorShader, typedef Magnum::Shaders::AbstractVectorShader2D, Magnum::Shaders::AbstractVectorShader3D + * @brief Class Magnum::Shaders::AbstractVector, typedef Magnum::Shaders::AbstractVector2D, Magnum::Shaders::AbstractVector3D */ #include "AbstractShaderProgram.h" @@ -37,9 +37,9 @@ namespace Magnum { namespace Shaders { /** @brief Base for vector shaders -@see AbstractVectorShader2D, AbstractVectorShader3D +@see AbstractVector2D, AbstractVector3D */ -template class AbstractVectorShader: public AbstractShaderProgram { +template class AbstractVector: public AbstractShaderProgram { public: /** @brief Vertex position */ typedef Attribute<0, typename DimensionTraits::VectorType> Position; @@ -51,16 +51,16 @@ template class AbstractVectorShader: public AbstractShad VectorTextureLayer = 16 /**< Layer for vector texture */ }; - virtual ~AbstractVectorShader() = 0; + virtual ~AbstractVector() = 0; }; -template inline AbstractVectorShader::~AbstractVectorShader() {} +template inline AbstractVector::~AbstractVector() {} /** @brief Base for two-dimensional text shaders */ -typedef AbstractVectorShader<2> AbstractVectorShader2D; +typedef AbstractVector<2> AbstractVector2D; /** @brief Base for three-dimensional text shader */ -typedef AbstractVectorShader<3> AbstractVectorShader3D; +typedef AbstractVector<3> AbstractVector3D; }} diff --git a/src/Shaders/AbstractVectorShader2D.vert b/src/Shaders/AbstractVector2D.vert similarity index 100% rename from src/Shaders/AbstractVectorShader2D.vert rename to src/Shaders/AbstractVector2D.vert diff --git a/src/Shaders/AbstractVectorShader3D.vert b/src/Shaders/AbstractVector3D.vert similarity index 100% rename from src/Shaders/AbstractVectorShader3D.vert rename to src/Shaders/AbstractVector3D.vert diff --git a/src/Shaders/CMakeLists.txt b/src/Shaders/CMakeLists.txt index d5eff9498..79de6f97c 100644 --- a/src/Shaders/CMakeLists.txt +++ b/src/Shaders/CMakeLists.txt @@ -22,30 +22,26 @@ # DEALINGS IN THE SOFTWARE. # -corrade_add_resource(MagnumShaders_RCS MagnumShaders - AbstractVectorShader2D.vert AbstractVectorShader3D.vert - FlatShader2D.vert FlatShader3D.vert FlatShader.frag - PhongShader.vert PhongShader.frag - VectorShader.frag DistanceFieldVectorShader.frag - VertexColorShader2D.vert VertexColorShader3D.vert VertexColorShader.frag - compatibility.glsl) +corrade_add_resource(MagnumShaders_RCS resources.conf) set(MagnumShaders_SRCS - DistanceFieldVectorShader.cpp - FlatShader.cpp - PhongShader.cpp - VectorShader.cpp - VertexColorShader.cpp + DistanceFieldVector.cpp + Flat.cpp + MeshVisualizer.cpp + Phong.cpp + Vector.cpp + VertexColor.cpp ${MagnumShaders_RCS}) set(MagnumShaders_HEADERS - DistanceFieldVectorShader.h - AbstractVectorShader.h - FlatShader.h - PhongShader.h + DistanceFieldVector.h + AbstractVector.h + Flat.h + MeshVisualizer.h + Phong.h Shaders.h - VectorShader.h - VertexColorShader.h + Vector.h + VertexColor.h magnumShadersVisibility.h) diff --git a/src/Shaders/DistanceFieldVectorShader.cpp b/src/Shaders/DistanceFieldVector.cpp similarity index 72% rename from src/Shaders/DistanceFieldVectorShader.cpp rename to src/Shaders/DistanceFieldVector.cpp index fcd4b74eb..3f2f34a27 100644 --- a/src/Shaders/DistanceFieldVectorShader.cpp +++ b/src/Shaders/DistanceFieldVector.cpp @@ -22,7 +22,7 @@ DEALINGS IN THE SOFTWARE. */ -#include "DistanceFieldVectorShader.h" +#include "DistanceFieldVector.h" #include @@ -34,12 +34,12 @@ namespace Magnum { namespace Shaders { namespace { template constexpr const char* vertexShaderName(); - template<> constexpr const char* vertexShaderName<2>() { return "AbstractVectorShader2D.vert"; } - template<> constexpr const char* vertexShaderName<3>() { return "AbstractVectorShader3D.vert"; } + template<> constexpr const char* vertexShaderName<2>() { return "AbstractVector2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "AbstractVector3D.vert"; } } -template DistanceFieldVectorShader::DistanceFieldVectorShader(): transformationProjectionMatrixUniform(0), colorUniform(1), outlineColorUniform(2), outlineRangeUniform(3), smoothnessUniform(4) { - Corrade::Utility::Resource rs("MagnumShaders"); +template DistanceFieldVector::DistanceFieldVector(): transformationProjectionMatrixUniform(0), colorUniform(1), outlineColorUniform(2), outlineRangeUniform(3), smoothnessUniform(4) { + Utility::Resource rs("MagnumShaders"); /* Weird bug in GCC 4.5 - cannot use initializer list here, although the same thing works in PhongShader flawlessly */ @@ -50,15 +50,17 @@ template DistanceFieldVectorShader::Distance #endif Version v = Context::current()->supportedVersion(vs); - Shader vertexShader(v, Shader::Type::Vertex); - vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get(vertexShaderName())); - AbstractShaderProgram::attachShader(vertexShader); + Shader frag(v, Shader::Type::Vertex); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + AbstractShaderProgram::attachShader(frag); - Shader fragmentShader(v, Shader::Type::Fragment); - fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get("DistanceFieldVectorShader.frag")); - AbstractShaderProgram::attachShader(fragmentShader); + Shader vert(v, Shader::Type::Fragment); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("DistanceFieldVector.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + AbstractShaderProgram::attachShader(vert); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -67,11 +69,11 @@ template DistanceFieldVectorShader::Distance if(!Context::current()->isVersionSupported(Version::GLES300)) #endif { - AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::Position::Location, "position"); - AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::TextureCoordinates::Location, "textureCoordinates"); + AbstractShaderProgram::bindAttributeLocation(AbstractVector::Position::Location, "position"); + AbstractShaderProgram::bindAttributeLocation(AbstractVector::TextureCoordinates::Location, "textureCoordinates"); } - AbstractShaderProgram::link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(AbstractShaderProgram::link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) @@ -87,11 +89,11 @@ template DistanceFieldVectorShader::Distance #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), - AbstractVectorShader::VectorTextureLayer); + AbstractVector::VectorTextureLayer); #endif } -template class DistanceFieldVectorShader<2>; -template class DistanceFieldVectorShader<3>; +template class DistanceFieldVector<2>; +template class DistanceFieldVector<3>; }} diff --git a/src/Shaders/DistanceFieldVectorShader.frag b/src/Shaders/DistanceFieldVector.frag similarity index 100% rename from src/Shaders/DistanceFieldVectorShader.frag rename to src/Shaders/DistanceFieldVector.frag diff --git a/src/Shaders/DistanceFieldVectorShader.h b/src/Shaders/DistanceFieldVector.h similarity index 78% rename from src/Shaders/DistanceFieldVectorShader.h rename to src/Shaders/DistanceFieldVector.h index e938ee695..06bd4c8dc 100644 --- a/src/Shaders/DistanceFieldVectorShader.h +++ b/src/Shaders/DistanceFieldVector.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Shaders_DistanceFieldVectorShader_h -#define Magnum_Shaders_DistanceFieldVectorShader_h +#ifndef Magnum_Shaders_DistanceFieldVector_h +#define Magnum_Shaders_DistanceFieldVector_h /* This file is part of Magnum. @@ -25,12 +25,12 @@ */ /** @file - * @brief Class Magnum::Shaders::DistanceFieldVectorShader, typedef Magnum::Shaders::DistanceFieldVectorShader2D, Magnum::Shaders::DistanceFieldVectorShader3D + * @brief Class Magnum::Shaders::DistanceFieldVector, typedef Magnum::Shaders::DistanceFieldVector2D, Magnum::Shaders::DistanceFieldVector3D */ #include "Math/Matrix3.h" #include "Math/Matrix4.h" -#include "AbstractVectorShader.h" +#include "AbstractVector.h" #include "magnumShadersVisibility.h" @@ -42,14 +42,14 @@ namespace Magnum { namespace Shaders { Renders vector art in form of signed distance field. See 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 DistanceFieldVectorShader2D, DistanceFieldVectorShader3D +@see DistanceFieldVector2D, DistanceFieldVector3D */ -template class MAGNUM_SHADERS_EXPORT DistanceFieldVectorShader: public AbstractVectorShader { +template class MAGNUM_SHADERS_EXPORT DistanceFieldVector: public AbstractVector { public: - DistanceFieldVectorShader(); + DistanceFieldVector(); /** @brief Set transformation and projection matrix */ - inline DistanceFieldVectorShader* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { + DistanceFieldVector* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { AbstractShaderProgram::setUniform(transformationProjectionMatrixUniform, matrix); return this; } @@ -60,7 +60,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * * @see setOutlineColor() */ - inline DistanceFieldVectorShader* setColor(const Color4<>& color) { + DistanceFieldVector* setColor(const Color4<>& color) { AbstractShaderProgram::setUniform(colorUniform, color); return this; } @@ -71,7 +71,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * * @see setOutlineRange(), setColor() */ - inline DistanceFieldVectorShader* setOutlineColor(const Color4<>& color) { + DistanceFieldVector* setOutlineColor(const Color4<>& color) { AbstractShaderProgram::setUniform(outlineColorUniform, color); return this; } @@ -90,7 +90,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * * @see setOutlineColor() */ - inline DistanceFieldVectorShader* setOutlineRange(Float start, Float end) { + DistanceFieldVector* setOutlineRange(Float start, Float end) { AbstractShaderProgram::setUniform(outlineRangeUniform, Vector2(start, end)); return this; } @@ -103,7 +103,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * values will make them look more crisp (but possibly aliased). Initial * value is `0.04f`. */ - inline DistanceFieldVectorShader* setSmoothness(Float value) { + DistanceFieldVector* setSmoothness(Float value) { AbstractShaderProgram::setUniform(smoothnessUniform, value); return this; } @@ -117,10 +117,10 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector }; /** @brief Two-dimensional distance field vector shader */ -typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D; +typedef DistanceFieldVector<2> DistanceFieldVector2D; /** @brief Three-dimensional distance field vector shader */ -typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D; +typedef DistanceFieldVector<3> DistanceFieldVector3D; }} diff --git a/src/Shaders/FlatShader.cpp b/src/Shaders/Flat.cpp similarity index 77% rename from src/Shaders/FlatShader.cpp rename to src/Shaders/Flat.cpp index 0dcda6ffa..35a06b84a 100644 --- a/src/Shaders/FlatShader.cpp +++ b/src/Shaders/Flat.cpp @@ -22,7 +22,7 @@ DEALINGS IN THE SOFTWARE. */ -#include "FlatShader.h" +#include "Flat.h" #include @@ -33,12 +33,12 @@ namespace Magnum { namespace Shaders { namespace { template constexpr const char* vertexShaderName(); - template<> constexpr const char* vertexShaderName<2>() { return "FlatShader2D.vert"; } - template<> constexpr const char* vertexShaderName<3>() { return "FlatShader3D.vert"; } + template<> constexpr const char* vertexShaderName<2>() { return "Flat2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "Flat3D.vert"; } } -template FlatShader::FlatShader(): transformationProjectionMatrixUniform(0), colorUniform(1) { - Corrade::Utility::Resource rs("MagnumShaders"); +template Flat::Flat(): transformationProjectionMatrixUniform(0), colorUniform(1) { + Utility::Resource rs("MagnumShaders"); /* Weird bug in GCC 4.5 - cannot use initializer list here, although the same thing works in PhongShader flawlessly */ @@ -49,15 +49,17 @@ template FlatShader::FlatShader(): transform #endif Version v = Context::current()->supportedVersion(vs); - Shader vertexShader(v, Shader::Type::Vertex); - vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get(vertexShaderName())); - attachShader(vertexShader); + Shader frag(v, Shader::Type::Vertex); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); - Shader fragmentShader(v, Shader::Type::Fragment); - fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get("FlatShader.frag")); - attachShader(fragmentShader); + Shader vert(v, Shader::Type::Fragment); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Flat.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -69,7 +71,7 @@ template FlatShader::FlatShader(): transform bindAttributeLocation(Position::Location, "position"); } - link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) @@ -80,7 +82,7 @@ template FlatShader::FlatShader(): transform } } -template class FlatShader<2>; -template class FlatShader<3>; +template class Flat<2>; +template class Flat<3>; }} diff --git a/src/Shaders/FlatShader.frag b/src/Shaders/Flat.frag similarity index 100% rename from src/Shaders/FlatShader.frag rename to src/Shaders/Flat.frag diff --git a/src/Shaders/FlatShader.h b/src/Shaders/Flat.h similarity index 82% rename from src/Shaders/FlatShader.h rename to src/Shaders/Flat.h index 71f5e7d49..be01877fd 100644 --- a/src/Shaders/FlatShader.h +++ b/src/Shaders/Flat.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Shaders_FlatShader_h -#define Magnum_Shaders_FlatShader_h +#ifndef Magnum_Shaders_Flat_h +#define Magnum_Shaders_Flat_h /* This file is part of Magnum. @@ -25,7 +25,7 @@ */ /** @file - * @brief Class Magnum::Shaders::FlatShader + * @brief Class Magnum::Shaders::Flat */ #include "Math/Matrix3.h" @@ -42,20 +42,20 @@ namespace Magnum { namespace Shaders { @brief Flat shader Draws whole mesh with one color. -@see FlatShader2D, FlatShader3D +@see Flat2D, Flat3D */ -template class MAGNUM_SHADERS_EXPORT FlatShader: public AbstractShaderProgram { +template class MAGNUM_SHADERS_EXPORT Flat: public AbstractShaderProgram { public: /** @brief Vertex position */ typedef Attribute<0, typename DimensionTraits::VectorType> Position; - explicit FlatShader(); + explicit Flat(); /** * @brief Set transformation and projection matrix * @return Pointer to self (for method chaining) */ - FlatShader* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { + Flat* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { setUniform(transformationProjectionMatrixUniform, matrix); return this; } @@ -64,7 +64,7 @@ template class MAGNUM_SHADERS_EXPORT FlatShader: public * @brief Set color * @return Pointer to self (for method chaining) */ - FlatShader* setColor(const Color4<>& color) { + Flat* setColor(const Color4<>& color) { setUniform(colorUniform, color); return this; } @@ -75,10 +75,10 @@ template class MAGNUM_SHADERS_EXPORT FlatShader: public }; /** @brief 2D flat shader */ -typedef FlatShader<2> FlatShader2D; +typedef Flat<2> Flat2D; /** @brief 3D flat shader */ -typedef FlatShader<3> FlatShader3D; +typedef Flat<3> Flat3D; }} diff --git a/src/Shaders/FlatShader2D.vert b/src/Shaders/Flat2D.vert similarity index 100% rename from src/Shaders/FlatShader2D.vert rename to src/Shaders/Flat2D.vert diff --git a/src/Shaders/FlatShader3D.vert b/src/Shaders/Flat3D.vert similarity index 100% rename from src/Shaders/FlatShader3D.vert rename to src/Shaders/Flat3D.vert diff --git a/src/Shaders/MeshVisualizer.cpp b/src/Shaders/MeshVisualizer.cpp new file mode 100644 index 000000000..f2e3f5a84 --- /dev/null +++ b/src/Shaders/MeshVisualizer.cpp @@ -0,0 +1,113 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "MeshVisualizer.h" + +#include + +#include "Context.h" +#include "Extensions.h" +#include "Shader.h" + +namespace Magnum { namespace Shaders { + +MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationProjectionMatrixUniform(0), viewportSizeUniform(1), colorUniform(2), wireframeColorUniform(3), wireframeWidthUniform(4), smoothnessUniform(5) { + #ifndef MAGNUM_TARGET_GLES + if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); + #endif + + Utility::Resource rs("MagnumShaders"); + + #ifndef MAGNUM_TARGET_GLES + const Version v = Context::current()->supportedVersion({Version::GL320, Version::GL310, Version::GL210}); + #else + const Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); + #endif + + Shader vert(v, Shader::Type::Vertex); + vert.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + .addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "") + .addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("MeshVisualizer.vert")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + vert.compile(); + attachShader(vert); + + #ifndef MAGNUM_TARGET_GLES + if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { + Shader geom(v, Shader::Type::Geometry); + geom.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("MeshVisualizer.geom")); + CORRADE_INTERNAL_ASSERT_OUTPUT(geom.compile()); + geom.compile(); + attachShader(geom); + } + #endif + + Shader frag(v, Shader::Type::Fragment); + frag.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + .addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "") + .addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("MeshVisualizer.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + frag.compile(); + attachShader(frag); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) + #endif + { + bindAttributeLocation(Position::Location, "position"); + #ifndef MAGNUM_TARGET_GLES + if(v < Version::GL310) + #else + if(v < Version::GLES300) + #endif + bindAttributeLocation(VertexIndex::Location, "vertexIndex"); + } + + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + link(); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + #endif + { + transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); + colorUniform = uniformLocation("color"); + if(flags & Flag::Wireframe) { + wireframeColorUniform = uniformLocation("wireframeColor"); + wireframeWidthUniform = uniformLocation("wireframeWidth"); + smoothnessUniform = uniformLocation("smoothness"); + if(!(flags & Flag::NoGeometryShader)) + viewportSizeUniform = uniformLocation("viewportSize"); + } + } +} + +}} diff --git a/src/Shaders/MeshVisualizer.frag b/src/Shaders/MeshVisualizer.frag new file mode 100644 index 000000000..ad3c9103a --- /dev/null +++ b/src/Shaders/MeshVisualizer.frag @@ -0,0 +1,82 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef NEW_GLSL +#define in varying +#define fragmentColor gl_FragColor +#endif + +#ifndef EXPLICIT_UNIFORM_LOCATION +#define layout(arg) +#endif + +#ifndef GL_ES +layout(location = 2) uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); +#else +uniform lowp vec4 color; +#endif + +#ifdef WIREFRAME_RENDERING +#ifndef GL_ES +layout(location = 3) uniform vec4 wireframeColor = vec4(0.0, 0.0, 0.0, 1.0); +layout(location = 4) uniform float wireframeWidth = 1.0; +layout(location = 5) uniform float smoothness = 2.0; +#else +uniform lowp vec4 wireframeColor; +uniform lowp float wireframeWidth; +uniform lowp float smoothness; +#endif + +#ifndef NO_GEOMETRY_SHADER +noperspective in vec3 dist; +#else +in vec3 barycentric; +#endif +#endif + +out vec4 fragmentColor; + +#if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER) && defined(GL_ES) +#extension GL_OES_standard_derivatives : enable +#endif + +void main() { + #ifdef WIREFRAME_RENDERING + #ifndef NO_GEOMETRY_SHADER + /* Distance to nearest side */ + const float nearest = min(min(dist.x, dist.y), dist.z); + + /* Smooth step between face color and wireframe color based on distance */ + fragmentColor = mix(wireframeColor, color, smoothstep(wireframeWidth-smoothness, wireframeWidth+smoothness, nearest)); + #else + const vec3 d = fwidth(barycentric); + const vec3 factor = smoothstep(vec3(0.0), d*1.5, barycentric); + const float nearest = min(min(factor.x, factor.y), factor.z); + fragmentColor = mix(wireframeColor, color, nearest); + #endif + + #else + fragmentColor = color; + #endif +} diff --git a/src/Shaders/MeshVisualizer.geom b/src/Shaders/MeshVisualizer.geom new file mode 100644 index 000000000..3043f38cf --- /dev/null +++ b/src/Shaders/MeshVisualizer.geom @@ -0,0 +1,59 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +layout(location = 1) uniform vec2 viewportSize; + +layout(triangles) in; + +layout(triangle_strip, max_vertices = 3) out; + +/* Interpolate in screen space */ +noperspective out vec3 dist; + +void main() { + /* Screen position of each vertex */ + vec2 p[3]; + for(int i = 0; i != 3; ++i) + p[i] = viewportSize*gl_in[i].gl_Position.xy/gl_in[i].gl_Position.w; + + /* Vector of each triangle side */ + const vec2 v[3] = { + p[2]-p[1], + p[2]-p[0], + p[1]-p[0] + }; + + /* Compute area using perp-dot product */ + const float area = abs(dot(vec2(-v[1].y, v[1].x), v[2])); + + /* Add distance to opposite side to each vertex */ + for(int i = 0; i != 3; ++i) { + dist = vec3(0.0, 0.0, 0.0); + dist[i] = area/length(v[i]); + gl_Position = gl_in[i].gl_Position; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/src/Shaders/MeshVisualizer.h b/src/Shaders/MeshVisualizer.h new file mode 100644 index 000000000..1eb9896a2 --- /dev/null +++ b/src/Shaders/MeshVisualizer.h @@ -0,0 +1,199 @@ +#ifndef Magnum_Shaders_MeshVisualizer_h +#define Magnum_Shaders_MeshVisualizer_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Shaders::MeshVisualizer + */ + +#include "Math/Matrix4.h" +#include "AbstractShaderProgram.h" +#include "Color.h" + +#include "Shaders/magnumShadersVisibility.h" + +namespace Magnum { namespace Shaders { + +/** +@brief %Mesh visualization shader + +Uses geometry shader to visualize wireframe. You need to provide @ref Position +attribute in your triangle mesh and call at least @ref setTransformationProjectionMatrix() +to be able to render. + +@section ShadersMeshVisualizer-wireframe Wireframe visualization + +Wireframe visualization is done by enabling @ref Flag "Flag::Wireframe". It is +done either using geometry shaders or with help of additional vertex information. + +If you have geometry shaders available, you don't need to do anything else. + +@requires_gl32 %Extension @extension{ARB,geometry_shader4} for wireframe + rendering using geometry shaders. + +If you don't have geometry shaders, you need to set @ref Flag "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. + +@requires_es_extension %Extension @extension{OES,standard_derivatives} for + wireframe rendering. + +@todo Understand and add support wireframe width/smoothness without GS +*/ +class MAGNUM_SHADERS_EXPORT MeshVisualizer: public AbstractShaderProgram { + public: + typedef Attribute<0, Vector3> Position; /**< @brief Vertex position */ + + /** + * @brief Vertex index + * + * Used only in OpenGL < 3.1 and OpenGL ES 2.0 if @ref Flag "Flag::Wireframe" + * is enabled. This attribute specifies index of given vertex in + * triangle, i.e. `0` for first, `1` for second, `2` for third. In + * OpenGL 3.1, OpenGL ES 3.0 and newer this value is provided by the + * shader itself, so the attribute is not needed. + */ + typedef Attribute<1, Float> VertexIndex; + + /** + * @brief %Flag + * + * @see Flags, MeshVisualizer() + */ + enum class Flag: UnsignedByte { + /** + * Visualize wireframe. On OpenGL ES this also enables + * @ref Flag "Flag::NoGeometryShader". + */ + #ifndef MAGNUM_TARGET_GLES + Wireframe = 1 << 0, + #else + Wireframe = (1 << 0) | (1 << 1), + #endif + + /** + * 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 "Flag::Wireframe". + */ + NoGeometryShader = 1 << 1 + }; + + /** @brief %Flags */ + typedef Containers::EnumSet Flags; + + /** + * @brief Constructor + * @param flags %Flags + */ + explicit MeshVisualizer(Flags flags); + + /** + * @brief Set transformation and projection matrix + * @return Pointer to self (for method chaining) + */ + MeshVisualizer* setTransformationProjectionMatrix(const Matrix4& matrix) { + setUniform(transformationProjectionMatrixUniform, matrix); + return this; + } + + /** + * @brief Set viewport size + * @return Pointer to self (for method chaining) + * + * Has effect only if @ref Flag "Flag::Wireframe" is enabled. + */ + MeshVisualizer* setViewportSize(const Vector2& size) { + setUniform(viewportSizeUniform, size); + return this; + } + + /** + * @brief Set base object color + * @return Pointer to self (for method chaining) + * + * Initial value is fully opaque white. + */ + MeshVisualizer* setColor(const Color4<>& color) { + setUniform(colorUniform, color); + return this; + } + + /** + * @brief Set wireframe color + * @return Pointer to self (for method chaining) + * + * Initial value is fully opaque black. Has effect only if + * @ref Flag "Flag::Wireframe" is enabled. + */ + MeshVisualizer* setWireframeColor(const Color4<>& color) { + if(flags & Flag::Wireframe) setUniform(wireframeColorUniform, color); + return this; + } + + /** + * @brief Set wireframe width + * @return Pointer to self (for method chaining) + * + * Initial value is `1.0f`. Has effect only if + * @ref Flag "Flag::Wireframe" is enabled. + */ + MeshVisualizer* setWireframeWidth(Float width) { + if(flags & Flag::Wireframe) setUniform(wireframeWidthUniform, width); + return this; + } + + /** + * @brief Set line smoothness + * @return Pointer to self (for method chaining) + * + * Initial value is `2.0f`. Has effect only if + * @ref Flag "Flag::Wireframe" is enabled. + */ + MeshVisualizer* setSmoothness(Float smoothness); + + private: + Flags flags; + Int transformationProjectionMatrixUniform, + viewportSizeUniform, + colorUniform, + wireframeColorUniform, + wireframeWidthUniform, + smoothnessUniform; +}; + +CORRADE_ENUMSET_OPERATORS(MeshVisualizer::Flags) + +inline MeshVisualizer* MeshVisualizer::setSmoothness(Float smoothness) { + if(flags & Flag::Wireframe) + setUniform(smoothnessUniform, smoothness); + return this; +} + +}} + +#endif diff --git a/src/Math/Angle.cpp b/src/Shaders/MeshVisualizer.vert similarity index 57% rename from src/Math/Angle.cpp rename to src/Shaders/MeshVisualizer.vert index bae169c3f..90f579d77 100644 --- a/src/Math/Angle.cpp +++ b/src/Shaders/MeshVisualizer.vert @@ -22,17 +22,41 @@ DEALINGS IN THE SOFTWARE. */ -#include "Angle.h" +#ifndef NEW_GLSL +#define in attribute +#define out varying +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat4 transformationProjectionMatrix; +#else +uniform highp mat4 transformationProjectionMatrix; +#endif -namespace Magnum { namespace Math { +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 0) highp in vec4 position; +#else +in highp vec4 position; +#endif -#ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Unit&); +#if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER) +#if (!defined(GL_ES) && __VERSION__ < 140) || (defined(GL_ES) && __VERSION__ < 300) +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 1) highp in float vertexIndex; +#else +in lowp float vertexIndex; #endif +#define gl_VertexID int(vertexIndex) #endif -}} +out vec3 barycentric; +#endif + +void main() { + gl_Position = transformationProjectionMatrix*position; + + #if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER) + barycentric = vec3(0.0); + barycentric[gl_VertexID % 3] = 1.0; + #endif +} diff --git a/src/Shaders/PhongShader.cpp b/src/Shaders/Phong.cpp similarity index 79% rename from src/Shaders/PhongShader.cpp rename to src/Shaders/Phong.cpp index a953c3d8a..c96fc0e01 100644 --- a/src/Shaders/PhongShader.cpp +++ b/src/Shaders/Phong.cpp @@ -22,7 +22,7 @@ DEALINGS IN THE SOFTWARE. */ -#include "PhongShader.h" +#include "Phong.h" #include @@ -31,8 +31,8 @@ namespace Magnum { namespace Shaders { -PhongShader::PhongShader(): transformationMatrixUniform(0), projectionMatrixUniform(1), normalMatrixUniform(2), lightUniform(3), diffuseColorUniform(4), ambientColorUniform(5), specularColorUniform(6), lightColorUniform(7), shininessUniform(8) { - Corrade::Utility::Resource rs("MagnumShaders"); +Phong::Phong(): transformationMatrixUniform(0), projectionMatrixUniform(1), normalMatrixUniform(2), lightUniform(3), diffuseColorUniform(4), ambientColorUniform(5), specularColorUniform(6), lightColorUniform(7), shininessUniform(8) { + Utility::Resource rs("MagnumShaders"); #ifndef MAGNUM_TARGET_GLES Version v = Context::current()->supportedVersion({Version::GL320, Version::GL210}); @@ -40,15 +40,17 @@ PhongShader::PhongShader(): transformationMatrixUniform(0), projectionMatrixUnif Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - Shader vertexShader(v, Shader::Type::Vertex); - vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get("PhongShader.vert")); - attachShader(vertexShader); + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Phong.vert")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); - Shader fragmentShader(v, Shader::Type::Fragment); - fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get("PhongShader.frag")); - attachShader(fragmentShader); + Shader frag(v, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Phong.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -61,7 +63,7 @@ PhongShader::PhongShader(): transformationMatrixUniform(0), projectionMatrixUnif bindAttributeLocation(Normal::Location, "normal"); } - link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) diff --git a/src/Shaders/PhongShader.frag b/src/Shaders/Phong.frag similarity index 100% rename from src/Shaders/PhongShader.frag rename to src/Shaders/Phong.frag diff --git a/src/Shaders/PhongShader.h b/src/Shaders/Phong.h similarity index 84% rename from src/Shaders/PhongShader.h rename to src/Shaders/Phong.h index 98b3312d6..7bce3636b 100644 --- a/src/Shaders/PhongShader.h +++ b/src/Shaders/Phong.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Shaders_PhongShader_h -#define Magnum_Shaders_PhongShader_h +#ifndef Magnum_Shaders_Phong_h +#define Magnum_Shaders_Phong_h /* This file is part of Magnum. @@ -25,7 +25,7 @@ */ /** @file - * @brief Class Magnum::Shaders::PhongShader + * @brief Class Magnum::Shaders::Phong */ #include "Math/Matrix4.h" @@ -42,12 +42,12 @@ namespace Magnum { namespace Shaders { If supported, uses GLSL 3.20 and @extension{ARB,explicit_attrib_location}, otherwise falls back to GLSL 1.20. */ -class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { +class MAGNUM_SHADERS_EXPORT Phong: public AbstractShaderProgram { public: typedef Attribute<0, Vector3> Position; /**< @brief Vertex position */ typedef Attribute<1, Vector3> Normal; /**< @brief Normal direction */ - explicit PhongShader(); + explicit Phong(); /** * @brief Set ambient color @@ -55,7 +55,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * * If not set, default value is `(0.0f, 0.0f, 0.0f)`. */ - inline PhongShader* setAmbientColor(const Color3<>& color) { + Phong* setAmbientColor(const Color3<>& color) { setUniform(ambientColorUniform, color); return this; } @@ -64,7 +64,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * @brief Set diffuse color * @return Pointer to self (for method chaining) */ - inline PhongShader* setDiffuseColor(const Color3<>& color) { + Phong* setDiffuseColor(const Color3<>& color) { setUniform(diffuseColorUniform, color); return this; } @@ -75,7 +75,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * * If not set, default value is `(1.0f, 1.0f, 1.0f)`. */ - inline PhongShader* setSpecularColor(const Color3<>& color) { + Phong* setSpecularColor(const Color3<>& color) { setUniform(specularColorUniform, color); return this; } @@ -87,7 +87,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * The larger value, the harder surface (smaller specular highlight). * If not set, default value is `80.0f`. */ - inline PhongShader* setShininess(Float shininess) { + Phong* setShininess(Float shininess) { setUniform(shininessUniform, shininess); return this; } @@ -96,7 +96,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * @brief Set transformation and normal matrix * @return Pointer to self (for method chaining) */ - inline PhongShader* setTransformationMatrix(const Matrix4& matrix) { + Phong* setTransformationMatrix(const Matrix4& matrix) { setUniform(transformationMatrixUniform, matrix); setUniform(normalMatrixUniform, matrix.rotation()); return this; @@ -106,7 +106,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * @brief Set projection matrix * @return Pointer to self (for method chaining) */ - inline PhongShader* setProjectionMatrix(const Matrix4& matrix) { + Phong* setProjectionMatrix(const Matrix4& matrix) { setUniform(projectionMatrixUniform, matrix); return this; } @@ -115,7 +115,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * @brief Set light position * @return Pointer to self (for method chaining) */ - inline PhongShader* setLightPosition(const Vector3& light) { + Phong* setLightPosition(const Vector3& light) { setUniform(lightUniform, light); return this; } @@ -126,7 +126,7 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { * * If not set, default value is `(1.0f, 1.0f, 1.0f)`. */ - inline PhongShader* setLightColor(const Color3<>& color) { + Phong* setLightColor(const Color3<>& color) { setUniform(lightColorUniform, color); return this; } diff --git a/src/Shaders/PhongShader.vert b/src/Shaders/Phong.vert similarity index 100% rename from src/Shaders/PhongShader.vert rename to src/Shaders/Phong.vert diff --git a/src/Shaders/Shaders.h b/src/Shaders/Shaders.h index 855c3d0c3..0a6591e91 100644 --- a/src/Shaders/Shaders.h +++ b/src/Shaders/Shaders.h @@ -35,27 +35,28 @@ namespace Magnum { namespace Shaders { /** @todoc remove when doxygen is sane again */ #ifndef DOXYGEN_GENERATING_OUTPUT -template class DistanceFieldVectorShader; -typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D; -typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D; +template class DistanceFieldVector; +typedef DistanceFieldVector<2> DistanceFieldVector2D; +typedef DistanceFieldVector<3> DistanceFieldVector3D; -template class AbstractVectorShader; -typedef AbstractVectorShader<2> AbstractVectorShader2D; -typedef AbstractVectorShader<3> AbstractVectorShader3D; +template class AbstractVector; +typedef AbstractVector<2> AbstractVector2D; +typedef AbstractVector<3> AbstractVector3D; -template class FlatShader; -typedef FlatShader<2> FlatShader2D; -typedef FlatShader<3> FlatShader3D; +template class Flat; +typedef Flat<2> Flat2D; +typedef Flat<3> Flat3D; -class PhongShader; +class MeshVisualizer; +class Phong; -template class VectorShader; -typedef VectorShader<2> VectorShader2D; -typedef VectorShader<3> VectorShader3D; +template class Vector; +typedef Vector<2> Vector2D; +typedef Vector<3> Vector3D; -template class VertexColorShader; -typedef VertexColorShader<2> VertexColorShader2D; -typedef VertexColorShader<3> VertexColorShader3D; +template class VertexColor; +typedef VertexColor<2> VertexColor2D; +typedef VertexColor<3> VertexColor3D; #endif }} diff --git a/src/Shaders/VectorShader.cpp b/src/Shaders/Vector.cpp similarity index 73% rename from src/Shaders/VectorShader.cpp rename to src/Shaders/Vector.cpp index a4790ed89..802283f19 100644 --- a/src/Shaders/VectorShader.cpp +++ b/src/Shaders/Vector.cpp @@ -22,7 +22,7 @@ DEALINGS IN THE SOFTWARE. */ -#include "VectorShader.h" +#include "Vector.h" #include @@ -34,12 +34,12 @@ namespace Magnum { namespace Shaders { namespace { template constexpr const char* vertexShaderName(); - template<> constexpr const char* vertexShaderName<2>() { return "AbstractVectorShader2D.vert"; } - template<> constexpr const char* vertexShaderName<3>() { return "AbstractVectorShader3D.vert"; } + template<> constexpr const char* vertexShaderName<2>() { return "AbstractVector2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "AbstractVector3D.vert"; } } -template VectorShader::VectorShader(): transformationProjectionMatrixUniform(0), colorUniform(1) { - Corrade::Utility::Resource rs("MagnumShaders"); +template Vector::Vector(): transformationProjectionMatrixUniform(0), colorUniform(1) { + Utility::Resource rs("MagnumShaders"); /* Weird bug in GCC 4.5 - cannot use initializer list here, although the same thing works in PhongShader flawlessly */ @@ -50,15 +50,17 @@ template VectorShader::VectorShader(): trans #endif Version v = Context::current()->supportedVersion(vs); - Shader vertexShader(v, Shader::Type::Vertex); - vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get(vertexShaderName())); - AbstractShaderProgram::attachShader(vertexShader); + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + AbstractShaderProgram::attachShader(vert); - Shader fragmentShader(v, Shader::Type::Fragment); - fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get("VectorShader.frag")); - AbstractShaderProgram::attachShader(fragmentShader); + Shader frag(v, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Vector.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + AbstractShaderProgram::attachShader(frag); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -67,11 +69,11 @@ template VectorShader::VectorShader(): trans if(!Context::current()->isVersionSupported(Version::GLES300)) #endif { - AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::Position::Location, "position"); - AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::TextureCoordinates::Location, "textureCoordinates"); + AbstractShaderProgram::bindAttributeLocation(AbstractVector::Position::Location, "position"); + AbstractShaderProgram::bindAttributeLocation(AbstractVector::TextureCoordinates::Location, "textureCoordinates"); } - AbstractShaderProgram::link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(AbstractShaderProgram::link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) @@ -83,11 +85,11 @@ template VectorShader::VectorShader(): trans #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) - AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVectorShader::VectorTextureLayer); + AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVector::VectorTextureLayer); #endif } -template class VectorShader<2>; -template class VectorShader<3>; +template class Vector<2>; +template class Vector<3>; }} diff --git a/src/Shaders/VectorShader.frag b/src/Shaders/Vector.frag similarity index 100% rename from src/Shaders/VectorShader.frag rename to src/Shaders/Vector.frag diff --git a/src/Shaders/VectorShader.h b/src/Shaders/Vector.h similarity index 77% rename from src/Shaders/VectorShader.h rename to src/Shaders/Vector.h index 64ebba832..9c86a0f3e 100644 --- a/src/Shaders/VectorShader.h +++ b/src/Shaders/Vector.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Shaders_VectorShader_h -#define Magnum_Shaders_VectorShader_h +#ifndef Magnum_Shaders_Vector_h +#define Magnum_Shaders_Vector_h /* This file is part of Magnum. @@ -25,12 +25,12 @@ */ /** @file - * @brief Class Magnum::Shaders::VectorShader, typedef Magnum::Shaders::VectorShader2D, Magnum::Shaders::VectorShader3D + * @brief Class Magnum::Shaders::Vector, typedef Magnum::Shaders::Vector2D, Magnum::Shaders::Vector3D */ #include "Math/Matrix3.h" #include "Math/Matrix4.h" -#include "AbstractVectorShader.h" +#include "AbstractVector.h" #include "magnumShadersVisibility.h" @@ -39,19 +39,19 @@ namespace Magnum { namespace Shaders { /** @brief Vector shader -Renders vector art in plain grayscale form. See also DistanceFieldVectorShader +Renders vector art in plain grayscale form. See also DistanceFieldVector for more advanced effects. -@see VectorShader2D, VectorShader3D +@see Vector2D, Vector3D */ -template class MAGNUM_SHADERS_EXPORT VectorShader: public AbstractVectorShader { +template class MAGNUM_SHADERS_EXPORT Vector: public AbstractVector { public: - VectorShader(); + Vector(); /** * @brief Set transformation and projection matrix * @return Pointer to self (for method chaining) */ - inline VectorShader* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { + Vector* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { AbstractShaderProgram::setUniform(transformationProjectionMatrixUniform, matrix); return this; } @@ -60,7 +60,7 @@ template class MAGNUM_SHADERS_EXPORT VectorShader: publi * @brief Set fill color * @return Pointer to self (for method chaining) */ - inline VectorShader* setColor(const Color4<>& color) { + Vector* setColor(const Color4<>& color) { AbstractShaderProgram::setUniform(colorUniform, color); return this; } @@ -71,10 +71,10 @@ template class MAGNUM_SHADERS_EXPORT VectorShader: publi }; /** @brief Two-dimensional vector shader */ -typedef VectorShader<2> VectorShader2D; +typedef Vector<2> Vector2D; /** @brief Three-dimensional vector shader */ -typedef VectorShader<3> VectorShader3D; +typedef Vector<3> Vector3D; }} diff --git a/src/Shaders/VertexColorShader.cpp b/src/Shaders/VertexColor.cpp similarity index 79% rename from src/Shaders/VertexColorShader.cpp rename to src/Shaders/VertexColor.cpp index df2b37b9a..0ceb36f18 100644 --- a/src/Shaders/VertexColorShader.cpp +++ b/src/Shaders/VertexColor.cpp @@ -22,7 +22,7 @@ DEALINGS IN THE SOFTWARE. */ -#include "VertexColorShader.h" +#include "VertexColor.h" #include @@ -33,12 +33,12 @@ namespace Magnum { namespace Shaders { namespace { template constexpr const char* vertexShaderName(); - template<> constexpr const char* vertexShaderName<2>() { return "VertexColorShader2D.vert"; } - template<> constexpr const char* vertexShaderName<3>() { return "VertexColorShader3D.vert"; } + template<> constexpr const char* vertexShaderName<2>() { return "VertexColor2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "VertexColor3D.vert"; } } -template VertexColorShader::VertexColorShader(): transformationProjectionMatrixUniform(0) { - Corrade::Utility::Resource rs("MagnumShaders"); +template VertexColor::VertexColor(): transformationProjectionMatrixUniform(0) { + Utility::Resource rs("MagnumShaders"); /* Weird bug in GCC 4.5 - cannot use initializer list here, although the same thing works in PhongShader flawlessly*/ @@ -57,15 +57,17 @@ template VertexColorShader::VertexColorShade Version v = Context::current()->supportedVersion(vs); #endif - Shader vertexShader(v, Shader::Type::Vertex); - vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get(vertexShaderName())); - attachShader(vertexShader); + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); - Shader fragmentShader(v, Shader::Type::Fragment); - fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get("VertexColorShader.frag")); - attachShader(fragmentShader); + Shader frag(v, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("VertexColor.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -78,7 +80,7 @@ template VertexColorShader::VertexColorShade bindAttributeLocation(Color::Location, "color"); } - link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) @@ -93,7 +95,7 @@ template VertexColorShader::VertexColorShade #endif } -template class VertexColorShader<2>; -template class VertexColorShader<3>; +template class VertexColor<2>; +template class VertexColor<3>; }} diff --git a/src/Shaders/VertexColorShader.frag b/src/Shaders/VertexColor.frag similarity index 100% rename from src/Shaders/VertexColorShader.frag rename to src/Shaders/VertexColor.frag diff --git a/src/Shaders/VertexColorShader.h b/src/Shaders/VertexColor.h similarity index 81% rename from src/Shaders/VertexColorShader.h rename to src/Shaders/VertexColor.h index a68697f90..e47630e46 100644 --- a/src/Shaders/VertexColorShader.h +++ b/src/Shaders/VertexColor.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Shaders_VertexColorShader_h -#define Magnum_Shaders_VertexColorShader_h +#ifndef Magnum_Shaders_VertexColor_h +#define Magnum_Shaders_VertexColor_h /* This file is part of Magnum. @@ -25,7 +25,7 @@ */ /** @file - * @brief Class Magnum::Shaders::VertexColorShader + * @brief Class Magnum::Shaders::VertexColor */ #include "Math/Matrix3.h" @@ -42,9 +42,9 @@ namespace Magnum { namespace Shaders { @brief Vertex color shader Draws vertex-colored mesh. -@see VertexColorShader2D, VertexColorShader3D +@see VertexColor2D, VertexColor3D */ -template class MAGNUM_SHADERS_EXPORT VertexColorShader: public AbstractShaderProgram { +template class MAGNUM_SHADERS_EXPORT VertexColor: public AbstractShaderProgram { public: /** @brief Vertex position */ typedef Attribute<0, typename DimensionTraits::VectorType> Position; @@ -52,7 +52,7 @@ template class MAGNUM_SHADERS_EXPORT VertexColorShader: /** @brief Vertex color */ typedef Attribute<1, Color3<>> Color; - explicit VertexColorShader(); + explicit VertexColor(); /** * @brief Set transformation and projection matrix @@ -60,7 +60,7 @@ template class MAGNUM_SHADERS_EXPORT VertexColorShader: * * Default is identity matrix. */ - inline VertexColorShader* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { + VertexColor* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { setUniform(transformationProjectionMatrixUniform, matrix); return this; } @@ -70,10 +70,10 @@ template class MAGNUM_SHADERS_EXPORT VertexColorShader: }; /** @brief 2D vertex color shader */ -typedef VertexColorShader<2> VertexColorShader2D; +typedef VertexColor<2> VertexColor2D; /** @brief 3D vertex color shader */ -typedef VertexColorShader<3> VertexColorShader3D; +typedef VertexColor<3> VertexColor3D; }} diff --git a/src/Shaders/VertexColorShader2D.vert b/src/Shaders/VertexColor2D.vert similarity index 100% rename from src/Shaders/VertexColorShader2D.vert rename to src/Shaders/VertexColor2D.vert diff --git a/src/Shaders/VertexColorShader3D.vert b/src/Shaders/VertexColor3D.vert similarity index 100% rename from src/Shaders/VertexColorShader3D.vert rename to src/Shaders/VertexColor3D.vert diff --git a/src/Shaders/magnumShadersResourceImport.hpp b/src/Shaders/magnumShadersResourceImport.hpp index 624b956b1..818f86e9f 100644 --- a/src/Shaders/magnumShadersResourceImport.hpp +++ b/src/Shaders/magnumShadersResourceImport.hpp @@ -29,9 +29,9 @@ #ifdef MAGNUM_BUILD_STATIC #include static int magnumShadersResourceImport() { - RESOURCE_INITIALIZE(MagnumShaders_RCS) + CORRADE_RESOURCE_INITIALIZE(MagnumShaders_RCS) return 0; -} AUTOMATIC_INITIALIZER(magnumShadersResourceImport) +} CORRADE_AUTOMATIC_INITIALIZER(magnumShadersResourceImport) #endif #endif diff --git a/src/Shaders/resources.conf b/src/Shaders/resources.conf new file mode 100644 index 000000000..3f23a2663 --- /dev/null +++ b/src/Shaders/resources.conf @@ -0,0 +1,49 @@ +group=MagnumShaders + +[file] +filename=AbstractVector2D.vert + +[file] +filename=AbstractVector3D.vert + +[file] +filename=Flat2D.vert + +[file] +filename=Flat3D.vert + +[file] +filename=Flat.frag + +[file] +filename=MeshVisualizer.vert + +[file] +filename=MeshVisualizer.geom + +[file] +filename=MeshVisualizer.frag + +[file] +filename=Phong.vert + +[file] +filename=Phong.frag + +[file] +filename=Vector.frag + +[file] +filename=DistanceFieldVector.frag + +[file] +filename=VertexColor2D.vert + +[file] +filename=VertexColor3D.vert + +[file] +filename=VertexColor.frag + +[file] +filename=compatibility.glsl diff --git a/src/Shapes/AbstractShape.cpp b/src/Shapes/AbstractShape.cpp new file mode 100644 index 000000000..4ee79d443 --- /dev/null +++ b/src/Shapes/AbstractShape.cpp @@ -0,0 +1,63 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "AbstractShape.h" + +#include + +#include "Shapes/ShapeGroup.h" +#include "Shapes/Implementation/CollisionDispatch.h" + +namespace Magnum { namespace Shapes { + +template AbstractShape::AbstractShape(SceneGraph::AbstractObject* object, ShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group) { + this->setCachedTransformations(SceneGraph::CachedTransformation::Absolute); +} + +template ShapeGroup* AbstractShape::group() { + return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +} + +template const ShapeGroup* AbstractShape::group() const { + return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); +} + +template auto AbstractShape::type() const -> Type { + return abstractTransformedShape()->type(); +} + +template bool AbstractShape::collides(const AbstractShape* other) const { + return Implementation::collides(abstractTransformedShape(), other->abstractTransformedShape()); +} + +template void AbstractShape::markDirty() { + if(group()) group()->setDirty(); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SHAPES_EXPORT AbstractShape<2>; +template class MAGNUM_SHAPES_EXPORT AbstractShape<3>; +#endif + +}} diff --git a/src/Shapes/AbstractShape.h b/src/Shapes/AbstractShape.h new file mode 100644 index 000000000..c742b969e --- /dev/null +++ b/src/Shapes/AbstractShape.h @@ -0,0 +1,120 @@ +#ifndef Magnum_Shapes_AbstractShape_h +#define Magnum_Shapes_AbstractShape_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Shapes::AbstractShape, typedef Magnum::Shapes::AbstractShape2D, Magnum::Shapes::AbstractShape3D + */ + +#include "Magnum.h" +#include "DimensionTraits.h" +#include "Shapes/magnumShapesVisibility.h" +#include "Shapes/shapeImplementation.h" +#include "SceneGraph/AbstractGroupedFeature.h" + +namespace Magnum { namespace Shapes { + +namespace Implementation { + template inline const AbstractShape* getAbstractShape(const Shapes::AbstractShape* shape) { + return shape->abstractTransformedShape(); + } +} + +/** +@brief Base class for object shapes + +This class is not directly instantiable, see Shape instead. See @ref shapes for +brief introduction. +@see AbstractShape2D, AbstractShape3D +*/ +template class MAGNUM_SHAPES_EXPORT AbstractShape: public SceneGraph::AbstractGroupedFeature> { + friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const AbstractShape*); + + public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + + /** @brief Shape type */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class Type { + Point, /**< Point */ + Line, /**< Line */ + LineSegment, /**< @ref LineSegment "Line segment" */ + Sphere, /**< Sphere */ + Capsule, /**< Capsule */ + AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ + Box, /**< Box */ + Composition, /**< @ref Composition "Shape group" */ + Plane /**< Plane (3D only) */ + }; + #else + typedef typename Implementation::ShapeDimensionTraits::Type Type; + #endif + + /** + * @brief Constructor + * @param object Object holding this feature + * @param group Group this shape belongs to + */ + explicit AbstractShape(SceneGraph::AbstractObject* object, ShapeGroup* group = nullptr); + + /** + * @brief Shape group containing this shape + * + * If the shape doesn't belong to any group, returns `nullptr`. + */ + ShapeGroup* group(); + const ShapeGroup* group() const; /**< @overload */ + + /** + * @brief Shape type + */ + Type type() const; + + /** + * @brief Detect collision with other shape + * + * Default implementation returns false. + */ + bool collides(const AbstractShape* other) const; + + protected: + /** Marks also the group as dirty */ + void markDirty() override; + + private: + virtual const Implementation::AbstractShape MAGNUM_SHAPES_LOCAL * abstractTransformedShape() const = 0; +}; + +/** @brief Base class for two-dimensional object shapes */ +typedef AbstractShape<2> AbstractShape2D; + +/** @brief Base class for three-dimensional object shapes */ +typedef AbstractShape<3> AbstractShape3D; + +}} + +#endif diff --git a/src/Physics/AxisAlignedBox.cpp b/src/Shapes/AxisAlignedBox.cpp similarity index 62% rename from src/Physics/AxisAlignedBox.cpp rename to src/Shapes/AxisAlignedBox.cpp index 5b7a5d7bb..d5474755f 100644 --- a/src/Physics/AxisAlignedBox.cpp +++ b/src/Shapes/AxisAlignedBox.cpp @@ -26,30 +26,23 @@ #include "Math/Matrix3.h" #include "Math/Matrix4.h" -#include "Physics/Point.h" +#include "Shapes/Point.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { -template void AxisAlignedBox::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedMin = matrix.transformPoint(_min); - _transformedMax = matrix.transformPoint(_max); -} - -template bool AxisAlignedBox::collides(const AbstractShape* other) const { - if(other->type() == AbstractShape::Type::Point) - return *this % *static_cast*>(other); - - return AbstractShape::collides(other); +template AxisAlignedBox AxisAlignedBox::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return AxisAlignedBox(matrix.transformPoint(_min), + matrix.transformPoint(_max)); } template bool AxisAlignedBox::operator%(const Point& other) const { - return (other.transformedPosition() >= _transformedMin).all() && - (other.transformedPosition() < _transformedMax).all(); + return (other.position() >= _min).all() && + (other.position() < _max).all(); } #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox<2>; -template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox<3>; +template class MAGNUM_SHAPES_EXPORT AxisAlignedBox<2>; +template class MAGNUM_SHAPES_EXPORT AxisAlignedBox<3>; #endif }} diff --git a/src/Physics/AxisAlignedBox.h b/src/Shapes/AxisAlignedBox.h similarity index 55% rename from src/Physics/AxisAlignedBox.h rename to src/Shapes/AxisAlignedBox.h index 1a0a1e6d7..b65f89e98 100644 --- a/src/Physics/AxisAlignedBox.h +++ b/src/Shapes/AxisAlignedBox.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_AxisAlignedBox_h -#define Magnum_Physics_AxisAlignedBox_h +#ifndef Magnum_Shapes_AxisAlignedBox_h +#define Magnum_Shapes_AxisAlignedBox_h /* This file is part of Magnum. @@ -25,79 +25,67 @@ */ /** @file - * @brief Class Magnum::Physics::AxisAlignedBox, typedef Magnum::Physics::AxisAlignedBox2D, Magnum::Physics.:AxisAlignedBox3D + * @brief Class Magnum::Shapes::AxisAlignedBox, typedef Magnum::Shapes::AxisAlignedBox2D, Magnum::Shapes.:AxisAlignedBox3D */ #include "Math/Vector3.h" -#include "Physics/AbstractShape.h" -#include "Physics/Physics.h" +#include "DimensionTraits.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief Axis-aligned box -Unit-size means that half extents are equal to 1, equivalent to e.g. sphere -radius. +See @ref shapes for brief introduction. @see AxisAlignedBox2D, AxisAlignedBox3D @todo Assert for rotation */ -template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox: public AbstractShape { +template class MAGNUM_SHAPES_EXPORT AxisAlignedBox { public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + /** * @brief Default constructor * * Creates zero sized box positioned at origin. */ - inline explicit AxisAlignedBox() {} + constexpr /*implicit*/ AxisAlignedBox() {} /** @brief Constructor */ - inline explicit AxisAlignedBox(const typename DimensionTraits::VectorType& min, const typename DimensionTraits::VectorType& max): _min(min), _max(max), _transformedMin(min), _transformedMax(max) {} - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::AxisAlignedBox; - } - - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; + constexpr /*implicit*/ AxisAlignedBox(const typename DimensionTraits::VectorType& min, const typename DimensionTraits::VectorType& max): _min(min), _max(max) {} - bool collides(const AbstractShape* other) const override; + /** @brief Transformed shape */ + AxisAlignedBox transformed(const typename DimensionTraits::MatrixType& matrix) const; /** @brief Minimal coordinates */ - inline typename DimensionTraits::VectorType min() const { + constexpr typename DimensionTraits::VectorType min() const { return _min; } /** @brief Set minimal coordinates */ - inline void setMin(const typename DimensionTraits::VectorType& min) { + void setMin(const typename DimensionTraits::VectorType& min) { _min = min; } /** @brief Maximal coordinates */ - inline typename DimensionTraits::VectorType max() const { return _max; } + constexpr typename DimensionTraits::VectorType max() const { + return _max; + } /** @brief Set maximal coordinates */ - inline void setMax(const typename DimensionTraits::VectorType& max) { + void setMax(const typename DimensionTraits::VectorType& max) { _max = max; } - /** @brief Transformed minimal coordinates */ - inline typename DimensionTraits::VectorType transformedMin() const { - return _transformedMin; - } - - /** @brief Transformed maximal coordinates */ - inline typename DimensionTraits::VectorType transformedMax() const { - return _transformedMax; - } - /** @brief Collision with point */ bool operator%(const Point& other) const; private: - typename DimensionTraits::VectorType _min, _max, - _transformedMin, _transformedMax; + typename DimensionTraits::VectorType _min, _max; }; /** @brief Two-dimensional axis-aligned box */ diff --git a/src/Physics/Box.cpp b/src/Shapes/Box.cpp similarity index 82% rename from src/Physics/Box.cpp rename to src/Shapes/Box.cpp index 3f724793e..6282784ee 100644 --- a/src/Physics/Box.cpp +++ b/src/Shapes/Box.cpp @@ -24,12 +24,10 @@ #include "Box.h" -#include "Math/Matrix4.h" +namespace Magnum { namespace Shapes { -namespace Magnum { namespace Physics { - -template void Box::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedTransformation = matrix*_transformation; +template Box Box::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Box(matrix*_transformation); } template class Box<2>; diff --git a/src/Physics/Box.h b/src/Shapes/Box.h similarity index 59% rename from src/Physics/Box.h rename to src/Shapes/Box.h index cf7276187..22750192d 100644 --- a/src/Physics/Box.h +++ b/src/Shapes/Box.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Box_h -#define Magnum_Physics_Box_h +#ifndef Magnum_Shapes_Box_h +#define Magnum_Shapes_Box_h /* This file is part of Magnum. @@ -25,62 +25,56 @@ */ /** @file - * @brief Class Magnum::Physics::Box, typedef Magnum::Physics::Box2D, Magnum::Physics::Box3D + * @brief Class Magnum::Shapes::Box, typedef Magnum::Shapes::Box2D, Magnum::Shapes::Box3D */ #include "Math/Matrix3.h" #include "Math/Matrix4.h" -#include "AbstractShape.h" +#include "DimensionTraits.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief Unit-size box with assigned transformation matrix Unit-size means that half extents are equal to 1, equivalent to e.g. sphere -radius. +radius. See @ref shapes for brief introduction. @todo Use quat + position + size instead? @see Box2D, Box3D @todo Assert for skew */ -template class MAGNUM_PHYSICS_EXPORT Box: public AbstractShape { +template class MAGNUM_SHAPES_EXPORT Box { public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + /** * @brief Default constructor * * Creates zero-sized box positioned at origin. */ - inline explicit Box(): _transformation(DimensionTraits::MatrixType::Zero), _transformedTransformation(DimensionTraits::MatrixType::Zero) {} + constexpr /*implicit*/ Box(): _transformation(DimensionTraits::MatrixType::Zero) {} /** @brief Constructor */ - inline explicit Box(const typename DimensionTraits::MatrixType& transformation): _transformation(transformation), _transformedTransformation(transformation) {} - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::Box; - } + constexpr /*implicit*/ Box(const typename DimensionTraits::MatrixType& transformation): _transformation(transformation) {} - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; + /** @brief Transformed shape */ + Box transformed(const typename DimensionTraits::MatrixType& matrix) const; /** @brief Transformation */ - inline typename DimensionTraits::MatrixType transformation() const { + constexpr typename DimensionTraits::MatrixType transformation() const { return _transformation; } /** @brief Set transformation */ - inline void setTransformation(const typename DimensionTraits::MatrixType& transformation) { + void setTransformation(const typename DimensionTraits::MatrixType& transformation) { _transformation = transformation; } - /** @brief Transformed transformation */ - inline typename DimensionTraits::MatrixType transformedTransformation() const { - return _transformedTransformation; - } - private: - typename DimensionTraits::MatrixType _transformation, - _transformedTransformation; + typename DimensionTraits::MatrixType _transformation; }; /** @brief Two-dimensional box */ diff --git a/src/Physics/CMakeLists.txt b/src/Shapes/CMakeLists.txt similarity index 71% rename from src/Physics/CMakeLists.txt rename to src/Shapes/CMakeLists.txt index ef1d51a51..189a1f07e 100644 --- a/src/Physics/CMakeLists.txt +++ b/src/Shapes/CMakeLists.txt @@ -22,45 +22,50 @@ # DEALINGS IN THE SOFTWARE. # -set(MagnumPhysics_SRCS +set(MagnumShapes_SRCS AbstractShape.cpp AxisAlignedBox.cpp Box.cpp Capsule.cpp + Composition.cpp Line.cpp Plane.cpp Point.cpp - ObjectShape.cpp - ObjectShapeGroup.cpp + Shape.cpp ShapeGroup.cpp - Sphere.cpp) + Sphere.cpp -set(MagnumPhysics_HEADERS + shapeImplementation.cpp + + Implementation/CollisionDispatch.cpp) + +set(MagnumShapes_HEADERS AbstractShape.h AxisAlignedBox.h Box.h Capsule.h + Composition.h Line.h LineSegment.h - ObjectShape.h - ObjectShapeGroup.h - Physics.h + Shape.h + ShapeGroup.h + Shapes.h Plane.h Point.h - ShapeGroup.h Sphere.h - magnumPhysicsVisibility.h) + magnumShapesVisibility.h + shapeImplementation.h) -add_library(MagnumPhysics ${SHARED_OR_STATIC} ${MagnumPhysics_SRCS}) +add_library(MagnumShapes ${SHARED_OR_STATIC} ${MagnumShapes_SRCS}) if(BUILD_STATIC_PIC) # TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property - set_target_properties(MagnumPhysics PROPERTIES COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}) + set_target_properties(MagnumShapes PROPERTIES COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}) endif() -target_link_libraries(MagnumPhysics Magnum MagnumSceneGraph) +target_link_libraries(MagnumShapes Magnum MagnumSceneGraph) -install(TARGETS MagnumPhysics DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) -install(FILES ${MagnumPhysics_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Physics) +install(TARGETS MagnumShapes DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +install(FILES ${MagnumShapes_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Shapes) if(BUILD_TESTS) add_subdirectory(Test) diff --git a/src/Physics/Capsule.cpp b/src/Shapes/Capsule.cpp similarity index 54% rename from src/Physics/Capsule.cpp rename to src/Shapes/Capsule.cpp index 09823df5d..69c543ec9 100644 --- a/src/Physics/Capsule.cpp +++ b/src/Shapes/Capsule.cpp @@ -28,42 +28,32 @@ #include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Math/Geometry/Distance.h" -#include "Point.h" -#include "Sphere.h" +#include "Magnum.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" using namespace Magnum::Math::Geometry; -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { -template void Capsule::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedA = matrix.transformPoint(_a); - _transformedB = matrix.transformPoint(_b); - Float scaling = (matrix.rotationScaling()*typename DimensionTraits::VectorType(1/Constants::sqrt3())).length(); - _transformedRadius = scaling*_radius; -} - -template bool Capsule::collides(const AbstractShape* other) const { - if(other->type() == AbstractShape::Type::Point) - return *this % *static_cast*>(other); - if(other->type() == AbstractShape::Type::Sphere) - return *this % *static_cast*>(other); - - return AbstractShape::collides(other); +template Capsule Capsule::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Capsule(matrix.transformPoint(_a), matrix.transformPoint(_b), + (matrix.rotationScaling()*typename DimensionTraits::VectorType(1/Constants::sqrt3())).length()*_radius); } template bool Capsule::operator%(const Point& other) const { - return Distance::lineSegmentPointSquared(transformedA(), transformedB(), other.transformedPosition()) < - Math::pow<2>(transformedRadius()); + return Distance::lineSegmentPointSquared(_a, _b, other.position()) < + Math::pow<2>(_radius); } template bool Capsule::operator%(const Sphere& other) const { - return Distance::lineSegmentPointSquared(transformedA(), transformedB(), other.transformedPosition()) < - Math::pow<2>(transformedRadius()+other.transformedRadius()); + return Distance::lineSegmentPointSquared(_a, _b, other.position()) < + Math::pow<2>(_radius+other.radius()); } #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT Capsule<2>; -template class MAGNUM_PHYSICS_EXPORT Capsule<3>; +template class MAGNUM_SHAPES_EXPORT Capsule<2>; +template class MAGNUM_SHAPES_EXPORT Capsule<3>; #endif }} diff --git a/src/Physics/Capsule.h b/src/Shapes/Capsule.h similarity index 55% rename from src/Physics/Capsule.h rename to src/Shapes/Capsule.h index b40a33b4f..4eb91869d 100644 --- a/src/Physics/Capsule.h +++ b/src/Shapes/Capsule.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Capsule_h -#define Magnum_Physics_Capsule_h +#ifndef Magnum_Shapes_Capsule_h +#define Magnum_Shapes_Capsule_h /* This file is part of Magnum. @@ -25,85 +25,69 @@ */ /** @file - * @brief Class Magnum::Physics::Capsule, typedef Magnum::Physics::Capsule2D, Magnum::Physics::Capsule3D + * @brief Class Magnum::Shapes::Capsule, typedef Magnum::Shapes::Capsule2D, Magnum::Shapes::Capsule3D */ #include "Math/Vector3.h" -#include "AbstractShape.h" -#include "Physics.h" +#include "DimensionTraits.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief %Capsule defined by cylinder start and end point and radius Unlike other elements the capsule doesn't support asymmetric scaling. When -applying transformation, the scale factor is averaged from all axes. +applying transformation, the scale factor is averaged from all axes. See +@ref shapes for brief introduction. @see Capsule2D, Capsule3D @todo Assert for asymmetric scaling */ -template class MAGNUM_PHYSICS_EXPORT Capsule: public AbstractShape { +template class MAGNUM_SHAPES_EXPORT Capsule { public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + /** * @brief Constructor * * Creates zero-sized capsule at origin. */ - inline explicit Capsule(): _radius(0.0f), _transformedRadius(0.0f) {} + constexpr /*implicit*/ Capsule(): _radius(0.0f) {} /** @brief Constructor */ - inline explicit Capsule(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius): _a(a), _transformedA(a), _b(b), _transformedB(b), _radius(radius), _transformedRadius(radius) {} - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::Capsule; - } - - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; + constexpr /*implicit*/ Capsule(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius): _a(a), _b(b), _radius(radius) {} - bool collides(const AbstractShape* other) const override; + /** @brief Transformed shape */ + Capsule transformed(const typename DimensionTraits::MatrixType& matrix) const; /** @brief Start point */ - inline typename DimensionTraits::VectorType a() const { + constexpr typename DimensionTraits::VectorType a() const { return _a; } - /** @brief End point */ - inline typename DimensionTraits::VectorType b() const { - return _b; - } - /** @brief Set start point */ - inline void setA(const typename DimensionTraits::VectorType& a) { + void setA(const typename DimensionTraits::VectorType& a) { _a = a; } + /** @brief End point */ + constexpr typename DimensionTraits::VectorType b() const { + return _b; + } + /** @brief Set end point */ - inline void setB(const typename DimensionTraits::VectorType& b) { + void setB(const typename DimensionTraits::VectorType& b) { _b = b; } /** @brief Radius */ - inline Float radius() const { return _radius; } + constexpr Float radius() const { return _radius; } /** @brief Set radius */ - inline void setRadius(Float radius) { _radius = radius; } - - /** @brief Transformed first point */ - inline typename DimensionTraits::VectorType transformedA() const { - return _transformedA; - } - - /** @brief Transformed second point */ - inline typename DimensionTraits::VectorType transformedB() const { - return _transformedB; - } - - /** @brief Transformed radius */ - inline Float transformedRadius() const { - return _transformedRadius; - } + void setRadius(Float radius) { _radius = radius; } /** @brief Collision with point */ bool operator%(const Point& other) const; @@ -112,9 +96,8 @@ template class MAGNUM_PHYSICS_EXPORT Capsule: public Abs bool operator%(const Sphere& other) const; private: - typename DimensionTraits::VectorType _a, _transformedA, - _b, _transformedB; - Float _radius, _transformedRadius; + typename DimensionTraits::VectorType _a, _b; + Float _radius; }; /** @brief Two-dimensional capsule */ diff --git a/src/Shapes/Composition.cpp b/src/Shapes/Composition.cpp new file mode 100644 index 000000000..3bc721b73 --- /dev/null +++ b/src/Shapes/Composition.cpp @@ -0,0 +1,167 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Composition.h" + +#include +#include + +#include "Shapes/Implementation/CollisionDispatch.h" + +namespace Magnum { namespace Shapes { + +/* +Hierarchy implementation notes: + +The hierarchy is stored in flat array to provide easy access for the user and +to save some allocations. Each node has zero, one or two subnodes. Value of +`Node::rightNode` describes which child nodes exist: + + * 0 - no child subnodes + * 1 - only left subnode exists + * 2 - only right subnode exists + * >2 - both child nodes exist + +If left node exists, it is right next to current one. If right node exists, it +is at position `Node::rightNode-1` relative to current one (this applies also +when `rightNode` is equal to 2, right node is right next to current one, +because there are no left nodes). + +The node also specifies which shapes belong to it. Root node owns whole shape +array and `Node::rightShape` marks first shape belonging to the right child +node, relatively to begin. This recurses into child nodes, thus left child node +has shapes from parent's begin to parent's `rightShape`. + +Shapes are merged together by concatenating its node and shape list and adding +new node at the beginning with properly set `rightNode` and `rightShape`. +Because these values are relative to parent, they don't need to be modified +when concatenating. +*/ + +template Composition::Composition(const Composition& other): _shapeCount(other._shapeCount), _nodeCount(other._nodeCount) { + copyShapes(0, other); + copyNodes(0, other); +} + +template Composition::Composition(Composition&& other): _shapeCount(other._shapeCount), _nodeCount(other._nodeCount), _shapes(other._shapes), _nodes(other._nodes) { + other._shapes = nullptr; + other._shapeCount = 0; + + other._nodes = nullptr; + other._nodeCount = 0; +} + +template Composition::~Composition() { + for(std::size_t i = 0; i != _shapeCount; ++i) + delete _shapes[i]; + + delete[] _shapes; + delete[] _nodes; +} + +template Composition& Composition::operator=(const Composition& other) { + for(std::size_t i = 0; i != _shapeCount; ++i) + delete _shapes[i]; + + if(_shapeCount != other._shapeCount) { + delete[] _shapes; + _shapeCount = other._shapeCount; + _shapes = new Implementation::AbstractShape*[_shapeCount]; + } + + if(_nodeCount != other._nodeCount) { + delete[] _nodes; + _nodeCount = other._nodeCount; + _nodes = new Node[_nodeCount]; + } + + copyShapes(0, other); + copyNodes(0, other); + return *this; +} + +template Composition& Composition::operator=(Composition&& other) { + std::swap(other._shapeCount, _shapeCount); + std::swap(other._nodeCount, _nodeCount); + std::swap(other._shapes, _shapes); + std::swap(other._nodes, _nodes); + return *this; +} + +template void Composition::copyShapes(const std::size_t offset, Composition&& other) { + std::move(other._shapes, other._shapes+other._shapeCount, _shapes+offset); + delete[] other._shapes; + other._shapes = nullptr; + other._shapeCount = 0; +} + +template void Composition::copyShapes(const std::size_t offset, const Composition& other) { + for(std::size_t i = 0; i != other._shapeCount; ++i) + _shapes[i+offset] = other._shapes[i]->clone(); +} + +template void Composition::copyNodes(std::size_t offset, const Composition& other) { + std::copy(other._nodes, other._nodes+other._nodeCount, _nodes+offset); +} + +template Composition Composition::transformed(const typename DimensionTraits::MatrixType& matrix) const { + Composition out(*this); + for(std::size_t i = 0; i != _shapeCount; ++i) + _shapes[i]->transform(matrix, out._shapes[i]); + return out; +} + +template bool Composition::collides(const Implementation::AbstractShape* const a, const std::size_t node, const std::size_t shapeBegin, const std::size_t shapeEnd) const { + /* Empty group */ + if(shapeBegin == shapeEnd) return false; + + CORRADE_INTERNAL_ASSERT(node < _nodeCount && shapeBegin < shapeEnd); + + /* Collision on the left child. If the node is leaf one (no left child + exists), do it directly, recurse instead. */ + const bool collidesLeft = (_nodes[node].rightNode == 0 || _nodes[node].rightNode == 2) ? + Implementation::collides(a, _shapes[shapeBegin]) : + collides(a, node+1, shapeBegin, shapeBegin+_nodes[node].rightShape); + + /* NOT operation */ + if(_nodes[node].operation == CompositionOperation::Not) + return !collidesLeft; + + /* Short-circuit evaluation for AND/OR */ + if((_nodes[node].operation == CompositionOperation::Or) == collidesLeft) + return collidesLeft; + + /* Now the collision result depends only on the right child. Similar to + collision on the left child. */ + return (_nodes[node].rightNode < 2) ? + Implementation::collides(a, _shapes[shapeBegin+_nodes[node].rightShape]) : + collides(a, node+_nodes[node].rightNode-1, shapeBegin+_nodes[node].rightShape, shapeEnd); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SHAPES_EXPORT Composition<2>; +template class MAGNUM_SHAPES_EXPORT Composition<3>; +#endif + +}} diff --git a/src/Shapes/Composition.h b/src/Shapes/Composition.h new file mode 100644 index 000000000..6f6abdbf6 --- /dev/null +++ b/src/Shapes/Composition.h @@ -0,0 +1,297 @@ +#ifndef Magnum_Shapes_Composition_h +#define Magnum_Shapes_Composition_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Shapes::Composition, enum Magnum::Shapes::CompositionOperation + */ + +#include +#include +#include + +#include "DimensionTraits.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" +#include "Shapes/shapeImplementation.h" + +namespace Magnum { namespace Shapes { + +namespace Implementation { + template struct ShapeHelper; + + template inline AbstractShape* getAbstractShape(Composition& group, std::size_t i) { + return group._shapes[i]; + } + template inline const AbstractShape* getAbstractShape(const Composition& group, std::size_t i) { + return group._shapes[i]; + } +} + +/** @brief Shape operation */ +enum class CompositionOperation: UnsignedByte { + Not, /**< Boolean NOT */ + And, /**< Boolean AND */ + Or /**< Boolean OR */ +}; + +/** +@brief Composition of shapes + +Result of logical operations on shapes. See @ref shapes for brief introduction. +*/ +template class MAGNUM_SHAPES_EXPORT Composition { + friend Implementation::AbstractShape* Implementation::getAbstractShape<>(Composition&, std::size_t); + friend const Implementation::AbstractShape* Implementation::getAbstractShape<>(const Composition&, std::size_t); + friend struct Implementation::ShapeHelper>; + + public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + + /** @brief Shape type */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class Type { + Point, /**< Point */ + Line, /**< Line */ + LineSegment, /**< @ref LineSegment "Line segment" */ + Sphere, /**< Sphere */ + Capsule, /**< Capsule */ + AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ + Box, /**< Box */ + Plane /**< Plane (3D only) */ + }; + #else + typedef typename Implementation::ShapeDimensionTraits::Type Type; + #endif + + /** + * @brief Default constructor + * + * Creates empty hierarchy. + */ + explicit Composition(): _shapeCount(0), _nodeCount(0), _shapes(nullptr), _nodes(nullptr) {} + + /** + * @brief Unary operation constructor + * @param operation Unary operation + * @param a Operand + */ + template explicit Composition(CompositionOperation operation, T&& a); + + /** + * @brief Binary operation constructor + * @param operation Binary operation + * @param a Left operand + * @param b Right operand + */ + template explicit Composition(CompositionOperation operation, T&& a, U&& b); + + /** @brief Copy constructor */ + Composition(const Composition& other); + + /** @brief Move constructor */ + Composition(Composition&& other); + + ~Composition(); + + /** @brief Assigment operator */ + Composition& operator=(const Composition& other); + + /** @brief Move assignment operator */ + Composition& operator=(Composition&& other); + + /** @brief Transformed shape */ + Composition transformed(const typename DimensionTraits::MatrixType& matrix) const; + + /** @brief Count of shapes in the hierarchy */ + std::size_t size() const { return _shapeCount; } + + /** @brief Type of shape at given position */ + Type type(std::size_t i) const { return _shapes[i]->type(); } + + /** @brief Shape at given position */ + template const T& get(std::size_t i) const; + + /** @brief Collision with another shape */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template bool operator%(const T& other) const { + #else + template auto operator%(const T& other) const -> typename std::enable_if::type()), typename Implementation::ShapeDimensionTraits::Type>::value, bool>::type { + #endif + Implementation::Shape a(other); + return collides(&a); + } + + private: + struct Node { + std::size_t rightNode, rightShape; + CompositionOperation operation; + }; + + bool collides(const Implementation::AbstractShape* a) const { + return collides(a, 0, 0, _shapeCount); + } + + bool collides(const Implementation::AbstractShape* a, std::size_t node, std::size_t shapeBegin, std::size_t shapeEnd) const; + + template constexpr static std::size_t shapeCount(const T&) { + return 1; + } + constexpr static std::size_t shapeCount(const Composition& hierarchy) { + return hierarchy._shapeCount; + } + template constexpr static std::size_t nodeCount(const T&) { + return 0; + } + constexpr static std::size_t nodeCount(const Composition& hierarchy) { + return hierarchy._nodeCount; + } + + template void copyShapes(std::size_t offset, const T& shape) { + _shapes[offset] = new Implementation::Shape(shape); + } + void copyShapes(std::size_t offset, Composition&& other); + void copyShapes(std::size_t offset, const Composition& other); + + template void copyNodes(std::size_t, const T&) {} + void copyNodes(std::size_t offset, const Composition& other); + + std::size_t _shapeCount, _nodeCount; + Implementation::AbstractShape** _shapes; + Node* _nodes; +}; + +/** @brief Two-dimensional shape hierarchy */ +typedef Composition<2> Composition2D; + +/** @brief Three-dimensional shape hierarchy */ +typedef Composition<3> Composition3D; + +#ifdef DOXYGEN_GENERATING_OUTPUT +/** @debugoperator{Magnum::Shapes::Composition} */ +template Debug operator<<(Debug debug, typename Composition::Type value); +#endif + +/** @relates Composition +@brief Collision of shape with Composition +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline bool operator%(const T& a, const Composition& b) { +#else +template inline auto operator%(const T& a, const Composition& b) -> typename std::enable_if::type()), typename Implementation::ShapeDimensionTraits::Type>::value, bool>::type { +#endif + return b % a; +} + +#ifdef DOXYGEN_GENERATING_OUTPUT +/** @relates Composition +@brief Logical NOT of shape +*/ +template inline Composition operator!(T a); + +/** @relates Composition +@brief Logical AND of two shapes + +[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) +is used here, so this operation can be used for providing simplified shape +version, because collision with @p b is computed only if @p a collides. +See @ref shapes-simplification for an example. +*/ +template inline Composition operator&&(T a, T b); + +/** @relates Composition +@brief Logical OR of two shapes + +[Short-circuit evaluation](http://en.wikipedia.org/wiki/Short-circuit_evaluation) +is used, so if collision with @p a is detected, collision with @p b is not +computed. +*/ +template inline Composition operator||(T a, T b); +#endif + +#ifndef DOXYGEN_GENERATING_OUTPUT +#define enableIfIsShapeType typename std::enable_if< \ + std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value, \ + Composition>::type +#define enableIfAreShapeType typename std::enable_if< \ + std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value && \ + std::is_same::type()), typename Implementation::ShapeDimensionTraits::Type>::value, \ + Composition>::type +template inline auto operator!(T&& a) -> enableIfIsShapeType { + return Composition(CompositionOperation::Not, std::forward(a)); +} +template inline auto operator&&(T&& a, U&& b) -> enableIfAreShapeType { + return Composition(CompositionOperation::And, std::forward(a), std::forward(b)); +} +template inline auto operator||(T&& a, U&& b) -> enableIfAreShapeType { + return Composition(CompositionOperation::Or, std::forward(a), std::forward(b)); +} +#undef enableIfIsShapeType +#undef enableIfAreShapeType +#endif + +template template Composition::Composition(CompositionOperation operation, T&& a): _shapeCount(shapeCount(a)), _nodeCount(nodeCount(a)+1), _shapes(new Implementation::AbstractShape*[_shapeCount]), _nodes(new Node[_nodeCount]) { + CORRADE_ASSERT(operation == CompositionOperation::Not, + "Shapes::Composition::Composition(): unary operation expected", ); + _nodes[0].operation = operation; + + /* 0 = no children, 1 = left child only */ + _nodes[0].rightNode = (nodeCount(a) == 0 ? 0 : 1); + _nodes[0].rightShape = shapeCount(a); + copyNodes(1, a); + copyShapes(0, std::forward(a)); +} + +template template Composition::Composition(CompositionOperation operation, T&& a, U&& b): _shapeCount(shapeCount(a) + shapeCount(b)), _nodeCount(nodeCount(a) + nodeCount(b) + 1), _shapes(new Implementation::AbstractShape*[_shapeCount]), _nodes(new Node[_nodeCount]) { + CORRADE_ASSERT(operation != CompositionOperation::Not, + "Shapes::Composition::Composition(): binary operation expected", ); + _nodes[0].operation = operation; + + /* 0 = no children, 1 = left child only, 2 = right child only, >2 = both */ + if(nodeCount(a) == 0 && nodeCount(b) == 0) + _nodes[0].rightNode = 0; + else if(nodeCount(b) == 0) + _nodes[0].rightNode = 1; + else _nodes[0].rightNode = nodeCount(a) + 2; + + _nodes[0].rightShape = shapeCount(a); + copyNodes(1, a); + copyNodes(nodeCount(a) + 1, b); + copyShapes(shapeCount(a), std::forward(b)); + copyShapes(0, std::forward(a)); +} + +template template inline const T& Composition::get(std::size_t i) const { + CORRADE_ASSERT(_shapes[i]->type() == Implementation::TypeOf::type(), + "Shapes::Composition::get(): given shape is not of type" << Implementation::TypeOf::type() << + "but" << _shapes[i]->type(), *static_cast(nullptr)); + return static_cast*>(_shapes[i])->shape; +} + +}} + +#endif diff --git a/src/Shapes/Implementation/CollisionDispatch.cpp b/src/Shapes/Implementation/CollisionDispatch.cpp new file mode 100644 index 000000000..0b9a59964 --- /dev/null +++ b/src/Shapes/Implementation/CollisionDispatch.cpp @@ -0,0 +1,102 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "CollisionDispatch.h" + +#include "Shapes/AxisAlignedBox.h" +#include "Shapes/Box.h" +#include "Shapes/Capsule.h" +#include "Shapes/LineSegment.h" +#include "Shapes/Plane.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" +#include "Shapes/shapeImplementation.h" + +namespace Magnum { namespace Shapes { namespace Implementation { + +namespace { + constexpr UnsignedInt operator*(ShapeDimensionTraits<2>::Type a, ShapeDimensionTraits<2>::Type b) { + return UnsignedInt(a)*UnsignedInt(b); + } + constexpr UnsignedInt operator*(ShapeDimensionTraits<3>::Type a, ShapeDimensionTraits<3>::Type b) { + return UnsignedInt(a)*UnsignedInt(b); + } +} + +template<> bool collides(const AbstractShape<2>* const a, const AbstractShape<2>* const b) { + if(a->type() < b->type()) return collides(b, a); + + switch(a->type()*b->type()) { + case ShapeDimensionTraits<2>::Type::Sphere*ShapeDimensionTraits<2>::Type::Point: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<2>::Type::Sphere*ShapeDimensionTraits<2>::Type::Line: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<2>::Type::Sphere*ShapeDimensionTraits<2>::Type::LineSegment: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<2>::Type::Sphere*ShapeDimensionTraits<2>::Type::Sphere: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + + case ShapeDimensionTraits<2>::Type::Capsule*ShapeDimensionTraits<2>::Type::Point: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<2>::Type::Capsule*ShapeDimensionTraits<2>::Type::Sphere: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + + case ShapeDimensionTraits<2>::Type::AxisAlignedBox*ShapeDimensionTraits<2>::Type::Point: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + } + + return false; +} + +template<> bool collides(const AbstractShape<3>* const a, const AbstractShape<3>* const b) { + if(a->type() < b->type()) return collides(b, a); + + switch(a->type()*b->type()) { + case ShapeDimensionTraits<3>::Type::Sphere*ShapeDimensionTraits<3>::Type::Point: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<3>::Type::Sphere*ShapeDimensionTraits<3>::Type::Line: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<3>::Type::Sphere*ShapeDimensionTraits<3>::Type::LineSegment: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<3>::Type::Sphere*ShapeDimensionTraits<3>::Type::Sphere: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + + case ShapeDimensionTraits<3>::Type::Capsule*ShapeDimensionTraits<3>::Type::Point: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<3>::Type::Capsule*ShapeDimensionTraits<3>::Type::Sphere: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + + case ShapeDimensionTraits<3>::Type::AxisAlignedBox*ShapeDimensionTraits<3>::Type::Point: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + + case ShapeDimensionTraits<3>::Type::Plane*ShapeDimensionTraits<3>::Type::Line: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + case ShapeDimensionTraits<3>::Type::Plane*ShapeDimensionTraits<3>::Type::LineSegment: + return static_cast*>(a)->shape % static_cast*>(b)->shape; + } + + return false; +} + +}}} diff --git a/src/Shapes/Implementation/CollisionDispatch.h b/src/Shapes/Implementation/CollisionDispatch.h new file mode 100644 index 000000000..99517c970 --- /dev/null +++ b/src/Shapes/Implementation/CollisionDispatch.h @@ -0,0 +1,46 @@ +#ifndef Magnum_Shapes_Implementation_CollisionDispatch_h +#define Magnum_Shapes_Implementation_CollisionDispatch_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Types.h" + +namespace Magnum { namespace Shapes { namespace Implementation { + +template struct AbstractShape; + +/* +Shape collision double-dispatch: + +The collision is symmetric, i.e. it doesn't matter if we test Point vs. Sphere +or Sphere vs. Point. Each type is specified by unique prime number. Then we +multiply the two numbers together and switch() on the result. Because of +multiplying two prime numbers, there is no ambiguity (the result is unique for +each combination). +*/ +template bool collides(const AbstractShape* a, const AbstractShape* b); + +}}} + +#endif diff --git a/src/Physics/Line.cpp b/src/Shapes/Line.cpp similarity index 82% rename from src/Physics/Line.cpp rename to src/Shapes/Line.cpp index bcb5f9a15..abbdb5d9a 100644 --- a/src/Physics/Line.cpp +++ b/src/Shapes/Line.cpp @@ -27,11 +27,11 @@ #include "Math/Matrix3.h" #include "Math/Matrix4.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { -template void Line::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedA = matrix.transformPoint(_a); - _transformedB = matrix.transformPoint(_b); +template Line Line::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Line(matrix.transformPoint(_a), + matrix.transformPoint(_b)); } /* Explicitly instantiate the templates */ diff --git a/src/Physics/Line.h b/src/Shapes/Line.h similarity index 54% rename from src/Physics/Line.h rename to src/Shapes/Line.h index 49e835c3c..eb9f5afba 100644 --- a/src/Physics/Line.h +++ b/src/Shapes/Line.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Line_h -#define Magnum_Physics_Line_h +#ifndef Magnum_Shapes_Line_h +#define Magnum_Shapes_Line_h /* This file is part of Magnum. @@ -25,73 +25,63 @@ */ /** @file - * @brief Class Magnum::Physics::Line, typedef Magnum::Physics::Line2D, Magnum::Physics::Line3D + * @brief Class Magnum::Shapes::Line, typedef Magnum::Shapes::Line2D, Magnum::Shapes::Line3D */ #include "Math/Vector3.h" -#include "AbstractShape.h" +#include "DimensionTraits.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief Infinite line, defined by two points +See @ref shapes for brief introduction. @see Line2D, Line3D @todo collision detection of two Line2D */ -template class MAGNUM_PHYSICS_EXPORT Line: public AbstractShape { +template class MAGNUM_SHAPES_EXPORT Line { public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + /** * @brief Default constructor * * Creates line with both points at origin. */ - inline explicit Line() {} + constexpr /*implicit*/ Line() {} /** @brief Constructor */ - inline explicit Line(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b): _a(a), _transformedA(a), _b(b), _transformedB(b) {} - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::Line; - } + constexpr /*implicit*/ Line(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b): _a(a), _b(b) {} - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; + /** @brief Transformed shape */ + Line transformed(const typename DimensionTraits::MatrixType& matrix) const; /** @brief First point */ - inline typename DimensionTraits::VectorType a() const { + constexpr typename DimensionTraits::VectorType a() const { return _a; } - /** @brief Second point */ - inline typename DimensionTraits::VectorType b() const { - return _b; - } - /** @brief Set first point */ - inline void setA(const typename DimensionTraits::VectorType& a) { + void setA(const typename DimensionTraits::VectorType& a) { _a = a; } - /** @brief Set second point */ - inline void setB(const typename DimensionTraits::VectorType& b) { - _b = b; - } - - /** @brief Transformed first point */ - inline typename DimensionTraits::VectorType transformedA() const { - return _transformedA; + /** @brief Second point */ + constexpr typename DimensionTraits::VectorType b() const { + return _b; } - /** @brief Transformed second point */ - inline typename DimensionTraits::VectorType transformedB() const { - return _transformedB; + /** @brief Set second point */ + void setB(const typename DimensionTraits::VectorType& b) { + _b = b; } private: - typename DimensionTraits::VectorType _a, _transformedA, - _b, _transformedB; + typename DimensionTraits::VectorType _a, _b; }; /** @brief Infinite two-dimensional line */ diff --git a/src/Physics/LineSegment.h b/src/Shapes/LineSegment.h similarity index 68% rename from src/Physics/LineSegment.h rename to src/Shapes/LineSegment.h index 666764734..a79bc0d4d 100644 --- a/src/Physics/LineSegment.h +++ b/src/Shapes/LineSegment.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_LineSegment_h -#define Magnum_Physics_LineSegment_h +#ifndef Magnum_Shapes_LineSegment_h +#define Magnum_Shapes_LineSegment_h /* This file is part of Magnum. @@ -25,16 +25,17 @@ */ /** @file - * @brief Class Magnum::Physics::LineSegment, typedef Magnum::Physics::LineSegment2D, Magnum::Physics::LineSegment3D + * @brief Class Magnum::Shapes::LineSegment, typedef Magnum::Shapes::LineSegment2D, Magnum::Shapes::LineSegment3D */ #include "Line.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief %Line segment, defined by starting and ending point +See @ref shapes for brief introduction. @see LineSegment2D, LineSegment3D */ template class LineSegment: public Line { @@ -44,14 +45,18 @@ template class LineSegment: public Line { * * Creates line segment with both points at origin. */ - inline explicit LineSegment() {} + constexpr /*implicit*/ LineSegment() {} /** @brief Constructor */ - inline explicit LineSegment(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b): Line(a, b) {} + constexpr /*implicit*/ LineSegment(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b): Line(a, b) {} - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::LineSegment; + /** @brief Transformed shape */ + LineSegment transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Line::transformed(matrix); } + + private: + constexpr LineSegment(const Line& line): Line(line) {} }; /** @brief Two-dimensional line segment */ diff --git a/src/Physics/Plane.cpp b/src/Shapes/Plane.cpp similarity index 65% rename from src/Physics/Plane.cpp rename to src/Shapes/Plane.cpp index 047e22773..e62d5a15f 100644 --- a/src/Physics/Plane.cpp +++ b/src/Shapes/Plane.cpp @@ -28,33 +28,24 @@ #include "Math/Matrix4.h" #include "Math/Geometry/Intersection.h" -#include "LineSegment.h" +#include "Shapes/LineSegment.h" using namespace Magnum::Math::Geometry; -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { -void Plane::applyTransformationMatrix(const Matrix4& matrix) { - _transformedPosition = matrix.transformPoint(_position); - _transformedNormal = matrix.rotation()*_normal; -} - -bool Plane::collides(const AbstractShape<3>* other) const { - if(other->type() == Type::Line) - return *this % *static_cast(other); - if(other->type() == Type::LineSegment) - return *this % *static_cast(other); - - return AbstractShape<3>::collides(other); +Plane Plane::transformed(const Matrix4& matrix) const { + return Plane(matrix.transformPoint(_position), + matrix.rotation()*_normal); } bool Plane::operator%(const Line3D& other) const { - Float t = Intersection::planeLine(transformedPosition(), transformedNormal(), other.transformedA(), other.transformedB()-other.transformedA()); + Float t = Intersection::planeLine(_position, _normal, other.a(), other.b()-other.a()); return t != t || (t != std::numeric_limits::infinity() && t != -std::numeric_limits::infinity()); } bool Plane::operator%(const LineSegment3D& other) const { - Float t = Intersection::planeLine(transformedPosition(), transformedNormal(), other.transformedA(), other.transformedB()-other.transformedA()); + Float t = Intersection::planeLine(_position, _normal, other.a(), other.b()-other.a()); return t > 0.0f && t < 1.0f; } diff --git a/src/Physics/Plane.h b/src/Shapes/Plane.h similarity index 56% rename from src/Physics/Plane.h rename to src/Shapes/Plane.h index fbb576eb6..c3f3471d8 100644 --- a/src/Physics/Plane.h +++ b/src/Shapes/Plane.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Plane_h -#define Magnum_Physics_Plane_h +#ifndef Magnum_Shapes_Plane_h +#define Magnum_Shapes_Plane_h /* This file is part of Magnum. @@ -25,66 +25,56 @@ */ /** @file - * @brief Class Magnum::Physics::Plane + * @brief Class Magnum::Shapes::Plane */ #include "Math/Vector3.h" -#include "AbstractShape.h" -#include "Physics.h" +#include "Magnum.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" +namespace Magnum { namespace Shapes { -namespace Magnum { namespace Physics { +/** +@brief Infinite plane, defined by position and normal (3D only) -/** @brief Infinite plane, defined by position and normal (3D only) */ -class MAGNUM_PHYSICS_EXPORT Plane: public AbstractShape<3> { +See @ref shapes for brief introduction. +*/ +class MAGNUM_SHAPES_EXPORT Plane { public: + enum: UnsignedInt { + Dimensions = 3 /**< Dimension count */ + }; + /** * @brief Default constructor * * Creates plane with zero-sized normal at origin. */ - inline explicit Plane() {} + constexpr /*implicit*/ Plane() {} /** @brief Constructor */ - inline explicit Plane(const Vector3& position, const Vector3& normal): _position(position), _transformedPosition(position), _normal(normal), _transformedNormal(normal) {} + constexpr /*implicit*/ Plane(const Vector3& position, const Vector3& normal): _position(position), _normal(normal) {} - inline Type type() const override { return Type::Plane; } - - #ifndef DOXYGEN_GENERATING_OUTPUT - void applyTransformationMatrix(const Matrix4& matrix) override; - bool collides(const AbstractShape<3>* other) const override; - #else - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; - bool collides(const AbstractShape* other) const override; - #endif + /** @brief Transformed shape */ + Plane transformed(const Matrix4& matrix) const; /** @brief Position */ - inline Vector3 position() const { return _position; } + constexpr Vector3 position() const { return _position; } /** @brief Set position */ - inline void setPosition(const Vector3& position) { + void setPosition(const Vector3& position) { _position = position; } /** @brief Normal */ - inline Vector3 normal() const { return _normal; } + constexpr Vector3 normal() const { return _normal; } /** @brief Set normal */ - inline void setNormal(const Vector3& normal) { + void setNormal(const Vector3& normal) { _normal = normal; } - /** @brief Transformed position */ - inline Vector3 transformedPosition() const { - return _transformedPosition; - } - - /** @brief Transformed normal */ - inline Vector3 transformedNormal() const { - return _transformedNormal; - } - /** @brief Collision with line */ bool operator%(const Line3D& other) const; @@ -92,8 +82,7 @@ class MAGNUM_PHYSICS_EXPORT Plane: public AbstractShape<3> { bool operator%(const LineSegment3D& other) const; private: - Vector3 _position, _transformedPosition, - _normal, _transformedNormal; + Vector3 _position, _normal; }; /** @collisionoperator{Line,Plane} */ diff --git a/src/Physics/Point.cpp b/src/Shapes/Point.cpp similarity index 83% rename from src/Physics/Point.cpp rename to src/Shapes/Point.cpp index fb52d3b7e..5631e1137 100644 --- a/src/Physics/Point.cpp +++ b/src/Shapes/Point.cpp @@ -27,10 +27,10 @@ #include "Math/Matrix3.h" #include "Math/Matrix4.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { -template void Point::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedPosition = matrix.transformPoint(_position); +template Point Point::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Point(matrix.transformPoint(_position)); } template class Point<2>; diff --git a/src/Physics/Point.h b/src/Shapes/Point.h similarity index 60% rename from src/Physics/Point.h rename to src/Shapes/Point.h index 606ad0b51..a03a2c676 100644 --- a/src/Physics/Point.h +++ b/src/Shapes/Point.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Point_h -#define Magnum_Physics_Point_h +#ifndef Magnum_Shapes_Point_h +#define Magnum_Shapes_Point_h /* This file is part of Magnum. @@ -25,56 +25,52 @@ */ /** @file - * @brief Class Magnum::Physics::Point, typedef Magnum::Physics::Point2D, Magnum::Physics::Point3D + * @brief Class Magnum::Shapes::Point, typedef Magnum::Shapes::Point2D, Magnum::Shapes::Point3D */ #include "Math/Vector3.h" -#include "AbstractShape.h" +#include "DimensionTraits.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief %Point +See @ref shapes for brief introduction. @see Point2D, Point3D */ -template class MAGNUM_PHYSICS_EXPORT Point: public AbstractShape { +template class MAGNUM_SHAPES_EXPORT Point { public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + /** * @brief Default constructor * * Creates point at origin. */ - inline explicit Point() {} + constexpr /*implicit*/ Point() {} /** @brief Constructor */ - inline explicit Point(const typename DimensionTraits::VectorType& position): _position(position), _transformedPosition(position) {} - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::Point; - } + constexpr /*implicit*/ Point(const typename DimensionTraits::VectorType& position): _position(position) {} - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; + /** @brief Transformed shape */ + Point transformed(const typename DimensionTraits::MatrixType& matrix) const; /** @brief Position */ - inline typename DimensionTraits::VectorType position() const { + constexpr typename DimensionTraits::VectorType position() const { return _position; } /** @brief Set position */ - inline void setPosition(const typename DimensionTraits::VectorType& position) { + void setPosition(const typename DimensionTraits::VectorType& position) { _position = position; } - /** @brief Transformed position */ - inline typename DimensionTraits::VectorType transformedPosition() const { - return _transformedPosition; - } - private: - typename DimensionTraits::VectorType _position, _transformedPosition; + typename DimensionTraits::VectorType _position; }; /** @brief Two-dimensional point */ diff --git a/src/Shapes/Shape.cpp b/src/Shapes/Shape.cpp new file mode 100644 index 000000000..ed8d477a2 --- /dev/null +++ b/src/Shapes/Shape.cpp @@ -0,0 +1,48 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Shape.h" + +#include "Shapes/Composition.h" + +namespace Magnum { namespace Shapes { namespace Implementation { + +template void ShapeHelper>::set(Shapes::Shape>& shape, const Composition& composition) { + shape._transformedShape.shape = shape._shape.shape = composition; +} + +template void ShapeHelper>::set(Shapes::Shape>& shape, Composition&& composition) { + shape._transformedShape.shape = shape._shape.shape = std::move(composition); +} + +template void ShapeHelper>::transform(Shapes::Shape>& shape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + CORRADE_INTERNAL_ASSERT(shape._shape.shape.size() == shape._transformedShape.shape.size()); + for(std::size_t i = 0; i != shape.shape().size(); ++i) + shape._shape.shape._shapes[i]->transform(absoluteTransformationMatrix, shape._transformedShape.shape._shapes[i]); +} + +template struct MAGNUM_SHAPES_EXPORT ShapeHelper>; +template struct MAGNUM_SHAPES_EXPORT ShapeHelper>; + +}}} diff --git a/src/Shapes/Shape.h b/src/Shapes/Shape.h new file mode 100644 index 000000000..37f478d05 --- /dev/null +++ b/src/Shapes/Shape.h @@ -0,0 +1,156 @@ +#ifndef Magnum_Shapes_Shape_h +#define Magnum_Shapes_Shape_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Shapes::Shape + */ + +#include "Shapes/AbstractShape.h" +#include "Shapes/Shapes.h" + +#include "magnumShapesVisibility.h" + +namespace Magnum { namespace Shapes { + +namespace Implementation { + template struct ShapeHelper; +} + +/** +@brief Object shape + +Adds shape for collision detection to object. Each %Shape is part of +some ShapeGroup, which essentially maintains a set of objects which can +collide with each other. See @ref shapes for brief introduction. + +The shape contains original shape with relative transformation under shape() +and also caches a shape with absolute transformation under transformedShape(), +which can be used for collision detection. To conveniently use collision +detection among many object, you need to add the shape to ShapeGroup, which +then provides collision detection for given group of shapes. You can also use +ShapeGroup::add() and ShapeGroup::remove() later to manage e.g. collision +islands. +@code +Shapes::ShapeGroup3D shapes; + +Object3D* object; +auto shape = new Shapes::Shape(object, {{}, 0.75f}, &shapes); + +Shapes::AbstractShape3D* firstCollision = shapes.firstCollision(shape); +@endcode + +@see @ref scenegraph, ShapeGroup2D, ShapeGroup3D, + DebugTools::ShapeRenderer +*/ +template class MAGNUM_SHAPES_EXPORT Shape: public AbstractShape { + friend struct Implementation::ShapeHelper; + + public: + /** + * @brief Constructor + * @param object Object holding this feature + * @param shape Shape + * @param group Group this shape belongs to + */ + template explicit Shape(SceneGraph::AbstractObject* object, const T& shape, ShapeGroup* group = nullptr): AbstractShape(object, group) { + Implementation::ShapeHelper::set(*this, shape); + } + + /** @overload */ + template explicit Shape(SceneGraph::AbstractObject* object, T&& shape, ShapeGroup* group = nullptr): AbstractShape(object, group) { + Implementation::ShapeHelper::set(*this, std::move(shape)); + } + + /** @overload */ + template explicit Shape(SceneGraph::AbstractObject* object, ShapeGroup* group = nullptr): AbstractShape(object, group) {} + + /** @brief Shape */ + const T& shape() const { return _shape.shape; } + + /** + * @brief Set shape + * @return Pointer to self (for method chaining) + * + * Marks the feature as dirty. + */ + Shape* setShape(const T& shape); + + /** + * @brief Transformed shape + * + * Cleans the feature before returning the shape. + */ + const T& transformedShape(); + + protected: + /** Applies transformation to associated shape. */ + void clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) override; + + private: + const Implementation::AbstractShape* abstractTransformedShape() const override { + return &_transformedShape; + } + + Implementation::Shape _shape, _transformedShape; +}; + +template inline Shape* Shape::setShape(const T& shape) { + Implementation::ShapeHelper::set(*this, shape); + this->object()->setDirty(); + return this; +} + +template inline const T& Shape::transformedShape() { + this->object()->setClean(); + return _transformedShape.shape; +} + +template void Shape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + Implementation::ShapeHelper::transform(*this, absoluteTransformationMatrix); +} + +namespace Implementation { + template struct ShapeHelper { + static void set(Shapes::Shape& shape, const T& s) { + shape._shape.shape = s; + } + + static void transform(Shapes::Shape& shape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { + shape._transformedShape.shape = shape._shape.shape.transformed(absoluteTransformationMatrix); + } + }; + + template struct MAGNUM_SHAPES_EXPORT ShapeHelper> { + static void set(Shapes::Shape>& shape, const Composition& composition); + static void set(Shapes::Shape>& shape, Composition&& composition); + + static void transform(Shapes::Shape>& shape, const typename DimensionTraits::MatrixType& absoluteTransformationMatrix); + }; +} + +}} + +#endif diff --git a/src/Physics/ObjectShapeGroup.cpp b/src/Shapes/ShapeGroup.cpp similarity index 70% rename from src/Physics/ObjectShapeGroup.cpp rename to src/Shapes/ShapeGroup.cpp index 994f71a02..d99b9d598 100644 --- a/src/Physics/ObjectShapeGroup.cpp +++ b/src/Shapes/ShapeGroup.cpp @@ -22,41 +22,37 @@ DEALINGS IN THE SOFTWARE. */ -#include "ObjectShapeGroup.h" +#include "ShapeGroup.h" -#include "Physics/AbstractShape.h" -#include "Physics/ObjectShape.h" +#include "Shapes/AbstractShape.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { -template void ObjectShapeGroup::setClean() { +template void ShapeGroup::setClean() { /* Clean all objects */ if(!this->isEmpty()) { std::vector*> objects(this->size()); for(std::size_t i = 0; i != this->size(); ++i) objects[i] = (*this)[i]->object(); - objects[0]->setClean(objects); + SceneGraph::AbstractObject::setClean(objects); } dirty = false; } -template ObjectShape* ObjectShapeGroup::firstCollision(const ObjectShape* shape) { - /* Nothing to test with, done */ - if(!shape->shape()) return nullptr; - +template AbstractShape* ShapeGroup::firstCollision(const AbstractShape* shape) { setClean(); for(std::size_t i = 0; i != this->size(); ++i) - if((*this)[i] != shape && (*this)[i]->shape() && (*this)[i]->shape()->collides(shape->shape())) + if((*this)[i] != shape && (*this)[i]->collides(shape)) return (*this)[i]; return nullptr; } #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup<2>; -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup<3>; +template class MAGNUM_SHAPES_EXPORT ShapeGroup<2>; +template class MAGNUM_SHAPES_EXPORT ShapeGroup<3>; #endif }} diff --git a/src/Physics/ObjectShapeGroup.h b/src/Shapes/ShapeGroup.h similarity index 69% rename from src/Physics/ObjectShapeGroup.h rename to src/Shapes/ShapeGroup.h index 9d674b0be..b3564f372 100644 --- a/src/Physics/ObjectShapeGroup.h +++ b/src/Shapes/ShapeGroup.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_ObjectShapeGroup_h -#define Magnum_Physics_ObjectShapeGroup_h +#ifndef Magnum_Shapes_ShapeGroup_h +#define Magnum_Shapes_ShapeGroup_h /* This file is part of Magnum. @@ -25,26 +25,26 @@ */ /** @file - * @brief Class Magnum::Physics::ObjectShapeGroup, typedef Magnum::Physics::ObjectShapeGroup2D, Magnum::Physics::ObjectShapeGroup3D + * @brief Class Magnum::Shapes::ShapeGroup, typedef Magnum::Shapes::ShapeGroup2D, Magnum::Shapes::ShapeGroup3D */ #include -#include "Physics/ObjectShape.h" +#include "Shapes/AbstractShape.h" #include "SceneGraph/FeatureGroup.h" -#include "magnumPhysicsVisibility.h" +#include "magnumShapesVisibility.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** -@brief Group of object shapes +@brief Group of shapes -See ObjectShape for more information. -@see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D +See Shape for more information. See @ref shapes for brief introduction. +@see @ref scenegraph, ShapeGroup2D, ShapeGroup3D */ -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup> { - friend class ObjectShape; +template class MAGNUM_SHAPES_EXPORT ShapeGroup: public SceneGraph::FeatureGroup> { + friend class AbstractShape; public: /** @@ -52,13 +52,13 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: p * * Marks the group as dirty. */ - inline explicit ObjectShapeGroup(): dirty(true) {} + explicit ShapeGroup(): dirty(true) {} /** * @brief Whether the group is dirty * @return True if any object in the group is dirty, false otherwise. */ - inline bool isDirty() const { return dirty; } + bool isDirty() const { return dirty; } /** * @brief Set the group as dirty @@ -69,7 +69,7 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: p * * @see setClean() */ - inline void setDirty() { dirty = true; } + void setDirty() { dirty = true; } /** * @brief Set the group and all bodies as clean @@ -86,7 +86,7 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: p * collisions, returns `nullptr`. Calls setClean() before the * operation. */ - ObjectShape* firstCollision(const ObjectShape* shape); + AbstractShape* firstCollision(const AbstractShape* shape); private: bool dirty; @@ -95,18 +95,18 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: p /** @brief Group of two-dimensional shaped objects -See ObjectShape for more information. -@see ObjectShapeGroup3D +See Shape for more information. +@see ShapeGroup3D */ -typedef ObjectShapeGroup<2> ObjectShapeGroup2D; +typedef ShapeGroup<2> ShapeGroup2D; /** @brief Group of three-dimensional shaped objects -See ObjectShape for more information. -@see ObjectShapeGroup2D +See Shape for more information. +@see ShapeGroup2D */ -typedef ObjectShapeGroup<3> ObjectShapeGroup3D; +typedef ShapeGroup<3> ShapeGroup3D; }} diff --git a/src/Physics/Physics.h b/src/Shapes/Shapes.h similarity index 84% rename from src/Physics/Physics.h rename to src/Shapes/Shapes.h index d0a297bc5..dfc0d0fd7 100644 --- a/src/Physics/Physics.h +++ b/src/Shapes/Shapes.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Physics_h -#define Magnum_Physics_Physics_h +#ifndef Magnum_Shapes_Shapes_h +#define Magnum_Shapes_Shapes_h /* This file is part of Magnum. @@ -25,12 +25,12 @@ */ /** @file - * @brief Forward declarations for Magnum::Physics namespace + * @brief Forward declarations for Magnum::Shapes namespace */ #include "Types.h" -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @todoc remove when doxygen is sane again */ #ifndef DOXYGEN_GENERATING_OUTPUT @@ -50,6 +50,10 @@ template class Capsule; typedef Capsule<2> Capsule2D; typedef Capsule<3> Capsule3D; +template class Composition; +typedef Composition<2> Composition2D; +typedef Composition<3> Composition3D; + template class Line; typedef Line<2> Line2D; typedef Line<3> Line3D; @@ -58,19 +62,7 @@ template class LineSegment; typedef LineSegment<2> LineSegment2D; typedef LineSegment<3> LineSegment3D; -template class ObjectShape; -typedef ObjectShape<2> ObjectShape2D; -typedef ObjectShape<3> ObjectShape3D; - -template class ObjectShapeGroup; -typedef ObjectShapeGroup<2> ObjectShapeGroup2D; -typedef ObjectShapeGroup<3> ObjectShapeGroup3D; - -class Plane; - -template class Point; -typedef Point<2> Point2D; -typedef Point<3> Point3D; +template class Shape; template class ShapeGroup; typedef ShapeGroup<2> ShapeGroup2D; @@ -81,6 +73,12 @@ typedef Sphere<2> Sphere2D; typedef Sphere<3> Sphere3D; #endif +class Plane; + +template class Point; +typedef Point<2> Point2D; +typedef Point<3> Point3D; + }} #endif diff --git a/src/Physics/Sphere.cpp b/src/Shapes/Sphere.cpp similarity index 55% rename from src/Physics/Sphere.cpp rename to src/Shapes/Sphere.cpp index 4eebd8c49..154641c09 100644 --- a/src/Physics/Sphere.cpp +++ b/src/Shapes/Sphere.cpp @@ -28,12 +28,13 @@ #include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Math/Geometry/Distance.h" -#include "LineSegment.h" -#include "Point.h" +#include "Magnum.h" +#include "Shapes/LineSegment.h" +#include "Shapes/Point.h" using namespace Magnum::Math::Geometry; -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { namespace { template static typename DimensionTraits::VectorType unitVector(); @@ -47,48 +48,30 @@ namespace { } } -template void Sphere::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedPosition = matrix.transformPoint(_position); - Float scaling = (matrix.rotationScaling()*unitVector()).length(); - _transformedRadius = scaling*_radius; -} - -template bool Sphere::collides(const AbstractShape* other) const { - if(other->type() == AbstractShape::Type::Point) - return *this % *static_cast*>(other); - if(other->type() == AbstractShape::Type::Line) - return *this % *static_cast*>(other); - if(other->type() == AbstractShape::Type::LineSegment) - return *this % *static_cast*>(other); - if(other->type() == AbstractShape::Type::Sphere) - return *this % *static_cast*>(other); - - return AbstractShape::collides(other); +template Sphere Sphere::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Sphere(matrix.transformPoint(_position), + (matrix.rotationScaling()*unitVector()).length()*_radius); } template bool Sphere::operator%(const Point& other) const { - return (other.transformedPosition()-transformedPosition()).dot() < - Math::pow<2>(transformedRadius()); + return (other.position()-_position).dot() < Math::pow<2>(_radius); } template bool Sphere::operator%(const Line& other) const { - return Distance::linePointSquared(other.transformedA(), other.transformedB(), transformedPosition()) < - Math::pow<2>(transformedRadius()); + return Distance::linePointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); } template bool Sphere::operator%(const LineSegment& other) const { - return Distance::lineSegmentPointSquared(other.transformedA(), other.transformedB(), transformedPosition()) < - Math::pow<2>(transformedRadius()); + return Distance::lineSegmentPointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); } template bool Sphere::operator%(const Sphere& other) const { - return (other.transformedPosition()-transformedPosition()).dot() < - Math::pow<2>(transformedRadius()+other.transformedRadius()); + return (other._position-_position).dot() < Math::pow<2>(_radius+other._radius); } #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_PHYSICS_EXPORT Sphere<2>; -template class MAGNUM_PHYSICS_EXPORT Sphere<3>; +template class MAGNUM_SHAPES_EXPORT Sphere<2>; +template class MAGNUM_SHAPES_EXPORT Sphere<3>; #endif }} diff --git a/src/Physics/Sphere.h b/src/Shapes/Sphere.h similarity index 63% rename from src/Physics/Sphere.h rename to src/Shapes/Sphere.h index 6f83d2ddb..d9792109b 100644 --- a/src/Physics/Sphere.h +++ b/src/Shapes/Sphere.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_Sphere_h -#define Magnum_Physics_Sphere_h +#ifndef Magnum_Shapes_Sphere_h +#define Magnum_Shapes_Sphere_h /* This file is part of Magnum. @@ -25,70 +25,59 @@ */ /** @file - * @brief Class Magnum::Physics::Sphere, typedef Magnum::Physics::Sphere2D, Magnum::Physics::Sphere3D + * @brief Class Magnum::Shapes::Sphere, typedef Magnum::Shapes::Sphere2D, Magnum::Shapes::Sphere3D */ #include "Math/Vector3.h" -#include "AbstractShape.h" -#include "Physics.h" +#include "DimensionTraits.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { +namespace Magnum { namespace Shapes { /** @brief %Sphere defined by position and radius Unlike other elements the sphere doesn't support asymmetric scaling. When -applying transformation, the scale factor is averaged from all axes. +applying transformation, the scale factor is averaged from all axes. See +@ref shapes for brief introduction. @see Sphere2D, Sphere3D @todo Assert for asymmetric scaling */ -template class MAGNUM_PHYSICS_EXPORT Sphere: public AbstractShape { +template class MAGNUM_SHAPES_EXPORT Sphere { public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + /** * @brief Default constructor * * Creates zero-sized sphere at origin. */ - inline explicit Sphere(): _radius(0.0f), _transformedRadius(0.0f) {} + constexpr /*implicit*/ Sphere(): _radius(0.0f) {} /** @brief Constructor */ - inline explicit Sphere(const typename DimensionTraits::VectorType& position, Float radius): _position(position), _transformedPosition(position), _radius(radius), _transformedRadius(radius) {} - - inline typename AbstractShape::Type type() const override { - return AbstractShape::Type::Sphere; - } - - void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; + constexpr /*implicit*/ Sphere(const typename DimensionTraits::VectorType& position, Float radius): _position(position), _radius(radius) {} - bool collides(const AbstractShape* other) const override; + /** @brief Transformed shape */ + Sphere transformed(const typename DimensionTraits::MatrixType& matrix) const; /** @brief Position */ - inline typename DimensionTraits::VectorType position() const { + constexpr typename DimensionTraits::VectorType position() const { return _position; } /** @brief Set position */ - inline void setPosition(const typename DimensionTraits::VectorType& position) { + void setPosition(const typename DimensionTraits::VectorType& position) { _position = position; } /** @brief Radius */ - inline Float radius() const { return _radius; } + constexpr Float radius() const { return _radius; } /** @brief Set radius */ - inline void setRadius(Float radius) { _radius = radius; } - - /** @brief Transformed position */ - inline typename DimensionTraits::VectorType transformedPosition() const { - return _transformedPosition; - } - - /** @brief Transformed radius */ - inline Float transformedRadius() const { - return _transformedRadius; - } + void setRadius(Float radius) { _radius = radius; } /** @brief Collision with point */ bool operator%(const Point& other) const; @@ -103,9 +92,8 @@ template class MAGNUM_PHYSICS_EXPORT Sphere: public Abst bool operator%(const Sphere& other) const; private: - typename DimensionTraits::VectorType _position, - _transformedPosition; - Float _radius, _transformedRadius; + typename DimensionTraits::VectorType _position; + Float _radius; }; /** @brief Two-dimensional sphere */ diff --git a/src/Physics/Test/AxisAlignedBoxTest.cpp b/src/Shapes/Test/AxisAlignedBoxTest.cpp similarity index 60% rename from src/Physics/Test/AxisAlignedBoxTest.cpp rename to src/Shapes/Test/AxisAlignedBoxTest.cpp index cf45bf009..8f4a940c5 100644 --- a/src/Physics/Test/AxisAlignedBoxTest.cpp +++ b/src/Shapes/Test/AxisAlignedBoxTest.cpp @@ -22,45 +22,39 @@ DEALINGS IN THE SOFTWARE. */ -#include - #include "Math/Matrix4.h" -#include "Physics/AxisAlignedBox.h" -#include "Physics/Point.h" +#include "Magnum.h" +#include "Shapes/AxisAlignedBox.h" +#include "Shapes/Point.h" #include "ShapeTestBase.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class AxisAlignedBoxTest: public Corrade::TestSuite::Tester, ShapeTestBase { +class AxisAlignedBoxTest: public TestSuite::Tester { public: AxisAlignedBoxTest(); - void applyTransformation(); + void transformed(); void collisionPoint(); }; AxisAlignedBoxTest::AxisAlignedBoxTest() { - addTests({&AxisAlignedBoxTest::applyTransformation, + addTests({&AxisAlignedBoxTest::transformed, &AxisAlignedBoxTest::collisionPoint}); } -void AxisAlignedBoxTest::applyTransformation() { - Physics::AxisAlignedBox3D box({-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}); - - box.applyTransformationMatrix(Matrix4::translation(Vector3(1.0f))*Matrix4::scaling({2.0f, -1.0f, 1.5f})); - CORRADE_COMPARE(box.transformedMin(), Vector3(-1.0f, 3.0f, -3.5f)); - CORRADE_COMPARE(box.transformedMax(), Vector3(3.0f, -1.0f, 5.5f)); +void AxisAlignedBoxTest::transformed() { + const auto box = Shapes::AxisAlignedBox3D({-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}) + .transformed(Matrix4::translation(Vector3(1.0f))*Matrix4::scaling({2.0f, -1.0f, 1.5f})); + CORRADE_COMPARE(box.min(), Vector3(-1.0f, 3.0f, -3.5f)); + CORRADE_COMPARE(box.max(), Vector3(3.0f, -1.0f, 5.5f)); } void AxisAlignedBoxTest::collisionPoint() { - Physics::AxisAlignedBox3D box({-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}); - Physics::Point3D point1({-1.5f, -1.0f, 2.0f}); - Physics::Point3D point2({0.5f, 1.0f, -2.5f}); - - randomTransformation(box); - randomTransformation(point1); - randomTransformation(point2); + Shapes::AxisAlignedBox3D box({-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}); + Shapes::Point3D point1({-1.5f, -1.0f, 2.0f}); + Shapes::Point3D point2({0.5f, 1.0f, -2.5f}); VERIFY_NOT_COLLIDES(box, point1); VERIFY_COLLIDES(box, point2); @@ -68,4 +62,4 @@ void AxisAlignedBoxTest::collisionPoint() { }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::AxisAlignedBoxTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::AxisAlignedBoxTest) diff --git a/src/Physics/Test/BoxTest.cpp b/src/Shapes/Test/BoxTest.cpp similarity index 69% rename from src/Physics/Test/BoxTest.cpp rename to src/Shapes/Test/BoxTest.cpp index 33bc2781b..1be8e1c71 100644 --- a/src/Physics/Test/BoxTest.cpp +++ b/src/Shapes/Test/BoxTest.cpp @@ -25,28 +25,28 @@ #include #include "Math/Matrix4.h" -#include "Physics/Box.h" +#include "Magnum.h" +#include "Shapes/Box.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class BoxTest: public Corrade::TestSuite::Tester { +class BoxTest: public TestSuite::Tester { public: BoxTest(); - void applyTransformation(); + void transformed(); }; BoxTest::BoxTest() { - addTests({&BoxTest::applyTransformation}); + addTests({&BoxTest::transformed}); } -void BoxTest::applyTransformation() { - Physics::Box3D box(Matrix4::translation({1.0f, 2.0f, -3.0f})); - - box.applyTransformationMatrix(Matrix4::scaling({2.0f, -1.0f, 1.5f})); - CORRADE_COMPARE(box.transformedTransformation(), Matrix4::scaling({2.0f, -1.0f, 1.5f})*Matrix4::translation({1.0f, 2.0f, -3.0f})); +void BoxTest::transformed() { + const auto box = Shapes::Box3D(Matrix4::translation({1.0f, 2.0f, -3.0f})) + .transformed(Matrix4::scaling({2.0f, -1.0f, 1.5f})); + CORRADE_COMPARE(box.transformation(), Matrix4::scaling({2.0f, -1.0f, 1.5f})*Matrix4::translation({1.0f, 2.0f, -3.0f})); } }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::BoxTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::BoxTest) diff --git a/src/Physics/Test/CMakeLists.txt b/src/Shapes/Test/CMakeLists.txt similarity index 60% rename from src/Physics/Test/CMakeLists.txt rename to src/Shapes/Test/CMakeLists.txt index 2467787cc..2615b6d99 100644 --- a/src/Physics/Test/CMakeLists.txt +++ b/src/Shapes/Test/CMakeLists.txt @@ -22,14 +22,14 @@ # DEALINGS IN THE SOFTWARE. # -corrade_add_test(PhysicsAbstractShapeTest AbstractShapeTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsAxisAlignedBoxTest AxisAlignedBoxTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsBoxTest BoxTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsLineTest LineTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsPlaneTest PlaneTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsPointTest PointTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsShapeGroupTest ShapeGroupTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test(PhysicsSphereTest SphereTest.cpp LIBRARIES MagnumPhysics) +corrade_add_test(ShapesShapeImplementationTest ShapeImplementationTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesAxisAlignedBoxTest AxisAlignedBoxTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesBoxTest BoxTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesLineTest LineTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesPlaneTest PlaneTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesPointTest PointTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesCompositionTest CompositionTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesSphereTest SphereTest.cpp LIBRARIES MagnumShapes) -corrade_add_test(PhysicsObjectShapeTest ObjectShapeTest.cpp LIBRARIES MagnumPhysics) +corrade_add_test(ShapesShapeTest ShapeTest.cpp LIBRARIES MagnumShapes) diff --git a/src/Physics/Test/CapsuleTest.cpp b/src/Shapes/Test/CapsuleTest.cpp similarity index 51% rename from src/Physics/Test/CapsuleTest.cpp rename to src/Shapes/Test/CapsuleTest.cpp index 9c829f7e8..b4fd8a048 100644 --- a/src/Physics/Test/CapsuleTest.cpp +++ b/src/Shapes/Test/CapsuleTest.cpp @@ -22,52 +22,50 @@ DEALINGS IN THE SOFTWARE. */ -#include "Physics/Capsule.h" -#include "Physics/Point.h" -#include "Physics/Sphere.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "Shapes/Capsule.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" #include "ShapeTestBase.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class CapsuleTest: public Corrade::TestSuite::Tester, ShapeTestBase { +class CapsuleTest: public TestSuite::Tester { public: CapsuleTest(); - void applyTransformation(); + void transformed(); + void transformedAverageScaling(); void collisionPoint(); void collisionSphere(); }; CapsuleTest::CapsuleTest() { - addTests({&CapsuleTest::applyTransformation, + addTests({&CapsuleTest::transformed, &CapsuleTest::collisionPoint, &CapsuleTest::collisionSphere}); } -void CapsuleTest::applyTransformation() { - Physics::Capsule3D capsule({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}, 7.0f); +void CapsuleTest::transformed() { + const Shapes::Capsule3D capsule({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}, 7.0f); - capsule.applyTransformationMatrix(Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); - CORRADE_COMPARE(capsule.transformedA(), Vector3(-2.0f, 1.0f, 3.0f)); - CORRADE_COMPARE(capsule.transformedB(), Vector3(2.0f, -1.0f, -3.0f)); - CORRADE_COMPARE(capsule.transformedRadius(), 7.0f); + const auto transformed = capsule.transformed(Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); + CORRADE_COMPARE(transformed.a(), Vector3(-2.0f, 1.0f, 3.0f)); + CORRADE_COMPARE(transformed.b(), Vector3(2.0f, -1.0f, -3.0f)); + CORRADE_COMPARE(transformed.radius(), 7.0f); /* Apply average scaling to radius */ - capsule.applyTransformationMatrix(Matrix4::scaling({Constants::sqrt3(), -Constants::sqrt2(), 2.0f})); - CORRADE_COMPARE(capsule.transformedRadius(), Constants::sqrt3()*7.0f); + const auto scaled = capsule.transformed(Matrix4::scaling({Constants::sqrt3(), -Constants::sqrt2(), 2.0f})); + CORRADE_COMPARE(scaled.radius(), Constants::sqrt3()*7.0f); } void CapsuleTest::collisionPoint() { - Physics::Capsule3D capsule({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); - Physics::Point3D point({2.0f, 0.0f, 0.0f}); - Physics::Point3D point1({2.9f, 1.0f, 0.0f}); - Physics::Point3D point2({1.0f, 3.1f, 0.0f}); - - randomTransformation(capsule); - randomTransformation(point); - randomTransformation(point1); - randomTransformation(point2); + Shapes::Capsule3D capsule({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); + Shapes::Point3D point({2.0f, 0.0f, 0.0f}); + Shapes::Point3D point1({2.9f, 1.0f, 0.0f}); + Shapes::Point3D point2({1.0f, 3.1f, 0.0f}); VERIFY_COLLIDES(capsule, point); VERIFY_COLLIDES(capsule, point1); @@ -75,15 +73,10 @@ void CapsuleTest::collisionPoint() { } void CapsuleTest::collisionSphere() { - Physics::Capsule3D capsule({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); - Physics::Sphere3D sphere({3.0f, 0.0f, 0.0f}, 0.9f); - Physics::Sphere3D sphere1({3.5f, 1.0f, 0.0f}, 0.6f); - Physics::Sphere3D sphere2({1.0f, 4.1f, 0.0f}, 1.0f); - - randomTransformation(capsule); - randomTransformation(sphere); - randomTransformation(sphere1); - randomTransformation(sphere2); + Shapes::Capsule3D capsule({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); + Shapes::Sphere3D sphere({3.0f, 0.0f, 0.0f}, 0.9f); + Shapes::Sphere3D sphere1({3.5f, 1.0f, 0.0f}, 0.6f); + Shapes::Sphere3D sphere2({1.0f, 4.1f, 0.0f}, 1.0f); VERIFY_COLLIDES(capsule, sphere); VERIFY_COLLIDES(capsule, sphere1); @@ -92,4 +85,4 @@ void CapsuleTest::collisionSphere() { }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::CapsuleTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::CapsuleTest) diff --git a/src/Shapes/Test/CompositionTest.cpp b/src/Shapes/Test/CompositionTest.cpp new file mode 100644 index 000000000..e07e34a9d --- /dev/null +++ b/src/Shapes/Test/CompositionTest.cpp @@ -0,0 +1,130 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include "Math/Matrix4.h" +#include "Shapes/Point.h" +#include "Shapes/AxisAlignedBox.h" +#include "Shapes/Composition.h" +#include "Shapes/Sphere.h" + +#include "ShapeTestBase.h" + +namespace Magnum { namespace Shapes { namespace Test { + +class CompositionTest: public TestSuite::Tester { + public: + CompositionTest(); + + void negated(); + void anded(); + void ored(); + void multipleUnary(); + void hierarchy(); + void empty(); +}; + +CompositionTest::CompositionTest() { + addTests({&CompositionTest::negated, + &CompositionTest::anded, + &CompositionTest::ored, + &CompositionTest::multipleUnary, + &CompositionTest::hierarchy, + &CompositionTest::empty}); +} + +void CompositionTest::negated() { + const Shapes::Composition2D a = !Shapes::Point2D(Vector2::xAxis(0.5f)); + + CORRADE_COMPARE(a.size(), 1); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Point); + CORRADE_COMPARE(a.get(0).position(), Vector2::xAxis(0.5f)); + + VERIFY_NOT_COLLIDES(a, Shapes::Sphere2D({}, 1.0f)); +} + +void CompositionTest::anded() { + const Shapes::Composition2D a = Shapes::Sphere2D({}, 1.0f) && Shapes::Point2D(Vector2::xAxis(0.5f)); + + CORRADE_COMPARE(a.size(), 2); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Sphere); + CORRADE_COMPARE(a.type(1), Composition2D::Type::Point); + CORRADE_COMPARE(a.get(0).position(), Vector2()); + CORRADE_COMPARE(a.get(0).radius(), 1.0f); + CORRADE_COMPARE(a.get(1).position(), Vector2::xAxis(0.5f)); + + VERIFY_NOT_COLLIDES(a, Shapes::Point2D()); + VERIFY_COLLIDES(a, Shapes::Sphere2D(Vector2::xAxis(0.5f), 0.25f)); +} + +void CompositionTest::ored() { + const Shapes::Composition2D a = Shapes::Sphere2D({}, 1.0f) || Shapes::Point2D(Vector2::xAxis(1.5f)); + + CORRADE_COMPARE(a.size(), 2); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Sphere); + CORRADE_COMPARE(a.type(1), Composition2D::Type::Point); + CORRADE_COMPARE(a.get(0).position(), Vector2()); + CORRADE_COMPARE(a.get(0).radius(), 1.0f); + CORRADE_COMPARE(a.get(1).position(), Vector2::xAxis(1.5f)); + + VERIFY_COLLIDES(a, Shapes::Point2D()); + VERIFY_COLLIDES(a, Shapes::Sphere2D(Vector2::xAxis(1.5f), 0.25f)); +} + +void CompositionTest::multipleUnary() { + const Shapes::Composition2D a = !!!!Shapes::Point2D(Vector2::xAxis(0.5f)); + + CORRADE_COMPARE(a.size(), 1); + CORRADE_COMPARE(a.type(0), Composition2D::Type::Point); + CORRADE_COMPARE(a.get(0).position(), Vector2::xAxis(0.5f)); + + VERIFY_COLLIDES(a, Shapes::Sphere2D({}, 1.0f)); +} + +void CompositionTest::hierarchy() { + const Shapes::Composition3D a = Shapes::Sphere3D({}, 1.0f) && + (Shapes::Point3D(Vector3::xAxis(1.5f)) || !Shapes::AxisAlignedBox3D({}, Vector3(0.5f))); + + CORRADE_COMPARE(a.size(), 3); + CORRADE_COMPARE(a.type(0), Composition3D::Type::Sphere); + CORRADE_COMPARE(a.type(1), Composition3D::Type::Point); + CORRADE_COMPARE(a.type(2), Composition3D::Type::AxisAlignedBox); + CORRADE_COMPARE(a.get(1).position(), Vector3::xAxis(1.5f)); + + VERIFY_COLLIDES(a, Shapes::Sphere3D(Vector3::xAxis(1.5f), 0.6f)); + VERIFY_NOT_COLLIDES(a, Shapes::Point3D(Vector3(0.25f))); +} + +void CompositionTest::empty() { + const Shapes::Composition2D a; + + CORRADE_COMPARE(a.size(), 0); + + VERIFY_NOT_COLLIDES(a, Shapes::Sphere2D({}, 1.0f)); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Shapes::Test::CompositionTest) diff --git a/src/Physics/Test/LineTest.cpp b/src/Shapes/Test/LineTest.cpp similarity index 68% rename from src/Physics/Test/LineTest.cpp rename to src/Shapes/Test/LineTest.cpp index 6f0f2cd9d..bb8ce701d 100644 --- a/src/Physics/Test/LineTest.cpp +++ b/src/Shapes/Test/LineTest.cpp @@ -25,28 +25,29 @@ #include #include "Math/Matrix4.h" -#include "Physics/Line.h" +#include "Magnum.h" +#include "Shapes/Line.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class LineTest: public Corrade::TestSuite::Tester { +class LineTest: public TestSuite::Tester { public: LineTest(); - void applyTransformation(); + void transformed(); }; LineTest::LineTest() { - addTests({&LineTest::applyTransformation}); + addTests({&LineTest::transformed}); } -void LineTest::applyTransformation() { - Physics::Line3D line({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}); - line.applyTransformationMatrix(Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); - CORRADE_COMPARE(line.transformedA(), Vector3(-2.0f, 1.0f, 3.0f)); - CORRADE_COMPARE(line.transformedB(), Vector3(2.0f, -1.0f, -3.0f)); +void LineTest::transformed() { + const auto line = Shapes::Line3D({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}) + .transformed(Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); + CORRADE_COMPARE(line.a(), Vector3(-2.0f, 1.0f, 3.0f)); + CORRADE_COMPARE(line.b(), Vector3(2.0f, -1.0f, -3.0f)); } }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::LineTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::LineTest) diff --git a/src/Physics/Test/PlaneTest.cpp b/src/Shapes/Test/PlaneTest.cpp similarity index 50% rename from src/Physics/Test/PlaneTest.cpp rename to src/Shapes/Test/PlaneTest.cpp index 028ccb770..c86a6386b 100644 --- a/src/Physics/Test/PlaneTest.cpp +++ b/src/Shapes/Test/PlaneTest.cpp @@ -22,52 +22,48 @@ DEALINGS IN THE SOFTWARE. */ -#include "Physics/LineSegment.h" -#include "Physics/Point.h" -#include "Physics/Plane.h" +#include "Math/Matrix4.h" +#include "Shapes/LineSegment.h" +#include "Shapes/Point.h" +#include "Shapes/Plane.h" #include "ShapeTestBase.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class PlaneTest: public Corrade::TestSuite::Tester, ShapeTestBase { +class PlaneTest: public TestSuite::Tester { public: PlaneTest(); - void applyTransformation(); + void transformed(); void collisionLine(); void collisionLineSegment(); }; PlaneTest::PlaneTest() { - addTests({&PlaneTest::applyTransformation, + addTests({&PlaneTest::transformed, &PlaneTest::collisionLine, &PlaneTest::collisionLineSegment}); } -void PlaneTest::applyTransformation() { - Physics::Plane plane({1.0f, 2.0f, 3.0f}, {Constants::sqrt2(), -Constants::sqrt2(), 0}); +void PlaneTest::transformed() { + const Shapes::Plane plane({1.0f, 2.0f, 3.0f}, {Constants::sqrt2(), -Constants::sqrt2(), 0}); - plane.applyTransformationMatrix(Matrix4::rotation(Deg(90.0f), Vector3::xAxis())); - CORRADE_COMPARE(plane.transformedPosition(), Vector3(1.0f, -3.0f, 2.0f)); - CORRADE_COMPARE(plane.transformedNormal(), Vector3(Constants::sqrt2(), 0, -Constants::sqrt2())); + const auto transformed = plane.transformed(Matrix4::rotation(Deg(90.0f), Vector3::xAxis())); + CORRADE_COMPARE(transformed.position(), Vector3(1.0f, -3.0f, 2.0f)); + CORRADE_COMPARE(transformed.normal(), Vector3(Constants::sqrt2(), 0, -Constants::sqrt2())); /* The normal should stay normalized */ - plane.applyTransformationMatrix(Matrix4::scaling({1.5f, 2.0f, 3.0f})); - CORRADE_COMPARE(plane.transformedPosition(), Vector3(1.5f, 4.0f, 9.0f)); - CORRADE_COMPARE(plane.transformedNormal(), Vector3(Constants::sqrt2(), -Constants::sqrt2(), 0)); + const auto scaled = plane.transformed(Matrix4::scaling({1.5f, 2.0f, 3.0f})); + CORRADE_COMPARE(scaled.position(), Vector3(1.5f, 4.0f, 9.0f)); + CORRADE_COMPARE(scaled.normal(), Vector3(Constants::sqrt2(), -Constants::sqrt2(), 0)); } void PlaneTest::collisionLine() { - Physics::Plane plane(Vector3(), Vector3::yAxis()); - Physics::Line3D line({0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}); - Physics::Line3D line2({0.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}); - Physics::Line3D line3({0.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}); - - randomTransformation(plane); - randomTransformation(line); - randomTransformation(line2); - randomTransformation(line3); + Shapes::Plane plane(Vector3(), Vector3::yAxis()); + Shapes::Line3D line({0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}); + Shapes::Line3D line2({0.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}); + Shapes::Line3D line3({0.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}); VERIFY_COLLIDES(plane, line); VERIFY_COLLIDES(plane, line2); @@ -75,15 +71,10 @@ void PlaneTest::collisionLine() { } void PlaneTest::collisionLineSegment() { - Physics::Plane plane(Vector3(), Vector3::yAxis()); - Physics::LineSegment3D line({0.0f, -0.1f, 0.0f}, {0.0f, 7.0f, 0.0f}); - Physics::LineSegment3D line2({0.0f, 0.1f, 0.0f}, {0.0f, 7.0f, 0.0f}); - Physics::LineSegment3D line3({0.0f, -7.0f, 0.0f}, {0.0f, -0.1f, 0.0f}); - - randomTransformation(plane); - randomTransformation(line); - randomTransformation(line2); - randomTransformation(line3); + Shapes::Plane plane(Vector3(), Vector3::yAxis()); + Shapes::LineSegment3D line({0.0f, -0.1f, 0.0f}, {0.0f, 7.0f, 0.0f}); + Shapes::LineSegment3D line2({0.0f, 0.1f, 0.0f}, {0.0f, 7.0f, 0.0f}); + Shapes::LineSegment3D line3({0.0f, -7.0f, 0.0f}, {0.0f, -0.1f, 0.0f}); VERIFY_COLLIDES(plane, line); VERIFY_NOT_COLLIDES(plane, line2); @@ -92,4 +83,4 @@ void PlaneTest::collisionLineSegment() { }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::PlaneTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::PlaneTest) diff --git a/src/Physics/Test/PointTest.cpp b/src/Shapes/Test/PointTest.cpp similarity index 72% rename from src/Physics/Test/PointTest.cpp rename to src/Shapes/Test/PointTest.cpp index f2e10188c..38d344edc 100644 --- a/src/Physics/Test/PointTest.cpp +++ b/src/Shapes/Test/PointTest.cpp @@ -25,27 +25,28 @@ #include #include "Math/Matrix4.h" -#include "Physics/Point.h" +#include "Magnum.h" +#include "Shapes/Point.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class PointTest: public Corrade::TestSuite::Tester { +class PointTest: public TestSuite::Tester { public: PointTest(); - void applyTransformation(); + void transformed(); }; PointTest::PointTest() { - addTests({&PointTest::applyTransformation}); + addTests({&PointTest::transformed}); } -void PointTest::applyTransformation() { - Physics::Point3D point({1.0f, 2.0f, 3.0f}); - point.applyTransformationMatrix(Matrix4::translation({5.0f, 6.0f, 7.0f})); - CORRADE_COMPARE(point.transformedPosition(), Vector3(6.0f, 8.0f, 10.0f)); +void PointTest::transformed() { + const auto point = Shapes::Point3D({1.0f, 2.0f, 3.0f}) + .transformed(Matrix4::translation({5.0f, 6.0f, 7.0f})); + CORRADE_COMPARE(point.position(), Vector3(6.0f, 8.0f, 10.0f)); } }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::PointTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::PointTest) diff --git a/src/Physics/Test/AbstractShapeTest.cpp b/src/Shapes/Test/ShapeImplementationTest.cpp similarity index 66% rename from src/Physics/Test/AbstractShapeTest.cpp rename to src/Shapes/Test/ShapeImplementationTest.cpp index 0b451e78d..eced1884a 100644 --- a/src/Physics/Test/AbstractShapeTest.cpp +++ b/src/Shapes/Test/ShapeImplementationTest.cpp @@ -25,31 +25,31 @@ #include #include -#include "Physics/AbstractShape.h" +#include "Shapes/shapeImplementation.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class AbstractShapeTest: public Corrade::TestSuite::Tester { +class ShapeImplementationTest: public TestSuite::Tester { public: - AbstractShapeTest(); + ShapeImplementationTest(); void debug(); }; -AbstractShapeTest::AbstractShapeTest() { - addTests({&AbstractShapeTest::debug}); +ShapeImplementationTest::ShapeImplementationTest() { + addTests({&ShapeImplementationTest::debug}); } -void AbstractShapeTest::debug() { +void ShapeImplementationTest::debug() { std::ostringstream o; - Debug(&o) << AbstractShape2D::Type::ShapeGroup; - CORRADE_COMPARE(o.str(), "AbstractShape2D::Type::ShapeGroup\n"); + Debug(&o) << Implementation::ShapeDimensionTraits<2>::Type::Composition; + CORRADE_COMPARE(o.str(), "Shapes::Shape2D::Type::Composition\n"); o.str({}); - Debug(&o) << AbstractShape3D::Type::Plane; - CORRADE_COMPARE(o.str(), "AbstractShape3D::Type::Plane\n"); + Debug(&o) << Implementation::ShapeDimensionTraits<3>::Type::Plane; + CORRADE_COMPARE(o.str(), "Shapes::Shape3D::Type::Plane\n"); } }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::AbstractShapeTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::ShapeImplementationTest) diff --git a/src/Physics/Test/ObjectShapeTest.cpp b/src/Shapes/Test/ShapeTest.cpp similarity index 52% rename from src/Physics/Test/ObjectShapeTest.cpp rename to src/Shapes/Test/ShapeTest.cpp index 056c680f1..3515a2739 100644 --- a/src/Physics/Test/ObjectShapeTest.cpp +++ b/src/Shapes/Test/ShapeTest.cpp @@ -24,107 +24,121 @@ #include -#include "Physics/ObjectShapeGroup.h" -#include "Physics/ObjectShape.h" -#include "Physics/Point.h" -#include "Physics/Sphere.h" +#include "Shapes/ShapeGroup.h" +#include "Shapes/Shape.h" +#include "Shapes/Point.h" +#include "Shapes/Composition.h" +#include "Shapes/Sphere.h" +#include "SceneGraph/MatrixTransformation2D.h" #include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/Scene.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class ObjectShapeTest: public Corrade::TestSuite::Tester { +class ShapeTest: public TestSuite::Tester { public: - ObjectShapeTest(); + ShapeTest(); void clean(); void firstCollision(); + void shapeGroup(); }; +typedef SceneGraph::Scene> Scene2D; +typedef SceneGraph::Object> Object2D; typedef SceneGraph::Scene> Scene3D; typedef SceneGraph::Object> Object3D; -ObjectShapeTest::ObjectShapeTest() { - addTests({&ObjectShapeTest::clean, - &ObjectShapeTest::firstCollision}); +ShapeTest::ShapeTest() { + addTests({&ShapeTest::clean, + &ShapeTest::firstCollision, + &ShapeTest::shapeGroup}); } -void ObjectShapeTest::clean() { +void ShapeTest::clean() { Scene3D scene; - ObjectShapeGroup3D group; + ShapeGroup3D shapes; Object3D a(&scene); - ObjectShape3D* shape = new ObjectShape3D(&a, &group); - shape->setShape(Physics::Point3D({1.0f, -2.0f, 3.0f})); + auto shape = new Shapes::Shape(&a, {{1.0f, -2.0f, 3.0f}}, &shapes); a.scale(Vector3(-2.0f)); Object3D b(&scene); - new ObjectShape3D(&b, &group); + new Shapes::Shape(&b, &shapes); /* Everything is dirty at the beginning */ - CORRADE_VERIFY(group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); CORRADE_VERIFY(a.isDirty()); CORRADE_VERIFY(b.isDirty()); /* Cleaning object will not clean anything other */ a.setClean(); - CORRADE_VERIFY(group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(b.isDirty()); /* Verify that the feature was actually cleaned */ - CORRADE_COMPARE(static_cast(shape->shape())->transformedPosition(), + CORRADE_COMPARE(shape->transformedShape().position(), Vector3(-2.0f, 4.0f, -6.0f)); /* Setting group clean will clean whole group */ a.setDirty(); - group.setClean(); - CORRADE_VERIFY(!group.isDirty()); + shapes.setClean(); + CORRADE_VERIFY(!shapes.isDirty()); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!b.isDirty()); /* Setting object dirty will set also the group, but not other objects */ b.setDirty(); - CORRADE_VERIFY(group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(b.isDirty()); } -void ObjectShapeTest::firstCollision() { +void ShapeTest::firstCollision() { Scene3D scene; - ObjectShapeGroup3D group; + ShapeGroup3D shapes; Object3D a(&scene); - ObjectShape3D* aShape = new ObjectShape3D(&a, &group); - aShape->setShape(Physics::Sphere3D({1.0f, -2.0f, 3.0f}, 1.5f)); + auto aShape = new Shape(&a, {{1.0f, -2.0f, 3.0f}, 1.5f}, &shapes); Object3D b(&scene); - ObjectShape3D* bShape = new ObjectShape3D(&b, &group); - bShape->setShape(Physics::Point3D({3.0f, -2.0f, 3.0f})); + auto bShape = new Shape(&b, {{3.0f, -2.0f, 3.0f}}, &shapes); Object3D c(&scene); - ObjectShape3D* cShape = new ObjectShape3D(&c, &group); - - /* No-op if the object has no shape */ - CORRADE_VERIFY(group.isDirty()); - CORRADE_VERIFY(!group.firstCollision(cShape)); - CORRADE_VERIFY(group.isDirty()); + new Shape(&c, &shapes); /* No collisions initially */ - CORRADE_VERIFY(!group.firstCollision(aShape)); - CORRADE_VERIFY(!group.firstCollision(bShape)); - CORRADE_VERIFY(!group.isDirty()); + CORRADE_VERIFY(!shapes.firstCollision(aShape)); + CORRADE_VERIFY(!shapes.firstCollision(bShape)); + CORRADE_VERIFY(!shapes.isDirty()); /* Move point into sphere */ b.translate(Vector3::xAxis(-1.0f)); /* Collision */ - CORRADE_VERIFY(group.isDirty()); - CORRADE_VERIFY(group.firstCollision(aShape) == bShape); - CORRADE_VERIFY(group.firstCollision(bShape) == aShape); - CORRADE_VERIFY(!group.isDirty()); + CORRADE_VERIFY(shapes.isDirty()); + CORRADE_VERIFY(shapes.firstCollision(aShape) == bShape); + CORRADE_VERIFY(shapes.firstCollision(bShape) == aShape); + CORRADE_VERIFY(!shapes.isDirty()); +} + +void ShapeTest::shapeGroup() { + Scene2D scene; + ShapeGroup2D shapes; + + /* Verify construction */ + Object2D a(&scene); + auto shape = new Shape(&a, Shapes::Sphere2D({}, 0.5f) || Shapes::Point2D({0.25f, -1.0f})); + CORRADE_COMPARE(shape->transformedShape().size(), 2); + + /* Verify the original shape is updated */ + const auto& point = shape->transformedShape().get(1); + a.translate(Vector2::xAxis(5.0f)); + a.setClean(); + CORRADE_COMPARE(point.position(), Vector2(5.25f, -1.0f)); } }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::ObjectShapeTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::ShapeTest) diff --git a/src/SceneGraph/DualQuaternionTransformation.cpp b/src/Shapes/Test/ShapeTestBase.h similarity index 69% rename from src/SceneGraph/DualQuaternionTransformation.cpp rename to src/Shapes/Test/ShapeTestBase.h index bedf48480..348cc3ee7 100644 --- a/src/SceneGraph/DualQuaternionTransformation.cpp +++ b/src/Shapes/Test/ShapeTestBase.h @@ -1,3 +1,5 @@ +#ifndef Magnum_Shapes_Test_ShapeTestBase_h +#define Magnum_Shapes_Test_ShapeTestBase_h /* This file is part of Magnum. @@ -22,14 +24,18 @@ DEALINGS IN THE SOFTWARE. */ -#include "DualQuaternionTransformation.h" +#include -#include "Object.hpp" +namespace Magnum { namespace Shapes { namespace Test { -namespace Magnum { namespace SceneGraph { +#define VERIFY_COLLIDES(a, b) \ + CORRADE_VERIFY(a % b); \ + CORRADE_VERIFY(b % a); -#ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT Object>; -#endif +#define VERIFY_NOT_COLLIDES(a, b) \ + CORRADE_VERIFY(!(a % b)); \ + CORRADE_VERIFY(!(b % a)); + +}}} -}} +#endif diff --git a/src/Physics/Test/SphereTest.cpp b/src/Shapes/Test/SphereTest.cpp similarity index 50% rename from src/Physics/Test/SphereTest.cpp rename to src/Shapes/Test/SphereTest.cpp index ba50a5b15..70f413be5 100644 --- a/src/Physics/Test/SphereTest.cpp +++ b/src/Shapes/Test/SphereTest.cpp @@ -22,19 +22,21 @@ DEALINGS IN THE SOFTWARE. */ -#include "Physics/LineSegment.h" -#include "Physics/Point.h" -#include "Physics/Sphere.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "Shapes/LineSegment.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" #include "ShapeTestBase.h" -namespace Magnum { namespace Physics { namespace Test { +namespace Magnum { namespace Shapes { namespace Test { -class SphereTest: public Corrade::TestSuite::Tester, ShapeTestBase { +class SphereTest: public TestSuite::Tester { public: SphereTest(); - void applyTransformation(); + void transformed(); void collisionPoint(); void collisionLine(); void collisionLineSegment(); @@ -42,77 +44,61 @@ class SphereTest: public Corrade::TestSuite::Tester, ShapeTestBase { }; SphereTest::SphereTest() { - addTests({&SphereTest::applyTransformation, + addTests({&SphereTest::transformed, &SphereTest::collisionPoint, &SphereTest::collisionLine, &SphereTest::collisionLineSegment, &SphereTest::collisionSphere}); } -void SphereTest::applyTransformation() { - Physics::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 7.0f); +void SphereTest::transformed() { + const Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 7.0f); - sphere.applyTransformationMatrix(Matrix4::rotation(Deg(90.0f), Vector3::yAxis())); - CORRADE_COMPARE(sphere.transformedPosition(), Vector3(3.0f, 2.0f, -1.0f)); - CORRADE_COMPARE(sphere.transformedRadius(), 7.0f); + const auto transformed = sphere.transformed(Matrix4::rotation(Deg(90.0f), Vector3::yAxis())); + CORRADE_COMPARE(transformed.position(), Vector3(3.0f, 2.0f, -1.0f)); + CORRADE_COMPARE(transformed.radius(), 7.0f); /* Symmetric scaling */ - sphere.applyTransformationMatrix(Matrix4::scaling(Vector3(2.0f))); - CORRADE_COMPARE(sphere.transformedPosition(), Vector3(2.0f, 4.0f, 6.0f)); - CORRADE_COMPARE(sphere.transformedRadius(), 14.0f); + const auto scaled = sphere.transformed(Matrix4::scaling(Vector3(2.0f))); + CORRADE_COMPARE(scaled.position(), Vector3(2.0f, 4.0f, 6.0f)); + CORRADE_COMPARE(scaled.radius(), 14.0f); /* Apply average scaling to radius */ - sphere.applyTransformationMatrix(Matrix4::scaling({Constants::sqrt3(), -Constants::sqrt2(), 2.0f})); - CORRADE_COMPARE(sphere.transformedRadius(), Constants::sqrt3()*7.0f); + const auto nonEven = sphere.transformed(Matrix4::scaling({Constants::sqrt3(), -Constants::sqrt2(), 2.0f})); + CORRADE_COMPARE(nonEven.radius(), Constants::sqrt3()*7.0f); } void SphereTest::collisionPoint() { - Physics::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); - Physics::Point3D point({1.0f, 3.0f, 3.0f}); - Physics::Point3D point2({1.0f, 3.0f, 1.0f}); - - randomTransformation(sphere); - randomTransformation(point); - randomTransformation(point2); + Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); + Shapes::Point3D point({1.0f, 3.0f, 3.0f}); + Shapes::Point3D point2({1.0f, 3.0f, 1.0f}); VERIFY_COLLIDES(sphere, point); VERIFY_NOT_COLLIDES(sphere, point2); } void SphereTest::collisionLine() { - Physics::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); - Physics::Line3D line({1.0f, 1.5f, 3.5f}, {1.0f, 2.5f, 2.5f}); - Physics::Line3D line2({1.0f, 2.0f, 5.1f}, {1.0f, 3.0f, 5.1f}); - - randomTransformation(sphere); - randomTransformation(line); - randomTransformation(line2); + Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); + Shapes::Line3D line({1.0f, 1.5f, 3.5f}, {1.0f, 2.5f, 2.5f}); + Shapes::Line3D line2({1.0f, 2.0f, 5.1f}, {1.0f, 3.0f, 5.1f}); VERIFY_COLLIDES(sphere, line); VERIFY_NOT_COLLIDES(sphere, line2); } void SphereTest::collisionLineSegment() { - Physics::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); - Physics::LineSegment3D line({1.0f, 2.0f, 4.9f}, {1.0f, 2.0f, 7.0f}); - Physics::LineSegment3D line2({1.0f, 2.0f, 5.1f}, {1.0f, 2.0f, 7.0f}); - - randomTransformation(sphere); - randomTransformation(line); - randomTransformation(line2); + Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); + Shapes::LineSegment3D line({1.0f, 2.0f, 4.9f}, {1.0f, 2.0f, 7.0f}); + Shapes::LineSegment3D line2({1.0f, 2.0f, 5.1f}, {1.0f, 2.0f, 7.0f}); VERIFY_COLLIDES(sphere, line); VERIFY_NOT_COLLIDES(sphere, line2); } void SphereTest::collisionSphere() { - Physics::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); - Physics::Sphere3D sphere1({1.0f, 3.0f, 5.0f}, 1.0f); - Physics::Sphere3D sphere2({1.0f, 3.0f, 0.0f}, 1.0f); - - randomTransformation(sphere); - randomTransformation(sphere1); - randomTransformation(sphere2); + Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); + Shapes::Sphere3D sphere1({1.0f, 3.0f, 5.0f}, 1.0f); + Shapes::Sphere3D sphere2({1.0f, 3.0f, 0.0f}, 1.0f); VERIFY_COLLIDES(sphere, sphere1); VERIFY_NOT_COLLIDES(sphere, sphere2); @@ -120,4 +106,4 @@ void SphereTest::collisionSphere() { }}} -CORRADE_TEST_MAIN(Magnum::Physics::Test::SphereTest) +CORRADE_TEST_MAIN(Magnum::Shapes::Test::SphereTest) diff --git a/src/Physics/magnumPhysicsVisibility.h b/src/Shapes/magnumShapesVisibility.h similarity index 81% rename from src/Physics/magnumPhysicsVisibility.h rename to src/Shapes/magnumShapesVisibility.h index 6ee2b89c0..c5f8fa30f 100644 --- a/src/Physics/magnumPhysicsVisibility.h +++ b/src/Shapes/magnumShapesVisibility.h @@ -1,5 +1,5 @@ -#ifndef Magnum_Physics_magnumPhysicsVisibility_h -#define Magnum_Physics_magnumPhysicsVisibility_h +#ifndef Magnum_Shapes_magnumShapesVisibility_h +#define Magnum_Shapes_magnumShapesVisibility_h /* This file is part of Magnum. @@ -26,10 +26,11 @@ #include -#ifdef MagnumPhysics_EXPORTS - #define MAGNUM_PHYSICS_EXPORT CORRADE_VISIBILITY_EXPORT +#ifdef MagnumShapes_EXPORTS + #define MAGNUM_SHAPES_EXPORT CORRADE_VISIBILITY_EXPORT #else - #define MAGNUM_PHYSICS_EXPORT CORRADE_VISIBILITY_IMPORT + #define MAGNUM_SHAPES_EXPORT CORRADE_VISIBILITY_IMPORT #endif +#define MAGNUM_SHAPES_LOCAL CORRADE_VISIBILITY_LOCAL #endif diff --git a/src/Physics/AbstractShape.cpp b/src/Shapes/shapeImplementation.cpp similarity index 67% rename from src/Physics/AbstractShape.cpp rename to src/Shapes/shapeImplementation.cpp index 2321bd481..1b3b57973 100644 --- a/src/Physics/AbstractShape.cpp +++ b/src/Shapes/shapeImplementation.cpp @@ -22,29 +22,15 @@ DEALINGS IN THE SOFTWARE. */ -#include "AbstractShape.h" +#include "shapeImplementation.h" #include -namespace Magnum { namespace Physics { - -template bool AbstractShape::collides(const AbstractShape* other) const { - /* Operate only with simpler types than this */ - if(static_cast(other->type()) > static_cast(type())) - return other->collides(this); - - return false; -} - -template class AbstractShape<2>; -template class AbstractShape<3>; - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { +namespace Magnum { namespace Shapes { namespace Implementation { Debug operator<<(Debug debug, ShapeDimensionTraits<2>::Type value) { switch(value) { - #define _val(value) case AbstractShape2D::Type::value: return debug << "AbstractShape2D::Type::" #value; + #define _val(value) case ShapeDimensionTraits<2>::Type::value: return debug << "Shapes::Shape2D::Type::" #value; _val(Point) _val(Line) _val(LineSegment) @@ -52,16 +38,16 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<2>::Type value) { _val(Capsule) _val(AxisAlignedBox) _val(Box) - _val(ShapeGroup) + _val(Composition) #undef _val } - return debug << "AbstractShape2D::Type::(unknown)"; + return debug << "Shapes::Shape2D::Type::(unknown)"; } Debug operator<<(Debug debug, ShapeDimensionTraits<3>::Type value) { switch(value) { - #define _val(value) case AbstractShape3D::Type::value: return debug << "AbstractShape3D::Type::" #value; + #define _val(value) case ShapeDimensionTraits<3>::Type::value: return debug << "Shapes::Shape3D::Type::" #value; _val(Point) _val(Line) _val(LineSegment) @@ -69,15 +55,18 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<3>::Type value) { _val(Capsule) _val(AxisAlignedBox) _val(Box) - _val(ShapeGroup) _val(Plane) + _val(Composition) #undef _val } - return debug << "AbstractShape2D::Type::(unknown)"; + return debug << "Shapes::Shape3D::Type::(unknown)"; } -} -#endif +template AbstractShape::~AbstractShape() = default; +template AbstractShape::AbstractShape() = default; + +template struct AbstractShape<2>; +template struct AbstractShape<3>; -}} +}}} diff --git a/src/Shapes/shapeImplementation.h b/src/Shapes/shapeImplementation.h new file mode 100644 index 000000000..d90f889e5 --- /dev/null +++ b/src/Shapes/shapeImplementation.h @@ -0,0 +1,155 @@ +#ifndef Magnum_Shapes_shapeImplementation_h +#define Magnum_Shapes_shapeImplementation_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "DimensionTraits.h" +#include "Magnum.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" + +namespace Magnum { namespace Shapes { namespace Implementation { + +/* Shape type for given dimension count */ + +template struct ShapeDimensionTraits; + +template<> struct ShapeDimensionTraits<2> { + enum class Type: UnsignedByte { + Point = 1, + Line = 2, + LineSegment = 3, + Sphere = 5, + Capsule = 7, + AxisAlignedBox = 11, + Box = 13, + Composition = 17 + }; +}; + +template<> struct ShapeDimensionTraits<3> { + enum class Type: UnsignedByte { + Point = 1, + Line = 2, + LineSegment = 3, + Sphere = 5, + Capsule = 7, + AxisAlignedBox = 11, + Box = 13, + Plane = 17, + Composition = 19 + }; +}; + +Debug MAGNUM_SHAPES_EXPORT operator<<(Debug debug, ShapeDimensionTraits<2>::Type value); +Debug MAGNUM_SHAPES_EXPORT operator<<(Debug debug, ShapeDimensionTraits<3>::Type value); + +/* Enum value corresponding to given type */ + +template struct TypeOf; + +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Point; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Line; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::LineSegment; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Sphere; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Capsule; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::AxisAlignedBox; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Box; + } +}; +template<> struct TypeOf { + constexpr static typename ShapeDimensionTraits<3>::Type type() { + return ShapeDimensionTraits<3>::Type::Plane; + } +}; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Composition; + } +}; + +/* Polymorphic shape wrappers */ + +template struct MAGNUM_SHAPES_EXPORT AbstractShape { + explicit AbstractShape(); + virtual ~AbstractShape(); + + virtual typename ShapeDimensionTraits::Type MAGNUM_SHAPES_LOCAL type() const = 0; + virtual AbstractShape MAGNUM_SHAPES_LOCAL * clone() const = 0; + virtual void MAGNUM_SHAPES_LOCAL transform(const typename DimensionTraits::MatrixType& matrix, AbstractShape* result) const = 0; +}; + +template struct Shape: AbstractShape { + T shape; + + explicit Shape() = default; + explicit Shape(const T& shape): shape(shape) {} + explicit Shape(T&& shape): shape(std::move(shape)) {} + + typename ShapeDimensionTraits::Type type() const override { + return TypeOf::type(); + } + + AbstractShape* clone() const override { + return new Shape(shape); + } + + void transform(const typename DimensionTraits::MatrixType& matrix, AbstractShape* result) const override { + CORRADE_INTERNAL_ASSERT(result->type() == type()); + static_cast*>(result)->shape = shape.transformed(matrix); + } +}; + +}}} + +#endif diff --git a/src/Swizzle.h b/src/Swizzle.h index 972cf70cc..07216c3b1 100644 --- a/src/Swizzle.h +++ b/src/Swizzle.h @@ -33,7 +33,6 @@ namespace Magnum { -#ifndef DOXYGEN_GENERATING_OUTPUT namespace Math { namespace Implementation { template struct Component: public ComponentAtPosition {}; template struct Component: public ComponentAtPosition {}; @@ -53,7 +52,6 @@ namespace Implementation { template struct TypeForSize<4, Color3> { typedef Color4 Type; }; template struct TypeForSize<4, Color4> { typedef Color4 Type; }; } -#endif /** @brief Swizzle Vector components @@ -74,7 +72,7 @@ Color3 or Color4 specialization is returned. @see @ref matrix-vector-component-access, Math::swizzle(), Vector4::xyz(), Color4::rgb(), Vector4::xy(), Vector3::xy() */ -template inline constexpr typename Implementation::TypeForSize::Type swizzle(const T& vector) { +template constexpr typename Implementation::TypeForSize::Type swizzle(const T& vector) { return {Math::Implementation::Component::value(vector)...}; } diff --git a/src/Test/AbstractImageTest.cpp b/src/Test/AbstractImageTest.cpp index 2f1e475ec..73b2b7239 100644 --- a/src/Test/AbstractImageTest.cpp +++ b/src/Test/AbstractImageTest.cpp @@ -26,10 +26,11 @@ #include #include "AbstractImage.h" +#include "ImageFormat.h" namespace Magnum { namespace Test { -class AbstractImageTest: public Corrade::TestSuite::Tester { +class AbstractImageTest: public TestSuite::Tester { public: explicit AbstractImageTest(); @@ -44,14 +45,14 @@ AbstractImageTest::AbstractImageTest() { void AbstractImageTest::debugFormat() { std::ostringstream o; - Debug(&o) << AbstractImage::Format::RGBA; - CORRADE_COMPARE(o.str(), "AbstractImage::Format::RGBA\n"); + Debug(&o) << ImageFormat::RGBA; + CORRADE_COMPARE(o.str(), "ImageFormat::RGBA\n"); } void AbstractImageTest::debugType() { std::ostringstream o; - Debug(&o) << AbstractImage::Type::UnsignedShort5551; - CORRADE_COMPARE(o.str(), "AbstractImage::Type::UnsignedShort5551\n"); + Debug(&o) << ImageType::UnsignedShort5551; + CORRADE_COMPARE(o.str(), "ImageType::UnsignedShort5551\n"); } }} diff --git a/src/Test/AbstractShaderProgramTest.cpp b/src/Test/AbstractShaderProgramTest.cpp index 889007f64..b3c4c3c30 100644 --- a/src/Test/AbstractShaderProgramTest.cpp +++ b/src/Test/AbstractShaderProgramTest.cpp @@ -28,7 +28,7 @@ namespace Magnum { namespace Test { -class AbstractShaderProgramTest: public Corrade::TestSuite::Tester { +class AbstractShaderProgramTest: public TestSuite::Tester { public: explicit AbstractShaderProgramTest(); diff --git a/src/Test/ArrayTest.cpp b/src/Test/ArrayTest.cpp index dcf4de7bd..cff946fbf 100644 --- a/src/Test/ArrayTest.cpp +++ b/src/Test/ArrayTest.cpp @@ -28,7 +28,7 @@ namespace Magnum { namespace Test { -class ArrayTest: public Corrade::TestSuite::Tester { +class ArrayTest: public TestSuite::Tester { public: ArrayTest(); diff --git a/src/Test/ColorTest.cpp b/src/Test/ColorTest.cpp index 773913454..52b815f65 100644 --- a/src/Test/ColorTest.cpp +++ b/src/Test/ColorTest.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace Test { -class ColorTest: public Corrade::TestSuite::Tester { +class ColorTest: public TestSuite::Tester { public: ColorTest(); @@ -178,7 +178,7 @@ void ColorTest::debug() { } void ColorTest::configuration() { - Corrade::Utility::Configuration c; + Utility::Configuration c; Color3f color3(0.5f, 0.75f, 1.0f); std::string value3("0.5 0.75 1"); diff --git a/src/Test/MeshTest.cpp b/src/Test/MeshTest.cpp index 10c91fcc8..7b382c3e4 100644 --- a/src/Test/MeshTest.cpp +++ b/src/Test/MeshTest.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace Test { -class MeshTest: public Corrade::TestSuite::Tester { +class MeshTest: public TestSuite::Tester { public: MeshTest(); @@ -60,7 +60,7 @@ void MeshTest::debugIndexType() { } void MeshTest::configurationPrimitive() { - Corrade::Utility::Configuration c; + Utility::Configuration c; c.setValue("primitive", Mesh::Primitive::LineStrip); CORRADE_COMPARE(c.value("primitive"), "LineStrip"); @@ -68,7 +68,7 @@ void MeshTest::configurationPrimitive() { } void MeshTest::configurationIndexType() { - Corrade::Utility::Configuration c; + Utility::Configuration c; c.setValue("type", Mesh::IndexType::UnsignedByte); CORRADE_COMPARE(c.value("type"), "UnsignedByte"); diff --git a/src/Test/ResourceManagerTest.cpp b/src/Test/ResourceManagerTest.cpp index 0b964d68a..a99956e6b 100644 --- a/src/Test/ResourceManagerTest.cpp +++ b/src/Test/ResourceManagerTest.cpp @@ -32,7 +32,7 @@ namespace Magnum { namespace Test { -class ResourceManagerTest: public Corrade::TestSuite::Tester { +class ResourceManagerTest: public TestSuite::Tester { public: ResourceManagerTest(); @@ -50,8 +50,8 @@ class Data { public: static std::size_t count; - inline Data() { ++count; } - inline ~Data() { --count; } + Data() { ++count; } + ~Data() { --count; } }; typedef Magnum::ResourceManager ResourceManager; diff --git a/src/Test/SwizzleTest.cpp b/src/Test/SwizzleTest.cpp index f0ca3446f..164785e27 100644 --- a/src/Test/SwizzleTest.cpp +++ b/src/Test/SwizzleTest.cpp @@ -28,7 +28,7 @@ namespace Magnum { namespace Test { -class SwizzleTest: public Corrade::TestSuite::Tester { +class SwizzleTest: public TestSuite::Tester { public: SwizzleTest(); diff --git a/src/Text/AbstractFont.cpp b/src/Text/AbstractFont.cpp index 74f116ad3..58a90cf2b 100644 --- a/src/Text/AbstractFont.cpp +++ b/src/Text/AbstractFont.cpp @@ -28,7 +28,7 @@ namespace Magnum { namespace Text { AbstractFont::AbstractFont(): _size(0.0f) {} -AbstractFont::AbstractFont(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)), _size(0.0f) {} +AbstractFont::AbstractFont(PluginManager::AbstractManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)), _size(0.0f) {} AbstractLayouter::AbstractLayouter(): _glyphCount(0) {} diff --git a/src/Text/AbstractFont.h b/src/Text/AbstractFont.h index 495af5f5e..765defb49 100644 --- a/src/Text/AbstractFont.h +++ b/src/Text/AbstractFont.h @@ -52,15 +52,15 @@ information. See TextRenderer for information about text rendering. Plugin implements functions open(), close(), createGlyphCache() and layout(). */ -class MAGNUM_TEXT_EXPORT AbstractFont: public Corrade::PluginManager::AbstractPlugin { - PLUGIN_INTERFACE("cz.mosra.magnum.Text.AbstractFont/0.1") +class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { + CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Text.AbstractFont/0.1") public: /** @brief Default constructor */ explicit AbstractFont(); /** @brief Plugin manager constructor */ - explicit AbstractFont(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin); + explicit AbstractFont(PluginManager::AbstractManager* manager, std::string plugin); /** * @brief Open font from file @@ -87,7 +87,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public Corrade::PluginManager::AbstractPl virtual void close() = 0; /** @brief Font size */ - inline Float size() const { return _size; } + Float size() const { return _size; } /** * @brief Create glyph cache for given character set @@ -132,7 +132,7 @@ class MAGNUM_TEXT_EXPORT AbstractLayouter { virtual ~AbstractLayouter() = 0; /** @brief Count of glyphs in laid out text */ - inline UnsignedInt glyphCount() const { + UnsignedInt glyphCount() const { return _glyphCount; } diff --git a/src/Text/DistanceFieldGlyphCache.cpp b/src/Text/DistanceFieldGlyphCache.cpp index af4a842d7..73ffcd4b7 100644 --- a/src/Text/DistanceFieldGlyphCache.cpp +++ b/src/Text/DistanceFieldGlyphCache.cpp @@ -26,15 +26,16 @@ #include "Extensions.h" #include "Image.h" +#include "TextureFormat.h" #include "TextureTools/DistanceField.h" namespace Magnum { namespace Text { namespace { #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3) - const AbstractTexture::InternalFormat internalFormat = AbstractTexture::InternalFormat::R8; + const TextureFormat internalFormat = TextureFormat::R8; #else - const AbstractTexture::InternalFormat internalFormat = AbstractTexture::InternalFormat::Red; + const TextureFormat internalFormat = TextureFormat::Red; #endif } @@ -50,9 +51,9 @@ DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, c void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const image) { Texture2D input; - input.setWrapping(Texture2D::Wrapping::ClampToEdge) - ->setMinificationFilter(Texture2D::Filter::Linear) - ->setMagnificationFilter(Texture2D::Filter::Linear) + input.setWrapping(Sampler::Wrapping::ClampToEdge) + ->setMinificationFilter(Sampler::Filter::Linear) + ->setMagnificationFilter(Sampler::Filter::Linear) ->setImage(0, internalFormat, image); /* Create distance field from input texture */ diff --git a/src/Text/GlyphCache.cpp b/src/Text/GlyphCache.cpp index c46af37e0..1db6a252d 100644 --- a/src/Text/GlyphCache.cpp +++ b/src/Text/GlyphCache.cpp @@ -26,15 +26,16 @@ #include "Extensions.h" #include "Image.h" +#include "TextureFormat.h" #include "TextureTools/Atlas.h" namespace Magnum { namespace Text { namespace { #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3) - const AbstractTexture::InternalFormat internalFormat = AbstractTexture::InternalFormat::R8; + const TextureFormat internalFormat = TextureFormat::R8; #else - const AbstractTexture::InternalFormat internalFormat = AbstractTexture::InternalFormat::Red; + const TextureFormat internalFormat = TextureFormat::Red; #endif } @@ -48,7 +49,7 @@ GlyphCache::GlyphCache(const Vector2i& size): _size(size) { initialize(internalFormat, size); } -GlyphCache::GlyphCache(const Vector2i& size, const AbstractTexture::InternalFormat internalFormat): _size(size) { +GlyphCache::GlyphCache(const Vector2i& size, const TextureFormat internalFormat): _size(size) { initialize(internalFormat, size); } @@ -57,16 +58,16 @@ GlyphCache::GlyphCache(const Vector2i& size, const Vector2i& padding): _size(siz GlyphCache::~GlyphCache() = default; /** @todo Delegating constructor when support for GCC 4.6 is dropped */ -void GlyphCache::initialize(const AbstractTexture::InternalFormat internalFormat, const Vector2i& size) { +void GlyphCache::initialize(const TextureFormat internalFormat, const Vector2i& size) { #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_storage); #else MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_storage); #endif - _texture.setWrapping(Texture2D::Wrapping::ClampToEdge) - ->setMinificationFilter(Texture2D::Filter::Linear) - ->setMagnificationFilter(Texture2D::Filter::Linear) + _texture.setWrapping(Sampler::Wrapping::ClampToEdge) + ->setMinificationFilter(Sampler::Filter::Linear) + ->setMagnificationFilter(Sampler::Filter::Linear) ->setStorage(1, internalFormat, size); } diff --git a/src/Text/GlyphCache.h b/src/Text/GlyphCache.h index 6d452a72c..bd6c55d5b 100644 --- a/src/Text/GlyphCache.h +++ b/src/Text/GlyphCache.h @@ -62,7 +62,7 @@ class MAGNUM_TEXT_EXPORT GlyphCache { * @param size Glyph cache texture size * @param internalFormat Internal texture format */ - explicit GlyphCache(const Vector2i& size, Texture2D::InternalFormat internalFormat); + explicit GlyphCache(const Vector2i& size, TextureFormat internalFormat); /** * @brief Constructor @@ -81,13 +81,13 @@ class MAGNUM_TEXT_EXPORT GlyphCache { * * Size of unscaled glyph cache texture. */ - inline Vector2i textureSize() const { return _size; } + Vector2i textureSize() const { return _size; } /** @brief Count of glyphs in the cache */ - inline std::size_t glyphCount() const { return glyphs.size(); } + std::size_t glyphCount() const { return glyphs.size(); } /** @brief Cache texture */ - inline Texture2D* texture() { return &_texture; } + Texture2D* texture() { return &_texture; } /** * @brief Parameters of given glyph @@ -97,7 +97,7 @@ class MAGNUM_TEXT_EXPORT GlyphCache { * second element is glyph region in texture atlas. If no glyph is * found, glyph on zero index is returned. */ - inline std::pair operator[](UnsignedInt glyph) const { + std::pair operator[](UnsignedInt glyph) const { auto it = glyphs.find(glyph); return it == glyphs.end() ? glyphs.at(0) : it->second; } @@ -142,7 +142,7 @@ class MAGNUM_TEXT_EXPORT GlyphCache { /* Used from DistanceFieldGlyphCache */ explicit MAGNUM_LOCAL GlyphCache(const Vector2i& size, const Vector2i& padding); - void MAGNUM_LOCAL initialize(Texture2D::InternalFormat internalFormat, const Vector2i& size); + void MAGNUM_LOCAL initialize(TextureFormat internalFormat, const Vector2i& size); const Vector2i _size; Texture2D _texture; diff --git a/src/Text/TextRenderer.cpp b/src/Text/TextRenderer.cpp index a0ee125d6..8ef22ea3a 100644 --- a/src/Text/TextRenderer.cpp +++ b/src/Text/TextRenderer.cpp @@ -27,7 +27,7 @@ #include "Context.h" #include "Extensions.h" #include "Mesh.h" -#include "Shaders/AbstractVectorShader.h" +#include "Shaders/AbstractVector.h" #include "Text/AbstractFont.h" namespace Magnum { namespace Text { @@ -179,9 +179,9 @@ template std::tuple TextRenderer(r); mesh.addInterleavedVertexBuffer(vertexBuffer, 0, - typename Shaders::AbstractVectorShader::Position( - Shaders::AbstractVectorShader::Position::Components::Two), - typename Shaders::AbstractVectorShader::TextureCoordinates()); + typename Shaders::AbstractVector::Position( + Shaders::AbstractVector::Position::Components::Two), + typename Shaders::AbstractVector::TextureCoordinates()); return std::move(r); } @@ -203,8 +203,8 @@ AbstractTextRenderer::~AbstractTextRenderer() {} template TextRenderer::TextRenderer(AbstractFont* const font, const GlyphCache* const cache, const Float size): AbstractTextRenderer(font, cache, size) { /* Finalize mesh configuration */ _mesh.addInterleavedVertexBuffer(&vertexBuffer, 0, - typename Shaders::AbstractVectorShader::Position(Shaders::AbstractVectorShader::Position::Components::Two), - typename Shaders::AbstractVectorShader::TextureCoordinates()); + typename Shaders::AbstractVector::Position(Shaders::AbstractVector::Position::Components::Two), + typename Shaders::AbstractVector::TextureCoordinates()); } void AbstractTextRenderer::reserve(const uint32_t glyphCount, const Buffer::Usage vertexBufferUsage, const Buffer::Usage indexBufferUsage) { diff --git a/src/Text/TextRenderer.h b/src/Text/TextRenderer.h index b4f470723..4c1299a58 100644 --- a/src/Text/TextRenderer.h +++ b/src/Text/TextRenderer.h @@ -77,13 +77,13 @@ class MAGNUM_TEXT_EXPORT AbstractTextRenderer { * * @see reserve() */ - inline UnsignedInt capacity() const { return _capacity; } + UnsignedInt capacity() const { return _capacity; } /** @brief Rectangle spanning the rendered text */ - inline Rectangle rectangle() const { return _rectangle; } + Rectangle rectangle() const { return _rectangle; } /** @brief Text mesh */ - inline Mesh* mesh() { return &_mesh; } + Mesh* mesh() { return &_mesh; } /** * @brief Reserve capacity for rendered glyphs diff --git a/src/Texture.h b/src/Texture.h index 9ab67c85b..139dc7950 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -46,14 +46,14 @@ data from e.g. Image. Example configuration of high quality texture with trilinear anisotropic filtering, i.e. the best you can ask for: @code void* data; -Image2D image({4096, 4096}, Image2D::Components::RGBA, Image2D::ComponentType::UnsignedByte, data); +Image2D image({4096, 4096}, ImageFormat::RGBA, ImageType::UnsignedByte, data); Texture2D texture; -texture.setMagnificationFilter(Texture2D::Filter::Linear) - ->setMinificationFilter(Texture2D::Filter::Linear, Texture2D::Mipmap::Linear) - ->setWrapping(Texture2D::Wrapping::ClampToEdge) - ->setMaxAnisotropy(Texture2D::maxSupportedAnisotropy) - ->setStorage(Math::log2(4096)+1, Texture2D::Format::RGBA8, {4096, 4096}) +texture.setMagnificationFilter(Sampler::Filter::Linear) + ->setMinificationFilter(Sampler::Filter::Linear, Texture2D::Mipmap::Linear) + ->setWrapping(Sampler::Wrapping::ClampToEdge) + ->setMaxAnisotropy(Sampler::maxSupportedAnisotropy()) + ->setStorage(Math::log2(4096)+1, TextureFormat::RGBA8, {4096, 4096}) ->setSubImage(0, {}, &image) ->generateMipmap(); @endcode @@ -67,14 +67,14 @@ texture.setMagnificationFilter(Texture2D::Filter::Linear) textures. See also setMagnificationFilter() and setBorderColor(). The texture is bound to layer specified by shader via bind(). In shader, the -texture is used via `sampler1D`, `sampler2D` or `sampler3D` depending on -dimension count. See also AbstractShaderProgram documentation for more -information. +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 Texture::Target "Texture2D::Target::Texture1DArray" -or @ref Texture::Target "Texture3D::Target::Texture2DArray" to constructor. +You can create texture arrays by passing @ref Target "Texture2D::Target::Texture1DArray" +or @ref Target "Texture3D::Target::Texture2DArray" to constructor. It is possible to specify each layer separately using setSubImage(), but you have to allocate the memory for all layers first either by calling setStorage() @@ -82,13 +82,13 @@ or by passing properly sized empty Image to setImage(). Example: 2D texture array with 16 layers of 64x64 images: @code Texture3D texture(Texture3D::Target::Texture2DArray); -texture.setMagnificationFilter(Texture2D::Filter::Linear) +texture.setMagnificationFilter(Sampler::Filter::Linear) // ... - ->setStorage(levels, Texture2D::Format::RGBA8, {64, 64,16}); + ->setStorage(levels, TextureFormat::RGBA8, {64, 64,16}); for(std::size_t i = 0; i != 16; ++i) { void* data = ...; - Image2D image({64, 64}, Image3D::Components::RGBA, Image3D::ComponentType::UnsignedByte, image); + Image2D image({64, 64}, ImageFormat::RGBA, ImageType::UnsignedByte, image); texture->setSubImage(0, Vector3i::zAxis(i), image); } @@ -99,21 +99,36 @@ Similar approach can be used for any other texture types (e.g. setting Texture3D data using 2D layers, 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 "Texture2D::Target::Texture2DMultisample" +or @ref Target "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. + @section Texture-rectangle Rectangle textures -Rectangle texture is created by passing @ref Texture::Target "Texture::Target::Rectangle" -to constructor. In shader, the texture is used via sampler2DRect`. Unlike -`sampler2D`, which accepts coordinates between 0 and 1, `sampler2DRect` +Rectangle texture is created by passing @ref Target "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 Texture::Filter "Filter", @ref Texture::Mipmap "Mipmap" and -generateMipmap() documentation for more information. +@ref Sampler::Filter "Sampler::Filter", @ref Sampler::Mipmap "Sampler::Mipmap" +and generateMipmap() documentation for more information. +@requires_gl31 %Extension @extension{ARB,texture_rectangle} for rectangle + textures. @requires_gl Rectangle textures are not available in OpenGL ES. -@requires_gl31 %Extension @extension{ARB,texture_rectangle} (rectangle - textures) -@see Texture1D, Texture2D, Texture3D, CubeMapTexture, CubeMapTextureArray +@see Texture1D, Texture2D, Texture3D, CubeMapTexture, CubeMapTextureArray, + BufferTexture @todo @extension{AMD,sparse_texture} */ template class Texture: public AbstractTexture { @@ -128,22 +143,30 @@ template class Texture: public AbstractTexture { */ enum class Target: GLenum { /** - * One-dimensional texture + * One-dimensional texture. Use `sampler1D`, `sampler1DShadow`, + * `isampler1D` or `usampler1D` in shader. * @requires_gl Only 2D and 3D textures are available in OpenGL * ES. */ Texture1D = GL_TEXTURE_1D, - Texture2D = GL_TEXTURE_2D, /**< Two-dimensional texture */ + /** + * Two-dimensional texture. Use `sampler2D`, `sampler2DShadow`, + * `isampler2D` or `usampler2D` in shader. + */ + Texture2D = GL_TEXTURE_2D, /** - * Three-dimensional texture + * Three-dimensional texture. Use `sampler3D`, `isampler3D` or + * `usampler3D` in shader. * @requires_gles30 %Extension @es_extension{OES,texture_3D} */ Texture3D = GL_TEXTURE_3D, /** - * One-dimensional texture array (i.e. two dimensions in total) + * 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. @@ -151,15 +174,38 @@ template class Texture: public AbstractTexture { Texture1DArray = GL_TEXTURE_1D_ARRAY, /** - * Two-dimensional texture array (i.e. three dimensions in total) + * 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 + * @requires_gles30 %Array textures are not available in OpenGL ES * 2.0. */ Texture2DArray = GL_TEXTURE_2D_ARRAY, /** - * Rectangle texture (i.e. two dimensions) + * 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. + */ + 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. + */ + 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. */ @@ -178,10 +224,10 @@ template class Texture: public AbstractTexture { * Creates one OpenGL texture. * @see @fn_gl{GenTextures} */ - inline explicit Texture(Target target = DataHelper::target()): AbstractTexture(static_cast(target)) {} + explicit Texture(Target target = DataHelper::target()): AbstractTexture(static_cast(target)) {} /** @brief %Texture target */ - inline constexpr Target target() const { return static_cast(_target); } + constexpr Target target() const { return static_cast(_target); } #ifndef MAGNUM_TARGET_GLES /** @@ -195,7 +241,7 @@ 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. */ - inline typename DimensionTraits::VectorType imageSize(Int level) { + typename DimensionTraits::VectorType imageSize(Int level) { return DataHelper::imageSize(this, _target, level); } #endif @@ -209,16 +255,16 @@ template class Texture: public AbstractTexture { * textures and (0, textureSizeInGivenDirection-1) 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 AbstractTexture::Wrapping "Wrapping::Repeat". + * value is @ref Sampler::Wrapping "Sampler::Wrapping::Repeat". * @attention For rectangle textures only some modes are supported, - * see @ref AbstractTexture::Wrapping "Wrapping" documentation + * see @ref Sampler::Wrapping "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} */ - inline Texture* setWrapping(const Array& wrapping) { + Texture* setWrapping(const Array& wrapping) { DataHelper::setWrapping(this, wrapping); return this; } @@ -245,11 +291,52 @@ template class Texture: public AbstractTexture { * @requires_gl42 %Extension @extension{ARB,texture_storage} * @requires_gles30 %Extension @es_extension{EXT,texture_storage} */ - inline Texture* setStorage(Int levels, InternalFormat internalFormat, const typename DimensionTraits::VectorType& size) { + Texture* setStorage(Int levels, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size) { DataHelper::setStorage(this, _target, levels, internalFormat, size); return this; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Read given mip level of texture to image + * @param level Mip level + * @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 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}, @def_gl{TEXTURE_HEIGHT} or @def_gl{TEXTURE_DEPTH}, + * then @fn_gl{GetTexImage}, @fn_gl_extension{GetTextureImage,EXT,direct_state_access} + * or @fn_gl_extension{GetnTexImage,ARB,robustness} + */ + void image(Int level, Image* image) { + AbstractTexture::image(_target, level, image); + } + + /** + * @brief Read given mip level of texture to buffer image + * @param level Mip level + * @param image %Buffer image where to put the data + * @param usage %Buffer usage + * + * See image(Int, Image*) for more information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + void image(Int level, BufferImage* image, Buffer::Usage usage) { + AbstractTexture::image(_target, level, image, usage); + } + #endif + /** * @brief Set image data * @param level Mip level @@ -272,8 +359,8 @@ template class Texture: public AbstractTexture { * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access} */ - template inline Texture* setImage(Int level, InternalFormat internalFormat, Image* image) { - DataHelper::set(this, _target, level, internalFormat, image); + template Texture* setImage(Int level, TextureFormat internalFormat, Image* image) { + DataHelper::setImage(this, _target, level, internalFormat, image); return this; } @@ -302,8 +389,8 @@ template class Texture: public AbstractTexture { * @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} */ - template inline Texture* setSubImage(Int level, const typename DimensionTraits::VectorType& offset, Image* image) { - DataHelper::setSub(this, _target, level, offset, image); + template Texture* setSubImage(Int level, const typename DimensionTraits::VectorType& offset, Image* image) { + DataHelper::setSubImage(this, _target, level, offset, image); return this; } @@ -317,31 +404,31 @@ template class Texture: public AbstractTexture { * is not available, this function does nothing. * @see invalidateImage(), @fn_gl{InvalidateTexSubImage} */ - inline void invalidateSubImage(Int level, const typename DimensionTraits::VectorType& offset, const typename DimensionTraits::VectorType& size) { - DataHelper::invalidateSub(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 - inline Texture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base) { + Texture* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); return this; } - inline Texture* setMagnificationFilter(Filter filter) { + Texture* setMagnificationFilter(Sampler::Filter filter) { AbstractTexture::setMagnificationFilter(filter); return this; } #ifndef MAGNUM_TARGET_GLES3 - inline Texture* setBorderColor(const Color4<>& color) { + Texture* setBorderColor(const Color4<>& color) { AbstractTexture::setBorderColor(color); return this; } - inline Texture* setMaxAnisotropy(Float anisotropy) { + Texture* setMaxAnisotropy(Float anisotropy) { AbstractTexture::setMaxAnisotropy(anisotropy); return this; } #endif - inline Texture* generateMipmap() { + Texture* generateMipmap() { AbstractTexture::generateMipmap(); return this; } diff --git a/src/TextureFormat.h b/src/TextureFormat.h new file mode 100644 index 000000000..7857540f7 --- /dev/null +++ b/src/TextureFormat.h @@ -0,0 +1,823 @@ +#ifndef Magnum_TextureFormat_h +#define Magnum_TextureFormat_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Enum Magnum::TextureFormat + */ + +#include "OpenGL.h" + +namespace Magnum { + +/** +@brief Internal texture format + +@see Texture, CubeMapTexture, CubeMapTextureArray +*/ +enum class TextureFormat: GLenum { + /** + * Red component, normalized unsigned, size implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::TextureFormat "TextureFormat::R8". + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + */ + #ifndef MAGNUM_TARGET_GLES2 + Red = GL_RED, + #else + Red = GL_RED_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Red component, normalized unsigned byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::Red" in + * OpenGL ES 2.0 instead. + */ + R8 = GL_R8, + #endif + + /** + * Red and green component, normalized unsigned, size + * implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::TextureFormat "TextureFormat::RG8". + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + */ + #ifndef MAGNUM_TARGET_GLES2 + RG = GL_RG, + #else + RG = GL_RG_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Red and green component, each normalized unsigned byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::RG" in + * OpenGL ES 2.0 instead. + */ + RG8 = GL_RG8, + #endif + + /** + * RGB, normalized unsigned, size implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::TextureFormat "TextureFormat::RGB8". + */ + RGB = GL_RGB, + + /** + * RGB, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + */ + #ifndef MAGNUM_TARGET_GLES2 + RGB8 = GL_RGB8, + #else + RGB8 = GL_RGB8_OES, + #endif + + /** + * RGBA, normalized unsigned, size implementation-dependent. + * @deprecated Prefer to use the exactly specified version of this format, + * e.g. @ref Magnum::TextureFormat "TextureFormat::RGBA8". + */ + RGBA = GL_RGBA, + + /** + * RGBA, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + */ + #ifndef MAGNUM_TARGET_GLES2 + RGBA8 = GL_RGBA8, + #else + RGBA8 = GL_RGBA8_OES, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Red component, normalized signed byte. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned formats are available in OpenGL ES 2.0. + */ + R8Snorm = GL_R8_SNORM, + + /** + * Red and green component, each normalized signed byte. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned formats are available in OpenGL ES 2.0. + */ + RG8Snorm = GL_RG8_SNORM, + + /** + * RGB, each component normalized signed byte. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned formats are available in OpenGL ES 2.0. + */ + RGB8Snorm = GL_RGB8_SNORM, + + /** + * RGBA, each component normalized signed byte. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned formats are available in OpenGL ES 2.0. + */ + RGBA8Snorm = GL_RGBA8_SNORM, + + #ifndef MAGNUM_TARGET_GLES + /** + * Red component, normalized unsigned short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + R16 = GL_R16, + + /** + * Red and green component, each normalized unsigned short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RG16 = GL_RG16, + + /** + * RGB, each component normalized unsigned short. + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RGB16 = GL_RGB16, + + /** + * RGBA, each component normalized unsigned short. + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RGBA16 = GL_RGBA16, + + /** + * Red component, normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + R16Snorm = GL_R16_SNORM, + + /** + * Red and green component, each normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RG16Snorm = GL_RG16_SNORM, + + /** + * RGB, each component normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RGB16Snorm = GL_RGB16_SNORM, + + /** + * RGBA, each component normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gl Only byte-sized normalized formats are available in OpenGL + * ES. + */ + RGBA16Snorm = GL_RGBA16_SNORM, + #endif + + /** + * Red component, non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R8UI = GL_R8UI, + + /** + * Red and green component, each non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG8UI = GL_RG8UI, + + /** + * RGB, each component non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB8UI = GL_RGB8UI, + + /** + * RGBA, each component non-normalized unsigned byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA8UI = GL_RGBA8UI, + + /** + * Red component, non-normalized signed byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R8I = GL_R8I, + + /** + * Red and green component, each non-normalized signed byte. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG8I = GL_RG8I, + + /** + * RGB, each component non-normalized signed byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB8I = GL_RGB8I, + + /** + * RGBA, each component non-normalized signed byte. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA8I = GL_RGBA8I, + + /** + * Red component, non-normalized unsigned short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R16UI = GL_R16UI, + + /** + * Red and green component, each non-normalized unsigned short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG16UI = GL_RG16UI, + + /** + * RGB, each component non-normalized unsigned short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB16UI = GL_RGB16UI, + + /** + * RGBA, each component non-normalized unsigned short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA16UI = GL_RGBA16UI, + + /** + * Red component, non-normalized signed short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R16I = GL_R16I, + + /** + * Red and green component, each non-normalized signed short. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG16I = GL_RG16I, + + /** + * RGB, each component non-normalized signed short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB16I = GL_RGB16I, + + /** + * RGBA, each component non-normalized signed short. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA16I = GL_RGBA16I, + + /** + * Red component, non-normalized unsigned int. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R32UI = GL_R32UI, + + /** + * Red and green component, each non-normalized unsigned int. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG32UI = GL_RG32UI, + + /** + * RGB, each component non-normalized unsigned int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB32UI = GL_RGB32UI, + + /** + * RGBA, each component non-normalized unsigned int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA32UI = GL_RGBA32UI, + + /** + * Red component, non-normalized signed int. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R32I = GL_R32I, + + /** + * Red and green component, each non-normalized signed int. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG32I = GL_RG32I, + + /** + * RGB, each component non-normalized signed int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB32I = GL_RGB32I, + + /** + * RGBA, each component non-normalized signed int. + * @requires_gl30 %Extension @extension{EXT,texture_integer} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA32I = GL_RGBA32I, + + /** + * Red component, half float. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R16F = GL_R16F, + + /** + * Red and green component, each half float. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG16F = GL_RG16F, + + /** + * RGB, each component half float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB16F = GL_RGB16F, + + /** + * RGBA, each component half float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA16F = GL_RGBA16F, + + /** + * Red component, float. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R32F = GL_R32F, + + /** + * Red and green component, each float. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RG32F = GL_RG32F, + + /** + * RGB, each component float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB32F = GL_RGB32F, + + /** + * RGBA, each component float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGBA32F = GL_RGBA32F, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * RGB, normalized unsigned, red and green component 3bit, blue 2bit. + * @requires_gl Packed 8bit types are not available in OpenGL ES. + */ + R3B3G2 = GL_R3_G3_B2, + + /** + * RGB, each component normalized unsigned 4bit. + * @requires_gl Packed 12bit types are not available in OpenGL ES. + */ + RGB4 = GL_RGB4, + + /** + * RGB, each component normalized unsigned 5bit. + * @requires_gl Use @ref Magnum::TextureFormat "TextureFormat::RGB5A1" or + * @ref Magnum::TextureFormat "TextureFormat::RGB565" in OpenGL ES. + */ + RGB5 = GL_RGB5, + #endif + + /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is + GL_ARB_ES2_compatibility */ + #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * RGB, normalized unsigned, red and blue component 5bit, green 6bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + */ + RGB565 = GL_RGB565, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * RGB, each component normalized unsigned 10bit. + * @requires_es_extension %Extension @es_extension{OES,required_internalformat} + * and @es_extension{EXT,texture_type_2_10_10_10_REV} + */ + #ifndef MAGNUM_TARGET_GLES + RGB10 = GL_RGB10, + #else + RGB10 = GL_RGB10_EXT, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * RGB, each component normalized unsigned 12bit. + * @requires_gl Packed 36bit types are not available in OpenGL ES. + */ + RGB12 = GL_RGB12, + + /** + * RGBA, normalized unsigned, each component 2bit. + * @requires_gl Packed 8bit types are not available in OpenGL ES. + */ + RGBA2 = GL_RGBA2, + #endif + + /** + * RGBA, normalized unsigned, each component 4bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + */ + RGBA4 = GL_RGBA4, + + /** + * RGBA, normalized unsigned, each RGB component 5bit, alpha 1bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + */ + 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} + */ + #ifndef MAGNUM_TARGET_GLES2 + RGB10A2 = GL_RGB10_A2, + #else + RGB10A2 = GL_RGB10_A2_EXT, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * RGBA, non-normalized unsigned, each RGB component 10bit, alpha 2bit. + * @requires_gl33 %Extension @extension{ARB,texture_rgb10_a2ui} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + RGB10A2UI = GL_RGB10_A2UI, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * RGBA, each component normalized unsigned 12bit. + * @requires_gl Packed 48bit types are not available in OpenGL ES. + */ + RGBA12 = GL_RGBA12, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * RGB, float, red and green component 11bit, blue 10bit. + * @requires_gl30 %Extension @extension{EXT,packed_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R11FG11FB10F = GL_R11F_G11F_B10F, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * RGB, unsigned with exponent, each RGB component 9bit, exponent 5bit. + * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::RGB" in + * OpenGL ES 2.0 instead. + */ + RGB9E5 = GL_RGB9_E5, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * sRGB, normalized unsigned, size implementation-dependent. + * @todo is this allowed in core? + * @deprecated Prefer to use the exactly specified version of this format, + * i.e. @ref Magnum::TextureFormat "TextureFormat::SRGB8". + * @requires_es_extension %Extension @es_extension{EXT,sRGB} in OpenGL ES + * 2.0, use @ref Magnum::TextureFormat "TextureFormat::SRGB8" in + * OpenGL ES 3.0 instead. + */ + #ifndef MAGNUM_TARGET_GLES + SRGB = GL_SRGB, + #else + SRGB = GL_SRGB_EXT, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * sRGB, each component normalized unsigned byte. + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::SRGB" in + * OpenGL ES 2.0 instead. + */ + SRGB8 = GL_SRGB8, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * sRGBA, normalized unsigned, size implementation-dependent. + * @todo is this allowed in core? + * @deprecated Prefer to use the exactly specified version of this format, + * i.e. @ref Magnum::TextureFormat "TextureFormat::SRGB8Alpha8". + * @requires_es_extension %Extension @es_extension{EXT,sRGB} in OpenGL ES + * 2.0, use @ref Magnum::TextureFormat "TextureFormat::SRGB8Alpha8" in + * OpenGL ES 3.0 instead. + */ + #ifndef MAGNUM_TARGET_GLES + SRGBAlpha = GL_SRGB_ALPHA, + #else + SRGBAlpha = GL_SRGB_ALPHA_EXT, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * sRGBA, each component normalized unsigned byte. + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::SRGBAlpha" + * in OpenGL ES 2.0 instead. + */ + SRGB8Alpha8 = GL_SRGB8_ALPHA8, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Compressed red channel, normalized unsigned. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Generic texture compression is not available in OpenGL ES. + */ + CompressedRed = GL_COMPRESSED_RED, + + /** + * Compressed red and green channel, normalized unsigned. + * @requires_gl30 %Extension @extension{ARB,texture_rg} + * @requires_gl Generic texture compression is not available in OpenGL ES. + */ + CompressedRG = GL_COMPRESSED_RG, + + /** + * Compressed RGB, normalized unsigned. + * @requires_gl Generic texture compression is not available in OpenGL ES. + */ + CompressedRGB = GL_COMPRESSED_RGB, + + /** + * Compressed RGBA, normalized unsigned. + * @requires_gl Generic texture compression is not available in OpenGL ES. + */ + CompressedRGBA = GL_COMPRESSED_RGBA, + + /** + * RTGC compressed red channel, normalized unsigned. + * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} + * @requires_gl RGTC texture compression is not available in OpenGL ES. + */ + CompressedRedRtgc1 = GL_COMPRESSED_RED_RGTC1, + + /** + * RTGC compressed red and green channel, normalized unsigned. + * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} + * @requires_gl RGTC texture compression is not available in OpenGL ES. + */ + CompressedRGRgtc2 = GL_COMPRESSED_RG_RGTC2, + + /** + * RTGC compressed red channel, normalized signed. + * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} + * @requires_gl RGTC texture compression is not available in OpenGL ES. + */ + CompressedSignedRedRgtc1 = GL_COMPRESSED_SIGNED_RED_RGTC1, + + /** + * RTGC compressed red and green channel, normalized signed. + * @requires_gl30 %Extension @extension{EXT,texture_compression_rgtc} + * @requires_gl RGTC texture compression is not available in OpenGL ES. + */ + CompressedSignedRGRgtc2 = GL_COMPRESSED_SIGNED_RG_RGTC2, + + /* These are named with _ARB suffix, because glcorearb.h doesn't + have suffixless version (?!) and GLEW has it without suffix as + late as of 1.8.0 { */ + + /** + * BPTC compressed RGBA, normalized unsigned. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in OpenGL ES. + */ + CompressedRGBABtpcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, + + /** + * BPTC compressed sRGBA, normalized unsigned. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in OpenGL ES. + */ + CompressedSRGBAlphaBtpcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, + + /** + * BPTC compressed RGB, unsigned float. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in OpenGL ES. + */ + CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, + + /** + * BPTC compressed RGB, signed float. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in OpenGL ES. + */ + CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, + + /*}*/ + #endif + + /** + * Depth component, size implementation-dependent. + * @deprecated Prefer to use exactly specified version of this format, e.g. + * @ref Magnum::TextureFormat "TextureFormat::DepthComponent16". + * @requires_gles30 %Extension @es_extension{OES,depth_texture} or + * @es_extension{ANGLE,depth_texture} + */ + DepthComponent = GL_DEPTH_COMPONENT, + + /** + * Depth and stencil component, size implementation-dependent. + * @deprecated Prefer to use exactly specified version of this format, e.g. + * @ref Magnum::TextureFormat "TextureFormat::Depth24Stencil8". + * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} + */ + #ifndef MAGNUM_TARGET_GLES2 + DepthStencil = GL_DEPTH_STENCIL, + #else + DepthStencil = GL_DEPTH_STENCIL_OES, + #endif + + /** + * Depth component, 16bit. + * @requires_gles30 %Extension (@es_extension{OES,required_internalformat} + * and @es_extension{OES,depth_texture}) or (@es_extension{EXT,texture_storage} + * and @es_extension{ANGLE,depth_texture}) + */ + DepthComponent16 = GL_DEPTH_COMPONENT16, + + /** + * Depth component, 24bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat}, + * @es_extension{OES,depth_texture} and @es_extension{OES,depth24} + */ + #ifndef MAGNUM_TARGET_GLES2 + DepthComponent24 = GL_DEPTH_COMPONENT24, + #else + DepthComponent24 = GL_DEPTH_COMPONENT24_OES, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * Depth component, 32bit. + * @requires_es_extension %Extension (@es_extension{OES,required_internalformat}, + * @es_extension{OES,depth_texture} and @es_extension{OES,depth32}) or + * (@es_extension{EXT,texture_storage} and @es_extension{ANGLE,depth_texture}) + */ + #ifndef MAGNUM_TARGET_GLES2 + DepthComponent32 = GL_DEPTH_COMPONENT32, + #else + DepthComponent32 = GL_DEPTH_COMPONENT32_OES, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Depth component, 32bit float. + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 Only integral depth textures are available in OpenGL ES + * 2.0. + */ + DepthComponent32F = GL_DEPTH_COMPONENT32F, + #endif + + /** + * 24bit depth and 8bit stencil component. + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @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})) + */ + #ifdef MAGNUM_TARGET_GLES2 + Depth24Stencil8 = GL_DEPTH24_STENCIL8_OES + #else + Depth24Stencil8 = GL_DEPTH24_STENCIL8, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * 32bit float depth component and 8bit stencil component. + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 Only integral depth textures are available in OpenGL ES + * 2.0. + */ + Depth32FStencil8 = GL_DEPTH32F_STENCIL8 + #endif +}; + +} + +#endif diff --git a/src/TextureTools/CMakeLists.txt b/src/TextureTools/CMakeLists.txt index fdede4e15..b2237b57b 100644 --- a/src/TextureTools/CMakeLists.txt +++ b/src/TextureTools/CMakeLists.txt @@ -22,9 +22,7 @@ # DEALINGS IN THE SOFTWARE. # -corrade_add_resource(MagnumTextureTools_RCS MagnumTextureTools - DistanceFieldShader.vert DistanceFieldShader.frag - ../Shaders/compatibility.glsl ALIAS compatibility.glsl) +corrade_add_resource(MagnumTextureTools_RCS resources.conf) set(MagnumTextureTools_SRCS Atlas.cpp diff --git a/src/TextureTools/DistanceField.cpp b/src/TextureTools/DistanceField.cpp index c2804541c..fbc1eeee6 100644 --- a/src/TextureTools/DistanceField.cpp +++ b/src/TextureTools/DistanceField.cpp @@ -45,12 +45,12 @@ class DistanceFieldShader: public AbstractShaderProgram { explicit DistanceFieldShader(); - inline DistanceFieldShader* setRadius(Int radius) { + DistanceFieldShader* setRadius(Int radius) { setUniform(radiusUniform, radius); return this; } - inline DistanceFieldShader* setScaling(Vector2 scaling) { + DistanceFieldShader* setScaling(Vector2 scaling) { setUniform(scalingUniform, scaling); return this; } @@ -68,15 +68,20 @@ DistanceFieldShader::DistanceFieldShader() { /** @todo compatibility! */ - Corrade::Utility::Resource rs("MagnumTextureTools"); - attachShader(Shader::fromData(Version::GL330, Shader::Type::Vertex, rs.get("DistanceFieldShader.vert"))); + Utility::Resource rs("MagnumTextureTools"); - Shader fragmentShader(Version::GL330, Shader::Type::Fragment); - fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get("DistanceFieldShader.frag")); - attachShader(fragmentShader); + Shader vert(Version::GL330, Shader::Type::Vertex); + vert.addSource(rs.get("DistanceFieldShader.vert")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); - link(); + Shader frag(Version::GL330, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("DistanceFieldShader.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); + + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } } @@ -88,7 +93,7 @@ void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectan Framebuffer framebuffer(rectangle); framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), output, 0); - framebuffer.bind(Framebuffer::Target::Draw); + framebuffer.bind(FramebufferTarget::Draw); DistanceFieldShader shader; shader.setRadius(radius) diff --git a/src/TextureTools/Test/AtlasTest.cpp b/src/TextureTools/Test/AtlasTest.cpp index 553906193..3c582cff4 100644 --- a/src/TextureTools/Test/AtlasTest.cpp +++ b/src/TextureTools/Test/AtlasTest.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace TextureTools { namespace Test { -class AtlasTest: public Corrade::TestSuite::Tester { +class AtlasTest: public TestSuite::Tester { public: explicit AtlasTest(); diff --git a/src/TextureTools/magnumTextureToolsResourceImport.hpp b/src/TextureTools/magnumTextureToolsResourceImport.hpp index d540e7536..fa62dded2 100644 --- a/src/TextureTools/magnumTextureToolsResourceImport.hpp +++ b/src/TextureTools/magnumTextureToolsResourceImport.hpp @@ -29,9 +29,9 @@ #ifdef MAGNUM_BUILD_STATIC #include static int magnumTextureToolsResourceImport() { - RESOURCE_INITIALIZE(MagnumTextureTools_RCS) + CORRADE_RESOURCE_INITIALIZE(MagnumTextureTools_RCS) return 0; -} AUTOMATIC_INITIALIZER(magnumTextureToolsResourceImport) +} CORRADE_AUTOMATIC_INITIALIZER(magnumTextureToolsResourceImport) #endif #endif diff --git a/src/TextureTools/resources.conf b/src/TextureTools/resources.conf new file mode 100644 index 000000000..71a74be59 --- /dev/null +++ b/src/TextureTools/resources.conf @@ -0,0 +1,11 @@ +group=MagnumTextureTools + +[file] +filename=DistanceFieldShader.vert + +[file] +filename=DistanceFieldShader.frag + +[file] +filename=../Shaders/compatibility.glsl +alias=compatibility.glsl diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 2df6f5e74..94cecc19f 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -27,6 +27,8 @@ #include #include +#include "Magnum.h" + using namespace std::chrono; namespace Magnum { @@ -53,7 +55,7 @@ void Timeline::nextFrame() { _previousFrameDuration = duration/1e6f; if(_previousFrameDuration < _minimalFrameTime) { - Corrade::Utility::sleep(_minimalFrameTime*1000 - duration/1000); + Utility::sleep(_minimalFrameTime*1000 - duration/1000); now = high_resolution_clock::now(); _previousFrameDuration = duration_cast(now-_previousFrameTime).count()/1e6f; } diff --git a/src/Timeline.h b/src/Timeline.h index 4fde2a561..35b9ac0bd 100644 --- a/src/Timeline.h +++ b/src/Timeline.h @@ -63,8 +63,8 @@ Example usage: MyApplication::MyApplication(const Parameters& parameters): Platform::Application(parameters) { // Initialization ... - timeline.setMinimalFrameTime(1/120.0f); // 120 FPS at max - timeline.start(); + timeline.setMinimalFrameTime(1/120.0f) // 120 FPS at max + ->start(); } void MyApplication::drawEvent() { @@ -78,6 +78,9 @@ void MyApplication::drawEvent() { timeline.nextFrame(); } @endcode +@todo FPS should be governed by Application (imagine more than one simultaenous + timeline and the harm it could do, also vsync etc. can't be handled in + platform-independent way here) */ class MAGNUM_EXPORT Timeline { public: @@ -87,21 +90,21 @@ class MAGNUM_EXPORT Timeline { * Creates stopped timeline. * @see start() */ - inline constexpr explicit Timeline(): _minimalFrameTime(0), _previousFrameDuration(0), running(false) {} + explicit Timeline(): _minimalFrameTime(0), _previousFrameDuration(0), running(false) {} /** @brief Minimal frame time (in seconds) */ - inline constexpr Float minimalFrameTime() const { - return _minimalFrameTime; - } + Float minimalFrameTime() const { return _minimalFrameTime; } /** * @brief Set minimal frame time + * @return Pointer to self (for method chaining) * * Default value is 0. * @see nextFrame() */ - inline void setMinimalFrameTime(Float seconds) { + Timeline* setMinimalFrameTime(Float seconds) { _minimalFrameTime = seconds; + return this; } /** @@ -142,9 +145,7 @@ class MAGNUM_EXPORT Timeline { * * If the timeline is stopped, the function returns `0.0f`. */ - inline constexpr Float previousFrameDuration() const { - return _previousFrameDuration; - } + Float previousFrameDuration() const { return _previousFrameDuration; } private: std::chrono::high_resolution_clock::time_point _startTime; diff --git a/src/Trade/AbstractImageConverter.cpp b/src/Trade/AbstractImageConverter.cpp index bb743ff92..ec548d374 100644 --- a/src/Trade/AbstractImageConverter.cpp +++ b/src/Trade/AbstractImageConverter.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace Trade { AbstractImageConverter::AbstractImageConverter() = default; -AbstractImageConverter::AbstractImageConverter(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)) {} +AbstractImageConverter::AbstractImageConverter(PluginManager::AbstractManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)) {} Image2D* AbstractImageConverter::convertToImage(const Image2D* const) const { CORRADE_ASSERT(features() & Feature::ConvertToImage, diff --git a/src/Trade/AbstractImageConverter.h b/src/Trade/AbstractImageConverter.h index b0870c87b..b2826b96c 100644 --- a/src/Trade/AbstractImageConverter.h +++ b/src/Trade/AbstractImageConverter.h @@ -48,8 +48,8 @@ Plugin implements function features() and one or more of convertToImage(), convertToData() or convertToFile() functions based on what features are supported. */ -class MAGNUM_EXPORT AbstractImageConverter: public Corrade::PluginManager::AbstractPlugin { - PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImageConverter/0.1") +class MAGNUM_EXPORT AbstractImageConverter: public PluginManager::AbstractPlugin { + CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImageConverter/0.1") public: /** @@ -73,13 +73,13 @@ class MAGNUM_EXPORT AbstractImageConverter: public Corrade::PluginManager::Abstr * * @see features() */ - typedef Corrade::Containers::EnumSet Features; + typedef Containers::EnumSet Features; /** @brief Default constructor */ explicit AbstractImageConverter(); /** @brief Plugin manager constructor */ - explicit AbstractImageConverter(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin); + explicit AbstractImageConverter(PluginManager::AbstractManager* manager, std::string plugin); /** @brief Features supported by this converter */ virtual Features features() const = 0; diff --git a/src/Trade/AbstractImporter.cpp b/src/Trade/AbstractImporter.cpp index ce792335c..f0319dd51 100644 --- a/src/Trade/AbstractImporter.cpp +++ b/src/Trade/AbstractImporter.cpp @@ -30,7 +30,7 @@ namespace Magnum { namespace Trade { AbstractImporter::AbstractImporter() = default; -AbstractImporter::AbstractImporter(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)) {} +AbstractImporter::AbstractImporter(PluginManager::AbstractManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)) {} bool AbstractImporter::openData(const void* const, const std::size_t) { CORRADE_ASSERT(features() & Feature::OpenData, diff --git a/src/Trade/AbstractImporter.h b/src/Trade/AbstractImporter.h index 54233c69b..85dde6362 100644 --- a/src/Trade/AbstractImporter.h +++ b/src/Trade/AbstractImporter.h @@ -31,9 +31,9 @@ #include #include -#include "Trade/Trade.h" - +#include "Magnum.h" #include "magnumVisibility.h" +#include "Trade/Trade.h" namespace Magnum { namespace Trade { @@ -53,8 +53,8 @@ be done in data parsing functions, because the user might want to import only some data. This is obviously not the case for single-data formats like images, as the file contains all data user wants to import. */ -class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlugin { - PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImporter/0.2.1") +class MAGNUM_EXPORT AbstractImporter: public PluginManager::AbstractPlugin { + CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImporter/0.2.1") public: /** @@ -68,13 +68,13 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu }; /** @brief Set of features supported by this importer */ - typedef Corrade::Containers::EnumSet Features; + typedef Containers::EnumSet Features; /** @brief Default constructor */ explicit AbstractImporter(); /** @brief Plugin manager constructor */ - explicit AbstractImporter(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin); + explicit AbstractImporter(PluginManager::AbstractManager* manager, std::string plugin); /** @brief Features supported by this importer */ virtual Features features() const = 0; @@ -98,7 +98,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu * Convenience alternative to above function useful when array size is * known at compile-time. */ - template inline bool openData(const T(&data)[size]) { + template bool openData(const T(&data)[size]) { return openData(data, size*sizeof(T)); } @@ -129,10 +129,10 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu * @note The function is not const, because the value will probably * be lazy-populated. */ - virtual inline Int defaultScene() { return -1; } + virtual Int defaultScene() { return -1; } /** @brief %Scene count */ - virtual inline UnsignedInt sceneCount() const { return 0; } + virtual UnsignedInt sceneCount() const { return 0; } /** * @brief %Scene ID for given name @@ -160,7 +160,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual SceneData* scene(UnsignedInt id); /** @brief %Light count */ - virtual inline UnsignedInt lightCount() const { return 0; } + virtual UnsignedInt lightCount() const { return 0; } /** * @brief %Light ID for given name @@ -188,7 +188,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual LightData* light(UnsignedInt id); /** @brief Camera count */ - virtual inline UnsignedInt cameraCount() const { return 0; } + virtual UnsignedInt cameraCount() const { return 0; } /** * @brief Camera ID for given name @@ -216,7 +216,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual CameraData* camera(UnsignedInt id); /** @brief Two-dimensional object count */ - virtual inline UnsignedInt object2DCount() const { return 0; } + virtual UnsignedInt object2DCount() const { return 0; } /** * @brief Two-dimensional object ID for given name @@ -244,7 +244,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual ObjectData2D* object2D(UnsignedInt id); /** @brief Three-dimensional object count */ - virtual inline UnsignedInt object3DCount() const { return 0; } + virtual UnsignedInt object3DCount() const { return 0; } /** * @brief Three-dimensional object ID for given name @@ -272,7 +272,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual ObjectData3D* object3D(UnsignedInt id); /** @brief Two-dimensional mesh count */ - virtual inline UnsignedInt mesh2DCount() const { return 0; } + virtual UnsignedInt mesh2DCount() const { return 0; } /** * @brief Two-dimensional mesh ID for given name @@ -300,7 +300,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual MeshData2D* mesh2D(UnsignedInt id); /** @brief Three-dimensional mesh count */ - virtual inline UnsignedInt mesh3DCount() const { return 0; } + virtual UnsignedInt mesh3DCount() const { return 0; } /** * @brief Three-dimensional mesh ID for given name @@ -328,7 +328,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual MeshData3D* mesh3D(UnsignedInt id); /** @brief Material count */ - virtual inline UnsignedInt materialCount() const { return 0; } + virtual UnsignedInt materialCount() const { return 0; } /** * @brief Material ID for given name @@ -356,7 +356,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual AbstractMaterialData* material(UnsignedInt id); /** @brief %Texture count */ - virtual inline UnsignedInt textureCount() const { return 0; } + virtual UnsignedInt textureCount() const { return 0; } /** * @brief %Texture ID for given name @@ -384,7 +384,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual TextureData* texture(UnsignedInt id); /** @brief One-dimensional image count */ - virtual inline UnsignedInt image1DCount() const { return 0; } + virtual UnsignedInt image1DCount() const { return 0; } /** * @brief One-dimensional image ID for given name @@ -412,7 +412,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual ImageData1D* image1D(UnsignedInt id); /** @brief Two-dimensional image count */ - virtual inline UnsignedInt image2DCount() const { return 0; } + virtual UnsignedInt image2DCount() const { return 0; } /** * @brief Two-dimensional image ID for given name @@ -440,7 +440,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlu virtual ImageData2D* image2D(UnsignedInt id); /** @brief Three-dimensional image count */ - virtual inline UnsignedInt image3DCount() const { return 0; } + virtual UnsignedInt image3DCount() const { return 0; } /** * @brief Three-dimensional image ID for given name diff --git a/src/Trade/AbstractMaterialData.h b/src/Trade/AbstractMaterialData.h index 7b26ee0b8..4c4cd9903 100644 --- a/src/Trade/AbstractMaterialData.h +++ b/src/Trade/AbstractMaterialData.h @@ -59,7 +59,7 @@ class MAGNUM_EXPORT AbstractMaterialData { virtual ~AbstractMaterialData() = 0; /** @brief Material type */ - inline Type type() const { return _type; } + Type type() const { return _type; } private: Type _type; diff --git a/src/Trade/ImageData.h b/src/Trade/ImageData.h index dbc6a548b..ab134a96a 100644 --- a/src/Trade/ImageData.h +++ b/src/Trade/ImageData.h @@ -55,17 +55,17 @@ template class ImageData: public AbstractImage { * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - inline explicit ImageData(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} + explicit ImageData(const typename DimensionTraits::VectorType& size, ImageFormat format, ImageType type, void* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} /** @brief Destructor */ - inline ~ImageData() { delete[] _data; } + ~ImageData() { delete[] _data; } /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + typename DimensionTraits::VectorType size() const { return _size; } /** @brief Pointer to raw data */ - inline unsigned char* data() { return _data; } - inline const unsigned char* data() const { return _data; } /**< @overload */ + unsigned char* data() { return _data; } + const unsigned char* data() const { return _data; } /**< @overload */ private: Math::Vector _size; diff --git a/src/Trade/MeshData2D.h b/src/Trade/MeshData2D.h index 97369a79e..d8a910460 100644 --- a/src/Trade/MeshData2D.h +++ b/src/Trade/MeshData2D.h @@ -68,17 +68,17 @@ class MAGNUM_EXPORT MeshData2D { MeshData2D& operator=(MeshData2D&&); /** @brief Primitive */ - inline Mesh::Primitive primitive() const { return _primitive; } + Mesh::Primitive primitive() const { return _primitive; } /** * @brief Indices * @return Indices or nullptr if the mesh is not indexed. */ - inline std::vector* indices() { return _indices; } - inline const std::vector* indices() const { return _indices; } /**< @overload */ + std::vector* indices() { return _indices; } + const std::vector* indices() const { return _indices; } /**< @overload */ /** @brief Count of vertex position arrays */ - inline UnsignedInt positionArrayCount() const { return _positions.size(); } + UnsignedInt positionArrayCount() const { return _positions.size(); } /** * @brief Positions @@ -86,11 +86,11 @@ class MAGNUM_EXPORT MeshData2D { * @return Positions or nullptr if there is no vertex array with given * ID. */ - inline std::vector* positions(UnsignedInt id) { return _positions[id]; } - inline const std::vector* positions(UnsignedInt id) const { return _positions[id]; } /**< @overload */ + std::vector* positions(UnsignedInt id) { return _positions[id]; } + const std::vector* positions(UnsignedInt id) const { return _positions[id]; } /**< @overload */ /** @brief Count of 2D texture coordinate arrays */ - inline UnsignedInt textureCoords2DArrayCount() const { return _textureCoords2D.size(); } + UnsignedInt textureCoords2DArrayCount() const { return _textureCoords2D.size(); } /** * @brief 2D texture coordinates @@ -98,8 +98,8 @@ class MAGNUM_EXPORT MeshData2D { * @return %Texture coordinates or nullptr if there is no texture * coordinates array with given ID. */ - inline std::vector* textureCoords2D(UnsignedInt id) { return _textureCoords2D[id]; } - inline const std::vector* textureCoords2D(UnsignedInt id) const { return _textureCoords2D[id]; } /**< @overload */ + std::vector* textureCoords2D(UnsignedInt id) { return _textureCoords2D[id]; } + const std::vector* textureCoords2D(UnsignedInt id) const { return _textureCoords2D[id]; } /**< @overload */ private: Mesh::Primitive _primitive; diff --git a/src/Trade/MeshData3D.h b/src/Trade/MeshData3D.h index 61e02e807..64271f2a0 100644 --- a/src/Trade/MeshData3D.h +++ b/src/Trade/MeshData3D.h @@ -69,17 +69,17 @@ class MAGNUM_EXPORT MeshData3D { MeshData3D& operator=(MeshData3D&&); /** @brief Primitive */ - inline Mesh::Primitive primitive() const { return _primitive; } + Mesh::Primitive primitive() const { return _primitive; } /** * @brief Indices * @return Indices or nullptr if the mesh is not indexed. */ - inline std::vector* indices() { return _indices; } - inline const std::vector* indices() const { return _indices; } /**< @overload */ + std::vector* indices() { return _indices; } + const std::vector* indices() const { return _indices; } /**< @overload */ /** @brief Count of vertex position arrays */ - inline UnsignedInt positionArrayCount() const { return _positions.size(); } + UnsignedInt positionArrayCount() const { return _positions.size(); } /** * @brief Positions @@ -87,11 +87,11 @@ class MAGNUM_EXPORT MeshData3D { * @return Positions or nullptr if there is no vertex array with given * ID. */ - inline std::vector* positions(UnsignedInt id) { return _positions[id]; } - inline const std::vector* positions(UnsignedInt id) const { return _positions[id]; } /**< @overload */ + std::vector* positions(UnsignedInt id) { return _positions[id]; } + const std::vector* positions(UnsignedInt id) const { return _positions[id]; } /**< @overload */ /** @brief Count of normal arrays */ - inline UnsignedInt normalArrayCount() const { return _normals.size(); } + UnsignedInt normalArrayCount() const { return _normals.size(); } /** * @brief Normals @@ -99,11 +99,11 @@ class MAGNUM_EXPORT MeshData3D { * @return Normals or nullptr if there is no normal array with given * ID. */ - inline std::vector* normals(UnsignedInt id) { return _normals[id]; } - inline const std::vector* normals(UnsignedInt id) const { return _normals[id]; } /**< @overload */ + std::vector* normals(UnsignedInt id) { return _normals[id]; } + const std::vector* normals(UnsignedInt id) const { return _normals[id]; } /**< @overload */ /** @brief Count of 2D texture coordinate arrays */ - inline UnsignedInt textureCoords2DArrayCount() const { return _textureCoords2D.size(); } + UnsignedInt textureCoords2DArrayCount() const { return _textureCoords2D.size(); } /** * @brief 2D texture coordinates @@ -111,8 +111,8 @@ class MAGNUM_EXPORT MeshData3D { * @return %Texture coordinates or nullptr if there is no texture * coordinates array with given ID. */ - inline std::vector* textureCoords2D(UnsignedInt id) { return _textureCoords2D[id]; } - inline const std::vector* textureCoords2D(UnsignedInt id) const { return _textureCoords2D[id]; } /**< @overload */ + std::vector* textureCoords2D(UnsignedInt id) { return _textureCoords2D[id]; } + const std::vector* textureCoords2D(UnsignedInt id) const { return _textureCoords2D[id]; } /**< @overload */ private: Mesh::Primitive _primitive; diff --git a/src/Trade/MeshObjectData2D.h b/src/Trade/MeshObjectData2D.h index bbe38cd0c..b250e28df 100644 --- a/src/Trade/MeshObjectData2D.h +++ b/src/Trade/MeshObjectData2D.h @@ -57,7 +57,7 @@ class MAGNUM_EXPORT MeshObjectData2D: public ObjectData2D { explicit MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, UnsignedInt material); /** @brief Material ID */ - inline UnsignedInt material() const { return _material; } + UnsignedInt material() const { return _material; } private: UnsignedInt _material; diff --git a/src/Trade/MeshObjectData3D.h b/src/Trade/MeshObjectData3D.h index 636ad52b1..e29250553 100644 --- a/src/Trade/MeshObjectData3D.h +++ b/src/Trade/MeshObjectData3D.h @@ -57,7 +57,7 @@ class MAGNUM_EXPORT MeshObjectData3D: public ObjectData3D { explicit MeshObjectData3D(std::vector children, const Matrix4& transformation, UnsignedInt instance, UnsignedInt material); /** @brief Material ID */ - inline UnsignedInt material() const { return _material; } + UnsignedInt material() const { return _material; } private: UnsignedInt _material; diff --git a/src/Trade/ObjectData2D.h b/src/Trade/ObjectData2D.h index 46d2305f3..ec44b0181 100644 --- a/src/Trade/ObjectData2D.h +++ b/src/Trade/ObjectData2D.h @@ -76,10 +76,10 @@ class MAGNUM_EXPORT ObjectData2D { virtual ~ObjectData2D(); /** @brief Child objects */ - inline std::vector& children() { return _children; } + std::vector& children() { return _children; } /** @brief Transformation (relative to parent) */ - inline Matrix3 transformation() const { return _transformation; } + Matrix3 transformation() const { return _transformation; } /** * @brief Instance type @@ -88,14 +88,14 @@ class MAGNUM_EXPORT ObjectData2D { * If the instance is of type InstanceType::Mesh, the instance can be * casted to MeshObjectData2D and provide more information. */ - inline InstanceType instanceType() const { return _instanceType; } + InstanceType instanceType() const { return _instanceType; } /** * @brief Instance ID * @return ID of given camera / light / mesh etc., specified by * instanceType() */ - inline Int instanceId() const { return _instanceId; } + Int instanceId() const { return _instanceId; } private: std::vector _children; diff --git a/src/Trade/ObjectData3D.h b/src/Trade/ObjectData3D.h index f6ac02923..a2ccffe21 100644 --- a/src/Trade/ObjectData3D.h +++ b/src/Trade/ObjectData3D.h @@ -74,13 +74,13 @@ class MAGNUM_EXPORT ObjectData3D { explicit ObjectData3D(std::vector children, const Matrix4& transformation); /** @brief Destructor */ - inline virtual ~ObjectData3D() {} + virtual ~ObjectData3D() {} /** @brief Child objects */ - inline std::vector& children() { return _children; } + std::vector& children() { return _children; } /** @brief Transformation (relative to parent) */ - inline Matrix4 transformation() const { return _transformation; } + Matrix4 transformation() const { return _transformation; } /** * @brief Instance type @@ -89,14 +89,14 @@ class MAGNUM_EXPORT ObjectData3D { * If the instance is of type InstanceType::Mesh, the instance can be * casted to MeshObjectData3D and provide more information. */ - inline InstanceType instanceType() const { return _instanceType; } + InstanceType instanceType() const { return _instanceType; } /** * @brief Instance ID * @return ID of given camera / light / mesh etc., specified by * instanceType() */ - inline Int instanceId() const { return _instanceId; } + Int instanceId() const { return _instanceId; } private: std::vector _children; diff --git a/src/Trade/PhongMaterialData.h b/src/Trade/PhongMaterialData.h index dec88b406..d648c51ee 100644 --- a/src/Trade/PhongMaterialData.h +++ b/src/Trade/PhongMaterialData.h @@ -49,16 +49,16 @@ class MAGNUM_EXPORT PhongMaterialData: public AbstractMaterialData { explicit PhongMaterialData(const Vector3& ambientColor, const Vector3& diffuseColor, const Vector3& specularColor, Float shininess); /** @brief Ambient color */ - inline Vector3 ambientColor() const { return _ambientColor; } + Vector3 ambientColor() const { return _ambientColor; } /** @brief Diffuse color */ - inline Vector3 diffuseColor() const { return _diffuseColor; } + Vector3 diffuseColor() const { return _diffuseColor; } /** @brief Specular color */ - inline Vector3 specularColor() const { return _specularColor; } + Vector3 specularColor() const { return _specularColor; } /** @brief Shininess */ - inline Float shininess() const { return _shininess; } + Float shininess() const { return _shininess; } private: Vector3 _ambientColor, diff --git a/src/Trade/SceneData.h b/src/Trade/SceneData.h index 66b33c21a..ba81ff8c8 100644 --- a/src/Trade/SceneData.h +++ b/src/Trade/SceneData.h @@ -54,10 +54,10 @@ class MAGNUM_EXPORT SceneData { explicit SceneData(std::vector children2D, std::vector children3D); /** @brief Two-dimensional child objects */ - inline const std::vector& children2D() const { return _children2D; } + const std::vector& children2D() const { return _children2D; } /** @brief Three-dimensional child objects */ - inline const std::vector& children3D() const { return _children3D; } + const std::vector& children3D() const { return _children3D; } private: std::vector _children2D, diff --git a/src/Trade/Test/ObjectData2DTest.cpp b/src/Trade/Test/ObjectData2DTest.cpp index 75c377943..4161386b4 100644 --- a/src/Trade/Test/ObjectData2DTest.cpp +++ b/src/Trade/Test/ObjectData2DTest.cpp @@ -29,7 +29,7 @@ namespace Magnum { namespace Trade { namespace Test { -class ObjectData2DTest: public Corrade::TestSuite::Tester { +class ObjectData2DTest: public TestSuite::Tester { public: explicit ObjectData2DTest(); diff --git a/src/Trade/Test/ObjectData3DTest.cpp b/src/Trade/Test/ObjectData3DTest.cpp index f723262c5..8cb6d1332 100644 --- a/src/Trade/Test/ObjectData3DTest.cpp +++ b/src/Trade/Test/ObjectData3DTest.cpp @@ -29,7 +29,7 @@ namespace Magnum { namespace Trade { namespace Test { -class ObjectData3DTest: public Corrade::TestSuite::Tester { +class ObjectData3DTest: public TestSuite::Tester { public: explicit ObjectData3DTest(); diff --git a/src/Types.h b/src/Types.h index d8e04bb65..18627ff63 100644 --- a/src/Types.h +++ b/src/Types.h @@ -43,6 +43,8 @@ typedef std::uint32_t UnsignedInt; typedef std::int32_t Int; typedef std::uint64_t UnsignedLong; typedef std::int64_t Long; + +/** @todo C++14: use std::float32_t and std::float_64t [N3626](http://open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3626.pdf) */ typedef float Float; #ifndef MAGNUM_TARGET_GLES