diff --git a/.gitignore b/.gitignore index 20c227ec1..d1ef973af 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ build* pkg *.kdev4 *~ +*.kate-swp *.pkg.tar.xz +CMakeLists.txt.user* diff --git a/CMakeLists.txt b/CMakeLists.txt index a9222b42f..bfa00704c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,27 @@ +# +# 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. +# + # CMake 2.8.8 required for OBJECT library target cmake_minimum_required(VERSION 2.8) project(Magnum) @@ -6,29 +30,39 @@ include(CMakeDependentOption) option(TARGET_GLES "Build for OpenGL ES instead of desktop OpenGL" OFF) cmake_dependent_option(TARGET_GLES2 "Build for OpenGL ES 2" ON "TARGET_GLES" OFF) +cmake_dependent_option(TARGET_DESKTOP_GLES "Build for OpenGL ES on desktop" OFF "TARGET_GLES" OFF) # Parts of the library -option(WITH_EVERYTHING "Build everything (doesn't include contexts)" ON) -cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" OFF "NOT WITH_EVERYTHING" ON) -cmake_dependent_option(WITH_PHYSICS "Build Physics library" OFF "NOT WITH_EVERYTHING" ON) -cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" OFF "NOT WITH_EVERYTHING" ON) -cmake_dependent_option(WITH_SCENEGRAPH "Build SceneGraph library" OFF "NOT WITH_EVERYTHING;NOT WITH_PHYSICS" ON) -cmake_dependent_option(WITH_SHADERS "Build Shaders library" OFF "NOT WITH_EVERYTHING;NOT WITH_PHYSICS" ON) - -option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF) -cmake_dependent_option(WITH_XEGLAPPLICATION "Build XEglApplication library" OFF "TARGET_GLES" OFF) -cmake_dependent_option(WITH_GLUTAPPLICATION "Build GlutApplication library" OFF "NOT TARGET_GLES" OFF) -option(WITH_SDL2APPLICATION "Build Sdl2Application library" OFF) +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_SHADERS "Build Shaders 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) + +# Library features +cmake_dependent_option(USE_HARFBUZZ "Use HarfBuzz in Text library" ON "WITH_TEXT" OFF) + +# Application libraries if(${CMAKE_SYSTEM_NAME} STREQUAL NaCl) option(WITH_NACLAPPLICATION "Build NaClApplication library" OFF) +else() + option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF) + cmake_dependent_option(WITH_WINDOWLESSGLXAPPLICATION "Build WindowlessGlxApplication library" OFF "NOT WITH_MAGNUMINFO" ON) + cmake_dependent_option(WITH_XEGLAPPLICATION "Build XEglApplication library" OFF "TARGET_GLES" OFF) + cmake_dependent_option(WITH_GLUTAPPLICATION "Build GlutApplication library" OFF "NOT TARGET_GLES" OFF) + option(WITH_SDL2APPLICATION "Build Sdl2Application library" OFF) endif() -option(BUILD_TESTS "Build unit tests." OFF) +option(BUILD_TESTS "Build unit tests." OFF) if(BUILD_TESTS) enable_testing() endif() -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Magnum_SOURCE_DIR}/modules/") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/modules/") if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} VERSION_LESS 2.8.8) set(CMAKE_NO_OBJECT_TARGET 1) @@ -47,12 +81,14 @@ endif() # Check dependencies find_package(Corrade REQUIRED) -if(NOT TARGET_GLES) +if(NOT TARGET_GLES OR TARGET_DESKTOP_GLES) find_package(OpenGL REQUIRED) - find_package(GLEW REQUIRED) else() find_package(OpenGLES2 REQUIRED) endif() +if(NOT TARGET_GLES) + find_package(GLEW REQUIRED) +endif() # Configuration variables (saved later to corradeConfigure.h) if(TARGET_GLES) @@ -61,8 +97,16 @@ endif() if(TARGET_GLES2) set(MAGNUM_TARGET_GLES2 1) endif() +if(TARGET_DESKTOP_GLES) + set(MAGNUM_TARGET_DESKTOP_GLES 1) +endif() +if(USE_HARFBUZZ) + set(MAGNUM_USE_HARFBUZZ 1) +endif() # Installation paths +include(CorradeLibSuffix) +set(MAGNUM_BINARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/bin) set(MAGNUM_LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) set(MAGNUM_CMAKE_MODULE_INSTALL_DIR ${CMAKE_ROOT}/Modules) set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d55a03a71..ec263025d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,41 +4,51 @@ To make things easier, here are a few tips: Reporting bugs, requesting features ----------------------------------- -- Best way to report bugs and request new features is to use GitHub - [issues](https://github.com/mosra/magnum/issues), but you can contact me - also any other way. +* Best way to report bugs and request new features is to use GitHub + [issues](https://github.com/mosra/magnum/issues), but you can contact me + also any other way. Code contribution ----------------- -- Building and installing Magnum is described in the - [documentation](http://mosra.cz/blog/magnum-doc/building.html). -- Follow the project coding guidelines. In short - try to match style of - surrounding code and avoid any trailing whitespace. When in doubt, consult - coding guidelines, which are available also - [online](http://mosra.cz/blog/magnum-doc/coding-style.html). -- Document your code. When updating or adding new API, make sure that Doxygen - documentation is up to date. Run - - doxygen - - in project root to generate the documentation and check that your - modifications didn't add any warnings. -- Build unit tests (`-DBUILD_TESTS=ON` parameter to CMake) and run them - using - - ctest --output-on-failure - - in build directory. All tests should always pass. Add new tests or modify - the existing to make sure new code is properly covered (if possible). Here - is a [short tutorial](http://mosra.cz/blog/corrade-doc/unit-testing.html) to - help you with creating unit tests. -- Best way to contribute is by using GitHub - [pull requests](https://github.com/mosra/magnum/pulls) - fork the repository - and make pull request from feature branch. You can also send patches via - e-mail or contact me any other way. -- All your code will be released under license of the project, so make sure - you (or your employers) have no problems with it. +* Building and installing Magnum is described in the [documentation](http://mosra.cz/blog/magnum-doc/building.html). +* Follow the project coding guidelines. In short -- try to match style of the + surrounding code and avoid any trailing whitespace. When in doubt, consult + coding guidelines, which are available also [online](http://mosra.cz/blog/magnum-doc/coding-style.html). +* Document your code. When updating or adding new API, make sure that Doxygen + documentation is up to date. Run + + doxygen + + in project root to generate the documentation and check that your + modifications didn't add any warnings. +* Build unit tests (`-DBUILD_TESTS=ON` parameter to CMake) and run them + using + + ctest --output-on-failure + + in build directory. All tests should *always* pass. Add new tests or modify + the existing to make sure new code is properly covered (if possible). Here + is a [short tutorial](http://mosra.cz/blog/corrade-doc/unit-testing.html) + to help you with creating unit tests. +* Best way to contribute is by using GitHub [pull requests](https://github.com/mosra/magnum/pulls) + -- fork the repository and make pull request from feature branch. You can + also send patches via e-mail or contact me any other way. +* All your code will be released under license of the project (see [COPYING](COPYING) + file for details), so make sure you and your collaborators (or employers) + have no problems with it. If you create new files, don't forget to add + license header (verbatim copied from other files) and don't forget to add + yourself to license header of files you added or significantly modified, + for example: + + /* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + Copyright © YEAR YOUR_NAME + + Permission is hereby granted, free of charge, to any person obtaining a + ... Contact ------- diff --git a/COPYING b/COPYING index 94a9ed024..06646e0a9 100644 --- a/COPYING +++ b/COPYING @@ -1,674 +1,19 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +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. diff --git a/COPYING.LESSER b/COPYING.LESSER deleted file mode 100644 index 65c5ca88a..000000000 --- a/COPYING.LESSER +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/Doxyfile b/Doxyfile index 2553d0c84..54e5ba71f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -202,6 +202,7 @@ ALIASES = \ "todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \ "fn_gl{1}=gl\1()" \ "fn_gl_extension{3}=gl\1\2()" \ + "fn_gles_extension{3}=gl\1\2()" \ "def_gl{1}=`GL_\1`" \ "requires_gl30=@xrefitem requires-gl30 \"Requires OpenGL 3.0\" \"Functionality requiring OpenGL 3.0\"" \ "requires_gl31=@xrefitem requires-gl31 \"Requires OpenGL 3.1\" \"Functionality requiring OpenGL 3.1\"" \ @@ -1189,7 +1190,7 @@ EXT_LINKS_IN_WINDOW = NO # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. -FORMULA_FONTSIZE = 10 +FORMULA_FONTSIZE = 12 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are @@ -1670,7 +1671,7 @@ DOT_FONTPATH = # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. -CLASS_GRAPH = YES +CLASS_GRAPH = NO # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and @@ -1737,7 +1738,7 @@ CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. -GRAPHICAL_HIERARCHY = YES +GRAPHICAL_HIERARCHY = NO # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories diff --git a/PKGBUILD b/PKGBUILD index 532445d6f..ca4a64126 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -5,7 +5,7 @@ pkgrel=1 pkgdesc="OpenGL 3 graphics engine" arch=('i686' 'x86_64') url="https://github.com/mosra/magnum" -license=('LGPLv3') +license=('MIT') depends=('corrade' 'glew') makedepends=('cmake') options=(!strip) @@ -15,6 +15,10 @@ build() { mkdir -p "$startdir/build" cd "$startdir/build/" + # Disable optimization (saves A LOT of compilation time) + newcxxflags=$(echo $CXXFLAGS | sed s/-O.//g | sed s/-D_FORTIFY_SOURCE=.//g) + export CXXFLAGS="$newcxxflags" + if [ "$CXX" = clang++ ] ; then newcxxflags=$(echo $CXXFLAGS | sed s/--param=ssp-buffer-size=4//g) export CXXFLAGS="$newcxxflags" diff --git a/PKGBUILD-mingw32 b/PKGBUILD-mingw32 index 106fd8f2f..42b3835c3 100644 --- a/PKGBUILD-mingw32 +++ b/PKGBUILD-mingw32 @@ -5,7 +5,7 @@ pkgrel=1 pkgdesc="OpenGL 3 graphics engine (mingw32)" arch=('any') url="https://github.com/mosra/magnum" -license=('LGPLv3') +license=('MIT') depends=('mingw32-runtime' 'mingw32-corrade' 'mingw32-glew') makedepends=('mingw32-gcc' 'cmake' 'corrade') options=(!buildflags !strip) diff --git a/PKGBUILD-nacl b/PKGBUILD-nacl index 344e53f7b..668cafd4c 100644 --- a/PKGBUILD-nacl +++ b/PKGBUILD-nacl @@ -5,7 +5,7 @@ pkgrel=1 pkgdesc="OpenGL 3 graphics engine (NaCl x86-64 version)" arch=('any') url="https://github.com/mosra/magnum" -license=('LGPLv3') +license=('MIT') depends=('nacl-corrade') makedepends=('nacl-sdk' 'cmake') options=(!buildflags !strip) diff --git a/PKGBUILD-release b/PKGBUILD-release index 3409b26e2..a09e48d39 100644 --- a/PKGBUILD-release +++ b/PKGBUILD-release @@ -5,7 +5,7 @@ pkgrel=1 pkgdesc="OpenGL 3 graphics engine" arch=('i686' 'x86_64') url="https://github.com/mosra/magnum" -license=('LGPLv3') +license=('MIT') depends=('corrade' 'glew') makedepends=('cmake' 'qt') provides=('magnum-git') diff --git a/README.md b/README.md index 067288410..fdb1f940f 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,60 @@ -Magnum is 3D graphics engine written in C++11 and OpenGL 3 Core Profile. -Features: - - * Easy-to-use templated mathematical library for matrix/vector calculations - and geometry. - * Classes wrapping OpenGL objects and simplifying their usage - shaders, - buffers, meshes and textures. Access to framebuffer and occlusion queries. - * Mesh tools for cleaning, optimizing and generating meshes, utility classes - for color conversion, timeline and profiling. - * Hierarchical scene graph which supports transformation caching for better - performance, physics library for collision detection and rigid body - dynamics. - * Plugin-based data exchange framework for importing image, mesh, material - and scene data in various formats. - * Collection of pre-made graphic primitives and shaders for testing purposes. - * Classes for creating OpenGL-enabled applications with various toolkits, - methods for querying supported OpenGL version and available extensions. - * Comprehensive use of C++11 features for safety, performance and ease of - development. All code which doesn't directly interact with OpenGL is - covered with unit tests. - * Actively maintained Doxygen documentation. Occasionally updated snapshot is - also available online at http://mosra.cz/blog/magnum-doc/ . +Magnum is 2D/3D graphics engine written in C++11 and OpenGL 3 Core Profile. + +DESIGN GOALS +============ + +* **2D is not an ugly stepchild** + Many engines out there are either purely 2D or 3D and if you want to do + your next project in 2D only, you have to either relearn another engine + from scratch or emulate it in 3D, leaving many things overly complicated. + Magnum treats 2D equivalently to 3D so you can reuse what you already + learned for 3D and even combine 2D and 3D in one project. + +* **Forward compatibility** + If newer technology makes things faster, simpler or more intuitive, it is + the way to go. If you then really need to, you can selectively backport + some features and it will be easier than maintaining full backward + compatibility by default. Magnum by default relies on decent C++11 support + and modern OpenGL features, but compatibility functions for older hardware + and compatibility branch for older compilers are available if you need + them. + +* **Intuitive, but not restrictive API** + Scripting languages are often preferred to C/C++ because they tend to do + more with less -- less complicated APIs, nicer syntax and less boilerplate + code. Magnum is designed with scripting language intuitivity in mind, but + also with speed and static checks that native code and strong typing + offers. Usually the most common way is the most simple, but if you need + full control, you can have it. + +* **Extensible and replaceable components** + If you want to use different mathematical library for specific purposes, + that new windowing toolkit, your own file formats or another physics + library, you can. Conversion of data between different libraries can be + done on top of pre-made skeleton classes, support for file formats is done + using plugins and platform support is done by writing simple wrapper class. + +FEATURES +======== + +* Actively maintained Doxygen documentation with tutorials and examples. + Snapshot is available at http://mosra.cz/blog/magnum-doc/. +* Vector and matrix library with implementation of complex numbers, + quaternions and their dual counterparts for representing transformations. +* Classes wrapping OpenGL and simplifying its usage with direct state access + and automatic fallback for unavailable features. +* Extensible scene graph which can be modified for each specific usage. +* Plugin-based data exchange framework, tools for manipulating meshes, + textures and images. +* Integration with various windowing toolkits and also ability to create + windowless contexts. +* Pre-made shaders, primitives and other tools for easy prototyping and + debugging. INSTALLATION ============ -You can either use packaging scripts, which are stored in package/ +You can either use packaging scripts, which are stored in `package/` subdirectory, or compile and install everything manually. Note that Doxygen documentation (see above or build your own using instructions below) contains more comprehensive guide for building, packaging and crosscompiling. @@ -38,7 +68,7 @@ Minimal dependencies * **CMake** >= 2.8.8 (needed for `OBJECT` library target) * **GLEW** - OpenGL extension wrangler (only if targeting desktop OpenGL) * **Corrade** - Plugin management and utility library. You can get it at - http://github.com/mosra/corrade or at http://mosra.cz/blog/corrade.php. + https://github.com/mosra/corrade. Compilation, installation ------------------------- @@ -53,6 +83,9 @@ installed using these four commands: make make install +See Doxygen documentation for more information about enabling or disabling +additional features and targeting different platforms such as OpenGL ES. + Building and running unit tests ------------------------------- @@ -82,12 +115,11 @@ PLUGINS AND EXAMPLES ==================== Various importer plugins for image and 3D model formats are maintained in -separate repository, which can be found at -http://github.com/mosra/magnum-plugins . +separate repository, which can be found at https://github.com/mosra/magnum-plugins. -There are also examples of engine usage, varying from simple *Hello -World*-like example to more advanced applications, such as viewer for complex -3D models. Example repository is at http://github.com/mosra/magnum-examples . +There are also examples of engine usage, varying from simple *Hello World*-like +example to more advanced applications, such as viewer for complex 3D models. +Example repository is at https://github.com/mosra/magnum-examples. CONTACT ======= @@ -99,3 +131,9 @@ awesome idea? Feel free to visit my website or contact me at: * GitHub - https://github.com/mosra/magnum * E-mail - mosra@centrum.cz * Jabber - mosra@jabbim.cz + +LICENSE +======= + +Magnum is licensed under MIT/Expat license, see [COPYING](COPYING) file for +details. diff --git a/doc/best-practices.dox b/doc/best-practices.dox index 2c06f6ce7..7517541ca 100644 --- a/doc/best-practices.dox +++ b/doc/best-practices.dox @@ -1,3 +1,27 @@ +/* + 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 { /** @page best-practices Best practices and platform-specific information @@ -38,5 +62,9 @@ cannot be later rebound to @ref Buffer::Target "Target::Element". However, internally (e.g. for setting data or copying). To avoid this, set target hint to desired target, either in constructor or using Buffer::setTargetHint(). +@subsection best-practices-powervr PowerVR hardware + +- [PowerVR Performance Recommendations](http://www.imgtec.com/powervr/insider/docs/PowerVR.Performance%20Recommendations.1.0.28.External.pdf) [PDF] + */ } diff --git a/doc/building.dox b/doc/building.dox index 8d122190c..df562d963 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -1,3 +1,27 @@ +/* + 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 { /** @page building Downloading and building @brief Guide how to download and build %Magnum on different platforms. @@ -55,33 +79,60 @@ If you want to build with another compiler (e.g. Clang), pass @subsection building-optional Enabling or disabling features -By default the engine is built for desktop OpenGL. If you want to target -OpenGL ES, set `TARGET_GLES` to `ON` or pass `-DTARGET_GLES=ON` to CMake. Note -that some features are available for desktop OpenGL only, see @ref requires-gl. - -By default the engine is built with everything except -@ref Platform "application libraries". Using `WITH_*` CMake parameters you can -specify which parts will be built and which not: - - - `WITH_EVERYTHING` - Defaults to `ON`, builds everything except window - contexts. If set to `OFF`, only the main library is built and you can - select additional libraries with the following: - - `WITH_MESHTOOLS` - MeshTools library. - - `WITH_PHYSICS` - Physics library. - - `WITH_PRIMITIVES` - Primitives library. - - `WITH_SCENEGRAPH` - SceneGraph library. - - `WITH_SHADERS` - Shaders library. - -None of the application libraries is built by default, regardless to -`WITH_EVERYTHING` is enabled or not: - - - `WITH_XEGLAPPLICATION` - X/EGL application, available only if targeting - OpenGL ES (see above). Requires **X11** and **EGL** libraries. - - `WITH_GLXAPPLICATION` - GLX application. Requires **X11** and **GLX** - libraries. - - `WITH_GLUTAPPLICATION` - GLUT application, available only if targeting - desktop OpenGL. Requires **GLUT** library. - - `WITH_SDL2APPLICATION` - SDL2 application. Requires **SDL2** library. +By default the engine is built for desktop OpenGL. Using `TARGET_*` CMake +parameters you can target other platforms. Note that some features are available +for desktop OpenGL only, see @ref requires-gl. + + - `TARGET_GLES` - Target OpenGL ES. + - `TARGET_GLES2` - Target OpenGL ES 2.0. Currently enabled by default when + `TARGET_GLES` is set, as no customer OpenGL ES 3.0 platform exists yet. + - `TARGET_DESKTOP_GLES` - Target OpenGL ES on desktop, i.e. use OpenGL ES + emulation in desktop OpenGL library. Might not be supported in all drivers. + +By default the engine is built with everything except application libraries (see +below). Using `WITH_*` CMake parameters you can specify which parts will be built +and which not: + + - `WITH_DEBUGTOOLS` - DebugTools library. Enables also building of MeshTools, + Physics, Primitives, SceneGraph and Shaders 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. + - `WITH_SHADERS` - Shaders library. Enabled automatically if `WITH_DEBUGTOOLS` + is enabled. + - `WITH_TEXT` - Text library. Enables also building of TextureTools library. + Requires **FreeType** and possibly **HarfBuzz** library (see below). + - `WITH_TEXTURETOOLS` - TextureTools library. Enabled automatically if `WITH_TEXT` + is enabled. + - `WITH_MAGNUMINFO` - `magnum-info` executable, provides information about the + engine and OpenGL capabilities. + +Some dependencies are optional, although disabling them might reduce some +functionality: + + - `USE_HARFBUZZ` - Defaults to `ON`, disabling it will result in worse text + rendering (no kerning & ligatures) and possible issues with non-Latin text. + +None of the @ref Platform "application libraries" is built by default (and you +need at least one). Choose the one which suits your requirements and your +platform best: + + - `WITH_XEGLAPPLICATION` - @ref Platform::XEglApplication "XEglApplication", + available only if targeting OpenGL ES (see above). Requires **X11** and + **EGL** libraries. + - `WITH_GLXAPPLICATION` - @ref Platform::GlxApplication "GlxApplication". + Requires **X11** and **GLX** libraries. + - `WITH_WINDOWLESSGLXAPPLICATION` - @ref Platform::WindowlessGlxApplication "WindowlessGlxApplication". + Requires **X11** and **GLX** libraries. + - `WITH_GLUTAPPLICATION` - @ref Platform::GlutApplication "GlutApplication", + available only if targeting desktop OpenGL. Requires **GLUT** library. + - `WITH_SDL2APPLICATION` - @ref Platform::Sdl2Application "Sdl2Application". + Requires **SDL2** library. @subsection building-tests Building and running unit tests @@ -159,9 +210,10 @@ You will need [Native Client SDK](https://developers.google.com/native-client/be 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 +@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`. +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. 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 diff --git a/doc/coding-style.dox b/doc/coding-style.dox index 1e0e96b66..68a8ea39f 100644 --- a/doc/coding-style.dox +++ b/doc/coding-style.dox @@ -1,3 +1,27 @@ +/* + 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 { /** @page coding-style Coding style @brief Coding style and best practices to preserve maintainability and @@ -27,6 +51,15 @@ have `*.hpp` extension (hinting that they are something between `*.h` and @subsection cpp-format Code format +@subsubsection cpp-types Builtin types + +Use %Magnum's own type aliases for public API (e.g. @ref UnsignedInt, see +@ref types for more information), but use specific types when interacting with +third party libraries and OpenGL (e.g. `GLuint`) and rely only on implicit +conversions when converting between them. This helps avoiding sign, truncation +and other issues, e.g. `%Math::%Vector2` will implicitly convert to +@ref Vector2i if and only if @ref Int is the same type as `GLsizei`. + @subsubsection cpp-naming Naming When writing wrappers for OpenGL functions and defines, try to match the @@ -35,12 +68,30 @@ removing redundant prefixes) is encouraged. @subsubsection cpp-forward-declarations Forward declarations and forward declaration headers -Use forward declarations in headers as much as possible, as it can -significantly reduce time of incremental compilation. When an namespace has -classes which are commonly forward-declared, consider making a forward -declaration header - it should have the same name as the namespace itself and -contain foward declarations for all classes, enums and copies of all -meaningful typedefs. See SceneGraph/SceneGraph.h for an example. +When a namespace has classes which are commonly forward-declared, consider +making a forward declaration header - it should have the same name as the +namespace itself and contain foward declarations for all classes, enums and +copies of all meaningful typedefs. See @ref compilation-forward-declarations +for more information. + +@section compatibility Compatibility with various OpenGL editions + +If any class, function or part of code depends on particular OpenGL edition +(e.g. only for desktop), use conditional compilation to avoid erors on other +platforms (see @ref portability-target for more information). Put related +documentation also into the conditional compilation block and don't forget to +appropriately mark the class/function (@ref documentation-commands-requires "see below"). +Example: +@code +#ifndef MAGNUM_TARGET_GLES +// +// @brief Set polygon mode +// +// @requires_gl Polygon mode is not available in OpenGL ES. +// +void setPolygonMode(PolygonMode mode); +#endif +@endcode @section documentation Doxygen documentation @@ -69,15 +120,17 @@ with @c \@extension command: @code @extension{ARB,timer_query} @endcode -It produces link to the specification of the extension in OpenGL registry, -e.g. @extension{ARB,timer_query}. Similarly for OpenGL ES extensions there is -@c \@es_extension command. Some extensions have slightly different URL, -with command @c \@es_extension2 you can specify extension filename, if the -previous command gives 404 error. The following produces link to -@es_extension2{NV,read_buffer_front,GL_NV_read_buffer} extension: +It produces link to the specification of the extension in OpenGL registry: +> @extension{ARB,timer_query} + +Similarly for OpenGL ES extensions there is @c \@es_extension command. Some +extensions have slightly different URL, with command @c \@es_extension2 you can +specify extension filename, if the previous command gives 404 error. For example @code @es_extension2{NV,read_buffer_front,GL_NV_read_buffer} @endcode +produces this link: +> @es_extension2{NV,read_buffer_front,GL_NV_read_buffer} @subsubsection documentation-commands-ref_gl Links to related OpenGL functions and definitions @@ -90,9 +143,8 @@ inline static void setSeamless(bool enabled) { enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } @endcode - -It produces link to the online manual, in this case @fn_gl{Enable}/@fn_gl{Disable} -with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS}. +It produces link to the online manual: +> @fn_gl{Enable}/@fn_gl{Disable} with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS}. For functions which are not part of OpenGL core specification, but only as extensions, use @c \@fn_gl_extension command, e.g. @@ -101,8 +153,8 @@ extensions, use @c \@fn_gl_extension command, e.g. @endcode First parameter is function name without the suffix, the second two parameters are the same as in @c \@extension command. It produced link to extension -specification, with function name as link text, in this case -@fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access}. +specification, with function name as link text: +> @fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access}. @subsubsection documentation-commands-requires Classes and functions requiring specific OpenGL version or extensions diff --git a/doc/collision-detection.dox b/doc/collision-detection.dox index 033f7607d..e263492a0 100644 --- a/doc/collision-detection.dox +++ b/doc/collision-detection.dox @@ -1,3 +1,27 @@ +/* + 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. diff --git a/doc/compilation-speedup.dox b/doc/compilation-speedup.dox index d67a69c6b..f05196e0a 100644 --- a/doc/compilation-speedup.dox +++ b/doc/compilation-speedup.dox @@ -1,3 +1,27 @@ +/* + 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 { /** @page compilation-speedup Speeding up compilation @brief Techniques for reducing compilation times. @@ -19,16 +43,20 @@ some types it can be too cumbersome -- e.g. too many template parameters, typedefs etc. In this case a header with forward declarations is usually available, each namespace has its own: + - Math/Math.h - Magnum.h + - DebugTools/DebugTools.h - Physics/Physics.h - SceneGraph/SceneGraph.h - Shaders/Shaders.h + - Text/Text.h + - Trade/Trade.h @section compilation-speedup-templates Templates Many things in %Magnum are templated to allow handling of various types and -sizes of data, for example whole Scene graph can operate either with `float`s -or with `double`s. However, having templated classes and function usually +sizes of data, for example whole Scene graph can operate either with @ref Float +or @ref Double data type. However, having templated classes and function usually means that the compiler compiles the whole templated code again in each compilation unit (i.e. source file). In linking stage of the application or library the duplicates are just thrown out, which is a waste of compilation @@ -60,7 +88,7 @@ Sometimes you however need to use your own specialization and that's why template implementation files are included in the library. For example we want to use @ref SceneGraph::Object "Object" from SceneGraph with @ref SceneGraph::MatrixTransformation3D "MatrixTransformation3D" with -`GLdouble` as underlying type, because our scene will span the whole universe. +@ref Double as underlying type, because our scene will span the whole universe. We include the implementation file in dedicated source file and explicitly instantiate the template: @code @@ -69,7 +97,7 @@ instantiate the template: using namespace Magnum::SceneGraph; -template class Object>; +template class Object>; @endcode All other files using the same object specialization now need to include only SceneGraph/Object.h header. Thus the Object specialization will be compiled diff --git a/doc/debug-tools.dox b/doc/debug-tools.dox new file mode 100644 index 000000000..916df7408 --- /dev/null +++ b/doc/debug-tools.dox @@ -0,0 +1,79 @@ +/* + 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 { +/** @page debug-tools Debugging helpers + +@brief Convenience classes to help you during development. + +@tableofcontents + +DebugTools library provides various helper classes to help you with +prototyping and debugging applications without the need to write too much +common code. They probably have no usage in production code, but can be useful +in development. + +@section debug-tools-renderers Debug renderers + +%Debug renderers provide a way to visualize objects and object features in +@ref scenegraph "scene graph" without the need to mess around with meshes and +shaders. They are implemented as object features, so you can attach any number +of them to any object. + +Basic usage involves instancing DebugTools::ResourceManager and keeping it for +for the whole lifetime of debug renderers. Next you need some SceneGraph::DrawableGroup +instance. You can use the same group as for the rest of your scene, but +preferrably use dedicated one for debug renderers, so you can easily enable or +disable debug rendering. + +Next step is to create configuration for your debug renderers and create +particular debug renderer. The configuration is managed using the resource +manager - you create configuration instance, add it to the manager and then +reference it using particular resource key. This way you can easily share the +same options with more renderers. If no options are specified or resource with +given key doesn't exist, default fallback is used. + +Example usage: visualizing object position, rotation and scaling using +DebugTools::ObjectRenderer: +@code +// Global instance of debug resource manager, drawable group for the renderers +DebugTools::ResourceManager manager; +SceneGraph::DrawableGroup3D debugDrawables; + +// Create renderer options which will be referenced later by "my" resource key +DebugTools::ResourceManager::instance()->set("my", + (new DebugTools::ObjectRendererOptions())->setSize(0.3f)); + +// Create debug renderer for given object, use "my" options for it. The +// renderer is automatically added to the object features and also to +// specified drawable group. +Object3D* object; +new DebugTools::ObjectRenderer2D(object, "my", debugDrawables); +@endcode + +See DebugTools::ObjectRenderer and DebugTools::ShapeRenderer for more +information. + +*/ +} diff --git a/doc/features.dox b/doc/features.dox index 339e66824..2e0813e95 100644 --- a/doc/features.dox +++ b/doc/features.dox @@ -1,9 +1,36 @@ +/* + 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 { /** @page features Feature overview @brief Fundamental principles and design goals -- @subpage matrix-vector - @copybrief matrix-vector -- @subpage scenegraph - @copybrief scenegraph -- @subpage collision-detection - @copybrief collision-detection +- @subpage types -- @copybrief types +- @subpage matrix-vector -- @copybrief matrix-vector +- @subpage transformations -- @copybrief transformations +- @subpage scenegraph -- @copybrief scenegraph +- @subpage collision-detection -- @copybrief collision-detection +- @subpage debug-tools -- @copybrief debug-tools */ } diff --git a/doc/mainpage.dox b/doc/mainpage.dox index b262155a7..cc5e6df15 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -1,59 +1,91 @@ +/* + 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 { /** @mainpage -%Magnum is 3D graphics engine written in C++11 and OpenGL 3 Core Profile. -Features: - -- Easy-to-use templated @ref Math "mathematical library" for - @ref matrix-vector "matrix/vector calculations" and - @ref Math::Geometry "geometry". -- Classes wrapping OpenGL objects and simplifying their usage - - @ref AbstractShaderProgram "shaders", @ref Buffer "buffers", - @ref Mesh "meshes" and @ref AbstractTexture "textures". Access to - @ref Framebuffer "framebuffer" and @ref AbstractQuery "occlusion queries". -- @ref MeshTools "Mesh tools" for cleaning, optimizing and generating meshes, - utility classes for @ref Color.h "color conversion", @ref Timeline "timeline" - and @ref Profiler "profiling". -- Hierarchical @ref SceneGraph "scene graph" which supports transformation - caching for better performance, @ref Physics "physics library" for collision - detection and rigid body dynamics. -- Plugin-based @ref Trade "data exchange framework" for importing image, mesh, - material and scene data in various formats. -- Collection of pre-made @ref Primitives "graphic primitives" and - @ref Shaders "shaders" for testing purposes. -- Classes for creating OpenGL-enabled applications with @ref Platform - "various toolkits", methods for querying - @ref Context "supported OpenGL version and available extensions". -- Comprehensive use of C++11 features for safety, performance and ease of - development. All code which doesn't directly interact with OpenGL is - covered with unit tests. - -The engine is meant to be run on OpenGL 3 capable hardware, but most of the -functionality is working on OpenGL 2.1 hardware too. The engine can be built -also for OpenGL ES with limited functionality. See also @ref required-extensions. - -@section download-build Downloading and building Magnum +%Magnum is 2D/3D graphics engine written in C++11 and OpenGL 3 Core Profile. -Guide @ref building "how to download and build Magnum" on different platforms. +@section mainpage-design-goals Design goals + +- **2D is not an ugly stepchild** + Many engines out there are either purely 2D or 3D and if you want to do + your next project in 2D only, you have to either relearn another engine + from scratch or emulate it in 3D, leaving many things overly complicated. + %Magnum treats 2D equivalently to 3D so you can reuse what you already + learned for 3D and even combine 2D and 3D in one project. -@section getting-started Getting started +- **Forward compatibility** + If newer technology makes things faster, simpler or more intuitive, it is + the way to go. If you then really need to, you can selectively backport + some features and it will be easier than maintaining full backward + compatibility by default. %Magnum by default relies on decent C++11 support + and modern OpenGL features, but compatibility functions for older hardware + and compatibility branch for older compilers are available if you need + them. -To get up and running, you must first subclass one of the provided window -context classes and implement required functions. %Magnum provides -implementations for the most common toolkits (such as GLUT, Xlib, or SDL2) in -Platform namespace. +- **Intuitive, but not restrictive API** + Scripting languages are often preferred to C/C++ because they tend to do + more with less -- less complicated APIs, nicer syntax and less boilerplate + code. %Magnum is designed with scripting language intuitivity in mind, but + also with speed and static checks that native code and strong typing + offers. Usually the most common way is the most simple, but if you need + full control, you can have it. -Then you can either draw your meshes directly or use SceneGraph which will -help you with object hierarchy, transformations and resource management. +- **Extensible and replaceable components** + If you want to use different mathematical library for specific purposes, + that new windowing toolkit, your own file formats or another physics + library, you can. Conversion of data between different libraries can be + done on top of pre-made skeleton classes, support for file formats is done + using plugins and platform support is done by writing simple wrapper class. -@subsection getting-started-examples Tutorials and examples +@section mainpage-features Features + +- Vector and matrix library with implementation of complex numbers, + quaternions and their dual counterparts for representing transformations. +- Classes wrapping OpenGL and simplifying its usage with direct state access + and automatic fallback for unavailable features. +- Extensible scene graph which can be modified for each specific usage. +- Plugin-based data exchange framework, tools for manipulating meshes, + textures and images. +- Integration with various windowing toolkits and also ability to create + windowless contexts. Ported to OpenGL ES and various platforms. +- Pre-made shaders, primitives and other tools for easy prototyping and + debugging. + +@section mainpage-download-build Downloading and building Magnum + +Guide @ref building "how to download and build Magnum" on different platforms. + +@section mainpage-getting-started Getting started The best way to get started is to render your first triangle in @ref example-index "step-by-step tutorial". Then you can dig deeper and try other examples, read about @ref features "fundamental principles" in the documentation or start experimenting on your own! -@subsection getting-started-hacking Hacking Magnum +@section mainpage-hacking Hacking Magnum If you want to hack on this engine, if you spotted a bug, need an feature or have an awesome idea, you can get a copy of the sources from GitHub and start @@ -69,5 +101,31 @@ Feel free to get more information or contact the author at: - E-mail - mosra@centrum.cz - Jabber - mosra@jabbim.cz +@section mainpage-license License + +%Magnum is licensed under MIT/Expat license: + +> +> Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz> +> +> Permission is hereby granted, free of charge, to any person obtaining a +> copy of this software and associated documentation files (the "Software"), +> to deal in the Software without restriction, including without limitation +> the rights to use, copy, modify, merge, publish, distribute, sublicense, +> and/or sell copies of the Software, and to permit persons to whom the +> Software is furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included +> in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +> THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +> FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +> DEALINGS IN THE SOFTWARE. +> + */ } diff --git a/doc/matrix-vector.dox b/doc/matrix-vector.dox index 6b05b00c3..82ab2d98b 100644 --- a/doc/matrix-vector.dox +++ b/doc/matrix-vector.dox @@ -1,3 +1,27 @@ +/* + 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 Math { /** @page matrix-vector Operations with matrices and vectors @@ -14,9 +38,9 @@ easier. %Magnum has three main matrix and vector classes: RectangularMatrix, (square) Matrix and Vector. To achieve greatest code reuse, %Matrix is internally -square %RectangularMatrix and %Vector is internally one-column -%RectangularMatrix. Both vectors and matrices can have arbitrary size (known -at compile time) and can store any meaningful type. +square %RectangularMatrix and %RectangularMatrix is internally array of one or +more %Vector instances. Both vectors and matrices can have arbitrary size +(known at compile time) and can store any arithmetic type. Each subclass brings some specialization to its superclass and for most common vector and matrix sizes there are specialized classes Matrix3 and Matrix4, @@ -26,38 +50,34 @@ return the most specialized type known to make subsequent operations more convenient - columns of %RectangularMatrix are returned as %Vector, but when accessing columns of e.g. %Matrix3, they are returned as %Vector3. -There are also even more specialized subclasses - Point2D, Point3D for -creating points with homogeneous coordinates and Color3, Color4 for color -handling and conversion. +There are also even more specialized subclasses, e.g. Color3 and Color4 for +color handling and conversion. @section matrix-vector-construction Constructing matrices and vectors Default constructors of RectangularMatrix and Vector (and Vector2, Vector3, Vector4, Color3) create zero-filled objects. Matrix (and Matrix3, Matrix4) is -by default constructed as identity matrix. Point2D and Point3D have -homogeneous component set to one, Color4 has alpha value set to opaque. +by default constructed as identity matrix. Color4 has alpha value set to opaque. @code -RectangularMatrix<2, 3, int> a; // zero-filled -Vector<3, int> b; // zero-filled - -Matrix<3, int> identity; // diagonal set to 1 -Matrix<3, int> zero(Matrix<3, int>::Zero); // zero-filled +RectangularMatrix<2, 3, Int> a; // zero-filled +Vector<3, Int> b; // zero-filled -Point2D c; // {0, 0, 1} -Point3D d; // {0, 0, 0, 1} +Matrix<3, Int> identity; // diagonal set to 1 +Matrix<3, Int> zero(Matrix<3, Int>::Zero); // zero-filled -Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} +Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} Color4 black2; // {0, 0, 0, 255} @endcode -Most common and most efficient way to create matrix or vector is to pass -values of all components to the constructor. +Most common and most efficient way to create vector is to pass all values to +constructor, matrix is created by passing all column vectors to the +constructor. @code -Matrix3 mat(0, 1, 2, - 3, 4, 5, - 6, 7, 8); // column-major (see explanation why below) +Vector3 vec(0, 1, 2); -Vector3 vec(0, 1, 2); +Matrix3 mat({0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}); @endcode All constructors check number of passed arguments and the errors are catched at compile time. @@ -65,43 +85,34 @@ at compile time. You can specify all components of vector or whole diagonal of square matrix at once: @code -Matrix3 diag(Matrix3::Identity, 2); // diagonal set to 2, zeros elsewhere -Vector3 fill(10); // {10, 10, 10} -@endcode - -Vectors are commonly used to specify various axes and scaling coefficients in -transformations, you can use convenience functions instead of typing out all -other elements: -@code -Matrix4::rotation(deg(5.0f), Vector3::xAxis()); // {1.0f, 0.0f, 0.0f} -Matrix3::translation(Vector2::yAxis(2.0f)); // {0.0f, 2.0f} -Matrix4::scaling(Vector3::zScale(-10.0f)); // {1.0f, 1.0f, -10.0f} +Matrix3 diag(Matrix3::Identity, 2); // diagonal set to 2, zeros elsewhere +Vector3 fill(10); // {10, 10, 10} @endcode It is possible to create matrices from other matrices and vectors with the same row count; vectors from vector and scalar: @code -RectangularMatrix<2, 3, int> a; -Vector3 b, c; -Matrix3 mat = Matrix3::from(b, a, c); -Vector<8, int> vec = Vector<8, int>::from(1, b, 2, c); +RectangularMatrix<2, 3, Int> a; +Vector3 b, c; +Matrix3 mat(a, b); +Vector<8, Int> vec(1, b, 2, c); @endcode It is also possible to create them from an C-style array. The function does simple type cast without any copying, so it's possible to conveniently operate on the array itself: @code -int[] mat = { 2, 4, 6, +Int[] mat = { 2, 4, 6, 1, 3, 5 }; -RectangularMatrix<2, 3, int>::from(mat) *= 2; // mat == { 4, 8, 12, 2, 6, 10 } +RectangularMatrix<2, 3, Int>::from(mat) *= 2; // mat == { 4, 8, 12, 2, 6, 10 } @endcode Note that unlike constructors, this function has no way to check whether the array is long enough to contain all elements, so use with caution. -You can also convert between data types: +You can also *explicitly* convert between data types: @code -Vector4 floating(1.3f, 2.7f, -15.0f, 7.0f); -Vector4 integral(Vector4::from(floating)); // {1, 2, -15, 7} +Vector4 floating(1.3f, 2.7f, -15.0f, 7.0f); +Vector4 integral(floating); // {1, 2, -15, 7} @endcode @section matrix-vector-component-access Accessing matrix and vector components @@ -110,37 +121,37 @@ Column vectors of matrices and vector components can be accessed using square brackets, there is also round bracket operator for accessing matrix components directly: @code -RectangularMatrix<3, 2, int> a; +RectangularMatrix<3, 2, Int> a; a[2] /= 2; // third column (column major indexing, see explanation below) a[0][1] = 5; // first column, second element -a(0, 1) += 3; // first column, second element (preferred) -Vector<3, int> b; +Vector<3, Int> b; b[1] = 1; // second element @endcode -For accessing matrix element prefer round bracket operator, as it is possibly -faster than the double square brackets (but never slower) and isn't prone to -compiler mis-optimizations. + +Row vectors can be accessed too, but only for reading, and the access is slower +due to the way the matrix is stored (see explanation below): +@code +Vector<2, Int> c = a.row(2); // third row +@endcode Fixed-size vector subclasses have functions for accessing named components and subparts: @code -Vector4 a; -int x = a.x(); +Vector4 a; +Int x = a.x(); a.y() += 5; -Vector3 xyz = a.xyz(); +Vector3 xyz = a.xyz(); xyz.xy() *= 5; @endcode Color3 and Color4 name their components `rgba` instead of `xyzw`. -For more involved operations with components there are two swizzle() functions, -they have the same features, but one is guaranteed to do most of the work at -compile-time, while the second has more convenient syntax: +For more involved operations with components there is the swizzle() function: @code -Vector4 original(-1, 2, 3, 4); -Vector4 bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 } -Vector<6, int> a10rgb = swizzle(original, "a10rgb"); // { 4, 1, 0, -1, 2, 3 } +Vector<4, Int> original(-1, 2, 3, 4); +Vector<4, Int> bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 } +Vector<6, Int> w10xyz = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); // { 4, 1, 0, -1, 2, 3 } @endcode @section matrix-vector-column-major Matrices are column-major and vectors are columns @@ -152,28 +163,24 @@ implications and it may differ from what is common in mathematics: - Order of template arguments in specification of RectangularMatrix is also column-major: @code -RectangularMatrix<2, 3, int> mat; // two columns, three rows +RectangularMatrix<2, 3, Int> mat; // two columns, three rows @endcode -- Order of components in matrix constructors is also column-major, so the - elements passed in constructor doesn't need to be reordered internally - before putting them into data array: +- Order of components in matrix constructors is also column-major, further + emphasized by requirement that you have to pass directly column vectors: @code -Matrix3 mat(0, 1, 2, - 3, 4, 5, - 6, 7, 8); // first column is {0, 1, 2} +Matrix3 mat({0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}); // first column is {0, 1, 2} @endcode -- Element accessing order is also column-major. It costs virtually no time to - return reference to portion of data array as column vector, thus the bracket - operator is accessing columns. Returned vector has also its own bracket - operator, which is indexing rows. To avoid confusion, first parameter of - round bracket operator is thus also column index. +- Element accessing order is also column-major, thus the bracket operator is + accessing columns. Returned vector has also its own bracket operator, which + is then indexing rows. @code mat[0] *= 2; // first column -mat[2][0] = 5; // first element of first column vector -mat(2, 0) += 3; // first element of first column +mat[2][0] = 5; // first element of first column @endcode - Various algorithms which commonly operate on matrix rows (such as - @ref Algorithms::GaussJordan "Gauss-Jordan elimination") have faster + @ref Algorithms::gaussJordanInPlace() "Gauss-Jordan elimination") have faster alternatives which operate on columns. It's then up to user decision to operate with transposed matrices or use the slower non-transposed alternative of the algorithm. diff --git a/doc/method-chaining.dox b/doc/method-chaining.dox new file mode 100644 index 000000000..798830984 --- /dev/null +++ b/doc/method-chaining.dox @@ -0,0 +1,90 @@ +/* + 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 { +/** @page method-chaining Method chaining + +@brief Little feature helping to reduce typing and encourage best practices. + +Method chaining ([Wikipedia](http://en.wikipedia.org/wiki/Method_chaining)) is a +feature which allows you to chain method calls one after another without +repeatedly specifying variable the method is called on. Its primary goal is to +reduce unnecessary repeated names, improving code readability. + +%Magnum uses this feature for configuring OpenGL objects (such as various mesh +and framebuffer options, shader uniforms etc.). Because OpenGL was designed with +"bind-to-modify" approach, most configuration calls need to bind the object +first and only after that change the parameters (unless @extension{EXT,direct_state_access} +extension is available to avoid this). To reduce unneeded bind calls, %Magnum +binds the object only if it is not already bound somewhere. Method chaining +encourages you to configure whole object in one run, effectively reducing the +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->setSubImage(0, {}, diffuse); +carSpecularTexture->setSubImage(0, {}, specular; +carBumpTexture->setSubImage(0, {}, bump); +carDiffuseTexture->generateMipmap(); +carSpecularTexture->generateMipmap(); +carBumpTexture->generateMipmap(); +@endcode + +This code is written that similar configuration steps are grouped together, +which might be good when somebody needs to change something for all three +textures at once, but on the other hand the code is cluttered with repeated +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) + ->setSubImage(0, {}, diffuse) + ->generateMipmap(); +carSpecularTexture->setStorage(3, Texture2D::InternalFormat::R8) + ->setSubImage(0, {}, diffuse) + ->generateMipmap(); +carBumpTexture->setStorage(5, Texture2D::InternalFormat::RGB8) + ->setSubImage(0, {}, bump) + ->generateMipmap(); +@endcode + +Method chaining is not used on non-configuring functions, such as Framebuffer::clear() +or Mesh::draw(), as these won't be commonly used in conjunction with other +functions anyway. + +Method chaining is also used in SceneGraph and other libraries and in some cases +it allows you to just "configure and forget" without even saving the created +object to some variable, for example when adding static object to an scene: +@code +Scene3D scene; + +(new MyObject(&scene)) + ->rotateX(90.0_degf) + ->translate({-1.5f, 0.5f, 7.0f}); +@endcode +*/ +} diff --git a/doc/namespaces.dox b/doc/namespaces.dox index 7e0f7c08e..179c15fc5 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -1,3 +1,27 @@ +/* + 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. +*/ + /** @dir magnum * @brief %Magnum library */ @@ -47,6 +71,15 @@ Various matrix and vector algorithms. Functions for computing intersections, distances, areas and volumes. */ +/** @dir DebugTools + * @brief Namespace Magnum::DebugTools + */ +/** @namespace Magnum::DebugTools +@brief %Debug tools + +Debugging helpers, renderers and profilers. +*/ + /** @dir MeshTools * @brief Namespace Magnum::MeshTools */ @@ -95,6 +128,24 @@ Collision detection system and rigid body objects. See @ref collision-detection for introduction. */ +/** @dir Text + * @brief Namespace Magnum::Text + */ +/** @namespace Magnum::Text +@brief %Text rendering + +Font texture creation and text layouting. +*/ + +/** @dir TextureTools + * @brief Namespace Magnum::TextureTools + */ +/** @namespace Magnum::TextureTools +@brief %Texture tools + +Tools for generating, compressing and optimizing textures. +*/ + /** @dir Trade * @brief Namespace Magnum::Trade */ diff --git a/doc/portability.dox b/doc/portability.dox index 673ca1f42..113177123 100644 --- a/doc/portability.dox +++ b/doc/portability.dox @@ -1,3 +1,27 @@ +/* + 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 { /** @page portability Writing portable applications @brief How to support different platforms and different OpenGL capabilities within one codebase. @@ -71,10 +95,20 @@ You can also decide on particular OpenGL version using Context::isVersionSupport but remember that some features from that version might be available even if the drivers don't expose that version. -Each feature is marked accordingly if it needs specific extension or specific -OpenGL version. Various classes in %Magnum are taking advantage of some -extensions and enable faster code paths if given extension is available, for -example @ref AbstractShaderProgram-performance-optimization "AbstractShaderProgram", +On the other hand, if you don't want to write fallback code for unsupported +extensions, you can use macros MAGNUM_ASSERT_EXTENSION_SUPPORTED() or +MAGNUM_ASSERT_VERSION_SUPPORTED() to add mandatory requirement of given +extension or version: +@code +MAGNUM_ASSERT_EXTENSION_SUPPORTED(GL::ARB::geometry_shader4); +// just use geometry shader and don't care about old hardware +@endcode + +Each class, function or enum value is marked accordingly if it needs specific +extension or specific OpenGL version. Various classes in %Magnum are taking +advantage of some extensions and enable faster code paths if given extension is +available, but also have proper fallback when it's not, for example +@ref AbstractShaderProgram-performance-optimization "AbstractShaderProgram", @ref AbstractTexture-performance-optimization "AbstractTexture" or @ref Mesh-performance-optimization "Mesh". See also @ref required-extensions. @@ -121,7 +155,7 @@ Your application might run on Windows box, on some embedded Linux or even in browser - each platform has different requirements how to create entry point to the application, how to handle input events, how to create window and OpenGL context etc. Namespace Platform contains base classes for applications -which are abstracting most of it for your convenience. +which are abstracting out most of it for your convenience. All the classes support limited form of static polymorphism, which means you can switch to another base class and probably don't need to change any other @@ -136,7 +170,8 @@ macro is also aliased to MAGNUM_APPLICATION_MAIN() to save you typing. Example application, which targets both embedded Linux (using plain X and EGL) and desktop (using SDL2 toolkit). Thanks to static polymorphism most of the -functions will work on both without changes: +functions will work on both without changes, the main difference will be in +particular *Event class implementations: @code #ifndef MAGNUM_TARGET_GLES #include @@ -157,7 +192,7 @@ class MyApplication: public ApplicationBase { } protected: - void viewportEvent(const Math::Vector2& size) override { + void viewportEvent(const Vector2i& size) override { // ... } @@ -165,7 +200,7 @@ class MyApplication: public ApplicationBase { // ... } - void keyPressEvent(Key key, Modifiers modifiers, const Math::Vector2& position) { + void keyPressEvent(KeyEvent& event) override { // ... } }; diff --git a/doc/required-extensions.dox b/doc/required-extensions.dox index 58a47ebfc..554359a1f 100644 --- a/doc/required-extensions.dox +++ b/doc/required-extensions.dox @@ -1,3 +1,27 @@ +/* + 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. +*/ + /** @page required-extensions Functionality requiring specific OpenGL version or extensions @brief List of functions not available on OpenGL 2.1 / OpenGL ES 2. diff --git a/doc/scenegraph.dox b/doc/scenegraph.dox index 4c478397b..6588fe109 100644 --- a/doc/scenegraph.dox +++ b/doc/scenegraph.dox @@ -1,3 +1,27 @@ +/* + 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 SceneGraph { /** @page scenegraph Using scene graph @brief Overview of scene management capabilities. @@ -22,12 +46,12 @@ main components: Transformation handles object position, rotation etc. and its basic property is dimension count (2D or 3D) and underlying floating-point type (by default -`float`s are used everywhere, but you can use `double`s too). +@ref Float type is used everywhere, but you can use @ref Double too). -@note All classes in SceneGraph have `GLfloat` as default underlying - floating-point type, which means that you can omit that template parameter - and write just %AbstractObject<2> or %MatrixTransformation3D<> - instead of %AbstractObject<2, GLfloat> and %MatrixTransformation3D<GLfloat>. +@note All classes in SceneGraph have Float as default underlying floating-point + type, which means that you can omit that template parameter and write just + %AbstractObject<2> or %MatrixTransformation3D<> instead of + %AbstractObject<2, Float> and %MatrixTransformation3D<Float>. %Scene graph has implementation of transformations in both 2D and 3D, using either matrices or combination of position and rotation. Each implementation @@ -88,7 +112,7 @@ transformation. For convenience you can use method chaining: Object3D* next = new Object3D; next->setParent(another) ->translate(Vector3::yAxis(3.0f)) - ->rotateY(deg(35.0f)); + ->rotateY(35.0_degf); @endcode @section scenegraph-features Object features diff --git a/doc/tips.dox b/doc/tips.dox index 85e0d6ad4..3931ccd7f 100644 --- a/doc/tips.dox +++ b/doc/tips.dox @@ -1,9 +1,34 @@ +/* + 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 { /** @page tips Tips and tricks @brief Hints for better productivity and performance. -- @subpage portability - @copybrief portability -- @subpage best-practices - @copybrief best-practices -- @subpage compilation-speedup - @copybrief compilation-speedup +- @subpage method-chaining -- @copybrief method-chaining +- @subpage portability -- @copybrief portability +- @subpage best-practices -- @copybrief best-practices +- @subpage compilation-speedup -- @copybrief compilation-speedup */ } diff --git a/doc/transformations.dox b/doc/transformations.dox new file mode 100644 index 000000000..138adb951 --- /dev/null +++ b/doc/transformations.dox @@ -0,0 +1,314 @@ +/* + 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 Math { +/** @page transformations 2D and 3D transformations + +@brief Introduction to essential operations on vectors and points. + +@tableofcontents + +Transformations are essential operations involved in scene management -- object +relations, hierarchies, animations etc. %Magnum provides classes for +transformations in both 2D and 3D. Each class is suited for different purposes, +but their usage is nearly the same to make your life simpler. This page will +explain the basic operation and differences between various representations. + +@section transformations-representation Representing transformations + +The first and most straightforward way to represent transformations is to use +homogeneous transformation matrix, i.e. Matrix3 for 2D and Matrix4 for 3D. The +matrices are able to represent all possible types of transformations -- rotation, +translation, scaling, reflection etc. and also projective transformation, thus +they are used at the very core of graphics pipeline and are supported natively +in OpenGL. + +On the other hand, matrices need 9 or 16 floats to represent the transformation, +which has implications on both memory usage and performance (relatively slow +matrix multiplication). It is also relatively hard to extract transformation +properties (such as rotation angle/axis) from them, interpolate between them or +compute inverse transformation. They suffer badly from so-called floating-point +drift -- e.g. after a few combined rotations the transformation won't be pure +rotation anymore, but will involve also a bit of scaling, shearing and whatnot. + +However, you can trade some transformation features for improved performance and +better behavior -- for just a rotation you can use Complex in 2D and Quaternion +in 3D, or DualComplex and DualQuaternion if you want also translation. It is not +possible to represent scaling, reflection or other transformations with them, +but they occupy only 2 or 4 floats (4 or 8 floats in dual versions), can be +easily inverted and interpolated and have many other awesome properties. However, +they are not magic so they also suffer slightly from floating-point drift, but +not too much and the drift can be accounted for more easily than with matrices. + +@section transformations-types Transformation types + +Transformation matrices and (dual) complex numbers or quaternions have completely +different internals, but they share the same API to achieve the same things, +greatly simplifying their usage. In many cases it is even possible to hot-swap +the transformation class type without changing any function calls. + +@subsection transformations-default Default (identity) transformation + +Default-constructed Matrix3, Matrix4, Complex, Quaternion, DualComplex and +DualQuaternion represent identity transformation, so you don't need to worry +about them in initialization. + +@subsection transformations-rotation Rotation + +2D rotation is represented solely by its angle in counterclockwise direction and +rotation transformation can be created by calling Matrix3::rotation(), +Complex::rotation() or DualComplex::rotation(), for example: +@code +auto a = Matrix3::rotation(23.0_degf); +auto b = Complex::rotation(Rad(Constants::pi()/2)); +auto c = DualComplex::rotation(-1.57_radf); +@endcode + +3D rotation is represented by angle and (three-dimensional) axis. The rotation +can be created by calling Matrix4::rotation(), Quaternion::rotation() or +DualQuaternion::rotation(). The axis must be always of unit length to avoid +redundant normalization. Shortcuts Vector3::xAxis(), Vector3::yAxis() and +Vector3::zAxis() are provided for convenience. %Matrix representation has also +Matrix4::rotationX(), Matrix4::rotationY() and Matrix4::rotationZ() which are +faster than using the generic function for rotation around primary axes. +Examples: +@code +auto a = Quaternion::rotation(60.0_degf, Vector3::xAxis()); +auto b = DualQuaternion::rotation(-1.0_degf, Vector3(1.0f, 0.5f, 3.0f).normalized()); +auto c = Matrix4::rotationZ(angle); +@endcode + +Rotations are always around origin. Rotation about arbitrary point can be done +by applying translation to have the point at origin, performing the rotation and +then translating back. Read below for more information. +@todo DualQuaternion and rotation around arbitrary axis + +@subsection transformations-translation Translation + +2D translation is defined by two-dimensional vector and can be created with +Matrix3::translation() or DualComplex::translation(). You can use Vector2::xAxis() +or Vector2::yAxis() to translate only along given axis. Examples: +@code +auto a = Matrix3::translation(Vector2::xAxis(-5.0f)); +auto b = DualComplex::translation({-1.0f, 0.5f}); +@endcode + +3D translation is defined by three-dimensional vector and can be created with +Matrix4::translation() or DualQuaternion::translation(). You can use +Vector3::xAxis() and friends also here. Examples: +@code +auto a = Matrix4::translation(vector); +auto b = DualQuaternion::translation(Vector3::zAxis(1.3f)); +@endcode + +@subsection transformations-scaling Scaling and reflection + +Scaling is defined by two- or three-dimensional vector and is represented by +matrices. You can create it with Matrix3::scaling() or Matrix4::scaling(). You +can use Vector3::xScale(), Vector3::yScale(), Vector3::zScale() or their 2D +counterparts to scale along one axis and leave the rest unchanged or call +explicit one-parameter vector constructor to scale uniformly on all axes. +Examples: +@code +auto a = Matrix3::scaling(Vector2::xScale(2.0f)); +auto b = Matrix4::scaling({2.0f, -2.0f, 1.5f}); +auto c = Matrix4::scaling(Vector3(10.0f)); +@endcode + +Reflections are defined by normal along which to reflect (i.e., two- or +three-dimensional vector of unit length) and they are also represented by +matrices. Reflection is created with Matrix3::reflection() or Matrix4::reflection(). +You can use Vector3::xAxis() and friends also here. Examples: +@code +auto a = Matrix3::reflection(Vector2::yAxis()); +auto b = Matrix4::reflection(axis.normalized()); +@endcode + +Scaling and reflection is also done relative to origin, you can use method +mentioned above to scale or reflect around arbitrary point. + +Sscaling and reflection can be (to some extent) also represented by complex +numbers and quaternions, but it has some bad properties and would make some +operations more expensive, so it's not implemented. + +@subsection transformations-projective Projective transformations + +Projective transformations eploit the full potential of transformation matrices. +In 2D there is only one projection type, which can be created with Matrix3::projection() +and it is defined by area which will be projected into unit rectangle. In 3D +there is orthographic projection, created with Matrix4::orthographicProjection() +and defined by volume to project into unit cube, and perspective projection. +Perspective projection is created with Matrix4::perspectiveProjection() and is +defined either by field-of-view, aspect ratio and distance to near and far plane +of view frustum or by size of near plane, its distance and distance to far +plane. Some examples: +@code +auto a = Matrix3::projection({4.0f, 3.0f}); +auto b = Matrix4::orthographicProjection({4.0f, 3.0f, 100.0f}); +auto c = Matrix4::perspectiveProjection(35.0_degf, 1.333f, 0.001f, 100.0f); +@endcode + +@section transformations-composing Composing and inverting transformations + +Transformations (of the same representation) can be composed simply by +multiplying them, it works the same for matrices, complex numbers, quaternions +and their dual counterparts. Order of multiplication matters -- the +transformation on the right-hand side of multiplication is applied first, the +transformation on the left-hand side is applied second. For example, rotation +followed by translation is done like this: +@code +auto a = DualComplex::translation(Vector2::yAxis(2.0f))* + DualComplex::rotation(25.0_degf); +auto b = Matrix4::translation(Vector3::yAxis(5.0f))* + Matrix4::rotationY(25.0_degf); +@endcode + +Inverse transformation can be computed using Matrix3::inverted(), Matrix4::inverted(), +Complex::inverted(), Quaternion::inverted(), DualComplex::inverted() or +DualQuaternion::inverted(). %Matrix inversion is quite costly, so if your +transformation involves only translation and rotation, you can use faster +alternatives Matrix3::invertedRigid() and Matrix4::invertedRigid(). If you are +sure that the (dual) complex number or (dual) quaternion is of unit length, you +can use Complex::invertedNormalized(), Quaternion::invertedNormalized(), +DualComplex::invertedNormalized() or DualQuaternion::invertedNormalized() which +is a little bit faster, because it doesn't need to renormalize the result. + +@section transformations-transforming Transforming vectors and points + +Transformations can be used directly for transforming vectors and points. %Vector +transformation does not involve translation, in 2D can be done using +Matrix3::transformVector() and Complex::transformVector(), in 3D using +Matrix4::transformVector() and Quaternion::transformVector(). For transformation +with normalized quaternion you can use faster alternative Quaternion::transformVectorNormalized(). +Example: +@code +auto transformation = Matrix3::rotation(-30.0_degf)*Matrix3::scaling(Vector2(3.0f)); +Vector2 transformed = transformation.transformVector({1.5f, -7.9f}); +@endcode + +Point transformation involves also translation, in 2D is done with +Matrix3::transformPoint() and DualComplex::transformPoint(), in 3D with +Matrix4::transformPoint() and DualQuaternion::transformPoint(). Also here you +can use faster alternative Quaternion::transformPointNormalized(): +@code +auto transformation = DualQuaternion::rotation(-30.0_degf, Vector3::xAxis())* + DualQuaternion::translation(Vector3::yAxis(3.0f)); +Vector3 transformed = transformation.transformPointNormalized({1.5f, 3.0f, -7.9f}); +@endcode + +@section transformations-properties Transformation properties and conversion + +It is possible to extract some transformation properties from transformation +matrices, particularly translation vector, rotation/scaling part of the matrix +(or pure rotation if the matrix has uniform scaling) and also base vectors: +@code +Matrix4 a; +auto rotationScaling = transformation.rotationScaling(); +Vector3 up = transformation.up(); +Vector3 right = transformation.right(); + +Matrix3 b; +auto rotation = b.rotation(); +Float xTranslation = b.translation().x(); +@endcode +Extracting scaling and rotation from arbitrary transformation matrices is harder +and can be done using Algorithms::svd(). Extracting rotation angle (and axis in +3D) from rotation part is possible using by converting it to complex number or +quaternion, see below. + +You can also recreate transformation matrix from rotation and translation parts: +@code +Matrix3 c = Matrix3::from(rotation, {1.0f, 3.0f}); +@endcode + +%Complex numbers and quaternions are far better in this regard and they allow +you to extract rotation angle using Complex::angle() or Quaternion::angle() or +rotation axis in 3D using Quaternion::axis(). Their dual versions allow to +extract both rotation and translation part using DualComplex::rotation() const, +DualQuaternion::rotation() const, DualComplex::translation() const and +DualQuaternion::translation() const. +@code +DualComplex a; +Rad rotationAngle = a.rotation().angle(); +Vector2 translation = a.translation(); + +Quaternion b; +Vector3 rotationAxis = b.axis(); +@endcode + +You can convert Complex and Quaternion to rotation matrix using Complex::toMatrix() +and Quaternion::toMatrix() or their dual version to rotation and translation +matrix using DualComplex::toMatrix() and DualQuaternion::toMatrix(): +@code +Quaternion a; +auto rotation = Matrix4::from(a.toMatrix(), {}); + +DualComplex b; +Matrix3 transformation = b.toMatrix(); +@endcode + +Conversion the other way around is possible only from rotation matrices using +Complex::fromMatrix() or Quaternion::fromMatrix() and from rotation and +translation matrices using DualComplex::fromMatrix() and +DualQuaternion::fromMatrix(): +@code +Matrix3 rotation; +auto a = Complex::fromMatrix(rotation.rotationScaling()); + +Matrix4 transformation; +auto b = DualQuaternion::fromMatrix(transformation); +@endcode + +@section transformations-interpolation Transformation interpolation + +@todoc Write this when interpolation is done also for (dual) complex numbers and + dual quaternions + +@section transformations-normalization Normalizing transformations + +When doing multiplicative transformations, e.g. adding rotating to an +transformation many times during an animation, the resulting transformation will +accumulate rounding errors and behave strangely. For transformation matrices +this can't always be fixed, because they can represent any transformation (and +thus no algorithm can't tell if the transformation is in expected form or not). +If you restrict yourselves (e.g. only uniform scaling and no skew), the matrix +can be reorthogonalized using Algorithms::gramSchmidtOrthogonalize() (or +Algorithms::gramSchmidtOrthonormalize(), if you don't have any scaling). You can +also use Algorithms::svd() to more precisely (but way more slowly) account for +the drift. Example: +@code +Matrix4 transformation; +Math::Algorithms::gramSchmidtOrthonormalizeInPlace(transformation); +@endcode + +For quaternions and complex number this problem can be solved far more easily +using Complex::normalized(), Quaternion::normalized(), DualComplex::normalized() +and DualQuaternion::normalized(). Transformation quaternions and complex numbers +are always of unit length, thus normalizing them reduces the drift. +@code +DualQuaternion transformation; +transformation = transformation.normalized(); +@endcode +*/ +}} diff --git a/doc/types.dox b/doc/types.dox new file mode 100644 index 000000000..99d6f8755 --- /dev/null +++ b/doc/types.dox @@ -0,0 +1,99 @@ +/* + 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 { +/** @page types Type system + +@brief Type aliases, naming and compatibility with OpenGL and GLSL types + +@section types-builtin Builtin types + +%Magnum provides typedefs for builtin integral and floating-point arithmetic +types to ensure portability (e.g. Int is *always* 32bit), maintain consistency +and reduce confusion (e.g. `std::int32_t`, `int` and `GLint` all refer to the +same type). + +| %Magnum type | Size | Equivalent GLSL type | +| ------------------ | -------------- | -------------------- | +| @ref UnsignedByte | 8bit unsigned | | +| @ref Byte | 8bit signed | | +| @ref UnsignedShort | 16bit unsigned | | +| @ref Short | 16bit signed | | +| @ref UnsignedInt | 32bit unsigned | `uint` | +| @ref Int | 32bit signed | `int` | +| @ref UnsignedLong | 64bit unsigned | | +| @ref Long | 64bit signed | | +| @ref Float | 32bit | `float` | +| @ref Double | 64bit | `double` | + +Types not meant to be used in arithmetic (such as `bool` or `std::size_t`) or +types which cannot be directly passed to GLSL shaders (such as `long double`) +have no typedefs. + +Types from the above table are then used to define other types. All following +types are aliases of corresponding types in Math namespace. No suffix after type +name means @ref Float underlying type, `ui` means @ref UnsignedInt underlying +type, `i` is @ref Int underlying type and `d` is for @ref Double underlying type. + +@section types-matrix Matrix/vector types + +| %Magnum vector type | Equivalent GLSL type | +| ---------------------------------------------- | ------------------------- | +| @ref Vector2, @ref Vector3, @ref Vector4 | `vec2`, `vec3`, `vec4` | +| @ref Vector2ui, @ref Vector3ui, @ref Vector4ui | `uvec2`, `uvec3`, `uvec4` | +| @ref Vector2i, @ref Vector3i, @ref Vector4i | `ivec2`, `ivec3`, `ivec4` | +| @ref Vector2d, @ref Vector3d, @ref Vector4d | `dvec2`, `dvec3`, `dvec4` | + +| %Magnum matrix type | Equivalent GLSL type | +| --------------------------------- | ------------------------------------ | +| @ref Matrix2 or @ref Matrix2d | `mat2`/`mat2x2` or `dmat2`/`dmat2x2` | +| @ref Matrix3 or @ref Matrix3d | `mat3`/`mat3x3` or `dmat3`/`dmat3x3` | +| @ref Matrix4 or @ref Matrix4d | `mat4`/`mat4x4` or `dmat3`/`dmat4x4` | +| @ref Matrix2x3 or @ref Matrix2x3d | `mat2x3` or `dmat2x3` | +| @ref Matrix3x2 or @ref Matrix3x2d | `mat3x2` or `dmat3x2` | +| @ref Matrix2x4 or @ref Matrix2x4d | `mat2x4` or `dmat2x4` | +| @ref Matrix4x2 or @ref Matrix4x2d | `mat4x2` or `dmat4x2` | +| @ref Matrix3x4 or @ref Matrix3x4d | `mat3x4` or `dmat3x4` | +| @ref Matrix4x3 or @ref Matrix4x3d | `mat4x3` or `dmat4x3` | + +Any super- or sub-class of the same size and underlying type can be used +equivalently (e.g. Math::Vector or Color3 instead of @ref Vector3). + +@section types-other Other types + +Other types, which don't have their GLSL equivalent, are: + + - @ref Rectangle, @ref Rectanglei or @ref Rectangled + - @ref Complex or @ref Complexd, @ref DualComplex or @ref DualComplexd + - @ref Quaternion or @ref Quaterniond, @ref DualQuaternion or @ref DualQuaterniond + +These types can be used in GLSL either by extracting values from their +underlying structure or converting them to types supported by GLSL (e.g. +quaternion to matrix). + +For your convenience, there is also alias for class with often used constants -- +@ref Constants or @ref Constantsd. + +*/ +} diff --git a/doc/unsupported.dox b/doc/unsupported.dox index 4d6ae1232..85a52c830 100644 --- a/doc/unsupported.dox +++ b/doc/unsupported.dox @@ -1,3 +1,27 @@ +/* + 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. +*/ + /** @page unsupported Unsupported OpenGL features Some functionality, which is either soon-to-be deprecated or isn't proven to diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index a24503e8b..e4e61ff4a 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -1,3 +1,27 @@ +# +# 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. +# + if(NOT TARGET_GLES) add_subdirectory(GL) else() diff --git a/external/GL/CMakeLists.txt b/external/GL/CMakeLists.txt index a24337831..0cfe57d4e 100644 --- a/external/GL/CMakeLists.txt +++ b/external/GL/CMakeLists.txt @@ -1 +1,25 @@ +# +# 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. +# + install(FILES glcorearb.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/external/GL) diff --git a/external/GLES2/gl2ext.h b/external/GLES2/gl2ext.h index 8df11d9f5..9fb46cac9 100644 --- a/external/GLES2/gl2ext.h +++ b/external/GLES2/gl2ext.h @@ -1,7 +1,7 @@ #ifndef __gl2ext_h_ #define __gl2ext_h_ -/* $Revision: 19436 $ on $Date:: 2012-10-10 10:37:04 -0700 #$ */ +/* $Revision: 20040 $ on $Date:: 2013-01-03 01:43:00 -0800 #$ */ #ifdef __cplusplus extern "C" { @@ -1167,6 +1167,7 @@ typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum #endif #ifndef GL_ANGLE_instanced_arrays +#define GL_ANGLE_instanced_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); diff --git a/external/GLES3/CMakeLists.txt b/external/GLES3/CMakeLists.txt index 420ee834b..ccb237ced 100644 --- a/external/GLES3/CMakeLists.txt +++ b/external/GLES3/CMakeLists.txt @@ -1 +1,25 @@ +# +# 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. +# + install(FILES gl3.h gl3platform.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/external/GLES3) diff --git a/external/GLES3/gl3.h b/external/GLES3/gl3.h index 7d9b04d94..4d49393e2 100644 --- a/external/GLES3/gl3.h +++ b/external/GLES3/gl3.h @@ -2,7 +2,7 @@ #define __gl3_h_ /* - * gl3.h last updated on $Date: 2012-09-12 10:13:02 -0700 (Wed, 12 Sep 2012) $ + * gl3.h last updated on $Date: 2012-10-03 07:52:40 -0700 (Wed, 03 Oct 2012) $ */ #include @@ -796,7 +796,7 @@ typedef struct __GLsync *GLsync; #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_NUM_SAMPLE_COUNTS 0x9380 -#define GL_TEXTURE_IMMUTABLE_LEVELS 0x8D63 +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF /*------------------------------------------------------------------------- * Entrypoint definitions diff --git a/external/KHR/CMakeLists.txt b/external/KHR/CMakeLists.txt index 19c9ed8d8..ba1402551 100644 --- a/external/KHR/CMakeLists.txt +++ b/external/KHR/CMakeLists.txt @@ -1 +1,25 @@ +# +# 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. +# + install(FILES khrplatform.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/external/KHR) diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 7fbed6775..c4a1b4638 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -1,3 +1,27 @@ +# +# 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. +# + if(NOT CMAKE_CROSSCOMPILING) install(FILES FindMagnum.cmake DESTINATION ${MAGNUM_CMAKE_MODULE_INSTALL_DIR}) endif() diff --git a/modules/FindCorrade.cmake b/modules/FindCorrade.cmake index b1362cbd4..3edc5db9d 100644 --- a/modules/FindCorrade.cmake +++ b/modules/FindCorrade.cmake @@ -5,57 +5,41 @@ # This module tries to find Corrade library and then defines: # CORRADE_FOUND - True if Corrade library is found # CORRADE_INCLUDE_DIR - Include dir for Corrade -# CORRADE_UTILITY_LIBRARIES - Corrade Utility library and dependent -# libraries -# CORRADE_PLUGINMANAGER_LIBRARIES - Corrade Plugin manager library and +# CORRADE_INTERCONNECT_LIBRARIES - Corrade Interconnect library and +# dependent libraries +# CORRADE_UTILITY_LIBRARIES - Corrade Utility library and +# dependent libraries +# CORRADE_PLUGINMANAGER_LIBRARIES - Corrade PluginManager library and +# dependent libraries +# CORRADE_TESTSUITE_LIBRARIES - Corrade TestSuite library and # dependent libraries -# CORRADE_TESTSUITE_LIBRARIES - Corrade TestSuite library and dependent -# libraries # CORRADE_RC_EXECUTABLE - Corrade resource compiler executable # Additionally these variables are defined for internal usage: +# CORRADE_INTERCONNECT_LIBRARY - Corrade Interconnect library (w/o +# dependencies) # CORRADE_UTILITY_LIBRARY - Corrade Utility library (w/o # dependencies) # CORRADE_PLUGINMANAGER_LIBRARY - Corrade Plugin manager library (w/o # dependencies) # CORRADE_TESTSUITE_LIBRARY - Corrade TestSuite library (w/o # dependencies) +# Corrade configures the compiler to use C++11 standard. Additionally you can +# use CORRADE_CXX_FLAGS to enable additional pedantic set of warnings and enable +# hidden visibility by default. +# # If Corrade library is found, these macros and functions are defined: # # # Add unit test using Corrade's TestSuite. -# corrade_add_test2(test_name -# sources... -# [LIBRARIES libraries...]) +# corrade_add_test(test_name +# sources... +# [LIBRARIES libraries...]) # Test name is also executable name. You can also specify libraries to link # with instead of using target_link_libraries(). CORRADE_TESTSUITE_LIBRARIES # are linked atuomatically to each test. Note that the enable_testing() # function must be called explicitly. # # -# Add QtTest unit test. -# corrade_add_test(test_name moc_header source_file -# [libraries...]) -# These tests contain mainly from one source file and one header, which is -# processed by Qt meta-object compiler. The executable is then linked to QtCore -# and QtTest library, more libraries can be specified as another parameters. -# Test name is also executable name. Header file is processed with Qt's moc. -# -# Note: Before using this function you must find package Qt4. The -# enable_testing() function must be also called explicitly. -# -# -# Add QtTest unit test with multiple source files. -# corrade_add_multifile_test(test_name -# moc_header_variable -# source_files_variable) -# Useful when there is need to compile more than one cpp/h file into the test. -# -# Example usage: -# set(test_headers ComplexTest.h MyObject.h) -# set(test_sources ComplexTest.cpp MyObject.cpp) -# corrade_add_test(MyComplexTest test_headers test_sources -# CoreLibrary AnotherLibrary) -# # Compile data resources into application binary. # corrade_add_resource(name group_name # file [ALIAS alias] @@ -64,9 +48,7 @@ # generates resource file with group group_name from given files in current # build directory. Argument name is name under which the resources can be # explicitly loaded. Variable 'name' contains compiled resource filename, -# which is then used for compiling library / executable. -# -# Example usage: +# which is then used for compiling library / executable. Example usage: # corrade_add_resource(name group_name file1 ALIAS alias1 file2 file3) # add_executable(app source1 source2 ... ${name}) # @@ -84,13 +66,10 @@ # plugin_name metadata_file # sources...) # The macro adds preprocessor directive CORRADE_STATIC_PLUGIN. Additional -# libraries can be linked in via target_link_libraries(plugin_name ...). -# -# Plugin library name will be added at the end of static_plugins_variable and -# the variable is meant to be used for linking plugins to main -# executable/library, e.g: +# libraries can be linked in via target_link_libraries(plugin_name ...). Plugin +# library name will be appended to static_plugins_variable and the variable is +# meant to be used for linking plugins to main executable/library, e.g: # target_link_libraries(app lib1 lib2 ... ${static_plugins_variable}) -# # This variable is set with parent scope to be available in parent directory. # If there are more intermediate directories between plugin directory and main # executable directory, the variable can be propagated to parent scope like @@ -106,7 +85,33 @@ # DLL is not found, fatal error message is printed. # +# +# 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. +# + # Libraries +find_library(CORRADE_INTERCONNECT_LIBRARY CorradeInterconnect) find_library(CORRADE_UTILITY_LIBRARY CorradeUtility) find_library(CORRADE_PLUGINMANAGER_LIBRARY CorradePluginManager) find_library(CORRADE_TESTSUITE_LIBRARY CorradeTestSuite) @@ -122,6 +127,7 @@ find_path(CORRADE_INCLUDE_DIR include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Corrade DEFAULT_MSG CORRADE_UTILITY_LIBRARY + CORRADE_INTERCONNECT_LIBRARY CORRADE_PLUGINMANAGER_LIBRARY CORRADE_TESTSUITE_LIBRARY CORRADE_INCLUDE_DIR @@ -149,9 +155,12 @@ if(NOT _GCC46_COMPATIBILITY EQUAL -1) endif() set(CORRADE_UTILITY_LIBRARIES ${CORRADE_UTILITY_LIBRARY}) +set(CORRADE_INTERCONNECT_LIBRARIES ${CORRADE_INTERCONNECT_LIBRARY} ${CORRADE_UTILITY_LIBRARIES}) set(CORRADE_PLUGINMANAGER_LIBRARIES ${CORRADE_PLUGINMANAGER_LIBRARY} ${CORRADE_UTILITY_LIBRARIES}) set(CORRADE_TESTSUITE_LIBRARIES ${CORRADE_TESTSUITE_LIBRARY} ${CORRADE_UTILITY_LIBRARIES}) -mark_as_advanced(CORRADE_UTILITY_LIBRARY CORRADE_PLUGINMANAGER_LIBRARY CORRADE_TESTSUITE_LIBRARY) +mark_as_advanced(CORRADE_UTILITY_LIBRARY + CORRADE_INTERCONNECT_LIBRARY + CORRADE_PLUGINMANAGER_LIBRARY + CORRADE_TESTSUITE_LIBRARY) -include(CorradeMacros) -include(CorradeLibSuffix) +include(UseCorrade) diff --git a/modules/FindEGL.cmake b/modules/FindEGL.cmake index fa7ee7cda..2550a03b7 100644 --- a/modules/FindEGL.cmake +++ b/modules/FindEGL.cmake @@ -7,6 +7,30 @@ # EGL_INCLUDE_DIR - Include dir # +# +# 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. +# + # Library find_library(EGL_LIBRARY EGL) diff --git a/modules/FindGLEW.cmake b/modules/FindGLEW.cmake index abc1b044a..71f02394c 100644 --- a/modules/FindGLEW.cmake +++ b/modules/FindGLEW.cmake @@ -3,33 +3,65 @@ # This module defines: # # GLEW_FOUND - True if GLEW library is found -# GLEW_LIBRARY - GLEW dynamic library +# GLEW_LIBRARIES - GLEW libraries # GLEW_INCLUDE_DIR - Include dir # -if(GLEW_LIBRARY AND GLEW_INCLUDE_DIR) +# +# 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. +# - set(GLEW_FOUND TRUE) +# Include dir +find_path(GLEW_INCLUDE_DIR + NAMES GL/glew.h) +# Library +if(NOT WIN32) + find_library(GLEW_LIBRARY GLEW) + set(GLEW_LIBRARIES_ GLEW_LIBRARY) + mark_as_advanced(GLEW_LIBRARY) else() + find_library(GLEW_LIBRARY_DLL glew32) + find_library(GLEW_LIBRARY_LIB glew32) + set(GLEW_LIBRARIES_ GLEW_LIBRARY_DLL GLEW_LIBRARY_LIB) + mark_as_advanced(GLEW_LIBRARY_DLL GLEW_LIBRARY_LIB) +endif() - # Library - if(NOT WIN32) - find_library(GLEW_LIBRARY GLEW) - else() - find_library(GLEW_LIBRARY glew32) - endif() +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args("GLEW" DEFAULT_MSG + ${GLEW_LIBRARIES_} + GLEW_INCLUDE_DIR) - # Include dir - find_path(GLEW_INCLUDE_DIR - NAMES glew.h - PATH_SUFFIXES GL - ) +if(NOT GLEW_FOUND) + return() +endif() - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args("GLEW" DEFAULT_MSG - GLEW_LIBRARY - GLEW_INCLUDE_DIR - ) +unset(GLEW_LIBRARIES_) +if(NOT WIN32) + set(GLEW_LIBRARIES ${GLEW_LIBRARY}) + mark_as_advanced(GLEW_LIBRARY) +else() + set(GLEW_LIBRARIES ${GLEW_LIBRARY_DLL} ${GLEW_LIBRARY_LIB}) + mark_as_advanced(GLEW_LIBRARY_DLL GLEW_LIBRARY_LIB) endif() diff --git a/modules/FindHarfBuzz.cmake b/modules/FindHarfBuzz.cmake new file mode 100644 index 000000000..f4b0139f5 --- /dev/null +++ b/modules/FindHarfBuzz.cmake @@ -0,0 +1,57 @@ +# - Find HarfBuzz +# +# This module tries to find HarfBuzz library and then defines: +# HARFBUZZ_FOUND - True if HarfBuzz library is found +# HARFBUZZ_INCLUDE_DIRS - Include dirs +# HARFBUZZ_LIBRARIES - HarfBuzz libraries +# +# Additionally these variables are defined for internal usage: +# HARFBUZZ_INCLUDE_DIR - Include dir (w/o dependencies) +# HARFBUZZ_LIBRARY - HarfBuzz library (w/o dependencies) +# + +# +# 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. +# + +# Library +find_library(HARFBUZZ_LIBRARY NAMES harfbuzz) + +# Include dir +find_path(HARFBUZZ_INCLUDE_DIR + NAMES hb.h + PATH_SUFFIXES harfbuzz +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args("HarfBuzz" DEFAULT_MSG + HARFBUZZ_LIBRARY + HARFBUZZ_INCLUDE_DIR +) + +set(HARFBUZZ_INCLUDE_DIRS ${HARFBUZZ_INCLUDE_DIR}) +set(HARFBUZZ_LIBRARIES ${HARFBUZZ_LIBRARY}) + +mark_as_advanced(FORCE + HARFBUZZ_LIBRARY + HARFBUZZ_INCLUDE_DIR) diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 52d1bd474..b94183bcb 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -15,18 +15,25 @@ # components. The base library depends on Corrade, OpenGL and GLEW # libraries. Additional dependencies are specified by the components. The # optional components are: -# MeshTools - MeshTools library -# Physics - Physics library (depends on Primitives, SceneGraph and -# Shaders components) -# Primitives - Library with stock geometric primitives (static) -# SceneGraph - Scene graph library -# Shaders - Library with stock shaders -# GlxApplication - GLX application (depends on X11 libraries) -# XEglApplication - X/EGL application (depends on EGL and X11 libraries) -# GlutApplication - GLUT application (depends on GLUT library) -# Sdl2Application - SDL2 application (depends on SDL2 library) -# NaClApplication - NaCl application (only if targetting Google Chrome -# Native Client) +# DebugTools - DebugTools library (depends on MeshTools, Physics, +# Primitives, SceneGraph and Shaders components) +# MeshTools - MeshTools library +# Physics - Physics library +# Primitives - Library with stock geometric primitives (static) +# SceneGraph - Scene graph library +# Shaders - Library with stock shaders +# Text - Text rendering library (depends on TextureTools +# component, FreeType library and possibly HarfBuzz +# library, see below) +# TextureTools - TextureTools library +# GlxApplication - GLX application (depends on X11 libraries) +# XEglApplication - X/EGL application (depends on EGL and X11 libraries) +# WindowlessGlxApplication - Windowless GLX application (depends on X11 +# libraries) +# GlutApplication - GLUT application (depends on GLUT library) +# Sdl2Application - SDL2 application (depends on SDL2 library) +# NaClApplication - NaCl application (only if targetting Google Chrome +# Native Client) # Example usage with specifying additional components is: # find_package(Magnum [REQUIRED|COMPONENTS] # MeshTools Primitives GlutApplication) @@ -35,6 +42,16 @@ # MAGNUM_*_LIBRARIES - Component library and dependent libraries # MAGNUM_*_INCLUDE_DIRS - Include dirs of module dependencies # +# Features of found Magnum library are exposed in these variables: +# MAGNUM_TARGET_GLES - Defined if compiled for OpenGL ES +# MAGNUM_TARGET_GLES2 - Defined if compiled for OpenGL ES 2.0 +# MAGNUM_TARGET_DESKTOP_GLES - Defined if compiled with OpenGL ES +# emulation on desktop OpenGL +# MAGNUM_TARGET_NACL - Defined if compiled for Google Chrome Native +# Client +# MAGNUM_USE_HARFBUZZ - Defined if HarfBuzz library is used for text +# rendering +# # Additionally these variables are defined for internal usage: # MAGNUM_INCLUDE_DIR - Root include dir (w/o # dependencies) @@ -53,6 +70,30 @@ # directory # +# +# 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. +# + # Dependencies find_package(Corrade REQUIRED) @@ -80,13 +121,23 @@ string(FIND "${_magnumConfigure}" "#define MAGNUM_TARGET_NACL" _TARGET_NACL) if(NOT _TARGET_NACL EQUAL -1) set(MAGNUM_TARGET_NACL 1) endif() +string(FIND "${_magnumConfigure}" "#define MAGNUM_TARGET_DESKTOP_GLES" _TARGET_DESKTOP_GLES) +if(NOT _TARGET_DESKTOP_GLES EQUAL -1) + set(MAGNUM_TARGET_DESKTOP_GLES 1) +endif() +string(FIND "${_magnumConfigure}" "#define MAGNUM_USE_HARFBUZZ" _USE_HARFBUZZ) +if(NOT _USE_HARFBUZZ EQUAL -1) + set(MAGNUM_USE_HARFBUZZ 1) +endif() -if(NOT MAGNUM_TARGET_GLES) +if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES) find_package(OpenGL REQUIRED) - find_package(GLEW REQUIRED) else() find_package(OpenGLES2 REQUIRED) endif() +if(NOT MAGNUM_TARGET_GLES) + find_package(GLEW REQUIRED) +endif() # On Windows, *Application libraries need to have ${MAGNUM_LIBRARY} listed # in dependencies also after *Application.lib static library name to avoid @@ -152,6 +203,21 @@ foreach(component ${Magnum_FIND_COMPONENTS}) unset(MAGNUM_${_COMPONENT}_LIBRARY) endif() endif() + + # Windowless GLX application dependencies + if(${component} STREQUAL WindowlessGlxApplication) + find_package(X11) + if(X11_FOUND) + set(_MAGNUM_${_COMPONENT}_LIBRARIES ${X11_LIBRARIES} ${_WINDOWCONTEXT_MAGNUM_LIBRARY_DEPENDENCY}) + else() + unset(MAGNUM_${_COMPONENT}_LIBRARY) + endif() + endif() + endif() + + # DebugTools library + if(${component} STREQUAL DebugTools) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Profiler.h) endif() # Mesh tools library @@ -179,6 +245,28 @@ foreach(component ${Magnum_FIND_COMPONENTS}) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongShader.h) endif() + # Text library + if(${component} STREQUAL Text) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Font.h) + + # Dependencies + find_package(Freetype) + if(NOT FREETYPE_FOUND) + unset(MAGNUM_${_COMPONENT}_LIBRARY) + endif() + if(MAGNUM_USE_HARFBUZZ) + find_package(HarfBuzz) + if(NOT HARFBUZZ_FOUND) + unset(MAGNUM_${_COMPONENT}_LIBRARY) + endif() + endif() + endif() + + # TextureTools library + if(${component} STREQUAL TextureTools) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Atlas.h) + endif() + # Try to find the includes if(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES) find_path(_MAGNUM_${_COMPONENT}_INCLUDE_DIR @@ -212,13 +300,13 @@ set(MAGNUM_INCLUDE_DIRS ${MAGNUM_INCLUDE_DIR} set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARY} ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY}) -if(NOT MAGNUM_TARGET_GLES) - set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} - ${OPENGL_gl_LIBRARY} - ${GLEW_LIBRARY}) +if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES) + set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGL_gl_LIBRARY}) else() - set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} - ${OPENGLES2_LIBRARY}) + set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGLES2_LIBRARY}) +endif() +if(NOT MAGNUM_TARGET_GLES) + set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${GLEW_LIBRARIES}) endif() # Installation dirs diff --git a/modules/FindOpenGLES2.cmake b/modules/FindOpenGLES2.cmake index 414db8368..3bc3865a3 100644 --- a/modules/FindOpenGLES2.cmake +++ b/modules/FindOpenGLES2.cmake @@ -7,6 +7,30 @@ # OPENGLES2_INCLUDE_DIR - Include dir # +# +# 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. +# + # Library find_library(OPENGLES2_LIBRARY NAMES GLESv2 diff --git a/modules/FindSDL2.cmake b/modules/FindSDL2.cmake index 9ac6e9020..f352a7b58 100644 --- a/modules/FindSDL2.cmake +++ b/modules/FindSDL2.cmake @@ -7,6 +7,30 @@ # SDL2_INCLUDE_DIR - Include dir # +# +# 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. +# + # Library find_library(SDL2_LIBRARY SDL2) diff --git a/package/archlinux/magnum-git/PKGBUILD b/package/archlinux/magnum-git/PKGBUILD index f4931acf7..5e3128719 100644 --- a/package/archlinux/magnum-git/PKGBUILD +++ b/package/archlinux/magnum-git/PKGBUILD @@ -5,7 +5,7 @@ pkgrel=1 pkgdesc="OpenGL 3 graphics engine (Git version)" arch=('i686' 'x86_64') url="https://github.com/mosra/magnum" -license=('LGPLv3') +license=('MIT') depends=('corrade-git' 'glew') makedepends=('cmake' 'git') diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp new file mode 100644 index 000000000..ac57b4402 --- /dev/null +++ b/src/AbstractFramebuffer.cpp @@ -0,0 +1,250 @@ +/* + 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 "AbstractFramebuffer.h" + +#include "BufferImage.h" +#include "Context.h" +#include "Extensions.h" +#include "Image.h" + +#include "Implementation/FramebufferState.h" +#include "Implementation/State.h" + +namespace Magnum { + +#ifndef DOXYGEN_GENERATING_OUTPUT +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 + +void AbstractFramebuffer::bind(Target target) { + bindInternal(target); + setViewportInternal(); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +void AbstractFramebuffer::bindInternal(Target target) { + Implementation::FramebufferState* state = Context::current()->state()->framebuffer; + + /* If already bound, done, otherwise update tracked state */ + if(target == Target::Read) { + if(state->readBinding == _id) return; + state->readBinding = _id; + } else if(target == Target::Draw) { + if(state->drawBinding == _id) return; + state->drawBinding = _id; + } else if(target == Target::ReadDraw) { + if(state->readBinding == _id && state->drawBinding == _id) return; + state->readBinding = state->drawBinding = _id; + } else CORRADE_INTERNAL_ASSERT(false); + + glBindFramebuffer(static_cast(target), _id); +} + +AbstractFramebuffer::Target 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; + if(state->readBinding == _id) + return Target::Read; + if(state->drawBinding == _id) + return Target::Draw; + + /* Or bind it, if not already */ + state->readBinding = _id; + if(readTarget == Target::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); + /** @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)); + #else + static_cast(sourceRectangle); + static_cast(destinationRectangle); + static_cast(mask); + static_cast(filter); + #endif +} + +AbstractFramebuffer* AbstractFramebuffer::setViewport(const Rectanglei& rectangle) { + _viewport = rectangle; + + /* Update the viewport if the framebuffer is currently bound */ + if(Context::current()->state()->framebuffer->drawBinding == _id) + setViewportInternal(); + + return this; +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +void AbstractFramebuffer::setViewportInternal() { + Implementation::FramebufferState* state = Context::current()->state()->framebuffer; + + CORRADE_INTERNAL_ASSERT(state->drawBinding == _id); + + /* Already up-to-date, nothing to do */ + if(state->viewport == _viewport) + return; + + /* Update the state and viewport */ + state->viewport = _viewport; + glViewport(_viewport.left(), _viewport.bottom(), _viewport.width(), _viewport.height()); +} +#endif + +void AbstractFramebuffer::clear(ClearMask mask) { + bindInternal(drawTarget); + glClear(static_cast(mask)); +} + +void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, 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); +} + +#ifndef MAGNUM_TARGET_GLES2 +void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, 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); + + image->buffer()->bind(Buffer::Target::PixelPack); + glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), 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 + glInvalidateFramebuffer(GLenum(bindInternal()), count, attachments); + #else + //glDiscardFramebufferEXT(GLenum(bindInternal()), count, attachments); + static_cast(count); + static_cast(attachments); + #endif +} + +void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attachments, const Rectanglei& rectangle) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glInvalidateSubFramebuffer(GLenum(bindInternal()), count, attachments, rectangle.left(), rectangle.bottom(), rectangle.width(), rectangle.height()); + #else + //glDiscardSubFramebufferEXT(GLenum(bindInternal()), count, attachments, rectangle.left(), rectangle.bottom(), rectangle.width(), rectangle.height()); + static_cast(count); + static_cast(attachments); + 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; + } + + if(context->isExtensionSupported()) { + Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; + drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; + readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; + } + #else + static_cast(context); + #endif +} + +void AbstractFramebuffer::drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(drawTarget); + glDrawBuffers(count, buffers); + #else + static_cast(count); + static_cast(buffers); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::drawBuffersImplementationDSA(GLsizei count, const GLenum* buffers) { + glFramebufferDrawBuffersEXT(_id, count, buffers); +} +#endif + +void AbstractFramebuffer::drawBufferImplementationDefault(GLenum buffer) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(drawTarget); + glDrawBuffer(buffer); + #else + static_cast(buffer); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::drawBufferImplementationDSA(GLenum buffer) { + glFramebufferDrawBufferEXT(_id, buffer); +} +#endif + +void AbstractFramebuffer::readBufferImplementationDefault(GLenum buffer) { + /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(readTarget); + glReadBuffer(buffer); + #else + static_cast(buffer); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::readBufferImplementationDSA(GLenum buffer) { + glFramebufferReadBufferEXT(_id, buffer); +} +#endif + +} diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h new file mode 100644 index 000000000..34615da53 --- /dev/null +++ b/src/AbstractFramebuffer.h @@ -0,0 +1,310 @@ +#ifndef Magnum_AbstractFramebuffer_h +#define Magnum_AbstractFramebuffer_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::AbstractFramebuffer + */ + +#include + +#include "Math/Geometry/Rectangle.h" +#include "AbstractImage.h" +#include "Buffer.h" + +namespace Magnum { + +/** +@brief Base for default and named framebuffers + +See DefaultFramebuffer and Framebuffer for more information. + +@section AbstractFramebuffer-performance-optimization Performance optimizations + +The engine tracks currently bound framebuffer and current viewport to avoid +unnecessary calls to @fn_gl{BindFramebuffer} and @fn_gl{Viewport} when +switching framebuffers. + +@todo @extension{ARB,viewport_array} +*/ +class MAGNUM_EXPORT AbstractFramebuffer { + friend class Context; + + AbstractFramebuffer(const AbstractFramebuffer& other) = delete; + AbstractFramebuffer(AbstractFramebuffer&& other) = delete; + AbstractFramebuffer& operator=(const AbstractFramebuffer& other) = delete; + AbstractFramebuffer& operator=(AbstractFramebuffer&& other) = 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} + */ + 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} + */ + 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} + * or @es_extension{ANGLE,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} + * or @es_extension{ANGLE,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 + * @param destination Destination framebuffer + * @param sourceRectangle Source rectangle + * @param destinationRectangle Destination rectangle + * @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(), + * Framebuffer::mapForRead(), DefaultFramebuffer::mapForDraw() and + * Framebuffer::mapForDraw() for specifying particular buffers for + * blitting operation. + * @see @fn_gl{BlitFramebuffer} + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} + */ + static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, BlitMask mask, BlitFilter filter); + + /** + * @brief Copy block of pixels + * @param source Source framebuffer + * @param destination Destination framebuffer + * @param rectangle Source and destination rectangle + * @param mask Which buffers to perform blit operation on + * + * 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. + * @see @fn_gl{BlitFramebuffer} + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} + */ + inline static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& rectangle, BlitMask mask) { + blit(source, destination, rectangle, rectangle, mask, BlitFilter::Nearest); + } + + explicit AbstractFramebuffer() = default; + virtual ~AbstractFramebuffer() = 0; + + /** + * @brief Bind framebuffer for rendering + * + * Binds the framebuffer and updates viewport to saved dimensions. + * @see setViewport(), DefaultFramebuffer::mapForRead(), + * Framebuffer::mapForRead(), DefaultFramebuffer::mapForDraw(), + * Framebuffer::mapForDraw(), @fn_gl{BindFramebuffer}, + * @fn_gl{Viewport} + */ + void bind(Target target); + + /** @brief Viewport rectangle */ + inline Rectanglei viewport() const { return _viewport; } + + /** + * @brief Set viewport + * @return Pointer to self (for method chaining) + * + * Saves the viewport to be used at later time in bind(). If the + * framebuffer is currently bound, updates the viewport to given + * rectangle. + * @see @fn_gl{Viewport} + */ + AbstractFramebuffer* setViewport(const Rectanglei& rectangle); + + /** + * @brief Clear specified buffers in framebuffer + * @param mask Which buffers to clear + * + * To improve performance you can also use + * DefaultFramebuffer::invalidate() / Framebuffer::invalidate() instead + * of clearing given buffer if you will not use it anymore or fully + * overwrite it later. + * @see Renderer::setClearColor(), Renderer::setClearDepth(), + * Renderer::setClearStencil(), @fn_gl{BindFramebuffer}, + * @fn_gl{Clear} + */ + void clear(ClearMask 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? + */ + void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, 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} + * @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); + #endif + + #ifndef DOXYGEN_GENERATING_OUTPUT + protected: + void MAGNUM_LOCAL bindInternal(Target target); + Target MAGNUM_LOCAL bindInternal(); + void MAGNUM_LOCAL setViewportInternal(); + + static MAGNUM_LOCAL Target readTarget; + static MAGNUM_LOCAL Target drawTarget; + + typedef void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*); + static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation; + + typedef void(AbstractFramebuffer::*DrawBufferImplementation)(GLenum); + static DrawBufferImplementation drawBufferImplementation; + + typedef void(AbstractFramebuffer::*ReadBufferImplementation)(GLenum); + static ReadBufferImplementation readBufferImplementation; + + void MAGNUM_LOCAL invalidateImplementation(GLsizei count, GLenum* attachments); + void MAGNUM_LOCAL invalidateImplementation(GLsizei count, GLenum* attachments, const Rectanglei& rectangle); + + GLuint _id; + Rectanglei _viewport; + #endif + + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + void MAGNUM_LOCAL drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL drawBuffersImplementationDSA(GLsizei count, const GLenum* buffers); + #endif + + void MAGNUM_LOCAL drawBufferImplementationDefault(GLenum buffer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL drawBufferImplementationDSA(GLenum buffer); + #endif + + void MAGNUM_LOCAL readBufferImplementationDefault(GLenum buffer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL readBufferImplementationDSA(GLenum buffer); + #endif +}; + +inline AbstractFramebuffer::~AbstractFramebuffer() {} + +CORRADE_ENUMSET_OPERATORS(AbstractFramebuffer::ClearMask) +CORRADE_ENUMSET_OPERATORS(AbstractFramebuffer::BlitMask) + +} + +#endif diff --git a/src/AbstractImage.cpp b/src/AbstractImage.cpp index 04f14f2b6..6d34289e3 100644 --- a/src/AbstractImage.cpp +++ b/src/AbstractImage.cpp @@ -1,105 +1,216 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ + 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: -#include "AbstractImage.h" + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. -#include + 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 "TypeTraits.h" +#include "AbstractImage.h" -using namespace std; +#include namespace Magnum { -size_t AbstractImage::pixelSize(Components format, ComponentType type) { - size_t size = 0; +std::size_t AbstractImage::pixelSize(Format format, Type type) { + std::size_t size = 0; switch(type) { - #ifndef MAGNUM_TARGET_GLES - case ComponentType::RGB332: - case ComponentType::BGR233: - return 1; + case Type::UnsignedByte: + #ifndef MAGNUM_TARGET_GLES2 + case Type::Byte: #endif - case ComponentType::RGB565: - #ifndef MAGNUM_TARGET_GLES - case ComponentType::BGR565: + size = 1; break; + case Type::UnsignedShort: + #ifndef MAGNUM_TARGET_GLES2 + case Type::Short: + #endif + case Type::HalfFloat: + size = 2; break; + case Type::UnsignedInt: + #ifndef MAGNUM_TARGET_GLES2 + case Type::Int: #endif - case ComponentType::RGBA4: + case Type::Float: + size = 4; break; + #ifndef MAGNUM_TARGET_GLES - case ComponentType::ABGR4: + case Type::UnsignedByte332: + case Type::UnsignedByte233Rev: + return 1; #endif - case ComponentType::RGB5Alpha1: + case Type::UnsignedShort565: #ifndef MAGNUM_TARGET_GLES - case ComponentType::Alpha1BGR5: + case Type::UnsignedShort565Rev: #endif + case Type::UnsignedShort4444: + case Type::UnsignedShort4444Rev: + case Type::UnsignedShort5551: + case Type::UnsignedShort1555Rev: return 2; #ifndef MAGNUM_TARGET_GLES - case ComponentType::RGBA8: - case ComponentType::ABGR8: - case ComponentType::RGB10Alpha2: - case ComponentType::Alpha2RGB10: - case ComponentType::Depth24Stencil8: - case ComponentType::B10GR11Float: - case ComponentType::Exponent5RGB9: + case Type::UnsignedInt8888: + case Type::UnsignedInt8888Rev: + case Type::UnsignedInt1010102: + #endif + case Type::UnsignedInt2101010Rev: + #ifndef MAGNUM_TARGET_GLES2 + case Type::UnsignedInt10F11F11FRev: + case Type::UnsignedInt5999Rev: + #endif + case Type::UnsignedInt248: return 4; - case ComponentType::Depth32FloatStencil8: + #ifndef MAGNUM_TARGET_GLES2 + case Type::Float32UnsignedInt248Rev: return 8; #endif - case ComponentType::UnsignedByte: - case ComponentType::Byte: - size = 1; break; - case ComponentType::UnsignedShort: - case ComponentType::Short: - #ifndef MAGNUM_TARGET_GLES - case ComponentType::HalfFloat: - size = 2; break; - #endif - case ComponentType::UnsignedInt: - case ComponentType::Int: - case ComponentType::Float: - size = 4; break; } switch(format) { + case Format::Red: + #ifndef MAGNUM_TARGET_GLES2 + case Format::RedInteger: + #endif #ifndef MAGNUM_TARGET_GLES - case Components::Red: - case Components::Green: - case Components::Blue: + case Format::Green: + case Format::Blue: + case Format::GreenInteger: + case Format::BlueInteger: + #endif return 1*size; - case Components::RedGreen: + case Format::RG: + #ifndef MAGNUM_TARGET_GLES2 + case Format::RGInteger: + #endif return 2*size; + case Format::RGB: + #ifndef MAGNUM_TARGET_GLES2 + case Format::RGBInteger: #endif - case Components::RGB: #ifndef MAGNUM_TARGET_GLES - case Components::BGR: + case Format::BGR: + case Format::BGRInteger: #endif return 3*size; - case Components::RGBA: + case Format::RGBA: + #ifndef MAGNUM_TARGET_GLES2 + case Format::RGBAInteger: + #endif + case Format::BGRA: #ifndef MAGNUM_TARGET_GLES - case Components::BGRA: + case Format::BGRAInteger: #endif return 4*size; - #ifndef MAGNUM_TARGET_GLES - case Components::Depth: - case Components::StencilIndex: - case Components::DepthStencil: + /* Handled above */ + case Format::DepthComponent: + case Format::StencilIndex: + case Format::DepthStencil: CORRADE_INTERNAL_ASSERT(false); - #endif } + CORRADE_INTERNAL_ASSERT(false); 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 + _c(BGRA) + #ifndef MAGNUM_TARGET_GLES2 + _c(RedInteger) + _c(GreenInteger) + _c(BlueInteger) + _c(RGInteger) + _c(RGBInteger) + _c(RGBAInteger) + _c(BGRInteger) + _c(BGRAInteger) + #endif + _c(DepthComponent) + _c(StencilIndex) + _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_GLES2 + _c(UnsignedByte332) + _c(UnsignedByte233Rev) + #endif + _c(UnsignedShort565) + #ifndef MAGNUM_TARGET_GLES + _c(UnsignedShort565Rev) + #endif + _c(UnsignedShort4444) + _c(UnsignedShort4444Rev) + _c(UnsignedShort5551) + _c(UnsignedShort1555Rev) + #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 e310ff00a..6de9cd7cc 100644 --- a/src/AbstractImage.h +++ b/src/AbstractImage.h @@ -1,18 +1,27 @@ #ifndef Magnum_AbstractImage_h #define Magnum_AbstractImage_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,7 +31,7 @@ #include #include "Magnum.h" - +#include "OpenGL.h" #include "magnumVisibility.h" namespace Magnum { @@ -30,7 +39,12 @@ namespace Magnum { /** @brief Non-templated base for one-, two- or three-dimensional images -See Image, BufferedImage, Trade::ImageData documentation for more information. +See Image, ImageWrapper, BufferImage, Trade::ImageData documentation for +more information. +@todo Where to put glClampColor() and glPixelStore() encapsulation? It is +needed in AbstractFramebuffer::read(), Texture::setImage() etc (i.e. all +functions operating with images). It also possibly needs to be "stackable" to +easily revert the state back. */ class MAGNUM_EXPORT AbstractImage { AbstractImage(const AbstractImage& other) = delete; @@ -44,220 +58,391 @@ class MAGNUM_EXPORT AbstractImage { * * Note that some formats can be used only for framebuffer reading * (using Framebuffer::read()) and some only for texture data (using - * Texture::setData() and others). + * Texture::setImage() and others). */ - /** @brief Color components */ - /** @todo Support *_INTEGER types */ - enum class Components: GLenum { - #ifndef MAGNUM_TARGET_GLES + /** + * @brief Format of pixel data + * + * @todo What is allowed for FB reading and what for image + * specification? + * @see pixelSize() + */ + enum class Format: GLenum { /** - * One-component (red channel) - * @requires_gl + * Floating-point red channel. + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} */ + #ifndef MAGNUM_TARGET_GLES2 Red = GL_RED, + #else + Red = GL_RED_EXT, + #endif + #ifndef MAGNUM_TARGET_GLES /** - * One-component (green channel). For framebuffer reading only. - * @requires_gl + * Floating-point green channel. For framebuffer reading only. + * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::Red" + * is available in OpenGL ES. */ Green = GL_GREEN, /** - * One-component (green channel). For framebuffer reading only. - * @requires_gl + * Floating-point blue channel. For framebuffer reading only. + * @requires_gl Only @ref Magnum::AbstractImage::Format "Format::Red" + * is available in OpenGL ES. */ Blue = GL_BLUE, + /** @todo GL_ALPHA? */ + #endif + /** - * Two-component (red and green channel). For texture data only. - * @requires_gl + * Floating-point red and green channel. For texture data only. + * @requires_gl30 %Extension @extension{ARB,texture_rg} and + * @extension{EXT,texture_integer} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} */ - RedGreen = GL_RG, + #ifndef MAGNUM_TARGET_GLES2 + RG = GL_RG, + #else + RG = GL_RG_EXT, #endif - RGB = GL_RGB, /**< Three-component RGB */ - RGBA = GL_RGBA /**< Four-component RGBA */ + /** Floating-point RGB. */ + RGB = GL_RGB, - #ifndef MAGNUM_TARGET_GLES - , + /** Floating-point RGBA. */ + RGBA = GL_RGBA, + #ifndef MAGNUM_TARGET_GLES /** - * Three-component BGR - * @requires_gl + * Floating-point BGR. + * @requires_gl Only RGB component ordering is available in OpenGL + * ES. */ BGR = GL_BGR, + #endif /** - * Four-component BGRA - * @requires_gl + * 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 + + #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_gles30 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_gles30 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. For framebuffer reading only. - * @requires_gl + * @requires_gles30 %Extension @es_extension2{NV,read_depth,GL_NV_read_depth_stencil} */ - Depth = GL_DEPTH_COMPONENT, + DepthComponent = GL_DEPTH_COMPONENT, /** * Stencil index. For framebuffer reading only. - * @requires_gl + * @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 /** - * Depth and stencil component. For framebuffer reading only. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,packed_depth_stencil} + * Depth and stencil. For framebuffer reading only. + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gles30 %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 */ - enum class ComponentType: GLenum { - UnsignedByte = GL_UNSIGNED_BYTE, /**< Each component unsigned byte */ - Byte = GL_BYTE, /**< Each component byte */ - UnsignedShort = GL_UNSIGNED_SHORT, /**< Each component unsigned short */ - Short = GL_SHORT, /**< Each component short */ - UnsignedInt = GL_UNSIGNED_INT, /**< Each component unsigned int */ - Int = GL_INT, /**< Each component int */ + /** + * @brief Data type of pixel data + * + * @see pixelSize() + */ + enum class Type: GLenum { + /** Each component unsigned byte. */ + UnsignedByte = GL_UNSIGNED_BYTE, - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 /** - * Each component half float (16bit). For framebuffer reading only. - * - * @requires_gl - * @requires_gl30 Extension @extension{NV,half_float} / @extension{ARB,half_float_pixel} + * Each component signed byte. + * @requires_gles30 Only @ref Magnum::AbstractImage::Type "Type::UnsignedByte" + * is available in OpenGL ES 2.0. */ - HalfFloat = GL_HALF_FLOAT, + Byte = GL_BYTE, #endif - Float = GL_FLOAT, /**< Each component float (32bit) */ - - #ifndef MAGNUM_TARGET_GLES /** - * Three-component RGB, unsigned normalized, red and green 3bit, - * blue 2bit, 8bit total. - * @requires_gl + * Each component unsigned short. + * @requires_gles30 %Extension @es_extension{OES,depth_texture} */ - RGB332 = GL_UNSIGNED_BYTE_3_3_2, + UnsignedShort = GL_UNSIGNED_SHORT, + #ifndef MAGNUM_TARGET_GLES2 /** - * Three-component BGR, unsigned normalized, red and green 3bit, - * blue 2bit, 8bit total. - * @requires_gl + * Each component signed short. + * @requires_gles30 Only @ref Magnum::AbstractImage::Type "Type::UnsignedShort" + * is available in OpenGL ES 2.0. */ - BGR233 = GL_UNSIGNED_BYTE_2_3_3_REV, + Short = GL_SHORT, #endif /** - * Three-component RGB, unsigned normalized, red and blue 5bit, - * green 6bit, 16bit total. + * Each component unsigned int. + * @requires_gles30 %Extension @es_extension{OES,depth_texture} */ - RGB565 = GL_UNSIGNED_SHORT_5_6_5, + 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 - #ifndef MAGNUM_TARGET_GLES /** - * Three-component BGR, unsigned normalized, red and blue 5bit, - * green 6bit, 16bit total. - * @requires_gl + * Each component half float. For framebuffer reading only. + * @requires_gl30 %Extension @extension{NV,half_float} / @extension{ARB,half_float_pixel} + * @requires_gles30 %Extension @es_extension2{OES,texture_half_float,OES_texture_float}, + * for texture data only. */ - BGR565 = GL_UNSIGNED_SHORT_5_6_5_REV, + #ifndef MAGNUM_TARGET_GLES2 + HalfFloat = GL_HALF_FLOAT, + #else + HalfFloat = GL_HALF_FLOAT_OES, #endif /** - * Four-component RGBA, unsigned normalized, each component 4bit, - * 16bit total. + * Each component float. + * @requires_gles30 %Extension @es_extension{OES,texture_float} */ - RGBA4 = GL_UNSIGNED_SHORT_4_4_4_4, + Float = GL_FLOAT, #ifndef MAGNUM_TARGET_GLES /** - * Four-component ABGR, unsigned normalized, each component 4bit, - * 16bit total. - * @requires_gl + * RGB, unsigned byte, red and green component 3bit, blue + * component 2bit. + * @requires_gl Packed 12bit types are not available in OpenGL ES. */ - ABGR4 = GL_UNSIGNED_SHORT_4_4_4_4_REV, + 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. */ + UnsignedShort565 = GL_UNSIGNED_SHORT_5_6_5, + + #ifndef MAGNUM_TARGET_GLES /** - * Four-component RGBA, unsigned normalized, each RGB component - * 5bit, alpha 1bit, 16bit total. + * BGR, unsigned short, red and blue 5bit, green 6bit. + * @requires_gl Only @ref Magnum::AbstractImage::Type "Type::RGB565" + * is available in OpenGL ES. */ - RGB5Alpha1 = GL_UNSIGNED_SHORT_5_5_5_1 + UnsignedShort565Rev = GL_UNSIGNED_SHORT_5_6_5_REV, + #endif + + /** RGBA, unsigned short, each component 4bit. */ + UnsignedShort4444 = GL_UNSIGNED_SHORT_4_4_4_4, + /** + * ABGR, unsigned short, each component 4bit. + * @requires_es_extension %Extension @es_extension{EXT,read_format_bgra}, + * for framebuffer reading only. + */ #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 + + /** + * RGBA, unsigned short, each RGB component 5bit, alpha component + * 1bit. + */ + UnsignedShort5551 = GL_UNSIGNED_SHORT_5_5_5_1, /** - * Four-component ABGR, unsigned normalized, each RGB component - * 5bit, alpha 1bit, 16bit total. - * @requires_gl + * ABGR, unsigned short, each RGB component 5bit, alpha component + * 1bit. + * @requires_es_extension %Extension @es_extension{EXT,read_format_bgra}, + * for framebuffer reading only. */ - Alpha1BGR5 = GL_UNSIGNED_SHORT_1_5_5_5_REV, + #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 + #ifndef MAGNUM_TARGET_GLES /** - * Four-component RGBA, unsigned normalized, each component 8bit, - * 32bit total. - * @requires_gl + * RGBA, unsigned int, each component 8bit. + * @requires_gl Use @ref Magnum::AbstractImage::Type "Type::UnsignedByte" + * in OpenGL ES instead. */ - RGBA8 = GL_UNSIGNED_INT_8_8_8_8, + UnsignedInt8888 = GL_UNSIGNED_INT_8_8_8_8, /** - * Four-component ABGR, unsigned normalized, each component 8bit, - * 32bit total. - * @requires_gl + * 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. */ - ABGR8 = GL_UNSIGNED_INT_8_8_8_8_REV, + UnsignedInt8888Rev = GL_UNSIGNED_INT_8_8_8_8_REV, /** - * Four-component RGBA, unsigned normalized, each RGB component - * 10bit, alpha 2bit, 32bit total. - * @requires_gl + * RGBA, unsigned int, each RGB component 10bit, alpha component + * 2bit. + * @requires_gl Only @ref Magnum::AbstractImage::Type "Type::UnsignedInt2101010Rev" + * is available in OpenGL ES. */ - RGB10Alpha2 = GL_UNSIGNED_INT_10_10_10_2, + UnsignedInt1010102 = GL_UNSIGNED_INT_10_10_10_2, + #endif /** - * Four-component ABGR, unsigned normalized, each RGB component - * 10bit, alpha 2bit, 32bit total. - * @requires_gl + * ABGR, unsigned int, each RGB component 10bit, alpha component + * 2bit. + * @requires_gles30 %Extension @es_extension{EXT,texture_type_2_10_10_10_REV}, + * for texture data only. */ - Alpha2RGB10 = GL_UNSIGNED_INT_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 /** - * Three-component BGR, float, red and green 11bit, blue 10bit, - * 32bit total. For framebuffer reading only. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,packed_float} + * BGR, unsigned int, red and green 11bit float, blue 10bit float. + * For framebuffer reading only. + * @requires_gl30 %Extension @extension{EXT,packed_float} + * @requires_gles30 Floating-point types are not available in + * OpenGL ES 2.0. */ - B10GR11Float = GL_UNSIGNED_INT_10F_11F_11F_REV, + UnsignedInt10F11F11FRev = GL_UNSIGNED_INT_10F_11F_11F_REV, /** - * Three-component BGR, unsigned integers with exponent, each - * component 9bit, exponent 5bit, 32bit total. For framebuffer - * reading only. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,texture_shared_exponent} + * BGR, unsigned int, each component 9bit + 5bit exponent. For + * framebuffer reading only. + * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} + * @requires_gles30 Only 8bit and 16bit types are available in + * OpenGL ES 2.0. */ - Exponent5RGB9 = GL_UNSIGNED_INT_5_9_9_9_REV, + UnsignedInt5999Rev = GL_UNSIGNED_INT_5_9_9_9_REV, + #endif /** - * 24bit depth and 8bit stencil component, 32bit total. For + * Unsigned int, depth component 24bit, stencil index 8bit. For * framebuffer reading only. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} */ - Depth24Stencil8 = GL_UNSIGNED_INT_24_8, + #ifdef MAGNUM_TARGET_GLES2 + UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES, + #else + UnsignedInt248 = GL_UNSIGNED_INT_24_8, /** - * 32bit float depth component and 8bit stencil component, 64bit - * total. For framebuffer reading only. - * @requires_gl - * @requires_gl30 Extension @extension{ARB,depth_buffer_float} + * Float + unsigned int, depth component 32bit float, 24bit gap, + * stencil index 8bit. For framebuffer reading only. + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 Only @ref Magnum::AbstractImage::Type "Type::UnsignedInt248" + * is available in OpenGL ES 2.0. */ - Depth32FloatStencil8 = GL_FLOAT_32_UNSIGNED_INT_24_8_REV + Float32UnsignedInt248Rev = GL_FLOAT_32_UNSIGNED_INT_24_8_REV #endif }; @@ -265,34 +450,42 @@ class MAGNUM_EXPORT AbstractImage { /** * @brief Pixel size (in bytes) - * @param components Color components - * @param type Data type + * @param format Format of the pixel + * @param type Data type of the pixel */ - static std::size_t pixelSize(Components components, ComponentType type); + static std::size_t pixelSize(Format format, Type type); /** * @brief Constructor - * @param components Color components of passed data - * @param type %Image data type + * @param format Format of pixel data + * @param type Data type of pixel data */ - inline AbstractImage(Components components, ComponentType type): _components(components), _type(type) {} + inline explicit AbstractImage(Format format, Type type): _format(format), _type(type) {} /** @brief Destructor */ virtual ~AbstractImage() = 0; - /** @brief Color components */ - inline Components components() const { return _components; } + /** @brief Format of pixel data */ + inline Format format() const { return _format; } - /** @brief Data type */ - inline ComponentType type() const { return _type; } + /** @brief Data type of pixel data */ + inline Type type() const { return _type; } + #ifndef DOXYGEN_GENERATING_OUTPUT protected: - Components _components; /**< @brief Color components */ - ComponentType _type; /**< @brief Data type */ + Format _format; + Type _type; + #endif }; 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 038054604..194157607 100644 --- a/src/AbstractResourceLoader.h +++ b/src/AbstractResourceLoader.h @@ -1,26 +1,33 @@ #ifndef Magnum_AbstractResourceLoader_h #define Magnum_AbstractResourceLoader_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::AbstractResourceLoader */ -#include "Magnum.h" - #include #include "ResourceManager.h" @@ -30,13 +37,68 @@ namespace Magnum { /** @brief Base for resource loaders -Provides asynchronous resource loading for ResourceManager. +Provides (a)synchronous resource loading for ResourceManager. + +@section AbstractResourceLoader-usage Usage and subclassing + +Usage is done by subclassing. Subclass instances can be added to +ResourceManager using ResourceManager::setLoader(). After adding the loader, +each call to ResourceManager::get() will call load() implementation unless the +resource is already loaded (or loading is in progress). Note that resources +requested before the loader was added are not be affected by the loader. + +Subclassing is done by implementing at least load() function. The loading can +be done synchronously or asynchronously (i.e., in another thread). The base +implementation provides interface to ResourceManager and manages loading +progress (which is then available through functions requestedCount(), +loadedCount() and notFoundCount()). You shouldn't access the ResourceManager +directly when loading the data. + +Your load() implementation must call the base implementation at the beginning +so ResourceManager is informed about loading state. Then, after your resources +are loaded, call set() to pass them to ResourceManager or call setNotFound() +to indicate that the resource was not found. + +You can also implement name() to provide meaningful names for resource keys. + +Example implementation for synchronous mesh loader: +@code +class MeshResourceLoader: public AbstractResourceLoader { + public: + void load(ResourceKey key) { + // Indicate that loading has begun + AbstractResourceLoader::load(key); + + // Load the mesh... + + // Not found + if(!found) { + setNotFound(key); + return; + } + + // Found, pass it to resource manager + set(key, mesh, state, policy); + } +}; +@endcode + +You can then add it to resource manager instance like this: +@code +MyResourceManager manager; +MeshResourceLoader loader; + +manager->setLoader(loader); + +// This will now automatically request the mesh from loader by calling load() +Resource myMesh = manager->get("my-mesh"); +@endcode */ template class AbstractResourceLoader { friend class Implementation::ResourceManagerData; public: - inline AbstractResourceLoader(): manager(nullptr), _requestedCount(0), _loadedCount(0), _notFoundCount(0) {} + inline explicit AbstractResourceLoader(): manager(nullptr), _requestedCount(0), _loadedCount(0), _notFoundCount(0) {} inline virtual ~AbstractResourceLoader() { if(manager) manager->_loader = nullptr; @@ -55,7 +117,7 @@ template class AbstractResourceLoader { * Count of resources requested by calling load(), but not found by * the loader. */ - inline std::size_t notFountCount() const { return _notFoundCount; } + inline std::size_t notFoundCount() const { return _notFoundCount; } /** * @brief Count of loaded resources @@ -78,11 +140,12 @@ template class AbstractResourceLoader { * * If the resource isn't yet loaded or loading, state of the resource * is set to @ref Resource::ResourceState "ResourceState::Loading" and count of - * requested features is incremented. + * requested features is incremented. Depending on implementation the + * resource might be loaded synchronously or asynchronously. + * + * See class documentation for reimplementation guide. * - * The resource might be loaded asynchronously and added to - * ResourceManager when loading is done. - * @see ResourceManager::state(), requestedCount(), notFountCount(), + * @see ResourceManager::state(), requestedCount(), notFoundCount(), * loadedCount() */ virtual void load(ResourceKey key) = 0; diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index cb181b9b4..b353ca475 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -1,21 +1,31 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AbstractShaderProgram.h" #include +#include #include "Math/Matrix.h" #include "Shader.h" @@ -25,8 +35,6 @@ #define LINKER_MESSAGE_MAX_LENGTH 1024 -using namespace std; - namespace Magnum { AbstractShaderProgram::Uniform1fImplementation AbstractShaderProgram::uniform1fImplementation = &AbstractShaderProgram::uniformImplementationDefault; @@ -73,7 +81,7 @@ AbstractShaderProgram::UniformMatrix3x4dvImplementation AbstractShaderProgram::u AbstractShaderProgram::UniformMatrix4x3dvImplementation AbstractShaderProgram::uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; #endif -GLint AbstractShaderProgram::maxSupportedVertexAttributeCount() { +Int AbstractShaderProgram::maxSupportedVertexAttributeCount() { GLint& value = Context::current()->state()->shaderProgram->maxSupportedVertexAttributeCount; /* Get the value, if not already cached */ @@ -108,19 +116,19 @@ bool AbstractShaderProgram::attachShader(Shader& shader) { return true; } -void AbstractShaderProgram::bindAttributeLocation(GLuint location, const string& name) { +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(GLuint location, const std::string& name) { +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(GLuint location, GLuint index, const std::string& name) { +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()); @@ -156,7 +164,7 @@ void AbstractShaderProgram::link() { state = status == GL_FALSE ? Failed : Linked; } -GLint AbstractShaderProgram::uniformLocation(const std::string& name) { +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); @@ -570,4 +578,265 @@ void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math: } #endif +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + +std::size_t FloatAttribute::size(GLint components, DataType dataType) { + switch(dataType) { + case DataType::UnsignedByte: + case DataType::Byte: + return components; + case DataType::UnsignedShort: + case DataType::Short: + case DataType::HalfFloat: + return 2*components; + case DataType::UnsignedInt: + case DataType::Int: + case DataType::Float: + return 4*components; + #ifndef MAGNUM_TARGET_GLES + case DataType::Double: + return 8*components; + #endif + } + + CORRADE_INTERNAL_ASSERT(false); + return 0; +} + +#ifndef MAGNUM_TARGET_GLES2 +std::size_t IntAttribute::size(GLint components, DataType dataType) { + switch(dataType) { + case DataType::UnsignedByte: + case DataType::Byte: + return components; + case DataType::UnsignedShort: + case DataType::Short: + return 2*components; + case DataType::UnsignedInt: + case DataType::Int: + return 4*components; + } + + CORRADE_INTERNAL_ASSERT(false); + return 0; +} +#endif + +#ifndef MAGNUM_TARGET_GLES +std::size_t DoubleAttribute::size(GLint components, DataType dataType) { + switch(dataType) { + case DataType::Double: + return 8*components; + } + + CORRADE_INTERNAL_ASSERT(false); + return 0; +} +#endif + +std::size_t Attribute>::size(GLint components, DataType dataType) { + #ifndef MAGNUM_TARGET_GLES + if(components == GL_BGRA) components = 4; + #endif + + switch(dataType) { + case DataType::UnsignedByte: + case DataType::Byte: + return components; + case DataType::UnsignedShort: + case DataType::Short: + case DataType::HalfFloat: + return 2*components; + case DataType::UnsignedInt: + case DataType::Int: + case DataType::Float: + return 4*components; + #ifndef MAGNUM_TARGET_GLES + case DataType::Double: + return 8*components; + #endif + + #ifndef MAGNUM_TARGET_GLES2 + case DataType::UnsignedInt2101010Rev: + case DataType::Int2101010Rev: + CORRADE_INTERNAL_ASSERT(components == 4); + return 4; + #endif + } + + CORRADE_INTERNAL_ASSERT(false); + return 0; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 1>::Components value) { + switch(value) { + case SizedAttribute<1, 1>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 2>::Components value) { + switch(value) { + case SizedAttribute<1, 2>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case SizedAttribute<1, 2>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 3>::Components value) { + switch(value) { + case SizedAttribute<1, 3>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case SizedAttribute<1, 3>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + case SizedAttribute<1, 3>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 4>::Components value) { + switch(value) { + case SizedAttribute<1, 4>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case SizedAttribute<1, 4>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + case SizedAttribute<1, 4>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + case SizedAttribute<1, 4>::Components::Four: + return debug << "AbstractShaderProgram::Attribute::Components::Four"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedMatrixAttribute<2>::Components value) { + switch(value) { + case SizedMatrixAttribute<2>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedMatrixAttribute<3>::Components value) { + switch(value) { + case SizedMatrixAttribute<3>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedMatrixAttribute<4>::Components value) { + switch(value) { + case SizedMatrixAttribute<4>::Components::Four: + return debug << "AbstractShaderProgram::Attribute::Components::Four"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, Attribute>::Components value) { + switch(value) { + case Attribute>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case Attribute>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + case Attribute>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + case Attribute>::Components::Four: + return debug << "AbstractShaderProgram::Attribute::Components::Four"; + #ifndef MAGNUM_TARGET_GLES + case Attribute>::Components::BGRA: + return debug << "AbstractShaderProgram::Attribute::Components::BGRA"; + #endif + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, FloatAttribute::DataType value) { + switch(value) { + #define _c(value) case FloatAttribute::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(UnsignedByte) + _c(Byte) + _c(UnsignedShort) + _c(Short) + _c(UnsignedInt) + _c(Int) + _c(HalfFloat) + _c(Float) + #ifndef MAGNUM_TARGET_GLES + _c(Double) + #endif + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} + +#ifndef MAGNUM_TARGET_GLES2 +Debug operator<<(Debug debug, IntAttribute::DataType value) { + switch(value) { + #define _c(value) case IntAttribute::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(UnsignedByte) + _c(Byte) + _c(UnsignedShort) + _c(Short) + _c(UnsignedInt) + _c(Int) + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} +#endif + +#ifndef MAGNUM_TARGET_GLES +Debug operator<<(Debug debug, DoubleAttribute::DataType value) { + switch(value) { + #define _c(value) case DoubleAttribute::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(Double) + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} +#endif + +Debug operator<<(Debug debug, Attribute>::DataType value) { + switch(value) { + #define _c(value) case Attribute>::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(UnsignedByte) + _c(Byte) + _c(UnsignedShort) + _c(Short) + _c(UnsignedInt) + _c(Int) + _c(HalfFloat) + _c(Float) + #ifndef MAGNUM_TARGET_GLES + _c(Double) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(UnsignedInt2101010Rev) + _c(Int2101010Rev) + #endif + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} + +} +#endif + } diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h index 19653753c..02e161d58 100644 --- a/src/AbstractShaderProgram.h +++ b/src/AbstractShaderProgram.h @@ -1,18 +1,27 @@ #ifndef Magnum_AbstractShaderProgram_h #define Magnum_AbstractShaderProgram_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -23,20 +32,13 @@ #include #include "Magnum.h" -#include "TypeTraits.h" - +#include "OpenGL.h" #include "magnumVisibility.h" /** @todo early asserts (no bool returns?) */ namespace Magnum { -namespace Math { - template class RectangularMatrix; - template class Matrix; - template class Vector; -} - #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Attribute; @@ -53,26 +55,32 @@ functions and properties: - %Attribute definitions with location and type for configuring meshes, for example: @code -typedef Attribute<0, Point3D> Position; +typedef Attribute<0, Vector3> Position; typedef Attribute<1, Vector3> Normal; typedef Attribute<2, Vector2> TextureCoordinates; @endcode - @todoc Output attribute location (for bindFragmentDataLocationIndexed(), - referenced also from Framebuffer::mapDefaultForDraw() / Framebuffer::mapForDraw()) - + - **Output attribute locations**, if desired, for example: +@code +enum: UnsignedInt { + ColorOutput = 0, + NormalOutput = 1 +}; +@endcode - **Layers for texture uniforms** to which the textures will be bound before rendering, for example: @code -static const GLint DiffuseTextureLayer = 0; -static const GLint SpecularTextureLayer = 1; +enum: Int { + DiffuseTextureLayer = 0, + SpecularTextureLayer = 1 +}; @endcode - **Uniform locations** for setting uniform data (see below) (private - constants), for example: + variables), for example: @code -static const GLint TransformationUniform = 0; -static const GLint ProjectionUniform = 1; -static const GLint DiffuseTextureUniform = 2; -static const GLint SpecularTextureUniform = 3; +Int TransformationUniform = 0, + ProjectionUniform = 1, + DiffuseTextureUniform = 2, + SpecularTextureUniform = 3; @endcode - **Constructor**, which attaches particular shaders, links the program and gets uniform locations, for example: @@ -112,12 +120,13 @@ layout(location = 0) in vec4 position; layout(location = 1) in vec3 normal; layout(location = 2) in vec2 textureCoordinates; @endcode + Similarly for ouput attributes, you can also specify blend equation color index for them (see Framebuffer::BlendFunction for more information about using color input index): @code layout(location = 0, index = 0) out vec4 color; -layout(location = 1, index = 1) out vec4 ambient; +layout(location = 1, index = 1) out vec3 normal; @endcode If you don't have the required extension, you can use functions @@ -131,8 +140,8 @@ bindAttributeLocation(Position::Location, "position"); bindAttributeLocation(Normal::Location, "normal"); bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); -bindFragmentDataLocationIndexed(0, 0, "color"); -bindFragmentDataLocationIndexed(1, 1, "ambient"); +bindFragmentDataLocationIndexed(ColorOutput, 0, "color"); +bindFragmentDataLocationIndexed(NormalOutput, 1, "normal"); // Link... @endcode @@ -164,11 +173,11 @@ layout(location = 1) uniform mat4 projection; If you don't have the required extension, you can get uniform location using uniformLocation() after linking stage: @code -GLint transformationUniform = uniformLocation("transformation"); -GLint projectionUniform = uniformLocation("projection"); +Int transformationUniform = uniformLocation("transformation"); +Int projectionUniform = uniformLocation("projection"); @endcode -@requires_gl43 Extension @extension{ARB,explicit_uniform_location} for +@requires_gl43 %Extension @extension{ARB,explicit_uniform_location} for explicit uniform location instead of using uniformLocation(). @requires_gl Explicit uniform location is not supported in OpenGL ES. Use uniformLocation() instead. @@ -185,24 +194,27 @@ layout(binding = 1) uniform sampler2D specularTexture; @endcode If you don't have the required extension (or if you want to change the layer -later), you can set the texture layer uniform using setUniform(GLint, GLint): +later), you can set the texture layer uniform using setUniform(Int, Int): @code setUniform(DiffuseTextureUniform, DiffuseTextureLayer); setUniform(SpecularTextureUniform, SpecularTextureLayer); @endcode -@requires_gl42 Extension @extension{ARB,shading_language_420pack} for explicit - texture layer binding instead of using setUniform(GLint, GLint). +@requires_gl42 %Extension @extension{ARB,shading_language_420pack} for explicit + texture layer binding instead of using setUniform(Int, Int). @requires_gl Explicit texture layer binding is not supported in OpenGL ES. Use - setUniform(GLint, GLint) instead. + setUniform(Int, Int) instead. @section AbstractShaderProgram-rendering-workflow Rendering workflow -Basic workflow with %AbstractShaderProgram subclasses is to instance the class -and configuring attribute binding in meshes (see @ref Mesh-configuration "Mesh documentation" -for more information) at the beginning, then in draw event setting uniforms -and marking the shader for use, binding required textures to their respective -layers using AbstractTexture::bind(GLint) and calling Mesh::draw(). Example: +Basic workflow with %AbstractShaderProgram subclasses is: instance shader +class, configure attribute binding in meshes (see @ref Mesh-configuration "Mesh documentation" +for more information) and map shader outputs to framebuffer attachments if +needed (see @ref Framebuffer-usage "Framebuffer documentation" for more +information). In each draw event set uniforms, mark the shader for use, bind +specific framebuffer (if needed) and bind required textures to their +respective layers using AbstractTexture::bind(Int). Then call Mesh::draw(). +Example: @code shader->setTransformation(transformation) ->setProjection(projection) @@ -216,53 +228,43 @@ mesh.draw(); @section AbstractShaderProgram-types Mapping between GLSL and Magnum types -- `vec2`, `vec3` and `vec4` is @ref Math::Vector "Math::Vector<2, GLfloat>", - @ref Math::Vector "Math::Vector<3, GLfloat>" and - @ref Math::Vector "Math::Vector<4, GLfloat>". - -- `mat2`, `mat3` and `mat4` is @ref Math::Matrix "Math::Matrix<2, GLfloat>", - @ref Math::Matrix "Math::Matrix<3, GLfloat>" and - @ref Math::Matrix "Math::Matrix<4, GLfloat>". - -- `mat2x3`, `mat3x2`, `mat2x4`, `mat4x2`, `mat3x4`, `mat4x3` is - @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 3, GLfloat>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 2, GLfloat>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 4, GLfloat>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 2, GLfloat>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 4, GLfloat>" and - @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 3, GLfloat>". - -- `ivec2`, `ivec3` and `ivec4` is @ref Math::Vector "Math::Vector<2, GLint>", - @ref Math::Vector "Math::Vector<3, GLint>" and - @ref Math::Vector "Math::Vector<4, GLint>", `uvec2`, `uvec3` and `uvec4` is - @ref Math::Vector "Math::Vector<2, GLuint>", - @ref Math::Vector "Math::Vector<3, GLuint>" and - @ref Math::Vector "Math::Vector<4, GLuint>". - @requires_gl30 %Extension @extension{EXT,gpu_shader4} (for integer attributes - and unsigned integer uniforms) - @requires_gles30 Integer attributes and unsigned integer uniforms are not +See @ref types for more information, only types with GLSL equivalent can be used +(and their super- or subclasses with the same size and underlying type). + +@requires_gl30 %Extension @extension{EXT,gpu_shader4} is required when using + integer attributes (i.e. @ref Magnum::UnsignedInt "UnsignedInt", + @ref Magnum::Int "Int", @ref Magnum::Vector2ui "Vector2ui", + @ref Magnum::Vector2i "Vector2i", @ref Magnum::Vector3ui "Vector3ui", + @ref Magnum::Vector3i "Vector3i", @ref Magnum::Vector4ui "Vector4ui" and + @ref Magnum::Vector4i "Vector4i") or unsigned integer uniforms (i.e. + @ref Magnum::UnsignedInt "UnsignedInt", @ref Magnum::Vector2ui "Vector2ui", + @ref Magnum::Vector3ui "Vector3ui" and @ref Magnum::Vector4ui "Vector4ui"). +@requires_gles30 Integer attributes and unsigned integer uniforms are not available in OpenGL ES 2.0. -- `dvec2`, `dvec3` and `dvec4` is @ref Math::Vector "Math::Vector<2, GLdouble>", - @ref Math::Vector "Math::Vector<3, GLdouble>" and - @ref Math::Vector "Math::Vector<4, GLdouble>", `dmat2`, `dmat3` and `dmat4` - is @ref Math::Matrix "Math::Matrix<2, GLdouble>", - @ref Math::Matrix "Math::Matrix<3, GLdouble>" and - @ref Math::Matrix "Math::Matrix<4, GLdouble>", `dmat2x3`, `dmat3x2`, - `dmat2x4`, `dmat4x2`, `dmat3x4`, `dmat4x3` is - @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 3, GLdouble>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 2, GLdouble>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 4, GLdouble>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 2, GLdouble>", - @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 4, GLdouble>" and - @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 3, GLdouble>". - @requires_gl41 %Extension @extension{ARB,vertex_attrib_64bit} (for double - attributes) - @requires_gl Double attributes are not available in OpenGL ES. - -Only types listed here (and their subclasses and specializations, such as -@ref Matrix3 or Color4) can be used for setting uniforms and specifying -vertex attributes. See also TypeTraits::AttributeType. +@requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} is required when + using double uniforms (i.e. @ref Magnum::Double "Double", + @ref Magnum::Vector2d "Vector2d", @ref Magnum::Vector3d "Vector3d", + @ref Magnum::Vector4d "Vector4d", @ref Magnum::Matrix2d "Matrix2d", + @ref Magnum::Matrix3d "Matrix3d", @ref Magnum::Matrix4d "Matrix4d", + @ref Magnum::Matrix2x3d "Matrix2x3d", @ref Magnum::Matrix3x2d "Matrix3x2d", + @ref Magnum::Matrix2x4d "Matrix2x4d", @ref Magnum::Matrix4x2d "Matrix4x2d", + @ref Magnum::Matrix3x4d "Matrix3x4d" and @ref Magnum::Matrix4x3d "Matrix4x3d"). +@requires_gl41 %Extension @extension{ARB,vertex_attrib_64bit} is required when + using double attributes (i.e. @ref Magnum::Double "Double", + @ref Magnum::Vector2d "Vector2d", @ref Magnum::Vector3d "Vector3d", + @ref Magnum::Vector4d "Vector4d", @ref Magnum::Matrix2d "Matrix2d", + @ref Magnum::Matrix3d "Matrix3d", @ref Magnum::Matrix4d "Matrix4d", + @ref Magnum::Matrix2x3d "Matrix2x3d", @ref Magnum::Matrix3x2d "Matrix3x2d", + @ref Magnum::Matrix2x4d "Matrix2x4d", @ref Magnum::Matrix4x2d "Matrix4x2d", + @ref Magnum::Matrix3x4d "Matrix3x4d" and @ref Magnum::Matrix4x3d "Matrix4x3d"). +@requires_gl Double attributes and uniforms are not available in OpenGL ES. + +@requires_gles30 Non-square matrix attributes and uniforms (i.e. + @ref Magnum::Matrix2x3 "Matrix2x3", @ref Magnum::Matrix3x2 "Matrix3x2", + @ref Magnum::Matrix2x4 "Matrix2x4", @ref Magnum::Matrix4x2d "Matrix4x2", + @ref Magnum::Matrix3x4 "Matrix3x4" and @ref Magnum::Matrix4x3 "Matrix4x3") + are not available in OpenGL ES 2.0. @section AbstractShaderProgram-performance-optimization Performance optimizations @@ -273,7 +275,7 @@ are cached, so repeated queries don't result in repeated @fn_gl{Get} calls. If extension @extension{ARB,separate_shader_objects} or @extension{EXT,direct_state_access} is available, uniform setting functions use DSA functions to avoid unnecessary calls to @fn_gl{UseProgram}. See -setUniform(GLint, GLfloat) documentation for more information. +setUniform() documentation for more information. To achieve least state changes, set all uniforms in one run -- method chaining comes in handy. @@ -298,14 +300,13 @@ class MAGNUM_EXPORT AbstractShaderProgram { * location `0`. * * Template parameter @p T is the type which is used for shader - * attribute, e.g. @ref Math::Vector4 "Vector4" 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 Math::Vector4 "Vector4"). - * 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". + * 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 @@ -315,10 +316,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { * shaders and @ref Mesh-configuration for example usage when adding * vertex buffers to mesh. */ - template class Attribute { + template class Attribute { public: - /** @brief Location to which the attribute is bound */ - static const GLuint Location = location; + enum: UnsignedInt { + Location = location /**< Location to which the attribute is bound */ + }; /** * @brief Type @@ -326,7 +328,61 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Type used in shader code. * @see DataType */ - typedef typename TypeTraits::AttributeType Type; + 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 @@ -348,7 +404,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @requires_gl30 %Extension @extension{NV,half_float} * @requires_gles30 %Extension @es_extension{OES,vertex_half_float} */ - Half = GL_HALF_FLOAT, + HalfFloat = GL_HALF_FLOAT, /** Float. Only for float attribute types. */ Float = GL_FLOAT, @@ -371,7 +427,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @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, + UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, /** * Signed 2.10.10.10 packed integer. Only for @@ -379,7 +435,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @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 + Int2101010Rev = GL_INT_2_10_10_10_REV #endif }; #else @@ -391,21 +447,12 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @see DataOptions, Attribute() */ #ifdef DOXYGEN_GENERATING_OUTPUT - enum class DataOption: std::uint8_t { + enum class DataOption: UnsignedByte { /** * Normalize integer components. Only for float attribute * types. Default is to not normalize. */ - Normalize = 1 << 0, - - /** - * BGRA component ordering. Default is RGBA. Only for - * four-component float vector attribute type. - * @requires_gl32 %Extension @extension{ARB,vertex_array_bgra} - * @requires_gl Only RGBA component ordering is supported - * in OpenGL ES. - */ - BGRA = 1 << 1 + Normalize = 1 << 0 }; #else typedef typename Implementation::Attribute::DataOption DataOption; @@ -416,27 +463,49 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @see Attribute() */ #ifdef DOXYGEN_GENERATING_OUTPUT - typedef typename Corrade::Containers::EnumSet DataOptions; + 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 Vector4). + * for Vector4i). * @param dataOptions Data options. Default is no options. */ - inline constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _dataType(dataType), _dataOptions(dataOptions) {} + 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; }; @@ -448,7 +517,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * OpenGL calls. * @see Attribute, @fn_gl{Get} with @def_gl{MAX_VERTEX_ATTRIBS} */ - static GLint maxSupportedVertexAttributeCount(); + static Int maxSupportedVertexAttributeCount(); /** * @brief Constructor @@ -456,7 +525,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Creates one OpenGL shader program. * @see @fn_gl{CreateProgram} */ - inline AbstractShaderProgram(): state(Initialized) { + inline explicit AbstractShaderProgram(): state(Initialized) { _id = glCreateProgram(); } @@ -486,7 +555,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @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_gl41 %Extension @extension{ARB,get_program_binary} * @requires_gles30 Always allowed in OpenGL ES 2.0. */ inline void setRetrievableBinary(bool enabled) { @@ -501,7 +570,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @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_gl41 %Extension @extension{ARB,separate_shader_objects} * @requires_es_extension %Extension @es_extension{EXT,separate_shader_objects} */ inline void setSeparable(bool enabled) { @@ -544,7 +613,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * for more information. * @see @fn_gl{BindAttribLocation} */ - void bindAttributeLocation(GLuint location, const std::string& name); + void bindAttributeLocation(UnsignedInt location, const std::string& name); #ifndef MAGNUM_TARGET_GLES /** @@ -563,11 +632,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @ref AbstractShaderProgram-attribute-location "class documentation" * for more information. * @see @fn_gl{BindFragDataLocationIndexed} - * @requires_gl33 Extension @extension{ARB,blend_func_extended} + * @requires_gl33 %Extension @extension{ARB,blend_func_extended} * @requires_gl Multiple blend function inputs are not available in * OpenGL ES. */ - void bindFragmentDataLocationIndexed(GLuint location, GLuint index, const std::string& name); + void bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, const std::string& name); /** * @brief Bind fragment data to given location and first color input index @@ -577,11 +646,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { * The same as bindFragmentDataLocationIndexed(), but with `index` set * to `0`. * @see @fn_gl{BindFragDataLocation} - * @requires_gl30 Extension @extension{EXT,gpu_shader4} + * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gl Use explicit location specification in OpenGL ES 3.0 * instead. */ - void bindFragmentDataLocation(GLuint location, const std::string& name); + void bindFragmentDataLocation(UnsignedInt location, const std::string& name); #endif /** @@ -605,7 +674,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * for more information. * @see @fn_gl{GetUniformLocation} */ - GLint uniformLocation(const std::string& name); + Int uniformLocation(const std::string& name); /** * @brief Set uniform value @@ -618,265 +687,265 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @see @fn_gl{UseProgram}, @fn_gl{Uniform} or `glProgramUniform()` * from @extension{ARB,separate_shader_objects}/@extension{EXT,direct_state_access}. */ - inline void setUniform(GLint location, GLfloat value) { + inline void setUniform(Int location, Float value) { (this->*uniform1fImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Vector<2, GLfloat>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Vector<2, Float>& value) { (this->*uniform2fvImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Vector<3, GLfloat>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Vector<3, Float>& value) { (this->*uniform3fvImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Vector<4, GLfloat>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Vector<4, Float>& value) { (this->*uniform4fvImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, GLint value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, Int value) { (this->*uniform1iImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Vector<2, GLint>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Vector<2, Int>& value) { (this->*uniform2ivImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Vector<3, GLint>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Vector<3, Int>& value) { (this->*uniform3ivImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Vector<4, GLint>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Vector<4, Int>& value) { (this->*uniform4ivImplementation)(location, value); } #ifndef MAGNUM_TARGET_GLES2 /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl30 Extension @extension{EXT,gpu_shader4} + * @copydoc setUniform(Int, Float) + * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, GLuint value) { + inline void setUniform(Int location, UnsignedInt value) { (this->*uniform1uiImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl30 Extension @extension{EXT,gpu_shader4} + * @copydoc setUniform(Int, Float) + * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::Vector<2, GLuint>& value) { + inline void setUniform(Int location, const Math::Vector<2, UnsignedInt>& value) { (this->*uniform2uivImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl30 Extension @extension{EXT,gpu_shader4} + * @copydoc setUniform(Int, Float) + * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::Vector<3, GLuint>& value) { + inline void setUniform(Int location, const Math::Vector<3, UnsignedInt>& value) { (this->*uniform3uivImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl30 Extension @extension{EXT,gpu_shader4} + * @copydoc setUniform(Int, Float) + * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::Vector<4, GLuint>& value) { + inline void setUniform(Int location, const Math::Vector<4, UnsignedInt>& value) { (this->*uniform4uivImplementation)(location, value); } #endif #ifndef MAGNUM_TARGET_GLES /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, GLdouble value) { + inline void setUniform(Int location, Double value) { (this->*uniform1dImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::Vector<2, GLdouble>& value) { + inline void setUniform(Int location, const Math::Vector<2, Double>& value) { (this->*uniform2dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::Vector<3, GLdouble>& value) { + inline void setUniform(Int location, const Math::Vector<3, Double>& value) { (this->*uniform3dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::Vector<4, GLdouble>& value) { + inline void setUniform(Int location, const Math::Vector<4, Double>& value) { (this->*uniform4dvImplementation)(location, value); } #endif - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Matrix<2, GLfloat>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Matrix<2, Float>& value) { (this->*uniformMatrix2fvImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Matrix<3, GLfloat>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Matrix<3, Float>& value) { (this->*uniformMatrix3fvImplementation)(location, value); } - /** @copydoc setUniform(GLint, GLfloat) */ - inline void setUniform(GLint location, const Math::Matrix<4, GLfloat>& value) { + /** @copydoc setUniform(Int, Float) */ + inline void setUniform(Int location, const Math::Matrix<4, Float>& value) { (this->*uniformMatrix4fvImplementation)(location, value); } #ifndef MAGNUM_TARGET_GLES2 /** - * @copydoc setUniform(GLint, GLfloat) + * @copydoc setUniform(Int, Float) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<2, 3, GLfloat>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<2, 3, Float>& value) { (this->*uniformMatrix2x3fvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) + * @copydoc setUniform(Int, Float) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<3, 2, GLfloat>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<3, 2, Float>& value) { (this->*uniformMatrix3x2fvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) + * @copydoc setUniform(Int, Float) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<2, 4, GLfloat>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<2, 4, Float>& value) { (this->*uniformMatrix2x4fvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) + * @copydoc setUniform(Int, Float) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<4, 2, GLfloat>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<4, 2, Float>& value) { (this->*uniformMatrix4x2fvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) + * @copydoc setUniform(Int, Float) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<3, 4, GLfloat>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<3, 4, Float>& value) { (this->*uniformMatrix3x4fvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) + * @copydoc setUniform(Int, Float) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<4, 3, GLfloat>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<4, 3, Float>& value) { (this->*uniformMatrix4x3fvImplementation)(location, value); } #endif #ifndef MAGNUM_TARGET_GLES /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::Matrix<2, GLdouble>& value) { + inline void setUniform(Int location, const Math::Matrix<2, Double>& value) { (this->*uniformMatrix2dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::Matrix<3, GLdouble>& value) { + inline void setUniform(Int location, const Math::Matrix<3, Double>& value) { (this->*uniformMatrix3dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::Matrix<4, GLdouble>& value) { + inline void setUniform(Int location, const Math::Matrix<4, Double>& value) { (this->*uniformMatrix4dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<2, 3, GLdouble>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<2, 3, Double>& value) { (this->*uniformMatrix2x3dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<3, 2, GLdouble>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<3, 2, Double>& value) { (this->*uniformMatrix3x2dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<2, 4, GLdouble>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<2, 4, Double>& value) { (this->*uniformMatrix2x4dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<4, 2, GLdouble>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<4, 2, Double>& value) { (this->*uniformMatrix4x2dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<3, 4, GLdouble>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<3, 4, Double>& value) { (this->*uniformMatrix3x4dvImplementation)(location, value); } /** - * @copydoc setUniform(GLint, GLfloat) - * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} + * @copydoc setUniform(Int, Float) + * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - inline void setUniform(GLint location, const Math::RectangularMatrix<4, 3, GLdouble>& value) { + inline void setUniform(Int location, const Math::RectangularMatrix<4, 3, Double>& value) { (this->*uniformMatrix4x3dvImplementation)(location, value); } #endif @@ -1056,12 +1125,81 @@ class MAGNUM_EXPORT AbstractShaderProgram { State state; }; +#ifdef DOXYGEN_GENERATING_OUTPUT +/** @debugoperator{Magnum::AbstractShaderProgram::Attribute} */ +template Debug operator<<(Debug debug, AbstractShaderProgram::Attribute::Components); + +/** @debugoperator{Magnum::AbstractShaderProgram::Attribute} */ +template Debug operator<<(Debug debug, AbstractShaderProgram::Attribute::DataType); +#endif + #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { -template struct Attribute {}; +/* Base for sized attributes */ +template struct SizedAttribute; + +/* Vector attribute sizes */ +template struct SizedVectorAttribute { + inline constexpr static std::size_t vectorCount() { return cols; } +}; +template<> struct SizedAttribute<1, 1>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1 }; + constexpr static Components DefaultComponents = Components::One; +}; +template<> struct SizedAttribute<1, 2>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1, Two = 2 }; + constexpr static Components DefaultComponents = Components::Two; +}; +template<> struct SizedAttribute<1, 3>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1, Two = 2, Three = 3 }; + constexpr static Components DefaultComponents = Components::Three; +}; +template<> struct SizedAttribute<1, 4>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1, Two = 2, Three = 3, Four = 4 }; + constexpr static Components DefaultComponents = Components::Four; +}; +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 1>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 2>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 3>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 4>::Components value); + +/* Matrix attribute sizes */ +template struct SizedMatrixAttribute; +template<> struct SizedMatrixAttribute<2> { + enum class Components: GLint { Two = 2 }; + constexpr static Components DefaultComponents = Components::Two; +}; +template<> struct SizedMatrixAttribute<3> { + enum class Components: GLint { Three = 3 }; + constexpr static Components DefaultComponents = Components::Three; +}; +template<> struct SizedMatrixAttribute<4> { + enum class Components: GLint { Four = 4 }; + constexpr static Components DefaultComponents = Components::Four; +}; +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedMatrixAttribute<2>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedMatrixAttribute<3>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedMatrixAttribute<4>::Components value); +template<> struct SizedAttribute<2, 2>: SizedVectorAttribute<2>, SizedMatrixAttribute<2> {}; +template<> struct SizedAttribute<3, 3>: SizedVectorAttribute<3>, SizedMatrixAttribute<3> {}; +template<> struct SizedAttribute<4, 4>: SizedVectorAttribute<4>, SizedMatrixAttribute<4> {}; +#ifndef MAGNUM_TARGET_GLES2 +template<> struct SizedAttribute<2, 3>: SizedVectorAttribute<2>, SizedMatrixAttribute<3> {}; +template<> struct SizedAttribute<3, 2>: SizedVectorAttribute<3>, SizedMatrixAttribute<2> {}; +template<> struct SizedAttribute<2, 4>: SizedVectorAttribute<2>, SizedMatrixAttribute<4> {}; +template<> struct SizedAttribute<4, 2>: SizedVectorAttribute<4>, SizedMatrixAttribute<2> {}; +template<> struct SizedAttribute<3, 4>: SizedVectorAttribute<3>, SizedMatrixAttribute<4> {}; +template<> struct SizedAttribute<4, 3>: SizedVectorAttribute<4>, SizedMatrixAttribute<3> {}; +#endif + +/* Base for attributes */ +template struct Attribute; + +/* Base for float attributes */ +struct FloatAttribute { + typedef Float Type; -template<> struct Attribute { enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, @@ -1081,37 +1219,94 @@ template<> struct Attribute { Double = GL_DOUBLE #endif }; + constexpr static DataType DefaultDataType = DataType::Float; - enum class DataOption: std::uint8_t { + enum class DataOption: UnsignedByte { Normalized = 1 << 0 }; + typedef Corrade::Containers::EnumSet DataOptions; - typedef Corrade::Containers::EnumSet DataOptions; + static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); +}; - static const DataType DefaultDataType = DataType::Float; +CORRADE_ENUMSET_OPERATORS(FloatAttribute::DataOptions) - inline constexpr static GLint size(DataOptions) { return 1; } - inline constexpr static std::size_t vectorCount() { return 1; } -}; +Debug MAGNUM_EXPORT operator<<(Debug debug, FloatAttribute::DataType value); -CORRADE_ENUMSET_OPERATORS(Attribute::DataOptions) +#ifndef MAGNUM_TARGET_GLES2 +/* Base for int attributes */ +struct IntAttribute { + typedef Int Type; -template struct Attribute>: public Attribute { - inline constexpr static GLint size(DataOptions) { return vectorSize; } - inline constexpr static std::size_t vectorCount() { return 1; } + enum class DataType: GLenum { + UnsignedByte = GL_UNSIGNED_BYTE, + Byte = GL_BYTE, + UnsignedShort = GL_UNSIGNED_SHORT, + Short = GL_SHORT, + UnsignedInt = GL_UNSIGNED_INT, + Int = GL_INT + }; + constexpr static DataType DefaultDataType = DataType::Int; + + enum class DataOption: UnsignedByte {}; + typedef Corrade::Containers::EnumSet DataOptions; + + static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; -template struct Attribute>: public Attribute { - inline constexpr static GLint size(DataOptions) { return rows; } - inline constexpr static std::size_t vectorCount() { return cols; } +Debug MAGNUM_EXPORT operator<<(Debug debug, IntAttribute::DataType value); + +/* Base for unsigned int attributes */ +struct UnsignedIntAttribute { + typedef UnsignedInt Type; + + typedef IntAttribute::DataType DataType; + constexpr static DataType DefaultDataType = DataType::UnsignedInt; + + typedef IntAttribute::DataOption DataOption; + typedef Corrade::Containers::EnumSet DataOptions; + + inline static std::size_t size(GLint components, DataType dataType) { + return IntAttribute::size(components, dataType); + } }; +#endif -template struct Attribute>: public Attribute { - inline constexpr static GLint size(DataOptions) { return matrixSize; } - inline constexpr static std::size_t vectorCount() { return matrixSize; } +#ifndef MAGNUM_TARGET_GLES +/* Base for double attributes */ +struct DoubleAttribute { + typedef Double Type; + + enum class DataType: GLenum { + Double = GL_DOUBLE + }; + constexpr static DataType DefaultDataType = DataType::Double; + + enum class DataOption: UnsignedByte {}; + typedef Corrade::Containers::EnumSet DataOptions; + + static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; -template<> struct Attribute> { +Debug MAGNUM_EXPORT operator<<(Debug debug, DoubleAttribute::DataType value); +#endif + +/* Floating-point four-component vector is absolutely special case */ +template<> struct Attribute> { + typedef Float Type; + + enum class Components: GLint { + One = 1, + Two = 2, + Three = 3, + Four = 4 + #ifndef MAGNUM_TARGET_GLES + , + BGRA = GL_BGRA + #endif + }; + constexpr static Components DefaultComponents = Components::Four; + enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, @@ -1131,120 +1326,66 @@ template<> struct Attribute> { #endif #ifndef MAGNUM_TARGET_GLES2 , - UnsignedAlpha2RGB10 = GL_UNSIGNED_INT_2_10_10_10_REV, - Alpha2RGB10 = GL_INT_2_10_10_10_REV + UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, + Int2101010Rev = GL_INT_2_10_10_10_REV #endif }; + constexpr static DataType DefaultDataType = DataType::Float; - enum class DataOption: std::uint8_t { + enum class DataOption: UnsignedByte { Normalized = 1 << 0 - - #ifndef MAGNUM_TARGET_GLES - , - BGRA = 2 << 0 - #endif }; - - typedef Corrade::Containers::EnumSet DataOptions; - - static const DataType DefaultDataType = DataType::Float; - - #ifndef MAGNUM_TARGET_GLES - inline constexpr static GLint size(DataOptions options) { - return options & DataOption::BGRA ? GL_BGRA : 4; - } - #else - inline constexpr static GLint size(DataOptions) { return 4; } - #endif + typedef Corrade::Containers::EnumSet DataOptions; inline constexpr static std::size_t vectorCount() { return 1; } -}; - -typedef Math::Vector<4, GLfloat> _Vector4; -CORRADE_ENUMSET_OPERATORS(Attribute<_Vector4>::DataOptions) -template<> struct Attribute { - enum class DataType: GLenum { - UnsignedByte = GL_UNSIGNED_BYTE, - Byte = GL_BYTE, - UnsignedShort = GL_UNSIGNED_SHORT, - Short = GL_SHORT, - UnsignedInt = GL_UNSIGNED_INT, - Int = GL_INT - }; - - enum class DataOption: std::uint8_t {}; - - typedef Corrade::Containers::EnumSet DataOptions; - - static const DataType DefaultDataType = DataType::Int; - - inline constexpr static GLint size() { return 1; } + static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; -template<> struct Attribute { - typedef Attribute::DataType DataType; - typedef Attribute::DataOption DataOption; - - typedef Corrade::Containers::EnumSet DataOptions; - - static const DataType DefaultDataType = DataType::UnsignedInt; - - inline constexpr static GLint size() { return 1; } -}; +typedef Math::Vector<4, Float> _Vector4; +CORRADE_ENUMSET_OPERATORS(Attribute<_Vector4>::DataOptions) -template struct Attribute>: public Attribute { - inline constexpr static GLint size() { return size; } -}; - -template struct Attribute>: public Attribute { - inline constexpr static GLint size() { return size; } -}; +Debug MAGNUM_EXPORT operator<<(Debug debug, Attribute>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, Attribute>::DataType value); +/* Common float, int, unsigned int and double scalar attributes */ +template<> struct Attribute: FloatAttribute, SizedAttribute<1, 1> {}; +#ifndef MAGNUM_TARGET_GLES2 +template<> struct Attribute: IntAttribute, SizedAttribute<1, 1> {}; +template<> struct Attribute: UnsignedIntAttribute, SizedAttribute<1, 1> {}; #ifndef MAGNUM_TARGET_GLES -template<> struct Attribute { - enum class DataType: GLenum { - Double = GL_DOUBLE - }; - - enum class DataOption: std::uint8_t {}; - - typedef Corrade::Containers::EnumSet DataOptions; - - static const DataType DefaultDataType = DataType::Double; - - inline constexpr static GLint size() { return 1; } - inline constexpr static std::size_t vectorCount() { return 1; } -}; - -template struct Attribute>: public Attribute { - inline constexpr static GLint size() { return rows; } - inline constexpr static std::size_t vectorCount() { return cols; } -}; - -template struct Attribute>: public Attribute { - inline constexpr static GLint size() { return size; } - inline constexpr static std::size_t vectorCount() { return size; } -}; - -template struct Attribute>: public Attribute { - inline constexpr static GLint size() { return size; } - inline constexpr static std::size_t vectorCount() { return size; } -}; +template<> struct Attribute: DoubleAttribute, SizedAttribute<1, 1> {}; +#endif #endif -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; - -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; - -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; +/* Common float, int, unsigned int and double vector attributes */ +template struct Attribute>: FloatAttribute, SizedAttribute<1, size_> {}; +#ifndef MAGNUM_TARGET_GLES2 +template struct Attribute>: IntAttribute, SizedAttribute<1, size_> {}; +template struct Attribute>: UnsignedIntAttribute, SizedAttribute<1, size_> {}; +#ifndef MAGNUM_TARGET_GLES +template struct Attribute>: DoubleAttribute, SizedAttribute<1, size_> {}; +#endif +#endif +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; + +/* Common float and double rectangular matrix attributes */ +template struct Attribute>: FloatAttribute, SizedAttribute {}; +#ifndef MAGNUM_TARGET_GLES +template struct Attribute>: DoubleAttribute, SizedAttribute {}; +#endif -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; +/* Common float and double square matrix attributes */ +template struct Attribute>: Attribute> {}; +#ifndef MAGNUM_TARGET_GLES +template struct Attribute>: Attribute> {}; +#endif +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; } #endif diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index 4545baeff..04bfef4de 100644 --- a/src/AbstractTexture.cpp +++ b/src/AbstractTexture.cpp @@ -1,20 +1,31 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AbstractTexture.h" +#include "Buffer.h" +#include "BufferImage.h" #include "Context.h" #include "Extensions.h" #include "Implementation/State.h" @@ -30,9 +41,21 @@ AbstractTexture::ParameterfImplementation AbstractTexture::parameterfImplementat &AbstractTexture::parameterImplementationDefault; AbstractTexture::ParameterfvImplementation AbstractTexture::parameterfvImplementation = &AbstractTexture::parameterImplementationDefault; +#ifndef MAGNUM_TARGET_GLES +AbstractTexture::GetLevelParameterivImplementation AbstractTexture::getLevelParameterivImplementation = + &AbstractTexture::getLevelParameterImplementationDefault; +#endif AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation = &AbstractTexture::mipmapImplementationDefault; #ifndef MAGNUM_TARGET_GLES +AbstractTexture::Storage1DImplementation AbstractTexture::storage1DImplementation = + &AbstractTexture::storageImplementationDefault; +#endif +AbstractTexture::Storage2DImplementation AbstractTexture::storage2DImplementation = + &AbstractTexture::storageImplementationDefault; +AbstractTexture::Storage3DImplementation AbstractTexture::storage3DImplementation = + &AbstractTexture::storageImplementationDefault; +#ifndef MAGNUM_TARGET_GLES AbstractTexture::Image1DImplementation AbstractTexture::image1DImplementation = &AbstractTexture::imageImplementationDefault; #endif @@ -49,6 +72,9 @@ 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 @@ -56,21 +82,21 @@ AbstractTexture::SubImage3DImplementation AbstractTexture::subImage3DImplementat thus testing only on AbstractTexture. */ #define filter_or(filter, mipmap) \ (static_cast(AbstractTexture::Filter::filter)|static_cast(AbstractTexture::Mipmap::mipmap)) -static_assert((filter_or(NearestNeighbor, BaseLevel) == GL_NEAREST) && - (filter_or(NearestNeighbor, NearestLevel) == GL_NEAREST_MIPMAP_NEAREST) && - (filter_or(NearestNeighbor, LinearInterpolation) == GL_NEAREST_MIPMAP_LINEAR) && - (filter_or(LinearInterpolation, BaseLevel) == GL_LINEAR) && - (filter_or(LinearInterpolation, NearestLevel) == GL_LINEAR_MIPMAP_NEAREST) && - (filter_or(LinearInterpolation, LinearInterpolation) == GL_LINEAR_MIPMAP_LINEAR), +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 -GLint AbstractTexture::maxSupportedLayerCount() { +Int AbstractTexture::maxSupportedLayerCount() { return Context::current()->state()->texture->maxSupportedLayerCount; } -GLfloat AbstractTexture::maxSupportedAnisotropy() { +Float AbstractTexture::maxSupportedAnisotropy() { GLfloat& value = Context::current()->state()->texture->maxSupportedAnisotropy; /** @todo Re-enable when extension header is available */ @@ -83,7 +109,10 @@ GLfloat AbstractTexture::maxSupportedAnisotropy() { return value; } -AbstractTexture::~AbstractTexture() { +void AbstractTexture::destroy() { + /* Moved out */ + if(!_id) return; + /* Remove all bindings */ std::vector& bindings = Context::current()->state()->texture->bindings; for(auto it = bindings.begin(); it != bindings.end(); ++it) @@ -92,7 +121,27 @@ AbstractTexture::~AbstractTexture() { glDeleteTextures(1, &_id); } -void AbstractTexture::bind(GLint layer) { +void AbstractTexture::move() { + _id = 0; +} + +AbstractTexture::~AbstractTexture() { destroy(); } + +AbstractTexture::AbstractTexture(AbstractTexture&& other): _target(other._target), _id(other._id) { + other.move(); +} + +AbstractTexture& AbstractTexture::operator=(AbstractTexture&& other) { + destroy(); + + _target = other._target; + _id = other._id; + + other.move(); + return *this; +} + +void AbstractTexture::bind(Int layer) { Implementation::TextureState* const textureState = Context::current()->state()->texture; /* If already bound in given layer, nothing to do */ @@ -120,7 +169,7 @@ void AbstractTexture::bindImplementationDSA(GLint layer) { AbstractTexture* AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) { #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::BaseLevel, "AbstractTexture: rectangle textures cannot have mipmaps", this); + CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::Base, "AbstractTexture: rectangle textures cannot have mipmaps", this); #endif (this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER, @@ -183,7 +232,11 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { parameteriImplementation = &AbstractTexture::parameterImplementationDSA; parameterfImplementation = &AbstractTexture::parameterImplementationDSA; parameterfvImplementation = &AbstractTexture::parameterImplementationDSA; + getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA; mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; + storage1DImplementation = &AbstractTexture::storageImplementationDSA; + storage2DImplementation = &AbstractTexture::storageImplementationDSA; + storage3DImplementation = &AbstractTexture::storageImplementationDSA; image1DImplementation = &AbstractTexture::imageImplementationDSA; image2DImplementation = &AbstractTexture::imageImplementationDSA; image3DImplementation = &AbstractTexture::imageImplementationDSA; @@ -191,6 +244,13 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { subImage2DImplementation = &AbstractTexture::subImageImplementationDSA; subImage3DImplementation = &AbstractTexture::subImageImplementationDSA; } + + if(context->isExtensionSupported()) { + Debug() << "AbstractTexture: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; + + invalidateImplementation = &AbstractTexture::invalidateImplementationARB; + invalidateSubImplementation = &AbstractTexture::invalidateSubImplementationARB; + } #endif } @@ -225,170 +285,228 @@ void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLf void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat* values) { glTextureParameterfvEXT(_id, _target, parameter, values); } +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::getLevelParameterImplementationDefault(GLenum target, GLint level, GLenum parameter, GLint* values) { + bindInternal(); + glGetTexLevelParameteriv(target, level, parameter, values); +} + +void AbstractTexture::getLevelParameterImplementationDSA(GLenum target, GLint level, GLenum parameter, GLint* values) { + glGetTextureLevelParameterivEXT(_id, target, level, parameter, values); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { + bindInternal(); + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glTexStorage1D(target, levels, GLenum(internalFormat), size[0]); + #else + //glTexStorage2DEXT(target, levels, GLenum(internalFormat), size.x(), size.y()); + static_cast(target); + static_cast(levels); + static_cast(internalFormat); + static_cast(size); + #endif +} + +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat 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) { + bindInternal(); + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glTexStorage2D(target, levels, GLenum(internalFormat), size.x(), size.y()); + #else + //glTexStorage2DEXT(target, levels, GLenum(internalFormat), size.x(), size.y()); + static_cast(target); + static_cast(levels); + static_cast(internalFormat); + static_cast(size); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat 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) { + bindInternal(); + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glTexStorage3D(target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); + #else + //glTexStorage3DEXT(target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); + static_cast(target); + static_cast(levels); + static_cast(internalFormat); + static_cast(size); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector3i& size) { + glTextureStorage3DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); +} -void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* 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) { bindInternal(); - glTexImage1D(target, mipLevel, internalFormat, size[0], 0, static_cast(components), static_cast(type), data); + glTexImage1D(target, level, static_cast(internalFormat), size[0], 0, static_cast(format), static_cast(type), data); } -void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { - glTextureImage1DEXT(_id, target, mipLevel, internalFormat, size[0], 0, static_cast(components), 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) { + glTextureImage1DEXT(_id, target, level, GLint(internalFormat), size[0], 0, static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { +void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { bindInternal(); - glTexImage2D(target, mipLevel, internalFormat, size.x(), size.y(), 0, static_cast(components), static_cast(type), data); + 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 mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { - glTextureImage2DEXT(_id, target, mipLevel, internalFormat, size.x(), size.y(), 0, static_cast(components), static_cast(type), data); +void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type 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 mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { +void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { bindInternal(); /** @todo Get some extension wrangler instead to avoid linker errors to glTexImage3D() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 - glTexImage3D(target, mipLevel, internalFormat, size.x(), size.y(), size.z(), 0, static_cast(components), static_cast(type), data); + glTexImage3D(target, level, GLint(internalFormat), size.x(), size.y(), size.z(), 0, static_cast(format), static_cast(type), data); #else static_cast(target); - static_cast(mipLevel); + static_cast(level); static_cast(internalFormat); static_cast(size); - static_cast(components); + static_cast(format); static_cast(type); static_cast(data); #endif } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { - glTextureImage3DEXT(_id, target, mipLevel, internalFormat, size.x(), size.y(), size.z(), 0, static_cast(components), static_cast(type), data); +void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type 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 mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { +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) { bindInternal(); - glTexSubImage1D(target, mipLevel, offset[0], size[0], static_cast(components), static_cast(type), data); + glTexSubImage1D(target, level, offset[0], size[0], static_cast(format), static_cast(type), data); } -void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { - glTextureSubImage1DEXT(_id, target, mipLevel, offset[0], size[0], static_cast(components), 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) { + glTextureSubImage1DEXT(_id, target, level, offset[0], size[0], static_cast(format), static_cast(type), data); } #endif -void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { bindInternal(); - glTexSubImage2D(target, mipLevel, offset.x(), offset.y(), size.x(), size.y(), static_cast(components), static_cast(type), data); + 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 mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { - glTextureSubImage2DEXT(_id, target, mipLevel, offset.x(), offset.y(), size.x(), size.y(), static_cast(components), static_cast(type), data); +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type 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 mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { bindInternal(); /** @todo Get some extension wrangler instead to avoid linker errors to glTexSubImage3D() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 - glTexSubImage3D(target, mipLevel, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast(components), static_cast(type), data); + glTexSubImage3D(target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast(format), static_cast(type), data); #else static_cast(target); - static_cast(mipLevel); + static_cast(level); static_cast(offset); static_cast(size); - static_cast(components); + static_cast(format); static_cast(type); static_cast(data); #endif } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { - glTextureSubImage3DEXT(_id, target, mipLevel, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast(components), static_cast(type), data); +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type 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) {} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::invalidateImplementationARB(GLint level) { + glInvalidateTexImage(_id, level); } #endif +void AbstractTexture::invalidateSubImplementationNoOp(GLint, const Vector3i&, const Vector3i&) {} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::invalidateSubImplementationARB(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_GLES2 -AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components components, AbstractTexture::ComponentType type) { - #ifndef MAGNUM_TARGET_GLES - #define internalFormatSwitch(c) switch(type) { \ - case ComponentType::UnsignedByte: \ - internalFormat = GL_##c##8UI; break; \ - case ComponentType::Byte: \ - internalFormat = GL_##c##8I; break; \ - case ComponentType::UnsignedShort: \ - internalFormat = GL_##c##16UI; break; \ - case ComponentType::Short: \ - internalFormat = GL_##c##16I; break; \ - case ComponentType::UnsignedInt: \ - internalFormat = GL_##c##32UI; break; \ - case ComponentType::Int: \ - internalFormat = GL_##c##32I; break; \ - case ComponentType::Half: \ - internalFormat = GL_##c##16F; break; \ - case ComponentType::Float: \ - internalFormat = GL_##c##32F; break; \ - case ComponentType::NormalizedUnsignedByte: \ - internalFormat = GL_##c##8; break; \ - case ComponentType::NormalizedByte: \ - internalFormat = GL_##c##8_SNORM; break; \ - case ComponentType::NormalizedUnsignedShort: \ - internalFormat = GL_##c##16; break; \ - case ComponentType::NormalizedShort: \ - internalFormat = GL_##c##16_SNORM; break; \ - } - #else - #define internalFormatSwitch(c) switch(type) { \ - case ComponentType::UnsignedByte: \ - internalFormat = GL_##c##8UI; break; \ - case ComponentType::Byte: \ - internalFormat = GL_##c##8I; break; \ - case ComponentType::UnsignedShort: \ - internalFormat = GL_##c##16UI; break; \ - case ComponentType::Short: \ - internalFormat = GL_##c##16I; break; \ - case ComponentType::UnsignedInt: \ - internalFormat = GL_##c##32UI; break; \ - case ComponentType::Int: \ - internalFormat = GL_##c##32I; break; \ - case ComponentType::Half: \ - internalFormat = GL_##c##16F; break; \ - case ComponentType::Float: \ - internalFormat = GL_##c##32F; break; \ - case ComponentType::NormalizedUnsignedByte: \ - internalFormat = GL_##c##8; break; \ - case ComponentType::NormalizedByte: \ - internalFormat = GL_##c##8_SNORM; break; \ +namespace Implementation { + template const GLvoid* ImageHelper>::dataOrPixelUnpackBuffer(BufferImage* image) { + image->buffer()->bind(Buffer::Target::PixelUnpack); + return nullptr; } - #endif - if(components == Components::Red) - internalFormatSwitch(R) - else if(components == Components::RedGreen) - internalFormatSwitch(RG) - else if(components == Components::RGB) - internalFormatSwitch(RGB) - else if(components == Components::RGBA) - internalFormatSwitch(RGBA) - #undef internalFormatSwitch + + template struct ImageHelper; + template struct ImageHelper; + template struct ImageHelper; } #endif -#ifndef DOXYGEN_GENERATING_OUTPUT -void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Math::Vector2& wrapping) { +#ifndef MAGNUM_TARGET_GLES +Math::Vector<1, GLint> AbstractTexture::DataHelper<1>::imageSize(AbstractTexture* texture, GLenum target, GLint level) { + Math::Vector<1, GLint> value; + (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); + return value; +} + +Vector2i AbstractTexture::DataHelper<2>::imageSize(AbstractTexture* texture, GLenum target, GLint level) { + Vector2i value; + (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); + (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_HEIGHT, &value[1]); + return value; +} + +Vector3i AbstractTexture::DataHelper<3>::imageSize(AbstractTexture* texture, GLenum target, GLint level) { + Vector3i value; + (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); + (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_HEIGHT, &value[1]); + (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_DEPTH, &value[2]); + return value; +} +#endif + +void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Array2D& wrapping) { #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(texture->_target != GL_TEXTURE_RECTANGLE || ((wrapping[0] == Wrapping::ClampToEdge || wrapping[0] == Wrapping::ClampToBorder) && (wrapping[0] == Wrapping::ClampToEdge || wrapping[1] == Wrapping::ClampToEdge)), "AbstractTexture: rectangle texture wrapping must either clamp to border or to edge", ); + 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", ); #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 Math::Vector3& 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 038e4ad5d..19a5fe974 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -1,25 +1,37 @@ #ifndef Magnum_AbstractTexture_h #define Magnum_AbstractTexture_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::AbstractTexture */ -#include "Magnum.h" +#include "Array.h" +#ifndef MAGNUM_TARGET_GLES2 +#include "Buffer.h" +#endif #include "Color.h" #include "AbstractImage.h" @@ -28,22 +40,11 @@ namespace Magnum { /** @brief Base for textures -@attention Don't forget to call @ref Texture::setWrapping() "setWrapping()", - setMinificationFilter() and setMagnificationFilter() after creating the - texture, otherwise the texture will be incomplete. If you specified - @ref Wrapping "Wrapping::ClampToBorder" in @ref Texture::setWrapping() "setWrapping()", - be sure to also call setBorderColor(). If you specified mipmap filtering - in setMinificationFilter(), be sure to also either explicitly set all mip - levels or call generateMipmap(). - -The texture is bound to shader via bind(). Texture uniform on the shader must -also be set to particular texture layer using -AbstractShaderProgram::setUniform(GLint, GLint). - See Texture, CubeMapTexture and CubeMapTextureArray documentation for more -information. +information and usage examples. @section AbstractTexture-performance-optimization Performance optimizations + The engine tracks currently bound textures in all available layers to avoid unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. %Texture configuration functions use dedicated highest available texture layer to not @@ -53,27 +54,36 @@ repeated @fn_gl{Get} calls. If extension @extension{EXT,direct_state_access} is available, bind() uses DSA function to avoid unnecessary calls to @fn_gl{ActiveTexture}. Also all texture -configuration functions use DSA functions to avoid unnecessary calls to -@fn_gl{ActiveTexture} and @fn_gl{BindTexture}. See respective function -documentation for more information. +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. 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. - -Always fully configure the texture before setting the texture data, so OpenGL -can optimize the data to match your settings. - +dedicated layers, not occupied by other textures. First configure the texture +and *then* set the data, so OpenGL can optimize them to match the settings. To +avoid redundant consistency checks and memory reallocations when updating +texture data, set texture storage at once using @ref Texture::setStorage() "setStorage()" +and then set data using @ref Texture::setSubImage() "setSubImage()". + +You can use functions invalidateImage() and @ref Texture::invalidateSubImage() "invalidateSubImage()" +if you don't need texture data anymore to avoid unnecessary memory operations +performed by OpenGL in order to preserve the data. If running on OpenGL ES or +extension @extension{ARB,invalidate_subdata} is not available, these functions +do nothing. + +@todo all texture [level] parameters, global texture parameters @todo Add glPixelStore encapsulation @todo Texture copying +@todo Move constructor/assignment - how to avoid creation of empty texture and + then deleting it immediately? +@todo ES2 - proper support for pixel unpack buffer when extension is in headers */ class MAGNUM_EXPORT AbstractTexture { friend class Context; AbstractTexture(const AbstractTexture& other) = delete; - AbstractTexture(AbstractTexture&& other) = delete; AbstractTexture& operator=(const AbstractTexture& other) = delete; - AbstractTexture& operator=(AbstractTexture&& other) = delete; public: /** @@ -82,8 +92,18 @@ class MAGNUM_EXPORT AbstractTexture { * @see setMagnificationFilter() and setMinificationFilter() */ enum class Filter: GLint { - NearestNeighbor = GL_NEAREST, /**< Nearest neighbor filtering */ - LinearInterpolation = GL_LINEAR /**< Linear interpolation filtering */ + 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 }; /** @@ -92,18 +112,24 @@ class MAGNUM_EXPORT AbstractTexture { * @see setMinificationFilter() */ enum class Mipmap: GLint { - BaseLevel = GL_NEAREST & ~GL_NEAREST, /**< Select base mip level */ + Base = GL_NEAREST & ~GL_NEAREST, /**< Select base mip level */ /** * Select nearest mip level. **Unavailable on rectangle textures.** */ - NearestLevel = GL_NEAREST_MIPMAP_NEAREST & ~GL_NEAREST, + 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. */ - LinearInterpolation = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST + Linear = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST }; /** @@ -137,450 +163,836 @@ class MAGNUM_EXPORT AbstractTexture { #endif }; - /** @{ @name Internal texture formats */ - - #ifndef MAGNUM_TARGET_GLES2 /** - * @brief Color components + * @brief Internal format * - * @requires_gles30 (no extension providing this functionality) + * @see @ref Texture::setImage() "setImage()" */ - enum class Components { + enum class InternalFormat: GLint { /** - * Red component only. Green and blue are set to `0`, alpha is set - * to `1`. - * @requires_gl30 Extension @extension{ARB,texture_rg} + * 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} */ - Red, + #ifndef MAGNUM_TARGET_GLES2 + Red = GL_RED, + #else + Red = GL_RED_EXT, + #endif + #ifndef MAGNUM_TARGET_GLES2 /** - * Red and green component. Blue is set to `0`, alpha is set to - * `1`. - * @requires_gl30 Extension @extension{ARB,texture_rg} + * 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. */ - RedGreen, - - RGB, /**< Red, green and blue component. Alpha is set to `1`. */ - RGBA /**< Red, green, blue component and alpha. */ - }; + R8 = GL_R8, + #endif - /** - * @brief Type of data per each component - * - * `NormalizedUnsignedByte` and `NormalizedUnsignedShort` are the - * main ones for general usage. - * @requires_gles30 (no extension providing this functionality) - */ - enum class ComponentType { /** - * (Non-normalized) unsigned byte - * @requires_gl30 Extension @extension{EXT,texture_integer} + * 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} */ - UnsignedByte, + #ifndef MAGNUM_TARGET_GLES2 + RG = GL_RG, + #else + RG = GL_RG_EXT, + #endif + #ifndef MAGNUM_TARGET_GLES2 /** - * (Non-normalized) byte - * @requires_gl30 Extension @extension{EXT,texture_integer} + * 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. */ - Byte, + RG8 = GL_RG8, + #endif /** - * (Non-normalized) unsigned short - * @requires_gl30 Extension @extension{EXT,texture_integer} + * 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". */ - UnsignedShort, + RGB = GL_RGB, /** - * (Non-normalized) short - * @requires_gl30 Extension @extension{EXT,texture_integer} + * RGB, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} */ - Short, + #ifndef MAGNUM_TARGET_GLES2 + RGB8 = GL_RGB8, + #else + RGB8 = GL_RGB8_OES, + #endif /** - * (Non-normalized) unsigned integer - * @requires_gl30 Extension @extension{EXT,texture_integer} + * 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". */ - UnsignedInt, + RGBA = GL_RGBA, /** - * (Non-normalized) integer - * @requires_gl30 Extension @extension{EXT,texture_integer} + * RGBA, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} */ - Int, + #ifndef MAGNUM_TARGET_GLES2 + RGBA8 = GL_RGBA8, + #else + RGBA8 = GL_RGBA8_OES, + #endif + #ifndef MAGNUM_TARGET_GLES2 /** - * Half float (16 bit) - * @requires_gl30 Extension @extension{ARB,texture_float} + * Red component, normalized signed byte. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned formats are available in OpenGL + * ES 2.0. */ - Half, + R8Snorm = GL_R8_SNORM, /** - * Float (32 bit) - * @requires_gl30 Extension @extension{ARB,texture_float} + * 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. */ - Float, + RG8Snorm = GL_RG8_SNORM, /** - * Normalized unsigned byte, i.e. values from range @f$ [0; 255] @f$ - * are converted to range @f$ [0.0; 1.0] @f$. + * 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. */ - NormalizedUnsignedByte, + RGB8Snorm = GL_RGB8_SNORM, /** - * Normalized signed byte, i.e. values from range @f$ [-128; 127] @f$ - * are converted to range @f$ [-1.0; 1.0] @f$. - * @requires_gl31 Extension @extension{EXT,texture_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. */ - NormalizedByte + 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, /** - * Normalized unsigned short, i.e. values from range @f$ [0; 65536] @f$ - * are converted to range @f$ [0.0; 1.0] @f$. - * @requires_gl + * RGB, each component normalized unsigned short. + * @requires_gl Only byte-sized normalized formats are available + * in OpenGL ES. */ - NormalizedUnsignedShort, + RGB16 = GL_RGB16, /** - * Normalized signed short, i.e. values from range @f$ [-32768; 32767] @f$ - * are converted to range @f$ [-1.0; 1.0] @f$. - * @requires_gl - * @requires_gl31 Extension @extension{EXT,texture_snorm} + * RGBA, each component normalized unsigned short. + * @requires_gl Only byte-sized normalized formats are available + * in OpenGL ES. */ - NormalizedShort + RGBA16 = GL_RGBA16, #endif - }; - #endif - /** - * @brief Internal format - * - * For more information about default values for unused components and - * normalization see enums Components and ComponentType. - */ - enum class Format: GLenum { - #ifndef MAGNUM_TARGET_GLES2 /** - * One-component (red channel), unsigned normalized, probably - * 8bit. - * @requires_gl30 Extension @extension{ARB,texture_rg} - * @requires_gles30 (no extension providing this functionality) + * Red component, normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned normalized formats are available + * in OpenGL ES 2.0. */ - Red = GL_RED, + R16Snorm = GL_R16_SNORM, + + /** + * Red and green component, each normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned normalized formats are available + * in OpenGL ES 2.0. + */ + RG16Snorm = GL_RG16_SNORM, + + /** + * RGB, each component normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned normalized formats are available + * in OpenGL ES 2.0. + */ + RGB16Snorm = GL_RGB16_SNORM, + + /** + * RGBA, each component normalized signed short. + * @requires_gl31 %Extension @extension{EXT,texture_snorm} + * @requires_gles30 Only unsigned normalized formats are available + * in OpenGL ES 2.0. + */ + RGBA16Snorm = GL_RGBA16_SNORM, + + /** + * 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, /** - * Two-component (red and green channel), unsigned normalized, - * each component probably 8bit, 16bit total. - * @requires_gl30 Extension @extension{ARB,texture_rg} - * @requires_gles30 (no extension providing this functionality) + * RGBA, each component float. + * @requires_gl30 %Extension @extension{ARB,texture_float} + * @requires_gles30 Only normalized integral formats are available + * in OpenGL ES 2.0. */ - RedGreen = GL_RG, + RGBA32F = GL_RGBA32F, #endif + #ifndef MAGNUM_TARGET_GLES /** - * Three-component RGB, unsigned normalized, each component - * probably 8bit, 24bit total. - * - * Prefer to use the exactly specified version of this format, in - * this case `Components::RGB|ComponentType::%NormalizedUnsignedByte`. + * RGB, normalized unsigned, red and green component 3bit, blue + * 2bit. + * @requires_gl Packed 8bit types are not available in OpenGL ES. */ - RGB = GL_RGB, + R3B3G2 = GL_R3_G3_B2, /** - * Four-component RGBA, unsigned normalized, each component - * probably 8bit, 24bit total. - * - * Prefer to use the exactly specified version of this format, in - * this case `Components::RGBA|ComponentType::%NormalizedUnsignedByte`. + * RGB, each component normalized unsigned 4bit. + * @requires_gl Packed 12bit types are not available in OpenGL ES. */ - RGBA = GL_RGBA, + 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} + */ + #ifndef MAGNUM_TARGET_GLES2 + RGB565 = GL_RGB565, + #else + RGB565 = GL_RGB565_OES, + #endif + #endif + + /** + * 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 #ifndef MAGNUM_TARGET_GLES /** - * Three-component BGR, unsigned normalized, each component - * probably 8bit, 24bit total. - * @requires_gl + * RGB, each component normalized unsigned 12bit. + * @requires_gl Packed 36bit types are not available in OpenGL ES. */ - BGR = GL_BGR, + RGB12 = GL_RGB12, /** - * Four-component BGRA, unsigned normalized, each component - * probably 8bit, 24bit total. - * @requires_gl + * RGBA, normalized unsigned, each component 2bit. + * @requires_gl Packed 8bit types are not available in OpenGL ES. */ - BGRA = GL_BGRA, + RGBA2 = GL_RGBA2, #endif + /** + * RGBA, normalized unsigned, each component 4bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + */ #ifndef MAGNUM_TARGET_GLES2 + RGBA4 = GL_RGBA4, + #else + RGBA4 = GL_RGBA4_OES, + #endif + /** - * Four-component sRGBA, unsigned normalized, each component - * 8bit, 32bit total. - * @requires_gles30 (no extension providing this functionality) + * RGBA, normalized unsigned, each RGB component 5bit, alpha 1bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} */ - SRGBA8 = GL_SRGB8_ALPHA8, + #ifndef MAGNUM_TARGET_GLES2 + RGB5A1 = GL_RGB5_A1, + #else + RGB5A1 = GL_RGB5_A1_OES, + #endif /** - * Three-component sRGB, unsigned normalized, each component - * 8bit, 24bit total. - * @requires_gles30 (no extension providing this functionality) + * 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} */ - SRGB8 = GL_SRGB8, + #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 /** - * Four-component RGBA, unsigned normalized, each RGB component - * 10bit, alpha 2bit, 32bit total. - * @requires_gles30 (no extension providing this functionality) + * RGBA, each component normalized unsigned 12bit. + * @requires_gl Packed 48bit types are not available in OpenGL ES. */ - RGB10Alpha2 = GL_RGB10_A2, + RGBA12 = GL_RGBA12, + #endif + #ifndef MAGNUM_TARGET_GLES2 /** - * Four-component RGBA, unsigned non-normalized, each RGB - * component 10bit, alpha channel 2bit, 32bit total. - * @requires_gl33 Extension @extension{ARB,texture_rgb10_a2ui} - * @requires_gles30 (no extension providing this functionality) + * 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. */ - RGB10Alpha2Unsigned = GL_RGB10_A2UI, + R11FG11FB10F = GL_R11F_G11F_B10F, #endif + #ifndef MAGNUM_TARGET_GLES2 /** - * Four-component RGBA, unsigned normalized, each RGB component - * 5bit, alpha 1bit, 16bit total. + * 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. */ - RGB5Alpha1 = GL_RGB5_A1, + RGB9E5 = GL_RGB9_E5, + #endif /** - * Four-component RGBA, unsigned normalized, each component 4bit, - * 16bit total. + * 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. */ - RGBA4 = GL_RGBA4, + #ifndef MAGNUM_TARGET_GLES + SRGB = GL_SRGB, + #else + SRGB = GL_SRGB_EXT, + #endif #ifndef MAGNUM_TARGET_GLES2 /** - * Three-component RGB, float, red and green 11bit, blue 10bit, - * 32bit total. - * @requires_gl30 Extension @extension{EXT,packed_float} - * @requires_gles30 (no extension providing this functionality) + * sRGB, each component normalized unsigned byte. + * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGB" + * in OpenGL ES 2.0 instead. */ - RG11B10Float = GL_R11F_G11F_B10F, + SRGB8 = GL_SRGB8, #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) /** - * Three-component RGB, unsigned normalized, red and blue 5bit, - * green 6bit, 16bit total. + * 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. */ - RGB565 = GL_RGB565 + #ifndef MAGNUM_TARGET_GLES + SRGBAlpha = GL_SRGB_ALPHA, + #else + SRGBAlpha = GL_SRGB_ALPHA_EXT, #endif #ifndef MAGNUM_TARGET_GLES2 - , /** - * Three-component RGB, unsigned with exponent, each component - * 9bit, exponent 5bit, 32bit total. - * @requires_gl30 Extension @extension{EXT,texture_shared_exponent} - * @requires_gles30 (no extension providing this functionality) + * sRGBA, each component normalized unsigned byte. + * @requires_gles30 Use @ref Magnum::AbstractTexture::InternalFormat "InternalFormat::SRGBAlpha" + * in OpenGL ES 2.0 instead. */ - RGB9Exponent5 = GL_RGB9_E5, + SRGB8Alpha8 = GL_SRGB8_ALPHA8, #endif #ifndef MAGNUM_TARGET_GLES /** - * Compressed red channel, unsigned normalized. - * @requires_gl - * @requires_gl30 Extension @extension{ARB,texture_rg} + * 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, unsigned normalized. - * @requires_gl - * @requires_gl30 Extension @extension{ARB,texture_rg} + * 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. */ - CompressedRedGreen = GL_COMPRESSED_RG, + CompressedRG = GL_COMPRESSED_RG, /** - * Compressed RGB, unsigned normalized. - * @requires_gl + * Compressed RGB, normalized unsigned. + * @requires_gl Generic texture compression is not available in + * OpenGL ES. */ CompressedRGB = GL_COMPRESSED_RGB, /** - * Compressed RGBA, unsigned normalized. - * @requires_gl + * Compressed RGBA, normalized unsigned. + * @requires_gl Generic texture compression is not available in + * OpenGL ES. */ CompressedRGBA = GL_COMPRESSED_RGBA, /** - * RTGC compressed red channel, unsigned normalized. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,texture_compression_rgtc} + * 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. */ - CompressedRtgcRed = GL_COMPRESSED_RED_RGTC1, + CompressedRedRtgc1 = GL_COMPRESSED_RED_RGTC1, /** - * RTGC compressed red channel, signed normalized. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,texture_compression_rgtc} + * 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. */ - CompressedRtgcSignedRed = GL_COMPRESSED_SIGNED_RED_RGTC1, + CompressedRGRgtc2 = GL_COMPRESSED_RG_RGTC2, /** - * RTGC compressed red and green channel, unsigned normalized. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,texture_compression_rgtc} + * 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. */ - CompressedRtgcRedGreen = GL_COMPRESSED_RG_RGTC2, + CompressedSignedRedRgtc1 = GL_COMPRESSED_SIGNED_RED_RGTC1, /** - * RTGC compressed red and green channel, signed normalized. - * @requires_gl - * @requires_gl30 Extension @extension{EXT,texture_compression_rgtc} + * 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. */ - CompressedRtgcSignedRedGreen = GL_COMPRESSED_SIGNED_RG_RGTC2, + 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, unsigned normalized. - * @requires_gl - * @requires_gl42 Extension @extension{ARB,texture_compression_bptc} + * BPTC compressed RGBA, normalized unsigned. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in + * OpenGL ES. */ - CompressedBptcRGBA = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, + CompressedRGBABtpcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, /** - * BPTC compressed sRGBA, unsigned normalized. - * @requires_gl - * @requires_gl42 Extension @extension{ARB,texture_compression_bptc} + * BPTC compressed sRGBA, normalized unsigned. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in + * OpenGL ES. */ - CompressedBptcSRGBA = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, + CompressedSRGBAlphaBtpcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, /** - * BPTC compressed RGB, signed float. - * @requires_gl - * @requires_gl42 Extension @extension{ARB,texture_compression_bptc} + * BPTC compressed RGB, unsigned float. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in + * OpenGL ES. */ - CompressedBptcRGBSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, + CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, /** - * BPTC compressed RGB, unsigned float. - * @requires_gl - * @requires_gl42 Extension @extension{ARB,texture_compression_bptc} + * BPTC compressed RGB, signed float. + * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} + * @requires_gl BPTC texture compression is not available in + * OpenGL ES. */ - CompressedBptcRGBUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, + CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, /*}*/ + #endif /** - * Depth component, at least 16bit. - * - * Prefer to use the exactly specified version of this format, in - * this case e.g. `Format::Depth16`. - * @requires_gl + * 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} */ - Depth = GL_DEPTH_COMPONENT, + DepthComponent = GL_DEPTH_COMPONENT, /** - * Depth and stencil component, at least 24bit depth and 8bit - * stencil. - * - * Prefer to use the exactly specified version of this format, in - * this case e.g. `Format::Depth24Stencil8`. - * @requires_gl + * 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 - #ifndef MAGNUM_TARGET_GLES2 /** - * 16bit depth component. - * @requires_gles30 (no extension providing this functionality) + * Depth component, 16bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * and @es_extension{OES,depth_texture} */ - Depth16 = GL_DEPTH_COMPONENT16, + DepthComponent16 = GL_DEPTH_COMPONENT16, /** - * 24bit depth component. - * @requires_gles30 (no extension providing this functionality) + * Depth component, 24bit. + * @requires_gles30 %Extension @es_extension{OES,required_internalformat}, + * @es_extension{OES,depth_texture} and @es_extension{OES,depth24} */ - Depth24 = GL_DEPTH_COMPONENT24, + #ifndef MAGNUM_TARGET_GLES2 + DepthComponent24 = GL_DEPTH_COMPONENT24, + #else + DepthComponent24 = GL_DEPTH_COMPONENT24_OES, + #endif /** - * 32bit float depth component. - * @requires_gl30 Extension @extension{ARB,depth_buffer_float} - * @requires_gles30 (no extension providing this functionality) + * Depth component, 32bit. + * @requires_es_extension %Extension @es_extension{OES,required_internalformat}, + * @es_extension{OES,depth_texture} and @es_extension{OES,depth32} */ - Depth32Float = GL_DEPTH_COMPONENT32F, + #ifndef MAGNUM_TARGET_GLES2 + DepthComponent32 = GL_DEPTH_COMPONENT32, + #else + DepthComponent32 = GL_DEPTH_COMPONENT32_OES, + #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 (no extension providing this functionality) + * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * and @es_extension{OES,packed_depth_stencil} */ + #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 (no extension providing this functionality) + * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} + * @requires_gles30 Only integral depth textures are available in + * OpenGL ES 2.0. */ - Depth32FloatStencil8 = GL_DEPTH32F_STENCIL8 + Depth32FStencil8 = GL_DEPTH32F_STENCIL8 #endif }; - /** - * @brief Internal format - * - * When specifying internal format, you can either specify as binary - * OR of component count (using Component enum) and data type per - * component (value from ComponentType enum), or using one of named - * internal formats from Format enum, e.g.: - * @code - * InternalFormat fmt1 = Format::RGBA; - * InternalFormat fmt2 = Components::RGBA|ComponentType::NormalizedUnsignedByte; - * @endcode - * You can also use the constructor directly instead of binary OR: - * @code - * InternalFormat fmt2(Components::RGBA, ComponentType::NormalizedUnsignedByte); - * @endcode - */ - class MAGNUM_EXPORT InternalFormat { - public: - #ifndef MAGNUM_TARGET_GLES2 - /** - * @brief Constructor from component count and data type per component - * - * @requires_gles30 (no extension providing this functionality) - */ - InternalFormat(Components components, ComponentType type); - #endif - - /** @brief Constructor from named internal format */ - inline constexpr InternalFormat(Format format): internalFormat(static_cast(format)) {} - - /** @brief OpenGL internal format ID */ - inline constexpr operator GLint() const { return internalFormat; } - - private: - GLint internalFormat; - }; - - /*@}*/ - /** * @brief Max supported layer count * * The result is cached, repeated queries don't result in repeated * OpenGL calls. - * @see @ref AbstractShaderProgram-subclassing, bind(GLint), + * @see @ref AbstractShaderProgram-subclassing, bind(Int), * @fn_gl{Get} with @def_gl{MAX_COMBINED_TEXTURE_IMAGE_UNITS}, * @fn_gl{ActiveTexture} */ - static GLint maxSupportedLayerCount(); + static Int maxSupportedLayerCount(); /** * @brief Max supported anisotropy @@ -591,18 +1003,13 @@ 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} */ - static GLfloat maxSupportedAnisotropy(); + static Float maxSupportedAnisotropy(); - /** - * @brief Constructor - * @param target Target, e.g. `GL_TEXTURE_2D`. - * - * Creates one OpenGL texture. - * @see @fn_gl{GenTextures} - */ - inline AbstractTexture(GLenum target): _target(target) { + #ifndef DOXYGEN_GENERATING_OUTPUT + inline explicit AbstractTexture(GLenum target): _target(target) { glGenTextures(1, &_id); } + #endif /** * @brief Destructor @@ -612,6 +1019,12 @@ class MAGNUM_EXPORT AbstractTexture { */ virtual ~AbstractTexture() = 0; + /** @brief Move constructor */ + AbstractTexture(AbstractTexture&& other); + + /** @brief Move assignment */ + AbstractTexture& operator=(AbstractTexture&& other); + /** @brief OpenGL texture ID */ inline GLuint id() const { return _id; } @@ -626,7 +1039,7 @@ class MAGNUM_EXPORT AbstractTexture { * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or * @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} */ - void bind(GLint layer); + void bind(Int layer); /** * @brief Set minification filter @@ -639,6 +1052,8 @@ 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"). * @attention For rectangle textures only some modes are supported, * see @ref AbstractTexture::Filter "Filter" and * @ref AbstractTexture::Mipmap "Mipmap" documentation for more @@ -647,7 +1062,7 @@ class MAGNUM_EXPORT AbstractTexture { * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} * with @def_gl{TEXTURE_MIN_FILTER} */ - AbstractTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel); + AbstractTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base); /** * @brief Set magnification filter @@ -657,6 +1072,7 @@ 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". * @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} @@ -674,6 +1090,7 @@ class MAGNUM_EXPORT AbstractTexture { * 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}`. * @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} @@ -700,16 +1117,24 @@ 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(GLfloat anisotropy) { - /** @todo Remove `ifndef` when extension header is available */ - #ifndef MAGNUM_TARGET_GLES + inline AbstractTexture* setMaxAnisotropy(Float anisotropy) { (this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); - #else - static_cast(anisotropy); - #endif return this; } + /** + * @brief Invalidate texture image + * @param level Mip level + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. + * @see @ref Texture::invalidateSubImage() "invalidateSubImage()", + * @fn_gl{InvalidateTexImage} + */ + inline void invalidateImage(Int level) { + (this->*invalidateImplementation)(level); + } + /** * @brief Generate mipmap * @return Pointer to self (for method chaining) @@ -720,18 +1145,18 @@ class MAGNUM_EXPORT AbstractTexture { * @see setMinificationFilter(), @fn_gl{ActiveTexture}, * @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or * @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} */ AbstractTexture* generateMipmap(); protected: #ifndef DOXYGEN_GENERATING_OUTPUT - template struct DataHelper {}; + template struct DataHelper {}; /* Unlike bind() this also sets the binding layer as active */ void MAGNUM_LOCAL bindInternal(); - const GLenum _target; + GLenum _target; #endif private: @@ -765,6 +1190,13 @@ class MAGNUM_EXPORT AbstractTexture { #endif static ParameterfvImplementation parameterfvImplementation; + #ifndef MAGNUM_TARGET_GLES + typedef void(AbstractTexture::*GetLevelParameterivImplementation)(GLenum, GLint, GLenum, GLint*); + void MAGNUM_LOCAL getLevelParameterImplementationDefault(GLenum target, GLint level, GLenum parameter, GLint* values); + void MAGNUM_LOCAL getLevelParameterImplementationDSA(GLenum target, GLint level, GLenum parameter, GLint* values); + static MAGNUM_LOCAL GetLevelParameterivImplementation getLevelParameterivImplementation; + #endif + typedef void(AbstractTexture::*MipmapImplementation)(); void MAGNUM_LOCAL mipmapImplementationDefault(); #ifndef MAGNUM_TARGET_GLES @@ -773,61 +1205,106 @@ class MAGNUM_EXPORT AbstractTexture { static MAGNUM_LOCAL MipmapImplementation mipmapImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*Image1DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector<1, GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); - void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); - void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + 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); + 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); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, InternalFormat 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); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, InternalFormat 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); static Image1DImplementation image1DImplementation; #endif - typedef void(AbstractTexture::*Image2DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector2&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); - void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); - void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + 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); + #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); + #endif static Image2DImplementation image2DImplementation; - typedef void(AbstractTexture::*Image3DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector3&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); - void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); - void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + 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); + #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); + #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::Components, AbstractImage::ComponentType, const GLvoid*); - void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); - void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + 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); static SubImage1DImplementation subImage1DImplementation; #endif - typedef void(AbstractTexture::*SubImage2DImplementation)(GLenum, GLint, const Math::Vector2&, const Math::Vector2&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); - void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); - void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + 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); + #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); + #endif static SubImage2DImplementation subImage2DImplementation; - typedef void(AbstractTexture::*SubImage3DImplementation)(GLenum, GLint, const Math::Vector3&, const Math::Vector3&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); - void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); - void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + 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); + #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); + #endif static SubImage3DImplementation subImage3DImplementation; + typedef void(AbstractTexture::*InvalidateImplementation)(GLint); + void MAGNUM_LOCAL invalidateImplementationNoOp(GLint level); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateImplementationARB(GLint level); + #endif + static InvalidateImplementation invalidateImplementation; + + typedef void(AbstractTexture::*InvalidateSubImplementation)(GLint, const Vector3i&, const Vector3i&); + void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLint level, const Vector3i& offset, const Vector3i& size); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateSubImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size); + #endif + static InvalidateSubImplementation invalidateSubImplementation; + + void MAGNUM_LOCAL destroy(); + void MAGNUM_LOCAL move(); + GLuint _id; }; -#ifndef MAGNUM_TARGET_GLES2 -/** @relates AbstractTexture -@brief Convertor of component count and data type to InternalFormat - -@requires_gles30 (no extension providing this functionality) -*/ -inline AbstractTexture::InternalFormat operator|(AbstractTexture::Components components, AbstractTexture::ComponentType type) { - return AbstractTexture::InternalFormat(components, type); -} +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct ImageHelper { + inline static const GLvoid* dataOrPixelUnpackBuffer(Image* image) { + #ifndef MAGNUM_TARGET_GLES2 + Buffer::unbind(Buffer::Target::PixelUnpack); + #endif + return image->data(); + } + }; -/** @relates AbstractTexture - * @overload - */ -inline AbstractTexture::InternalFormat operator|(AbstractTexture::ComponentType type, AbstractTexture::Components components) { - return AbstractTexture::InternalFormat(components, type); + #ifndef MAGNUM_TARGET_GLES2 + template struct MAGNUM_EXPORT ImageHelper> { + static const GLvoid* dataOrPixelUnpackBuffer(BufferImage* image); + }; + #endif } -#endif -#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_TARGET_GLES template<> struct AbstractTexture::DataHelper<1> { enum class Target: GLenum { @@ -836,16 +1313,26 @@ template<> struct AbstractTexture::DataHelper<1> { inline constexpr static Target target() { return Target::Texture1D; } - inline static void setWrapping(AbstractTexture* texture, const Math::Vector<1, Wrapping>& wrapping) { - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping[0])); + static Math::Vector<1, GLint> imageSize(AbstractTexture* texture, GLenum target, GLint level); + + inline static void setWrapping(AbstractTexture* texture, const Array1D& wrapping) { + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping.x())); } - template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { - (texture->*image1DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data()); + inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size) { + (texture->*storage1DImplementation)(target, levels, internalFormat, size); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, Image* image) { - (texture->*subImage1DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data()); + template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat 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) { + (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}); } }; #endif @@ -861,18 +1348,30 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { inline constexpr static Target target() { return Target::Texture2D; } - static void setWrapping(AbstractTexture* texture, const Math::Vector2& wrapping); + #ifndef MAGNUM_TARGET_GLES + static Vector2i imageSize(AbstractTexture* texture, GLenum target, GLint level); + #endif + + static void setWrapping(AbstractTexture* texture, const Array2D& wrapping); - template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { - (texture->*image2DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data()); + inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector2i& size) { + (texture->*storage2DImplementation)(target, levels, internalFormat, size); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector2& offset, Image* image) { - (texture->*subImage2DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data()); + template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat 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 mipLevel, const Math::Vector2& offset, Image* image) { - (texture->*subImage2DImplementation)(target, mipLevel, offset, Math::Vector2(image->size(), 1), image->components(), image->type(), image->data()); + template inline static typename std::enable_if::type setSub(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) { + (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}); } }; template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { @@ -887,18 +1386,30 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { inline constexpr static Target target() { return Target::Texture3D; } - static void setWrapping(AbstractTexture* texture, const Math::Vector3& wrapping); + #ifndef MAGNUM_TARGET_GLES + static Vector3i imageSize(AbstractTexture* texture, GLenum target, GLint level); + #endif + + static void setWrapping(AbstractTexture* texture, const Array3D& wrapping); + + inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat 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) { + (texture->*image3DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), Implementation::ImageHelper::dataOrPixelUnpackBuffer(image)); + } - template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { - (texture->*image3DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data()); + template inline static typename std::enable_if::type setSub(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 mipLevel, const Math::Vector3& offset, Image* image) { - (texture->*subImage3DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data()); + template inline static typename std::enable_if::type setSub(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)); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector3& offset, Image* image) { - (texture->*subImage3DImplementation)(target, mipLevel, offset, Math::Vector3(image->size(), 1), image->components(), image->type(), image->data()); + inline static void invalidateSub(AbstractTexture* texture, GLint level, const Vector3i& offset, const Vector3i& size) { + (texture->*invalidateSubImplementation)(level, offset, size); } }; #endif diff --git a/src/Array.h b/src/Array.h new file mode 100644 index 000000000..5c79267e2 --- /dev/null +++ b/src/Array.h @@ -0,0 +1,221 @@ +#ifndef Magnum_Array_h +#define Magnum_Array_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::Array, Magnum::Array1D, Magnum::Array2D, Magnum::Array3D + */ + +#include +#include + +#include "Magnum.h" + +namespace Magnum { + +/** +@brief %Array +@tparam dimensions Dimension count +@tparam T Data type + +Similar to Math::Vector, but more suitable for storing enum values which don't +need any math operations and fuzzy comparison (e.g. enum values). Unlike +Math::Vector this class has non-explicit constructor from one value. +@see Array1D, Array2D, Array3D +*/ +template class Array { + public: + typedef T Type; /**< @brief Data type */ + const static UnsignedInt Dimensions = dimensions; /**< @brief Dimension count */ + + /** + * @brief Default constructor + * + * Sets all components to their default-constructed values + */ + inline constexpr /*implicit*/ Array(): _data() {} + + /** + * @brief Initializer-list constructor + * @param first First value + * @param next Next values + */ + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline 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} {} + #else + template inline 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) { + for(UnsignedInt i = 0; i != dimensions; ++i) + _data[i] = value; + } + + /** @brief Equality */ + inline 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 { + 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 */ + + /** + * @brief Raw data + * @return One-dimensional array of `dimensions` length + */ + inline T* data() { return _data; } + inline constexpr const T* data() const { return _data; } /**< @overload */ + + private: + T _data[dimensions]; +}; + +/** +@brief One-dimensional array +@tparam T Data type +*/ +template class Array1D: public Array<1, T> { + public: + /** @copydoc Array::Array() */ + inline constexpr /*implicit*/ Array1D() = default; + + /** + * @brief Constructor + * @param x X component + */ + inline constexpr /*implicit*/ Array1D(T x): Array<1, T>(x) {} + + /** @brief Copy constructor */ + inline 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 */ +}; + +/** +@brief Two-dimensional array +@tparam T Data type +*/ +template class Array2D: public Array<2, T> { + public: + /** @copydoc Array::Array() */ + inline 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) {} + + /** @copydoc Array::Array(U) */ + inline 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) {} + + 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 */ +}; + +/** +@brief Three-dimensional array +@tparam T Data type +*/ +template class Array3D: public Array<3, T> { + public: + /** @copydoc Array::Array() */ + inline constexpr /*implicit*/ Array3D() {} + + /** + * @brief Constructor + * @param x X component + * @param y Y component + * @param z Z component + */ + inline 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) {} + + /** @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 */ +}; + +/** @debugoperator{Magnum::Array} */ +template Debug operator<<(Debug debug, const Array& value) { + debug << "Array("; + debug.setFlag(Debug::SpaceAfterEachValue, false); + for(UnsignedInt i = 0; i != dimensions; ++i) { + if(i != 0) debug << ", "; + debug << value[i]; + } + debug << ")"; + debug.setFlag(Debug::SpaceAfterEachValue, true); + return debug; +} + +/** @debugoperator{Magnum::Array1D} */ +template inline Debug operator<<(Debug debug, const Array1D& value) { + return debug << static_cast&>(value); +} + +/** @debugoperator{Magnum::Array2D} */ +template inline Debug operator<<(Debug debug, const Array2D& value) { + return debug << static_cast&>(value); +} + +/** @debugoperator{Magnum::Array3D} */ +template inline Debug operator<<(Debug debug, const Array3D& value) { + return debug << static_cast&>(value); +} + +} + +#endif diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 777d0b06b..dd108bd2e 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Buffer.h" @@ -29,6 +38,12 @@ Buffer::CopyImplementation Buffer::copyImplementation = &Buffer::copyImplementat #endif Buffer::SetDataImplementation Buffer::setDataImplementation = &Buffer::setDataImplementationDefault; Buffer::SetSubDataImplementation Buffer::setSubDataImplementation = &Buffer::setSubDataImplementationDefault; +Buffer::InvalidateImplementation Buffer::invalidateImplementation = &Buffer::invalidateImplementationNoOp; +Buffer::InvalidateSubImplementation Buffer::invalidateSubImplementation = &Buffer::invalidateSubImplementationNoOp; +Buffer::MapImplementation Buffer::mapImplementation = &Buffer::mapImplementationDefault; +Buffer::MapRangeImplementation Buffer::mapRangeImplementation = &Buffer::mapRangeImplementationDefault; +Buffer::FlushMappedRangeImplementation Buffer::flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDefault; +Buffer::UnmapImplementation Buffer::unmapImplementation = &Buffer::unmapImplementationDefault; void Buffer::initializeContextBasedFunctionality(Context* context) { #ifndef MAGNUM_TARGET_GLES @@ -38,6 +53,17 @@ void Buffer::initializeContextBasedFunctionality(Context* context) { copyImplementation = &Buffer::copyImplementationDSA; setDataImplementation = &Buffer::setDataImplementationDSA; setSubDataImplementation = &Buffer::setSubDataImplementationDSA; + mapImplementation = &Buffer::mapImplementationDSA; + mapRangeImplementation = &Buffer::mapRangeImplementationDSA; + flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDSA; + unmapImplementation = &Buffer::unmapImplementationDSA; + } + + if(context->isExtensionSupported()) { + Debug() << "Buffer: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; + + invalidateImplementation = &Buffer::invalidateImplementationARB; + invalidateSubImplementation = &Buffer::invalidateSubImplementationARB; } #else static_cast(context); @@ -114,4 +140,85 @@ void Buffer::setSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, const } #endif +void Buffer::invalidateImplementationNoOp() {} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::invalidateImplementationARB() { + glInvalidateBufferData(_id); +} +#endif + +void Buffer::invalidateSubImplementationNoOp(GLintptr, GLsizeiptr) {} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length) { + glInvalidateBufferSubData(_id, offset, length); +} +#endif + +void* Buffer::mapImplementationDefault(MapAccess access) { + /** @todo Re-enable when extension wrangler is available for ES */ + #ifndef MAGNUM_TARGET_GLES + return glMapBuffer(static_cast(bindInternal(_targetHint)), GLenum(access)); + #else + static_cast(access); + return nullptr; + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void* Buffer::mapImplementationDSA(MapAccess access) { + return glMapNamedBufferEXT(_id, GLenum(access)); +} +#endif + +void* Buffer::mapRangeImplementationDefault(GLintptr offset, GLsizeiptr length, MapFlags access) { + /** @todo Re-enable when extension wrangler is available for ES */ + #ifndef MAGNUM_TARGET_GLES2 + return glMapBufferRange(static_cast(bindInternal(_targetHint)), offset, length, GLenum(access)); + #else + static_cast(offset); + static_cast(length); + static_cast(access); + return nullptr; + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void* Buffer::mapRangeImplementationDSA(GLintptr offset, GLsizeiptr length, MapFlags access) { + return glMapNamedBufferRangeEXT(_id, offset, length, GLenum(access)); +} +#endif + +void Buffer::flushMappedRangeImplementationDefault(GLintptr offset, GLsizeiptr length) { + /** @todo Re-enable when extension wrangler is available for ES */ + #ifndef MAGNUM_TARGET_GLES2 + glFlushMappedBufferRange(static_cast(bindInternal(_targetHint)), offset, length); + #else + static_cast(offset); + static_cast(length); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::flushMappedRangeImplementationDSA(GLintptr offset, GLsizeiptr length) { + glFlushMappedNamedBufferRangeEXT(_id, offset, length); +} +#endif + +bool Buffer::unmapImplementationDefault() { + /** @todo Re-enable when extension wrangler is available for ES */ + #ifndef MAGNUM_TARGET_GLES2 + return glUnmapBuffer(static_cast(bindInternal(_targetHint))); + #else + return false; + #endif +} + +#ifndef MAGNUM_TARGET_GLES +bool Buffer::unmapImplementationDSA() { + return glUnmapNamedBufferEXT(_id); +} +#endif + } diff --git a/src/Buffer.h b/src/Buffer.h index ff7dcc1a4..c1f41a2f7 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -1,18 +1,27 @@ #ifndef Magnum_Buffer_h #define Magnum_Buffer_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,9 +31,10 @@ #include #include #include +#include #include "Magnum.h" - +#include "OpenGL.h" #include "magnumVisibility.h" namespace Magnum { @@ -40,6 +50,7 @@ data updates. Default way to set or update buffer data with setData() or setSubData() is to explicitly specify data size and pass the pointer to it: @code +Buffer buffer; Vector3* data = new Vector3[200]; buffer.setData(200*sizeof(Vector3), data, Buffer::Usage::StaticDraw); @endcode @@ -59,19 +70,52 @@ std::vector data; buffer.setData(data, Buffer::Usage::StaticDraw); @endcode +@subsection Buffer-data-mapping Memory mapping + +%Buffer data can be also updated asynchronously. First you need to allocate +the buffer to desired size by passing `nullptr` to setData(), e.g.: +@code +buffer.setData(200*sizeof(Vector3)), nullptr, Buffer::Usage::StaticDraw); +@endcode +Then you can map the buffer to client memory and operate with the memory +directly. After you are done with the operation, call unmap() to unmap the +buffer again. +@code +Vector3* data = static_cast(buffer.map(0, 200*sizeof(Vector3), Buffer::MapFlag::Write|Buffer::MapFlag::InvalidateBuffer)); +for(std::size_t i = 0; i != 200; ++i) + data[i] = ...; +CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap()); +@endcode +If you are updating only a few discrete portions of the buffer, you can use +@ref MapFlag "MapFlag::FlushExplicit" and flushMappedRange() to reduce number +of memory operations performed by OpenGL on unmapping. Example: +@code +Vector3* data = static_cast(buffer.map(0, 200*sizeof(Vector3), Buffer::MapFlag::Write|Buffer::MapFlag::FlushExplicit)); +for(std::size_t i: {7, 27, 56, 128}) { + data[i] = ...; + buffer.flushMappedRange(i*sizeof(Vector3), sizeof(Vector3)); +} +CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap()); +@endcode + @section Buffer-performance-optimization Performance optimizations The engine tracks currently bound buffers to avoid unnecessary calls to -@fn_gl{BindBuffer}. If the buffer is already bound to some target, -functions copy(), setData() and setSubData() use that target in -@fn_gl{CopyBufferSubData}, @fn_gl{BufferData} and @fn_gl{BufferSubData} -functions instead of binding the buffer to some specific target. You can also -use setTargetHint() to possibly reduce unnecessary rebinding. +@fn_gl{BindBuffer}. If the buffer is already bound to some target, functions +copy(), setData(), setSubData(), map(), flushMappedRange() and unmap() use +that target instead of binding the buffer to some specific target. You can +also use setTargetHint() to possibly reduce unnecessary rebinding. If extension @extension{EXT,direct_state_access} is available, functions -copy(), setData() and setSubData() use DSA functions to avoid unnecessary -calls to @fn_gl{BindBuffer}. See their respective documentation for more -information. +copy(), setData(), setSubData(), map(), flushMappedRange() and unmap() use DSA +functions to avoid unnecessary calls to @fn_gl{BindBuffer}. See their +respective documentation for more information. + +You can use functions invalidateData() and invalidateSubData() if you don't +need buffer data anymore to avoid unnecessary memory operations performed by +OpenGL in order to preserve the data. If running on OpenGL ES or extension +@extension{ARB,invalidate_subdata} is not available, these functions do +nothing. @todo Support for AMD's query buffer (@extension{AMD,query_buffer_object}) @todo BindBufferRange/BindBufferOffset/BindBufferBase for transform feedback (3.0, @extension{EXT,transform_feedback}) @@ -97,7 +141,7 @@ class MAGNUM_EXPORT Buffer { #ifndef MAGNUM_TARGET_GLES /** * Used for storing atomic counters. - * @requires_gl42 Extension @extension{ARB,shader_atomic_counters} + * @requires_gl42 %Extension @extension{ARB,shader_atomic_counters} * @requires_gl Atomic counters are not available in OpenGL ES. */ AtomicCounter = GL_ATOMIC_COUNTER_BUFFER, @@ -106,7 +150,7 @@ class MAGNUM_EXPORT Buffer { #ifndef MAGNUM_TARGET_GLES2 /** * Source for copies. See copy(). - * @requires_gl31 Extension @extension{ARB,copy_buffer} + * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 Buffer copying is not available in OpenGL ES * 2.0. */ @@ -114,7 +158,7 @@ class MAGNUM_EXPORT Buffer { /** * Target for copies. See copy(). - * @requires_gl31 Extension @extension{ARB,copy_buffer} + * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 Buffer copying is not available in OpenGL ES * 2.0. */ @@ -124,14 +168,14 @@ class MAGNUM_EXPORT Buffer { #ifndef MAGNUM_TARGET_GLES /** * Indirect compute dispatch commands. - * @requires_gl43 Extension @extension{ARB,compute_shader} + * @requires_gl43 %Extension @extension{ARB,compute_shader} * @requires_gl Compute shaders are not available in OpenGL ES. */ DispatchIndirect = GL_DISPATCH_INDIRECT_BUFFER, /** * Used for supplying arguments for indirect drawing. - * @requires_gl40 Extension @extension{ARB,draw_indirect} + * @requires_gl40 %Extension @extension{ARB,draw_indirect} * @requires_gl Indirect drawing not available in OpenGL ES. */ DrawIndirect = GL_DRAW_INDIRECT_BUFFER, @@ -161,14 +205,14 @@ class MAGNUM_EXPORT Buffer { #ifndef MAGNUM_TARGET_GLES /** * Used for shader storage. - * @requires_gl43 Extension @extension{ARB,shader_storage_buffer_object} + * @requires_gl43 %Extension @extension{ARB,shader_storage_buffer_object} * @requires_gl Shader storage is not available in OpenGL ES. */ ShaderStorage = GL_SHADER_STORAGE_BUFFER, /** - * Source for texel fetches. See BufferedTexture. - * @requires_gl31 Extension @extension{ARB,texture_buffer_object} + * Source for texel fetches. See BufferTexture. + * @requires_gl31 %Extension @extension{ARB,texture_buffer_object} * @requires_gl Texture buffers are not available in OpenGL ES. */ Texture = GL_TEXTURE_BUFFER, @@ -177,7 +221,7 @@ class MAGNUM_EXPORT Buffer { #ifndef MAGNUM_TARGET_GLES2 /** * Target for transform feedback. - * @requires_gl30 Extension @extension{EXT,transform_feedback} + * @requires_gl30 %Extension @extension{EXT,transform_feedback} * @requires_gles30 Transform feedback is not available in OpenGL * ES 2.0. */ @@ -185,7 +229,7 @@ class MAGNUM_EXPORT Buffer { /** * Used for storing uniforms. - * @requires_gl31 Extension @extension{ARB,uniform_buffer_object} + * @requires_gl31 %Extension @extension{ARB,uniform_buffer_object} * @requires_gles30 Uniform buffers are not available in OpenGL ES * 2.0. */ @@ -265,13 +309,123 @@ class MAGNUM_EXPORT Buffer { /** * Updated frequently as output from OpenGL command and used * frequently for drawing or copying to other images. - * @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::DynamicCopy" + * @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::DynamicDraw" * is available in OpenGL ES 2.0. */ DynamicCopy = GL_DYNAMIC_COPY #endif }; + /** + * @brief Memory mapping access + * + * @deprecated Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * instead, as it has more complete set of features. + * @see map(MapAccess) + * @requires_es_extension %Extension @es_extension{OES,mapbuffer} in + * OpenGL ES 2.0, use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * in OpenGL ES 3.0 instead. + */ + enum class MapAccess: GLenum { + #ifndef MAGNUM_TARGET_GLES + /** + * Map buffer for reading only. + * @requires_gl Only @ref Magnum::Buffer::MapAccess "MapAccess::WriteOnly" + * is available in OpenGL ES 2.0. + */ + ReadOnly = GL_READ_ONLY, + #endif + + /** + * Map buffer for writing only. + */ + #ifdef MAGNUM_TARGET_GLES + WriteOnly = GL_WRITE_ONLY_OES + #else + WriteOnly = GL_WRITE_ONLY, + + /** + * Map buffer for both reading and writing. + * @requires_gl Only @ref Magnum::Buffer::MapAccess "MapAccess::WriteOnly" + * is available in OpenGL ES 2.0. + */ + ReadWrite = GL_READ_WRITE + #endif + }; + + /** + * @brief Memory mapping flag + * + * @see MapFlags, map(GLintptr, GLsizeiptr, MapFlags) + * @requires_gl30 %Extension @extension{ARB,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + */ + enum class MapFlag: GLbitfield { + /** Map buffer for reading. */ + #ifndef MAGNUM_TARGET_GLES2 + Read = GL_MAP_READ_BIT, + #else + Read = GL_MAP_READ_BIT_EXT, + #endif + + /** Map buffer for writing. */ + #ifndef MAGNUM_TARGET_GLES2 + Write = GL_MAP_WRITE_BIT, + #else + Write = GL_MAP_WRITE_BIT_EXT, + #endif + + /** + * Previous contents of the entire buffer may be discarded. May + * not be used in combination with @ref MapFlag "MapFlag::Read". + * @see invalidateData() + */ + #ifndef MAGNUM_TARGET_GLES2 + InvalidateBuffer = GL_MAP_INVALIDATE_BUFFER_BIT, + #else + InvalidateBuffer = GL_MAP_INVALIDATE_BUFFER_BIT_EXT, + #endif + + /** + * Previous contents of mapped range may be discarded. May not + * be used in combination with @ref MapFlag "MapFlag::Read". + * @see invalidateSubData() + */ + #ifndef MAGNUM_TARGET_GLES2 + InvalidateRange = GL_MAP_INVALIDATE_RANGE_BIT, + #else + InvalidateRange = GL_MAP_INVALIDATE_RANGE_BIT_EXT, + #endif + + /** + * Only one or more discrete subranges of the mapping will be + * modified. See flushMappedRange() for more information. May only + * be used in conjuction with @ref MapFlag "MapFlag::Write". + */ + #ifndef MAGNUM_TARGET_GLES2 + FlushExplicit = GL_MAP_FLUSH_EXPLICIT_BIT, + #else + FlushExplicit = GL_MAP_FLUSH_EXPLICIT_BIT_EXT, + #endif + + /** + * No pending operations on the buffer should be synchronized + * before mapping. + */ + #ifndef MAGNUM_TARGET_GLES2 + Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT + #else + Unsynchronized = GL_MAP_UNSYNCHRONIZED_BIT_EXT + #endif + }; + + /** + * @brief Memory mapping flags + * + * @see map(GLintptr, GLsizeiptr, MapFlags) + */ + typedef Corrade::Containers::EnumSet MapFlags; + /** * @brief Unbind any buffer from given target * @param target %Target @@ -293,10 +447,10 @@ class MAGNUM_EXPORT Buffer { * buffers aren't already bound somewhere, they are bound to * `Target::CopyRead` and `Target::CopyWrite` before the copy is * performed. - * @requires_gl31 Extension @extension{ARB,copy_buffer} - * @requires_gles30 Buffer copying is not available in OpenGL ES 2.0. * @see @fn_gl{BindBuffer} and @fn_gl{CopyBufferSubData} or * @fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access} + * @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) { copyImplementation(read, write, readOffset, writeOffset, size); @@ -311,7 +465,7 @@ class MAGNUM_EXPORT Buffer { * Generates new OpenGL buffer. * @see @fn_gl{GenBuffers} */ - inline Buffer(Target targetHint = Target::Array): _targetHint(targetHint) { + inline explicit Buffer(Target targetHint = Target::Array): _targetHint(targetHint) { glGenBuffers(1, &_id); } @@ -443,6 +597,111 @@ class MAGNUM_EXPORT Buffer { setSubData(offset, data.size()*sizeof(T), data.data()); } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Invalidate buffer data + * + * 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() { + (this->*invalidateImplementation)(); + } + + /** + * @brief Invalidate buffer subdata + * @param offset Offset into the buffer + * @param length Length of the invalidated range + * + * 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) { + (this->*invalidateSubImplementation)(offset, length); + } + #endif + + /** + * @brief Map buffer to client memory + * @param access Access + * @return Pointer to buffer data + * + * 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. + * @deprecated Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * instead, as it has more complete set of features. + * @see unmap(), setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{MapBuffer} + * or @fn_gl_extension{MapNamedBuffer,EXT,direct_state_access} + * @requires_es_extension %Extension @es_extension{OES,mapbuffer} in + * 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) { + return (this->*mapImplementation)(access); + } + + /** + * @brief Map buffer to client memory + * @param offset Offset into the buffer + * @param length Length of the mapped memory + * @param flags Flags. At least @ref MapFlag "MapFlag::Read" or + * @ref MapFlag "MapFlag::Write" must be specified. + * @return Pointer to buffer data + * + * 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 flushMappedRange(), unmap(), map(MapAccess), setTargetHint(), @fn_gl{BindBuffer} + * and @fn_gl{MapBufferRange} or @fn_gl_extension{MapNamedBufferRange,EXT,direct_state_access} + * @requires_gl30 %Extension @extension{ARB,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + */ + inline void* map(GLintptr offset, GLsizeiptr length, MapFlags flags) { + return (this->*mapRangeImplementation)(offset, length, flags); + } + + /** + * @brief Flush mapped range + * @param offset Offset relative to start of mapped range + * @param length Length of the flushed memory + * + * Flushes specified subsection of mapped range. Use only if you called + * map() with @ref MapFlag "MapFlag::FlushExplicit" flag. See + * @ref Buffer-data-mapping "class documentation" for usage example. + * + * 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 setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{FlushMappedBufferRange} + * or @fn_gl_extension{FlushMappedNamedBufferRange,EXT,direct_state_access} + * @requires_gl30 %Extension @extension{ARB,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + */ + inline void flushMappedRange(GLintptr offset, GLsizeiptr length) { + (this->*flushMappedRangeImplementation)(offset, length); + } + + /** + * @brief Unmap buffer + * @return `False` if the data have become corrupt during the time + * the buffer was mapped (e.g. after screen was resized), `true` + * otherwise. + * + * Unmaps buffer previously mapped with map(), invalidating the + * pointer returned by these functions. 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 setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{UnmapBuffer} or + * @fn_gl_extension{UnmapNamedBuffer,EXT,direct_state_access} + * @requires_gles30 %Extension @es_extension{OES,mapbuffer} + */ + inline bool unmap() { + return (this->*unmapImplementation)(); + } + private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); @@ -472,10 +731,54 @@ class MAGNUM_EXPORT Buffer { #endif static SetSubDataImplementation setSubDataImplementation; + typedef void(Buffer::*InvalidateImplementation)(); + void MAGNUM_LOCAL invalidateImplementationNoOp(); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateImplementationARB(); + #endif + static InvalidateImplementation invalidateImplementation; + + typedef void(Buffer::*InvalidateSubImplementation)(GLintptr, GLsizeiptr); + void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLintptr offset, GLsizeiptr length); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length); + #endif + static InvalidateSubImplementation invalidateSubImplementation; + + typedef void*(Buffer::*MapImplementation)(MapAccess); + void MAGNUM_LOCAL * mapImplementationDefault(MapAccess access); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL * mapImplementationDSA(MapAccess access); + #endif + static MapImplementation mapImplementation; + + typedef void*(Buffer::*MapRangeImplementation)(GLintptr, GLsizeiptr, MapFlags); + void MAGNUM_LOCAL * mapRangeImplementationDefault(GLintptr offset, GLsizeiptr length, MapFlags access); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL * mapRangeImplementationDSA(GLintptr offset, GLsizeiptr length, MapFlags access); + #endif + static MapRangeImplementation mapRangeImplementation; + + typedef void(Buffer::*FlushMappedRangeImplementation)(GLintptr, GLsizeiptr); + void MAGNUM_LOCAL flushMappedRangeImplementationDefault(GLintptr offset, GLsizeiptr length); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL flushMappedRangeImplementationDSA(GLintptr offset, GLsizeiptr length); + #endif + static FlushMappedRangeImplementation flushMappedRangeImplementation; + + typedef bool(Buffer::*UnmapImplementation)(); + bool MAGNUM_LOCAL unmapImplementationDefault(); + #ifndef MAGNUM_TARGET_GLES + bool MAGNUM_LOCAL unmapImplementationDSA(); + #endif + static UnmapImplementation unmapImplementation; + GLuint _id; Target _targetHint; }; +CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags) + } #endif diff --git a/src/BufferImage.cpp b/src/BufferImage.cpp new file mode 100644 index 000000000..db8d13069 --- /dev/null +++ b/src/BufferImage.cpp @@ -0,0 +1,42 @@ +/* + 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 "BufferImage.h" + +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) { + _format = format; + _type = type; + _size = size; + _buffer.setData(pixelSize(format, type)*size.product(), data, usage); +} + +template class BufferImage<1>; +template class BufferImage<2>; +template class BufferImage<3>; +#endif + +} diff --git a/src/BufferImage.h b/src/BufferImage.h new file mode 100644 index 000000000..ae4910eca --- /dev/null +++ b/src/BufferImage.h @@ -0,0 +1,103 @@ +#ifndef Magnum_BufferImage_h +#define Magnum_BufferImage_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. +*/ + +#ifndef MAGNUM_TARGET_GLES2 +/** @file + * @brief Class Magnum::BufferImage, typedef Magnum::BufferImage1D, Magnum::BufferImage2D, Magnum::BufferImage3D + */ +#endif + +#include "Math/Vector3.h" +#include "AbstractImage.h" +#include "Buffer.h" +#include "DimensionTraits.h" + +namespace Magnum { + +#ifndef MAGNUM_TARGET_GLES2 +/** +@brief %Buffer image + +Stores image data in GPU memory. Interchangeable with Image, ImageWrapper or +Trade::ImageData. +@see BufferImage1D, BufferImage2D, BufferImage3D, Buffer +@requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. +*/ +template class MAGNUM_EXPORT BufferImage: public AbstractImage { + public: + const static UnsignedInt Dimensions = dimensions; /**< @brief %Image dimension count */ + + /** + * @brief Constructor + * @param format Format of pixel data + * @param type Data type of pixel data + * + * Dimensions and buffer are empty, call setData() to fill the image + * with data. + */ + inline explicit BufferImage(Format format, Type type): AbstractImage(format, type) { + _buffer.setTargetHint(Buffer::Target::PixelPack); + } + + /** @brief %Image size */ + inline typename DimensionTraits::VectorType size() const { return _size; } + + /** @brief %Image buffer */ + inline Buffer* buffer() { return &_buffer; } + + /** + * @brief Set image data + * @param size %Image size + * @param format Format of pixel data + * @param type Data type of pixel data + * @param data %Image data + * @param usage %Image buffer usage + * + * Updates the image buffer with given data. The data are not deleted + * after filling the buffer. + * + * @see Buffer::setData() + */ + void setData(const typename DimensionTraits::VectorType& size, Format format, Type type, const GLvoid* data, Buffer::Usage usage); + + private: + Math::Vector _size; + Buffer _buffer; +}; + +/** @brief One-dimensional buffer image */ +typedef BufferImage<1> BufferImage1D; + +/** @brief Two-dimensional buffer image */ +typedef BufferImage<2> BufferImage2D; + +/** @brief Three-dimensional buffer image */ +typedef BufferImage<3> BufferImage3D; +#endif + +} + +#endif diff --git a/src/BufferTexture.cpp b/src/BufferTexture.cpp new file mode 100644 index 000000000..c06e62ec6 --- /dev/null +++ b/src/BufferTexture.cpp @@ -0,0 +1,66 @@ +/* + 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 "BufferTexture.h" + +#ifndef MAGNUM_TARGET_GLES +#include "Buffer.h" +#include "Context.h" +#include "Extensions.h" + +namespace Magnum { + +BufferTexture::SetBufferImplementation BufferTexture::setBufferImplementation = &BufferTexture::setBufferImplementationDefault; +BufferTexture::SetBufferRangeImplementation BufferTexture::setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDefault; + +void BufferTexture::initializeContextBasedFunctionality(Context* context) { + if(context->isExtensionSupported()) { + Debug() << "BufferTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + setBufferImplementation = &BufferTexture::setBufferImplementationDSA; + setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDSA; + } +} + +void BufferTexture::setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer) { + bindInternal(); + glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id()); +} + +void BufferTexture::setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer) { + glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id()); +} + +void BufferTexture::setBufferRangeImplementationDefault(InternalFormat 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) { + glTextureBufferRangeEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id(), offset, size); +} + + +} +#endif diff --git a/src/BufferTexture.h b/src/BufferTexture.h new file mode 100644 index 000000000..1f0fdeb52 --- /dev/null +++ b/src/BufferTexture.h @@ -0,0 +1,261 @@ +#ifndef Magnum_BufferTexture_h +#define Magnum_BufferTexture_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. +*/ + +#ifndef MAGNUM_TARGET_GLES +/** @file + * @brief Class Magnum::BufferTexture + */ +#endif + +#include "AbstractTexture.h" + +#ifndef MAGNUM_TARGET_GLES +namespace Magnum { + +/** +@brief %Buffer texture + +This texture is, unlike classic textures such as Texture or CubeMapTexture, +used as simple data source, without any unnecessary interpolation and +wrapping methods. + +@section BufferTexture-usage Usage + +%Texture data are stored in buffer and after binding the buffer to the texture +using setBuffer(), you can fill the buffer at any time using data setting +functions in Buffer itself. + +Note that the buffer is not managed (e.g. deleted on destruction) by the +texture, so you have to manage it on your own. On the other hand it allows you +to use one buffer for more textures or store more than one data in it. + +Example usage: +@code +Buffer* buffer; +BufferTexture texture; +texture.setBuffer(buffer); + +constexpr static Vector3 data[] = { + // ... +}; +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. + +@section BufferTexture-performance-optimization Performance optimizations +If extension @extension{EXT,direct_state_access} is available, setBuffer() +functions use DSA to avoid unnecessary calls to @fn_gl{ActiveTexture} and +@fn_gl{BindTexture}. See @ref AbstractTexture-performance-optimization +"relevant section in AbstractTexture documentation" and respective function +documentation for more information. + +@requires_gl31 %Extension @extension{ARB,texture_buffer_object} +@requires_gl Texture buffers are not available in OpenGL ES. +*/ +class MAGNUM_EXPORT BufferTexture: private AbstractTexture { + friend class Context; + + BufferTexture(const BufferTexture& other) = delete; + BufferTexture(BufferTexture&& other) = delete; + BufferTexture& operator=(const BufferTexture& other) = delete; + BufferTexture& operator=(BufferTexture&& other) = delete; + + public: + /** + * @brief Internal format + * + * @see setBuffer() + */ + enum class InternalFormat: GLenum { + /** Red component, normalized unsigned byte. */ + R8 = GL_R8, + + /** Red and green component, each normalized unsigned byte. */ + RG8 = GL_RG8, + + /** RGBA, each component normalized unsigned byte. */ + RGBA8 = GL_RGBA8, + + /** Red component, normalized unsigned short. */ + R16 = GL_R16, + + /** Red and green component, each normalized unsigned short. */ + RG16 = GL_RG16, + + /** RGBA, each component normalized unsigned short. */ + RGBA16 = GL_RGBA16, + + /** Red component, non-normalized unsigned byte. */ + R8UI = GL_R8UI, + + /** Red and green component, each non-normalized unsigned byte. */ + RG8UI = GL_RG8UI, + + /** RGBA, each component non-normalized unsigned byte. */ + RGBA8UI = GL_RGBA8UI, + + /** Red component, non-normalized signed byte. */ + R8I = GL_R8I, + + /** Red and green component, each non-normalized signed byte. */ + RG8I = GL_RG8I, + + /** RGBA, each component non-normalized signed byte. */ + RGBA8I = GL_RGBA8I, + + /** Red component, non-normalized unsigned short. */ + R16UI = GL_R16UI, + + /** Red and green component, each non-normalized unsigned short. */ + RG16UI = GL_RG16UI, + + /** RGBA, each component non-normalized unsigned short. */ + RGBA16UI = GL_RGBA16UI, + + /** Red component, non-normalized signed short. */ + R16I = GL_R16I, + + /** Red and green component, each non-normalized signed short. */ + RG16I = GL_RG16I, + + /** RGBA, each component non-normalized signed short. */ + RGBA16I = GL_RGBA16I, + + /** Red component, non-normalized unsigned int. */ + R32UI = GL_R32UI, + + /** Red and green component, each non-normalized unsigned int. */ + RG32UI = GL_RG32UI, + + /** + * RGB, each component non-normalized unsigned int. + * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} + */ + RGB32UI = GL_RGB32UI, + + /** RGBA, each component non-normalized unsigned int. */ + RGBA32UI = GL_RGBA32UI, + + /** Red component, non-normalized signed int. */ + R32I = GL_R32I, + + /** Red and green component, each non-normalized signed int. */ + RG32I = GL_RG32I, + + /** + * 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 int. */ + RGBA32I = GL_RGBA32I, + + /** Red component, half float. */ + R16F = GL_R16F, + + /** Red and green component, each half float. */ + RG16F = GL_RG16F, + + /** RGBA, each component half float. */ + RGBA16F = GL_RGBA16F, + + /** Red component, float. */ + R32F = GL_R32F, + + /** Red and green component, each float. */ + RG32F = GL_RG32F, + + /** + * RGB, each component float. + * @requires_gl40 %Extension @extension{ARB,texture_buffer_object_rgb32} + */ + RGB32F = GL_RGB32F, + + /** RGBA, each component float. */ + RGBA32F = GL_RGBA32F + }; + + inline explicit BufferTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {} + + /** @copydoc AbstractTexture::bind() */ + inline void bind(Int layer) { AbstractTexture::bind(layer); } + + /** + * @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); + } + + /** + * @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); + } + + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + 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; + + 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; +}; + +} +#endif + +#endif diff --git a/src/BufferedImage.cpp b/src/BufferedImage.cpp deleted file mode 100644 index f75688054..000000000 --- a/src/BufferedImage.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "BufferedImage.h" - -namespace Magnum { - -#ifndef MAGNUM_TARGET_GLES2 -template void BufferedImage::setData(const typename DimensionTraits::VectorType& size, Components components, ComponentType type, const GLvoid* data, Buffer::Usage usage) { - _components = components; - _type = type; - _size = size; - _buffer.setData(pixelSize(_components, _type)*size.product(), data, usage); -} - -template class BufferedImage<1>; -template class BufferedImage<2>; -template class BufferedImage<3>; -#endif - -} diff --git a/src/BufferedImage.h b/src/BufferedImage.h deleted file mode 100644 index bcc10c985..000000000 --- a/src/BufferedImage.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef Magnum_BufferedImage_h -#define Magnum_BufferedImage_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#ifndef MAGNUM_TARGET_GLES2 -/** @file - * @brief Class Magnum::BufferedImage, typedef Magnum::BufferedImage1D, Magnum::BufferedImage2D, Magnum::BufferedImage3D - */ -#endif - -#include "Math/Vector3.h" -#include "AbstractImage.h" -#include "Buffer.h" -#include "DimensionTraits.h" -#include "TypeTraits.h" - -namespace Magnum { - -#ifndef MAGNUM_TARGET_GLES2 -/** -@brief %Buffered image - -Class for storing image data in GPU memory. Can be replaced with Image, which -stores image data in client memory, ImageWrapper, or for example with -Trade::ImageData. -@see BufferedImage1D, BufferedImage2D, BufferedImage3D, Buffer -@requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. -*/ -template class MAGNUM_EXPORT BufferedImage: public AbstractImage { - public: - const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */ - - /** - * @brief Constructor - * @param components Color components - * @param type Data type - * - * Dimensions and buffer are empty, call setData() to fill the image - * with data. - */ - inline BufferedImage(Components components, ComponentType type): AbstractImage(components, type) { - _buffer.setTargetHint(Buffer::Target::PixelPack); - } - - /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } - - /** - * @brief Data - * - * Binds the buffer to @ref Buffer::Target "pixel unpack - * target" and returns nullptr, so it can be used for texture updating - * functions the same way as Image::data(). - * - * @see Buffer::bind(Target) - */ - inline void* data() { - _buffer.bind(Buffer::Target::PixelUnpack); - return nullptr; - } - - /** @brief %Image buffer */ - inline Buffer* buffer() { return &_buffer; } - - /** - * @brief Set image data - * @param size %Image size - * @param components Color components. Data type is detected - * from passed data array. - * @param data %Image data - * @param usage %Image buffer usage - * - * Updates the image buffer with given data. The data are not deleted - * after filling the buffer. - * - * @see setData(const Math::Vector&, Components, ComponentType, const GLvoid*, Buffer::Usage) - */ - template inline void setData(const typename DimensionTraits::VectorType& size, Components components, const T* data, Buffer::Usage usage) { - setData(size, components, TypeTraits::imageType(), data, usage); - } - - /** - * @brief Set image data - * @param size %Image size - * @param components Color components - * @param type Data type - * @param data %Image data - * @param usage %Image buffer usage - * - * Updates the image buffer with given data. The data are not deleted - * after filling the buffer. - * - * @see Buffer::setData() - */ - void setData(const typename DimensionTraits::VectorType& size, Components components, ComponentType type, const GLvoid* data, Buffer::Usage usage); - - protected: - Math::Vector _size; /**< @brief %Image size */ - Buffer _buffer; /**< @brief %Image buffer */ -}; - -/** @brief One-dimensional buffered image */ -typedef BufferedImage<1> BufferedImage1D; - -/** @brief Two-dimensional buffered image */ -typedef BufferedImage<2> BufferedImage2D; - -/** @brief Three-dimensional buffered image */ -typedef BufferedImage<3> BufferedImage3D; -#endif - -} - -#endif diff --git a/src/BufferedTexture.cpp b/src/BufferedTexture.cpp deleted file mode 100644 index 862f1f97a..000000000 --- a/src/BufferedTexture.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "BufferedTexture.h" - -#ifndef MAGNUM_TARGET_GLES -#include "Buffer.h" -#include "Context.h" -#include "Extensions.h" - -namespace Magnum { - -BufferedTexture::SetBufferImplementation BufferedTexture::setBufferImplementation = &BufferedTexture::setBufferImplementationDefault; - -void BufferedTexture::initializeContextBasedFunctionality(Context* context) { - if(context->isExtensionSupported()) { - Debug() << "BufferedTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - setBufferImplementation = &BufferedTexture::setBufferImplementationDSA; - } -} - -void BufferedTexture::setBufferImplementationDefault(BufferedTexture::InternalFormat internalFormat, Buffer* buffer) { - bindInternal(); - glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id()); -} - -void BufferedTexture::setBufferImplementationDSA(BufferedTexture::InternalFormat internalFormat, Buffer* buffer) { - glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, internalFormat, buffer->id()); -} - -BufferedTexture::InternalFormat::InternalFormat(Components components, ComponentType type) { - #define internalFormatSwitch(c) switch(type) { \ - case ComponentType::UnsignedByte: \ - internalFormat = GL_##c##8UI; break; \ - case ComponentType::Byte: \ - internalFormat = GL_##c##8I; break; \ - case ComponentType::UnsignedShort: \ - internalFormat = GL_##c##16UI; break; \ - case ComponentType::Short: \ - internalFormat = GL_##c##16I; break; \ - case ComponentType::UnsignedInt: \ - internalFormat = GL_##c##32UI; break; \ - case ComponentType::Int: \ - internalFormat = GL_##c##32I; break; \ - case ComponentType::Half: \ - internalFormat = GL_##c##16F; break; \ - case ComponentType::Float: \ - internalFormat = GL_##c##32F; break; \ - case ComponentType::NormalizedUnsignedByte: \ - internalFormat = GL_##c##8; break; \ - case ComponentType::NormalizedUnsignedShort: \ - internalFormat = GL_##c##16; break; \ - } - if(components == Components::Red) - internalFormatSwitch(R) - else if(components == Components::RedGreen) - internalFormatSwitch(RG) - else if(components == Components::RGBA) - internalFormatSwitch(RGBA) - #undef internalFormatSwitch -} - -} -#endif diff --git a/src/BufferedTexture.h b/src/BufferedTexture.h deleted file mode 100644 index 87f478ee0..000000000 --- a/src/BufferedTexture.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef Magnum_BufferedTexture_h -#define Magnum_BufferedTexture_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#ifndef MAGNUM_TARGET_GLES -/** @file - * @brief Class Magnum::BufferedTexture - */ -#endif - -#include "AbstractTexture.h" - -#ifndef MAGNUM_TARGET_GLES -namespace Magnum { - -/** -@brief Buffered texture - -This texture is, unlike classic textures such as Texture or CubeMapTexture, -used as simple data source, without any unneccessary interpolation and -wrapping methods. Texture data are stored in buffer and after binding the -buffer to the texture using setBuffer(), you can fill the buffer at any time -using data setting functions in Buffer itself. - -When using buffered texture in the shader, use `samplerBuffer` and fetch the -data using integer coordinates in `texelFetch()`. - -@section BufferedTexture-performance-optimization Performance optimizations -If extension @extension{EXT,direct_state_access} is available, setBuffer() -uses DSA function to avoid unnecessary calls to @fn_gl{ActiveTexture} and -@fn_gl{BindTexture}. See @ref AbstractTexture-performance-optimization -"relevant section in AbstractTexture documentation" and respective function -documentation for more information. - -@requires_gl31 Extension @extension{ARB,texture_buffer_object} -@requires_gl Texture buffers are not available in OpenGL ES. -*/ -class MAGNUM_EXPORT BufferedTexture: private AbstractTexture { - friend class Context; - - BufferedTexture(const BufferedTexture& other) = delete; - BufferedTexture(BufferedTexture&& other) = delete; - BufferedTexture& operator=(const BufferedTexture& other) = delete; - BufferedTexture& operator=(BufferedTexture&& other) = delete; - - public: - /** @{ @name Internal buffered texture formats */ - - /** - * @copybrief AbstractTexture::Components - * - * Like AbstractTexture::Components, without three-component RGB. - */ - enum class Components { - Red, RedGreen, RGBA - }; - - /** - * @copybrief AbstractTexture::ComponentType - * - * Like AbstractTexture::ComponentType, without normalized signed - * types. - */ - enum class ComponentType { - UnsignedByte, Byte, UnsignedShort, Short, UnsignedInt, Int, Half, - Float, NormalizedUnsignedByte, NormalizedUnsignedShort - }; - - /** @copybrief AbstractTexture::Format */ - enum class Format: GLenum { - /** - * Three-component RGB, float, each component 32bit, 96bit total. - * - * @requires_gl40 Extension @extension{ARB,texture_buffer_object_rgb32} - */ - RGB32Float = GL_RGB32F, - - /** - * Three-component RGB, unsigned non-normalized, each component - * 32bit, 96bit total. - * - * @requires_gl40 Extension @extension{ARB,texture_buffer_object_rgb32} - */ - RGB32UnsignedInt = GL_RGB32UI, - - /** - * Three-component RGB, signed non-normalized, each component - * 32bit, 96bit total. - * - * @requires_gl40 Extension @extension{ARB,texture_buffer_object_rgb32} - */ - RGB32Int = GL_RGB32I - }; - - /** @copydoc AbstractTexture::InternalFormat */ - class MAGNUM_EXPORT InternalFormat { - public: - /** @copybrief AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components, AbstractTexture::ComponentType) */ - InternalFormat(Components components, ComponentType type); - - /** @copydoc AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Format) */ - inline constexpr InternalFormat(Format format): internalFormat(static_cast(format)) {} - - /** - * @brief OpenGL internal format ID - * - * @todoc Remove workaround when Doxygen supports \@copydoc for conversion operators - */ - inline constexpr operator GLint() const { return internalFormat; } - - private: - GLint internalFormat; - }; - - /*@}*/ - - inline BufferedTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {} - - /** @copydoc AbstractTexture::bind() */ - inline void bind(GLint layer) { AbstractTexture::bind(layer); } - - /** - * @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); - } - - private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); - - typedef void(BufferedTexture::*SetBufferImplementation)(InternalFormat, Buffer*); - void MAGNUM_LOCAL setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer); - void MAGNUM_LOCAL setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer); - static SetBufferImplementation setBufferImplementation; -}; - -/** @relates BufferedTexture -@brief Convertor of component count and data type to InternalFormat -*/ -inline BufferedTexture::InternalFormat operator|(BufferedTexture::Components components, BufferedTexture::ComponentType type) { - return BufferedTexture::InternalFormat(components, type); -} -/** @relates BufferedTexture - * @overload - */ -inline BufferedTexture::InternalFormat operator|(BufferedTexture::ComponentType type, BufferedTexture::Components components) { - return BufferedTexture::InternalFormat(components, type); -} - -} -#endif - -#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7e06f1f2f..704b6d1a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,159 +1,167 @@ -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wold-style-cast -Winit-self -pedantic -std=c++0x -fvisibility=hidden") - -# Disable strict aliasing for GCC 4.4, as it breaks RectangularMatrix::from() -# (and I have no better solution for that yet) -if(CORRADE_GCC44_COMPATIBILITY) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") -endif() - -# -Wdouble-promotion is supported from GCC 4.6 -# TODO: do this with check_c_compiler_flags() -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.6.0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion") -endif() +# +# 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. +# + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CORRADE_CXX_FLAGS}") +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CORRADE_INCLUDE_DIR}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magnumConfigure.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/magnumConfigure.h) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CORRADE_INCLUDE_DIR}) - # Files shared between main library and unit test library set(Magnum_SRCS + AbstractFramebuffer.cpp AbstractImage.cpp AbstractTexture.cpp AbstractShaderProgram.cpp Buffer.cpp Context.cpp DebugMarker.cpp + DefaultFramebuffer.cpp Framebuffer.cpp Image.cpp - IndexedMesh.cpp Mesh.cpp - Profiler.cpp + OpenGL.cpp Query.cpp Renderbuffer.cpp Resource.cpp Shader.cpp - SizeTraits.cpp Timeline.cpp - TypeTraits.cpp Implementation/BufferState.cpp Implementation/State.cpp Trade/AbstractImporter.cpp Trade/MeshData2D.cpp - Trade/MeshData3D.cpp) + Trade/MeshData3D.cpp + Trade/ObjectData2D.cpp + Trade/ObjectData3D.cpp) # Desktop-only code if(NOT TARGET_GLES) set(Magnum_SRCS ${Magnum_SRCS} - BufferedTexture.cpp) + BufferTexture.cpp) endif() # Not-ES2 code if(NOT TARGET_GLES2) set(Magnum_SRCS ${Magnum_SRCS} - BufferedImage.cpp) + BufferImage.cpp) endif() set(Magnum_HEADERS + AbstractFramebuffer.h AbstractImage.h AbstractResourceLoader.h AbstractShaderProgram.h AbstractTexture.h + Array.h Buffer.h Color.h Context.h CubeMapTexture.h DebugMarker.h + DefaultFramebuffer.h DimensionTraits.h Extensions.h Framebuffer.h Image.h ImageWrapper.h - IndexedMesh.h Magnum.h Mesh.h - Profiler.h + OpenGL.h Query.h Renderbuffer.h + Renderer.h Resource.h ResourceManager.h Shader.h - SizeTraits.h Swizzle.h Texture.h Timeline.h - TypeTraits.h + Types.h magnumVisibility.h) # Desktop-only headers if(NOT TARGET_GLES) set(Magnum_HEADERS ${Magnum_HEADERS} - BufferedTexture.h + BufferTexture.h CubeMapTextureArray.h) endif() # Not-ES2 headers if(NOT TARGET_GLES2) set(Magnum_HEADERS ${Magnum_HEADERS} - BufferedImage.h) -endif() - -if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(MagnumObjects OBJECT ${Magnum_SRCS}) + BufferImage.h) endif() # Files shared between main library and math unit test library set(MagnumMath_SRCS - Math/Math.cpp + Math/Angle.cpp + Math/Complex.cpp + Math/DualComplex.cpp + Math/DualQuaternion.cpp + Math/Functions.cpp + Math/Quaternion.cpp Math/RectangularMatrix.cpp Math/Vector.cpp) -if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS}) -endif() # 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 -if(NOT CMAKE_NO_OBJECT_TARGET) - set_target_properties(MagnumObjects MagnumMathObjects PROPERTIES COMPILE_FLAGS "-DMagnumObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") -endif() +add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS}) +add_library(MagnumObjects OBJECT ${Magnum_SRCS}) +set_target_properties(MagnumObjects MagnumMathObjects PROPERTIES COMPILE_FLAGS "-DMagnumObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") # Main library -if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(Magnum SHARED - $ - $) -else() - add_library(Magnum SHARED - ${Magnum_SRCS} - ${MagnumMath_SRCS}) -endif() +add_library(Magnum SHARED + $ + $) set(Magnum_LIBS ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY}) -if(NOT TARGET_GLES) - set(Magnum_LIBS ${Magnum_LIBS} - ${OPENGL_gl_LIBRARY} - ${GLEW_LIBRARY}) +if(NOT TARGET_GLES OR TARGET_DESKTOP_GLES) + set(Magnum_LIBS ${Magnum_LIBS} ${OPENGL_gl_LIBRARY}) else() - set(Magnum_LIBS ${Magnum_LIBS} - ${OPENGLES2_LIBRARY}) + set(Magnum_LIBS ${Magnum_LIBS} ${OPENGLES2_LIBRARY}) +endif() +if(NOT TARGET_GLES) + set(Magnum_LIBS ${Magnum_LIBS} ${GLEW_LIBRARIES}) endif() target_link_libraries(Magnum ${Magnum_LIBS}) install(TARGETS Magnum DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${Magnum_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}) - -# Install also configure file install(FILES ${CMAKE_CURRENT_BINARY_DIR}/magnumConfigure.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}) -add_subdirectory(Platform) add_subdirectory(Math) +add_subdirectory(Platform) add_subdirectory(Trade) +if(WITH_DEBUGTOOLS) + add_subdirectory(DebugTools) +endif() + if(WITH_MESHTOOLS) add_subdirectory(MeshTools) endif() @@ -174,26 +182,27 @@ if(WITH_SHADERS) add_subdirectory(Shaders) endif() +if(WITH_TEXT) + add_subdirectory(Text) +endif() + +if(WITH_TEXTURETOOLS) + add_subdirectory(TextureTools) +endif() + if(BUILD_TESTS) - enable_testing() - - # Library with graceful assert for testing - if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(MagnumMathTestLib SHARED - $) - - add_library(MagnumTestLib SHARED - $ - $) - else() - add_library(MagnumMathTestLib SHARED - ${MagnumMath_SRCS}) - - add_library(MagnumTestLib SHARED - ${Magnum_SRCS} - ${MagnumMath_SRCS}) + # Libraries with graceful assert for testing + add_library(MagnumMathTestLib SHARED + $) + set_target_properties(MagnumMathTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) + if(WIN32) + target_link_libraries(MagnumMathTestLib ${CORRADE_UTILITY_LIBRARY}) endif() - set_target_properties(MagnumTestLib MagnumMathTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) + + add_library(MagnumTestLib SHARED + $ + $) + set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) target_link_libraries(MagnumTestLib ${Magnum_LIBS}) add_subdirectory(Test) diff --git a/src/Color.h b/src/Color.h index 300fa549a..74b634d84 100644 --- a/src/Color.h +++ b/src/Color.h @@ -1,18 +1,27 @@ #ifndef Magnum_Color_h #define Magnum_Color_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,8 +30,7 @@ #include -#include "Math/MathTypeTraits.h" -#include "Math/Math.h" +#include "Math/Functions.h" #include "Math/Vector4.h" #include "Magnum.h" @@ -33,15 +41,16 @@ namespace Implementation { /* Convert color from HSV */ template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { - T hue, saturation, value; + Math::Deg hue; + T saturation, value; std::tie(hue, saturation, value) = hsv; /* Remove repeats */ - hue -= int(hue/T(360))*T(360); - if(hue < T(0)) hue += T(360); + hue -= int(T(hue)/T(360))*Math::Deg(360); + if(hue < Math::Deg(0)) hue += Math::Deg(360); - int h = int(hue/T(60)) % 6; - T f = hue/T(60) - h; + int h = int(T(hue)/T(60)) % 6; + T f = T(hue)/T(60) - h; T p = value * (T(1) - saturation); T q = value * (T(1) - f*saturation); @@ -54,16 +63,15 @@ template inline typename std::enable_if::valu case 3: return {p, q, value}; case 4: return {t, p, value}; case 5: return {value, p, q}; - default: - CORRADE_ASSERT(false, "It shouldn't get here.", {}); + default: CORRADE_INTERNAL_ASSERT(false); } } template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { - return Color3::fromNormalized(fromHSV::FloatingPointType>(hsv)); + return Math::denormalize>(fromHSV::FloatingPointType>(hsv)); } /* Internal hue computing function */ -template T hue(const Color3& color, T max, T delta) { +template Math::Deg hue(const Color3& color, T max, T delta) { T deltaInv60 = T(60)/delta; T hue(0); @@ -76,11 +84,11 @@ template T hue(const Color3& color, T max, T delta) { hue = (color.r()-color.g())*deltaInv60 + T(240); } - return hue; + return Math::Deg(hue); } /* Hue, saturation, value for floating-point types */ -template inline T hue(typename std::enable_if::value, const Color3&>::type color) { +template inline Math::Deg hue(typename std::enable_if::value, const Color3&>::type color) { T max = color.max(); T delta = max - color.min(); return hue(color, max, delta); @@ -95,11 +103,11 @@ template inline T value(typename std::enable_if inline typename Color3::FloatingPointType hue(typename std::enable_if::value, const Color3&>::type color) { - return hue::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); +template inline Math::Deg::FloatingPointType> hue(typename std::enable_if::value, const Color3&>::type color) { + return hue::FloatingPointType>(Math::normalize::FloatingPointType>>(color)); } template inline typename Color3::FloatingPointType saturation(typename std::enable_if::value, const Color3&>::type& color) { - return saturation::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); + return saturation::FloatingPointType>(Math::normalize::FloatingPointType>>(color)); } template inline typename Color3::FloatingPointType value(typename std::enable_if::value, const Color3&>::type color) { return Math::normalize::FloatingPointType>(color.max()); @@ -113,7 +121,7 @@ template inline typename Color3::HSV toHSV(typename std::enable_if::HSV(hue::FloatingPointType>(color, max, delta), max != T(0) ? delta/max : T(0), max); } template inline typename Color3::HSV toHSV(typename std::enable_if::value, const Color3&>::type color) { - return toHSV::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); + return toHSV::FloatingPointType>(Math::normalize::FloatingPointType>>(color)); } /* Default alpha value */ @@ -139,21 +147,18 @@ is always in range in range @f$ [0.0, 360.0] @f$, saturation and value in range @f$ [0.0, 1.0] @f$. @see Color4 - -@todo Hue in degrees so users can use deg() -@todo Signed normalization to [-1.0, 1.0] like in OpenGL? */ /* Not using template specialization because some internal functions are impossible to explicitly instantiate */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class Color3: public Math::Vector3 { public: /** @brief Corresponding floating-point type for HSV computation */ - typedef typename Math::MathTypeTraits::FloatingPointType FloatingPointType; + typedef typename Math::TypeTraits::FloatingPointType FloatingPointType; /** * @brief Type for storing HSV values @@ -161,37 +166,7 @@ class Color3: public Math::Vector3 { * Hue in range @f$ [0.0, 360.0] @f$, saturation and value in * range @f$ [0.0, 1.0] @f$. */ - typedef std::tuple HSV; - - /** - * @brief Create integral color from floating-point color - * - * E.g. `{0.294118, 0.45098, 0.878431}` is converted to - * `{75, 115, 224}`, if resulting type is `uint8_t`. - * - * @note This function is enabled only if source type is floating-point - * and destination type is integral. - */ - template inline constexpr static typename std::enable_if::value && std::is_floating_point::value, Color3>::type fromNormalized(const Color3& color) { - return Color3(Math::denormalize(color.r()), - Math::denormalize(color.g()), - Math::denormalize(color.b())); - } - - /** - * @brief Create floating-point color from integral color - * - * E.g. `{75, 115, 224}` is converted to - * `{0.294118, 0.45098, 0.878431}`, if source type is `uint8_t`. - * - * @note This function is enabled only if source type is integral - * and destination type is floating-point. - */ - template inline constexpr static typename std::enable_if::value && std::is_integral::value, Color3>::type fromDenormalized(const Color3& color) { - return Color3(Math::normalize(color.r()), - Math::normalize(color.g()), - Math::normalize(color.b())); - } + typedef std::tuple, FloatingPointType, FloatingPointType> HSV; /** * @brief Create RGB color from HSV representation @@ -203,7 +178,7 @@ class Color3: public Math::Vector3 { return Implementation::fromHSV(hsv); } /** @overload */ - inline constexpr static Color3 fromHSV(FloatingPointType hue, FloatingPointType saturation, FloatingPointType value) { + inline constexpr static Color3 fromHSV(Math::Deg hue, FloatingPointType saturation, FloatingPointType value) { return fromHSV(std::make_tuple(hue, saturation, value)); } @@ -212,7 +187,7 @@ class Color3: public Math::Vector3 { * * All components are set to zero. */ - inline constexpr Color3() {} + inline constexpr /*implicit*/ Color3() {} /** * @brief Gray constructor @@ -220,16 +195,19 @@ class Color3: public Math::Vector3 { */ inline constexpr explicit Color3(T rgb): Math::Vector3(rgb) {} - /** @brief Copy constructor */ - inline constexpr Color3(const Math::RectangularMatrix<1, 3, T>& other): Math::Vector3(other) {} - /** * @brief Constructor * @param r R value * @param g G value * @param b B value */ - inline constexpr Color3(T r, T g, T b): Math::Vector3(r, g, b) {} + inline 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) {} + + /** @brief Copy constructor */ + inline 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 */ @@ -259,8 +237,8 @@ class Color3: public Math::Vector3 { * * @see saturation(), value(), toHSV(), fromHSV() */ - inline constexpr FloatingPointType hue() const { - return Implementation::hue(*this); + inline constexpr Math::Deg hue() const { + return Math::Deg(Implementation::hue(*this)); } /** @@ -284,7 +262,6 @@ class Color3: public Math::Vector3 { } MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color3, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Color3) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color3, 3) @@ -299,7 +276,7 @@ See Color3 for more information. #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class Color4: public Math::Vector4 { public: @@ -309,22 +286,6 @@ class Color4: public Math::Vector4 { /** @copydoc Color3::HSV */ typedef typename Color3::HSV HSV; - /** @copydoc Color3::fromNormalized() */ - template inline constexpr static typename std::enable_if::value && std::is_floating_point::value, Color4>::type fromNormalized(const Color4& color) { - return Color4(Math::denormalize(color.r()), - Math::denormalize(color.g()), - Math::denormalize(color.b()), - Math::denormalize(color.a())); - } - - /** @copydoc Color3::fromDenormalized() */ - template inline constexpr static typename std::enable_if::value && std::is_integral::value, Color4>::type fromDenormalized(const Color4& color) { - return Color4(Math::normalize(color.r()), - Math::normalize(color.g()), - Math::normalize(color.b()), - Math::normalize(color.a())); - } - /** * @copydoc Color3::fromHSV() * @param a Alpha value, defaults to 1.0 for floating-point types @@ -334,7 +295,7 @@ class Color4: public Math::Vector4 { return Color4(Implementation::fromHSV(hsv), a); } /** @overload */ - inline constexpr static Color4 fromHSV(FloatingPointType hue, FloatingPointType saturation, FloatingPointType value, T alpha) { + inline constexpr static Color4 fromHSV(Math::Deg hue, FloatingPointType saturation, FloatingPointType value, T alpha) { return fromHSV(std::make_tuple(hue, saturation, value), alpha); } @@ -344,7 +305,7 @@ 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 Color4(): Math::Vector4(T(0), T(0), T(0), Implementation::defaultAlpha()) {} + inline constexpr /*implicit*/ Color4(): Math::Vector4(T(0), T(0), T(0), Implementation::defaultAlpha()) {} /** * @copydoc Color3::Color3(T) @@ -353,9 +314,6 @@ class Color4: public Math::Vector4 { */ inline constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha()): Math::Vector4(rgb, rgb, rgb, alpha) {} - /** @brief Copy constructor */ - inline constexpr Color4(const Math::RectangularMatrix<1, 4, T>& other): Math::Vector4(other) {} - /** * @brief Constructor * @param r R value @@ -364,7 +322,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 Color4(T r, T g, T b, T a = Implementation::defaultAlpha()): Math::Vector4(r, g, b, a) {} + inline constexpr /*implicit*/ Color4(T r, T g, T b, T a = Implementation::defaultAlpha()): Math::Vector4(r, g, b, a) {} /** * @brief Constructor @@ -373,7 +331,13 @@ 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 Color4(const Math::Vector3& rgb, T a = Implementation::defaultAlpha()): Math::Vector4(rgb[0], rgb[1], rgb[2], a) {} + inline 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) {} + + /** @brief Copy constructor */ + inline 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 */ @@ -399,7 +363,7 @@ class Color4: public Math::Vector4 { } /** @copydoc Color3::hue() */ - inline constexpr FloatingPointType hue() const { + inline constexpr Math::Deg hue() const { return Implementation::hue(rgb()); } @@ -414,18 +378,17 @@ class Color4: public Math::Vector4 { } MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color4, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Color4) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4) /** @debugoperator{Magnum::Color3} */ -template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Color3& value) { +template inline Debug operator<<(Debug debug, const Color3& value) { return debug << static_cast&>(value); } /** @debugoperator{Magnum::Color4} */ -template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Color4& value) { +template inline Debug operator<<(Debug debug, const Color4& value) { return debug << static_cast&>(value); } diff --git a/src/Context.cpp b/src/Context.cpp index a47c68915..6f2284402 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Context.h" @@ -20,17 +29,19 @@ #include #include +#include "AbstractFramebuffer.h" #include "AbstractShaderProgram.h" #include "AbstractTexture.h" #include "Buffer.h" -#include "BufferedTexture.h" +#include "BufferTexture.h" +#include "DebugMarker.h" +#include "DefaultFramebuffer.h" #include "Extensions.h" -#include "IndexedMesh.h" +#include "Framebuffer.h" #include "Mesh.h" -#include "Implementation/State.h" -#include "DebugMarker.h" +#include "Renderbuffer.h" -using namespace std; +#include "Implementation/State.h" namespace Magnum { @@ -66,103 +77,173 @@ const std::vector& Extension::extensions(Version version) { static const std::vector empty; #ifndef MAGNUM_TARGET_GLES static const std::vector extensions{ - _extension(GL,AMD,vertex_shader_layer), - _extension(GL,AMD,shader_trinary_minmax), - _extension(GL,EXT,texture_filter_anisotropic), + _extension(GL,AMD,vertex_shader_layer), // done + _extension(GL,AMD,shader_trinary_minmax), // done + _extension(GL,EXT,texture_filter_anisotropic), // done _extension(GL,EXT,direct_state_access), - _extension(GL,GREMEDY,string_marker)}; + _extension(GL,GREMEDY,string_marker)}; // done static const std::vector extensions300{ - _extension(GL,APPLE,flush_buffer_range), - _extension(GL,APPLE,vertex_array_object), + /** + * @todo Remove as it doesn't have all functionality present in GL 3.0 + * and leave only ARB_map_buffer_range? + */ + _extension(GL,APPLE,flush_buffer_range), // done + _extension(GL,APPLE,vertex_array_object), // done + _extension(GL,ARB,map_buffer_range), // done, replaces APPLE_flush_buffer_range _extension(GL,ARB,color_buffer_float), - _extension(GL,ARB,half_float_pixel), - _extension(GL,ARB,texture_float), - _extension(GL,ARB,depth_buffer_float), - _extension(GL,ARB,texture_rg), + _extension(GL,ARB,half_float_pixel), // done + _extension(GL,ARB,texture_float), // done + _extension(GL,ARB,depth_buffer_float), // done + _extension(GL,ARB,texture_rg), // done + /** + * @todo Remove as it doesn't have the same functionality present in + * GL 3.0 and replace with ARB_framebuffer_object? + */ _extension(GL,EXT,framebuffer_object), - _extension(GL,EXT,packed_depth_stencil), - _extension(GL,EXT,framebuffer_blit), + _extension(GL,EXT,packed_depth_stencil), // done + _extension(GL,EXT,framebuffer_blit), // done _extension(GL,EXT,framebuffer_multisample), _extension(GL,EXT,gpu_shader4), - _extension(GL,EXT,packed_float), + _extension(GL,EXT,packed_float), // done _extension(GL,EXT,texture_array), - _extension(GL,EXT,texture_compression_rgtc), - _extension(GL,EXT,texture_shared_exponent), + _extension(GL,EXT,texture_compression_rgtc), // done + _extension(GL,EXT,texture_shared_exponent), // done _extension(GL,EXT,framebuffer_sRGB), _extension(GL,EXT,draw_buffers2), _extension(GL,EXT,texture_integer), _extension(GL,EXT,transform_feedback), - _extension(GL,NV,half_float), + _extension(GL,NV,half_float), // done _extension(GL,NV,depth_buffer_float), - _extension(GL,NV,conditional_render)}; + _extension(GL,NV,conditional_render)}; // done static const std::vector extensions310{ _extension(GL,ARB,texture_rectangle), _extension(GL,ARB,draw_instanced), _extension(GL,ARB,texture_buffer_object), _extension(GL,ARB,uniform_buffer_object), - _extension(GL,ARB,copy_buffer), - _extension(GL,EXT,texture_snorm), + _extension(GL,ARB,copy_buffer), // done + _extension(GL,EXT,texture_snorm), // done _extension(GL,NV,primitive_restart)}; static const std::vector extensions320{ _extension(GL,ARB,geometry_shader4), - _extension(GL,ARB,depth_clamp), + _extension(GL,ARB,depth_clamp), // done _extension(GL,ARB,draw_elements_base_vertex), - _extension(GL,ARB,fragment_coord_conventions), - _extension(GL,ARB,provoking_vertex), - _extension(GL,ARB,seamless_cube_map), + _extension(GL,ARB,fragment_coord_conventions), // done + _extension(GL,ARB,provoking_vertex), // done + _extension(GL,ARB,seamless_cube_map), // done _extension(GL,ARB,sync), _extension(GL,ARB,texture_multisample), - _extension(GL,ARB,vertex_array_bgra)}; + _extension(GL,ARB,vertex_array_bgra)}; // done static const std::vector extensions330{ _extension(GL,ARB,instanced_arrays), _extension(GL,ARB,blend_func_extended), - _extension(GL,ARB,explicit_attrib_location), - _extension(GL,ARB,occlusion_query2), + _extension(GL,ARB,explicit_attrib_location), // done + _extension(GL,ARB,occlusion_query2), // done _extension(GL,ARB,sampler_objects), - _extension(GL,ARB,shader_bit_encoding), - _extension(GL,ARB,texture_rgb10_a2ui), + _extension(GL,ARB,shader_bit_encoding), // done + _extension(GL,ARB,texture_rgb10_a2ui), // done _extension(GL,ARB,texture_swizzle), _extension(GL,ARB,timer_query), - _extension(GL,ARB,vertex_type_2_10_10_10_rev)}; + _extension(GL,ARB,vertex_type_2_10_10_10_rev)}; // done static const std::vector extensions400{ _extension(GL,ARB,draw_buffers_blend), _extension(GL,ARB,sample_shading), - _extension(GL,ARB,texture_cube_map_array), + _extension(GL,ARB,texture_cube_map_array), // done _extension(GL,ARB,texture_gather), - _extension(GL,ARB,texture_query_lod), + _extension(GL,ARB,texture_query_lod), // done _extension(GL,ARB,draw_indirect), _extension(GL,ARB,gpu_shader5), - _extension(GL,ARB,gpu_shader_fp64), + _extension(GL,ARB,gpu_shader_fp64), // done _extension(GL,ARB,shader_subroutine), _extension(GL,ARB,tessellation_shader), - _extension(GL,ARB,texture_buffer_object_rgb32), + _extension(GL,ARB,texture_buffer_object_rgb32), // done _extension(GL,ARB,transform_feedback2), _extension(GL,ARB,transform_feedback3)}; static const std::vector extensions410{ _extension(GL,ARB,ES2_compatibility), _extension(GL,ARB,get_program_binary), _extension(GL,ARB,separate_shader_objects), - _extension(GL,ARB,shader_precision), - _extension(GL,ARB,vertex_attrib_64bit), + _extension(GL,ARB,shader_precision), // done + _extension(GL,ARB,vertex_attrib_64bit), // done _extension(GL,ARB,viewport_array)}; static const std::vector extensions420{ - _extension(GL,ARB,texture_compression_bptc), + _extension(GL,ARB,texture_compression_bptc), // done _extension(GL,ARB,base_instance), - _extension(GL,ARB,shading_language_420pack), + _extension(GL,ARB,shading_language_420pack), // done _extension(GL,ARB,transform_feedback_instanced), _extension(GL,ARB,compressed_texture_pixel_storage), - _extension(GL,ARB,conservative_depth), + _extension(GL,ARB,conservative_depth), // done _extension(GL,ARB,internalformat_query), _extension(GL,ARB,map_buffer_alignment), _extension(GL,ARB,shader_atomic_counters), _extension(GL,ARB,shader_image_load_store), _extension(GL,ARB,texture_storage)}; - static const std::vector extensions430; + static const std::vector extensions430{ + _extension(GL,ARB,arrays_of_arrays), // done + _extension(GL,ARB,ES3_compatibility), + _extension(GL,ARB,clear_buffer_object), + _extension(GL,ARB,compute_shader), + _extension(GL,ARB,copy_image), + _extension(GL,KHR,debug), + _extension(GL,ARB,explicit_uniform_location), + _extension(GL,ARB,fragment_layer_viewport), // done + _extension(GL,ARB,framebuffer_no_attachments), + _extension(GL,ARB,internalformat_query2), + _extension(GL,ARB,invalidate_subdata), // done + _extension(GL,ARB,multi_draw_indirect), + _extension(GL,ARB,program_interface_query), + _extension(GL,ARB,robust_buffer_access_behavior), // done + _extension(GL,ARB,shader_image_size), // done + _extension(GL,ARB,shader_storage_buffer_object), + _extension(GL,ARB,stencil_texturing), + _extension(GL,ARB,texture_buffer_range), // done + _extension(GL,ARB,texture_query_levels), // done + _extension(GL,ARB,texture_storage_multisample), + _extension(GL,ARB,texture_view), + _extension(GL,ARB,vertex_attrib_binding)}; #undef _extension #else - static const std::vector extensions; - static const std::vector extensionsES200; - static const std::vector extensionsES300; + static const std::vector extensions{ + _extension(GL,APPLE,texture_format_BGRA8888), + _extension(GL,EXT,texture_filter_anisotropic), + _extension(GL,EXT,texture_format_BGRA8888), + _extension(GL,EXT,read_format_bgra), + _extension(GL,EXT,debug_marker), + _extension(GL,EXT,separate_shader_objects), + _extension(GL,EXT,sRGB), + _extension(GL,NV,read_buffer_front), + _extension(GL,NV,read_stencil), + _extension(GL,OES,depth32), + _extension(GL,OES,mapbuffer), + _extension(GL,OES,stencil1), + _extension(GL,OES,stencil4), + _extension(GL,OES,texture_3D)}; + static const std::vector extensionsES300{ + _extension(GL,ANGLE,framebuffer_blit), + _extension(GL,APPLE,framebuffer_multisample), + _extension(GL,ARM,rgba8), + _extension(GL,EXT,texture_type_2_10_10_10_REV), + _extension(GL,EXT,discard_framebuffer), + _extension(GL,EXT,blend_minmax), + _extension(GL,EXT,occlusion_query_boolean), + _extension(GL,EXT,texture_rg), + _extension(GL,EXT,texture_storage), + _extension(GL,EXT,map_buffer_range), + _extension(GL,NV,draw_buffers), + _extension(GL,NV,read_buffer), + _extension(GL,NV,read_depth), + _extension(GL,NV,read_depth_stencil), + _extension(GL,OES,depth24), + _extension(GL,OES,element_index_uint), + _extension(GL,OES,rgb8_rgba8), + _extension(GL,OES,texture_half_float_linear), + _extension(GL,OES,texture_float_linear), + _extension(GL,OES,texture_half_float), + _extension(GL,OES,texture_float), + _extension(GL,OES,vertex_half_float), + _extension(GL,OES,packed_depth_stencil), + _extension(GL,OES,depth_texture), + _extension(GL,OES,vertex_array_object), + _extension(GL,OES,required_internalformat)}; #endif switch(version) { @@ -180,7 +261,7 @@ const std::vector& Extension::extensions(Version version) { /* case Version::GLES300: */ case Version::GL430: return extensions430; #else - case Version::GLES200: return extensionsES200; + case Version::GLES200: return empty; case Version::GLES300: return extensionsES300; #endif } @@ -202,7 +283,7 @@ Context::Context() { _version = static_cast(_majorVersion*100+_minorVersion*10); /* Get first future (not supported) version */ - vector versions{ + std::vector versions{ #ifndef MAGNUM_TARGET_GLES Version::GL300, Version::GL310, @@ -218,18 +299,18 @@ Context::Context() { #endif Version::None }; - size_t future = 0; - while(versions[future] != Version::None && !isVersionSupported(_version)) + std::size_t future = 0; + while(versions[future] != Version::None && isVersionSupported(versions[future])) ++future; /* List of extensions from future versions (extensions from current and previous versions should be supported automatically, so we don't need to check for them) */ - unordered_map futureExtensions; - for(size_t i = future; i != versions.size(); ++i) { + std::unordered_map futureExtensions; + for(std::size_t i = future; i != versions.size(); ++i) { const std::vector& extensions = Extension::extensions(versions[i]); for(auto it = extensions.begin(); it != extensions.end(); ++it) - futureExtensions.insert(make_pair(it->_string, *it)); + futureExtensions.insert(std::make_pair(it->_string, *it)); } /* Check for presence of extensions in future versions */ @@ -255,7 +336,7 @@ Context::Context() { /* Don't crash when glGetString() returns nullptr */ const char* e = reinterpret_cast(glGetString(GL_EXTENSIONS)); if(e) { - vector extensions = Corrade::Utility::String::split(e, ' '); + std::vector extensions = Corrade::Utility::String::split(e, ' '); for(auto it = extensions.begin(); it != extensions.end(); ++it) { auto found = futureExtensions.find(*it); if(found != futureExtensions.end()) { @@ -274,15 +355,18 @@ Context::Context() { _state = new Implementation::State; /* Initialize functionality based on current OpenGL version and extensions */ + AbstractFramebuffer::initializeContextBasedFunctionality(this); AbstractShaderProgram::initializeContextBasedFunctionality(this); AbstractTexture::initializeContextBasedFunctionality(this); Buffer::initializeContextBasedFunctionality(this); #ifndef MAGNUM_TARGET_GLES - BufferedTexture::initializeContextBasedFunctionality(this); + BufferTexture::initializeContextBasedFunctionality(this); #endif DebugMarker::initializeContextBasedFunctionality(this); - IndexedMesh::initializeContextBasedFunctionality(this); + DefaultFramebuffer::initializeContextBasedFunctionality(this); + Framebuffer::initializeContextBasedFunctionality(this); Mesh::initializeContextBasedFunctionality(this); + Renderbuffer::initializeContextBasedFunctionality(this); } Context::~Context() { @@ -291,7 +375,7 @@ Context::~Context() { _current = nullptr; } -Version Context::supportedVersion(initializer_list versions) const { +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 a5669b81d..ce52c4e13 100644 --- a/src/Context.h +++ b/src/Context.h @@ -1,36 +1,45 @@ #ifndef Magnum_Context_h #define Magnum_Context_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 Version, class Magnum::Context, Magnum::Extension, macro MAGNUM_ASSERT_VERSION_SUPPORTED(), MAGNUM_ASSERT_EXTENSION_SUPPORTED() + * @brief Enum Magnum::Version, class Magnum::Context, Magnum::Extension, macro MAGNUM_ASSERT_VERSION_SUPPORTED(), MAGNUM_ASSERT_EXTENSION_SUPPORTED() */ #include #include #include "Magnum.h" - +#include "OpenGL.h" #include "magnumVisibility.h" namespace Magnum { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - class State; + struct State; } #endif @@ -39,7 +48,7 @@ namespace Implementation { @see Context, MAGNUM_ASSERT_VERSION_SUPPORTED() */ -enum class Version: GLint { +enum class Version: Int { None = 0xFFFF, /**< @brief Unspecified */ #ifndef MAGNUM_TARGET_GLES GL210 = 210, /**< @brief OpenGL 2.1 / GLSL 1.20 */ @@ -123,7 +132,12 @@ class MAGNUM_EXPORT Extension { /** @brief OpenGL context -Provides access to version and extension information. +Provides access to version and extension information. Instance available +through Context::current() is automatically created during construction of +*Application classes in Platform namespace so you can safely assume that the +instance is available during whole lifetime of *Application object. +@todo @extension{ATI,meminfo}, @extension{NVX,gpu_memory_info}, GPU temperature? + (here or where?) */ class MAGNUM_EXPORT Context { Context(const Context&) = delete; @@ -135,10 +149,13 @@ class MAGNUM_EXPORT Context { /** * @brief Constructor * + * Constructed automatically, see class documentation for more + * information. * @see @fn_gl{Get} with @def_gl{MAJOR_VERSION}, @def_gl{MINOR_VERSION}, * @fn_gl{GetString} with @def_gl{EXTENSIONS} */ - Context(); + explicit Context(); + ~Context(); /** @brief Current context */ @@ -158,7 +175,7 @@ class MAGNUM_EXPORT Context { * @see minorVersion(), version(), versionString(), * shadingLanguageVersionString() */ - inline GLint majorVersion() const { return _majorVersion; } + inline Int majorVersion() const { return _majorVersion; } /** * @brief Minor OpenGL version (e.g. `3`) @@ -166,7 +183,7 @@ class MAGNUM_EXPORT Context { * @see majorVersion(), version(), versionString(), * shadingLanguageVersionString() */ - inline GLint minorVersion() const { return _minorVersion; } + inline Int minorVersion() const { return _minorVersion; } /** * @brief Vendor string @@ -178,7 +195,7 @@ class MAGNUM_EXPORT Context { } /** - * @brief Renderer string + * @brief %Renderer string * * @see vendorString(), @fn_gl{GetString} with @def_gl{RENDERER} */ @@ -289,8 +306,8 @@ class MAGNUM_EXPORT Context { static Context* _current; Version _version; - GLint _majorVersion; - GLint _minorVersion; + Int _majorVersion; + Int _minorVersion; std::bitset<128> extensionStatus; std::vector _supportedExtensions; @@ -322,7 +339,7 @@ MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); do { \ if(!Context::current()->isVersionSupported(version)) { \ Corrade::Utility::Error() << "Magnum: required version" << version << "is not supported"; \ - exit(-3); \ + std::exit(-3); \ } \ } while(0) #endif @@ -352,7 +369,7 @@ MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); do { \ if(!Context::current()->isExtensionSupported()) { \ Corrade::Utility::Error() << "Magnum: required extension" << extension::string() << "is not supported"; \ - exit(-3); \ + std::exit(-3); \ } \ } while(0) #endif diff --git a/src/CubeMapTexture.h b/src/CubeMapTexture.h index 5141f0a24..64d72cc99 100644 --- a/src/CubeMapTexture.h +++ b/src/CubeMapTexture.h @@ -1,35 +1,43 @@ #ifndef Magnum_CubeMapTexture_h #define Magnum_CubeMapTexture_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::CubeMapTexture */ -#include "Texture.h" +#include "AbstractTexture.h" namespace Magnum { /** @brief Cube map texture -%Texture used mainly for environemnt maps. See AbstractTexture documentation -for more information. It consists of 6 square textures generating 6 faces of -the cube as following. Note that all images must be turned upside down (+Y is -top): +%Texture used mainly for environment maps. It consists of 6 square textures +generating 6 faces of the cube as following. Note that all images must be +turned upside down (+Y is top): +----+ | -Y | @@ -39,11 +47,30 @@ top): | +Y | +----+ -When using cube map texture in the shader, use `samplerCube`. Unlike 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. +@section CubeMapTexture-usage Basic usage + +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); +// ... -See AbstractTexture documentation for more information about usage. +CubeMapTexture texture; +texture.setMagnificationFilter(Texture2D::Filter::Linear) + // ... + ->setStorage(Math::log2(256)+1, Texture2D::Format::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 */ @@ -65,7 +92,7 @@ class CubeMapTexture: public AbstractTexture { * * 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_gl32 %Extension @extension{ARB,seamless_cube_map} * @requires_gl Not available in OpenGL ES 2.0, always enabled in * OpenGL ES 3.0. */ @@ -78,41 +105,95 @@ class CubeMapTexture: public AbstractTexture { * @brief Constructor * * Creates one cube map OpenGL texture. - * @see @def_gl{TEXTURE_CUBE_MAP} + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP} */ - inline CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} + inline explicit CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} /** - * @copydoc Texture::setWrapping() + * @brief Set wrapping + * + * See Texture::setWrapping() for more information. */ - inline CubeMapTexture* setWrapping(const Math::Vector<3, Wrapping>& wrapping) { + inline CubeMapTexture* setWrapping(const Array3D& wrapping) { DataHelper<3>::setWrapping(this, wrapping); return this; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief %Image size in given mip level + * @param coordinate Coordinate + * @param level Mip level + * + * See Texture::imageSize() for more information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + inline Vector2i imageSize(Coordinate coordinate, Int level) { + return DataHelper<2>::imageSize(this, static_cast(coordinate), level); + } + #endif + /** - * @copydoc Texture::setData(GLint, InternalFormat, Image*) - * @param coordinate Coordinate + * @brief Set storage + * + * See Texture::setStorage() for more information. + */ + inline CubeMapTexture* setStorage(Int levels, InternalFormat internalFormat, const Vector2i& size) { + DataHelper<2>::setStorage(this, _target, levels, internalFormat, size); + return this; + } + + /** + * @brief Set image data + * @param coordinate Coordinate + * @param level Mip level + * @param internalFormat Internal format + * @param image Image, ImageWrapper, BufferImage or + * Trade::ImageData of the same dimension count * @return Pointer to self (for method chaining) + * + * See Texture::setImage() for more information. */ - template inline CubeMapTexture* setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, Image* image) { - DataHelper<2>::set(this, static_cast(coordinate), mipLevel, internalFormat, image); + template inline CubeMapTexture* setImage(Coordinate coordinate, Int level, InternalFormat internalFormat, Image* image) { + DataHelper<2>::set(this, static_cast(coordinate), level, internalFormat, image); return this; } /** - * @copydoc Texture::setSubData(GLint, const typename DimensionTraits::VectorType&, Image*) - * @param coordinate Coordinate + * @brief Set image subdata + * @param coordinate Coordinate + * @param level Mip level + * @param offset Offset where to put data in the texture + * @param image Image, ImageWrapper, BufferImage or + * Trade::ImageData of the same or one less dimension count * @return Pointer to self (for method chaining) + * + * See Texture::setSubImage() for more information. */ - template inline CubeMapTexture* setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector2& offset, const Image* image) { - DataHelper<2>::setSub(this, static_cast(coordinate), mipLevel, offset, image); + template inline CubeMapTexture* setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, const Image* image) { + DataHelper<2>::setSub(this, static_cast(coordinate), level, offset, image); return this; } + /** + * @brief Invalidate texture subimage + * @param level Mip level + * @param offset Offset into the texture + * @param size Size of invalidated data + * + * Z coordinate is equivalent to number of texture face, i.e. + * @ref Coordinate "Coordinate::PositiveX" is `0` and so on, in the + * same order as in the enum. + * + * See Texture::invalidateSubImage() for more information. + */ + inline void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { + DataHelper<3>::invalidateSub(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::BaseLevel) { + inline CubeMapTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); return this; } @@ -126,7 +207,7 @@ class CubeMapTexture: public AbstractTexture { return this; } #endif - inline CubeMapTexture* setMaxAnisotropy(GLfloat anisotropy) { + inline CubeMapTexture* setMaxAnisotropy(Float anisotropy) { AbstractTexture::setMaxAnisotropy(anisotropy); return this; } diff --git a/src/CubeMapTextureArray.h b/src/CubeMapTextureArray.h index fdf55ca79..619e232cc 100644 --- a/src/CubeMapTextureArray.h +++ b/src/CubeMapTextureArray.h @@ -1,18 +1,27 @@ #ifndef Magnum_CubeMapTextureArray_h #define Magnum_CubeMapTextureArray_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 MAGNUM_TARGET_GLES @@ -21,7 +30,7 @@ */ #endif -#include "Texture.h" +#include "AbstractTexture.h" #ifndef MAGNUM_TARGET_GLES namespace Magnum { @@ -29,15 +38,44 @@ namespace Magnum { /** @brief Cube map texture array -For information, see CubeMapTexture and AbstractTexture documentation. +See CubeMapTexture documentation for introduction. + +@section CubeMapTextureArray-usage Usage + +Common usage is to specify each layer and face separately using setSubImage(). +You have to allocate the memory for all layers and faces first either by +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); + +CubeMapTextureArray texture; +texture.setMagnificationFilter(CubeMapTextureArray::Filter::Linear) + // ... + ->setStorage(Math::log2(64)+1, CubeMapTextureArray::Format::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); + // ... + texture->setSubImage(i, CubeMapTextureArray::Coordinate::PositiveX, 0, {}, imagePositiveX); + texture->setSubImage(i, CubeMapTextureArray::Coordinate::NegativeX, 0, {}, imageNegativeX); + // ... +} + +// ... +@endcode -When using cube map texture in the shader, use `samplerCubeArray`. Unlike -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. +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. @see CubeMapTexture::setSeamless() -@requires_gl40 Extension @extension{ARB,texture_cube_map_array} +@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 { @@ -56,76 +94,122 @@ class CubeMapTextureArray: public AbstractTexture { * @brief Constructor * * Creates one cube map OpenGL texture. - * @see @def_gl{TEXTURE_CUBE_MAP_ARRAY} + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP} */ - inline CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} + inline explicit CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} /** - * @copydoc Texture::setWrapping() + * @brief Set wrapping + * + * See Texture::setWrapping() for more information. */ - inline CubeMapTextureArray* setWrapping(const Math::Vector3& wrapping) { + inline CubeMapTextureArray* setWrapping(const Array3D& wrapping) { DataHelper<3>::setWrapping(this, wrapping); return this; } /** - * @copydoc Texture::setData(GLint, InternalFormat, Image*) + * @brief %Image size in given mip level + * @param coordinate Coordinate + * @param level Mip level * - * Sets texture data from three-dimensional image for all cube faces - * for all layers. Each group of 6 2D images is one cube map layer. - * The images are ordered the same way as Coordinate enum. + * See Texture::imageSize() for more information. */ - template inline CubeMapTextureArray* setData(GLint mipLevel, InternalFormat internalFormat, T* image) { - DataHelper<3>::set(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, internalFormat, image); + inline Vector3i imageSize(Coordinate coordinate, Int level) { + return DataHelper<3>::imageSize(this, GL_TEXTURE_CUBE_MAP_POSITIVE_X + static_cast(coordinate), level); + } + + /** + * @brief Set storage + * + * See Texture::setStorage() for more information. + */ + inline CubeMapTextureArray* setStorage(Int levels, InternalFormat internalFormat, const Vector3i& size) { + DataHelper<3>::setStorage(this, _target, levels, internalFormat, size); return this; } /** - * @brief Set texture subdata from 3D image - * @param mipLevel Mip level + * @brief Set image data + * @param level Mip level + * @param internalFormat Internal format + * @param image Image, ImageWrapper, BufferImage or + * Trade::ImageData of the same dimension count + * @return Pointer to self (for method chaining) + * + * Sets texture image data from three-dimensional image for all cube + * faces for all layers. Each group of 6 2D images is one cube map + * layer. The images are ordered the same way as Coordinate enum. + * + * 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); + return this; + } + + /** + * @brief Set texture image 3D subdata + * @param level Mip level * @param offset Offset where to put data in the texture - * @param image Three-dimensional Image, BufferedImage or for - * example Trade::ImageData + * @param image Image3D, ImageWrapper3D, BufferImage3D or + * Trade::ImageData3D * @return Pointer to self (for method chaining) * - * Sets texture subdata from given image. The image is not deleted - * afterwards. + * Sets texture image subdata for more than one level/face at once. * * Z coordinate of @p offset specifies layer and cube map face. If * you want to start at given face in layer *n*, you have to specify * Z coordinate as @f$ 6n + i @f$, where i is face index as specified * in Coordinate enum. * - * @see setSubData(GLsizei, Coordinate, GLint, const Math::Vector<2, GLint>&, const Image*) + * See Texture::setSubImage() for more information. + * + * @see setSubImage(Int, Coordinate, Int, const Math::Vector<2, Int>&, const Image*) */ - template inline CubeMapTextureArray* setSubData(GLint mipLevel, const Math::Vector3& offset, const Image* image) { - DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector3(Math::Vector())); + 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())); return this; } /** - * @brief Set texture subdata from 2D image + * @brief Set texture image 2D subdata * @param layer Array layer * @param coordinate Coordinate - * @param mipLevel Mip level + * @param level Mip level * @param offset Offset where to put data in the texture - * @param image Two-dimensional Image, BufferedImage or for - * example Trade::ImageData + * @param image Image2D, ImageWrapper2D, BufferImage2D or + * Trade::ImageData2D * @return Pointer to self (for method chaining) * - * Sets texture subdata from given image. The image is not deleted - * afterwards. + * See Texture::setSubImage() for more information. * - * @see setSubData(GLint, const Math::Vector<3, GLint>&, const Image*) + * @see setSubImage(Int, const Math::Vector<3, Int>&, const Image*) */ - template inline CubeMapTextureArray* setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector2& offset, const Image* image) { - DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, Math::Vector3(offset, layer*6+static_cast(coordinate)), image, Math::Vector<2, GLsizei>(Math::Vector())); + 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())); return this; } + /** + * @brief Invalidate texture subimage + * @param level Mip level + * @param offset Offset into the texture + * @param size Size of invalidated data + * + * Z coordinate is equivalent to layer * 6 + number of texture face, + * i.e. @ref Coordinate "Coordinate::PositiveX" is `0` and so on, in + * the same order as in the enum. + * + * See Texture::invalidateSubImage() for more information. + */ + inline void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { + DataHelper<3>::invalidateSub(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::BaseLevel) { + inline CubeMapTextureArray* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); return this; } @@ -137,7 +221,7 @@ class CubeMapTextureArray: public AbstractTexture { AbstractTexture::setBorderColor(color); return this; } - inline CubeMapTextureArray* setMaxAnisotropy(GLfloat anisotropy) { + inline CubeMapTextureArray* setMaxAnisotropy(Float anisotropy) { AbstractTexture::setMaxAnisotropy(anisotropy); return this; } diff --git a/src/DebugMarker.cpp b/src/DebugMarker.cpp index e4ec3d21a..44b2e6919 100644 --- a/src/DebugMarker.cpp +++ b/src/DebugMarker.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "DebugMarker.h" diff --git a/src/DebugMarker.h b/src/DebugMarker.h index 942c38dad..3429c3c53 100644 --- a/src/DebugMarker.h +++ b/src/DebugMarker.h @@ -1,18 +1,27 @@ #ifndef Magnum_DebugMarker_h #define Magnum_DebugMarker_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -41,6 +50,8 @@ class MAGNUM_EXPORT DebugMarker { friend class Context; public: + DebugMarker() = delete; + /** @brief Put string mark into OpenGL command stream */ inline static void mark(const std::string& string) { markImplementation(string); diff --git a/src/DebugTools/CMakeLists.txt b/src/DebugTools/CMakeLists.txt new file mode 100644 index 000000000..55081223a --- /dev/null +++ b/src/DebugTools/CMakeLists.txt @@ -0,0 +1,62 @@ +# +# 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. +# + +set(MagnumDebugTools_SRCS + ForceRenderer.cpp + ObjectRenderer.cpp + Profiler.cpp + ResourceManager.cpp + ShapeRenderer.cpp + + Implementation/AbstractBoxRenderer.cpp + Implementation/AbstractShapeRenderer.cpp + Implementation/AxisAlignedBoxRenderer.cpp + Implementation/BoxRenderer.cpp + Implementation/PointRenderer.cpp) + +set(MagnumDebugTools_HEADERS + ForceRenderer.h + DebugTools.h + ObjectRenderer.h + Profiler.h + ResourceManager.h + ShapeRenderer.h + + magnumDebugToolsVisibility.h) + +add_library(MagnumDebugTools SHARED ${MagnumDebugTools_SRCS}) +target_link_libraries(MagnumDebugTools + Magnum + MagnumMeshTools + MagnumPhysics + MagnumPrimitives + MagnumSceneGraph + MagnumShaders) + +install(TARGETS MagnumDebugTools DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +install(FILES ${MagnumDebugTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/DebugTools) + +if(BUILD_TESTS) + add_subdirectory(Test) +endif() diff --git a/src/DebugTools/DebugTools.h b/src/DebugTools/DebugTools.h new file mode 100644 index 000000000..64f42a4e1 --- /dev/null +++ b/src/DebugTools/DebugTools.h @@ -0,0 +1,58 @@ +#ifndef Magnum_DebugTools_DebugTools_h +#define Magnum_DebugTools_DebugTools_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 Forward declarations for Magnum::DebugTools namespace + */ + +#include "Types.h" + +namespace Magnum { namespace DebugTools { + +/** @todoc Remove `ifndef` when Doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT +template class ForceRenderer; +typedef ForceRenderer<2> ForceRenderer2D; +typedef ForceRenderer<3> ForceRenderer3D; +class ForceRendererOptions; + +template class ObjectRenderer; +typedef ObjectRenderer<2> ObjectRenderer2D; +typedef ObjectRenderer<3> ObjectRenderer3D; +class ObjectRendererOptions; + +class Profiler; +class ResourceManager; + +template class ShapeRenderer; +typedef ShapeRenderer<2> ShapeRenderer2D; +typedef ShapeRenderer<3> ShapeRenderer3D; +class ShapeRendererOptions; +#endif + +}} + +#endif diff --git a/src/DebugTools/ForceRenderer.cpp b/src/DebugTools/ForceRenderer.cpp new file mode 100644 index 000000000..9b9fdd25a --- /dev/null +++ b/src/DebugTools/ForceRenderer.cpp @@ -0,0 +1,98 @@ +/* + 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 "ForceRenderer.h" + +#include "Buffer.h" +#include "Mesh.h" +#include "DebugTools/ResourceManager.h" +#include "SceneGraph/AbstractCamera.h" +#include "Shaders/FlatShader.h" + +#include "DebugTools/Implementation/ForceRendererTransformation.h" + +namespace Magnum { namespace DebugTools { + +namespace { + +template ResourceKey shaderKey(); +template<> inline ResourceKey shaderKey<2>() { return ResourceKey("FlatShader2D"); } +template<> inline ResourceKey shaderKey<3>() { return ResourceKey("FlatShader3D"); } + +constexpr std::array positions{{ + {0.0f, 0.0f}, + {1.0f, 0.0f}, + {0.9f, 0.1f}, + {0.9f, -0.1f} +}}; + +constexpr std::array indices{{ + 0, 1, + 1, 2, + 1, 3 +}}; + +} + +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); + + /* Mesh and vertex buffer */ + mesh = ResourceManager::instance()->get("force"); + vertexBuffer = ResourceManager::instance()->get("force-vertices"); + indexBuffer = ResourceManager::instance()->get("force-indices"); + if(mesh) return; + + /* Create the mesh */ + Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); + Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + + vertexBuffer->setData(positions, Buffer::Usage::StaticDraw); + ResourceManager::instance()->set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + + indexBuffer->setData(indices, Buffer::Usage::StaticDraw); + ResourceManager::instance()->set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + + Mesh* mesh = new Mesh; + mesh->setPrimitive(Mesh::Primitive::Lines) + ->setIndexCount(indices.size()) + ->addVertexBuffer(vertexBuffer, 0, + typename Shaders::FlatShader::Position(Shaders::FlatShader::Position::Components::Two)) + ->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, positions.size()); + ResourceManager::instance()->set(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); +} + +template void ForceRenderer::draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) { + shader->setTransformationProjectionMatrix(camera->projectionMatrix()*Implementation::forceRendererTransformation(transformationMatrix.translation()+forcePosition, *force)*DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->scale()))) + ->setColor(options->color()) + ->use(); + mesh->draw(); +} + +template class ForceRenderer<2>; +template class ForceRenderer<3>; + +}} diff --git a/src/DebugTools/ForceRenderer.h b/src/DebugTools/ForceRenderer.h new file mode 100644 index 000000000..2a947e8aa --- /dev/null +++ b/src/DebugTools/ForceRenderer.h @@ -0,0 +1,145 @@ +#ifndef Magnum_DebugTools_ForceRenderer_h +#define Magnum_DebugTools_ForceRenderer_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::DebugTools::ForceRenderer, Magnum::DebugTools::ForceRendererOptions, typedef Magnum::DebugTools::ForceRenderer2D, Magnum::DebugTools::ForceRenderer3D + */ + +#include "Color.h" +#include "Resource.h" +#include "SceneGraph/Drawable.h" +#include "Shaders/Shaders.h" + +#include "magnumDebugToolsVisibility.h" + +namespace Magnum { namespace DebugTools { + +/** +@brief Force renderer options + +See ForceRenderer documentation for more information. +*/ +class ForceRendererOptions { + public: + inline constexpr ForceRendererOptions(): _size(1.0f) {} + + /** @brief Color of rendered arrow */ + inline constexpr Color3<> color() const { return _color; } + + /** + * @brief Set color of rendered arrow + * @return Pointer to self (for method chaining) + * + * Default is black. + */ + inline ForceRendererOptions* setColor(const Color3<>& color) { + _color = color; + return this; + } + + /** @brief Scale of rendered arrow */ + inline constexpr Float scale() const { return _size; } + + /** + * @brief Set scale of rendered arrow + * @return Pointer to self (for method chaining) + * + * Default is `1.0f`. + */ + inline ForceRendererOptions* setSize(Float size) { + _size = size; + return this; + } + + private: + Color3<> _color; + Float _size; +}; + +/** +@brief Force renderer + +Visualizes force pushing on object by an arrow of the same direction and size. +See @ref debug-tools-renderers for more information. + +@section ForceRenderer-usage Basic usage + +Example code: +@code +// Create some options +DebugTools::ResourceManager::instance()->set("my", (new DebugTools::ForceRendererOptions() + ->setScale(5.0f) + ->setColor(Color3<>::fromHSV(120.0_degf, 1.0f, 0.7f))); + +// Create debug renderer for given object, use "my" options for it +Object3D* object; +Vector3 force; +new DebugTools::ForceRenderer2D(object, {0.3f, 1.5f, -0.7f}, &force, "my", debugDrawables); +@endcode + +@see ForceRenderer2D, ForceRenderer3D +*/ +template class MAGNUM_DEBUGTOOLS_EXPORT ForceRenderer: public SceneGraph::Drawable { + public: + /** + * @brief Constructor + * @param object Object for which to create debug renderer + * @param forcePosition Where to render the force, relative to object + * @param force Force vector + * @param options Options resource key. See + * @ref ForceRenderer-usage "class documentation" for more + * information. + * @param drawables Drawable group + * + * The renderer is automatically added to object's features, @p force is + * saved as reference to original vector and thus it must be available + * for the whole lifetime of the renderer. + */ + explicit ForceRenderer(SceneGraph::AbstractObject* object, const typename DimensionTraits::VectorType& forcePosition, const typename DimensionTraits::VectorType* force, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); + + protected: + /** @todoc Remove Float when Doxygen properly treats this as override */ + void draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) override; + + private: + const typename DimensionTraits::VectorType forcePosition; + const typename DimensionTraits::VectorType* const force; + + Resource options; + Resource> shader; + Resource mesh; + Resource vertexBuffer, indexBuffer; +}; + +/** @brief Two-dimensional force renderer */ +typedef ForceRenderer<2> ForceRenderer2D; + +/** @brief Three-dimensional force renderer */ +typedef ForceRenderer<3> ForceRenderer3D; + +}} + +#endif diff --git a/src/DebugTools/Implementation/AbstractBoxRenderer.cpp b/src/DebugTools/Implementation/AbstractBoxRenderer.cpp new file mode 100644 index 000000000..011997e4f --- /dev/null +++ b/src/DebugTools/Implementation/AbstractBoxRenderer.cpp @@ -0,0 +1,45 @@ +/* + 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 "AbstractBoxRenderer.h" + +#include "Primitives/Cube.h" +#include "Primitives/Square.h" +#include "Trade/MeshData2D.h" +#include "Trade/MeshData3D.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +AbstractBoxRenderer<2>::AbstractBoxRenderer(): AbstractShapeRenderer<2>("box2d", "box2d-vertices", {}) { + if(!mesh) this->createResources(Primitives::Square::wireframe()); +} + +AbstractBoxRenderer<3>::AbstractBoxRenderer(): AbstractShapeRenderer<3>("box3d", "box3d-vertices", "box3d-indices") { + if(!mesh) this->createResources(Primitives::Cube::wireframe()); +} + +template class AbstractBoxRenderer<2>; +template class AbstractBoxRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/AbstractBoxRenderer.h b/src/DebugTools/Implementation/AbstractBoxRenderer.h new file mode 100644 index 000000000..0996a20f7 --- /dev/null +++ b/src/DebugTools/Implementation/AbstractBoxRenderer.h @@ -0,0 +1,50 @@ +#ifndef Magnum_DebugTools_Implementation_AbstractBoxRenderer_h +#define Magnum_DebugTools_Implementation_AbstractBoxRenderer_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 "AbstractShapeRenderer.h" + +#include "Resource.h" +#include "Shaders/Shaders.h" + +#include "corradeCompatibility.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template class AbstractBoxRenderer; + +template<> class AbstractBoxRenderer<2>: public AbstractShapeRenderer<2> { + public: + AbstractBoxRenderer(); +}; + +template<> class AbstractBoxRenderer<3>: public AbstractShapeRenderer<3> { + public: + AbstractBoxRenderer(); +}; + +}}} + +#endif diff --git a/src/DebugTools/Implementation/AbstractShapeRenderer.cpp b/src/DebugTools/Implementation/AbstractShapeRenderer.cpp new file mode 100644 index 000000000..06f9b30cd --- /dev/null +++ b/src/DebugTools/Implementation/AbstractShapeRenderer.cpp @@ -0,0 +1,111 @@ +/* + 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 "AbstractShapeRenderer.h" + +#include "AbstractShaderProgram.h" +#include "Buffer.h" +#include "Mesh.h" +#include "DebugTools/ResourceManager.h" +#include "MeshTools/CompressIndices.h" +#include "Shaders/FlatShader.h" +#include "Trade/MeshData2D.h" +#include "Trade/MeshData3D.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +namespace { + +template ResourceKey shaderKey(); +template<> inline ResourceKey shaderKey<2>() { return ResourceKey("FlatShader2D"); } +template<> inline ResourceKey shaderKey<3>() { return ResourceKey("FlatShader3D"); } + +template void create(typename MeshData::Type&, Resource&, Resource&, Resource&); + +template<> void create<2>(Trade::MeshData2D& data, Resource& meshResource, Resource& vertexBufferResource, Resource& indexBufferResource) { + /* Vertex buffer */ + Buffer* buffer = new Buffer(Buffer::Target::Array); + buffer->setData(*data.positions(0), Buffer::Usage::StaticDraw); + ResourceManager::instance()->set(vertexBufferResource.key(), buffer, ResourceDataState::Final, ResourcePolicy::Manual); + + /* Mesh configuration */ + Mesh* mesh = new Mesh; + mesh->setPrimitive(data.primitive()) + ->setVertexCount(data.positions(0)->size()) + ->addVertexBuffer(buffer, 0, Shaders::FlatShader2D::Position()); + ResourceManager::instance()->set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); + + /* Index buffer, if needed, if not, resource key doesn't have to be set */ + if(data.indices()) { + CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey()); + Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, *data.indices()); + ResourceManager::instance()->set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + } +} + +template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, Resource& vertexBufferResource, Resource& indexBufferResource) { + /* Vertex buffer */ + Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); + vertexBuffer->setData(*data.positions(0), Buffer::Usage::StaticDraw); + ResourceManager::instance()->set(vertexBufferResource.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + + /* Mesh configuration */ + Mesh* mesh = new Mesh; + mesh->setPrimitive(data.primitive()) + ->setVertexCount(data.positions(0)->size()) + ->addVertexBuffer(vertexBuffer, 0, Shaders::FlatShader3D::Position()); + ResourceManager::instance()->set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); + + /* Index buffer, if needed, if not, resource key doesn't have to be set */ + if(data.indices()) { + CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey()); + Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, *data.indices()); + ResourceManager::instance()->set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + } +} + +} + +template AbstractShapeRenderer::AbstractShapeRenderer(ResourceKey meshKey, ResourceKey vertexBufferKey, ResourceKey indexBufferKey) { + shader = ResourceManager::instance()->get>(shaderKey()); + mesh = ResourceManager::instance()->get(meshKey); + vertexBuffer = ResourceManager::instance()->get(vertexBufferKey); + indexBuffer = ResourceManager::instance()->get(indexBufferKey); + + if(!shader) ResourceManager::instance()->set(shaderKey(), + new Shaders::FlatShader, ResourceDataState::Final, ResourcePolicy::Resident); +} + +template AbstractShapeRenderer::~AbstractShapeRenderer() {} + +template void AbstractShapeRenderer::createResources(typename MeshData::Type data) { + create(data, this->mesh, this->vertexBuffer, this->indexBuffer); +} + +template class AbstractShapeRenderer<2>; +template class AbstractShapeRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/AbstractShapeRenderer.h b/src/DebugTools/Implementation/AbstractShapeRenderer.h new file mode 100644 index 000000000..16f7f6606 --- /dev/null +++ b/src/DebugTools/Implementation/AbstractShapeRenderer.h @@ -0,0 +1,61 @@ +#ifndef Magnum_DebugTools_Implementation_AbstractShapeRenderer_h +#define Magnum_DebugTools_Implementation_AbstractShapeRenderer_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 "DimensionTraits.h" +#include "Resource.h" +#include "DebugTools/DebugTools.h" +#include "SceneGraph/SceneGraph.h" +#include "Shaders/Shaders.h" +#include "Trade/Trade.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template struct MeshData; + +template<> struct MeshData<2> { typedef Trade::MeshData2D Type; }; +template<> struct MeshData<3> { typedef Trade::MeshData3D Type; }; + +template class AbstractShapeRenderer { + public: + AbstractShapeRenderer(ResourceKey mesh, ResourceKey vertexBuffer, ResourceKey indexBuffer); + virtual ~AbstractShapeRenderer(); + + virtual void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) = 0; + + protected: + /* Call only if the mesh resource isn't already present */ + void createResources(typename MeshData::Type data); + + Resource> shader; + Resource mesh; + + private: + Resource indexBuffer, vertexBuffer; +}; + +}}} + +#endif diff --git a/src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp new file mode 100644 index 000000000..903cfbf57 --- /dev/null +++ b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.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 "AxisAlignedBoxRenderer.h" + +#include "Mesh.h" +#include "DebugTools/ShapeRenderer.h" +#include "Physics/AxisAlignedBox.h" +#include "Shaders/FlatShader.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template AxisAlignedBoxRenderer::AxisAlignedBoxRenderer(Physics::AxisAlignedBox& axisAlignedBox): axisAlignedBox(axisAlignedBox) {} + +template void AxisAlignedBoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { + /* Half scale, because the box is 2x2(x2) */ + typename DimensionTraits::MatrixType transformation = + DimensionTraits::MatrixType::translation((axisAlignedBox.transformedMin()+axisAlignedBox.transformedMax())/2)* + DimensionTraits::MatrixType::scaling((axisAlignedBox.transformedMax()-axisAlignedBox.transformedMin())/2); + this->shader->setTransformationProjectionMatrix(projectionMatrix*transformation) + ->setColor(options->color()) + ->use(); + this->mesh->draw(); +} + +template class AxisAlignedBoxRenderer<2>; +template class AxisAlignedBoxRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h new file mode 100644 index 000000000..9247fa2a1 --- /dev/null +++ b/src/DebugTools/Implementation/AxisAlignedBoxRenderer.h @@ -0,0 +1,47 @@ +#ifndef Magnum_DebugTools_Implementation_AxisAlignedBoxRenderer_h +#define Magnum_DebugTools_Implementation_AxisAlignedBoxRenderer_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 "AbstractBoxRenderer.h" + +#include "Physics/Physics.h" + +#include "corradeCompatibility.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template class AxisAlignedBoxRenderer: public AbstractBoxRenderer { + public: + AxisAlignedBoxRenderer(Physics::AxisAlignedBox& axisAlignedBox); + + void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; + + private: + Physics::AxisAlignedBox& axisAlignedBox; +}; + +}}} + +#endif diff --git a/src/DebugTools/Implementation/BoxRenderer.cpp b/src/DebugTools/Implementation/BoxRenderer.cpp new file mode 100644 index 000000000..e838b67f1 --- /dev/null +++ b/src/DebugTools/Implementation/BoxRenderer.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 "BoxRenderer.h" + +#include "Mesh.h" +#include "DebugTools/ShapeRenderer.h" +#include "Physics/Box.h" +#include "Shaders/FlatShader.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template BoxRenderer::BoxRenderer(Physics::Box& box): box(box) {} + +template void BoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { + /* Half scale, because the box is 2x2(x2) */ + this->shader->setTransformationProjectionMatrix(projectionMatrix*box.transformedTransformation()* + DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(0.5f))) + ->setColor(options->color()) + ->use(); + this->mesh->draw(); +} + +template class BoxRenderer<2>; +template class BoxRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/BoxRenderer.h b/src/DebugTools/Implementation/BoxRenderer.h new file mode 100644 index 000000000..90b459113 --- /dev/null +++ b/src/DebugTools/Implementation/BoxRenderer.h @@ -0,0 +1,47 @@ +#ifndef Magnum_DebugTools_Implementation_BoxRenderer_h +#define Magnum_DebugTools_Implementation_BoxRenderer_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 "AbstractBoxRenderer.h" + +#include "Physics/Physics.h" + +#include "corradeCompatibility.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template class BoxRenderer: public AbstractBoxRenderer { + public: + BoxRenderer(Physics::Box& box); + + void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; + + private: + Physics::Box& box; +}; + +}}} + +#endif diff --git a/src/DebugTools/Implementation/ForceRendererTransformation.h b/src/DebugTools/Implementation/ForceRendererTransformation.h new file mode 100644 index 000000000..067df4960 --- /dev/null +++ b/src/DebugTools/Implementation/ForceRendererTransformation.h @@ -0,0 +1,70 @@ +#ifndef Magnum_DebugTools_Implementation_ForceRendererTransformation_h +#define Magnum_DebugTools_Implementation_ForceRendererTransformation_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 "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "DimensionTraits.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template typename DimensionTraits::MatrixType forceRendererTransformation(const typename DimensionTraits::VectorType& forcePosition, const typename DimensionTraits::VectorType& force); + +template<> inline Matrix3 forceRendererTransformation<2>(const Vector2& forcePosition, const Vector2& force) { + return Matrix3::from({force, Vector2(-force.y(), force.x())}, forcePosition); +} + +template<> inline Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, const Vector3& force) { + const Matrix4 translation = Matrix4::translation(forcePosition); + const Float forceLength = force.length(); + + /* Zero length, zero scaling */ + if(forceLength < Math::TypeTraits::epsilon()) + return translation*Matrix4::scaling(Vector3(0.0f)); + + const Float dot = Vector3::dot(force/forceLength, Vector3::xAxis()); + + /* Force is parallel to X axis, just scaling */ + if(dot > 1.0f - Math::TypeTraits::epsilon()) + return translation*Matrix4::scaling(Vector3(forceLength)); + + /* Force is antiparallel to X axis, scaling inverted on X */ + if(-dot > 1.0f - Math::TypeTraits::epsilon()) + return translation*Matrix4::scaling({-forceLength, forceLength, forceLength}); + + /* Normal of plane going through force vector and X axis vector */ + const Vector3 normal = Vector3::cross(Vector3::xAxis(), force).normalized(); + + /* Third base vector, orthogonal to force and normal */ + const Vector3 binormal = Vector3::cross(normal, force).normalized(); + + /* Transformation matrix from scaled base vectors and translation vector */ + return Matrix4::from({force, normal*forceLength, binormal*forceLength}, forcePosition); +} + +}}} + +#endif diff --git a/src/DebugTools/Implementation/PointRenderer.cpp b/src/DebugTools/Implementation/PointRenderer.cpp new file mode 100644 index 000000000..c414813f2 --- /dev/null +++ b/src/DebugTools/Implementation/PointRenderer.cpp @@ -0,0 +1,68 @@ +/* + 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 "PointRenderer.h" + +#include "Mesh.h" +#include "DebugTools/ShapeRenderer.h" +#include "Physics/Point.h" +#include "Primitives/Crosshair.h" +#include "Shaders/FlatShader.h" +#include "Trade/MeshData2D.h" +#include "Trade/MeshData3D.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +namespace { + template ResourceKey meshKey(); + template<> inline ResourceKey meshKey<2>() { return ResourceKey("point2d"); } + template<> inline ResourceKey meshKey<3>() { return ResourceKey("point3d"); } + + template ResourceKey vertexBufferKey(); + template<> inline ResourceKey vertexBufferKey<2>() { return ResourceKey("point2d-vertices"); } + template<> inline ResourceKey vertexBufferKey<3>() { return ResourceKey("point3d-vertices"); } + + template typename MeshData::Type meshData(); + template<> inline Trade::MeshData2D meshData<2>() { return Primitives::Crosshair2D::wireframe(); } + template<> inline Trade::MeshData3D meshData<3>() { return Primitives::Crosshair3D::wireframe(); } +} + +template PointRenderer::PointRenderer(Physics::Point& point): AbstractShapeRenderer(meshKey(), vertexBufferKey(), {}), point(point) { + if(!this->mesh) this->createResources(meshData()); +} + +template void PointRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { + /* Half scale, because the point is 2x2(x2) */ + this->shader->setTransformationProjectionMatrix(projectionMatrix* + DimensionTraits::MatrixType::translation(point.transformedPosition())* + DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->pointSize()/2))) + ->setColor(options->color()) + ->use(); + this->mesh->draw(); +} + +template class PointRenderer<2>; +template class PointRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/PointRenderer.h b/src/DebugTools/Implementation/PointRenderer.h new file mode 100644 index 000000000..4ac4c78c7 --- /dev/null +++ b/src/DebugTools/Implementation/PointRenderer.h @@ -0,0 +1,47 @@ +#ifndef Magnum_DebugTools_Implementation_PointRenderer_h +#define Magnum_DebugTools_Implementation_PointRenderer_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 "AbstractShapeRenderer.h" + +#include "Physics/Physics.h" + +#include "corradeCompatibility.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template class PointRenderer: public AbstractShapeRenderer { + public: + PointRenderer(Physics::Point& point); + + void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; + + private: + Physics::Point& point; +}; + +}}} + +#endif diff --git a/src/DebugTools/ObjectRenderer.cpp b/src/DebugTools/ObjectRenderer.cpp new file mode 100644 index 000000000..240febe45 --- /dev/null +++ b/src/DebugTools/ObjectRenderer.cpp @@ -0,0 +1,186 @@ +/* + 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 "ObjectRenderer.h" + +#include "Buffer.h" +#include "DebugTools/ResourceManager.h" +#include "MeshTools/Interleave.h" +#include "SceneGraph/AbstractCamera.h" +#include "Shaders/VertexColorShader.h" + +namespace Magnum { namespace DebugTools { + +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 const std::array positions; + static const std::array, 8> colors; + static const std::array indices; +}; + +const std::array Renderer<2>::positions{{ + { 0.0f, 0.0f}, + { 1.0f, 0.0f}, /* X axis */ + { 0.9f, 0.1f}, + { 0.9f, -0.1f}, + + { 0.0f, 0.0f}, + { 0.0f, 1.0f}, /* Y axis */ + { 0.1f, 0.9f}, + {-0.1f, 0.9f} +}}; + +const std::array, 8> Renderer<2>::colors{{ + {1.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, /* X axis */ + {1.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + + {0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, /* Y axis */ + {0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, +}}; + +const std::array Renderer<2>::indices{{ + 0, 1, + 1, 2, /* X axis */ + 1, 3, + + 4, 5, + 5, 6, /* Y axis */ + 5, 7 +}}; + +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 const std::array positions; + static const std::array, 12> colors; + static const std::array indices; +}; + +const std::array Renderer<3>::positions{{ + { 0.0f, 0.0f, 0.0f}, + { 1.0f, 0.0f, 0.0f}, /* X axis */ + { 0.9f, 0.1f, 0.0f}, + { 0.9f, -0.1f, 0.0f}, + + { 0.0f, 0.0f, 0.0f}, + { 0.0f, 1.0f, 0.0f}, /* Y axis */ + { 0.1f, 0.9f, 0.0f}, + {-0.1f, 0.9f, 0.0f}, + + { 0.0f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 1.0f}, /* Z axis */ + { 0.1f, 0.0f, 0.9f}, + {-0.1f, 0.0f, 0.9f} +}}; + +const std::array, 12> Renderer<3>::colors{{ + {1.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, /* X axis */ + {1.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + + {0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, /* Y axis */ + {0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f}, /* Z axis */ + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f} +}}; + +const std::array Renderer<3>::indices{{ + 0, 1, + 1, 2, /* X axis */ + 1, 3, + + 4, 5, + 5, 6, /* Y axis */ + 5, 7, + + 8, 9, + 9, 10, /* Z axis */ + 9, 11 +}}; + +} + +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); + + /* Mesh and vertex buffer */ + mesh = ResourceManager::instance()->get(Renderer::mesh()); + vertexBuffer = ResourceManager::instance()->get(Renderer::vertexBuffer()); + indexBuffer = ResourceManager::instance()->get(Renderer::indexBuffer()); + if(mesh) return; + + /* Create the mesh */ + Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); + Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); + Mesh* mesh = new Mesh; + + MeshTools::interleave(mesh, vertexBuffer, Buffer::Usage::StaticDraw, Renderer::positions, Renderer::colors); + ResourceManager::instance()->set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + + indexBuffer->setData(Renderer::indices, Buffer::Usage::StaticDraw); + ResourceManager::instance()->set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); + + mesh->setPrimitive(Mesh::Primitive::Lines) + ->setIndexCount(Renderer::indices.size()) + ->addInterleavedVertexBuffer(vertexBuffer, 0, + typename Shaders::VertexColorShader::Position(), + typename Shaders::VertexColorShader::Color()) + ->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, Renderer::positions.size()); + ResourceManager::instance()->set(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); +} + +template void ObjectRenderer::draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) { + shader->setTransformationProjectionMatrix(camera->projectionMatrix()*transformationMatrix*DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->size()))) + ->use(); + + mesh->draw(); +} + +template class ObjectRenderer<2>; +template class ObjectRenderer<3>; + +}} diff --git a/src/DebugTools/ObjectRenderer.h b/src/DebugTools/ObjectRenderer.h new file mode 100644 index 000000000..e1c86cab8 --- /dev/null +++ b/src/DebugTools/ObjectRenderer.h @@ -0,0 +1,120 @@ +#ifndef Magnum_DebugTools_ObjectRenderer_h +#define Magnum_DebugTools_ObjectRenderer_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::DebugTools::ObjectRenderer, Magnum::DebugTools::ObjectRendererOptions, typedef Magnum::DebugTools::ObjectRenderer2D, Magnum::DebugTools::ObjectRenderer3D + */ + +#include "Resource.h" +#include "SceneGraph/Drawable.h" +#include "Shaders/Shaders.h" + +#include "magnumDebugToolsVisibility.h" + +namespace Magnum { namespace DebugTools { + +/** +@brief Object renderer options + +See ObjectRenderer documentation for more information. +*/ +class ObjectRendererOptions { + public: + inline constexpr ObjectRendererOptions(): _size(1.0f) {} + + /** @brief Size of the rendered axes */ + inline constexpr Float size() const { return _size; } + + /** + * @brief Set size of the rendered axes + * @return Pointer to self (for method chaining) + * + * Default is `1.0f`. + */ + inline ObjectRendererOptions* setSize(Float size) { + _size = size; + return this; + } + + private: + Float _size; +}; + +/** +@brief Object renderer + +Visualizes object position, rotation and scale using colored axes. See +@ref debug-tools-renderers for more information. + +@section ObjectRenderer-usage Basic usage + +Example code: +@code +// Create some options +DebugTools::ResourceManager::instance()->set("my", + (new DebugTools::ObjectRendererOptions())->setSize(0.3f)); + +// Create debug renderer for given object, use "my" options for it +Object3D* object; +new DebugTools::ObjectRenderer2D(object, "my", debugDrawables); +@endcode + +@see ObjectRenderer2D, ObjectRenderer3D +*/ +template class MAGNUM_DEBUGTOOLS_EXPORT ObjectRenderer: public SceneGraph::Drawable { + public: + /** + * @brief Constructor + * @param object Object for which to create debug renderer + * @param options Options resource key. See + * @ref ObjectRenderer-usage "class documentation" for more + * information. + * @param drawables Drawable group + * + * The renderer is automatically added to object's features. + */ + explicit ObjectRenderer(SceneGraph::AbstractObject* object, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); + + protected: + /** @todoc Remove Float when Doxygen properly treats this as override */ + void draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) override; + + private: + Resource options; + Resource> shader; + Resource mesh; + Resource vertexBuffer, indexBuffer; +}; + +/** @brief Two-dimensional object renderer */ +typedef ObjectRenderer<2> ObjectRenderer2D; + +/** @brief Three-dimensional object renderer */ +typedef ObjectRenderer<3> ObjectRenderer3D; + +}} + +#endif diff --git a/src/DebugTools/Profiler.cpp b/src/DebugTools/Profiler.cpp new file mode 100644 index 000000000..741b79b59 --- /dev/null +++ b/src/DebugTools/Profiler.cpp @@ -0,0 +1,131 @@ +/* + 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 "Profiler.h" + +#include +#include +#include + +#include "Magnum.h" + +using namespace std::chrono; + +namespace Magnum { namespace DebugTools { + +Profiler::Section Profiler::addSection(const std::string& name) { + CORRADE_ASSERT(!enabled, "Profiler: cannot add section when profiling is enabled", 0); + sections.push_back(name); + return sections.size()-1; +} + +void Profiler::setMeasureDuration(std::size_t frames) { + CORRADE_ASSERT(!enabled, "Profiler: cannot set measure duration when profiling is enabled", ); + measureDuration = frames; +} + +void Profiler::enable() { + enabled = true; + frameData.assign(measureDuration*sections.size(), high_resolution_clock::duration::zero()); + totalData.assign(sections.size(), high_resolution_clock::duration::zero()); + frameCount = 0; +} + +void Profiler::disable() { + enabled = false; +} + +void Profiler::start(Section section) { + if(!enabled) return; + CORRADE_ASSERT(section < sections.size(), "Profiler: unknown section passed to start()", ); + + save(); + + currentSection = section; +} + +void Profiler::stop() { + if(!enabled) return; + + save(); + + previousTime = high_resolution_clock::time_point(); +} + +void Profiler::save() { + auto now = high_resolution_clock::now(); + + /* If the profiler is already running, add time to given section */ + if(previousTime != high_resolution_clock::time_point()) + frameData[currentFrame*sections.size()+currentSection] += now-previousTime; + + /* Set current time as previous for next section */ + previousTime = now; +} + +void Profiler::nextFrame() { + if(!enabled) return; + + /* Next frame index */ + std::size_t nextFrame = (currentFrame+1) % measureDuration; + + /* Add times of current frame to total */ + for(std::size_t i = 0; i != sections.size(); ++i) + totalData[i] += frameData[currentFrame*sections.size()+i]; + + /* Subtract times of next frame from total and erase them */ + for(std::size_t i = 0; i != sections.size(); ++i) { + totalData[i] -= frameData[nextFrame*sections.size()+i]; + frameData[nextFrame*sections.size()+i] = high_resolution_clock::duration::zero(); + } + + /* Advance to next frame */ + currentFrame = nextFrame; + + if(frameCount < measureDuration) ++frameCount; +} + +void Profiler::printStatistics() { + if(!enabled) return; + + std::vector totalSorted(sections.size()); + std::iota(totalSorted.begin(), totalSorted.end(), 0); + + #ifndef CORRADE_GCC44_COMPATIBILITY + std::sort(totalSorted.begin(), totalSorted.end(), [this](std::size_t i, std::size_t j){return totalData[i] > totalData[j];}); + #else + std::sort(totalSorted.begin(), totalSorted.end(), Compare(this)); + #endif + + Debug() << "Statistics for last" << measureDuration << "frames:"; + for(std::size_t i = 0; i != sections.size(); ++i) + Debug() << " " << sections[totalSorted[i]] << duration_cast(totalData[totalSorted[i]]).count()/frameCount + #ifndef CORRADE_GCC44_COMPATIBILITY + << u8"µs"; + #else + << "µs"; + #endif +} + +}} diff --git a/src/Profiler.h b/src/DebugTools/Profiler.h similarity index 73% rename from src/Profiler.h rename to src/DebugTools/Profiler.h index e67c04ad5..c69d72e5c 100644 --- a/src/Profiler.h +++ b/src/DebugTools/Profiler.h @@ -1,46 +1,56 @@ -#ifndef Magnum_Profiler_h -#define Magnum_Profiler_h +#ifndef Magnum_DebugTools_Profiler_h +#define Magnum_DebugTools_Profiler_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Profiler + * @brief Class Magnum::DebugTools::Profiler */ #include #include #include #include +#include -#include "corradeCompatibility.h" -#include "magnumVisibility.h" +#include "Types.h" +#include "magnumDebugToolsVisibility.h" -namespace Magnum { +namespace Magnum { namespace DebugTools { /** -@brief Measuring elapsed time in each frame +@brief %Profiler Measures time passed during specified sections of each frame. It's meant to be used in rendering and event loops (e.g. Platform::GlutApplication::drawEvent()), but it's possible to use it standalone elsewhere. Example usage: @code -Profiler p; +DebugTools::Profiler p; // Register named sections struct { - Profiler::Section ai, physics, draw, bufferSwap; + DebugTools::Profiler::Section ai, physics, draw, bufferSwap; } sections; sections.ai = p.addSection("AI"); sections.physics = p.addSection("Physics"); @@ -51,7 +61,7 @@ sections.bufferSwap = p.addSection("Buffer swap"); p.enable(); // Mark sections in draw function -void MyContext::drawEvent() { +void MyApplication::drawEvent() { p.start(); // ... misc stuff belogning to "Other" section @@ -89,14 +99,14 @@ stop it again using stop(), if you are not interested in profiling the rest. @todo Some unit testing @todo More time intervals */ -class MAGNUM_EXPORT Profiler { +class MAGNUM_DEBUGTOOLS_EXPORT Profiler { public: /** * @brief Section ID * * @see otherSection, addSection(), start(Section) */ - typedef std::uint32_t Section; + typedef UnsignedInt Section; /** * @brief Default section @@ -106,7 +116,7 @@ class MAGNUM_EXPORT Profiler { static const Section otherSection = 0; #ifndef DOXYGEN_GENERATING_OUTPUT - Profiler(): enabled(false), measureDuration(60), currentFrame(0), frameCount(0), sections{"Other"}, currentSection(otherSection) {} + explicit Profiler(): enabled(false), measureDuration(60), currentFrame(0), frameCount(0), sections{"Other"}, currentSection(otherSection) {} #endif /** @@ -215,6 +225,6 @@ class MAGNUM_EXPORT Profiler { Section currentSection; }; -} +}} #endif diff --git a/src/DebugTools/ResourceManager.cpp b/src/DebugTools/ResourceManager.cpp new file mode 100644 index 000000000..204c28357 --- /dev/null +++ b/src/DebugTools/ResourceManager.cpp @@ -0,0 +1,49 @@ +/* + 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. +*/ + +#define MAGNUM_RESOURCEMANAGER_DEFINE_INTERNALINSTANCE + +#include "ResourceManager.h" + +#include "Buffer.h" +#include "Mesh.h" +#include "DebugTools/ForceRenderer.h" +#include "DebugTools/ObjectRenderer.h" +#include "DebugTools/ShapeRenderer.h" + +namespace Magnum { + +template class ResourceManager; + +namespace DebugTools { + +ResourceManager::ResourceManager() { + setFallback(new ForceRendererOptions); + setFallback(new ObjectRendererOptions); + setFallback(new ShapeRendererOptions); +} + +ResourceManager::~ResourceManager() {} + +}} diff --git a/src/DebugTools/ResourceManager.h b/src/DebugTools/ResourceManager.h new file mode 100644 index 000000000..3820cbcea --- /dev/null +++ b/src/DebugTools/ResourceManager.h @@ -0,0 +1,64 @@ +#ifndef Magnum_DebugTools_ResourceManager_h +#define Magnum_DebugTools_ResourceManager_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::DebugTools::ResourceManager + */ + +#include "Magnum.h" + +#ifndef MAGNUM_RESOURCEMANAGER_DEFINE_INTERNALINSTANCE +#define MAGNUM_RESOURCEMANAGER_DONT_DEFINE_INTERNALINSTANCE +#endif +#include "../ResourceManager.h" + +#include "SceneGraph/SceneGraph.h" +#include "Physics/Physics.h" +#include "DebugTools.h" + +#include "magnumDebugToolsVisibility.h" + +namespace Magnum { + +extern template ResourceManager MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager::internalInstance(); + +namespace DebugTools { + +/** +@brief %Resource manager for debug tools + +Stores various data used by debug renderers. See @ref debug-tools for more +information. +*/ +class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager { + public: + explicit ResourceManager(); + ~ResourceManager(); +}; + +}} + +#endif diff --git a/src/DebugTools/ShapeRenderer.cpp b/src/DebugTools/ShapeRenderer.cpp new file mode 100644 index 000000000..813bd317a --- /dev/null +++ b/src/DebugTools/ShapeRenderer.cpp @@ -0,0 +1,109 @@ +/* + 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 "ShapeRenderer.h" + +#include "ResourceManager.h" +#include "Physics/AbstractShape.h" +#include "Physics/AxisAlignedBox.h" +#include "Physics/Box.h" +#include "Physics/ObjectShape.h" +#include "Physics/Point.h" +#include "Physics/ShapeGroup.h" +#include "SceneGraph/AbstractCamera.h" + +#include "Implementation/AxisAlignedBoxRenderer.h" +#include "Implementation/BoxRenderer.h" +#include "Implementation/PointRenderer.h" + +namespace Magnum { namespace DebugTools { + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + +template<> void createDebugMesh(ShapeRenderer<2>* renderer, Physics::AbstractShape<2>* shape) { + switch(shape->type()) { + case Physics::AbstractShape2D::Type::AxisAlignedBox: + renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<2>(*static_cast(shape))); + break; + case Physics::AbstractShape2D::Type::Box: + renderer->renderers.push_back(new Implementation::BoxRenderer<2>(*static_cast(shape))); + break; + case Physics::AbstractShape2D::Type::Point: + renderer->renderers.push_back(new Implementation::PointRenderer<2>(*static_cast(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()); + } break; + default: + Warning() << "DebugTools::ShapeRenderer2D::createShapeRenderer(): type" << shape->type() << "not implemented"; + } +} + +template<> void createDebugMesh(ShapeRenderer<3>* renderer, Physics::AbstractShape<3>* shape) { + switch(shape->type()) { + case Physics::AbstractShape3D::Type::AxisAlignedBox: + renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<3>(*static_cast(shape))); + break; + case Physics::AbstractShape3D::Type::Box: + renderer->renderers.push_back(new Implementation::BoxRenderer<3>(*static_cast(shape))); + break; + case Physics::AbstractShape3D::Type::Point: + renderer->renderers.push_back(new Implementation::PointRenderer<3>(*static_cast(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()); + } break; + default: + Warning() << "DebugTools::ShapeRenderer3D::createShapeRenderer(): type" << shape->type() << "not implemented"; + } +} + +} +#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() { + for(auto it = renderers.begin(); it != renderers.end(); ++it) + delete *it; +} + +template void ShapeRenderer::draw(const typename DimensionTraits::MatrixType&, SceneGraph::AbstractCamera* camera) { + typename DimensionTraits::MatrixType projectionMatrix = camera->projectionMatrix()*camera->cameraMatrix(); + for(auto it = renderers.begin(); it != renderers.end(); ++it) + (*it)->draw(options, projectionMatrix); +} + +template class ShapeRenderer<2>; +template class ShapeRenderer<3>; + +}} diff --git a/src/DebugTools/ShapeRenderer.h b/src/DebugTools/ShapeRenderer.h new file mode 100644 index 000000000..354286c02 --- /dev/null +++ b/src/DebugTools/ShapeRenderer.h @@ -0,0 +1,157 @@ +#ifndef Magnum_DebugTools_ShapeRenderer_h +#define Magnum_DebugTools_ShapeRenderer_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::DebugTools::ShapeRenderer, Magnum::DebugTools::ShapeRendererOptions, typedef Magnum::DebugTools::ShapeRenderer2D, Magnum::DebugTools::ShapeRenderer3D + */ + +#include "Color.h" +#include "Resource.h" +#include "SceneGraph/Drawable.h" +#include "Physics/Physics.h" + +#include "magnumDebugToolsVisibility.h" + +namespace Magnum { namespace DebugTools { + +/** @todoc Remove `ifndef` when Doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT +template class ShapeRenderer; +#endif + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template class AbstractShapeRenderer; + + template void createDebugMesh(ShapeRenderer* renderer, Physics::AbstractShape* shape); +} +#endif + +/** +@brief Shape renderer options + +See ShapeRenderer documentation for more information. +*/ +class ShapeRendererOptions { + public: + inline constexpr ShapeRendererOptions(): _pointSize(0.25f) {} + + /** @brief Color of rendered shape */ + inline constexpr Color3<> color() const { return _color; } + + /** + * @brief Set color of rendered shape + * @return Pointer to self (for method chaining) + * + * Default is black. + */ + inline ShapeRendererOptions* setColor(const Color3<>& color) { + _color = color; + return this; + } + + /** @brief Point size */ + inline 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. + * Default is `0.25f`. + */ + inline ShapeRendererOptions* setPointSize(Float size) { + _pointSize = size; + return this; + } + + private: + Color3<> _color; + Float _pointSize; +}; + +/** +@brief Shape renderer + +Visualizes collision shapes using wireframe primitives. See +@ref debug-tools-renderers for more information. + +@section ShapeRenderer-usage Basic usage + +Example code: +@code +// Create some options +DebugTools::ResourceManager::instance()->set("red", + (new DebugTools::ShapeRendererOptions())->setColor({1.0f, 0.0f, 0.0f})); + +// Create debug renderer for given shape, use "red" options for it +Physics::ObjectShape2D* 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 + + public: + /** + * @brief Constructor + * @param shape Object 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. + */ + explicit ShapeRenderer(Physics::ObjectShape* shape, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup* drawables = nullptr); + + ~ShapeRenderer(); + + protected: + /** @todoc Remove Float when Doxygen properly treats this as override */ + void draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) override; + + private: + Resource options; + std::vector*> renderers; +}; + +/** @brief Two-dimensional shape renderer */ +typedef ShapeRenderer<2> ShapeRenderer2D; + +/** @brief Three-dimensional shape renderer */ +typedef ShapeRenderer<3> ShapeRenderer3D; + +}} + +#endif diff --git a/src/DebugTools/Test/CMakeLists.txt b/src/DebugTools/Test/CMakeLists.txt new file mode 100644 index 000000000..68a6ddae3 --- /dev/null +++ b/src/DebugTools/Test/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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. +# + +corrade_add_test(MagnumDebugToolsForceRendererTest ForceRendererTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/DebugTools/Test/ForceRendererTest.cpp b/src/DebugTools/Test/ForceRendererTest.cpp new file mode 100644 index 000000000..5dcf4022c --- /dev/null +++ b/src/DebugTools/Test/ForceRendererTest.cpp @@ -0,0 +1,123 @@ +/* + 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 "DebugTools/Implementation/ForceRendererTransformation.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { namespace Test { + +class ForceRendererTest: public Corrade::TestSuite::Tester { + public: + explicit ForceRendererTest(); + + void zero2D(); + void parallel2D(); + void antiParallel2D(); + void arbitrary2D(); + + void zero3D(); + void parallel3D(); + void antiParallel3D(); + void arbitrary3D(); +}; + +ForceRendererTest::ForceRendererTest() { + addTests({&ForceRendererTest::zero2D, + &ForceRendererTest::parallel2D, + &ForceRendererTest::antiParallel2D, + &ForceRendererTest::arbitrary2D, + + &ForceRendererTest::zero3D, + &ForceRendererTest::parallel3D, + &ForceRendererTest::antiParallel3D, + &ForceRendererTest::arbitrary3D}); +} + +void ForceRendererTest::zero2D() { + CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2()), + Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(0.0f))); +} + +void ForceRendererTest::parallel2D() { + CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2::xAxis(2.5f)), + Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(2.5f))); +} + +void ForceRendererTest::antiParallel2D() { + CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2::xAxis(-2.5f)), + Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(-2.5f))); +} + +void ForceRendererTest::arbitrary2D() { + Vector2 force(2.7f, -11.5f); + Matrix3 m = Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, force); + + /* Translation, right-pointing base vector is the same as force */ + CORRADE_COMPARE(m.translation(), Vector2(0.5f, -3.0f)); + CORRADE_COMPARE(m.right(), force); + + /* All vectors have the same length */ + CORRADE_COMPARE(m.up().length(), force.length()); + + /* All vectors are parallel */ + CORRADE_COMPARE(Vector2::dot(m.right(), m.up()), 0.0f); +} + +void ForceRendererTest::zero3D() { + CORRADE_COMPARE(Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, Vector3()), + Matrix4::translation({0.5f, -3.0f, 1.0f})*Matrix4::scaling(Vector3(0.0f))); +} + +void ForceRendererTest::parallel3D() { + CORRADE_COMPARE(Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, Vector3::xAxis(2.5f)), + Matrix4::translation({0.5f, -3.0f, 1.0f})*Matrix4::scaling(Vector3(2.5f))); +} + +void ForceRendererTest::antiParallel3D() { + CORRADE_COMPARE(Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, Vector3::xAxis(-2.5f)), + Matrix4::translation({0.5f, -3.0f, 1.0f})*Matrix4::scaling({-2.5f, 2.5f, 2.5f})); +} + +void ForceRendererTest::arbitrary3D() { + Vector3 force(3.7f, -5.7f, -11.5f); + Matrix4 m = Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, force); + + /* Translation, right-pointing base vector is the same as force */ + CORRADE_COMPARE(m.translation(), Vector3(0.5f, -3.0f, 1.0f)); + CORRADE_COMPARE(m.right(), force); + + /* All vectors have the same length */ + CORRADE_COMPARE(m.up().length(), force.length()); + CORRADE_COMPARE(m.backward().length(), force.length()); + + /* All vectors are parallel */ + CORRADE_COMPARE(Vector3::dot(m.right(), m.up()), 0.0f); + CORRADE_COMPARE(Vector3::dot(m.right(), m.backward()), 0.0f); + CORRADE_COMPARE(Vector3::dot(m.up(), m.backward()), 0.0f); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::DebugTools::Implementation::Test::ForceRendererTest) diff --git a/src/DebugTools/magnumDebugToolsVisibility.h b/src/DebugTools/magnumDebugToolsVisibility.h new file mode 100644 index 000000000..46eda28fd --- /dev/null +++ b/src/DebugTools/magnumDebugToolsVisibility.h @@ -0,0 +1,37 @@ +#ifndef Magnum_DebugTools_magnumDebugToolsVisibility_h +#define Magnum_DebugTools_magnumDebugToolsVisibility_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. +*/ + +#ifdef _WIN32 + #ifdef MagnumDebugTools_EXPORTS + #define MAGNUM_DEBUGTOOLS_EXPORT __declspec(dllexport) + #else + #define MAGNUM_DEBUGTOOLS_EXPORT __declspec(dllimport) + #endif +#else + #define MAGNUM_DEBUGTOOLS_EXPORT __attribute__ ((visibility ("default"))) +#endif + +#endif diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp new file mode 100644 index 000000000..895a12e74 --- /dev/null +++ b/src/DefaultFramebuffer.cpp @@ -0,0 +1,93 @@ +/* + 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 "DefaultFramebuffer.h" + +#include "Context.h" + +#include "Implementation/State.h" +#include "Implementation/FramebufferState.h" +#include "Extensions.h" + +namespace Magnum { + +DefaultFramebuffer defaultFramebuffer; + +DefaultFramebuffer::DefaultFramebuffer() { _id = 0; } + +#ifndef MAGNUM_TARGET_GLES2 +DefaultFramebuffer* DefaultFramebuffer::mapForDraw(std::initializer_list> attachments) { + /* Max attachment location */ + std::size_t max = 0; + for(const auto& attachment: attachments) + if(attachment.first > max) max = attachment.first; + + /* Create linear array from associative */ + GLenum* _attachments = new GLenum[max+1]; + std::fill_n(_attachments, max, GL_NONE); + for(const auto& attachment: attachments) + _attachments[attachment.first] = static_cast(attachment.second); + + (this->*drawBuffersImplementation)(max+1, _attachments); + delete[] _attachments; + return this; +} +#endif + +void DefaultFramebuffer::invalidate(std::initializer_list attachments) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments); + + delete[] _attachments; +} + +void DefaultFramebuffer::invalidate(std::initializer_list attachments, const Rectanglei& rectangle) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments, rectangle); + + delete[] _attachments; +} + +void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) { + Implementation::FramebufferState* state = context->state()->framebuffer; + + /* Initial framebuffer size */ + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + defaultFramebuffer._viewport = state->viewport = Rectanglei::fromSize({viewport[0], viewport[1]}, {viewport[2], viewport[3]}); + + /* Fake initial glViewport() call for ApiTrace */ + #ifndef MAGNUM_TARGET_GLES + if(context->isExtensionSupported()) + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + #endif +} + +} diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h new file mode 100644 index 000000000..3f37969cc --- /dev/null +++ b/src/DefaultFramebuffer.h @@ -0,0 +1,384 @@ +#ifndef Magnum_DefaultFramebuffer_h +#define Magnum_DefaultFramebuffer_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::DefaultFramebuffer + */ + +#include "AbstractFramebuffer.h" + +namespace Magnum { + +/** +@brief Default framebuffer + +Default framebuffer, i.e. the actual screen surface. It is automatically +created when Context is created and it is available through global variable +@ref defaultFramebuffer. It is by default mapped to whole screen surface. + +@section DefaultFramebuffer-usage Usage + +When you are using only the default framebuffer, the usage is simple. You +must ensure that it is properly resized when application surface is resized, +i.e. you must pass the new size in your @ref Platform::GlutApplication::viewportEvent() "viewportEvent()" +implementation, for example: +@code +void viewportEvent(const Vector2i& size) { + defaultFramebuffer.setViewport({}, size); + + // ... +} +@endcode + +Next thing you probably want is to clear all used buffers before performing +any drawing in your @ref Platform::GlutApplication::drawEvent() "drawEvent()" +implementation, for example: +@code +void drawEvent() { + defaultFramebuffer.clear(AbstractFramebuffer::Clear::Color|AbstractFramebuffer::Clear::Depth); + + // ... +} +@endcode + +See Framebuffer documentation for more involved usage, usage of non-default or +multiple framebuffers. + +@section DefaultFramebuffer-performance-optimization Performance optimizations + +See also @ref AbstractFramebuffer-performance-optimization "relevant section in AbstractFramebuffer". + +If extension @extension{EXT,direct_state_access} is available, functions +mapForDraw() and mapForRead() use DSA to avoid unnecessary calls to +@fn_gl{BindFramebuffer}. See their respective documentation for more +information. +*/ +class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { + friend class Context; + + public: + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Draw attachment + * + * @see mapForDraw() + * @requires_gles30 Draw attachments for default framebuffer are + * available only in OpenGL ES 3.0. + */ + enum class DrawAttachment: GLenum { + /** Don't use the output. */ + None = GL_NONE, + + #ifndef MAGNUM_TARGET_GLES + /** + * Write output to front left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontLeft = GL_FRONT_LEFT, + + /** + * Write output to front right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontRight = GL_FRONT_RIGHT, + + /** + * Write output to back left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackLeft = GL_BACK_LEFT, + + /** + * Write output to back right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackRight = GL_BACK_RIGHT, + #endif + + /** + * Write output to back buffer. + * + * On desktop OpenGL, this is equal to @ref DrawAttachment "DrawAttachment::BackLeft". + */ + #ifdef MAGNUM_TARGET_GLES + Back = GL_BACK, + #else + Back = GL_BACK_LEFT, + #endif + + /** + * Write output to front buffer. + * + * On desktop OpenGL, this is equal to @ref DrawAttachment "DrawAttachment::FrontLeft". + */ + #ifdef MAGNUM_TARGET_GLES + Front = GL_FRONT + #else + Front = GL_FRONT_LEFT + #endif + }; + #endif + + /** + * @brief Read attachment + * + * @see mapForRead() + * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + */ + enum class ReadAttachment: GLenum { + /** Don't read from any buffer */ + None = GL_NONE, + + #ifndef MAGNUM_TARGET_GLES + /** + * Read from front left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontLeft = GL_FRONT_LEFT, + + /** + * Read from front right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontRight = GL_FRONT_RIGHT, + + /** + * Read from back left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackLeft = GL_BACK_LEFT, + + /** + * Read from back right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackRight = GL_BACK_RIGHT, + + /** + * Read from left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + Left = GL_LEFT, + + /** + * Read from right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + Right = GL_RIGHT, + #endif + + /** Read from back buffer. */ + Back = GL_BACK, + + /** + * Read from front buffer. + * @requires_es_extension %Extension @es_extension2{NV,read_buffer_front,GL_NV_read_buffer} + */ + Front = GL_FRONT + + #ifndef MAGNUM_TARGET_GLES + , + + /** + * Read from front and back buffer. + * @requires_gl In OpenGL ES you must specify either + * @ref Magnum::DefaultFramebuffer::ReadAttachment "ReadAttachment::Front" + * or @ref Magnum::DefaultFramebuffer::ReadAttachment "ReadAttachment::Back". + */ + FrontAndBack = GL_FRONT_AND_BACK + #endif + }; + + /** + * @brief Invalidation attachment + * + * @see invalidate() + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + enum class InvalidationAttachment: GLenum { + #ifndef MAGNUM_TARGET_GLES + /** + * Invalidate front left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontLeft = GL_FRONT_LEFT, + + /** + * Invalidate front right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontRight = GL_FRONT_RIGHT, + + /** + * Invalidate back left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackLeft = GL_BACK_LEFT, + + /** + * Invalidate back right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackRight = GL_BACK_RIGHT, + #endif + + /** Invalidate color buffer. */ + #ifndef MAGNUM_TARGET_GLES2 + Color = GL_COLOR, + #else + Color = GL_COLOR_EXT, + #endif + + /** Invalidate depth bufer. */ + #ifndef MAGNUM_TARGET_GLES2 + Depth = GL_DEPTH, + #else + Depth = GL_DEPTH_EXT, + #endif + + /** Invalidate stencil buffer. */ + #ifndef MAGNUM_TARGET_GLES2 + Stencil = GL_STENCIL + #else + Stencil = GL_STENCIL_EXT + #endif + }; + + explicit MAGNUM_LOCAL DefaultFramebuffer(); + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Map shader outputs to buffer attachment + * @return Pointer to self (for method chaining) + * + * @p attachments is list of shader outputs mapped to buffer + * attachments. %Shader outputs which are not listed are not used, you + * can achieve the same by passing @ref DrawAttachment "DrawAttachment::None" + * as attachment. Example usage: + * @code + * framebuffer.mapForDraw({{MyShader::ColorOutput, DefaultFramebuffer::DrawAttachment::BackLeft}, + * {MyShader::NormalOutput, DefaultFramebuffer::DrawAttachment::None}}); + * @endcode + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or + * @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} + * @requires_gles30 Draw attachments for default framebuffer are + * available only in OpenGL ES 3.0. + */ + DefaultFramebuffer* mapForDraw(std::initializer_list> attachments); + + /** + * @brief Map shader output to buffer attachment + * @param attachment %Buffer attachment + * @return Pointer to self (for method chaining) + * + * Similar to above function, can be used in cases when shader has + * only one (unnamed) output. + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or + * @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access} + * @requires_gles30 Draw attachments for default framebuffer are + * available only in OpenGL ES 3.0. + */ + inline DefaultFramebuffer* mapForDraw(DrawAttachment attachment) { + (this->*drawBufferImplementation)(static_cast(attachment)); + return this; + } + #endif + + /** + * @brief Map given attachment for reading + * @param attachment %Buffer attachment + * @return Pointer to self (for method chaining) + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or + * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} + * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + */ + inline DefaultFramebuffer* mapForRead(ReadAttachment attachment) { + (this->*readBufferImplementation)(static_cast(attachment)); + return this; + } + + /** + * @brief Invalidate framebuffer + * @param attachments Attachments to invalidate + * + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateFramebuffer} or @fn_gles_extension{DiscardFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use + * clear() instead where the extension is not supported. + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. + * Use clear() instead where the extension is not supported. + */ + void invalidate(std::initializer_list attachments); + + /** + * @brief Invalidate framebuffer rectangle + * @param attachments Attachments to invalidate + * @param rectangle %Rectangle to invalidate + * + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateSubFramebuffer} or @fn_gles_extension{DiscardSubFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use + * clear() instead where the extension is not supported. + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. + * Use clear() instead where the extension is not supported. + */ + void invalidate(std::initializer_list attachments, const Rectanglei& rectangle); + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline DefaultFramebuffer* setViewport(const Rectanglei& rectangle) { + AbstractFramebuffer::setViewport(rectangle); + return this; + } + #endif + + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); +}; + +/** @brief Default framebuffer instance */ +extern DefaultFramebuffer MAGNUM_EXPORT defaultFramebuffer; + +} + +#endif diff --git a/src/DimensionTraits.h b/src/DimensionTraits.h index 2424c40d8..3ce74b5d7 100644 --- a/src/DimensionTraits.h +++ b/src/DimensionTraits.h @@ -1,23 +1,31 @@ #ifndef Magnum_DimensionTraits_h #define Magnum_DimensionTraits_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" +#include "Math/Math.h" +#include "Types.h" /** @file * @brief Class Magnum::DimensionTraits @@ -25,20 +33,10 @@ namespace Magnum { -namespace Math { - template class Vector; - template class Vector2; - template class Vector3; - - template class Point2D; - template class Point3D; - - template class Matrix3; - template class Matrix4; -} - /** @brief Matrix, point and vector specializations for given dimension count */ -template struct DimensionTraits { +template struct DimensionTraits { + DimensionTraits() = delete; + #ifdef DOXYGEN_GENERATING_OUTPUT /** * @brief Vector type @@ -47,14 +45,6 @@ template struct DimensionTraits { */ typedef U VectorType; - /** - * @brief Point type - * - * Floating-point Math::Point2D or Math::Point3D for 2D or 3D. No point - * type defined for one dimension and integral types. - */ - typedef U PointType; - /** * @brief Matrix type * @@ -68,41 +58,51 @@ template struct DimensionTraits { #ifndef DOXYGEN_GENERATING_OUTPUT /* One dimension */ template struct DimensionTraits<1, T> { + DimensionTraits() = delete; + typedef Math::Vector<1, T> VectorType; }; /* Two dimensions - integral */ template struct DimensionTraits<2, T> { + DimensionTraits() = delete; + typedef Math::Vector2 VectorType; }; /* Two dimensions - floating-point */ -template<> struct DimensionTraits<2, float> { - typedef Math::Vector2 VectorType; - typedef Math::Point2D PointType; - typedef Math::Matrix3 MatrixType; +template<> struct DimensionTraits<2, Float> { + DimensionTraits() = delete; + + typedef Math::Vector2 VectorType; + typedef Math::Matrix3 MatrixType; }; -template<> struct DimensionTraits<2, double> { - typedef Math::Vector2 VectorType; - typedef Math::Point2D PointType; - typedef Math::Matrix3 MatrixType; +template<> struct DimensionTraits<2, Double> { + DimensionTraits() = delete; + + typedef Math::Vector2 VectorType; + typedef Math::Matrix3 MatrixType; }; /* Three dimensions - integral */ template struct DimensionTraits<3, T> { + DimensionTraits() = delete; + typedef Math::Vector3 VectorType; }; /* Three dimensions - floating-point */ -template<> struct DimensionTraits<3, float> { - typedef Math::Vector3 VectorType; - typedef Math::Point3D PointType; - typedef Math::Matrix4 MatrixType; +template<> struct DimensionTraits<3, Float> { + DimensionTraits() = delete; + + typedef Math::Vector3 VectorType; + typedef Math::Matrix4 MatrixType; }; -template<> struct DimensionTraits<3, double> { - typedef Math::Vector3 VectorType; - typedef Math::Point3D PointType; - typedef Math::Matrix4 MatrixType; +template<> struct DimensionTraits<3, Double> { + DimensionTraits() = delete; + + typedef Math::Vector3 VectorType; + typedef Math::Matrix4 MatrixType; }; #endif diff --git a/src/Extensions.h b/src/Extensions.h index ab1f78830..aa570bef3 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -1,18 +1,27 @@ #ifndef Magnum_Extensions_h #define Magnum_Extensions_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -30,18 +39,13 @@ Each extension is `struct` named hierarchically by prefix, vendor and extension name, for example `GL::APPLE::vertex_array_object`. Each struct has the same public methods as Extension class (requiredVersion(), coreVersion() and string(), but these structs are better suited for compile-time decisions -rather than Extension instances. See Context::isExtensionSupported() for +rather than %Extension instances. See Context::isExtensionSupported() for example usage. - @see MAGNUM_ASSERT_EXTENSION_SUPPORTED() - @todo Manual indices for extensions, this has gaps -@todo Unhide ES2_compatibility, ES3_compatibility on ES -@todo Add ES and GL 4.3 extensions */ namespace Extensions { -#ifndef MAGNUM_TARGET_GLES #ifndef DOXYGEN_GENERATING_OUTPUT #define _extension(prefix, vendor, extension, _requiredVersion, _coreVersion) \ struct extension { \ @@ -54,6 +58,7 @@ namespace Extensions { /* IMPORTANT: don't forget to add new extensions also in Context.cpp */ namespace GL { + #ifndef MAGNUM_TARGET_GLES #line 1 namespace AMD { _extension(GL,AMD,vertex_shader_layer, GL210, None) // #417 @@ -70,6 +75,7 @@ namespace GL { _extension(GL,ARB,draw_instanced, GL210, GL310) // #44 _extension(GL,ARB,geometry_shader4, GL210, GL320) // #47 _extension(GL,ARB,instanced_arrays, GL210, GL330) // #49 + _extension(GL,ARB,map_buffer_range, GL210, GL300) // #50 _extension(GL,ARB,texture_buffer_object, GL210, GL310) // #51 _extension(GL,ARB,texture_rg, GL210, GL300) // #53 _extension(GL,ARB,uniform_buffer_object, GL210, GL310) // #57 @@ -121,6 +127,27 @@ namespace GL { _extension(GL,ARB,shader_atomic_counters, GL300, GL420) // #114 _extension(GL,ARB,shader_image_load_store, GL300, GL420) // #115 _extension(GL,ARB,texture_storage, GL210, GL420) // #117 + _extension(GL,ARB,arrays_of_arrays, GL210, GL430) // #120 + _extension(GL,ARB,clear_buffer_object, GL210, GL430) // #121 + _extension(GL,ARB,compute_shader, GL420, GL430) // #122 + _extension(GL,ARB,copy_image, GL210, GL430) // #123 + _extension(GL,ARB,texture_view, GL210, GL430) // #124 + _extension(GL,ARB,vertex_attrib_binding, GL210, GL430) // #125 + _extension(GL,ARB,ES3_compatibility, GL330, GL430) // #127 + _extension(GL,ARB,explicit_uniform_location, GL210, GL430) // #128 + _extension(GL,ARB,fragment_layer_viewport, GL300, GL430) // #129 + _extension(GL,ARB,framebuffer_no_attachments, GL210, GL430) // #130 + _extension(GL,ARB,internalformat_query2, GL210, GL430) // #131 + _extension(GL,ARB,invalidate_subdata, GL210, GL430) // #132 + _extension(GL,ARB,multi_draw_indirect, GL310, GL430) // #133 + _extension(GL,ARB,program_interface_query, GL210, GL430) // #134 + _extension(GL,ARB,robust_buffer_access_behavior,GL210, GL430) // #135 + _extension(GL,ARB,shader_image_size, GL420, GL430) // #136 + _extension(GL,ARB,shader_storage_buffer_object, GL400, GL430) // #137 + _extension(GL,ARB,stencil_texturing, GL210, GL430) // #138 + _extension(GL,ARB,texture_buffer_range, GL210, GL430) // #139 + _extension(GL,ARB,texture_query_levels, GL300, GL430) // #140 + _extension(GL,ARB,texture_storage_multisample, GL210, GL430) // #141 } namespace EXT { _extension(GL,EXT,texture_filter_anisotropic, GL210, None) // #187 _extension(GL,EXT,framebuffer_object, GL210, GL300) // #310 @@ -142,6 +169,8 @@ namespace GL { _extension(GL,GREMEDY,string_marker, GL210, None) // #311 } namespace INTEL { /* INTEL_map_texture not supported */ // #429 + } namespace KHR { + _extension(GL,KHR,debug, GL210, GL430) // #119 } namespace NV { _extension(GL,NV,half_float, GL210, GL300) // #283 _extension(GL,NV,primitive_restart, GL210, GL310) // #285 @@ -149,10 +178,60 @@ namespace GL { _extension(GL,NV,conditional_render, GL210, GL300) // #346 /* NV_draw_texture not supported */ // #430 } + /* IMPORTANT: if this line is > 188 (57 + size), don't forget to update array size in Context.h */ + #else + #line 1 + namespace ANGLE { + _extension(GL,ANGLE,framebuffer_blit, GLES200, GLES300) // #83 + } namespace APPLE { + _extension(GL,APPLE,framebuffer_multisample, GLES200, GLES300) // #78 + _extension(GL,APPLE,texture_format_BGRA8888, GLES200, None) // #79 + } namespace ARM { + _extension(GL,ARM,rgba8, GLES200, GLES300) // #82 + } namespace EXT { + _extension(GL,EXT,texture_filter_anisotropic, GLES200, None) // #41 + _extension(GL,EXT,texture_type_2_10_10_10_REV, GLES200, GLES300) // #42 + _extension(GL,EXT,texture_format_BGRA8888, GLES200, None) // #51 + _extension(GL,EXT,discard_framebuffer, GLES200, GLES300) // #64 + _extension(GL,EXT,blend_minmax, GLES200, GLES300) // #65 + _extension(GL,EXT,read_format_bgra, GLES200, None) // #66 + _extension(GL,EXT,debug_marker, GLES200, None) // #99 + _extension(GL,EXT,occlusion_query_boolean, GLES200, GLES300) // #100 + _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,texture_storage, GLES200, GLES300) // #108 + _extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121 + } namespace NV { + _extension(GL,NV,draw_buffers, GLES200, GLES300) // #91 + _extension(GL,NV,read_buffer, GLES200, GLES300) // #93 + _extension(GL,NV,read_buffer_front, GLES200, None) // #93 + _extension(GL,NV,read_depth, GLES200, GLES300) // #94 + _extension(GL,NV,read_stencil, GLES200, None) // #94 + _extension(GL,NV,read_depth_stencil, GLES200, GLES300) // #94 + } namespace OES { + _extension(GL,OES,depth24, GLES200, GLES300) // #24 + _extension(GL,OES,depth32, GLES200, None) // #25 + _extension(GL,OES,element_index_uint, GLES200, GLES300) // #26 + _extension(GL,OES,mapbuffer, GLES200, None) // #29 + _extension(GL,OES,rgb8_rgba8, GLES200, GLES300) // #30 + _extension(GL,OES,stencil1, GLES200, None) // #31 + _extension(GL,OES,stencil4, GLES200, None) // #32 + _extension(GL,OES,texture_3D, GLES200, None) // #34 + _extension(GL,OES,texture_half_float_linear, GLES200, GLES300) // #35 + _extension(GL,OES,texture_float_linear, GLES200, GLES300) // #35 + _extension(GL,OES,texture_half_float, GLES200, GLES300) // #36 + _extension(GL,OES,texture_float, GLES200, GLES300) // #36 + _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,vertex_array_object, GLES200, GLES300) // #71 + _extension(GL,OES,required_internalformat, GLES200, GLES300) // #? + } + #endif } #undef _extension #endif -#endif } diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index f63c9915f..01c0a7d5f 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -1,65 +1,174 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Framebuffer.h" -#include "BufferedImage.h" +#include "BufferImage.h" +#include "Context.h" +#include "Extensions.h" #include "Image.h" +#include "Renderbuffer.h" +#include "Texture.h" + +#include "Implementation/State.h" +#include "Implementation/FramebufferState.h" namespace Magnum { +Framebuffer::RenderbufferImplementation Framebuffer::renderbufferImplementation = &Framebuffer::renderbufferImplementationDefault; +#ifndef MAGNUM_TARGET_GLES +Framebuffer::Texture1DImplementation Framebuffer::texture1DImplementation = &Framebuffer::texture1DImplementationDefault; +#endif +Framebuffer::Texture2DImplementation Framebuffer::texture2DImplementation = &Framebuffer::texture2DImplementationDefault; +Framebuffer::Texture3DImplementation Framebuffer::texture3DImplementation = &Framebuffer::texture3DImplementationDefault; + +const Framebuffer::DrawAttachment Framebuffer::DrawAttachment::None = Framebuffer::DrawAttachment(GL_NONE); +const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Depth = Framebuffer::BufferAttachment(GL_DEPTH_ATTACHMENT); +const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Stencil = Framebuffer::BufferAttachment(GL_STENCIL_ATTACHMENT); #ifndef MAGNUM_TARGET_GLES2 -void Framebuffer::mapDefaultForDraw(std::initializer_list attachments) { +const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::DepthStencil = Framebuffer::BufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT); +#endif +const Framebuffer::InvalidationAttachment Framebuffer::InvalidationAttachment::Depth = Framebuffer::InvalidationAttachment(GL_DEPTH_ATTACHMENT); +const Framebuffer::InvalidationAttachment Framebuffer::InvalidationAttachment::Stencil = Framebuffer::InvalidationAttachment(GL_STENCIL_ATTACHMENT); + +Framebuffer::Framebuffer(const Rectanglei& viewport) { + _viewport = viewport; + + glGenFramebuffers(1, &_id); +} + +Framebuffer::~Framebuffer() { + /* If bound, remove itself from state */ + Implementation::FramebufferState* state = Context::current()->state()->framebuffer; + if(state->readBinding == _id) state->readBinding = 0; + if(state->drawBinding == _id) state->drawBinding = 0; + + glDeleteFramebuffers(1, &_id); +} + +Framebuffer* Framebuffer::mapForDraw(std::initializer_list> attachments) { + /* Max attachment location */ + std::size_t max = 0; + for(const auto& attachment: attachments) + if(attachment.first > max) max = attachment.first; + + /* Create linear array from associative */ + GLenum* _attachments = new GLenum[max+1]; + std::fill_n(_attachments, max, GL_NONE); + for(const auto& attachment: attachments) + _attachments[attachment.first] = GLenum(attachment.second); + + (this->*drawBuffersImplementation)(max+1, _attachments); + delete[] _attachments; + return this; +} + +void Framebuffer::invalidate(std::initializer_list attachments) { GLenum* _attachments = new GLenum[attachments.size()]; - for(auto it = attachments.begin(); it != attachments.end(); ++it) - _attachments[it-attachments.begin()] = static_cast(*it); + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments); - bindDefault(Target::Draw); - glDrawBuffers(attachments.size(), _attachments); delete[] _attachments; } -#endif -void Framebuffer::mapForDraw(std::initializer_list colorAttachments) { - GLenum* attachments = new GLenum[colorAttachments.size()]; - for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it) - attachments[it-colorAttachments.begin()] = *it + GL_COLOR_ATTACHMENT0; +void Framebuffer::invalidate(std::initializer_list attachments, const Rectanglei& rectangle) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments, rectangle); - bind(Target::Draw); - /** @todo Re-enable when extension wrangler is available for ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glDrawBuffers(colorAttachments.size(), attachments); + delete[] _attachments; +} + +Framebuffer* Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D* texture, Int mipLevel) { + /** @todo Check for texture target compatibility */ + (this->*texture2DImplementation)(attachment, GLenum(texture->target()), texture->id(), mipLevel); + return this; +} + +void Framebuffer::initializeContextBasedFunctionality(Context* context) { + #ifndef MAGNUM_TARGET_GLES + if(context->isExtensionSupported()) { + Debug() << "Framebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; + texture1DImplementation = &Framebuffer::texture1DImplementationDSA; + texture2DImplementation = &Framebuffer::texture2DImplementationDSA; + texture3DImplementation = &Framebuffer::texture3DImplementationDSA; + } + #else + static_cast(context); #endif - delete[] attachments; } -void Framebuffer::read(const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image) { - char* data = new char[AbstractImage::pixelSize(components, type)*size.product()]; - glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(components), static_cast(type), data); - image->setData(size, components, type, data); +void Framebuffer::renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer* renderbuffer) { + glFramebufferRenderbuffer(GLenum(bindInternal()), GLenum(attachment), GL_RENDERBUFFER, renderbuffer->id()); } -#ifndef MAGNUM_TARGET_GLES2 -void Framebuffer::read(const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage) { - /* If the buffer doesn't have sufficient size, resize it */ - /** @todo Explicitly reset also when buffer usage changes */ - if(image->size() != size || image->components() != components || image->type() != type) - image->setData(size, components, type, nullptr, usage); - - image->buffer()->bind(Buffer::Target::PixelPack); - glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(components), static_cast(type), nullptr); +#ifndef MAGNUM_TARGET_GLES +void Framebuffer::renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer* renderbuffer) { + glNamedFramebufferRenderbufferEXT(_id, GLenum(attachment), GL_RENDERBUFFER, renderbuffer->id()); +} + +void Framebuffer::texture1DImplementationDefault(BufferAttachment attachment, Texture1D* texture, GLint mipLevel) { + glFramebufferTexture1D(GLenum(bindInternal()), GLenum(attachment), static_cast(texture->target()), texture->id(), mipLevel); +} + +void Framebuffer::texture1DImplementationDSA(BufferAttachment attachment, Texture1D* texture, GLint mipLevel) { + glNamedFramebufferTexture1DEXT(_id, GLenum(attachment), GLenum(texture->target()), texture->id(), mipLevel); +} +#endif + +void Framebuffer::texture2DImplementationDefault(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel) { + glFramebufferTexture2D(GLenum(bindInternal()), GLenum(attachment), textureTarget, textureId, mipLevel); +} + +#ifndef MAGNUM_TARGET_GLES +void Framebuffer::texture2DImplementationDSA(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel) { + glNamedFramebufferTexture2DEXT(_id, GLenum(attachment), textureTarget, textureId, mipLevel); +} +#endif + +void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Texture3D* texture, GLint mipLevel, GLint layer) { + /** @todo Check for texture target compatibility */ + /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ + #ifndef MAGNUM_TARGET_GLES + glFramebufferTexture3D(GLenum(bindInternal()), GLenum(attachment), static_cast(texture->target()), texture->id(), mipLevel, layer); + #else + static_cast(attachment); + static_cast(texture); + static_cast(mipLevel); + static_cast(layer); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void Framebuffer::texture3DImplementationDSA(BufferAttachment attachment, Texture3D* texture, GLint mipLevel, GLint layer) { + glNamedFramebufferTexture3DEXT(_id, GLenum(attachment), GLenum(texture->target()), texture->id(), mipLevel, layer); } #endif diff --git a/src/Framebuffer.h b/src/Framebuffer.h index afe0a57f1..26a2029ea 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -1,1323 +1,456 @@ #ifndef Magnum_Framebuffer_h #define Magnum_Framebuffer_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Framebuffer */ -#include - -#include "AbstractImage.h" -#include "Buffer.h" +#include "AbstractFramebuffer.h" #include "CubeMapTexture.h" -#include "Color.h" -#include "Renderbuffer.h" namespace Magnum { -/** @nosubgrouping +/** @brief %Framebuffer -Provides operations with framebuffers (configuring, clearing, blitting...) and -creation and attaching of named framebuffers. -@todo @extension{ARB,viewport_array} -*/ -class MAGNUM_EXPORT Framebuffer { - Framebuffer(const Framebuffer& other) = delete; - Framebuffer(Framebuffer&& other) = delete; - Framebuffer& operator=(const Framebuffer& other) = delete; - Framebuffer& operator=(Framebuffer&& other) = delete; - - public: - /** - * @brief Affected polygon facing for culling, stencil operations and masks - * - * @see setFaceCullingMode(), - * setStencilFunction(PolygonFacing, StencilFunction, GLint, GLuint), - * setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation), - * setStencilMask(PolygonFacing, GLuint) - */ - enum class PolygonFacing: GLenum { - Front = GL_FRONT, /**< Front-facing polygons */ - Back = GL_BACK, /**< Back-facing polygons */ - FrontAndBack = GL_FRONT_AND_BACK /**< Front- and back-facing polygons */ - }; - - /** @{ @name Framebuffer features */ - - /** - * @brief Features - * - * If not specified otherwise, all features are disabled by default. - * @see setFeature() - */ - enum class Feature: GLenum { - /** - * Blending - * @see setBlendEquation(), setBlendFunction(), setBlendColor() - */ - Blending = GL_BLEND, - - #ifndef MAGNUM_TARGET_GLES - /** - * Logical operation - * @see setLogicOperation() - * @requires_gl Logical operations on framebuffer are not - * available in OpenGL ES. - */ - LogicOperation = GL_COLOR_LOGIC_OP, - - /** - * 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 - - /** - * Scissor test - * @see setScissor() - */ - ScissorTest = GL_SCISSOR_TEST, - DepthTest = GL_DEPTH_TEST, /**< Depth test */ - StencilTest = GL_STENCIL_TEST, /**< Stencil test */ - Dithering = GL_DITHER, /**< Dithering (enabled by default) */ - FaceCulling = GL_CULL_FACE /**< Back face culling */ - }; - - /** - * @brief Set feature - * - * @see @fn_gl{Enable}/@fn_gl{Disable} - */ - inline static void setFeature(Feature feature, bool enabled) { - enabled ? glEnable(static_cast(feature)) : glDisable(static_cast(feature)); - } - - /** - * @brief Which polygon facing to cull - * - * 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} - */ - inline static void setFaceCullingMode(PolygonFacing mode) { - glCullFace(static_cast(mode)); - } - - /** - * @brief Set viewport size - * - * Call when window size changes. - * @see @fn_gl{Viewport} - */ - inline static void setViewport(const Math::Vector2& position, const Math::Vector2& size) { - glViewport(position.x(), position.y(), size.x(), size.y()); - } - - /*@}*/ - - /** @{ @name Clearing the framebuffer */ - - /** - * @brief Mask for clearing - * - * @see ClearMask, clear(), clear(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 */ - typedef Corrade::Containers::EnumSet ClearMask; - - /** - * @brief Clear specified buffers in framebuffer - * - * @see clear(), setClearColor(), setClearDepth(), setClearStencil(), - * @fn_gl{Clear} - * @todo Clearing only given draw buffer - */ - inline static void clear(ClearMask mask) { glClear(static_cast(mask)); } - - /** - * @brief Set clear color - * - * Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`. - * @see @fn_gl{ClearColor} - */ - inline static void setClearColor(const Color4<>& color) { - glClearColor(color.r(), color.g(), color.b(), color.a()); - } - - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Set clear depth - * - * Initial value is `1.0`. - * @see @fn_gl{ClearDepth} - * @requires_gl See setClearDepth(GLfloat), which is available in OpenGL ES. - */ - inline static void setClearDepth(GLdouble depth) { glClearDepth(depth); } - #endif - - /** - * @overload - * - * @see @fn_gl{ClearDepth} - * @requires_gl41 Extension @extension{ARB,ES2_compatibility} - * @todo Call double version if the extension is not available - */ - inline static void setClearDepth(GLfloat depth) { glClearDepthf(depth); } - - /** - * @brief Set clear stencil - * - * Initial value is `0`. - * @see @fn_gl{ClearStencil} - */ - inline static void setClearStencil(GLint stencil) { glClearStencil(stencil); } - - /*@}*/ - - /** @{ @name Scissor operations */ - - /** - * @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} - */ - inline static void setScissor(const Math::Vector2& bottomLeft, const Math::Vector2& size) { - glScissor(bottomLeft.x(), bottomLeft.y(), size.x(), size.y()); - } - - /*@}*/ - - /** @{ @name Stencil operations */ - - /** - * @brief Stencil function - * - * @see setStencilFunction() - */ - enum class StencilFunction: GLenum { - Never = GL_NEVER, /**< Never pass the test. */ - Always = GL_ALWAYS, /**< Always pass the test. */ - Less = GL_LESS, /**< Pass when reference value is less than buffer value. */ - LessOrEqual = GL_LEQUAL, /**< Pass when reference value is less than or equal to buffer value. */ - Equal = GL_EQUAL, /**< Pass when reference value is equal to buffer value. */ - NotEqual = GL_NOTEQUAL, /**< Pass when reference value is not equal to buffer value. */ - GreaterOrEqual = GL_GEQUAL, /**< Pass when reference value is greater than or equal to buffer value. */ - Greater = GL_GREATER /**< Pass when reference value is greater than buffer value. */ - }; - - /** - * @brief Stencil operation - * - * @see setStencilOperation() - */ - enum class StencilOperation: GLenum { - Keep = GL_KEEP, /**< Keep the current value. */ - Zero = GL_ZERO, /**< Set the stencil buffer value to `0`. */ - - /** - * Set the stencil value to reference value specified by - * setStencilFunction(). - */ - Replace = GL_REPLACE, - - /** - * Increment the current stencil buffer value, clamp to maximum - * possible value on overflow. - */ - Increment = GL_INCR, - - /** - * Increment the current stencil buffer value, wrap to zero on - * overflow. - */ - IncrementWrap = GL_INCR_WRAP, - - /** - * Increment the current stencil buffer value, clamp to minimum - * possible value on underflow. - */ - Decrement = GL_DECR, - - /** - * Decrement the current stencil buffer value, wrap to maximum - * possible value on underflow. - */ - DecrementWrap = GL_DECR_WRAP, - - /** - * Bitwise invert the current stencil buffer value. - */ - Invert = GL_INVERT - }; - - /** - * @brief Set stencil function - * @param facing Affected polygon facing - * @param function Stencil function. Initial value is - * `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, GLint, GLuint), - * @fn_gl{StencilFuncSeparate} - */ - inline static void setStencilFunction(PolygonFacing facing, StencilFunction function, GLint referenceValue, GLuint mask) { - glStencilFuncSeparate(static_cast(facing), static_cast(function), referenceValue, mask); - } - - /** - * @brief Set stencil function - * - * The same as setStencilFunction(PolygonFacing, StencilFunction, GLint, GLuint) - * with `facing` set to `PolygonFacing::FrontAndBack`. - * @see @fn_gl{StencilFunc} - */ - inline static void setStencilFunction(StencilFunction function, GLint referenceValue, GLuint mask) { - glStencilFunc(static_cast(function), referenceValue, mask); - } - - /** - * @brief Set stencil operation - * @param facing Affected polygon facing - * @param stencilFail Action when stencil test fails - * @param depthFail Action when stencil test passes, but depth - * test fails - * @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} - */ - 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)); - } - - /** - * @brief Set stencil operation - * - * The same as setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation) - * with `facing` set to `PolygonFacing::FrontAndBack`. - * @see @fn_gl{StencilOp} - */ - inline static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) { - glStencilOp(static_cast(stencilFail), static_cast(depthFail), static_cast(depthPass)); - } - - /*@}*/ - - /** @{ @name Depth testing */ - - /** - * @brief Depth function - * - * @see setDepthFunction() - */ - typedef StencilFunction DepthFunction; - - /** - * @brief Set depth function - * - * Initial value is `DepthFunction::Less`. - * @attention You have to enable depth test with setFeature() first. - * @see @fn_gl{DepthFunc} - */ - inline static void setDepthFunction(DepthFunction function) { - glDepthFunc(static_cast(function)); - } - - /*@}*/ - - /** @{ @name Masking writes */ - - /** - * @brief Mask color writes - * - * Set to `false` to disallow writing to given color channel. Initial - * values are all `true`. - * @see @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); - } - - /** - * @brief Mask depth writes - * - * Set to `false` to disallow writing to depth buffer. Initial value - * is `true`. - * @see @fn_gl{DepthMask} - */ - inline static void setDepthMask(GLboolean allow) { - glDepthMask(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(GLuint), @fn_gl{StencilMaskSeparate} - */ - inline static void setStencilMask(PolygonFacing facing, GLuint allowBits) { - glStencilMaskSeparate(static_cast(facing), allowBits); - } - - /** - * @brief Mask stencil writes - * - * The same as setStencilMask(PolygonFacing, GLuint) with `facing` set - * to `PolygonFacing::FrontAndBack`. - * @see @fn_gl{StencilMask} - */ - inline static void setStencilMask(GLuint allowBits) { - glStencilMask(allowBits); - } - - /*@}*/ - - /** @{ @name Blending - * You have to enable blending with setFeature() first. - * @todo Blending for given draw buffer - */ - - /** - * @brief Blend equation - * - * @see setBlendEquation() - */ - enum class BlendEquation: GLenum { - Add = GL_FUNC_ADD, /**< `source + destination` */ - Subtract = GL_FUNC_SUBTRACT, /**< `source - destination` */ - ReverseSubtract = GL_FUNC_REVERSE_SUBTRACT /**< `destination - source` */ - - #ifndef MAGNUM_TARGET_GLES2 - , - /** - * `min(source, destination)` - * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax} - */ - Min = GL_MIN, - - /** - * `max(source, destination)` - * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax} - */ - Max = GL_MAX - #endif - }; - - /** - * @brief Blend function - * - * @see setBlendFunction() - */ - enum class BlendFunction: GLenum { - /** Zero (@f$ RGB = (0.0, 0.0, 0.0); A = 0.0 @f$) */ - Zero = GL_ZERO, - - /** One (@f$ RGB = (1.0, 1.0, 1.0); A = 1.0 @f$) */ - One = GL_ONE, - - /** - * Constant color (@f$ RGB = (R_c, G_c, B_c); A = A_c @f$) - * - * @see setBlendColor() - */ - ConstantColor = GL_CONSTANT_COLOR, - - /** - * One minus constant color (@f$ RGB = (1.0 - R_c, 1.0 - G_c, 1.0 - B_c); A = 1.0 - A_c @f$) - * - * @see setBlendColor() - */ - OneMinusConstantColor = GL_ONE_MINUS_CONSTANT_COLOR, - - /** - * Constant alpha (@f$ RGB = (A_c, A_c, A_c); A = A_c @f$) - * - * @see setBlendColor() - */ - ConstantAlpha = GL_CONSTANT_ALPHA, - - /** - * One minus constant alpha (@f$ RGB = (1.0 - A_c, 1.0 - A_c, 1.0 - A_c); A = 1.0 - A_c @f$) - * - * @see setBlendColor() - */ - OneMinusConstantAlpha = GL_ONE_MINUS_CONSTANT_ALPHA, - - /** Source color (@f$ RGB = (R_{s0}, G_{s0}, B_{s0}); A = A_{s0} @f$) */ - SourceColor = GL_SRC_COLOR, - - #ifndef MAGNUM_TARGET_GLES - /** - * Second source color (@f$ RGB = (R_{s1}, G_{s1}, B_{s1}); A = A_{s1} @f$) - * - * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() - * @requires_gl33 Extension @extension{ARB,blend_func_extended} - * @requires_gl Multiple blending inputs are not available in - * OpenGL ES. - */ - SecondSourceColor = GL_SRC1_COLOR, - #endif - - /** - * One minus source color (@f$ RGB = (1.0 - R_{s0}, 1.0 - G_{s0}, 1.0 - B_{s0}); A = 1.0 - A_{s0} @f$) - */ - OneMinusSourceColor = GL_ONE_MINUS_SRC_COLOR, - - #ifndef MAGNUM_TARGET_GLES - /** - * One minus second source color (@f$ RGB = (1.0 - R_{s1}, 1.0 - G_{s1}, 1.0 - B_{s1}); A = 1.0 - A_{s1} @f$) - * - * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() - * @requires_gl33 Extension @extension{ARB,blend_func_extended} - * @requires_gl Multiple blending inputs are not available in - * OpenGL ES. - */ - OneMinusSecondSourceColor = GL_ONE_MINUS_SRC1_COLOR, - #endif - - /** Source alpha (@f$ RGB = (A_{s0}, A_{s0}, A_{s0}); A = A_{s0} @f$) */ - SourceAlpha = GL_SRC_ALPHA, - - /** - * Saturate source alpha (@f$ RGB = (f, f, f); A = 1.0; f = min(A_s, 1.0 - A_d) @f$) - * - * Can be used only in source parameter of setBlendFunction(). - */ - SourceAlphaSaturate = GL_SRC_ALPHA_SATURATE, - - #ifndef MAGNUM_TARGET_GLES - /** - * Second source alpha (@f$ RGB = (A_{s1}, A_{s1}, A_{s1}); A = A_{s1} @f$) - * - * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() - * @requires_gl33 Extension @extension{ARB,blend_func_extended} - * @requires_gl Multiple blending inputs are not available in - * OpenGL ES. - */ - SecondSourceAlpha = GL_SRC1_ALPHA, - #endif - - /** - * One minus source alpha (@f$ RGB = (1.0 - A_{s0}, 1.0 - A_{s0}, 1.0 - A_{s0}); A = 1.0 - A_{s0} @f$) - */ - OneMinusSourceAlpha = GL_ONE_MINUS_SRC_ALPHA, - - #ifndef MAGNUM_TARGET_GLES - /** - * One minus second source alpha (@f$ RGB = (1.0 - A_{s1}, 1.0 - A_{s1}, 1.0 - A_{s1}); A = 1.0 - A_{s1} @f$) - * - * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() - * @requires_gl33 Extension @extension{ARB,blend_func_extended} - * @requires_gl Multiple blending inputs are not available in - * OpenGL ES. - */ - OneMinusSecondSourceAlpha = GL_ONE_MINUS_SRC1_ALPHA, - #endif - - /** Destination color (@f$ RGB = (R_d, G_d, B_d); A = A_d @f$) */ - DestinationColor = GL_DST_COLOR, - - /** - * One minus source color (@f$ RGB = (1.0 - R_d, 1.0 - G_d, 1.0 - B_d); A = 1.0 - A_d @f$) - */ - OneMinusDestinationColor = GL_ONE_MINUS_DST_COLOR, +Unlike DefaultFramebuffer, which is used for on-screen rendering, this class +is used for off-screen rendering, usable either in windowless applications, +texture generation or for various post-processing effects. + +@section Framebuffer-usage Example usage + +See @ref DefaultFramebuffer-usage "DefaultFramebuffer documentation" for +introduction. Imagine you have shader with multiple outputs (e.g. for deferred +rendering). You want to render them off-screen to textures and then use the +textures for actual on-screen rendering. First you need to create the +framebuffer with the same viewport as default framebuffer and attach textures +and renderbuffers to desired outputs: +@code +Framebuffer framebuffer(defaultFramebuffer.viewportPosition(), defaultFramebuffer.viewportSize()); +Texture2D color, normal; +Renderbuffer depthStencil; + +// configure the textures and allocate texture memory... + +framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), &color); +framebuffer.attachTexture2D(Framebuffer::ColorAttachment(1), &normal); +framebuffer.attachRenderbuffer(Framebuffer::BufferAttachment::DepthStencil, &depthStencil); +@endcode + +Then you need to map outputs of your shader to color attachments in the +framebuffer: +@code +framebuffer.mapForDraw({{MyShader::ColorOutput, Framebuffer::ColorAttachment(0)}, + {MyShader::NormalOutput, Framebuffer::ColorAttachment(1)}}); +@endcode + +The actual @ref Platform::GlutApplication::drawEvent() "drawEvent()" might +look like this. First you clear all buffers you need, perform drawing to +off-screen framebuffer, then bind the default and render the textures on +screen: +@code +void drawEvent() { + defaultFramebuffer.clear(DefaultFramebuffer::Clear::Color) + framebuffer.clear(Framebuffer::Clear::Color|Framebuffer::Clear::Depth|Framebuffer::Clear::Stencil); + + framebuffer.bind(Framebuffer::Target::Draw); + // ... + + defaultFramebuffer.bind(DefaultFramebuffer::Target::Draw); + // ... +} +@endcode - /** Destination alpha (@f$ RGB = (A_d, A_d, A_d); A = A_d @f$) */ - DestinationAlpha = GL_DST_ALPHA, +@section Framebuffer-performance-optimization Performance optimizations - /** - * One minus source alpha (@f$ RGB = (1.0 - A_d, 1.0 - A_d, 1.0 - A_d); A = 1.0 - A_d @f$) - */ - OneMinusDestinationAlpha = GL_ONE_MINUS_DST_ALPHA - }; +See also @ref AbstractFramebuffer-performance-optimization "relevant section in AbstractFramebuffer". - /** - * @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} - */ - inline static void setBlendEquation(BlendEquation equation) { - glBlendEquation(static_cast(equation)); - } +If extension @extension{EXT,direct_state_access} is available, functions +mapForDraw(), mapForRead(), attachRenderbuffer(), attachTexture1D(), +attachTexture2D(), attachCubeMapTexture() and attachTexture3D() use DSA +to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See their respective +documentation for more information. - /** - * @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} - */ - inline static void setBlendEquation(BlendEquation rgb, BlendEquation alpha) { - glBlendEquationSeparate(static_cast(rgb), static_cast(alpha)); - } - - /** - * @brief Set blend function - * @param source How the source blending factor is computed - * from pixel value. Initial value is `BlendFunction::One`. - * @param destination How the destination blending factor is - * computed from framebuffer. Initial value is - * `BlendFunction::Zero`. - * - * @attention You have to enable blending with setFeature() first. - * @see setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction), - * @fn_gl{BlendFunc} - */ - inline static void setBlendFunction(BlendFunction source, BlendFunction destination) { - glBlendFunc(static_cast(source), static_cast(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} - */ - 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)); - } +@requires_gl30 %Extension @extension{EXT,framebuffer_object} +*/ +class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { + friend class Context; + public: /** - * @brief Set blend color + * @brief Color attachment * - * 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} + * @see Attachment, attachRenderbuffer(), attachTexture1D(), + * attachTexture2D(), attachCubeMapTexture(), attachTexture3D() */ - inline static void setBlendColor(const Color4<>& color) { - glBlendColor(color.r(), color.g(), color.b(), color.a()); - } + class ColorAttachment { + friend class Framebuffer; - /*@}*/ + public: + /** + * @brief Constructor + * @param id Color attachment id + */ + inline constexpr explicit ColorAttachment(UnsignedInt id): attachment(GL_COLOR_ATTACHMENT0 + id) {} - #ifndef MAGNUM_TARGET_GLES - /** @{ @name Logical operation */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit operator GLenum() const { return attachment; } + #endif - /** - * @brief Logical operation - * - * @see setLogicOperation() - * @requires_gl Logical operations on framebuffer are not available in - * OpenGL ES. - */ - enum class LogicOperation: GLenum { - Clear = GL_CLEAR, /**< `0` */ - Set = GL_SET, /**< `1` */ - Copy = GL_COPY, /**< `source` */ - CopyInverted = GL_COPY_INVERTED,/**< `~source` */ - Noop = GL_NOOP, /**< `destination` */ - Invert = GL_INVERT, /**< `~destination` */ - And = GL_AND, /**< `source & destination` */ - AndReverse = GL_AND_REVERSE, /**< `source & ~destination` */ - AndInverted = GL_AND_INVERTED, /**< `~source & destination` */ - Nand = GL_NAND, /**< `~(source & destination)` */ - Or = GL_OR, /**< `source | destination` */ - OrReverse = GL_OR_REVERSE, /**< `source | ~destination` */ - OrInverted = GL_OR_INVERTED, /**< `~source | destination` */ - Nor = GL_NOR, /**< `~(source | destination)` */ - Xor = GL_XOR, /**< `source ^ destination` */ - Equivalence = GL_EQUIV /**< `~(source ^ destination)` */ + private: + GLenum attachment; }; /** - * @brief Set logical operation + * @brief Draw attachment * - * @attention You have to enable logical operation with setFeature() first. - * @see @fn_gl{LogicOp} - * @requires_gl Logical operations on framebuffer are not available in - * OpenGL ES. + * @see mapForDraw() */ - inline static void setLogicOperation(LogicOperation operation) { - glLogicOp(static_cast(operation)); - } + class DrawAttachment { + public: + /** @brief No attachment */ + static const DrawAttachment None; - /*@}*/ - #endif + /** @brief Color attachment */ + inline constexpr /*implicit*/ DrawAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} - /** @{ @name Framebuffer creation and binding */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit operator GLenum() const { return attachment; } + #endif - /** - * @brief %Framebuffer target - * - * @see bind(), bindDefault() - * @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} - * or @es_extension{ANGLE,framebuffer_blit} - */ - #ifndef MAGNUM_TARGET_GLES2 - Read = GL_READ_FRAMEBUFFER, - #else - Read = GL_READ_FRAMEBUFFER_APPLE, - #endif + private: + inline constexpr explicit DrawAttachment(GLenum attachment): attachment(attachment) {} - /** - * For drawing only. - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample} - * or @es_extension{ANGLE,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. */ + GLenum attachment; }; - #ifndef MAGNUM_TARGET_GLES2 /** - * @brief Draw attachment for default framebuffer + * @brief %Buffer attachment * - * @see mapDefaultForDraw() - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 Draw attachments for default framebuffer are - * available only in OpenGL ES 3.0. + * @see attachRenderbuffer(), attachTexture1D(), attachTexture2D(), + * attachCubeMapTexture(), attachTexture3D() */ - enum class DefaultDrawAttachment: GLenum { - /** Don't use the output. */ - None = GL_NONE, + class BufferAttachment { + public: + /** @brief Depth buffer */ + static const BufferAttachment Depth; - #ifndef MAGNUM_TARGET_GLES - /** - * Write output to back left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackLeft = GL_BACK_LEFT, + /** @brief Stencil buffer */ + static const BufferAttachment Stencil; - /** - * Write output to back right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackRight = GL_BACK_RIGHT, + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Both depth and stencil buffer + * + * @requires_gles30 Combined depth and stencil attachment is + * not available in OpenGL ES 2.0. + */ + static const BufferAttachment DepthStencil; + #endif - /** - * Write output to front left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontLeft = GL_FRONT_LEFT, + /** @brief Color buffer */ + inline constexpr /*implicit*/ BufferAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} - /** - * Write output to front right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontRight = GL_FRONT_RIGHT, - #endif + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit operator GLenum() const { return attachment; } + #endif - /** - * Write output to back framebuffer. - * - * On desktop OpenGL, this is equal to - * @ref Magnum::Framebuffer::DefaultDrawAttachment "DefaultDrawAttachment::BackLeft". - */ - #ifdef MAGNUM_TARGET_GLES - Back = GL_BACK, - #else - Back = GL_BACK_LEFT, - #endif + private: + inline constexpr explicit BufferAttachment(GLenum attachment): attachment(attachment) {} - /** - * Write output to front framebuffer. - * - * On desktop OpenGL, this is equal to - * @ref Magnum::Framebuffer::DefaultDrawAttachment "DefaultDrawAttachment::FrontLeft". - */ - #ifdef MAGNUM_TARGET_GLES - Front = GL_FRONT - #else - Front = GL_FRONT_LEFT - #endif + GLenum attachment; }; - #endif /** - * @brief Read attachment for default framebuffer + * @brief Invalidation attachment * - * @see mapDefaultForRead() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + * @see invalidate() + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} */ - enum class DefaultReadAttachment: GLenum { - /** Don't read from any framebuffer */ - None = GL_NONE, - - #ifndef MAGNUM_TARGET_GLES - /** - * Read from back left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackLeft = GL_BACK_LEFT, - - /** - * Read from back right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackRight = GL_BACK_RIGHT, - - /** - * Read from front left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontLeft = GL_FRONT_LEFT, + class InvalidationAttachment { + public: + /** @brief Invalidate depth buffer */ + static const InvalidationAttachment Depth; - /** - * Read from front right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontRight = GL_FRONT_RIGHT, + /** @brief Invalidate stencil buffer */ + static const InvalidationAttachment Stencil; - /** - * Read from left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - Left = GL_LEFT, + /** @brief Invalidate color buffer */ + inline constexpr /*implicit*/ InvalidationAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} - /** - * Read from right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - Right = GL_RIGHT, - #endif + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit operator GLenum() const { return attachment; } + #endif - /** Read from back framebuffer. */ - Back = GL_BACK, + private: + inline constexpr explicit InvalidationAttachment(GLenum attachment): attachment(attachment) {} - /** - * Read from front framebuffer. - * @requires_es_extension %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} - */ - Front = GL_FRONT - - #ifndef MAGNUM_TARGET_GLES - , - - /** - * Read from front and back framebuffer. - * @requires_gl In OpenGL ES you must specify either - * @ref Magnum::Framebuffer::DefaultReadAttachment "DefaultReadAttachment::Front" - * or @ref Magnum::Framebuffer::DefaultReadAttachment "DefaultReadAttachment::Back". - */ - FrontAndBack = GL_FRONT_AND_BACK - #endif + GLenum attachment; }; /** * @brief Constructor * * Generates new OpenGL framebuffer. - * @see @fn_gl{GenFramebuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * @see setViewport(), @fn_gl{GenFramebuffers} */ - inline Framebuffer() { glGenFramebuffers(1, &_id); } + explicit Framebuffer(const Rectanglei& viewport); /** * @brief Destructor * * Deletes associated OpenGL framebuffer. * @see @fn_gl{DeleteFramebuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ - inline ~Framebuffer() { glDeleteFramebuffers(1, &_id); } + ~Framebuffer(); /** - * @brief Bind default framebuffer to given target - * @param target %Target + * @brief Map shader output to attachments + * @return Pointer to self (for method chaining) * - * @see @fn_gl{BindFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - inline static void bindDefault(Target target) { - glBindFramebuffer(static_cast(target), 0); - } - - /** - * @brief Bind framebuffer + * @p attachments is list of shader outputs mapped to framebuffer + * color attachment IDs. %Shader outputs which are not listed are not + * used, you can achieve the same by passing Framebuffer::DrawAttachment::None + * as color attachment ID. Example usage: + * @code + * framebuffer.mapForDraw({{MyShader::ColorOutput, Framebuffer::ColorAttachment(0)}, + * {MyShader::NormalOutput, Framebuffer::DrawAttachment::None}}); + * @endcode * - * @see @fn_gl{BindFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or + * @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} + * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ - inline void bind(Target target) { - glBindFramebuffer(static_cast(target), _id); - } + Framebuffer* mapForDraw(std::initializer_list> attachments); - #ifndef MAGNUM_TARGET_GLES2 /** - * @brief Map given attachments of default framebuffer for drawing - * @param attachments Default attachments. If any value is - * DefaultAttachment::None, given output is not used. + * @brief Map shader output to attachment + * @param attachment Draw attachment + * @return Pointer to self (for method chaining) * - * If used for mapping output of fragment shader, the order must be as - * specified by the shader (see AbstractShaderProgram documentation). - * If used for blit(), the order is not important. Each used attachment - * should have either renderbuffer or texture attached for writing to - * work properly. - * @see mapForDraw(), mapDefaultForRead(), bindDefault(), @fn_gl{DrawBuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 Draw attachments for default framebuffer are - * available only in OpenGL ES 3.0. - */ - static void mapDefaultForDraw(std::initializer_list attachments); - #endif - - /** - * @brief Map given color attachments of current framebuffer for drawing - * @param colorAttachments Color attachment IDs. If any value is -1, - * given output is not used. + * Similar to above function, can be used in cases when shader has + * only one (unnamed) output. * - * If used for mapping output of fragment shader, the order must be as - * specified by the shader (see AbstractShaderProgram documentation). - * If used for blit(), the order is not important. Each used attachment - * should have either renderbuffer or texture attached for writing to - * work properly. - * @see mapDefaultForDraw(), mapForRead(), bind(), @fn_gl{DrawBuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or + * @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ - void mapForDraw(std::initializer_list colorAttachments); - - /** - * @brief Map given attachment of default framebuffer for reading - * @param attachment Default attachment - * - * Each used attachment should have either renderbuffer or texture - * attached to work properly. - * @see mapForRead(), mapDefaultForDraw(), bindDefault(), @fn_gl{ReadBuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} - */ - inline static void mapDefaultForRead(DefaultReadAttachment attachment) { - bindDefault(Target::Read); - /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glReadBuffer(static_cast(attachment)); - #else - static_cast(attachment); - #endif + inline Framebuffer* mapForDraw(DrawAttachment attachment) { + (this->*drawBufferImplementation)(GLenum(attachment)); + return this; } /** - * @brief Map given color attachment of current framebuffer for reading - * @param colorAttachment Color attachment ID + * @brief Invalidate framebuffer + * @param attachments Attachments to invalidate * - * The color attachment should have either renderbuffer or texture - * attached for reading to work properly. - * @see mapDefaultForRead(), mapForDraw(), bind(), @fn_gl{ReadBuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateFramebuffer} or @fn_gles_extension{DiscardFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use + * clear() instead where the extension is not supported. + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. + * Use clear() instead where the extension is not supported. */ - inline void mapForRead(std::uint8_t colorAttachment) { - bind(Target::Read); - /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachment); - #else - static_cast(colorAttachment); - #endif - } - - /*@}*/ - - /** @{ @name Attaching textures and renderbuffers */ + void invalidate(std::initializer_list attachments); /** - * @brief Attachment for depth/stencil part of fragment shader output + * @brief Invalidate framebuffer rectangle + * @param attachments Attachments to invalidate + * @param rectangle %Rectangle to invalidate * - * @see attachRenderbuffer(Target, DepthStencilAttachment, Renderbuffer*), - * attachTexture1D(Target, DepthStencilAttachment, Texture1D*, GLint), - * attachTexture2D(Target, DepthStencilAttachment, Texture2D*, GLint), - * attachCubeMapTexture(Target, DepthStencilAttachment, CubeMapTexture*, CubeMapTexture::Coordinate, GLint), - * attachTexture3D(Target, DepthStencilAttachment, Texture3D*, GLint, GLint) - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateSubFramebuffer} or @fn_gles_extension{DiscardSubFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use + * clear() instead where the extension is not supported. + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. + * Use clear() instead where the extension is not supported. */ - enum class DepthStencilAttachment: GLenum { - Depth = GL_DEPTH_ATTACHMENT, /**< Depth output only. */ - - Stencil = GL_STENCIL_ATTACHMENT /**< Stencil output only. */ - - #ifndef MAGNUM_TARGET_GLES2 - , - /** - * Both depth and stencil output. - * @requires_gles30 Combined depth and stencil attachment is not - * available in OpenGL ES 2.0. - */ - DepthStencil = GL_DEPTH_STENCIL_ATTACHMENT - #endif - }; + void invalidate(std::initializer_list attachments, const Rectanglei& rectangle); /** - * @brief Attach renderbuffer to given framebuffer depth/stencil attachment - * @param target %Target - * @param depthStencilAttachment Depth/stencil attachment - * @param renderbuffer %Renderbuffer + * @brief Map given color attachment for reading + * @param attachment Color attachment + * @return Pointer to self (for method chaining) * - * @see bind(), @fn_gl{FramebufferRenderbuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or + * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} + * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - inline void attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { - /** @todo Check for internal format compatibility */ - bind(target); - glFramebufferRenderbuffer(static_cast(target), static_cast(depthStencilAttachment), GL_RENDERBUFFER, renderbuffer->id()); + inline Framebuffer* mapForRead(ColorAttachment attachment) { + (this->*readBufferImplementation)(GLenum(attachment)); + return this; } /** - * @brief Attach renderbuffer to given framebuffer color attachment - * @param target %Target - * @param colorAttachment Color attachment ID (number between 0 and 15) + * @brief Attach renderbuffer to given buffer + * @param attachment %Buffer attachment * @param renderbuffer %Renderbuffer + * @return Pointer to self (for method chaining) * - * @see bind(), @fn_gl{FramebufferRenderbuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or + * @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} */ - inline void attachRenderbuffer(Target target, std::uint8_t colorAttachment, Renderbuffer* renderbuffer) { - /** @todo Check for internal format compatibility */ - bind(target); - glFramebufferRenderbuffer(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, GL_RENDERBUFFER, renderbuffer->id()); + inline Framebuffer* attachRenderbuffer(BufferAttachment attachment, Renderbuffer* renderbuffer) { + (this->*renderbufferImplementation)(attachment, renderbuffer); + return this; } #ifndef MAGNUM_TARGET_GLES /** - * @brief Attach 1D texture to given framebuffer depth/stencil attachment - * @param target %Target - * @param depthStencilAttachment Depth/stencil attachment + * @brief Attach 1D texture to given buffer + * @param attachment %Buffer attachment * @param texture 1D texture - * @param mipLevel Mip level - * - * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * @param level Mip level + * @return Pointer to self (for method chaining) + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ - inline void attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - /** @todo Check for texture target compatibility */ - bind(target); - glFramebufferTexture1D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel); - } - - /** - * @brief Attach 1D texture to given framebuffer color attachment - * @param target %Target - * @param colorAttachment Color attachment ID (number between 0 and 15) - * @param texture 1D texture - * @param mipLevel Mip level - * - * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gl Only 2D and 3D textures are available in OpenGL ES. - */ - inline void attachTexture1D(Target target, std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - /** @todo Check for texture target compatibility */ - bind(target); - glFramebufferTexture1D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel); + inline Framebuffer* attachTexture1D(BufferAttachment attachment, Texture1D* texture, Int level) { + (this->*texture1DImplementation)(attachment, texture, level); + return this; } #endif /** - * @brief Attach 2D texture to given framebuffer depth/stencil attachment - * @param target %Target - * @param depthStencilAttachment Depth/stencil attachment - * @param texture 2D texture - * @param mipLevel Mip level. For rectangle textures it - * should be always 0. - * - * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - inline void attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - /** @todo Check for texture target compatibility */ - bind(target); - glFramebufferTexture2D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel); - } - - /** - * @brief Attach 2D texture to given framebuffer color attachment - * @param target %Target - * @param colorAttachment Color attachment ID (number between 0 and 15) + * @brief Attach 2D texture to given buffer + * @param attachment %Buffer attachment * @param texture 2D texture - * @param mipLevel Mip level. For rectangle textures it - * should be always 0. + * @param level Mip level + * @return Pointer to self (for method chaining) * - * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - inline void attachTexture2D(Target target, std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - /** @todo Check for texture target compatibility */ - bind(target); - glFramebufferTexture2D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel); - } + Framebuffer* attachTexture2D(BufferAttachment attachment, Texture2D* texture, Int level); /** - * @brief Attach cube map texture to given framebuffer depth/stencil attachment - * @param target %Target - * @param depthStencilAttachment Depth/stencil attachment + * @brief Attach cube map texture to given buffer + * @param attachment %Buffer attachment * @param texture Cube map texture * @param coordinate Cube map coordinate - * @param mipLevel Mip level + * @param level Mip level + * @return Pointer to self (for method chaining) * - * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - inline void attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - bind(target); - glFramebufferTexture2D(static_cast(target), static_cast(depthStencilAttachment), static_cast(coordinate), texture->id(), mipLevel); + inline Framebuffer* attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, Int level) { + (this->*texture2DImplementation)(attachment, GLenum(coordinate), texture->id(), level); + return this; } /** - * @brief Attach cube map texture to given framebuffer color attachment - * @param target %Target - * @param colorAttachment Color attachment ID (number between 0 and 15) - * @param texture Cube map texture - * @param coordinate Cube map coordinate - * @param mipLevel Mip level - * - * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - inline void attachCubeMapTexture(Target target, std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - bind(target); - glFramebufferTexture2D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(coordinate), texture->id(), mipLevel); - } - - /** - * @brief Attach 3D texture to given framebuffer depth/stencil attachment - * @param target %Target - * @param depthStencilAttachment Depth/stencil attachment + * @brief Attach 3D texture to given buffer + * @param attachment %Buffer attachment * @param texture 3D texture - * @param mipLevel Mip level + * @param level Mip level * @param layer Layer of 2D image within a 3D texture + * @return Pointer to self (for method chaining) * - * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_es_extension %Extension @es_extension{OES,texture_3D} - */ - inline void attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { - /** @todo Check for internal format compatibility */ - /** @todo Check for texture target compatibility */ - bind(target); - /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ - #ifndef MAGNUM_TARGET_GLES - glFramebufferTexture3D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel, layer); - #else - static_cast(depthStencilAttachment); - static_cast(texture); - static_cast(mipLevel); - static_cast(layer); - #endif - } - - /** - * @brief Attach 3D texture to given framebuffer color attachment - * @param target %Target - * @param colorAttachment Color attachment ID (number between 0 and 15) - * @param texture 3D texture - * @param mipLevel Mip level - * @param layer Layer of 2D image within a 3D texture. - * - * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ - inline void attachTexture3D(Target target, std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { - /** @todo Check for internal format compatibility */ + inline Framebuffer* attachTexture3D(BufferAttachment attachment, Texture3D* texture, Int level, Int layer) { /** @todo Check for texture target compatibility */ - bind(target); - /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ - #ifndef MAGNUM_TARGET_GLES - glFramebufferTexture3D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel, layer); - #else - static_cast(colorAttachment); - static_cast(texture); - static_cast(mipLevel); - static_cast(layer); - #endif + (this->*texture3DImplementation)(attachment, texture, level, layer); + return this; } - /*@}*/ - - /** @{ @name Framebuffer blitting and reading */ - - /** - * @brief Output mask for blitting - * - * Specifies which data are copied when performing blit operation - * using blit(). - * @see BlitMask - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - enum class Blit: GLbitfield { - Color = GL_COLOR_BUFFER_BIT, /**< Color */ - Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ - Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ - }; - - /** - * @brief Output mask for blitting - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - typedef Corrade::Containers::EnumSet BlitMask; - - /** - * @brief Copy block of pixels from read to draw framebuffer - * @param bottomLeft Bottom left coordinates of source rectangle - * @param topRight Top right coordinates of source rectangle - * @param destinationBottomLeft Bottom left coordinates of destination rectangle - * @param destinationTopRight Top right coordinates of destination - * rectangle - * @param blitMask Blit mask - * @param filter Interpolation applied if the image is - * stretched - * - * See mapForRead() / mapDefaultForRead() and mapForDraw() / - * mapDefaultForDraw() for binding particular framebuffer for reading - * and drawing. If multiple attachments are specified in mapForDraw() - * / mapDefaultForDraw(), the data are written to each of them. - * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - inline static void blit(const Math::Vector2& bottomLeft, const Math::Vector2& topRight, const Math::Vector2& destinationBottomLeft, const Math::Vector2& destinationTopRight, BlitMask blitMask, AbstractTexture::Filter filter) { - /** @todo Get some extension wrangler instead to avoid undeclared glBlitFramebuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glBlitFramebuffer(bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), destinationBottomLeft.x(), destinationBottomLeft.y(), destinationTopRight.x(), destinationTopRight.y(), static_cast(blitMask), static_cast(filter)); - #else - static_cast(bottomLeft); - static_cast(topRight); - static_cast(destinationBottomLeft); - static_cast(destinationTopRight); - static_cast(blitMask); - static_cast(filter); - #endif + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline Framebuffer* setViewport(const Rectanglei& rectangle) { + AbstractFramebuffer::setViewport(rectangle); + return this; } + #endif - /** - * @brief Copy block of pixels from read to draw framebuffer - * @param bottomLeft Bottom left coordinates of source and - * destination rectangle - * @param topRight Top right coordinates of source and - * destination rectangle - * @param blitMask Blit mask - * - * Convenience function when source rectangle is the same as - * destination rectangle. As the image is copied pixel-by-pixel, - * no interpolation is needed and thus - * AbstractTexture::Filter::NearestNeighbor filtering is used by - * default. - * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - inline static void blit(const Math::Vector2& bottomLeft, const Math::Vector2& topRight, BlitMask blitMask) { - /** @todo Get some extension wrangler instead to avoid undeclared glBlitFramebuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glBlitFramebuffer(bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), static_cast(blitMask), static_cast(AbstractTexture::Filter::NearestNeighbor)); - #else - static_cast(bottomLeft); - static_cast(topRight); - static_cast(blitMask); - #endif - } + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); - /** - * @brief Read block of pixels from framebuffer to image - * @param offset Offset in the framebuffer - * @param size %Image size - * @param components Color components - * @param type Data type - * @param image %Image where to put the data - * - * @see @fn_gl{ReadPixels} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - static void read(const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image); + typedef void(Framebuffer::*RenderbufferImplementation)(BufferAttachment, Renderbuffer*); + void MAGNUM_LOCAL renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer* renderbuffer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer* renderbuffer); + #endif + static RenderbufferImplementation renderbufferImplementation; - #ifndef MAGNUM_TARGET_GLES2 - /** - * @brief Read block of pixels from framebuffer to buffered image - * @param offset Offset in the framebuffer - * @param size %Image size - * @param components Color components - * @param type Data type - * @param image Buffered image where to put the data - * @param usage %Buffer usage - * - * @see Buffer::bind(Target), @fn_gl{ReadPixels} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. - */ - static void read(const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage); + #ifndef MAGNUM_TARGET_GLES + typedef void(Framebuffer::*Texture1DImplementation)(BufferAttachment, Texture1D*, GLint); + void MAGNUM_LOCAL texture1DImplementationDefault(BufferAttachment attachment, Texture1D* texture, GLint level); + void MAGNUM_LOCAL texture1DImplementationDSA(BufferAttachment attachment, Texture1D* texture, GLint level); + static Texture1DImplementation texture1DImplementation; #endif - /*@}*/ + typedef void(Framebuffer::*Texture2DImplementation)(BufferAttachment, GLenum, GLuint, GLint); + void MAGNUM_LOCAL texture2DImplementationDefault(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint level); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL texture2DImplementationDSA(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint level); + #endif + static MAGNUM_LOCAL Texture2DImplementation texture2DImplementation; - private: - GLuint _id; + typedef void(Framebuffer::*Texture3DImplementation)(BufferAttachment, Texture3D*, GLint, GLint); + void MAGNUM_LOCAL texture3DImplementationDefault(BufferAttachment attachment, Texture3D* texture, GLint level, GLint layer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL texture3DImplementationDSA(BufferAttachment attachment, Texture3D* texture, GLint level, GLint layer); + #endif + static Texture3DImplementation texture3DImplementation; }; -CORRADE_ENUMSET_OPERATORS(Framebuffer::ClearMask) -#ifndef MAGNUM_TARGET_GLES -CORRADE_ENUMSET_OPERATORS(Framebuffer::BlitMask) -#endif - } #endif diff --git a/src/Image.cpp b/src/Image.cpp index 637001733..06f8cde86 100644 --- a/src/Image.cpp +++ b/src/Image.cpp @@ -1,25 +1,34 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Image.h" namespace Magnum { -template void Image::setData(const typename DimensionTraits::VectorType& size, Components components, ComponentType type, GLvoid* data) { +template void Image::setData(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data) { delete[] _data; - _components = components; + _format = format; _type = type; _size = size; _data = reinterpret_cast(data); diff --git a/src/Image.h b/src/Image.h index 8613ebc5c..37e4d80bd 100644 --- a/src/Image.h +++ b/src/Image.h @@ -1,18 +1,27 @@ #ifndef Magnum_Image_h #define Magnum_Image_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,61 +31,47 @@ #include "Math/Vector3.h" #include "AbstractImage.h" #include "DimensionTraits.h" -#include "TypeTraits.h" namespace Magnum { /** @brief %Image -Class for storing image data on client memory. Can be replaced with -ImageWrapper, BufferedImage, which stores image data in GPU memory, or for -example with Trade::ImageData. +Stores image data on client memory. Interchangeable with ImageWrapper, +BufferImage or Trade::ImageData. @see Image1D, Image2D, Image3D */ -template class Image: public AbstractImage { +template class Image: public AbstractImage { public: - const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */ - - /** - * @brief Constructor - * @param size %Image size - * @param components Color components. Data type is detected - * from passed data array. - * @param data %Image data with proper size - * - * Note that the image data are not copied on construction, but they - * are deleted on class destruction. - */ - template inline Image(const typename DimensionTraits::VectorType& size, Components components, T* data): AbstractImage(components, TypeTraits::imageType()), _size(size), _data(data) {} + const static UnsignedInt Dimensions = dimensions; /**< @brief %Image dimension count */ /** * @brief Constructor * @param size %Image size - * @param components Color components - * @param type Data type + * @param format Format of pixel data + * @param type Data type of pixel data * @param data %Image data * * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - inline Image(const typename DimensionTraits::VectorType& size, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _size(size), _data(reinterpret_cast(data)) {} + inline explicit Image(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} /** * @brief Constructor - * @param components Color components - * @param type Data type + * @param format Format of pixel data + * @param type Data type of pixel data * * Dimensions and data pointer are set to zero, call setData() to fill * the image with data. */ - inline Image(Components components, ComponentType type): AbstractImage(components, type), _data(nullptr) {} + inline explicit Image(Format format, Type type): AbstractImage(format, type), _data(nullptr) {} /** @brief Destructor */ inline ~Image() { delete[] _data; } /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + inline typename DimensionTraits::VectorType size() const { return _size; } /** @brief Pointer to raw data */ inline void* data() { return _data; } @@ -85,32 +80,18 @@ template class Image: public AbstractImage { /** * @brief Set image data * @param size %Image size - * @param components Color components. Data type is detected - * from passed data array. - * @param data %Image data - * - * Deletes previous data and replaces them with new. Note that the - * data are not copied, but they are deleted on destruction. - */ - template inline void setData(const typename DimensionTraits::VectorType& size, Components components, T* data) { - setData(size, components, TypeTraits::imageType(), data); - } - - /** - * @brief Set image data - * @param size %Image size - * @param components Color components - * @param type Data type + * @param format Format of pixel data + * @param type Data type of pixel data * @param data %Image data * * 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, Components components, ComponentType type, GLvoid* data); + void setData(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data); - protected: - Math::Vector _size; /**< @brief %Image size */ - char* _data; /**< @brief %Image data */ + private: + Math::Vector _size; + char* _data; }; #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/ImageWrapper.h b/src/ImageWrapper.h index 68aabd58f..132b2526f 100644 --- a/src/ImageWrapper.h +++ b/src/ImageWrapper.h @@ -1,18 +1,27 @@ #ifndef Magnum_ImageWrapper_h #define Magnum_ImageWrapper_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,7 +31,6 @@ #include "Math/Vector3.h" #include "AbstractImage.h" #include "DimensionTraits.h" -#include "TypeTraits.h" namespace Magnum { @@ -38,49 +46,37 @@ targeted for wrapping data which are either stored in stack/constant memory same properties for each frame, such as video stream. Thus it is not possible to change image properties, only data pointer. -See also Image, BufferedImage and Trade::ImageData. +Interchangeable with Image, BufferImage or Trade::ImageData. +@see ImageWrapper1D, ImageWrapper2D, ImageWrapper3D */ -template class ImageWrapper: public AbstractImage { +template class ImageWrapper: public AbstractImage { public: - const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */ - - /** - * @brief Constructor - * @param size %Image size - * @param components Color components. Data type is detected - * from passed data array. - * @param data %Image data with proper size - * - * Note that the image data are not copied on construction, but they - * are deleted on class destruction. - */ - template inline ImageWrapper(const typename DimensionTraits::VectorType& size, Components components, T* data): AbstractImage(components, TypeTraits::imageType()), _size(size), _data(data) {} - + const static UnsignedInt Dimensions = dimensions; /**< @brief %Image dimension count */ /** * @brief Constructor * @param size %Image size - * @param components Color components - * @param type Data type + * @param format Format of pixel data + * @param type Data type of pixel data * @param data %Image data * * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - inline ImageWrapper(const typename DimensionTraits::VectorType& size, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _size(size), _data(reinterpret_cast(data)) {} + inline explicit ImageWrapper(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} /** * @brief Constructor * @param size %Image size - * @param components Color components - * @param type Data type + * @param format Format of pixel data + * @param type Data type of pixel data * * Dimensions and data pointer are set to zero, call setData() to fill * the image with data. */ - inline ImageWrapper(const typename DimensionTraits::VectorType& size, Components components, ComponentType type): AbstractImage(components, type), _size(size), _data(nullptr) {} + inline explicit ImageWrapper(const typename DimensionTraits::VectorType& size, Format format, Type type): AbstractImage(format, type), _size(size), _data(nullptr) {} /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + inline typename DimensionTraits::VectorType size() const { return _size; } /** @brief Pointer to raw data */ inline void* data() { return _data; } @@ -98,9 +94,9 @@ template class ImageWrapper: public AbstractImage { _data = reinterpret_cast(data); } - protected: - Math::Vector _size; /**< @brief %Image size */ - char* _data; /**< @brief %Image data */ + private: + Math::Vector _size; + char* _data; }; /** @brief One-dimensional image wrapper */ diff --git a/src/Implementation/BufferState.cpp b/src/Implementation/BufferState.cpp index 229be3504..15ecc9a9e 100644 --- a/src/Implementation/BufferState.cpp +++ b/src/Implementation/BufferState.cpp @@ -1,21 +1,30 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "BufferState.h" -#include +#include namespace Magnum { namespace Implementation { @@ -62,8 +71,7 @@ std::size_t BufferState::indexForTarget(Buffer::Target target) { #endif } - CORRADE_ASSERT(false, "Unknown Buffer target", 0); - return 0; + CORRADE_INTERNAL_ASSERT(false); } }} diff --git a/src/Implementation/BufferState.h b/src/Implementation/BufferState.h index 097d3ea56..0378d8d6b 100644 --- a/src/Implementation/BufferState.h +++ b/src/Implementation/BufferState.h @@ -1,22 +1,29 @@ #ifndef Magnum_Implementation_BufferState_h #define Magnum_Implementation_BufferState_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" - #include "Buffer.h" namespace Magnum { namespace Implementation { diff --git a/src/Implementation/FramebufferState.h b/src/Implementation/FramebufferState.h new file mode 100644 index 000000000..4d213425c --- /dev/null +++ b/src/Implementation/FramebufferState.h @@ -0,0 +1,41 @@ +#ifndef Magnum_Implementation_FramebufferState_h +#define Magnum_Implementation_FramebufferState_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 "Math/Geometry/Rectangle.h" +#include "Magnum.h" + +namespace Magnum { namespace Implementation { + +struct FramebufferState { + inline FramebufferState(): readBinding(0), drawBinding(0), renderbufferBinding(0) {} + + GLuint readBinding, drawBinding, renderbufferBinding; + Rectanglei viewport; +}; + +}} + +#endif diff --git a/src/Implementation/MeshState.h b/src/Implementation/MeshState.h index 1e0b24328..b2a18d756 100644 --- a/src/Implementation/MeshState.h +++ b/src/Implementation/MeshState.h @@ -1,18 +1,27 @@ #ifndef Magnum_Implementation_MeshState_h #define Magnum_Implementation_MeshState_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" diff --git a/src/Implementation/ShaderProgramState.h b/src/Implementation/ShaderProgramState.h index 3aeb48310..5313d7d6c 100644 --- a/src/Implementation/ShaderProgramState.h +++ b/src/Implementation/ShaderProgramState.h @@ -1,18 +1,27 @@ #ifndef Magnum_Implementation_ShaderProgramState_h #define Magnum_Implementation_ShaderProgramState_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" diff --git a/src/Implementation/State.cpp b/src/Implementation/State.cpp index 062a98a8c..c4d00e811 100644 --- a/src/Implementation/State.cpp +++ b/src/Implementation/State.cpp @@ -1,33 +1,49 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "State.h" #include "BufferState.h" +#include "FramebufferState.h" #include "MeshState.h" #include "ShaderProgramState.h" #include "TextureState.h" namespace Magnum { namespace Implementation { -State::State(): buffer(new BufferState), mesh(new MeshState), shaderProgram(new ShaderProgramState), texture(new TextureState) {} +State::State(): + buffer(new BufferState), + framebuffer(new FramebufferState), + mesh(new MeshState), + shaderProgram(new ShaderProgramState), + texture(new TextureState) {} State::~State() { delete texture; delete shaderProgram; delete mesh; + delete framebuffer; delete buffer; } diff --git a/src/Implementation/State.h b/src/Implementation/State.h index a264247d7..16b5b59c9 100644 --- a/src/Implementation/State.h +++ b/src/Implementation/State.h @@ -1,25 +1,33 @@ #ifndef Magnum_Implementation_State_h #define Magnum_Implementation_State_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" - namespace Magnum { namespace Implementation { struct BufferState; +struct FramebufferState; struct MeshState; struct ShaderProgramState; struct TextureState; @@ -29,6 +37,7 @@ struct State { ~State(); BufferState* const buffer; + FramebufferState* const framebuffer; MeshState* const mesh; ShaderProgramState* const shaderProgram; TextureState* const texture; diff --git a/src/Implementation/TextureState.h b/src/Implementation/TextureState.h index 73eca32af..25d0d0500 100644 --- a/src/Implementation/TextureState.h +++ b/src/Implementation/TextureState.h @@ -1,20 +1,31 @@ #ifndef Magnum_Implementation_TextureState_h #define Magnum_Implementation_TextureState_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" namespace Magnum { namespace Implementation { diff --git a/src/IndexedMesh.cpp b/src/IndexedMesh.cpp deleted file mode 100644 index b64885fae..000000000 --- a/src/IndexedMesh.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "IndexedMesh.h" - -#include - -#include "Buffer.h" -#include "Context.h" -#include "Extensions.h" - -namespace Magnum { - -IndexedMesh::BindIndexBufferImplementation IndexedMesh::bindIndexBufferImplementation = &IndexedMesh::bindIndexBufferImplementationDefault; -IndexedMesh::BindIndexedImplementation IndexedMesh::bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationDefault; - -IndexedMesh* IndexedMesh::setIndexBuffer(Buffer* buffer) { - _indexBuffer = buffer; - (this->*bindIndexBufferImplementation)(); - return this; -} - -void IndexedMesh::draw() { - if(!_indexCount) return; - - bind(); - - /** @todo Start at given index */ - glDrawElements(static_cast(primitive()), _indexCount, static_cast(_indexType), nullptr); - - unbind(); -} - -void IndexedMesh::bind() { - CORRADE_ASSERT(!_indexCount || _indexBuffer, "IndexedMesh: index buffer must be added if index count is non-zero", ); - - Mesh::bind(); - (this->*bindIndexedImplementation)(); -} - -void IndexedMesh::initializeContextBasedFunctionality(Context* context) { - /** @todo VAOs are in ES 3.0 and as extension in ES 2.0, enable them when some extension wrangler is available */ - #ifndef MAGNUM_TARGET_GLES - if(context->isExtensionSupported()) { - Debug() << "IndexedMesh: using" << Extensions::GL::APPLE::vertex_array_object::string() << "features"; - - bindIndexBufferImplementation = &IndexedMesh::bindIndexBufferImplementationVAO; - bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationVAO; - } - #else - static_cast(context); - #endif -} - -void IndexedMesh::bindIndexBufferImplementationDefault() {} - -void IndexedMesh::bindIndexBufferImplementationVAO() { - bindVAO(vao); - if(_indexBuffer) _indexBuffer->bind(Buffer::Target::ElementArray); - else Buffer::unbind(Buffer::Target::ElementArray); -} - -void IndexedMesh::bindIndexedImplementationDefault() { - if(_indexBuffer) _indexBuffer->bind(Buffer::Target::ElementArray); - else Buffer::unbind(Buffer::Target::ElementArray); -} - -void IndexedMesh::bindIndexedImplementationVAO() {} - -} diff --git a/src/IndexedMesh.h b/src/IndexedMesh.h deleted file mode 100644 index 0d5bfd045..000000000 --- a/src/IndexedMesh.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef Magnum_IndexedMesh_h -#define Magnum_IndexedMesh_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file - * @brief Class Magnum::IndexedMesh - */ - -#include "Mesh.h" - -#include "corradeCompatibility.h" - -namespace Magnum { - -/** -@brief Indexed mesh - -@section IndexedMesh-configuration Indexed mesh configuration - -Next to @ref Mesh-configuration "everything needed for non-indexed mesh" you -have to call also setIndexCount() and setIndexType(). Then create index buffer -and assign it to the mesh using setIndexBuffer() or use -MeshTools::compressIndices() to conveniently fill the index buffer and set -index count and type. - -Similarly as in Mesh itself the index buffer is not managed by the mesh, so -you have to manage it on your own. On the other hand it allows you to use -one index buffer for more meshes (with different vertex data in each mesh, for -example) or store more than only index data in one buffer. - -@section IndexedMesh-drawing Rendering meshes - -From user point-of-view the operation is the same as for -@ref Mesh-drawing "non-indexed meshes". - -@section IndexedMesh-performance-optimization Performance optimizations - -If @extension{APPLE,vertex_array_object} is supported, next to -@ref Mesh-performance-optimization "optimizations in Mesh itself" the index -buffer is bound on object construction instead of in every draw() call. -*/ -class MAGNUM_EXPORT IndexedMesh: public Mesh { - friend class Context; - - public: - /** - * @brief Constructor - * @param primitive Primitive type - * - * Creates indexed mesh with no index buffer, zero vertex count and - * zero index count. - * @see setPrimitive(), setVertexCount(), setIndexBuffer(), - * setIndexCount(), setIndexType() - */ - inline IndexedMesh(Primitive primitive = Primitive::Triangles): Mesh(primitive), _indexBuffer(nullptr), _indexCount(0), _indexType(Type::UnsignedShort) {} - - /** - * @brief Set index buffer - * - * By default there is no index buffer. Parameter @p buffer can be - * `nullptr`, in that case current index buffer is unbound from the - * mesh. - * @see MeshTools::compressIndices(), @fn_gl{BindVertexArray}, - * @fn_gl{BindBuffer} (if @extension{APPLE,vertex_array_object} - * is available) - */ - IndexedMesh* setIndexBuffer(Buffer* buffer); - - /** @brief Index count */ - inline GLsizei indexCount() const { return _indexCount; } - - /** - * @brief Set index count - * @return Pointer to self (for method chaining) - * - * Default is zero. - * @see MeshTools::compressIndices() - */ - inline IndexedMesh* setIndexCount(GLsizei count) { - _indexCount = count; - return this; - } - - /** @brief Index type */ - inline Type indexType() const { return _indexType; } - - /** - * @brief Set index type - * @return Pointer to self (for method chaining) - * - * Default is @ref Type "Type::UnsignedShort". - * @see MeshTools::compressIndices() - */ - inline IndexedMesh* setIndexType(Type type) { - _indexType = type; - return this; - } - - /** - * @brief Draw the mesh - * - * Expects an active shader with all uniforms set. See - * @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" - * for more information. - * @see @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer}, - * @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray} - * or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object} - * is available), @fn_gl{DrawElements} - */ - void draw() override; - - /* Overloads to remove WTF-factor from method chaining order */ - #ifndef DOXYGEN_GENERATING_OUTPUT - inline IndexedMesh* setPrimitive(Primitive primitive) { - Mesh::setPrimitive(primitive); - return this; - } - inline IndexedMesh* setVertexCount(GLsizei vertexCount) { - Mesh::setVertexCount(vertexCount); - return this; - } - template inline IndexedMesh* addVertexBuffer(Buffer* buffer, const T&... attributes) { - Mesh::addVertexBuffer(buffer, attributes...); - return this; - } - template inline IndexedMesh* addInterleavedVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) { - Mesh::addInterleavedVertexBuffer(buffer, offset, attributes...); - return this; - } - template inline IndexedMesh* addVertexBufferStride(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute) { - Mesh::addVertexBufferStride(buffer, offset, stride, attribute); - return this; - } - #endif - - private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); - - void MAGNUM_LOCAL bind(); - - typedef void(IndexedMesh::*BindIndexBufferImplementation)(); - void MAGNUM_LOCAL bindIndexBufferImplementationDefault(); - void MAGNUM_LOCAL bindIndexBufferImplementationVAO(); - static MAGNUM_LOCAL BindIndexBufferImplementation bindIndexBufferImplementation; - - typedef void(IndexedMesh::*BindIndexedImplementation)(); - void MAGNUM_LOCAL bindIndexedImplementationDefault(); - void MAGNUM_LOCAL bindIndexedImplementationVAO(); - static MAGNUM_LOCAL BindIndexedImplementation bindIndexedImplementation; - - Buffer* _indexBuffer; - GLsizei _indexCount; - Type _indexType; -}; - -} - -#endif diff --git a/src/Magnum.h b/src/Magnum.h index 90263b281..6c1c85dda 100644 --- a/src/Magnum.h +++ b/src/Magnum.h @@ -1,50 +1,39 @@ #ifndef Magnum_Magnum_h #define Magnum_Magnum_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 Basic definitions and forward declarations for Magnum namespace + * @brief Forward declarations for Magnum namespace */ -#include +#include -#include "corradeCompatibility.h" +#include "Math/Math.h" +#include "Types.h" #include "magnumConfigure.h" -#ifndef MAGNUM_TARGET_GLES -#include -#include -#else -#ifndef MAGNUM_TARGET_GLES2 -#include -#else -#include -#include -#endif -#endif - -/** - * @todo Link to libGL / libGLES based on which windowcontext is used in app - * and whether GLES is enabled or not -- this allows us to use glx with - * ES on nvidia/intel. Using libGL and EGL on nvidia is whole another - * problem, though. How about windows? It won't allow unlinked DLLs, so - * probably always link Magnum itself to GL library there. How about unit - * tests not needing any of GL? -- different testing library? - */ - namespace Corrade { namespace Utility { class Debug; @@ -55,76 +44,252 @@ namespace Corrade { namespace Magnum { +/** @todoc Remove `ifndef` when Doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT namespace Math { - template class Vector2; - template class Vector3; - template class Vector4; - template class Point2D; - template class Point3D; - template class Matrix3; - template class Matrix4; - - template constexpr T deg(T value); - template constexpr T rad(T value); template struct Constants; + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Rad operator "" _rad(long double); + constexpr Rad operator "" _radf(long double); + constexpr Deg operator "" _deg(long double); + constexpr Deg operator "" _degf(long double); + #endif } /* Bring debugging facility from Corrade::Utility namespace */ using Corrade::Utility::Debug; using Corrade::Utility::Warning; using Corrade::Utility::Error; +#endif + +/** @{ @name Basic type definitions + +See @ref types for more information. +*/ + +/** @brief Unsigned byte (8bit) */ +typedef std::uint8_t UnsignedByte; + +/** @brief Signed byte (8bit) */ +typedef std::int8_t Byte; + +/** @brief Unsigned short (16bit) */ +typedef std::uint16_t UnsignedShort; + +/** @brief Signed short (16bit) */ +typedef std::int16_t Short; + +/** @brief Unsigned int (32bit) */ +typedef std::uint32_t UnsignedInt; + +/** @brief Signed int (32bit) */ +typedef std::int32_t Int; + +/** @brief Unsigned long (64bit) */ +typedef std::uint64_t UnsignedLong; + +/** @brief Signed long (64bit) */ +typedef std::int64_t Long; + +/** @brief Float (32bit) */ +typedef float Float; + +/** @brief Two-component float vector */ +typedef Math::Vector2 Vector2; + +/** @brief Three-component float vector */ +typedef Math::Vector3 Vector3; + +/** @brief Four-component float vector */ +typedef Math::Vector4 Vector4; + +/** @brief Two-component unsigned integer vector */ +typedef Math::Vector2 Vector2ui; + +/** @brief Three-component unsigned integer vector */ +typedef Math::Vector3 Vector3ui; + +/** @brief Four-component unsigned integer vector */ +typedef Math::Vector4 Vector4ui; + +/** @brief Two-component signed integer vector */ +typedef Math::Vector2 Vector2i; + +/** @brief Three-component signed integer vector */ +typedef Math::Vector3 Vector3i; + +/** @brief Four-component signed integer vector */ +typedef Math::Vector4 Vector4i; + +/** @brief 2x2 float matrix */ +typedef Math::Matrix<2, Float> Matrix2; + +/** @brief 3x3 float matrix */ +typedef Math::Matrix3 Matrix3; + +/** @brief 4x4 float matrix */ +typedef Math::Matrix4 Matrix4; + +/** @brief Float matrix with 2 columns and 3 rows */ +typedef Math::RectangularMatrix<2, 3, Float> Matrix2x3; + +/** @brief Float matrix with 3 columns and 2 rows */ +typedef Math::RectangularMatrix<3, 2, Float> Matrix3x2; -/** @brief Two-component floating-point vector */ -typedef Math::Vector2 Vector2; +/** @brief Float matrix with 2 columns and 4 rows */ +typedef Math::RectangularMatrix<2, 4, Float> Matrix2x4; -/** @brief Three-component floating-point vector */ -typedef Math::Vector3 Vector3; +/** @brief Float matrix with 4 columns and 2 rows */ +typedef Math::RectangularMatrix<4, 2, Float> Matrix4x2; -/** @brief Four-component floating-point vector */ -typedef Math::Vector4 Vector4; +/** @brief Float matrix with 3 columns and 4 rows */ +typedef Math::RectangularMatrix<3, 4, Float> Matrix3x4; -/** @brief Two-dimensional floating-point homogeneous coordinates */ -typedef Math::Point2D Point2D; +/** @brief Float matrix with 4 columns and 3 rows */ +typedef Math::RectangularMatrix<4, 3, Float> Matrix4x3; -/** @brief Three-dimensional floating-point homogeneous coordinates */ -typedef Math::Point3D Point3D; +/** @brief Float complex number */ +typedef Math::Complex Complex; -/** @brief 3x3 floating-point matrix */ -typedef Math::Matrix3 Matrix3; +/** @brief Float dual complex number */ +typedef Math::DualComplex DualComplex; -/** @brief 4x4 floating-point matrix */ -typedef Math::Matrix4 Matrix4; +/** @brief Float quaternion */ +typedef Math::Quaternion Quaternion; -/** @brief Floating-point constants */ -/* Using float instead of GLfloat to not break KDevelop autocompletion */ -typedef Math::Constants Constants; +/** @brief Float dual quaternion */ +typedef Math::DualQuaternion DualQuaternion; -/* Copying angle converters from Math namespace */ -using Math::deg; -using Math::rad; +/** @brief Float constants */ +typedef Math::Constants Constants; +/** @brief Angle in float degrees */ +typedef Math::Deg Deg; + +/** @brief Angle in float radians */ +typedef Math::Rad Rad; + +/** @brief Float rectangle */ +typedef Math::Geometry::Rectangle Rectangle; + +/** @brief Signed integer rectangle */ +typedef Math::Geometry::Rectangle Rectanglei; + +/*@}*/ + +#ifndef MAGNUM_TARGET_GLES +/** @{ @name Double-precision types + +See @ref types for more information. +@requires_gl Only single-precision types are available in OpenGL ES. +*/ + +/** @brief Double (64bit) */ +typedef double Double; + +/** @brief Two-component double vector */ +typedef Math::Vector2 Vector2d; + +/** @brief Three-component double vector */ +typedef Math::Vector3 Vector3d; + +/** @brief Four-component double vector */ +typedef Math::Vector4 Vector4d; + +/** @brief 2x2 double matrix */ +typedef Math::Matrix<2, Double> Matrix2d; + +/** @brief 3x3 double matrix */ +typedef Math::Matrix3 Matrix3d; + +/** @brief 4x4 double matrix */ +typedef Math::Matrix4 Matrix4d; + +/** @brief Double matrix with 2 columns and 3 rows */ +typedef Math::RectangularMatrix<2, 3, Double> Matrix2x3d; + +/** @brief Double matrix with 3 columns and 2 rows */ +typedef Math::RectangularMatrix<3, 2, Double> Matrix3x2d; + +/** @brief Double matrix with 2 columns and 4 rows */ +typedef Math::RectangularMatrix<2, 4, Double> Matrix2x4d; + +/** @brief Double matrix with 4 columns and 2 rows */ +typedef Math::RectangularMatrix<4, 2, Double> Matrix4x2d; + +/** @brief Double matrix with 3 columns and 4 rows */ +typedef Math::RectangularMatrix<3, 4, Double> Matrix3x4d; + +/** @brief Double matrix with 4 columns and 3 rows */ +typedef Math::RectangularMatrix<4, 3, Double> Matrix4x3d; + +/** @brief Double complex number */ +typedef Math::Complex Complexd; + +/** @brief Double dual complex number */ +typedef Math::DualComplex DualComplexd; + +/** @brief Double quaternion */ +typedef Math::Quaternion Quaterniond; + +/** @brief Double dual quaternion */ +typedef Math::DualQuaternion DualQuaterniond; + +/** @brief Double constants */ +typedef Math::Constants Constantsd; + +/** @brief Angle in double degrees */ +typedef Math::Deg Degd; + +/** @brief Angle in double radians */ +typedef Math::Rad Radd; + +/** @brief Double rectangle */ +typedef Math::Geometry::Rectangle Rectangled; + +/*@}*/ +#endif + +#ifndef CORRADE_GCC46_COMPATIBILITY +/* Using angle literals from Math namespace */ +using Math::operator "" _deg; +using Math::operator "" _degf; +using Math::operator "" _rad; +using Math::operator "" _radf; +#endif + +/** @todoc Remove `ifndef` when Doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT /* Forward declarations for all types in root namespace */ +class AbstractFramebuffer; class AbstractImage; class AbstractShaderProgram; class AbstractTexture; + +template class Array; +template class Array1D; +template class Array2D; +template class Array3D; + class Buffer; #ifndef MAGNUM_TARGET_GLES2 -template class BufferedImage; -typedef BufferedImage<1> BufferedImage1D; -typedef BufferedImage<2> BufferedImage2D; -typedef BufferedImage<3> BufferedImage3D; +template class BufferImage; +typedef BufferImage<1> BufferImage1D; +typedef BufferImage<2> BufferImage2D; +typedef BufferImage<3> BufferImage3D; #endif #ifndef MAGNUM_TARGET_GLES -class BufferedTexture; +class BufferTexture; #endif -template class Color3; -template class Color4; +template class Color3; +template class Color4; #ifndef CORRADE_GCC45_COMPATIBILITY -enum class Version: GLint; +enum class Version: Int; #endif class Context; class CubeMapTexture; @@ -134,31 +299,30 @@ class CubeMapTextureArray; #endif /* DebugMarker forward declaration is not needed */ +/* DefaultFramebuffer is available only through global instance */ /* DimensionTraits forward declaration is not needed */ class Extension; class Framebuffer; -template class Image; +template class Image; typedef Image<1> Image1D; typedef Image<2> Image2D; typedef Image<3> Image3D; -template class ImageWrapper; +template class ImageWrapper; typedef ImageWrapper<1> ImageWrapper1D; typedef ImageWrapper<2> ImageWrapper2D; typedef ImageWrapper<3> ImageWrapper3D; -class IndexedMesh; class Mesh; -class Profiler; class Query; class Renderbuffer; #ifndef CORRADE_GCC45_COMPATIBILITY -enum class ResourceState: std::uint8_t; -enum class ResourceDataState: std::uint8_t; -enum class ResourcePolicy: std::uint8_t; +enum class ResourceState: UnsignedByte; +enum class ResourceDataState: UnsignedByte; +enum class ResourcePolicy: UnsignedByte; #endif template class Resource; class ResourceKey; @@ -166,7 +330,7 @@ template class ResourceManager; class Shader; -template class Texture; +template class Texture; #ifndef MAGNUM_TARGET_GLES typedef Texture<1> Texture1D; #endif @@ -174,6 +338,7 @@ typedef Texture<2> Texture2D; typedef Texture<3> Texture3D; class Timeline; +#endif } diff --git a/src/Math/Algorithms/CMakeLists.txt b/src/Math/Algorithms/CMakeLists.txt index cb5121b20..3cc642da9 100644 --- a/src/Math/Algorithms/CMakeLists.txt +++ b/src/Math/Algorithms/CMakeLists.txt @@ -1,8 +1,34 @@ +# +# 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. +# + set(MagnumMathAlgorithms_HEADERS - GaussJordan.h) + GaussJordan.h + GramSchmidt.h + Svd.h) + install(FILES ${MagnumMathAlgorithms_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math/Algorithms) if(BUILD_TESTS) - enable_testing() add_subdirectory(Test) endif() diff --git a/src/Math/Algorithms/GaussJordan.h b/src/Math/Algorithms/GaussJordan.h index 2778fa5c2..37bacfe51 100644 --- a/src/Math/Algorithms/GaussJordan.h +++ b/src/Math/Algorithms/GaussJordan.h @@ -1,22 +1,31 @@ #ifndef Magnum_Math_Algorithms_GaussJordan_h #define Magnum_Math_Algorithms_GaussJordan_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::Algorithms::GaussJordan + * @brief Function Magnum::Math::Algorithms::gaussJordanInPlaceTransposed(), Magnum::Math::Algorithms::gaussJordanInPlace() */ #include "Math/RectangularMatrix.h" @@ -24,57 +33,30 @@ namespace Magnum { namespace Math { namespace Algorithms { /** -@brief Gauss-Jordan elimination +@brief In-place Gauss-Jordan elimination on transposed matrices +@param a Transposed left side of augmented matrix +@param t Transposed right side of augmented matrix +@return True if @p a is regular, false if @p a is singular (and thus the + system cannot be solved). + +As Gauss-Jordan elimination works on rows and matrices in OpenGL are +column-major, it is more efficient to operate on transposed matrices and treat +columns as rows. See also gaussJordanInPlace() which works with non-transposed matrices. + +The function eliminates matrix @p a and solves @p t in place. For efficiency +reasons, only pure Gaussian elimination is done on @p a and the final +backsubstitution is done only on @p t, as @p a would always end with identity +matrix anyway. Based on ultra-compact Python code by Jarno Elonen, http://elonen.iki.fi/code/misc-notes/python-gaussj/index.html. */ -class GaussJordan { - public: - /** - * @brief Eliminate transposed matrices in place - * @param a Transposed left side of augmented matrix - * @param t Transposed right side of augmented matrix - * @return True if @p a is regular, false if @p a is singular (and - * thus the system cannot be solved). - * - * As Gauss-Jordan elimination works on rows and matrices in OpenGL - * are column-major, it is more efficient to operate on transposed - * matrices and treat columns as rows. See also inPlace() which works - * with non-transposed matrices. - * - * The function eliminates matrix @p a and solves @p t in place. For - * efficiency reasons, only pure Gaussian elimination is done on @p a - * and the final backsubstitution is done only on @p t, as @p a would - * always end with identity matrix anyway. - */ - template static bool inPlaceTransposed(RectangularMatrix& a, RectangularMatrix& t); - - /** - * @brief Eliminate in place - * - * Transposes the matrices, calls inPlaceTransposed() on them and then - * transposes them back. - */ - template static bool inPlace(RectangularMatrix& a, RectangularMatrix& t) { - a = a.transposed(); - RectangularMatrix tTransposed = t.transposed(); - - bool ret = inPlaceTransposed(a, tTransposed); - - a = a.transposed(); - t = tTransposed.transposed(); - - return ret; - } -}; - -template bool GaussJordan::inPlaceTransposed(RectangularMatrix& a, RectangularMatrix& t) { +template bool gaussJordanInPlaceTransposed(RectangularMatrix& a, RectangularMatrix& t) { for(std::size_t row = 0; row != size; ++row) { /* Find max pivot */ std::size_t rowMax = row; for(std::size_t row2 = row+1; row2 != size; ++row2) - if(std::abs(a(row2, row)) > std::abs(a(rowMax, row))) + if(std::abs(a[row2][row]) > std::abs(a[rowMax][row])) rowMax = row2; /* Swap the rows */ @@ -82,12 +64,12 @@ template bool GaussJordan::inPlaceT std::swap(t[row], t[rowMax]); /* Singular */ - if(MathTypeTraits::equals(a(row, row), 0)) + if(TypeTraits::equals(a[row][row], T(0))) return false; /* Eliminate column */ for(std::size_t row2 = row+1; row2 != size; ++row2) { - T c = a(row2, row)/a(row, row); + T c = a[row2][row]/a[row][row]; a[row2] -= a[row]*c; t[row2] -= t[row]*c; @@ -96,10 +78,10 @@ template bool GaussJordan::inPlaceT /* Backsubstitute */ for(std::size_t row = size; row != 0; --row) { - T c = T(1)/a(row-1, row-1); + T c = T(1)/a[row-1][row-1]; for(std::size_t row2 = 0; row2 != row-1; ++row2) - t[row2] -= t[row-1]*a(row2, row-1)*c; + t[row2] -= t[row-1]*a[row2][row-1]*c; /* Normalize the row */ t[row-1] *= c; @@ -108,6 +90,24 @@ template bool GaussJordan::inPlaceT return true; } +/** +@brief In-place Gauss-Jordan elimination + +Transposes the matrices, calls gaussJordanInPlaceTransposed() on them and then +transposes them back. +*/ +template bool gaussJordanInPlace(RectangularMatrix& a, RectangularMatrix& t) { + a = a.transposed(); + RectangularMatrix tTransposed = t.transposed(); + + bool ret = gaussJordanInPlaceTransposed(a, tTransposed); + + a = a.transposed(); + t = tTransposed.transposed(); + + return ret; +} + }}} #endif diff --git a/src/Math/Algorithms/GramSchmidt.h b/src/Math/Algorithms/GramSchmidt.h new file mode 100644 index 000000000..5346fe9ee --- /dev/null +++ b/src/Math/Algorithms/GramSchmidt.h @@ -0,0 +1,84 @@ +#ifndef Magnum_Math_Algorithms_GramSchmidt_h +#define Magnum_Math_Algorithms_GramSchmidt_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::Math::Algorithms::gramSchmidtOrthogonalizeInPlace(), Magnum::Math::Algorithms::gramSchmidtOrthogonalize(), Magnum::Math::Algorithms::gramSchmidtOrthonormalizeInPlace(), Magnum::Math::Algorithms::gramSchmidtOrthonormalize() + */ + +#include "Math/RectangularMatrix.h" + +namespace Magnum { namespace Math { namespace Algorithms { + +/** +@brief In-place Gram-Schmidt matrix orthogonalization +@param[in,out] matrix %Matrix to perform orthogonalization on +*/ +template void gramSchmidtOrthogonalizeInPlace(RectangularMatrix& matrix) { + static_assert(cols <= rows, "Unsupported matrix aspect ratio"); + for(std::size_t i = 0; i != cols; ++i) { + for(std::size_t j = i+1; j != cols; ++j) + matrix[j] -= matrix[j].projected(matrix[i]); + } +} + +/** +@brief Gram-Schmidt matrix orthogonalization + +Unlike gramSchmidtOrthogonalizeInPlace() returns the modified matrix instead +of performing the orthogonalization in-place. +*/ +template RectangularMatrix gramSchmidtOrthogonalize(RectangularMatrix matrix) { + gramSchmidtOrthogonalizeInPlace(matrix); + return matrix; +} + +/** +@brief In-place Gram-Schmidt matrix orthonormalization +@param[in,out] matrix %Matrix to perform orthonormalization on +*/ +template void gramSchmidtOrthonormalizeInPlace(RectangularMatrix& matrix) { + static_assert(cols <= rows, "Unsupported matrix aspect ratio"); + for(std::size_t i = 0; i != cols; ++i) { + matrix[i] = matrix[i].normalized(); + for(std::size_t j = i+1; j != cols; ++j) + matrix[j] -= matrix[j].projectedOntoNormalized(matrix[i]); + } +} + +/** +@brief Gram-Schmidt matrix orthonormalization + +Unlike gramSchmidtOrthonormalizeInPlace() returns the modified matrix instead +of performing the orthonormalization in-place. +*/ +template RectangularMatrix gramSchmidtOrthonormalize(RectangularMatrix matrix) { + gramSchmidtOrthonormalizeInPlace(matrix); + return matrix; +} + +}}} + +#endif diff --git a/src/Math/Algorithms/Svd.h b/src/Math/Algorithms/Svd.h new file mode 100644 index 000000000..9c4200515 --- /dev/null +++ b/src/Math/Algorithms/Svd.h @@ -0,0 +1,337 @@ +#ifndef Magnum_Math_Algorithms_Svd_h +#define Magnum_Math_Algorithms_Svd_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::Math::Algorithms::svd() + */ + +#include + +#include "Math/Functions.h" +#include "Math/Matrix.h" + +namespace Magnum { namespace Math { namespace Algorithms { + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + +template T pythagoras(T a, T b) { + T absa = std::abs(a); + T absb = std::abs(b); + if(absa > absb) + return absa*std::sqrt(T(1) + Math::pow<2>(absb/absa)); + else if(absb == T(0)) /** @todo epsilon comparison? */ + return T(0); + else + return absb*std::sqrt(T(1) + Math::pow<2>(absa/absb)); +} + +template T smallestDelta(); +template<> inline constexpr Float smallestDelta() { return 1.0e-32; } +template<> inline constexpr Double smallestDelta() { return 1.0e-64; } + +} +#endif + +/** +@brief Singular Value Decomposition + +Performs Thin SVD on given matrix where @p rows >= @p cols: +@f[ + M = U \Sigma V^* +@f] +Returns first @p cols column vectors of @f$ U @f$, diagonal of @f$ \Sigma @f$ +and non-transposed @f$ V @f$. If the solution doesn't converge, returns +zero matrices. + +Full @f$ U @f$, @f$ \Sigma @f$ matrices and original @f$ M @f$ matrix can be +reconstructed from the values as following: +@code +RectangularMatrix m; + +RectangularMatrix uPart; +Vector wDiagonal; +Matrix v; + +std::tie(uPart, wDiagonal, v) = Math::Algorithms::svd(m); + +// Extend U +Matrix u(Matrix::Zero); +for(std::size_t i = 0; i != rows; ++i) + u[i] = uPart[i]; + +// Diagonal W +RectangularMatrix w = + RectangularMatrix::fromDiagonal(wDiagonal); + +// u*w*v.transposed() == m +@endcode + +Implementation based on *Golub, G. H.; Reinsch, C. (1970). "Singular value +decomposition and least squares solutions"*. +*/ +/* The matrix is passed by value because it is changed inside */ +template std::tuple, Vector, Matrix> svd(RectangularMatrix m) { + static_assert(rows >= cols, "Unsupported matrix aspect ratio"); + static_assert(T(1)+TypeTraits::epsilon() > T(1), "Epsilon too small"); + constexpr T tol = Implementation::smallestDelta()/TypeTraits::epsilon(); + static_assert(tol > T(0), "Tol too small"); + constexpr std::size_t maxIterations = 50; + + Matrix v(Matrix::Zero); + Vector e, q; + + /* Householder's reduction to bidiagonal form */ + T g = T(0); + T epsilonX = T(0); + for(std::size_t i = 0; i != cols; ++i) { + const std::size_t l = i+1; + + e[i] = g; + T s1 = T(0); + for(std::size_t j = i; j != rows; ++j) + s1 += Math::pow<2>(m[i][j]); + if(s1 > tol) { + const T f = m[i][i]; + g = (f < T(0) ? std::sqrt(s1) : -std::sqrt(s1)); + const T h = f*g - s1; + m[i][i] = f - g; + + for(std::size_t j = l; j != cols; ++j) { + T s = T(0); + for(std::size_t k = i; k != rows; ++k) + s += m[i][k]*m[j][k]; + const T f = s/h; + for(std::size_t k = i; k != rows; ++k) + m[j][k] += f*m[i][k]; + } + } else g = T(0); + + q[i] = g; + T s2 = T(0); + for(std::size_t j = l; j != cols; ++j) + s2 += Math::pow<2>(m[j][i]); + if(s2 > tol) { + const T f = m[i+1][i]; + g = (f < T(0) ? std::sqrt(s2) : -std::sqrt(s2)); + const T h = f*g - s2; + m[i+1][i] = f - g; + + for(std::size_t j = l; j != cols; ++j) + e[j] = m[j][i]/h; + + for(std::size_t j = l; j != rows; ++j) { + T s = T(0); + for(std::size_t k = l; k != cols; ++k) + s += m[k][j]*m[k][i]; + for(std::size_t k = l; k != cols; ++k) + m[k][j] += s*e[k]; + } + + } else g = T(0); + + const T y = std::abs(q[i]) + std::abs(e[i]); + if(y > epsilonX) epsilonX = y; + } + + /* Accumulation of right hand transformations */ + for(std::size_t l = cols; l != 0; --l) { + const std::size_t i = l-1; + + if(g != T(0)) { /** @todo epsilon check? */ + const T h = g*m[i+1][i]; + + for(std::size_t j = l; j != cols; ++j) + v[i][j] = m[j][i]/h; + + for(std::size_t j = l; j != cols; ++j) { + T s = T(0); + for(std::size_t k = l; k != cols; ++k) + s += m[k][i]*v[j][k]; + for(std::size_t k = l; k != cols; ++k) + v[j][k] += s*v[i][k]; + } + } + + for(std::size_t j = l; j != cols; ++j) + v[j][i] = v[i][j] = T(0); + + v[i][i] = T(1); + g = e[i]; + } + + /* Accumulation of left hand transformations */ + for(std::size_t l = cols; l != 0; --l) { + const std::size_t i = l-1; + + for(std::size_t j = l; j != cols; ++j) + m[j][i] = T(0); + + const T d = q[i]; + if(d != T(0)) { /** @todo epsilon check? */ + const T h = m[i][i]*d; + for(std::size_t j = l; j != cols; ++j) { + T s = T(0); + for(std::size_t k = l; k != rows; ++k) + s += m[i][k]*m[j][k]; + const T f = s/h; + for(std::size_t k = i; k != rows; ++k) + m[j][k] += f*m[i][k]; + } + + for(std::size_t j = i; j != rows; ++j) + m[i][j] /= d; + + } else for(std::size_t j = i; j != rows; ++j) + m[i][j] = T(0); + + m[i][i] += T(1); + } + + /* Diagonalization of the bidiagonal form */ + const T epsilon = TypeTraits::epsilon()*epsilonX; + for(std::size_t k2 = cols; k2 != 0; --k2) { + const std::size_t k = k2 - 1; + + for(std::size_t iteration = 0; iteration != maxIterations; ++iteration) { + /* Test for splitting */ + bool doCancellation = true; + std::size_t l = 0; + for(std::size_t l2 = k2; l2 != 0; --l2) { + l = l2 - 1; + if(std::abs(e[l]) <= epsilon) { + doCancellation = false; + break; + } else if(std::abs(q[l-1]) <= epsilon) { + break; + } + } + + /* Cancellation */ + if(doCancellation) { + const std::size_t l1 = l - 1; + T c = T(0); + T s = T(1); + for(std::size_t i = l; i != k+1; ++i) { + CORRADE_INTERNAL_ASSERT(i <= k+1); + + const T f = s*e[i]; + e[i] = c*e[i]; + if(std::abs(f) <= epsilon) break; + + const T g = q[i]; + const T h = Implementation::pythagoras(f, g); + q[i] = h; + c = g/h; + s = -f/h; + + const Vector a = m[l1]; + const Vector b = m[i]; + m[l1] = a*c+b*s; + m[i] = -a*s+b*c; + } + } + + /* Test for convergence */ + const T z = q[k]; + if(l == k) { + /* Invert to non-negative */ + if(z < T(0)) { + q[k] = -z; + v[k] = -v[k]; + } + + break; + + /* Exceeded iteration count, done */ + } else if(iteration >= maxIterations-1) { + Corrade::Utility::Error() << "Magnum::Math::Algorithms::svd(): no convergence"; + return std::make_tuple(RectangularMatrix(), Vector(), Matrix(Matrix::Zero)); + } + + /* Shift from bottom 2x2 minor */ + const T y = q[k-1]; + const T h = e[k]; + const T d = e[k-1]; + T x = q[l]; + T f = ((y - z)*(y + z) + (d - h)*(d + h))/(T(2)*h*y); + const T b = Implementation::pythagoras(f, T(1)); + if(f < T(0)) + f = ((x - z)*(x + z) + h*(y/(f - b) - h))/x; + else + f = ((x - z)*(x + z) + h*(y/(f + b) - h))/x; + + /* Next QR transformation */ + /** @todo isn't this extractable elsewhere? */ + T c = T(1); + T s = T(1); + for(std::size_t i = l+1; i != k+1; ++i) { + CORRADE_INTERNAL_ASSERT(i <= k+1); + + const T g1 = c*e[i]; + const T h1 = s*e[i]; + const T y1 = q[i]; + + const T z1 = Implementation::pythagoras(f, h1); + e[i-1] = z1; + c = f/z1; + s = h1/z1; + f = x*c + g1*s; + + const T g2 = -x*s + g1*c; + const T h2 = y1*s; + const T y2 = y1*c; + + const Vector a1 = v[i-1]; + const Vector b1 = v[i]; + v[i-1] = a1*c+b1*s; + v[i] = -a1*s+b1*c; + + const T z2 = Implementation::pythagoras(f, h2); + q[i-1] = z2; + c = f/z2; + s = h2/z2; + f = c*g2 + s*y2; + x = -s*g2 + c*y2; + + const Vector a2 = m[i-1]; + const Vector b2 = m[i]; + m[i-1] = a2*c+b2*s; + m[i] = -a2*s+b2*c; + } + + e[l] = T(0); + e[k] = f; + q[k] = x; + } + } + + return std::make_tuple(m, q, v); +} + +}}} + +#endif diff --git a/src/Math/Algorithms/Test/CMakeLists.txt b/src/Math/Algorithms/Test/CMakeLists.txt index 41e1779f2..8149a43f8 100644 --- a/src/Math/Algorithms/Test/CMakeLists.txt +++ b/src/Math/Algorithms/Test/CMakeLists.txt @@ -1 +1,27 @@ -corrade_add_test2(MathAlgorithmsGaussJordanTest GaussJordanTest.cpp LIBRARIES MagnumMathTestLib) +# +# 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. +# + +corrade_add_test(MathAlgorithmsGaussJordanTest GaussJordanTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathAlgorithmsGramSchmidtTest GramSchmidtTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathAlgorithmsSvdTest SvdTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/Math/Algorithms/Test/GaussJordanTest.cpp b/src/Math/Algorithms/Test/GaussJordanTest.cpp index 5a13365df..80ef9c1e5 100644 --- a/src/Math/Algorithms/Test/GaussJordanTest.cpp +++ b/src/Math/Algorithms/Test/GaussJordanTest.cpp @@ -1,61 +1,78 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "GaussJordanTest.h" +#include #include "Math/Algorithms/GaussJordan.h" -#include "Math/Matrix.h" - -CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::GaussJordanTest) namespace Magnum { namespace Math { namespace Algorithms { namespace Test { -typedef Matrix<4, float> Matrix4; +class GaussJordanTest: public Corrade::TestSuite::Tester { + public: + explicit GaussJordanTest(); + + void singular(); + void invert(); +}; + +typedef RectangularMatrix<4, 4, Float> Matrix4; +typedef Vector<4, Float> Vector4; GaussJordanTest::GaussJordanTest() { - addTests(&GaussJordanTest::singular, - &GaussJordanTest::invert); + addTests({&GaussJordanTest::singular, + &GaussJordanTest::invert}); } void GaussJordanTest::singular() { - Matrix4 a(1.0f, 2.0f, 3.0f, 4.0f, - 2.0f, 3.0f, -7.0f, 11.0f, - 2.0f, 4.0f, 6.0f, 8.0f, - 1.0f, 2.0f, 7.0f, 40.0f); - RectangularMatrix<4, 1, float> t; + Matrix4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(2.0f, 3.0f, -7.0f, 11.0f), + Vector4(2.0f, 4.0f, 6.0f, 8.0f), + Vector4(1.0f, 2.0f, 7.0f, 40.0f)); + RectangularMatrix<4, 1, Float> t; - CORRADE_VERIFY(!GaussJordan::inPlaceTransposed(a, t)); + CORRADE_VERIFY(!gaussJordanInPlaceTransposed(a, t)); } void GaussJordanTest::invert() { - Matrix4 a(3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f); + Matrix4 a(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); - Matrix4 expectedInverse(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f, - -66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f, - 177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f, - 259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f); + Matrix4 expectedInverse(Vector4(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f), + Vector4(-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f), + Vector4(177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f), + Vector4(259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f)); Matrix4 a2(a); - Matrix4 inverse(Matrix4::Identity); - CORRADE_VERIFY(GaussJordan::inPlace(a2, inverse)); + Matrix4 inverse = Matrix4::fromDiagonal(Vector4(1.0f)); + CORRADE_VERIFY(gaussJordanInPlace(a2, inverse)); CORRADE_COMPARE(inverse, expectedInverse); - CORRADE_COMPARE(a*inverse, Matrix4()); + CORRADE_COMPARE(a*inverse, Matrix4::fromDiagonal(Vector4(1.0f))); } }}}} + +CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::GaussJordanTest) diff --git a/src/Math/Algorithms/Test/GaussJordanTest.h b/src/Math/Algorithms/Test/GaussJordanTest.h deleted file mode 100644 index 0c25d27e0..000000000 --- a/src/Math/Algorithms/Test/GaussJordanTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Math_Algorithms_Test_GaussJordanTest_h -#define Magnum_Math_Algorithms_Test_GaussJordanTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Algorithms { namespace Test { - -class GaussJordanTest: public Corrade::TestSuite::Tester { - public: - GaussJordanTest(); - - void singular(); - void invert(); -}; - -}}}} - -#endif diff --git a/src/Math/Algorithms/Test/GramSchmidtTest.cpp b/src/Math/Algorithms/Test/GramSchmidtTest.cpp new file mode 100644 index 000000000..28700089d --- /dev/null +++ b/src/Math/Algorithms/Test/GramSchmidtTest.cpp @@ -0,0 +1,100 @@ +/* + 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/Algorithms/GramSchmidt.h" + +namespace Magnum { namespace Math { namespace Algorithms { namespace Test { + +class GramSchmidtTest: public Corrade::TestSuite::Tester { + public: + GramSchmidtTest(); + + void orthogonalize(); + void orthonormalize(); +}; + +typedef RectangularMatrix<3, 3, Float> Matrix3; +typedef Vector<3, Float> Vector3; + +GramSchmidtTest::GramSchmidtTest() { + addTests({&GramSchmidtTest::orthogonalize, + &GramSchmidtTest::orthonormalize}); +} + +void GramSchmidtTest::orthogonalize() { + Matrix3 m(Vector3(3.0f, 5.0f, 1.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, -3.0f)); + + Matrix3 orthogonalized = Algorithms::gramSchmidtOrthogonalize(m); + + /* Verify the first vector is in direction of first original */ + CORRADE_COMPARE(orthogonalized[0], m[0]); + + /* (The vectors don't need to unit length) */ + + /* Verify the vectors are orthogonal */ + CORRADE_COMPARE(Vector3::dot(orthogonalized[0], orthogonalized[1]), 0.0f); + CORRADE_COMPARE(Vector3::dot(orthogonalized[0], orthogonalized[2]), 0.0f); + CORRADE_COMPARE(Vector3::dot(orthogonalized[1], orthogonalized[2]), 0.0f); + + /* Just to be sure */ + Matrix3 expected(Vector3( 3.0f, 5.0f, 1.0f), + Vector3(0.657143f, -1.571429f, 5.885714f), + Vector3(6.086759f, -3.3379f, -1.570777f)); + CORRADE_COMPARE(orthogonalized, expected); +} + +void GramSchmidtTest::orthonormalize() { + Matrix3 m(Vector3(3.0f, 5.0f, 8.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, 8.0f)); + + Matrix3 orthonormalized = Algorithms::gramSchmidtOrthonormalize(m); + + /* Verify the first vector is in direction of first original */ + CORRADE_COMPARE(orthonormalized[0], m[0].normalized()); + + /* Verify the vectors have unit length */ + CORRADE_COMPARE(orthonormalized[0].length(), 1.0f); + CORRADE_COMPARE(orthonormalized[1].length(), 1.0f); + CORRADE_COMPARE(orthonormalized[2].length(), 1.0f); + + /* Verify the vectors are orthogonal */ + CORRADE_COMPARE(Vector3::dot(orthonormalized[0], orthonormalized[1]), 0.0f); + CORRADE_COMPARE(Vector3::dot(orthonormalized[0], orthonormalized[2]), 0.0f); + CORRADE_COMPARE(Vector3::dot(orthonormalized[1], orthonormalized[2]), 0.0f); + + /* Just to be sure */ + Matrix3 expected(Vector3( 0.303046f, 0.505076f, 0.808122f), + Vector3( 0.928316f, -0.348119f, -0.130544f), + Vector3(-0.215388f, -0.789754f, 0.574367f)); + CORRADE_COMPARE(orthonormalized, expected); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::GramSchmidtTest) diff --git a/src/Math/Algorithms/Test/SvdTest.cpp b/src/Math/Algorithms/Test/SvdTest.cpp new file mode 100644 index 000000000..ca1a1219b --- /dev/null +++ b/src/Math/Algorithms/Test/SvdTest.cpp @@ -0,0 +1,106 @@ +/* + 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/Algorithms/Svd.h" + +namespace Magnum { namespace Math { namespace Algorithms { namespace Test { + +class SvdTest: public Corrade::TestSuite::Tester { + public: + explicit SvdTest(); + + void testDouble(); + void testFloat(); +}; + +typedef RectangularMatrix<5, 8, Double> Matrix5x8d; +typedef Matrix<8, Double> Matrix8d; +typedef Matrix<5, Double> Matrix5d; +typedef Vector<8, Double> Vector8d; +typedef Vector<5, Double> Vector5d; + +typedef RectangularMatrix<5, 8, Float> Matrix5x8f; +typedef Matrix<8, Float> Matrix8f; +typedef Matrix<5, Float> Matrix5f; +typedef Vector<8, Float> Vector8f; +typedef Vector<5, Float> Vector5f; + +constexpr static Matrix5x8d a( + Vector8d(22.0, 14.0, -1.0, -3.0, 9.0, 9.0, 2.0, 4.0), + Vector8d(10.0, 7.0, 13.0, -2.0, 8.0, 1.0, -6.0, 5.0), + Vector8d( 2.0, 10.0, -1.0, 13.0, 1.0, -7.0, 6.0, 0.0), + Vector8d( 3.0, 0.0, -11.0, -2.0, -2.0, 5.0, 5.0, -2.0), + Vector8d( 7.0, 8.0, 3.0, 4.0, 4.0, -1.0, 1.0, 2.0) +); + +static const Vector5d expected(std::sqrt(1248.0), 0.0, 20.0, std::sqrt(384.0), 0.0); + +SvdTest::SvdTest() { + addTests({&SvdTest::testDouble, + &SvdTest::testFloat}); +} + +void SvdTest::testDouble() { + Matrix5x8d u; + Vector5d w; + Matrix5d v; + std::tie(u, w, v) = Algorithms::svd(a); + + /* Test composition */ + Matrix8d u2(u[0], u[1], u[2], u[3], u[4], Vector8d(), Vector8d(), Vector8d()); + Matrix5x8d w2 = Matrix5x8d::fromDiagonal(w); + CORRADE_COMPARE(u2*w2*v.transposed(), a); + + /* Test that V is unitary */ + CORRADE_COMPARE(v*v.transposed(), Matrix5d(Matrix5d::Identity)); + CORRADE_COMPARE(v.transposed()*v, Matrix5d(Matrix5d::Identity)); + + /* Test W */ + CORRADE_COMPARE(w, expected); +} + +void SvdTest::testFloat() { + Matrix5x8f u; + Vector5f w; + Matrix5f v; + std::tie(u, w, v) = Algorithms::svd(Matrix5x8f(a)); + + /* Test composition (single precision is not enough, test for similarity) */ + Matrix8f u2(u[0], u[1], u[2], u[3], u[4], Vector8f(), Vector8f(), Vector8f()); + Matrix5x8f w2 = Matrix5x8f::fromDiagonal(w); + CORRADE_VERIFY((u2*w2*v.transposed()-Matrix5x8f(a)).maxAbs() < 1.0e-5f); + + /* Test that V is unitary */ + CORRADE_COMPARE(v*v.transposed(), Matrix5f(Matrix5f::Identity)); + CORRADE_COMPARE(v.transposed()*v, Matrix5f(Matrix5f::Identity)); + + /* Test W (single precision is not enough, test for similarity) */ + CORRADE_VERIFY((w-Vector5f(expected)).maxAbs() < 1.0e-5f); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::SvdTest) diff --git a/src/Math/Angle.cpp b/src/Math/Angle.cpp new file mode 100644 index 000000000..bae169c3f --- /dev/null +++ b/src/Math/Angle.cpp @@ -0,0 +1,38 @@ +/* + 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 "Angle.h" + +namespace Magnum { namespace Math { + +#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&); +#endif +#endif + +}} diff --git a/src/Math/Angle.h b/src/Math/Angle.h new file mode 100644 index 000000000..8c95d20d4 --- /dev/null +++ b/src/Math/Angle.h @@ -0,0 +1,261 @@ +#ifndef Magnum_Math_Angle_h +#define Magnum_Math_Angle_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::Math::Deg, Magnum::Math::Rad and related operators. + */ + +#include +#include + +#include "Math/Constants.h" +#include "Math/Math.h" +#include "Math/Unit.h" + +#include "magnumVisibility.h" + +namespace Magnum { namespace Math { + +/** +@brief Angle in degrees + +Along with Rad provides convenience classes to make angle specification and +conversion less error-prone. + +@section Rad-usage Usage + +You can enter the value either by using literal: +@code +auto degrees = 60.0_degf; // type is Deg +auto radians = 1.047_rad; // type is Rad +@endcode + +Or explicitly convert unitless value (such as output from some function) to +either degrees or radians: +@code +Double foo(); + +Deg degrees(35.0f); +Rad radians(foo()); +//degrees = 60.0f; // error, no implicit conversion +@endcode + +The classes support all arithmetic operations, such as addition, subtraction +or multiplication/division by unitless number: +@code +auto a = 60.0_degf + 17.35_degf; +auto b = -a + 23.0_degf*4; +//auto c = 60.0_degf*45.0_degf; // error, undefined resulting unit +@endcode + +It is also possible to compare angles with all comparison operators, but +comparison of degrees and radians is not possible without explicit conversion +to common type: +@code +Rad angle(); + +Deg x = angle(); // convert to degrees for easier comparison +if(x < 30.0_degf) foo(); +//if(x > 1.57_radf) bar(); // error, both need to be of the same type +@endcode + +It is possible to seamlessly convert between degrees and radians and explicitly +convert the value back to underlying type: +@code +Float sine(Rad angle); +Float a = sine(60.0_degf); // the same as sine(1.047_radf) +Deg b = 1.047_rad; // the same as 60.0_deg +Float d = Double(b); // 60.0 +//Float e = b; // error, no implicit conversion +@endcode + +@section Rad-conversions Requirement of explicit conversion + +The requirement of explicit conversions from and to unitless types helps to +reduce unit-based errors. Consider following example with implicit conversions +allowed: +@code +Float std::sin(Float angle); +Float sine(Rad angle); + +Float a = 60.0f; // degrees +sine(a); // silent error, sine() expected radians + +auto b = 60.0_degf; // degrees +std::sin(b); // silent error, std::sin() expected radians +@endcode + +These silent errors are easily avoided by requiring explicit conversions: +@code +//sine(angleInDegrees); // compilation error +sine(Deg(angleInDegrees)); // explicitly specifying unit + +//std::sin(angleInDegrees); // compilation error +std::sin(Float(Rad(angleInDegrees)); // required explicit conversion hints + // to user that this case needs special + // attention (i.e., conversion to radians) +@endcode + +@see Magnum::Deg, Magnum::Degd +*/ +template class Deg: public Unit { + public: + /** @brief Default constructor */ + inline constexpr /*implicit*/ Deg() {} + + /** @brief Explicit constructor from unitless type */ + inline constexpr explicit Deg(T value): Unit(value) {} + + /** @brief Copy constructor */ + inline constexpr /*implicit*/ Deg(Unit value): Unit(value) {} + + /** @brief Construct from another underlying type */ + template inline constexpr explicit Deg(Unit value): Unit(value) {} + + /** + * @brief Construct degrees from radians + * + * Performs conversion from radians to degrees, i.e.: + * @f[ + * deg = 180 \frac {rad} \pi + * @f] + */ + inline constexpr /*implicit*/ Deg(Unit value); +}; + +#ifndef CORRADE_GCC46_COMPATIBILITY +/** @relates Deg +@brief Double-precision degree value literal + +Example usage: +@code +Double cosine = Math::cos(60.0_deg); // cosine = 0.5 +Double cosine = Math::cos(1.047_rad); // cosine = 0.5 +@endcode +@see Magnum::operator""_deg(), operator""_degf(), operator""_rad() +@note Not available on GCC < 4.7. Use Deg::Deg(T) instead. +*/ +inline constexpr Deg operator "" _deg(long double value) { return Deg(value); } + +/** @relates Deg +@brief Single-precision degree value literal + +Example usage: +@code +Float tangent = Math::tan(60.0_degf); // tangent = 1.732f +Float tangent = Math::tan(1.047_radf); // tangent = 1.732f +@endcode +@see Magnum::operator""_degf(), operator""_deg(), operator""_radf() +@note Not available on GCC < 4.7. Use Deg::Deg(T) instead. +*/ +inline constexpr Deg operator "" _degf(long double value) { return Deg(value); } +#endif + +/** +@brief Angle in radians + +See Deg for more information. +@see Magnum::Rad, Magnum::Radd +*/ +template class Rad: public Unit { + public: + /** @brief Default constructor */ + inline constexpr /*implicit*/ Rad() {} + + /** @brief Construct from unitless type */ + inline constexpr explicit Rad(T value): Unit(value) {} + + /** @brief Copy constructor */ + inline constexpr /*implicit*/ Rad(Unit value): Unit(value) {} + + /** @brief Construct from another underlying type */ + template inline constexpr explicit Rad(Unit value): Unit(value) {} + + /** + * @brief Construct radians from degrees + * + * Performs conversion from degrees to radians, i.e.: + * @f[ + * rad = deg \frac \pi 180 + * @f] + */ + inline constexpr /*implicit*/ Rad(Unit value); +}; + +#ifndef CORRADE_GCC46_COMPATIBILITY +/** @relates Rad +@brief Double-precision radian value literal + +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); } + +/** @relates Rad +@brief Single-precision radian value literal + +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); } +#endif + +template inline constexpr Deg::Deg(Unit value): Unit(T(180)*T(value)/Math::Constants::pi()) {} +template inline constexpr Rad::Rad(Unit value): Unit(T(value)*Math::Constants::pi()/T(180)) {} + +/** @debugoperator{Magnum::Math::Rad} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit& value) { + debug << "Rad("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << T(value) << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/** @debugoperator{Magnum::Math::Deg} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit& value) { + debug << "Deg("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << T(value) << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/* Explicit instantiation for commonly used types */ +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); +#ifndef MAGNUM_TARGET_GLES +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); +#endif +#endif + +}} + +#endif diff --git a/src/Math/BoolVector.h b/src/Math/BoolVector.h new file mode 100644 index 000000000..bb1433091 --- /dev/null +++ b/src/Math/BoolVector.h @@ -0,0 +1,271 @@ +#ifndef Magnum_Math_BoolVector_h +#define Magnum_Math_BoolVector_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::Math::BoolVector + */ + +#include +#include + +#include "Types.h" + +namespace Magnum { namespace Math { + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct Sequence {}; + + /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ + template struct GenerateSequence: + GenerateSequence {}; + + template struct GenerateSequence<0, sequence...> { + typedef Sequence Type; + }; + + template inline constexpr T repeat(T value, std::size_t) { return value; } +} +#endif + +/** +@brief %Vector storing boolean values +@tparam size Bit count + +Result of component-wise comparison from Vector. The boolean values are stored +as bits in array of unsigned bytes, unused bits have undefined value which +doesn't affect comparison or all() / none() / any() functions. See also +@ref matrix-vector for brief introduction. +*/ +template class BoolVector { + static_assert(size != 0, "BoolVector cannot have zero elements"); + + public: + static const std::size_t Size = size; /**< @brief %Vector size */ + static const std::size_t DataSize = (size-1)/8+1; /**< @brief %Vector storage size */ + + /** @brief Construct zero-filled boolean vector */ + inline constexpr BoolVector(): _data() {} + + /** + * @brief Construct boolean vector from segment values + * @param first Value for first 8bit segment + * @param next Values for next Bbit segments + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next); + #else + template::type> inline constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next): _data{first, UnsignedByte(next)...} {} + #endif + + /** @brief Construct boolean vector with one value for all fields */ + #ifdef DOXYGEN_GENERATING_OUTPUT + 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) {} + #else + template::value && size != 1, bool>::type> inline explicit BoolVector(T value) { + *this = BoolVector(typename Implementation::GenerateSequence::Type(), value ? FullSegmentMask : 0); + } + #endif + #endif + + /** @brief Copy constructor */ + inline constexpr BoolVector(const BoolVector&) = default; + + /** @brief Copy assignment */ + inline BoolVector& operator=(const BoolVector&) = default; + + /** + * @brief Raw data + * @return %Array of DataSize length + * + * @see operator[](), set() + */ + inline UnsignedByte* data() { return _data; } + inline constexpr const UnsignedByte* data() const { return _data; } /**< @overload */ + + /** @brief Bit at given position */ + inline 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) { + _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; + } + + /** @brief Non-equality comparison */ + inline 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; + } + + /** @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; + } + + /** @brief Whether any bit is set */ + inline 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; + } + + /** + * @brief Bitwise AND and assign + * + * The computation is done in-place. + */ + inline BoolVector& operator&=(const BoolVector& other) { + for(std::size_t i = 0; i != DataSize; ++i) + _data[i] &= other._data[i]; + + return *this; + } + + /** + * @brief Bitwise AND + * + * @see operator&=() + */ + inline BoolVector operator&(const BoolVector& other) const { + return BoolVector(*this) &= other; + } + + /** + * @brief Bitwise OR and assign + * + * The computation is done in-place. + */ + inline BoolVector& operator|=(const BoolVector& other) { + for(std::size_t i = 0; i != DataSize; ++i) + _data[i] |= other._data[i]; + + return *this; + } + + /** + * @brief Bitwise OR + * + * @see operator|=() + */ + inline BoolVector operator|(const BoolVector& other) const { + return BoolVector(*this) |= other; + } + + /** + * @brief Bitwise XOR and assign + * + * The computation is done in-place. + */ + inline BoolVector& operator^=(const BoolVector& other) { + for(std::size_t i = 0; i != DataSize; ++i) + _data[i] ^= other._data[i]; + + return *this; + } + + /** + * @brief Bitwise XOR + * + * @see operator^=() + */ + inline BoolVector operator^(const BoolVector& other) const { + return BoolVector(*this) ^= other; + } + + private: + enum: UnsignedByte { + FullSegmentMask = 0xFF, + LastSegmentMask = (1 << size%8) - 1 + }; + + /* Implementation for Vector::Vector(U) */ + template inline constexpr explicit BoolVector(Implementation::Sequence, UnsignedByte value): _data{Implementation::repeat(value, sequence)...} {} + + UnsignedByte _data[(size-1)/8+1]; +}; + +/** @debugoperator{Magnum::Math::BoolVector} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const BoolVector& value) { + debug << "BoolVector("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + for(std::size_t i = 0; i != size; ++i) { + if(i && !(i%8)) debug << " "; + debug << (value[i] ? "1" : "0"); + } + debug << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +}} + +#endif diff --git a/src/Math/CMakeLists.txt b/src/Math/CMakeLists.txt index a92da34c4..9552fd85c 100644 --- a/src/Math/CMakeLists.txt +++ b/src/Math/CMakeLists.txt @@ -1,25 +1,55 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +# +# 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. +# set(MagnumMath_HEADERS + Angle.h + BoolVector.h + Complex.h Constants.h + Dual.h + DualComplex.h + DualQuaternion.h + Functions.h Math.h - MathTypeTraits.h + TypeTraits.h Matrix.h Matrix3.h Matrix4.h - Point2D.h - Point3D.h + Quaternion.h RectangularMatrix.h + Swizzle.h + Unit.h Vector.h Vector2.h Vector3.h Vector4.h) + install(FILES ${MagnumMath_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math) add_subdirectory(Algorithms) add_subdirectory(Geometry) if(BUILD_TESTS) - enable_testing() add_subdirectory(Test) endif() diff --git a/src/Math/Complex.cpp b/src/Math/Complex.cpp new file mode 100644 index 000000000..0b234116c --- /dev/null +++ b/src/Math/Complex.cpp @@ -0,0 +1,36 @@ +/* + 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 new file mode 100644 index 000000000..2a2cb2349 --- /dev/null +++ b/src/Math/Complex.h @@ -0,0 +1,449 @@ +#ifndef Magnum_Math_Complex_h +#define Magnum_Math_Complex_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::Math::Complex + */ + +#include +#include +#include + +#include "Math/Matrix.h" +#include "Math/Vector2.h" + +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) { + return {matrix[0][0], matrix[0][1]}; + } +} +#endif + +/** +@brief %Complex number +@tparam T Data type + +Represents 2D rotation. See @ref transformations for brief introduction. +@see Magnum::Complex, Magnum::Complexd, Matrix3 +*/ +template class Complex { + public: + typedef T Type; /**< @brief Underlying data type */ + + /** + * @brief Dot product + * + * @f[ + * c_0 \cdot c_1 = a_0 a_1 + b_0 b_1 + * @f] + * @see dot() const + */ + inline static T dot(const Complex& a, const Complex& b) { + return a._real*b._real + a._imaginary*b._imaginary; + } + + /** + * @brief Angle between normalized complex numbers + * + * Expects that both complex numbers are normalized. @f[ + * \theta = acos \left( \frac{Re(c_0 \cdot c_1))}{|c_0| |c_1|} \right) = acos (a_0 a_1 + b_0 b_1) + * @f] + * @see isNormalized(), Quaternion::angle(), Vector::angle() + */ + inline 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)); + } + + /** + * @brief Rotation complex number + * @param angle Rotation angle (counterclockwise) + * + * @f[ + * c = cos \theta + i sin \theta + * @f] + * @see angle(), Matrix3::rotation(), Quaternion::rotation() + */ + inline static Complex rotation(Rad angle) { + return {std::cos(T(angle)), std::sin(T(angle))}; + } + + /** + * @brief Create complex number from rotation matrix + * + * 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) { + CORRADE_ASSERT(matrix.isOrthogonal(), + "Math::Complex::fromMatrix(): the matrix is not orthogonal", {}); + return Implementation::complexFromMatrix(matrix); + } + + /** + * @brief Default constructor + * + * Constructs unit complex number. @f[ + * c = 1 + i0 + * @f] + */ + inline constexpr /*implicit*/ Complex(): _real(T(1)), _imaginary(T(0)) {} + + /** + * @brief Construct complex number from real and imaginary part + * + * @f[ + * c = a + ib + * @f] + */ + inline constexpr /*implicit*/ Complex(T real, T imaginary): _real(real), _imaginary(imaginary) {} + + /** + * @brief Construct complex number from vector + * + * To be used in transformations later. @f[ + * c = v_x + iv_y + * @f] + * @see operator Vector2(), transformVector() + */ + inline constexpr explicit Complex(const Vector2& vector): _real(vector.x()), _imaginary(vector.y()) {} + + /** @brief Equality comparison */ + inline 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 { + return !operator==(other); + } + + /** + * @brief Whether the complex number is normalized + * + * Complex number is normalized if it has unit length: @f[ + * |c|^2 = |c| = 1 + * @f] + * @see dot(), normalized() + */ + inline bool isNormalized() const { + return Implementation::isNormalizedSquared(dot()); + } + + /** @brief Real part */ + inline constexpr T real() const { return _real; } + + /** @brief Imaginary part */ + inline constexpr T imaginary() const { return _imaginary; } + + /** + * @brief Convert complex number to vector + * + * @f[ + * \boldsymbol v = \begin{pmatrix} a \\ b \end{pmatrix} + * @f] + */ + inline constexpr explicit operator Vector2() const { + return {_real, _imaginary}; + } + + /** + * @brief Rotation angle of complex number + * + * @f[ + * \theta = atan2(b, a) + * @f] + * @see rotation() + */ + inline Rad angle() const { + return Rad(std::atan2(_imaginary, _real)); + } + + /** + * @brief Convert complex number to rotation matrix + * + * @f[ + * M = \begin{pmatrix} + * a & -b \\ + * b & a + * \end{pmatrix} + * @f] + * @see fromMatrix(), DualComplex::toMatrix(), + * Matrix3::from(const Matrix<2, T>&, const Vector2&) + */ + Matrix<2, T> toMatrix() const { + return {Vector<2, T>(_real, _imaginary), + Vector<2, T>(-_imaginary, _real)}; + } + + /** + * @brief Add complex number and assign + * + * The computation is done in-place. @f[ + * c_0 + c_1 = (a_0 + a_1) + i(b_0 + b_1) + * @f] + */ + inline Complex& operator+=(const Complex& other) { + _real += other._real; + _imaginary += other._imaginary; + return *this; + } + + /** + * @brief Add complex number + * + * @see operator+=() + */ + inline Complex operator+(const Complex& other) const { + return Complex(*this) += other; + } + + /** + * @brief Negated complex number + * + * @f[ + * -c = -a -ib + * @f] + */ + inline Complex operator-() const { + return {-_real, -_imaginary}; + } + + /** + * @brief Subtract complex number and assign + * + * The computation is done in-place. @f[ + * c_0 - c_1 = (a_0 - a_1) + i(b_0 - b_1) + * @f] + */ + inline Complex& operator-=(const Complex& other) { + _real -= other._real; + _imaginary -= other._imaginary; + return *this; + } + + /** + * @brief Subtract complex number + * + * @see operator-=() + */ + inline Complex operator-(const Complex& other) const { + return Complex(*this) -= other; + } + + /** + * @brief Multiply with scalar and assign + * + * The computation is done in-place. @f[ + * c \cdot t = ta + itb + * @f] + */ + inline Complex& operator*=(T scalar) { + _real *= scalar; + _imaginary *= scalar; + return *this; + } + + /** + * @brief Multiply with scalar + * + * @see operator*=(T) + */ + inline Complex operator*(T scalar) const { + return Complex(*this) *= scalar; + } + + /** + * @brief Divide with scalar and assign + * + * The computation is done in-place. @f[ + * \frac c t = \frac a t + i \frac b t + * @f] + */ + inline Complex& operator/=(T scalar) { + _real /= scalar; + _imaginary /= scalar; + return *this; + } + + /** + * @brief Divide with scalar + * + * @see operator/=(T) + */ + inline Complex operator/(T scalar) const { + return Complex(*this) /= scalar; + } + + /** + * @brief Multiply with complex number + * + * @f[ + * 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 { + return {_real*other._real - _imaginary*other._imaginary, + _imaginary*other._real + _real*other._imaginary}; + } + + /** + * @brief Dot product of the complex number + * + * Should be used instead of length() for comparing complex number length + * with other values, because it doesn't compute the square root. @f[ + * c \cdot c = a^2 + b^2 + * @f] + * @see dot(const Complex&, const Complex&), isNormalized() + */ + inline T dot() const { + return dot(*this, *this); + } + + /** + * @brief %Complex number length + * + * See also dot() const which is faster for comparing length with other + * values. @f[ + * |c| = \sqrt{c \cdot c} + * @f] + * @see isNormalized() + */ + inline T length() const { + return std::hypot(_real, _imaginary); + } + + /** + * @brief Normalized complex number (of unit length) + * + * @see isNormalized() + */ + inline Complex normalized() const { + return (*this)/length(); + } + + /** + * @brief Conjugated complex number + * + * @f[ + * c^* = a - ib + * @f] + */ + inline Complex conjugated() const { + return {_real, -_imaginary}; + } + + /** + * @brief Inverted complex number + * + * See invertedNormalized() which is faster for normalized + * complex numbers. @f[ + * c^{-1} = \frac{c^*}{|c|^2} = \frac{c^*}{c \cdot c} + * @f] + */ + inline Complex inverted() const { + return conjugated()/dot(); + } + + /** + * @brief Inverted normalized complex number + * + * Equivalent to conjugated(). Expects that the complex number is + * normalized. @f[ + * c^{-1} = \frac{c^*}{c \cdot c} = c^* + * @f] + * @see isNormalized(), inverted() + */ + inline Complex invertedNormalized() const { + CORRADE_ASSERT(isNormalized(), + "Math::Complex::invertedNormalized(): complex number must be normalized", + Complex(std::numeric_limits::quiet_NaN(), {})); + return conjugated(); + } + + /** + * @brief Rotate vector with complex number + * + * @f[ + * v' = c v = c (v_x + iv_y) + * @f] + * @see Complex(const Vector2&), operator Vector2(), Matrix3::transformVector() + */ + inline Vector2 transformVector(const Vector2& vector) const { + return Vector2((*this)*Complex(vector)); + } + + private: + T _real, _imaginary; +}; + +/** @relates Complex +@brief Multiply scalar with complex + +Same as Complex::operator*(T) const. +*/ +template inline Complex operator*(T scalar, const Complex& complex) { + return complex*scalar; +} + +/** @relates Complex +@brief Divide complex with number and invert + +@f[ + \frac t c = \frac t a + i \frac t b +@f] +@see Complex::operator/() +*/ +template inline Complex operator/(T scalar, const Complex& complex) { + return {scalar/complex.real(), scalar/complex.imaginary()}; +} + +/** @debugoperator{Magnum::Math::Complex} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Complex& value) { + debug << "Complex("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.real() << ", " << value.imaginary() << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/* Explicit instantiation for commonly used types */ +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Complex&); +#ifndef MAGNUM_TARGET_GLES +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Complex&); +#endif +#endif + +}} + +#endif diff --git a/src/Math/Constants.h b/src/Math/Constants.h index 0b27ae947..9f7402da6 100644 --- a/src/Math/Constants.h +++ b/src/Math/Constants.h @@ -1,38 +1,51 @@ #ifndef Magnum_Math_Constants_h #define Magnum_Math_Constants_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::Constants, functions Magnum::Math::deg(), Magnum::Math::rad() + * @brief Class Magnum::Math::Constants */ +#include "Types.h" + namespace Magnum { namespace Math { /** @brief Numeric constants -@see Magnum::Constants +@see Magnum::Constants, Magnum::Constantsd */ template struct Constants { - /* See MathTypeTraits for answer why these are functions and not constants. */ + Constants() = delete; + + /* See TypeTraits for answer why these are functions and not constants. */ #ifdef DOXYGEN_GENERATING_OUTPUT /** * @brief Pi * - * @see deg(), rad() + * @see Deg, Rad */ static inline constexpr T pi(); @@ -42,41 +55,22 @@ template struct Constants { }; #ifndef DOXYGEN_GENERATING_OUTPUT -template<> struct Constants { - static inline constexpr double pi() { return 3.141592653589793; } - static inline constexpr double sqrt2() { return 1.414213562373095; } - static inline constexpr double sqrt3() { return 1.732050807568877; } +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; } }; -template<> struct Constants { - static inline constexpr float pi() { return 3.141592654f; } - static inline constexpr float sqrt2() { return 1.414213562f; } - static inline constexpr float sqrt3() { return 1.732050808f; } +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; } }; #endif -/** -@brief Angle in degrees - -Function to make angle entering less error-prone. Converts the value to -radians at compile time. For example `deg(180.0f)` is converted to `3.14f`. - -Usable for entering e.g. rotation: -@code -Matrix4::rotation(deg(30.0f), Vector3::yAxis()); -@endcode - -This function (and also rad()) is available also in Magnum namespace itself. -@see Constants, rad() - */ -template inline constexpr T deg(T value) { return value*Constants::pi()/180; } - -/** - * @brief Angle in radians - * - * See deg() for more information. - */ -template inline constexpr T rad(T value) { return value; } - }} #endif diff --git a/src/Math/Dual.h b/src/Math/Dual.h new file mode 100644 index 000000000..630a6f736 --- /dev/null +++ b/src/Math/Dual.h @@ -0,0 +1,224 @@ +#ifndef Magnum_Math_Dual_h +#define Magnum_Math_Dual_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::Math::Dual + */ + +#include +#include + +#include "Math/TypeTraits.h" + +namespace Magnum { namespace Math { + +/** +@brief %Dual number +@tparam T Underlying data type +*/ +template class Dual { + template friend class Dual; + + public: + typedef T Type; /**< @brief Underlying data type */ + + /** + * @brief Default constructor + * + * Both parts are default-constructed. + */ + inline constexpr /*implicit*/ Dual(): _real(), _dual() {} + + /** + * @brief Construct dual number from real and dual part + * + * @f[ + * \hat a = a_0 + \epsilon a_\epsilon + * @f] + */ + inline constexpr /*implicit*/ Dual(const T& real, const T& dual = T()): _real(real), _dual(dual) {} + + /** @brief Equality comparison */ + inline 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 { + return !operator==(other); + } + + /** @brief Real part */ + inline constexpr T real() const { return _real; } + + /** @brief %Dual part */ + inline constexpr T dual() const { return _dual; } + + /** + * @brief Add and assign dual number + * + * The computation is done in-place. @f[ + * \hat a + \hat b = a_0 + b_0 + \epsilon (a_\epsilon + b_\epsilon) + * @f] + */ + inline Dual& operator+=(const Dual& other) { + _real += other._real; + _dual += other._dual; + return *this; + } + + /** + * @brief Add dual number + * + * @see operator+=() + */ + inline Dual operator+(const Dual& other) const { + return Dual(*this)+=other; + } + + /** + * @brief Negated dual number + * + * @f[ + * -\hat a = -a_0 - \epsilon a_\epsilon + * @f] + */ + inline Dual operator-() const { + return {-_real, -_dual}; + } + + /** + * @brief Subtract and assign dual number + * + * The computation is done in-place. @f[ + * \hat a - \hat b = a_0 - b_0 + \epsilon (a_\epsilon - b_\epsilon) + * @f] + */ + inline Dual& operator-=(const Dual& other) { + _real -= other._real; + _dual -= other._dual; + return *this; + } + + /** + * @brief Subtract dual number + * + * @see operator-=() + */ + inline Dual operator-(const Dual& other) const { + return Dual(*this)-=other; + } + + /** + * @brief Multiply by dual number + * + * @f[ + * \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 { + return {_real*other._real, _real*other._dual + _dual*other._real}; + } + + /** + * @brief Divide by dual number + * + * @f[ + * \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 { + return {_real/other._real, (_dual*other._real - _real*other._dual)/(other._real*other._real)}; + } + + /** + * @brief Conjugated dual number + * + * @f[ + * \overline{\hat a} = a_0 - \epsilon a_\epsilon + * @f] + */ + inline Dual conjugated() const { + return {_real, -_dual}; + } + + private: + T _real, _dual; +}; + +#ifndef DOXYGEN_GENERATING_OUTPUT +#define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying) \ + inline Type operator-() const { \ + return Dual>::operator-(); \ + } \ + inline Type& operator+=(const Dual>& other) { \ + Dual>::operator+=(other); \ + return *this; \ + } \ + inline Type operator+(const Dual>& other) const { \ + return Dual>::operator+(other); \ + } \ + inline Type& operator-=(const Dual>& other) { \ + Dual>::operator-=(other); \ + return *this; \ + } \ + inline Type operator-(const Dual>& other) const { \ + return Dual>::operator-(other); \ + } \ + template inline Type operator*(const Dual& other) const { \ + return Dual>::operator*(other); \ + } \ + template inline Type operator/(const Dual& other) const { \ + return Dual>::operator/(other); \ + } +#endif + +/** @debugoperator{Magnum::Math::Dual} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Dual& value) { + debug << "Dual("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.real() << ", " << value.dual() << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/** @relates Dual +@brief Square root of dual number + +@f[ + \sqrt{\hat a} = \sqrt{a_0} + \epsilon \frac{a_\epsilon}{2 \sqrt{a_0}} +@f] +@see Math::sqrt(const T&) +*/ +template Dual sqrt(const Dual& dual) { + T sqrt0 = std::sqrt(dual.real()); + return {sqrt0, dual.dual()/(2*sqrt0)}; +} + +}} + +#endif diff --git a/src/Math/DualComplex.cpp b/src/Math/DualComplex.cpp new file mode 100644 index 000000000..9b18e9abc --- /dev/null +++ b/src/Math/DualComplex.cpp @@ -0,0 +1,36 @@ +/* + 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 new file mode 100644 index 000000000..648f9f6bc --- /dev/null +++ b/src/Math/DualComplex.h @@ -0,0 +1,351 @@ +#ifndef Magnum_Math_DualComplex_h +#define Magnum_Math_DualComplex_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::Math::DualComplex + */ + +#include "Math/Dual.h" +#include "Math/Complex.h" +#include "Math/Matrix3.h" + +namespace Magnum { namespace Math { + +/** +@brief %Dual complex number +@tparam T Underlying data type + +Represents 2D rotation and translation. See @ref transformations for brief +introduction. +@see Magnum::DualComplex, Magnum::DualComplexd, Dual, Complex, Matrix3 +@todo Can this be done similarly as in dual quaternions? It sort of works, but + the math beneath is weird. +*/ +template class DualComplex: public Dual> { + public: + typedef T Type; /**< @brief Underlying data type */ + + /** + * @brief Rotation dual complex number + * @param angle Rotation angle (counterclockwise) + * + * @f[ + * \hat c = (cos \theta + i sin \theta) + \epsilon (0 + i0) + * @f] + * @see angle(), Complex::rotation(), Matrix3::rotation(), + * DualQuaternion::rotation() + */ + inline static DualComplex rotation(Rad angle) { + return {Complex::rotation(angle), {{}, {}}}; + } + + /** + * @brief Translation dual complex number + * @param vector Translation vector + * + * @f[ + * \hat c = (0 + i1) + \epsilon (v_x + iv_y) + * @f] + * @see translation() const, Matrix3::translation(const Vector2&), + * DualQuaternion::translation(), Vector2::xAxis(), Vector2::yAxis() + */ + inline static DualComplex translation(const Vector2& vector) { + return {{}, {vector.x(), vector.y()}}; + } + + /** + * @brief Create dual complex number from rotation matrix + * + * Expects that the matrix represents rigid transformation. + * @see toMatrix(), Complex::fromMatrix(), + * Matrix3::isRigidTransformation() + */ + inline 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())}; + } + + /** + * @brief Default constructor + * + * Creates unit dual complex number. @f[ + * \hat c = (0 + i1) + \epsilon (0 + i0) + * @f] + * @todoc Remove workaround when Doxygen is predictable + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + inline constexpr /*implicit*/ DualComplex(); + #else + inline constexpr /*implicit*/ DualComplex(): Dual>({}, {T(0), T(0)}) {} + #endif + + /** + * @brief Construct dual complex number from real and dual part + * + * @f[ + * \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) {} + + /** + * @brief Construct dual complex number from vector + * + * To be used in transformations later. @f[ + * \hat c = (0 + i1) + \epsilon(v_x + iv_y) + * @f] + * @todoc Remove workaround when Doxygen is predictable + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit DualComplex(const Vector2& vector); + #else + inline constexpr explicit DualComplex(const Vector2& vector): Dual>({}, Complex(vector)) {} + #endif + + /** + * @brief Whether the dual complex number is normalized + * + * Dual complex number is normalized if its real part has unit length: @f[ + * |c_0|^2 = |c_0| = 1 + * @f] + * @see Complex::dot(), normalized() + */ + inline bool isNormalized() const { + return Implementation::isNormalizedSquared(lengthSquared()); + } + + /** + * @brief Rotation part of dual complex number + * + * @see Complex::angle() + */ + inline constexpr Complex rotation() const { + return this->real(); + } + + /** + * @brief Translation part of dual complex number + * + * @f[ + * \boldsymbol a = (c_\epsilon c_0^*) + * @f] + * @see translation(const Vector2&) + */ + inline Vector2 translation() const { + return Vector2(this->dual()); + } + + /** + * @brief Convert dual complex number to transformation matrix + * + * @see fromMatrix(), Complex::toMatrix() + */ + inline Matrix3 toMatrix() const { + return Matrix3::from(this->real().toMatrix(), translation()); + } + + /** + * @brief Multipy with dual complex number + * + * @f[ + * \hat a \hat b = a_0 b_0 + \epsilon (a_0 b_\epsilon + a_\epsilon) + * @f] + * @todo can this be done similarly to dual quaternions? + */ + inline DualComplex operator*(const DualComplex& other) const { + return {this->real()*other.real(), this->real()*other.dual() + this->dual()}; + } + + /** + * @brief Complex-conjugated dual complex number + * + * @f[ + * \hat c^* = c^*_0 + c^*_\epsilon + * @f] + * @see dualConjugated(), conjugated(), Complex::conjugated() + */ + inline DualComplex complexConjugated() const { + return {this->real().conjugated(), this->dual().conjugated()}; + } + + /** + * @brief Dual-conjugated dual complex number + * + * @f[ + * \overline{\hat c} = c_0 - \epsilon c_\epsilon + * @f] + * @see complexConjugated(), conjugated(), Dual::conjugated() + */ + inline DualComplex dualConjugated() const { + return Dual>::conjugated(); + } + + /** + * @brief Conjugated dual complex number + * + * Both complex and dual conjugation. @f[ + * \overline{\hat c^*} = c^*_0 - \epsilon c^*_\epsilon = c^*_0 + \epsilon(-a_\epsilon + ib_\epsilon) + * @f] + * @see complexConjugated(), dualConjugated(), Complex::conjugated(), + * Dual::conjugated() + */ + inline DualComplex conjugated() const { + return {this->real().conjugated(), {-this->dual().real(), this->dual().imaginary()}}; + } + + /** + * @brief %Complex number length squared + * + * Should be used instead of length() for comparing complex number + * length with other values, because it doesn't compute the square root. @f[ + * |\hat c|^2 = c_0 \cdot c_0 = |c_0|^2 + * @f] + * @todo Can this be done similarly to dual quaternins? + */ + inline T lengthSquared() const { + return this->real().dot(); + } + + /** + * @brief %Dual quaternion length + * + * See lengthSquared() which is faster for comparing length with other + * values. @f[ + * |\hat c| = \sqrt{c_0 \cdot c_0} = |c_0| + * @f] + * @todo can this be done similarly to dual quaternions? + */ + inline T length() const { + return this->real().length(); + } + + /** + * @brief Normalized dual complex number (of unit length) + * + * @f[ + * c' = \frac{c_0}{|c_0|} + * @f] + * @see isNormalized() + * @todo can this be done similarly to dual quaternions? + */ + inline DualComplex normalized() const { + return {this->real()/length(), this->dual()}; + } + + /** + * @brief Inverted dual complex number + * + * See invertedNormalized() which is faster for normalized dual complex + * numbers. @f[ + * \hat c^{-1} = c_0^{-1} - \epsilon c_\epsilon + * @f] + * @todo can this be done similarly to dual quaternions? + */ + inline DualComplex inverted() const { + return DualComplex(this->real().inverted(), {{}, {}})*DualComplex({}, -this->dual()); + } + + /** + * @brief Inverted normalized dual complex number + * + * Expects that the complex number is normalized. @f[ + * \hat c^{-1} = c_0^{-1} - \epsilon c_\epsilon = c_0^* - \epsilon c_\epsilon + * @f] + * @see isNormalized(), inverted() + * @todo can this be done similarly to dual quaternions? + */ + inline DualComplex invertedNormalized() const { + return DualComplex(this->real().invertedNormalized(), {{}, {}})*DualComplex({}, -this->dual()); + } + + /** + * @brief Rotate and translate point with dual complex number + * + * See transformPointNormalized(), which is faster for normalized dual + * complex number. @f[ + * v' = \hat c v = \hat c ((0 + i) + \epsilon(v_x + iv_y)) + * @f] + * @see DualComplex(const Vector2&), dual(), Matrix3::transformPoint(), + * Complex::transformVector(), DualQuaternion::transformPoint() + */ + inline 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 { + return Dual>::operator-(); + } + inline DualComplex& operator+=(const Dual>& other) { + Dual>::operator+=(other); + return *this; + } + inline DualComplex operator+(const Dual>& other) const { + return Dual>::operator+(other); + } + inline DualComplex& operator-=(const Dual>& other) { + Dual>::operator-=(other); + return *this; + } + inline 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) {} + + /* Just to be sure nobody uses this, as it wouldn't probably work with + our operator*() */ + using Dual>::operator*; + using Dual>::operator/; +}; + +/** @debugoperator{Magnum::Math::DualQuaternion} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const DualComplex& value) { + debug << "DualComplex({"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.real().real() << ", " << value.real().imaginary() << "}, {" + << value.dual().real() << ", " << value.dual().imaginary() << "})"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/* Explicit instantiation for commonly used types */ +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const DualComplex&); +#ifndef MAGNUM_TARGET_GLES +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const DualComplex&); +#endif +#endif + +}} + +#endif diff --git a/src/Math/DualQuaternion.cpp b/src/Math/DualQuaternion.cpp new file mode 100644 index 000000000..0070e50ac --- /dev/null +++ b/src/Math/DualQuaternion.cpp @@ -0,0 +1,36 @@ +/* + 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 new file mode 100644 index 000000000..8d4837aac --- /dev/null +++ b/src/Math/DualQuaternion.h @@ -0,0 +1,339 @@ +#ifndef Magnum_Math_DualQuaternion_h +#define Magnum_Math_DualQuaternion_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::Math::DualQuaternion + */ + +#include "Math/Dual.h" +#include "Math/Matrix4.h" +#include "Math/Quaternion.h" + +namespace Magnum { namespace Math { + +/** +@brief %Dual quaternion +@tparam T Underlying data type + +Represents 3D rotation and translation. See @ref transformations for brief +introduction. +@see Magnum::DualQuaternion, Magnum::DualQuaterniond, Dual, Quaternion, Matrix4 +*/ +template class DualQuaternion: public Dual> { + public: + typedef T Type; /**< @brief Underlying data type */ + + /** + * @brief Rotation dual quaternion + * @param angle Rotation angle (counterclockwise) + * @param normalizedAxis Normalized rotation axis + * + * Expects that the rotation axis is normalized. @f[ + * \hat q = [\boldsymbol a \cdot sin \frac \theta 2, cos \frac \theta 2] + \epsilon [\boldsymbol 0, 0] + * @f] + * @see rotation() const, Quaternion::rotation(), Matrix4::rotation(), + * DualComplex::rotation(), Vector3::xAxis(), Vector3::yAxis(), + * Vector3::zAxis(), Vector::isNormalized() + */ + inline static DualQuaternion rotation(Rad angle, const Vector3& normalizedAxis) { + return {Quaternion::rotation(angle, normalizedAxis), {{}, T(0)}}; + } + + /** @todo Rotation about axis with arbitrary origin, screw motion */ + + /** + * @brief Translation dual quaternion + * @param vector Translation vector + * + * @f[ + * \hat q = [\boldsymbol 0, 1] + \epsilon [\frac{\boldsymbol v}{2}, 0] + * @f] + * @see translation() const, Matrix4::translation(const Vector3&), + * DualComplex::translation(), Vector3::xAxis(), Vector3::yAxis(), + * Vector3::zAxis() + */ + inline static DualQuaternion translation(const Vector3& vector) { + return {{}, {vector/T(2), T(0)}}; + } + + /** + * @brief Create dual quaternion from transformation matrix + * + * Expects that the matrix represents rigid transformation. + * @see toMatrix(), Quaternion::fromMatrix(), + * Matrix4::isRigidTransformation() + */ + inline static DualQuaternion fromMatrix(const Matrix4& matrix) { + CORRADE_ASSERT(matrix.isRigidTransformation(), + "Math::DualQuaternion::fromMatrix(): the matrix doesn't represent rigid transformation", {}); + + Quaternion q = Implementation::quaternionFromMatrix(matrix.rotationScaling()); + return {q, Quaternion(matrix.translation()/2)*q}; + } + + /** + * @brief Default constructor + * + * Creates unit dual quaternion. @f[ + * \hat q = [\boldsymbol 0, 1] + \epsilon [\boldsymbol 0, 0] + * @f] + * @todoc Remove workaround when Doxygen is predictable + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + inline constexpr /*implicit*/ DualQuaternion(); + #else + inline constexpr /*implicit*/ DualQuaternion(): Dual>({}, {{}, T(0)}) {} + #endif + + /** + * @brief Construct dual quaternion from real and dual part + * + * @f[ + * \hat q = q_0 + \epsilon q_\epsilon + * @f] + */ + inline constexpr /*implicit*/ DualQuaternion(const Quaternion& real, const Quaternion& dual = Quaternion({}, T(0))): Dual>(real, dual) {} + + /** + * @brief Construct dual quaternion from vector + * + * To be used in transformations later. @f[ + * \hat q = [\boldsymbol 0, 1] + \epsilon [\boldsymbol v, 0] + * @f] + * @see transformPointNormalized() + * @todoc Remove workaround when Doxygen is predictable + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit DualQuaternion(const Vector3& vector); + #else + inline constexpr explicit DualQuaternion(const Vector3& vector): Dual>({}, {vector, T(0)}) {} + #endif + + /** + * @brief Whether the dual quaternion is normalized + * + * Dual quaternion is normalized if it has unit length: @f[ + * |\hat q|^2 = |\hat q| = 1 + \epsilon 0 + * @f] + * @see lengthSquared(), normalized() + */ + inline bool isNormalized() const { + /* Comparing dual part classically, as comparing sqrt() of it would + lead to overly strict precision */ + Dual a = lengthSquared(); + return Implementation::isNormalizedSquared(a.real()) && + TypeTraits::equals(a.dual(), T(0)); + } + + /** + * @brief Rotation part of unit dual quaternion + * + * @see Quaternion::angle(), Quaternion::axis() + */ + inline constexpr Quaternion rotation() const { + return this->real(); + } + + /** + * @brief Translation part of unit dual quaternion + * + * @f[ + * \boldsymbol a = 2 (q_\epsilon q_0^*)_V + * @f] + * @see translation(const Vector3&) + */ + inline Vector3 translation() const { + return (this->dual()*this->real().conjugated()).vector()*T(2); + } + + /** + * @brief Convert dual quaternion to transformation matrix + * + * @see fromMatrix(), Quaternion::toMatrix() + */ + Matrix4 toMatrix() const { + return Matrix4::from(this->real().toMatrix(), translation()); + } + + /** + * @brief Quaternion-conjugated dual quaternion + * + * @f[ + * \hat q^* = q_0^* + q_\epsilon^* + * @f] + * @see dualConjugated(), conjugated(), Quaternion::conjugated() + */ + inline DualQuaternion quaternionConjugated() const { + return {this->real().conjugated(), this->dual().conjugated()}; + } + + /** + * @brief Dual-conjugated dual quaternion + * + * @f[ + * \overline{\hat q} = q_0 - \epsilon q_\epsilon + * @f] + * @see quaternionConjugated(), conjugated(), Dual::conjugated() + */ + inline DualQuaternion dualConjugated() const { + return Dual>::conjugated(); + } + + /** + * @brief Conjugated dual quaternion + * + * Both quaternion and dual conjugation. @f[ + * \overline{\hat q^*} = q_0^* - \epsilon q_\epsilon^* = q_0^* + \epsilon [\boldsymbol q_{V \epsilon}, -q_{S \epsilon}] + * @f] + * @see quaternionConjugated(), dualConjugated(), Quaternion::conjugated(), + * Dual::conjugated() + */ + inline DualQuaternion conjugated() const { + return {this->real().conjugated(), {this->dual().vector(), -this->dual().scalar()}}; + } + + /** + * @brief %Dual quaternion length squared + * + * Should be used instead of length() for comparing dual quaternion + * length with other values, because it doesn't compute the square root. @f[ + * |\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 { + return {this->real().dot(), T(2)*Quaternion::dot(this->real(), this->dual())}; + } + + /** + * @brief %Dual quaternion length + * + * See lengthSquared() which is faster for comparing length with other + * values. @f[ + * |\hat q| = \sqrt{\hat q^* \hat q} = |q_0| + \epsilon \frac{q_0 \cdot q_\epsilon}{|q_0|} + * @f] + */ + inline Dual length() const { + return Math::sqrt(lengthSquared()); + } + + /** + * @brief Normalized dual quaternion (of unit length) + * + * @see isNormalized() + */ + inline DualQuaternion normalized() const { + return (*this)/length(); + } + + /** + * @brief Inverted dual quaternion + * + * See invertedNormalized() which is faster for normalized dual + * quaternions. @f[ + * \hat q^{-1} = \frac{\hat q^*}{|\hat q|^2} + * @f] + */ + inline DualQuaternion inverted() const { + return quaternionConjugated()/lengthSquared(); + } + + /** + * @brief Inverted normalized dual quaternion + * + * Equivalent to quaternionConjugated(). Expects that the quaternion is + * normalized. @f[ + * \hat q^{-1} = \frac{\hat q^*}{|\hat q|^2} = \hat q^* + * @f] + * @see isNormalized(), inverted() + */ + inline DualQuaternion invertedNormalized() const { + CORRADE_ASSERT(isNormalized(), + "Math::DualQuaternion::invertedNormalized(): dual quaternion must be normalized", {}); + return quaternionConjugated(); + } + + /** + * @brief Rotate and translate point with dual quaternion + * + * See transformPointNormalized(), which is faster for normalized dual + * quaternions. @f[ + * v' = \hat q v \overline{\hat q^{-1}} = \hat q ([\boldsymbol 0, 1] + \epsilon [\boldsymbol v, 0]) \overline{\hat q^{-1}} + * @f] + * @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(), + * Quaternion::transformVector(), DualComplex::transformPoint() + */ + inline Vector3 transformPoint(const Vector3& vector) const { + return ((*this)*DualQuaternion(vector)*inverted().dualConjugated()).dual().vector(); + } + + /** + * @brief Rotate and translate point with normalized dual quaternion + * + * Faster alternative to transformPoint(), expects that the dual + * quaternion is normalized. @f[ + * v' = \hat q v \overline{\hat q^{-1}} = \hat q v \overline{\hat q^*} = \hat q ([\boldsymbol 0, 1] + \epsilon [\boldsymbol v, 0]) \overline{\hat q^*} + * @f] + * @see isNormalized(), DualQuaternion(const Vector3&), dual(), + * Matrix4::transformPoint(), Quaternion::transformVectorNormalized(), + * DualComplex::transformPointNormalized() + */ + inline Vector3 transformPointNormalized(const Vector3& vector) const { + CORRADE_ASSERT(isNormalized(), + "Math::DualQuaternion::transformPointNormalized(): dual quaternion must be normalized", + Vector3(std::numeric_limits::quiet_NaN())); + return ((*this)*DualQuaternion(vector)*conjugated()).dual().vector(); + } + + MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(DualQuaternion, Quaternion) + + private: + /* Used by Dual operators and dualConjugated() */ + inline constexpr DualQuaternion(const Dual>& other): Dual>(other) {} +}; + +/** @debugoperator{Magnum::Math::DualQuaternion} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const DualQuaternion& value) { + debug << "DualQuaternion({{"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.real().vector().x() << ", " << value.real().vector().y() << ", " << value.real().vector().z() + << "}, " << value.real().scalar() << "}, {{" + << value.dual().vector().x() << ", " << value.dual().vector().y() << ", " << value.dual().vector().z() + << "}, " << value.dual().scalar() << "})"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/* Explicit instantiation for commonly used types */ +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const DualQuaternion&); +#ifndef MAGNUM_TARGET_GLES +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const DualQuaternion&); +#endif +#endif + +}} + +#endif diff --git a/src/Math/Functions.cpp b/src/Math/Functions.cpp new file mode 100644 index 000000000..d562bd8f4 --- /dev/null +++ b/src/Math/Functions.cpp @@ -0,0 +1,43 @@ +/* + 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 "Functions.h" + +namespace Magnum { namespace Math { + +UnsignedInt log2(UnsignedInt number) { + UnsignedInt log = 0; + while(number >>= 1) + ++log; + return log; +} + +UnsignedInt log(UnsignedInt base, UnsignedInt number) { + UnsignedInt log = 0; + while(number /= base) + ++log; + return log; +} + +}} diff --git a/src/Math/Functions.h b/src/Math/Functions.h new file mode 100644 index 000000000..d324983a5 --- /dev/null +++ b/src/Math/Functions.h @@ -0,0 +1,313 @@ +#ifndef Magnum_Math_Functions_h +#define Magnum_Math_Functions_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 + +#include "Math/Vector.h" + +#include "magnumVisibility.h" + +/** @file + * @brief Functions usable with scalar and vector types + */ + +namespace Magnum { namespace Math { + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct Pow { + Pow() = delete; + + template inline 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; } + }; +} +#endif + +/** + * @brief Integral power + * + * Returns integral power of base to the exponent. + */ +template inline constexpr T pow(T base) { + return Implementation::Pow::pow(base); +} + +/** + * @brief Base-2 integral logarithm + * + * Returns integral logarithm of given number with base `2`. + * @see log() + */ +UnsignedInt MAGNUM_EXPORT log2(UnsignedInt number); + +/** + * @brief Integral logarithm + * + * Returns integral logarithm of given number with given base. + * @see log2() + */ +UnsignedInt MAGNUM_EXPORT log(UnsignedInt base, UnsignedInt number); + +/** @brief Sine */ +template inline T sin(Rad angle) { return std::sin(T(angle)); } + +/** @brief Cosine */ +template inline T cos(Rad angle) { return std::cos(T(angle)); } + +/** @brief Tangent */ +template inline T tan(Rad angle) { return std::tan(T(angle)); } + +/** @todo Can't trigonometric functions be done with only one overload? */ +#ifndef DOXYGEN_GENERATING_OUTPUT +template inline T sin(Deg angle) { return sin(Rad(angle)); } +template inline T cos(Deg angle) { return cos(Rad(angle)); } +template inline T tan(Deg angle) { return tan(Rad(angle)); } +#endif + +/** @brief Arc sine */ +template inline Rad asin(T value) { return Rad(std::asin(value)); } + +/** @brief Arc cosine */ +template inline Rad acos(T value) { return Rad(std::acos(value)); } + +/** @brief Arc tangent */ +template inline Rad atan(T value) { return Rad(std::atan(value)); } + +/** +@{ @name Scalar/vector functions + +These functions are overloaded for both scalar and vector types. Scalar +versions function exactly as their possible STL equivalents, vector overloads +perform the operations component-wise. +*/ + +/** +@brief Minimum + +@see min(), clamp() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T min(T a, T b); +#else +template inline typename std::enable_if::value, T>::type min(T a, T b) { + return std::min(a, b); +} +template inline Vector min(const Vector& a, const Vector& b) { + Vector out; + for(std::size_t i = 0; i != size; ++i) + out[i] = std::min(a[i], b[i]); + return out; +} +#endif + +/** +@brief Maximum + +@see max(), clamp() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T max(const T& a, const T& b); +#else +template inline typename std::enable_if::value, T>::type max(T a, T b) { + return std::max(a, b); +} +template Vector max(const Vector& a, const Vector& b) { + Vector out; + for(std::size_t i = 0; i != size; ++i) + out[i] = std::max(a[i], b[i]); + return out; +} +#endif + +/** @brief Absolute value */ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T abs(const T& a); +#else +template inline typename std::enable_if::value, T>::type abs(T a) { + return std::abs(a); +} +template Vector abs(const Vector& a) { + Vector out; + for(std::size_t i = 0; i != size; ++i) + out[i] = std::abs(a[i]); + return out; +} +#endif + +/** @brief Square root */ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T sqrt(const T& a); +#else +template inline typename std::enable_if::value, T>::type sqrt(T a) { + return std::sqrt(a); +} +template Vector sqrt(const Vector& a) { + Vector out; + for(std::size_t i = 0; i != size; ++i) + out[i] = std::sqrt(a[i]); + return out; +} +#endif + +/** +@brief Clamp value + +Values smaller than @p min are set to @p min, values larger than @p max are +set to @p max. +@see min(), max() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T clamp(const T& value, U min, U max); +#else +template inline typename std::enable_if::value, T>::type clamp(T value, T min, T max) { + return std::min(std::max(value, min), max); +} +template Vector clamp(const Vector& value, T min, T max) { + Vector out; + for(std::size_t i = 0; i != size; ++i) + out[i] = std::min(std::max(value[i], min), max); + return out; +} +#endif + +/** +@brief Linear interpolation of two values +@param a First value +@param b Second value +@param t Interpolation phase (from range @f$ [0; 1] @f$) + +The interpolation for vectors is done as in following, similarly for scalars: @f[ + \boldsymbol v_{LERP} = (1 - t) \boldsymbol v_A + t \boldsymbol v_B +@f] +@see Quaternion::lerp() +@todo http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ + (when SIMD is in place) +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline T lerp(const T& a, const T& b, U t); +#else +template inline T lerp(T a, T b, U t) { + return (U(1) - t)*a + t*b; +} +template inline Vector lerp(const Vector& a, const Vector& b, U t) { + return (U(1) - t)*a + t*b; +} +#endif + +/** +@brief Normalize integral value + +Converts integral value from full range of given *unsigned* integral type to +value in range @f$ [0, 1] @f$ or from *signed* integral to range @f$ [-1, 1] @f$. + +@note For best precision, resulting `FloatingPoint` type should be always + larger that `Integral` type (e.g. Double from Int, LongDouble from Long and + similarly for vector types). + +@attention To ensure the integral type is correctly detected when using + literals, this function should be called with both template parameters + explicit, e.g.: +@code +// Literal type is (signed) char, but we assumed unsigned char, a != 1.0f +Float a = normalize('\xFF'); + +// b = 1.0f +Float b = normalize('\xFF'); +@endcode + +@see denormalize() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline FloatingPoint normalize(const Integral& value); +#else +template inline typename std::enable_if::value && std::is_unsigned::value, FloatingPoint>::type normalize(Integral value) { + static_assert(std::is_floating_point::value && std::is_integral::value, + "Math::normalize(): normalization must be done from integral to floating-point type"); + return value/FloatingPoint(std::numeric_limits::max()); +} +template inline typename std::enable_if::value && std::is_signed::value, FloatingPoint>::type normalize(Integral value) { + static_assert(std::is_floating_point::value && std::is_integral::value, + "Math::normalize(): normalization must be done from integral to floating-point type"); + return Math::max(value/FloatingPoint(std::numeric_limits::max()), FloatingPoint(-1)); +} +template inline typename std::enable_if::value, FloatingPoint>::type normalize(const Integral& value) { + static_assert(std::is_floating_point::value && std::is_integral::value, + "Math::normalize(): normalization must be done from integral to floating-point type"); + return FloatingPoint(value)/typename FloatingPoint::Type(std::numeric_limits::max()); +} +template inline typename std::enable_if::value, FloatingPoint>::type normalize(const Integral& value) { + static_assert(std::is_floating_point::value && std::is_integral::value, + "Math::normalize(): normalization must be done from integral to floating-point type"); + return Math::max(FloatingPoint(value)/typename FloatingPoint::Type(std::numeric_limits::max()), FloatingPoint(-1)); +} +#endif + +/** +@brief Denormalize floating-point value + +Converts floating-point value in range @f$ [0, 1] @f$ to full range of given +*unsigned* integral type or range @f$ [-1, 1] @f$ to full range of given *signed* +integral type. + +@note For best precision, `FloatingPoint` type should be always larger that + resulting `Integral` type (e.g. Double to Int, LongDouble to Long and + similarly for vector types). + +@attention Return value for floating point numbers outside the normalized + range is undefined. + +@see normalize() +@todo Fix test for UnsignedLong +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline Integral denormalize(const FloatingPoint& value); +#else +template inline typename std::enable_if::value, Integral>::type denormalize(FloatingPoint value) { + static_assert(std::is_floating_point::value && std::is_integral::value, + "Math::denormalize(): denormalization must be done from floating-point to integral type"); + return value*std::numeric_limits::max(); +} +template inline typename std::enable_if::value, Integral>::type denormalize(const FloatingPoint& value) { + static_assert(std::is_floating_point::value && std::is_integral::value, + "Math::denormalize(): denormalization must be done from floating-point to integral type"); + return Integral(value*std::numeric_limits::max()); +} +#endif + +/*@}*/ + +}} + +#endif diff --git a/src/Math/Geometry/CMakeLists.txt b/src/Math/Geometry/CMakeLists.txt index 35e4ba1e0..bd64aff42 100644 --- a/src/Math/Geometry/CMakeLists.txt +++ b/src/Math/Geometry/CMakeLists.txt @@ -1,11 +1,34 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +# +# 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. +# set(MagnumMathGeometry_HEADERS Distance.h - Intersection.h) + Intersection.h + Rectangle.h) + install(FILES ${MagnumMathGeometry_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math/Geometry) if(BUILD_TESTS) - enable_testing() add_subdirectory(Test) endif() diff --git a/src/Math/Geometry/Distance.h b/src/Math/Geometry/Distance.h index 9073520a8..f4868a601 100644 --- a/src/Math/Geometry/Distance.h +++ b/src/Math/Geometry/Distance.h @@ -1,25 +1,34 @@ #ifndef Magnum_Math_Geometry_Distance_h #define Magnum_Math_Geometry_Distance_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::Geometry::Distance */ -#include "Math/Math.h" +#include "Math/Functions.h" #include "Math/Matrix.h" #include "Math/Vector3.h" @@ -28,6 +37,8 @@ namespace Magnum { namespace Math { namespace Geometry { /** @brief Functions for computing distances */ class Distance { public: + Distance() = delete; + /** * @brief %Distance of line and point in 2D * @param a First point of the line @@ -42,7 +53,7 @@ class Distance { * @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>::from(b - a, a - point).determinant())/(b - a).length(); + return std::abs(Matrix<2, T>(b - a, a - point).determinant())/(b - a).length(); } /** @@ -57,7 +68,7 @@ class Distance { */ 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>::from(bMinusA, a - point).determinant())/bMinusA.dot(); + return Math::pow<2>(Matrix<2, T>(bMinusA, a - point).determinant())/bMinusA.dot(); } /** @@ -132,7 +143,7 @@ class Distance { return std::sqrt(pointDistanceB); /* Between A and B */ - return std::abs(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA); + return std::abs(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA); } /** @@ -158,7 +169,7 @@ class Distance { return pointDistanceB; /* Between A and B */ - return Math::pow<2>(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/bDistanceA; + return Math::pow<2>(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/bDistanceA; } /** diff --git a/src/Math/Geometry/Intersection.h b/src/Math/Geometry/Intersection.h index 6eeba75bc..9d3bff5c7 100644 --- a/src/Math/Geometry/Intersection.h +++ b/src/Math/Geometry/Intersection.h @@ -1,18 +1,27 @@ #ifndef Magnum_Math_Geometry_Intersection_h #define Magnum_Math_Geometry_Intersection_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,6 +35,8 @@ namespace Magnum { namespace Math { namespace Geometry { /** @brief Functions for computing intersections */ class Intersection { public: + Intersection() = delete; + /** * @brief %Intersection of a plane and line * @param planePosition Plane position diff --git a/src/Math/Geometry/Rectangle.h b/src/Math/Geometry/Rectangle.h new file mode 100644 index 000000000..c832ecf36 --- /dev/null +++ b/src/Math/Geometry/Rectangle.h @@ -0,0 +1,151 @@ +#ifndef Magnum_Math_Geometry_Rectangle_h +#define Magnum_Math_Geometry_Rectangle_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::Math::Geometry::Rectangle + */ + +#include "Math/Vector2.h" + +namespace Magnum { namespace Math { namespace Geometry { + +/** +@brief %Rectangle + +Helper class for storing axis-aligned rectangles consisting of bottom left and +top right corner positions with origin in bottom left. Bottom/left positions +are inclusive, while top/right positions are exclusive. +@see Magnum::Rectangle, Magnum::Rectanglei, Magnum::Rectangled +*/ +template class Rectangle { + template friend class Rectangle; + + public: + /** + * Create rectangle from position and size + * @param bottomLeft Bottom left rectangle corner + * @param size %Rectangle size + */ + inline static Rectangle fromSize(const Vector2& bottomLeft, const Vector2& size) { + return {bottomLeft, bottomLeft+size}; + } + + /** + * @brief Construct zero rectangle + * + * Construct zero-area rectangle positioned at origin. + */ + inline constexpr Rectangle() = default; + + /** @brief Construct rectangle from two corners */ + inline constexpr Rectangle(const Vector2& bottomLeft, const Vector2& topRight): _bottomLeft(bottomLeft), _topRight(topRight) {} + + /** + * @brief Construct rectangle from another of different type + * + * Performs only default casting on the values, no rounding or + * anything else. Example usage: + * @code + * Rectangle floatingPoint({1.3f, 2.7f}, {-15.0f, 7.0f}); + * Rectangle integral(floatingPoint); // {{1, 2}, {-15, 7}} + * @endcode + */ + template inline constexpr explicit Rectangle(const Rectangle& other): _bottomLeft(other._bottomLeft), _topRight(other._topRight) {} + + /** @brief Copy constructor */ + inline constexpr Rectangle(const Rectangle&) = default; + + /** @brief Assignment operator */ + inline Rectangle& operator=(const Rectangle&) = default; + + /** @brief Equality operator */ + inline 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 { + return !operator==(other); + } + + /** @brief Bottom left corner */ + inline Vector2& bottomLeft() { return _bottomLeft; } + inline constexpr Vector2 bottomLeft() const { return _bottomLeft; } /**< @overload */ + + /** @brief Bottom right corner */ + inline 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 */ + + /** @brief Top right corner */ + inline Vector2& topRight() { return _topRight; } + inline 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 */ + + /** @brief Top edge */ + inline T& top() { return _topRight.y(); } + inline 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 */ + + /** @brief Right edge */ + inline T& right() { return _topRight.x(); } + inline constexpr T right() const { return _topRight.x(); } /**< @overload */ + + /** @brief %Rectangle size */ + inline constexpr Vector2 size() const { + return _topRight-_bottomLeft; + } + + /** @brief %Rectangle width */ + inline constexpr T width() const { return _topRight.x() - _bottomLeft.x(); } + + /** @brief %Rectangle height */ + inline constexpr T height() const { return _topRight.y() - _bottomLeft.y(); } + + private: + Vector2 _bottomLeft; + Vector2 _topRight; +}; + +/** @debugoperator{Magnum::Math::Geometry::Rectangle} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Rectangle& value) { + debug << "Rectangle({"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.left() << ", " << value.bottom() << "}, {" << value.right() << ", " << value.top() << "})"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +}}} + +#endif diff --git a/src/Math/Geometry/Test/CMakeLists.txt b/src/Math/Geometry/Test/CMakeLists.txt index eb7810334..e60e23aa3 100644 --- a/src/Math/Geometry/Test/CMakeLists.txt +++ b/src/Math/Geometry/Test/CMakeLists.txt @@ -1,2 +1,27 @@ -corrade_add_test2(MathGeometryDistanceTest DistanceTest.cpp) -corrade_add_test2(MathGeometryIntersectionTest IntersectionTest.cpp) +# +# 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. +# + +corrade_add_test(MathGeometryDistanceTest DistanceTest.cpp) +corrade_add_test(MathGeometryIntersectionTest IntersectionTest.cpp) +corrade_add_test(MathGeometryRectangleTest RectangleTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/Math/Geometry/Test/DistanceTest.cpp b/src/Math/Geometry/Test/DistanceTest.cpp index ace9c485a..3170265e7 100644 --- a/src/Math/Geometry/Test/DistanceTest.cpp +++ b/src/Math/Geometry/Test/DistanceTest.cpp @@ -1,39 +1,54 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "DistanceTest.h" - #include +#include -#include "Constants.h" -#include "Distance.h" +#include "Math/Constants.h" +#include "Math/Geometry/Distance.h" -CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::DistanceTest) +namespace Magnum { namespace Math { namespace Geometry { namespace Test { -using namespace std; +class DistanceTest: public Corrade::TestSuite::Tester { + public: + DistanceTest(); -namespace Magnum { namespace Math { namespace Geometry { namespace Test { + void linePoint2D(); + void linePoint3D(); + void lineSegmentPoint2D(); + void lineSegmentPoint3D(); +}; -typedef Magnum::Math::Vector2 Vector2; -typedef Magnum::Math::Vector3 Vector3; +typedef Math::Vector2 Vector2; +typedef Math::Vector3 Vector3; +typedef Math::Constants Constants; DistanceTest::DistanceTest() { - addTests(&DistanceTest::linePoint2D, - &DistanceTest::linePoint3D, - &DistanceTest::lineSegmentPoint2D, - &DistanceTest::lineSegmentPoint3D); + addTests({&DistanceTest::linePoint2D, + &DistanceTest::linePoint3D, + &DistanceTest::lineSegmentPoint2D, + &DistanceTest::lineSegmentPoint3D}); } void DistanceTest::linePoint2D() { @@ -44,14 +59,11 @@ void DistanceTest::linePoint2D() { 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() { @@ -62,10 +74,8 @@ void DistanceTest::linePoint3D() { 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()); } void DistanceTest::lineSegmentPoint2D() { @@ -76,19 +86,17 @@ void DistanceTest::lineSegmentPoint2D() { 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); /* 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, Vector2(1.0f, 0.0f))), 1.0f/Constants::sqrt2()); + CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(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); @@ -107,20 +115,21 @@ void DistanceTest::lineSegmentPoint3D() { 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, Vector3(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); /* 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()); } }}}} + +CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::DistanceTest) diff --git a/src/Math/Geometry/Test/DistanceTest.h b/src/Math/Geometry/Test/DistanceTest.h deleted file mode 100644 index dc7c7bc88..000000000 --- a/src/Math/Geometry/Test/DistanceTest.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef Magnum_Math_Geometry_Test_DistanceTest_h -#define Magnum_Math_Geometry_Test_DistanceTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Geometry { namespace Test { - -class DistanceTest: public Corrade::TestSuite::Tester { - public: - DistanceTest(); - - void linePoint2D(); - void linePoint3D(); - void lineSegmentPoint2D(); - void lineSegmentPoint3D(); -}; - -}}}} - -#endif diff --git a/src/Math/Geometry/Test/IntersectionTest.cpp b/src/Math/Geometry/Test/IntersectionTest.cpp index 5112b5e84..c70f48747 100644 --- a/src/Math/Geometry/Test/IntersectionTest.cpp +++ b/src/Math/Geometry/Test/IntersectionTest.cpp @@ -1,34 +1,45 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "IntersectionTest.h" - +#include #include -#include "Intersection.h" +#include "Math/Geometry/Intersection.h" -CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::IntersectionTest) +namespace Magnum { namespace Math { namespace Geometry { namespace Test { -using namespace std; +class IntersectionTest: public Corrade::TestSuite::Tester { + public: + IntersectionTest(); -namespace Magnum { namespace Math { namespace Geometry { namespace Test { + void planeLine(); +}; -typedef Magnum::Math::Vector3 Vector3; +typedef Math::Vector3 Vector3; IntersectionTest::IntersectionTest() { - addTests(&IntersectionTest::planeLine); + addTests({&IntersectionTest::planeLine}); } void IntersectionTest::planeLine() { @@ -45,11 +56,13 @@ void IntersectionTest::planeLine() { /* Line lies on the plane */ CORRADE_COMPARE(Intersection::planeLine(planePosition, planeNormal, - Vector3(1.0f, 0.5f, 0.5f), Vector3(0.0f, 1.0f, 0.5f)), numeric_limits::quiet_NaN()); + Vector3(1.0f, 0.5f, 0.5f), Vector3(0.0f, 1.0f, 0.5f)), std::numeric_limits::quiet_NaN()); /* Line is parallell to the plane */ CORRADE_COMPARE((Intersection::planeLine(planePosition, planeNormal, - Vector3(1.0f, 0.0f, 1.0f), Vector3(0.0f, 0.0f, 1.0f))), -numeric_limits::infinity()); + Vector3(1.0f, 0.0f, 1.0f), Vector3(0.0f, 0.0f, 1.0f))), -std::numeric_limits::infinity()); } }}}} + +CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::IntersectionTest) diff --git a/src/Math/Geometry/Test/IntersectionTest.h b/src/Math/Geometry/Test/IntersectionTest.h deleted file mode 100644 index 7187a28c2..000000000 --- a/src/Math/Geometry/Test/IntersectionTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Math_Geometry_Test_IntersectionTest_h -#define Magnum_Math_Geometry_Test_IntersectionTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Geometry { namespace Test { - -class IntersectionTest: public Corrade::TestSuite::Tester { - public: - IntersectionTest(); - - void planeLine(); -}; - -}}}} - -#endif diff --git a/src/Math/Geometry/Test/RectangleTest.cpp b/src/Math/Geometry/Test/RectangleTest.cpp new file mode 100644 index 000000000..0120168ea --- /dev/null +++ b/src/Math/Geometry/Test/RectangleTest.cpp @@ -0,0 +1,107 @@ +/* + 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/Geometry/Rectangle.h" + +namespace Magnum { namespace Math { namespace Geometry { namespace Test { + +class RectangleTest: public Corrade::TestSuite::Tester { + public: + RectangleTest(); + + void access(); + void compare(); + void construct(); + void size(); + + void debug(); +}; + +typedef Geometry::Rectangle Rectangle; +typedef Geometry::Rectangle Rectanglei; +typedef Vector2 Vector2i; + +RectangleTest::RectangleTest() { + addTests({&RectangleTest::access, + &RectangleTest::compare, + &RectangleTest::construct, + &RectangleTest::size, + + &RectangleTest::debug}); +} + +void RectangleTest::access() { + Rectanglei rect({34, 23}, {47, 30}); + const Rectanglei crect({34, 23}, {47, 30}); + + CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23)); + CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30)); + CORRADE_COMPARE(rect.bottom(), 23); + CORRADE_COMPARE(rect.top(), 30); + CORRADE_COMPARE(rect.left(), 34); + CORRADE_COMPARE(rect.right(), 47); + CORRADE_COMPARE(crect.bottomLeft(), Vector2i(34, 23)); + CORRADE_COMPARE(crect.topRight(), Vector2i(47, 30)); + CORRADE_COMPARE(crect.bottom(), 23); + CORRADE_COMPARE(crect.top(), 30); + CORRADE_COMPARE(crect.left(), 34); + CORRADE_COMPARE(crect.right(), 47); + + CORRADE_COMPARE(rect.topLeft(), Vector2i(34, 30)); + CORRADE_COMPARE(rect.bottomRight(), Vector2i(47, 23)); +} + +void RectangleTest::compare() { + CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) == Rectanglei({34, 23}, {47, 30})); + CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) != Rectanglei({34, 23}, {48, 30})); + CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) != Rectanglei({35, 23}, {47, 30})); +} + +void RectangleTest::construct() { + CORRADE_COMPARE(Rectanglei(), Rectanglei({0, 0}, {0, 0})); + CORRADE_COMPARE(Rectanglei::fromSize({3, 5}, {23, 78}), Rectanglei({3, 5}, {26, 83})); + CORRADE_COMPARE(Rectanglei(Rectangle({1.3f, 2.7f}, {-15.0f, 7.0f})), Rectanglei({1, 2}, {-15, 7})); +} + +void RectangleTest::size() { + Rectanglei rect({34, 23}, {47, 30}); + + CORRADE_COMPARE(rect.size(), Vector2i(13, 7)); + CORRADE_COMPARE(rect.width(), 13); + CORRADE_COMPARE(rect.height(), 7); +} + +void RectangleTest::debug() { + std::ostringstream o; + Debug(&o) << Rectanglei({34, 23}, {47, 30}); + + CORRADE_COMPARE(o.str(), "Rectangle({34, 23}, {47, 30})\n"); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::RectangleTest) diff --git a/src/Math/Math.cpp b/src/Math/Math.cpp deleted file mode 100644 index ec39d403d..000000000 --- a/src/Math/Math.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "Math.h" - -using namespace std; - -namespace Magnum { namespace Math { - -std::uint32_t log(std::uint32_t base, std::uint32_t number) { - uint32_t log = 0; - while(number /= base) - ++log; - return log; -} - -}} diff --git a/src/Math/Math.h b/src/Math/Math.h index d3fd2c387..081d7acdf 100644 --- a/src/Math/Math.h +++ b/src/Math/Math.h @@ -1,119 +1,67 @@ #ifndef Magnum_Math_Math_h #define Magnum_Math_Math_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 -#include -#include - -#include "corradeCompatibility.h" -#include "magnumVisibility.h" - /** @file - * @brief Math utilities + * @brief Forward declarations for Magnum::Math namespace */ -namespace Magnum { namespace Math { +#include -/** -@todo Quaternions: - - interpolation between rotations (=> animation, continuous collision detection) - - better rotation representation (4 floats instead of 9/16 floats when using - matrices) -*/ +namespace Magnum { namespace Math { +/** @todoc Remove `ifndef` when Doxygen is sane again */ #ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - template struct Pow { - template inline constexpr T operator()(T base) const { - return base*Pow()(base); - } - }; - template<> struct Pow<0> { - template inline constexpr T operator()(T) const { return 1; } - }; -} -#endif - -/** - * @brief Integral power - * - * Returns integral power of base to the exponent. - */ -template inline constexpr T pow(T base) { - return Implementation::Pow()(base); -} - -/** - * @brief Integral logarithm - * - * Returns integral logarithm of given number with given base. - */ -std::uint32_t MAGNUM_EXPORT log(std::uint32_t base, std::uint32_t number); +/* Class Constants used only statically */ -/** -@brief Normalize floating-point value +template class Complex; +template class Dual; +template class DualComplex; +template class DualQuaternion; -Converts integral value from full range of given (signed/unsigned) integral -type to value in range @f$ [0, 1] @f$. +template class Matrix; +template class Matrix3; +template class Matrix4; -@attention To ensure the integral type is correctly detected when using -literals, this function should be called with both template parameters -explicit, e.g.: -@code -// Even if this is character literal, integral type is 32bit, thus a != 1.0f -float a = normalize('\127'); +template class Quaternion; -// b = 1.0f -float b = normalize('\127'); -@endcode - -@todo Signed normalization to [-1.0, 1.0] like in OpenGL? -*/ -template inline constexpr typename std::enable_if::value && std::is_integral::value, FloatingPoint>::type normalize(Integral value) { - return (FloatingPoint(value)-FloatingPoint(std::numeric_limits::min()))/ - (FloatingPoint(std::numeric_limits::max()) - FloatingPoint(std::numeric_limits::min())); -} +template class RectangularMatrix; -/** -@brief Denormalize floating-point value +template class, class> class Unit; +template class Deg; +template class Rad; -Converts floating-point value in range @f$ [0, 1] @f$ to full range of given -integral type. +template class Vector; +template class Vector2; +template class Vector3; +template class Vector4; -@note For best precision, `FloatingPoint` type should be always larger that -resulting `Integral` type (e.g. `double` to `std::int32_t`, `long double` to -`std::int64_t`). - -@todo Signed normalization to [-1.0, 1.0] like in OpenGL? -@todo Stable behavior (working/broken) for long double and long long - (currently fails in Debug builds, but passes in Release on GCC 4.7) -*/ -template inline constexpr typename std::enable_if::value && std::is_integral::value, Integral>::type denormalize(FloatingPoint value) { - return std::numeric_limits::min() + - round(FloatingPoint(value*std::numeric_limits::max()) - - FloatingPoint(value*std::numeric_limits::min())); -} - -/** @brief Clamp value */ -template inline T clamp(T value, T min, T max) { - return std::min(std::max(value, min), max); +namespace Geometry { + template class Rectangle; } +#endif }} diff --git a/src/Math/MathTypeTraits.h b/src/Math/MathTypeTraits.h deleted file mode 100644 index 364fc2648..000000000 --- a/src/Math/MathTypeTraits.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef Magnum_Math_MathTypeTraits_h -#define Magnum_Math_MathTypeTraits_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file - * @brief Class Magnum::Math::MathTypeTraits - */ - -#include -#include -#include - -#include "corradeCompatibility.h" - -/** @brief Precision when testing floats for equality */ -#ifndef FLOAT_EQUALITY_PRECISION -#define FLOAT_EQUALITY_PRECISION 1.0e-6 -#endif - -/** @brief Precision when testing doubles for equality */ -#ifndef DOUBLE_EQUALITY_PRECISION -#define DOUBLE_EQUALITY_PRECISION 1.0e-12 -#endif - -namespace Magnum { namespace Math { - -/** -@brief Traits class for numeric types - -Traits classes are usable for detecting type features at compile time without -the need for repeated code such as method overloading or template -specialization for given types. - -This class and class methods are specialized only for types where it makes -sense, it has empty implementation for unknown types or types which don't -support given feature, thus forcing the compilation stop with an error. -*/ -template struct MathTypeTraits { - /* - * The following values are implemented as inline functions, not as - * static const variables, because the compiler will inline the return - * values instead of referencing to static data and unlike static const - * variables the functions can be overloaded, deleted and hidden. - */ - - #ifdef DOXYGEN_GENERATING_OUTPUT - /** - * @brief Corresponding numeric type large at least as 32bit integer - * - * Usable e.g. to prevent conversion of `char` to characters when printing - * numeric types to output. - */ - typedef U NumericType; - - /** - * @brief Corresponding floating-point type for normalization - * - * If the type is not already floating-point, defines smallest larger - * floating-point type. - */ - typedef U FloatingPointType; - - /** - * @brief Epsilon value for fuzzy compare - * - * Returns minimal difference between numbers to be considered - * inequal. Returns 1 for integer types and reasonably small value for - * floating-point types. - */ - inline constexpr static T epsilon(); - - /** - * @brief Fuzzy compare - * - * Uses equality for integer types and fuzzy compare for floating-point - * types (using @ref epsilon value). - */ - static bool equals(T a, T b); - #endif -}; - -/** @bug Infinity comparison! */ - -/** - * @todo Implement better fuzzy comparison algorithm, like at - * http://floating-point-gui.de/errors/comparison/ or - * http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm - */ - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - -template struct MathTypeTraitsIntegral { - inline constexpr static T epsilon() { return 1; } - - inline constexpr static bool equals(T a, T b) { - return a == b; - } -}; - -template struct MathTypeTraitsFloatingPoint { - inline static bool equals(T a, T b) { - return std::abs(a - b) < MathTypeTraits::epsilon(); - } -}; - -template struct MathTypeTraitsLong {}; - -template<> struct MathTypeTraitsLong<4> { - typedef std::uint32_t UnsignedType; - typedef std::int32_t Type; -}; - -template<> struct MathTypeTraitsLong<8> { - typedef std::uint64_t UnsignedType; - typedef std::int64_t Type; -}; - -} - -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::uint32_t NumericType; - typedef float FloatingPointType; -}; -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::int32_t NumericType; - typedef float FloatingPointType; -}; - -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::uint32_t NumericType; - typedef float FloatingPointType; -}; -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::int32_t NumericType; - typedef float FloatingPointType; -}; - -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::uint32_t NumericType; - typedef double FloatingPointType; -}; -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::int32_t NumericType; - typedef double FloatingPointType; -}; - -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::uint64_t NumericType; - typedef long double FloatingPointType; -}; -template<> struct MathTypeTraits: Implementation::MathTypeTraitsIntegral { - typedef std::int64_t NumericType; - typedef long double FloatingPointType; -}; - -template<> struct MathTypeTraits: Implementation::MathTypeTraitsFloatingPoint { - typedef float NumericType; - typedef float FloatingPointType; - - inline constexpr static float epsilon() { return FLOAT_EQUALITY_PRECISION; } -}; -template<> struct MathTypeTraits: Implementation::MathTypeTraitsFloatingPoint { - typedef float NumericType; - typedef double FloatingPointType; - - inline constexpr static double epsilon() { return DOUBLE_EQUALITY_PRECISION; } -}; -#endif - -}} - -#endif diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index a773af055..1db788d34 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -1,18 +1,27 @@ #ifndef Magnum_Math_Matrix_h #define Magnum_Math_Matrix_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -37,6 +46,7 @@ namespace Implementation { See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Matrix} +@see Magnum::Matrix2, Magnum::Matrix2d */ template class Matrix: public RectangularMatrix { public: @@ -61,33 +71,58 @@ template class Matrix: public RectangularMatrix inline constexpr /*implicit*/ Matrix(const Vector& first, const U&... next): RectangularMatrix(first, next...) {} + + /** + * @brief Construct matrix from another of different type * - * Note that the values are in column-major order. - * @todoc Make this copydoc when Doxygen is fixed - * @todoc Remove workaround when Doxygen supports uniform initialization + * Performs only default casting on the values, no rounding or + * anything else. Example usage: + * @code + * Matrix<2, Float> floatingPoint({1.3f, 2.7f}, + * {-15.0f, 7.0f}); + * Matrix<2, Byte> integral(floatingPoint); + * // integral == {{1, 2}, {-15, 7}} + * @endcode */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr Matrix(T first, U... next): RectangularMatrix(first, next...) {} - #else - template inline constexpr Matrix(T first, U... next); - #endif + template inline constexpr explicit Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} /** @brief Copy constructor */ inline constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} - /** @brief Multiply and assign matrix operator */ - inline Matrix& operator*=(const RectangularMatrix& other) { - return (*this = *this*other); + /** + * @brief Whether the matrix is orthogonal + * + * The matrix is orthogonal if its transpose is equal to its inverse: @f[ + * Q^T = Q^{-1} + * @f] + * @see transposed(), inverted(), Matrix3::isRigidTransformation(), + * Matrix4::isRigidTransformation() + */ + bool 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; } /** @@ -98,12 +133,7 @@ template class Matrix: public RectangularMatrixdiagonal().sum(); } /** @brief %Matrix without given column and row */ @@ -112,8 +142,8 @@ template class Matrix: public RectangularMatrix= skipCol), - row + (row >= skipRow)); + out[col][row] = (*this)[col + (col >= skipCol)] + [row + (row >= skipRow)]; return out; } @@ -137,6 +167,8 @@ template class Matrix: public RectangularMatrix inverted() const { Matrix out(Zero); @@ -145,11 +177,26 @@ template class Matrix: public RectangularMatrix invertedOrthogonal() const { + CORRADE_ASSERT(isOrthogonal(), + "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {}); + return this->transposed(); + } + #ifndef DOXYGEN_GENERATING_OUTPUT /* Reimplementation of functions to return correct type */ inline Matrix operator*(const Matrix& other) const { @@ -162,7 +209,6 @@ template class Matrix: public RectangularMatrix::operator*(other); } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix) #endif }; @@ -173,6 +219,9 @@ template inline typename std::enable_if inline typename std::enable_if::value, Matrix>::type operator/(U number, const Matrix& matrix) { return number/RectangularMatrix(matrix); } +template inline Matrix operator*(const Vector& vector, const RectangularMatrix& matrix) { + return RectangularMatrix<1, size, T>(vector)*matrix; +} #endif /** @debugoperator{Magnum::Math::Matrix} */ @@ -182,35 +231,19 @@ template inline Corrade::Utility::Debug operator<<(Co #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ - inline constexpr static Type& from(T* data) { \ - return *reinterpret_cast*>(data); \ - } \ - inline constexpr static const Type& from(const T* data) { \ - return *reinterpret_cast*>(data); \ - } \ - template inline constexpr static Type from(const Vector& first, const U&... next) { \ - return Matrix::from(first, next...); \ - } \ - \ - inline Type& operator=(const Type& other) { \ - Matrix::operator=(other); \ - return *this; \ - } \ - \ inline VectorType& operator[](std::size_t col) { \ - return VectorType::from(Matrix::data()+col*size); \ + return static_cast&>(Matrix::operator[](col)); \ } \ - inline constexpr const VectorType& operator[](std::size_t col) const { \ - return VectorType::from(Matrix::data()+col*size); \ + inline constexpr const VectorType operator[](std::size_t col) const { \ + return VectorType(Matrix::operator[](col)); \ + } \ + inline VectorType row(std::size_t row) const { \ + return VectorType(Matrix::row(row)); \ } \ \ inline Type operator*(const Matrix& other) const { \ return Matrix::operator*(other); \ } \ - inline Type& operator*=(const Matrix& other) { \ - Matrix::operator*=(other); \ - return *this; \ - } \ template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ return Matrix::operator*(other); \ } \ @@ -219,7 +252,10 @@ template inline Corrade::Utility::Debug operator<<(Co } \ \ inline Type transposed() const { return Matrix::transposed(); } \ - inline Type inverted() const { return Matrix::inverted(); } + inline Type inverted() const { return Matrix::inverted(); } \ + inline Type invertedOrthogonal() const { \ + return Matrix::invertedOrthogonal(); \ + } #define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& matrix) { \ @@ -227,6 +263,9 @@ template inline Corrade::Utility::Debug operator<<(Co } \ template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& matrix) { \ return number/Matrix(matrix); \ + } \ + template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ + return RectangularMatrix<1, size, T>(vector)*matrix; \ } namespace Implementation { @@ -237,7 +276,7 @@ template class MatrixDeterminant { T out(0); for(std::size_t col = 0; col != size; ++col) - out += ((col & 1) ? -1 : 1)*m(col, 0)*m.ij(col, 0).determinant(); + out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant(); return out; } @@ -246,14 +285,14 @@ template class MatrixDeterminant { template class MatrixDeterminant<2, T> { public: inline constexpr T operator()(const Matrix<2, T>& m) { - return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1); + 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) { - return m(0, 0); + return m[0][0]; } }; diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 1d96ebbbb..344f55d86 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -1,36 +1,46 @@ #ifndef Magnum_Math_Matrix3_h #define Magnum_Math_Matrix3_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::Matrix3 */ -#include "Matrix.h" -#include "Point2D.h" +#include "Math/Matrix.h" +#include "Math/Vector3.h" namespace Magnum { namespace Math { /** -@brief 3x3 matrix for affine transformations in 2D -@tparam T Data type +@brief 3x3 matrix +@tparam T Underlying data type -Provides functions for transformations in 2D. See Matrix4 for 3D -transformations. See also @ref matrix-vector for brief introduction. -@see Magnum::Matrix3 +Represents 2D transformation. See @ref matrix-vector and @ref transformations +for brief introduction. +@see Magnum::Matrix3, Magnum::Matrix3d, DualComplex, + SceneGraph::MatrixTransformation2D @configurationvalueref{Magnum::Math::Matrix3} */ template class Matrix3: public Matrix<3, T> { @@ -39,15 +49,14 @@ template class Matrix3: public Matrix<3, T> { * @brief 2D translation matrix * @param vector Translation vector * - * @see translation(), Matrix4::translation(const Vector3&), - * Vector2::xAxis(), Vector2::yAxis() + * @see translation(), DualComplex::translation(), + * Matrix4::translation(const Vector3&), Vector2::xAxis(), + * Vector2::yAxis() */ inline constexpr static Matrix3 translation(const Vector2& vector) { - return Matrix3( /* Column-major! */ - T(1), T(0), T(0), - T(0), T(1), T(0), - vector.x(), vector.y(), T(1) - ); + return {{ T(1), T(0), T(0)}, + { T(0), T(1), T(0)}, + {vector.x(), vector.y(), T(1)}}; } /** @@ -58,61 +67,112 @@ template class Matrix3: public Matrix<3, T> { * Vector2::xScale(), Vector2::yScale() */ inline constexpr static Matrix3 scaling(const Vector2& vector) { - return Matrix3( /* Column-major! */ - vector.x(), T(0), T(0), - T(0), vector.y(), T(0), - T(0), T(0), T(1) - ); + return {{vector.x(), T(0), T(0)}, + { T(0), vector.y(), T(0)}, + { T(0), T(0), T(1)}}; } /** * @brief 2D rotation matrix - * @param angle Rotation angle (counterclockwise, in radians) + * @param angle Rotation angle (counterclockwise) + * + * @see rotation() const, Complex::rotation(), DualComplex::rotation(), + * Matrix4::rotation(Rad, const Vector3&) + */ + static Matrix3 rotation(Rad angle) { + T sine = std::sin(T(angle)); + T cosine = std::cos(T(angle)); + + return {{ cosine, sine, T(0)}, + { -sine, cosine, T(0)}, + { T(0), T(0), T(1)}}; + } + + /** + * @brief 2D reflection matrix + * @param normal Normal of the line through which to reflect + * + * Expects that the normal is normalized. + * @see Matrix4::reflection(), Vector::isNormalized() + */ + static Matrix3 reflection(const Vector2& normal) { + CORRADE_ASSERT(normal.isNormalized(), + "Math::Matrix3::reflection(): normal must be normalized", {}); + return from(Matrix<2, T>() - T(2)*normal*RectangularMatrix<1, 2, T>(normal).transposed(), {}); + } + + /** + * @brief 2D projection matrix + * @param size Size of the view * - * @see rotation() const, Matrix4::rotation(T, const Vector3&), deg(), - * rad() + * @see Matrix4::orthographicProjection(), Matrix4::perspectiveProjection() */ - static Matrix3 rotation(T angle) { - T sine = std::sin(angle); - T cosine = std::cos(angle); + static Matrix3 projection(const Vector2& size) { + return scaling(2.0f/size); + } - return Matrix3( /* Column-major! */ - cosine, sine, T(0), - -sine, cosine, T(0), - T(0), T(0), T(1) - ); + /** + * @brief Create matrix from rotation/scaling part and translation part + * @param rotationScaling Rotation/scaling part (upper-left 2x2 + * matrix) + * @param translation Translation part (first two elements of + * third column) + * + * @see rotationScaling() const, translation() const + */ + inline 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) {} - /** @copydoc Matrix::Matrix(IdentityType, T) */ - inline constexpr Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>( - value, T(0), T(0), - T(0), value, T(0), - T(0), T(0), value + /** + * @brief Default constructor + * + * Creates identity matrix. You can also explicitly call this + * constructor with `Matrix3 m(Matrix3::Identity);`. Optional parameter + * @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>( + Vector<3, T>(value, T(0), T(0)), + Vector<3, T>( T(0), value, T(0)), + Vector<3, T>( T(0), T(0), value) ) {} - /** @copydoc Matrix::Matrix */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr Matrix3(T first, U... next): Matrix<3, T>(first, next...) {} - #else - template inline constexpr Matrix3(T first, U... next) {} - #endif + /** @brief %Matrix from column vectors */ + inline 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) {} /** @brief Copy constructor */ inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} + /** + * @brief Check whether the matrix represents rigid transformation + * + * Rigid transformation consists only of rotation and translation (i.e. + * no scaling or projection). + * @see isOrthogonal() + */ + inline bool isRigidTransformation() const { + return rotationScaling().isOrthogonal() && row(2) == Vector3(T(0), T(0), T(1)); + } + /** * @brief 2D rotation and scaling part of the matrix * * Upper-left 2x2 part of the matrix. - * @see rotation() const, rotation(T), Matrix4::rotationScaling() const + * @see from(const Matrix<2, T>&, const Vector2&), rotation() const, + * rotation(T), Matrix4::rotationScaling() const */ - inline Matrix<2, T> rotationScaling() const { - return Matrix<2, T>::from( - (*this)[0].xy(), - (*this)[1].xy()); + inline constexpr Matrix<2, T> rotationScaling() const { + return {(*this)[0].xy(), + (*this)[1].xy()}; } /** @@ -120,18 +180,20 @@ template class Matrix3: public Matrix<3, T> { * * Normalized upper-left 2x2 part of the matrix. * @see rotationScaling() const, rotation(T), Matrix4::rotation() const + * @todo assert uniform scaling (otherwise this would be garbage) */ inline Matrix<2, T> rotation() const { - return Matrix<2, T>::from( - (*this)[0].xy().normalized(), - (*this)[1].xy().normalized()); + return {(*this)[0].xy().normalized(), + (*this)[1].xy().normalized()}; } + /** @todo uniform scaling extraction */ + /** * @brief Right-pointing 2D vector * * First two elements of first column. - * @see Vector2::xAxis() + * @see up(), Vector2::xAxis(), Matrix4::right() */ inline Vector2& right() { return (*this)[0].xy(); } inline constexpr Vector2 right() const { return (*this)[0].xy(); } /**< @overload */ @@ -140,7 +202,7 @@ template class Matrix3: public Matrix<3, T> { * @brief Up-pointing 2D vector * * First two elements of second column. - * @see Vector2::yAxis() + * @see right(), Vector2::yAxis(), Matrix4::up() */ inline Vector2& up() { return (*this)[1].xy(); } inline constexpr Vector2 up() const { return (*this)[1].xy(); } /**< @overload */ @@ -149,21 +211,61 @@ template class Matrix3: public Matrix<3, T> { * @brief 2D translation part of the matrix * * First two elements of third column. - * @see translation(const Vector2&), Matrix4::translation() + * @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 */ - #ifndef DOXYGEN_GENERATING_OUTPUT - inline Point2D operator*(const Point2D& other) const { - return Matrix<3, T>::operator*(other); + /** + * @brief Inverted rigid transformation matrix + * + * Expects that the matrix represents rigid transformation. + * Significantly faster than the general algorithm in inverted(). + * @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()); } - #endif + /** + * @brief Transform 2D vector with the matrix + * + * Unlike in transformPoint(), translation is not involved in the + * transformation. @f[ + * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ 0 \end{pmatrix} + * @f] + * @see Complex::transformVector(), Matrix4::transformVector() + * @todo extract 2x2 matrix and multiply directly? (benchmark that) + */ + inline Vector2 transformVector(const Vector2& vector) const { + return ((*this)*Vector3(vector, T(0))).xy(); + } + + /** + * @brief Transform 2D point with the matrix + * + * Unlike in transformVector(), translation is also involved in the + * transformation. @f[ + * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ 1 \end{pmatrix} + * @f] + * @see DualComplex::transformPoint(), Matrix4::transformPoint() + */ + inline Vector2 transformPoint(const Vector2& vector) const { + return ((*this)*Vector3(vector, T(1))).xy(); + } + + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3) MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3) }; +MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix3, 3) + /** @debugoperator{Magnum::Math::Matrix3} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3& value) { return debug << static_cast&>(value); diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 4a7a7ef4d..7a72d9ec3 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -1,39 +1,52 @@ #ifndef Magnum_Math_Matrix4_h #define Magnum_Math_Matrix4_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::Matrix4 */ -#include "Matrix.h" -#include "Point3D.h" +#include "Math/Matrix.h" +#include "Math/Vector4.h" + +#ifdef _WIN32 /* I so HATE windows.h */ +#undef near +#undef far +#endif namespace Magnum { namespace Math { /** -@brief 4x4 matrix for affine transformations in 3D -@tparam T Data type +@brief 4x4 matrix +@tparam T Underlying data type -Provides functions for transformations in 3D. See Matrix3 for 2D -transformations. See also @ref matrix-vector for brief introduction. -@see Magnum::Matrix4 +Represents 3D transformation. See @ref matrix-vector and @ref transformations +for brief introduction. +@see Magnum::Matrix4, Magnum::Matrix4d, DualQuaternion, + SceneGraph::MatrixTransformation3D @configurationvalueref{Magnum::Math::Matrix4} -@todo Shearing -@todo Reflection */ template class Matrix4: public Matrix<4, T> { public: @@ -41,16 +54,15 @@ template class Matrix4: public Matrix<4, T> { * @brief 3D translation * @param vector Translation vector * - * @see translation(), Matrix3::translation(const Vector2&), - * Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis() + * @see translation(), DualQuaternion::translation(), + * Matrix3::translation(const Vector2&), Vector3::xAxis(), + * Vector3::yAxis(), Vector3::zAxis() */ inline constexpr static Matrix4 translation(const Vector3& vector) { - return Matrix4( /* Column-major! */ - T(1), T(0), T(0), T(0), - T(0), T(1), T(0), T(0), - T(0), T(0), T(1), T(0), - vector.x(), vector.y(), vector.z(), T(1) - ); + 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)}, + {vector.x(), vector.y(), vector.z(), T(1)}}; } /** @@ -61,32 +73,29 @@ template class Matrix4: public Matrix<4, T> { * Vector3::xScale(), Vector3::yScale(), Vector3::zScale() */ inline constexpr static Matrix4 scaling(const Vector3& vector) { - return Matrix4( /* Column-major! */ - vector.x(), T(0), T(0), T(0), - T(0), vector.y(), T(0), T(0), - T(0), T(0), vector.z(), T(0), - T(0), T(0), T(0), T(1) - ); + 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)}, + { T(0), T(0), T(0), T(1)}}; } /** * @brief 3D rotation around arbitrary axis - * @param angle Rotation angle (counterclockwise, in radians) + * @param angle Rotation angle (counterclockwise) * @param normalizedAxis Normalized rotation axis * - * If possible, use faster alternatives like rotationX(), rotationY() - * and rotationZ(). - * @see rotation() const, Matrix3::rotation(T), Vector3::xAxis(), - * Vector3::yAxis(), Vector3::zAxis(), deg(), rad() - * @attention Assertion fails on non-normalized rotation vector and - * identity matrix is returned. + * Expects that the rotation axis is normalized. If possible, use + * faster alternatives like rotationX(), rotationY() and rotationZ(). + * @see rotation() const, Quaternion::rotation(), DualQuaternion::rotation(), + * Matrix3::rotation(Rad), Vector3::xAxis(), Vector3::yAxis(), + * Vector3::zAxis(), Vector::isNormalized() */ - static Matrix4 rotation(T angle, const Vector3& normalizedAxis) { - CORRADE_ASSERT(MathTypeTraits::equals(normalizedAxis.dot(), T(1)), + static Matrix4 rotation(Rad angle, const Vector3& normalizedAxis) { + CORRADE_ASSERT(normalizedAxis.isNormalized(), "Math::Matrix4::rotation(): axis must be normalized", {}); - T sine = std::sin(angle); - T cosine = std::cos(angle); + T sine = std::sin(T(angle)); + T cosine = std::cos(T(angle)); T oneMinusCosine = T(1) - cosine; T xx = normalizedAxis.x()*normalizedAxis.x(); @@ -96,123 +105,212 @@ template class Matrix4: public Matrix<4, T> { T yz = normalizedAxis.y()*normalizedAxis.z(); T zz = normalizedAxis.z()*normalizedAxis.z(); - return Matrix4( /* Column-major! */ - cosine + xx*oneMinusCosine, + return { + {cosine + xx*oneMinusCosine, xy*oneMinusCosine + normalizedAxis.z()*sine, xz*oneMinusCosine - normalizedAxis.y()*sine, - T(0), - xy*oneMinusCosine - normalizedAxis.z()*sine, + T(0)}, + {xy*oneMinusCosine - normalizedAxis.z()*sine, cosine + yy*oneMinusCosine, yz*oneMinusCosine + normalizedAxis.x()*sine, - T(0), - xz*oneMinusCosine + normalizedAxis.y()*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) - ); + T(0)}, + {T(0), T(0), T(0), T(1)} + }; } /** * @brief 3D rotation around X axis - * @param angle Rotation angle (counterclockwise, in radians) + * @param angle Rotation angle (counterclockwise) * * Faster than calling `Matrix4::rotation(angle, Vector3::xAxis())`. - * @see rotation(T, const Vector3&), rotationY(), rotationZ(), - * rotation() const, Matrix3::rotation(T), deg(), rad() + * @see rotation(Rad, const Vector3&), rotationY(), rotationZ(), + * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) */ - static Matrix4 rotationX(T angle) { - T sine = std::sin(angle); - T cosine = std::cos(angle); - - return Matrix4( /* Column-major! */ - 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) { + T sine = std::sin(T(angle)); + T cosine = std::cos(T(angle)); + + 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)}}; } /** * @brief 3D rotation around Y axis - * @param angle Rotation angle (counterclockwise, in radians) + * @param angle Rotation angle (counterclockwise) * * Faster than calling `Matrix4::rotation(angle, Vector3::yAxis())`. - * @see rotation(T, const Vector3&), rotationX(), rotationZ(), - * rotation() const, Matrix3::rotation(T), deg(), rad() + * @see rotation(Rad, const Vector3&), rotationX(), rotationZ(), + * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) */ - static Matrix4 rotationY(T angle) { - T sine = std::sin(angle); - T cosine = std::cos(angle); - - return Matrix4( /* Column-major! */ - 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) { + T sine = std::sin(T(angle)); + T cosine = std::cos(T(angle)); + + 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)}}; } /** * @brief 3D rotation matrix around Z axis - * @param angle Rotation angle (counterclockwise, in radians) + * @param angle Rotation angle (counterclockwise) * * Faster than calling `Matrix4::rotation(angle, Vector3::zAxis())`. - * @see rotation(T, const Vector3&), rotationX(), rotationY(), - * rotation() const, Matrix3::rotation(T), deg(), rad() + * @see rotation(Rad, const Vector3&), rotationX(), rotationY(), + * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) */ - static Matrix4 rotationZ(T angle) { - T sine = std::sin(angle); - T cosine = std::cos(angle); - - return Matrix4( /* Column-major! */ - 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) { + T sine = std::sin(T(angle)); + T cosine = std::cos(T(angle)); + + 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)}}; + } + + /** + * @brief 3D reflection matrix + * @param normal Normal of the plane through which to reflect + * + * 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(), {}); + } + + /** + * @brief 3D orthographic projection matrix + * @param size Size of the view + * @param near Near clipping plane + * @param far Far clipping plane + * + * @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)}}; + } + + /** + * @brief 3D perspective projection matrix + * @param size Size of near clipping plane + * @param near Near clipping plane + * @param far Far clipping plane + * + * @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)}}; + } + + /** + * @brief 3D perspective projection matrix + * @param fov Field of view angle (horizontal) + * @param aspectRatio Aspect ratio + * @param near Near clipping plane + * @param far Far clipping plane + * + * @see orthographicProjection(), Matrix3::projection() + */ + static Matrix4 perspectiveProjection(Rad fov, T aspectRatio, T near, T far) { + T xyScale = 2*std::tan(T(fov)/2)*near; + + return perspectiveProjection(Vector2(xyScale, xyScale/aspectRatio), near, far); + } + + /** + * @brief Create matrix from rotation/scaling part and translation part + * @param rotationScaling Rotation/scaling part (upper-left 3x3 + * matrix) + * @param translation Translation part (first three elements of + * fourth column) + * + * @see rotationScaling() const, translation() const + */ + inline 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)}, + { translation, T(1)}}; } /** @copydoc Matrix::Matrix(ZeroType) */ inline constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {} - /** @copydoc Matrix::Matrix(IdentityType, T) */ - inline constexpr Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>( - value, T(0), T(0), T(0), - T(0), value, T(0), T(0), - T(0), T(0), value, T(0), - T(0), T(0), T(0), value + /** + * @brief Default constructor + * + * Creates identity matrix. You can also explicitly call this + * constructor with `Matrix4 m(Matrix4::Identity);`. Optional parameter + * @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>( + 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)), + Vector<4, T>( T(0), T(0), T(0), value) ) {} - /** @copydoc Matrix::Matrix */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr Matrix4(T first, U... next): Matrix<4, T>(first, next...) {} - #else - template inline constexpr Matrix4(T first, U... next) {} - #endif + /** @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) {} + + /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ + template inline constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other): Matrix<4, T>(other) {} /** @brief Copy constructor */ inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} + /** + * @brief Check whether the matrix represents rigid transformation + * + * Rigid transformation consists only of rotation and translation (i.e. + * no scaling or projection). + * @see isOrthogonal() + */ + inline bool isRigidTransformation() const { + return rotationScaling().isOrthogonal() && row(3) == Vector4(T(0), T(0), T(0), T(1)); + } + /** * @brief 3D rotation and scaling part of the matrix * * Upper-left 3x3 part of the matrix. - * @see rotation() const, rotation(T, const Vector3&), - * Matrix3::rotationScaling() const + * @see from(const Matrix<3, T>&, const Vector3&), rotation() const, + * rotation(T, const Vector3&), Matrix3::rotationScaling() const */ - inline Matrix<3, T> rotationScaling() const { + inline constexpr Matrix<3, T> rotationScaling() const { /* Not Matrix3, because it is for affine 2D transformations */ #ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */ - return Matrix<3, T>::from( - (*this)[0].xyz(), - (*this)[1].xyz(), - (*this)[2].xyz()); + return {(*this)[0].xyz(), + (*this)[1].xyz(), + (*this)[2].xyz()}; #else - return Matrix<3, T>( - (*this)(0, 0), (*this)(0, 1), (*this)(0, 2), - (*this)(1, 0), (*this)(1, 1), (*this)(1, 2), - (*this)(2, 0), (*this)(2, 1), (*this)(2, 2)); + return {Vector3((*this)[0][0], (*this)[0][1], (*this)[0][2]), + Vector3((*this)[1][0], (*this)[1][1], (*this)[1][2]), + Vector3((*this)[2][0], (*this)[2][1], (*this)[2][2])}; #endif } @@ -222,27 +320,28 @@ template class Matrix4: public Matrix<4, T> { * Normalized upper-left 3x3 part of the matrix. * @see rotationScaling() const, rotation(T, const Vector3&), * 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 Matrix<3, T>::from( - #ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */ - (*this)[0].xyz().normalized(), - (*this)[1].xyz().normalized(), - (*this)[2].xyz().normalized()); - #else - Vector3((*this)(0, 0), (*this)(0, 1), (*this)(0, 2)).normalized(), - Vector3((*this)(1, 0), (*this)(1, 1), (*this)(1, 2)).normalized(), - Vector3((*this)(2, 0), (*this)(2, 1), (*this)(2, 2)).normalized()); - #endif + #ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */ + return {(*this)[0].xyz().normalized(), + (*this)[1].xyz().normalized(), + (*this)[2].xyz().normalized()}; + #else + return {Vector3((*this)[0][0], (*this)[0][1], (*this)[0][2]).normalized(), + Vector3((*this)[1][0], (*this)[1][1], (*this)[1][2]).normalized(), + Vector3((*this)[2][0], (*this)[2][1], (*this)[2][2]).normalized()}; + #endif } + /** @todo uniform scaling extraction */ /** * @brief Right-pointing 3D vector * * First three elements of first column. - * @see Vector3::xAxis() + * @see up(), backward(), Vector3::xAxis(), Matrix3::right() */ inline Vector3& right() { return (*this)[0].xyz(); } inline constexpr Vector3 right() const { return (*this)[0].xyz(); } /**< @overload */ @@ -251,7 +350,7 @@ template class Matrix4: public Matrix<4, T> { * @brief Up-pointing 3D vector * * First three elements of second column. - * @see Vector3::yAxis() + * @see right(), backward(), Vector3::yAxis(), Matrix3::up() */ inline Vector3& up() { return (*this)[1].xyz(); } inline constexpr Vector3 up() const { return (*this)[1].xyz(); } /**< @overload */ @@ -260,7 +359,7 @@ template class Matrix4: public Matrix<4, T> { * @brief Backward-pointing 3D vector * * First three elements of third column. - * @see Vector3::yAxis() + * @see right(), up(), Vector3::yAxis() */ inline Vector3& backward() { return (*this)[2].xyz(); } inline constexpr Vector3 backward() const { return (*this)[2].xyz(); } /**< @overload */ @@ -269,21 +368,61 @@ template class Matrix4: public Matrix<4, T> { * @brief 3D translation part of the matrix * * First three elements of fourth column. - * @see translation(const Vector3&), Matrix3::translation() + * @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 */ - #ifndef DOXYGEN_GENERATING_OUTPUT - inline Point3D operator*(const Point3D& other) const { - return Matrix<4, T>::operator*(other); + /** + * @brief Inverted rigid transformation matrix + * + * Expects that the matrix represents rigid transformation. + * Significantly faster than the general algorithm in inverted(). + * @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()); + } + + /** + * @brief Transform 3D vector with the matrix + * + * Unlike in transformVector(), translation is not involved in the + * transformation. @f[ + * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ v_z \\ 0 \end{pmatrix} + * @f] + * @see Quaternion::transformVector(), Matrix3::transformVector() + * @todo extract 3x3 matrix and multiply directly? (benchmark that) + */ + inline Vector3 transformVector(const Vector3& vector) const { + return ((*this)*Vector4(vector, T(0))).xyz(); + } + + /** + * @brief Transform 3D point with the matrix + * + * Unlike in transformVector(), translation is also involved in the + * transformation. @f[ + * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ v_z \\ 1 \end{pmatrix} + * @f] + * @see DualQuaternion::transformPoint(), Matrix3::transformPoint() + */ + inline Vector3 transformPoint(const Vector3& vector) const { + return ((*this)*Vector4(vector, T(1))).xyz(); } - #endif + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4) MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4) }; +MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix4, 4) + /** @debugoperator{Magnum::Math::Matrix4} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4& value) { return debug << static_cast&>(value); diff --git a/src/Math/Point2D.h b/src/Math/Point2D.h deleted file mode 100644 index f26552d77..000000000 --- a/src/Math/Point2D.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef Magnum_Math_Point2D_h -#define Magnum_Math_Point2D_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file - * @brief Class Magnum::Math::Point2D - */ - -#include "Vector3.h" - -namespace Magnum { namespace Math { - -/** -@brief Two-dimensional homogeneous coordinates -@tparam T Data type - -Same as Vector3, except that constructors have default value for Z component -set to one. See also @ref matrix-vector for brief introduction. -@see Magnum::Point2D, Point3D -@configurationvalueref{Magnum::Math::Point2D} -*/ -template class Point2D: public Vector3 { - public: - /** - * @brief Default constructor - * - * X and Y components are set to zero, Z is set to one. - */ - inline constexpr Point2D(): Vector3(T(0), T(0), T(1)) {} - - /** @brief Copy constructor */ - inline constexpr Point2D(const RectangularMatrix<1, 3, T>& other): Vector3(other) {} - - /** - * @brief Constructor - * @param x X component - * @param y Y component - * @param z Z component - */ - inline constexpr Point2D(T x, T y, T z = T(1)): Vector3(x, y, z) {} - - /** - * @brief Constructor - * @param xy Two-component vector - * @param z Z component - */ - inline constexpr Point2D(const Vector2& xy, T z = T(1)): Vector3(xy, z) {} - - /** - * @brief Vector part of the point - * - * Equivalent to calling xy(). Useful for seamless 2D/3D integration. - * @see Point3D::vector() - */ - inline Vector2& vector() { return Vector3::xy(); } - inline constexpr Vector2 vector() const { return Vector3::xy(); } /**< @overload */ - - MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point2D, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Point2D) -}; - -MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point2D, 3) - -/** @debugoperator{Magnum::Math::Point2D} */ -template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Point2D& value) { - return debug << static_cast&>(value); -} - -}} - -namespace Corrade { namespace Utility { - /** @configurationvalue{Magnum::Math::Point2D} */ - template struct ConfigurationValue>: public ConfigurationValue> {}; -}} - -#endif diff --git a/src/Math/Point3D.h b/src/Math/Point3D.h deleted file mode 100644 index 339822217..000000000 --- a/src/Math/Point3D.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef Magnum_Math_Point3D_h -#define Magnum_Math_Point3D_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file - * @brief Class Magnum::Math::Point3D - */ - -#include "Vector4.h" - -namespace Magnum { namespace Math { - -/** -@brief Three-dimensional homogeneous coordinates -@tparam T Data type - -Same as Vector4, except that constructors have default value for W component -set to one. See also @ref matrix-vector for brief introduction. -@see Magnum::Point3D, Point2D -@configurationvalueref{Magnum::Math::Point3D} -*/ -template class Point3D: public Vector4 { - public: - /** - * @brief Default constructor - * - * X, Y and Z components are set to zero, W is set to one. - */ - inline constexpr Point3D(): Vector4(T(0), T(0), T(0), T(1)) {} - - /** @brief Copy constructor */ - inline constexpr Point3D(const RectangularMatrix<1, 4, T>& other): Vector4(other) {} - - /** - * @brief Constructor - * @param x X component - * @param y Y component - * @param z Z component - * @param w W component - */ - inline constexpr Point3D(T x, T y, T z, T w = T(1)): Vector4(x, y, z, w) {} - - /** - * @brief Constructor - * @param xyz Three-component vector - * @param w W component - */ - inline constexpr Point3D(const Vector3& xyz, T w = T(1)): Vector4(xyz, w) {} - - /** - * @brief Vector part of the point - * - * Equivalent to calling xyz(). Useful for seamless 2D/3D integration. - * @see Point2D::vector() - */ - inline Vector3& vector() { return Vector4::xyz(); } - inline constexpr Vector3 vector() const { return Vector4::xyz(); } /**< @overload */ - - MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point3D, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Point3D) -}; - -MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point3D, 4) - -/** @debugoperator{Magnum::Math::Point3D} */ -template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Point3D& value) { - return debug << static_cast&>(value); -} - -}} - -namespace Corrade { namespace Utility { - /** @configurationvalue{Magnum::Math::Point3D} */ - template struct ConfigurationValue>: public ConfigurationValue> {}; -}} - -#endif diff --git a/src/Math/Quaternion.cpp b/src/Math/Quaternion.cpp new file mode 100644 index 000000000..8ec3c0b13 --- /dev/null +++ b/src/Math/Quaternion.cpp @@ -0,0 +1,36 @@ +/* + 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 new file mode 100644 index 000000000..0cc1ac8ad --- /dev/null +++ b/src/Math/Quaternion.h @@ -0,0 +1,568 @@ +#ifndef Magnum_Math_Quaternion_h +#define Magnum_Math_Quaternion_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::Math::Quaternion + */ + +#include +#include +#include + +#include "Math/TypeTraits.h" +#include "Math/Matrix.h" +#include "Math/Vector3.h" + +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 + +Represents 3D rotation. See @ref transformations for brief introduction. +@see Magnum::Quaternion, Magnum::Quaterniond, DualQuaternion, Matrix4 +*/ +template class Quaternion { + public: + typedef T Type; /**< @brief Underlying data type */ + + /** + * @brief Dot product + * + * @f[ + * p \cdot q = \boldsymbol p_V \cdot \boldsymbol q_V + p_S q_S + * @f] + * @see dot() const + */ + inline 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(); + } + + /** + * @brief Angle between normalized quaternions + * + * Expects that both quaternions are normalized. @f[ + * \theta = acos \left( \frac{p \cdot q}{|p| |q|} \right) = acos(p \cdot q) + * @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)); + } + + /** + * @brief Linear interpolation of two quaternions + * @param normalizedA First quaternion + * @param normalizedB Second quaternion + * @param t Interpolation phase (from range @f$ [0; 1] @f$) + * + * Expects that both quaternions are normalized. @f[ + * q_{LERP} = \frac{(1 - t) q_A + t q_B}{|(1 - t) q_A + t q_B|} + * @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(); + } + + /** + * @brief Spherical linear interpolation of two quaternions + * @param normalizedA First quaternion + * @param normalizedB Second quaternion + * @param t Interpolation phase (from range @f$ [0; 1] @f$) + * + * Expects that both quaternions are normalized. @f[ + * q_{SLERP} = \frac{sin((1 - t) \theta) q_A + sin(t \theta) q_B}{sin \theta} + * ~~~~~~~~~~ + * \theta = acos \left( \frac{q_A \cdot q_B}{|q_A| \cdot |q_B|} \right) = acos(q_A \cdot q_B) + * @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); + } + + /** + * @brief Rotation quaternion + * @param angle Rotation angle (counterclockwise) + * @param normalizedAxis Normalized rotation axis + * + * Expects that the rotation axis is normalized. @f[ + * q = [\boldsymbol a \cdot sin \frac \theta 2, cos \frac \theta 2] + * @f] + * @see angle(), axis(), DualQuaternion::rotation(), + * 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(T(angle)/2), std::cos(T(angle)/2)}; + } + + /** + * @brief Create quaternion from rotation matrix + * + * 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); + } + + /** + * @brief Default constructor + * + * Creates unit quaternion. @f[ + * q = [\boldsymbol 0, 1] + * @f] + */ + inline constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {} + + /** + * @brief Construct quaternion from vector and scalar + * + * @f[ + * q = [\boldsymbol v, s] + * @f] + */ + inline constexpr /*implicit*/ Quaternion(const Vector3& vector, T scalar): _vector(vector), _scalar(scalar) {} + + /** + * @brief Construct quaternion from vector + * + * To be used in transformations later. @f[ + * q = [\boldsymbol v, 0] + * @f] + * @see transformVector(), transformVectorNormalized() + */ + inline constexpr explicit Quaternion(const Vector3& vector): _vector(vector), _scalar(T(0)) {} + + /** @brief Equality comparison */ + inline 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 { + return !operator==(other); + } + + /** + * @brief Whether the quaternion is normalized + * + * Quaternion is normalized if it has unit length: @f[ + * |q|^2 = |q| = 1 + * @f] + * @see dot(), normalized() + */ + inline bool isNormalized() const { + return Implementation::isNormalizedSquared(dot()); + } + + /** @brief %Vector part */ + inline constexpr Vector3 vector() const { return _vector; } + + /** @brief %Scalar part */ + inline constexpr T scalar() const { return _scalar; } + + /** + * @brief Rotation angle of unit quaternion + * + * Expects that the quaternion is normalized. @f[ + * \theta = 2 \cdot acos q_S + * @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)); + } + + /** + * @brief Rotation axis of unit quaternion + * + * Expects that the quaternion is normalized. Returns either unit-length + * vector for valid rotation quaternion or NaN vector for + * default-constructed quaternion. @f[ + * \boldsymbol a = \frac{\boldsymbol q_V}{\sqrt{1 - q_S^2}} + * @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)); + } + + /** + * @brief Convert quaternion to rotation matrix + * + * @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())) + }; + } + + /** + * @brief Add and assign quaternion + * + * The computation is done in-place. @f[ + * p + q = [\boldsymbol p_V + \boldsymbol q_V, p_S + q_S] + * @f] + */ + inline Quaternion& operator+=(const Quaternion& other) { + _vector += other._vector; + _scalar += other._scalar; + return *this; + } + + /** + * @brief Add quaternion + * + * @see operator+=() + */ + inline Quaternion operator+(const Quaternion& other) const { + return Quaternion(*this) += other; + } + + /** + * @brief Negated quaternion + * + * @f[ + * -q = [-\boldsymbol q_V, -q_S] + * @f] + */ + inline Quaternion operator-() const { + return {-_vector, -_scalar}; + } + + /** + * @brief Subtract and assign quaternion + * + * The computation is done in-place. @f[ + * p - q = [\boldsymbol p_V - \boldsymbol q_V, p_S - q_S] + * @f] + */ + inline Quaternion& operator-=(const Quaternion& other) { + _vector -= other._vector; + _scalar -= other._scalar; + return *this; + } + + /** + * @brief Subtract quaternion + * + * @see operator-=() + */ + inline Quaternion operator-(const Quaternion& other) const { + return Quaternion(*this) -= other; + } + + /** + * @brief Multiply with scalar and assign + * + * The computation is done in-place. @f[ + * q \cdot a = [\boldsymbol q_V \cdot a, q_S \cdot a] + * @f] + */ + inline Quaternion& operator*=(T scalar) { + _vector *= scalar; + _scalar *= scalar; + return *this; + } + + /** + * @brief Multiply with scalar + * + * @see operator*=(T) + */ + inline Quaternion operator*(T scalar) const { + return Quaternion(*this) *= scalar; + } + + /** + * @brief Divide with scalar and assign + * + * The computation is done in-place. @f[ + * \frac q a = [\frac {\boldsymbol q_V} a, \frac {q_S} a] + * @f] + */ + inline Quaternion& operator/=(T scalar) { + _vector /= scalar; + _scalar /= scalar; + return *this; + } + + /** + * @brief Divide with scalar + * + * @see operator/=(T) + */ + inline Quaternion operator/(T scalar) const { + return Quaternion(*this) /= scalar; + } + + /** + * @brief Multiply with quaternion + * + * @f[ + * p q = [p_S \boldsymbol q_V + q_S \boldsymbol p_V + \boldsymbol p_V \times \boldsymbol q_V, + * 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)}; + } + + /** + * @brief Dot product of the quaternion + * + * Should be used instead of length() for comparing quaternion length + * with other values, because it doesn't compute the square root. @f[ + * q \cdot q = \boldsymbol q_V \cdot \boldsymbol q_V + q_S^2 + * @f] + * @see isNormalized(), dot(const Quaternion&, const Quaternion&) + */ + inline T dot() const { + return dot(*this, *this); + } + + /** + * @brief %Quaternion length + * + * See also dot() const which is faster for comparing length with other + * values. @f[ + * |q| = \sqrt{q \cdot q} + * @f] + * @see isNormalized() + */ + inline T length() const { + return std::sqrt(dot()); + } + + /** + * @brief Normalized quaternion (of unit length) + * + * @see isNormalized() + */ + inline Quaternion normalized() const { + return (*this)/length(); + } + + /** + * @brief Conjugated quaternion + * + * @f[ + * q^* = [-\boldsymbol q_V, q_S] + * @f] + */ + inline Quaternion conjugated() const { + return {-_vector, _scalar}; + } + + /** + * @brief Inverted quaternion + * + * See invertedNormalized() which is faster for normalized + * quaternions. @f[ + * q^{-1} = \frac{q^*}{|q|^2} = \frac{q^*}{q \cdot q} + * @f] + */ + inline Quaternion inverted() const { + return conjugated()/dot(); + } + + /** + * @brief Inverted normalized quaternion + * + * Equivalent to conjugated(). Expects that the quaternion is + * normalized. @f[ + * q^{-1} = \frac{q^*}{|q|^2} = q^* + * @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(); + } + + /** + * @brief Rotate vector with quaternion + * + * See transformVectorNormalized(), which is faster for normalized + * quaternions. @f[ + * v' = qvq^{-1} = q [\boldsymbol v, 0] q^{-1} + * @f] + * @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(), + * DualQuaternion::transformPoint(), Complex::transformVector() + */ + inline Vector3 transformVector(const Vector3& vector) const { + return ((*this)*Quaternion(vector)*inverted()).vector(); + } + + /** + * @brief Rotate vector with normalized quaternion + * + * Faster alternative to transformVector(), expects that the quaternion + * is normalized. @f[ + * v' = qvq^{-1} = qvq^* = q [\boldsymbol v, 0] q^* + * @f] + * @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(); + } + + private: + /* Used to avoid including Functions.h */ + inline 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) { + return std::acos(dot(normalizedA, normalizedB)); + } + + Vector3 _vector; + T _scalar; +}; + +/** @relates Quaternion +@brief Multiply scalar with quaternion + +Same as Quaternion::operator*(T) const. +*/ +template inline Quaternion operator*(T scalar, const Quaternion& quaternion) { + return quaternion*scalar; +} + +/** @relates Quaternion +@brief Divide quaternion with number and invert + +@f[ + \frac a q = [\frac a {\boldsymbol q_V}, \frac a {q_S}] +@f] +@see Quaternion::operator/() +*/ +template inline Quaternion operator/(T scalar, const Quaternion& quaternion) { + return {scalar/quaternion.vector(), scalar/quaternion.scalar()}; +} + +/** @debugoperator{Magnum::Math::Quaternion} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Quaternion& value) { + debug << "Quaternion({"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + debug << value.vector().x() << ", " << value.vector().y() << ", " << value.vector().z() << "}, " << value.scalar() << ")"; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +/* Explicit instantiation for commonly used types */ +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Quaternion&); +#ifndef MAGNUM_TARGET_GLES +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Quaternion&); +#endif +#endif + +}} + +#endif diff --git a/src/Math/RectangularMatrix.cpp b/src/Math/RectangularMatrix.cpp index 73b56677d..7fcd9a6c7 100644 --- a/src/Math/RectangularMatrix.cpp +++ b/src/Math/RectangularMatrix.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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" @@ -18,43 +27,28 @@ namespace Magnum { namespace Math { #ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, unsigned int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, unsigned int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, unsigned int>&); +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<1, 2, double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, double>&); +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, 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>&); +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, 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>&); +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 @@ -63,43 +57,28 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnu 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 - -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>; +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>; +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 e01321277..fb869992d 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -1,77 +1,70 @@ #ifndef Magnum_Math_RectangularMatrix_h #define Magnum_Math_RectangularMatrix_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::RectangularMatrix */ -#include -#include -#include -#include - -#include "MathTypeTraits.h" - -#include "magnumVisibility.h" +#include "Math/Vector.h" namespace Magnum { namespace Math { -/** @todo Properly test all constexpr */ - -template class RectangularMatrix; - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - template struct Sequence {}; - - /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ - template struct GenerateSequence: - GenerateSequence {}; - - template struct GenerateSequence<0, sequence...> { - typedef Sequence Type; - }; - - /* Implementation for RectangularMatrix::from(const RectangularMatrix&) */ - template inline constexpr Math::RectangularMatrix rectangularMatrixFrom(Sequence, const Math::RectangularMatrix& matrix) { - return {T(matrix.data()[sequence])...}; - } -} -#endif - -template class Vector; - /** @brief Rectangular matrix @tparam cols Column count @tparam rows Row count -@tparam T Data type +@tparam T Underlying data type See @ref matrix-vector for brief introduction. See also Matrix (square) and Vector. + +The data are stored in column-major order, to reflect that, all indices in +math formulas are in reverse order (i.e. @f$ \boldsymbol A_{ji} @f$ instead +of @f$ \boldsymbol A_{ij} @f$). +@see Magnum::Matrix2x3, Magnum::Matrix3x2, Magnum::Matrix2x4, Magnum::Matrix4x2, + Magnum::Matrix3x4, Magnum::Matrix4x3, Magnum::Matrix2x3d, Magnum::Matrix3x2d, + Magnum::Matrix2x4d, Magnum::Matrix4x2d, Magnum::Matrix3x4d, Magnum::Matrix4x3d */ template class RectangularMatrix { - static_assert(cols != 0 && rows != 0, "Matrix cannot have zero elements"); + static_assert(cols != 0 && rows != 0, "RectangularMatrix cannot have zero elements"); + + template friend class RectangularMatrix; public: - typedef T Type; /**< @brief Data type */ + typedef T Type; /**< @brief Underlying data type */ const static std::size_t Cols = cols; /**< @brief %Matrix column count */ const static std::size_t Rows = rows; /**< @brief %Matrix row count */ + /** + * @brief Size of matrix diagonal + * + * @see fromDiagonal(), diagonal() + */ + const static std::size_t DiagonalSize = (cols < rows ? cols : rows); + /** * @brief %Matrix from array * @return Reference to the data as if it was Matrix, thus doesn't @@ -89,49 +82,51 @@ template class RectangularMatrix { } /** - * @brief %Matrix from column vectors + * @brief Construct diagonal matrix + * + * @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; + } + + /** @brief Construct zero-filled matrix */ + inline constexpr /*implicit*/ RectangularMatrix() {} + + /** + * @brief Construct matrix from column vectors * @param first First column vector * @param next Next column vectors * * @todo Creating matrix from arbitrary combination of matrices with n rows */ - template inline constexpr static RectangularMatrix from(const Vector& first, const U&... next) { - static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to Matrix from Vector constructor"); - return from(typename Implementation::GenerateSequence::Type(), first, next...); + template inline constexpr /*implicit*/ RectangularMatrix(const Vector& first, const U&... next): _data{first, next...} { + static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to RectangularMatrix constructor"); } /** - * @brief %Matrix from another of different type + * @brief Construct matrix from another of different type * * Performs only default casting on the values, no rounding or * anything else. Example usage: * @code - * RectangularMatrix<4, 1, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); - * RectangularMatrix<4, 1, std::int8_t> integral(RectangularMatrix<4, 1, std::int8_t>::from(floatingPoint)); + * RectangularMatrix<4, 1, Float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); + * RectangularMatrix<4, 1, Byte> integral(floatingPoint); * // integral == {1, 2, -15, 7} * @endcode */ - template inline constexpr static RectangularMatrix from(const RectangularMatrix& other) { - return Implementation::rectangularMatrixFrom(typename Implementation::GenerateSequence::Type(), other); - } - - /** @brief Zero-filled matrix constructor */ - inline constexpr RectangularMatrix(): _data() {} - - /** - * @brief Initializer-list constructor - * @param first First value - * @param next Next values - * - * Note that the values are in column-major order. - * @todoc Remove workaround when Doxygen supports uniform initialization - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr RectangularMatrix(T first, U... next): _data{first, next...} { - static_assert(sizeof...(next)+1 == cols*rows, "Improper number of arguments passed to Matrix constructor"); - } + #ifndef CORRADE_GCC46_COMPATIBILITY + template inline constexpr explicit RectangularMatrix(const RectangularMatrix& other): RectangularMatrix(typename Implementation::GenerateSequence::Type(), other) {} #else - template inline constexpr RectangularMatrix(T first, U... next); + template inline explicit RectangularMatrix(const RectangularMatrix& other) { + *this = RectangularMatrix(typename Implementation::GenerateSequence::Type(), other); + } #endif /** @brief Copy constructor */ @@ -144,47 +139,51 @@ template class RectangularMatrix { * @brief Raw data * @return One-dimensional array of `size*size` length in column-major * order. + * + * @see operator[] */ - inline T* data() { return _data; } - inline constexpr const T* data() const { return _data; } /**< @overload */ + inline T* data() { return _data[0].data(); } + inline constexpr const T* data() const { return _data[0].data(); } /**< @overload */ /** * @brief %Matrix column * - * For accessing individual elements prefer to use operator(), as it - * is guaranteed to not involve unnecessary conversions. + * Particular elements can be accessed using Vector::operator[], e.g.: + * @code + * RectangularMatrix<4, 3, Float> m; + * Float a = m[2][1]; + * @endcode + * + * @see row(), data() */ inline Vector& operator[](std::size_t col) { - return Vector::from(_data+col*rows); + return _data[col]; } /** @overload */ inline constexpr const Vector& operator[](std::size_t col) const { - return Vector::from(_data+col*rows); + return _data[col]; } /** - * @brief Element on given position + * @brief %Matrix row * - * Prefer this instead of using `[][]`. - * @see operator[] + * Consider using transposed() when accessing rows frequently, as this + * is slower than accessing columns due to the way the matrix is stored. + * @see operator[]() */ - inline T& operator()(std::size_t col, std::size_t row) { - return _data[col*rows+row]; - } - /** @overload */ - inline constexpr const T& operator()(std::size_t col, std::size_t row) const { - return _data[col*rows+row]; + 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; } - /** - * @brief Equality operator - * - * @see Vector::operator<(), Vector::operator<=(), Vector::operator>=(), - * Vector::operator>() - */ + /** @brief Equality comparison */ inline bool operator==(const RectangularMatrix& other) const { - for(std::size_t i = 0; i != cols*rows; ++i) - if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; + for(std::size_t i = 0; i != cols; ++i) + if(_data[i] != other._data[i]) return false; return true; } @@ -195,10 +194,24 @@ template class RectangularMatrix { * @see Vector::operator<(), Vector::operator<=(), Vector::operator>=(), * Vector::operator>() */ - inline constexpr bool operator!=(const RectangularMatrix& other) const { + inline bool operator!=(const RectangularMatrix& other) const { return !operator==(other); } + /** + * @brief Add and assign matrix + * + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = \boldsymbol A_j + \boldsymbol B_j + * @f] + */ + RectangularMatrix& operator+=(const RectangularMatrix& other) { + for(std::size_t i = 0; i != cols; ++i) + _data[i] += other._data[i]; + + return *this; + } + /** * @brief Add matrix * @@ -209,28 +222,35 @@ template class RectangularMatrix { } /** - * @brief Add and assign matrix + * @brief Negated matrix * - * More efficient than operator+(), because it does the computation - * in-place. + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = -\boldsymbol A_j + * @f] */ - RectangularMatrix& operator+=(const RectangularMatrix& other) { - for(std::size_t i = 0; i != cols*rows; ++i) - _data[i] += other._data[i]; - - return *this; - } - - /** @brief Negative matrix */ RectangularMatrix operator-() const { RectangularMatrix out; - for(std::size_t i = 0; i != cols*rows; ++i) + for(std::size_t i = 0; i != cols; ++i) out._data[i] = -_data[i]; return out; } + /** + * @brief Subtract and assign matrix + * + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = \boldsymbol A_j - \boldsymbol B_j + * @f] + */ + RectangularMatrix& operator-=(const RectangularMatrix& other) { + for(std::size_t i = 0; i != cols; ++i) + _data[i] -= other._data[i]; + + return *this; + } + /** * @brief Subtract matrix * @@ -241,14 +261,19 @@ template class RectangularMatrix { } /** - * @brief Subtract and assign matrix + * @brief Multiply matrix with number and assign * - * More efficient than operator-(), because it does the computation - * in-place. + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = a \boldsymbol A_j + * @f] */ - RectangularMatrix& operator-=(const RectangularMatrix& other) { - for(std::size_t i = 0; i != cols*rows; ++i) - _data[i] -= other._data[i]; + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline typename std::enable_if::value, RectangularMatrix&>::type operator*=(U number) { + #else + template RectangularMatrix& operator*=(U number) { + #endif + for(std::size_t i = 0; i != cols; ++i) + _data[i] *= number; return *this; } @@ -267,18 +292,19 @@ template class RectangularMatrix { } /** - * @brief Multiply matrix with number and assign + * @brief Divide matrix with number and assign * - * More efficient than operator*(U), because it does the computation - * in-place. + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = \frac{\boldsymbol A_j} a + * @f] */ #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix&>::type operator*=(U number) { + template inline typename std::enable_if::value, RectangularMatrix&>::type operator/=(U number) { #else - template RectangularMatrix& operator*=(U number) { + template RectangularMatrix& operator/=(U number) { #endif - for(std::size_t i = 0; i != cols*rows; ++i) - _data[i] *= number; + for(std::size_t i = 0; i != cols; ++i) + _data[i] /= number; return *this; } @@ -297,30 +323,19 @@ template class RectangularMatrix { } /** - * @brief Divide matrix with number and assign + * @brief Multiply matrix * - * More efficient than operator/(), because it does the computation - * in-place. + * @f[ + * (\boldsymbol {AB})_{ji} = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol B_{jk} + * @f] */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix&>::type operator/=(U number) { - #else - template RectangularMatrix& operator/=(U number) { - #endif - for(std::size_t i = 0; i != cols*rows; ++i) - _data[i] /= number; - - return *this; - } - - /** @brief Multiply matrix */ 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) += (*this)(pos, row)*other(col, pos); + out[col][row] += _data[pos][row]*other._data[col][pos]; return out; } @@ -329,46 +344,119 @@ template class RectangularMatrix { * @brief Multiply vector * * Internally the same as multiplying with one-column matrix, but - * returns vector. + * returns vector. @f[ + * (\boldsymbol {Aa})_i = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol a_k + * @f] */ Vector operator*(const Vector& other) const { - return operator*(static_cast>(other)); + return operator*(RectangularMatrix<1, rows, T>(other))[0]; } - /** @brief Transposed matrix */ + /** + * @brief Transposed matrix + * + * @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) = (*this)(col, row); + out[row][col] = _data[col][row]; + + return out; + } + + /** + * @brief Values on diagonal + * + * @see fromDiagonal() + */ + Vector diagonal() const { + Vector out; + + for(std::size_t i = 0; i != DiagonalSize; ++i) + out[i] = _data[i][i]; return out; } - #ifndef DOXYGEN_GENERATING_OUTPUT - protected: - T _data[rows*cols]; - #endif + /** @brief Sum of values in the matrix */ + T sum() const { + T out(_data[0].sum()); - private: - template inline constexpr static RectangularMatrix from(Implementation::Sequence s, const Vector& first, U... next) { - return from(s, next..., first[sequence]...); + for(std::size_t i = 1; i != cols; ++i) + out += _data[i].sum(); + + return out; + } + + /** @brief Product of values in the matrix */ + T product() const { + T out(_data[0].product()); + + for(std::size_t i = 1; i != cols; ++i) + out *= _data[i].product(); + + return out; } - template inline constexpr static RectangularMatrix from(Implementation::Sequence, T first, U... next) { - return RectangularMatrix(first, next...); + + /** @brief Minimal value in the matrix */ + T min() const { + T out(_data[0].min()); + + for(std::size_t i = 1; i != cols; ++i) + out = std::min(out, _data[i].min()); + + return out; + } + + /** @brief Minimal absolute value in the matrix */ + T minAbs() const { + T out(_data[0].minAbs()); + + for(std::size_t i = 1; i != cols; ++i) + out = std::min(out, _data[i].minAbs()); + + return out; + } + + /** @brief Maximal value in the matrix */ + T max() const { + T out(_data[0].max()); + + for(std::size_t i = 1; i != cols; ++i) + out = std::max(out, _data[i].max()); + + return out; } + + /** @brief Maximal absolute value in the matrix */ + T maxAbs() const { + T out(_data[0].maxAbs()); + + for(std::size_t i = 1; i != cols; ++i) + out = std::max(out, _data[i].maxAbs()); + + return out; + } + + private: + /* Implementation for RectangularMatrix::RectangularMatrix(const RectangularMatrix&) */ + template inline constexpr explicit RectangularMatrix(Implementation::Sequence, const RectangularMatrix& matrix): _data{Vector(matrix[sequence])...} {} + + Vector _data[cols]; }; /** @relates RectangularMatrix @brief Multiply number with matrix -@see RectangularMatrix::operator*(U) const +Same as RectangularMatrix::operator*(U) const. */ -#ifndef DOXYGEN_GENERATING_OUTPUT -template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number, const RectangularMatrix& matrix) { -#else +#ifdef DOXYGEN_GENERATING_OUTPUT template inline RectangularMatrix operator*(U number, const RectangularMatrix& matrix) { +#else +template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number, const RectangularMatrix& matrix) { #endif return matrix*number; } @@ -376,26 +464,36 @@ template inline Rectangula /** @relates RectangularMatrix @brief Divide matrix with number and invert -Example: -@code -RectangularMatrix<2, 3, float> mat(1.0f, 2.0f, -4.0f, 8.0f, -1.0f, 0.5f); -RectangularMatrix<2, 3, float> another = 1.0f/mat; // {1.0f, 0.5f, -0.25f, 0.128f, -1.0f, 2.0f} -@endcode -@see RectangularMatrix::operator/() +The computation is done column-wise. @f[ + \boldsymbol B_j = \frac a {\boldsymbol A_j} +@f] +@see RectangularMatrix::operator/(U) const */ -#ifndef DOXYGEN_GENERATING_OUTPUT -template typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { -#else +#ifdef DOXYGEN_GENERATING_OUTPUT template RectangularMatrix operator/(U number, const RectangularMatrix& matrix) { +#else +template typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { #endif RectangularMatrix out; - for(std::size_t i = 0; i != cols*rows; ++i) - out.data()[i] = number/matrix.data()[i]; + for(std::size_t i = 0; i != cols; ++i) + out[i] = number/matrix[i]; return out; } +/** @relates RectangularMatrix +@brief Multiply vector with rectangular matrix + +Internally the same as multiplying one-column matrix with one-row matrix. @f[ + (\boldsymbol {aA})_{ji} = \boldsymbol a_i \boldsymbol A_j +@f] +@see RectangularMatrix::operator*(const RectangularMatrix&) const +*/ +template inline RectangularMatrix operator*(const Vector& vector, const RectangularMatrix& matrix) { + return RectangularMatrix<1, size, T>(vector)*matrix; +} + /** @debugoperator{Magnum::Math::RectangularMatrix} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix& value) { debug << "Matrix("; @@ -404,110 +502,85 @@ template Corrade::Utility::Debug op if(row != 0) debug << ",\n "; for(std::size_t col = 0; col != cols; ++col) { if(col != 0) debug << ", "; - debug << typename MathTypeTraits::NumericType(value[col][row]); + debug << value[col][row]; } } - debug << ')'; + debug << ")"; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); return debug; } -/* Explicit instantiation for types used in OpenGL */ #ifndef DOXYGEN_GENERATING_OUTPUT -/* Vectors */ -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, unsigned int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, unsigned int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, unsigned int>&); -#ifndef MAGNUM_TARGET_GLES -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, double>&); -#endif - +/* Explicit instantiation for types used in OpenGL */ /* Square matrices */ -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, Float>&); #ifndef MAGNUM_TARGET_GLES -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, Double>&); #endif /* Rectangular matrices */ -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, Float>&); #ifndef MAGNUM_TARGET_GLES -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, double>&); -#endif +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, Double>&); #endif -#ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \ inline constexpr static __VA_ARGS__& from(T* data) { \ return *reinterpret_cast<__VA_ARGS__*>(data); \ } \ inline constexpr static const __VA_ARGS__& from(const T* data) { \ return *reinterpret_cast(data); \ - } \ - template inline constexpr static __VA_ARGS__ from(const Math::Vector& first, const U&... next) { \ - return Math::RectangularMatrix::from(first, next...); \ - } \ - template inline constexpr static RectangularMatrix from(const Math::RectangularMatrix& other) { \ - return Math::RectangularMatrix::from(other); \ } \ \ inline __VA_ARGS__& operator=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator=(other); \ return *this; \ - } - -#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(cols, rows, ...) \ + } \ + \ inline __VA_ARGS__ operator-() const { \ return Math::RectangularMatrix::operator-(); \ } \ - inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ - return Math::RectangularMatrix::operator+(other); \ - } \ inline __VA_ARGS__& operator+=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator+=(other); \ return *this; \ } \ - inline __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ - return Math::RectangularMatrix::operator-(other); \ + inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ + return Math::RectangularMatrix::operator+(other); \ } \ inline __VA_ARGS__& operator-=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator-=(other); \ return *this; \ } \ - template inline typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ - return Math::RectangularMatrix::operator*(number); \ + inline __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) { \ Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ - template inline 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) const { \ + return Math::RectangularMatrix::operator*(number); \ } \ template inline 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 { \ + return Math::RectangularMatrix::operator/(number); \ } #endif @@ -517,6 +590,8 @@ namespace Corrade { namespace Utility { /** @configurationvalue{Magnum::Math::RectangularMatrix} */ template struct ConfigurationValue> { + ConfigurationValue() = delete; + /** @brief Writes elements separated with spaces */ static std::string toString(const Magnum::Math::RectangularMatrix& value, ConfigurationValueFlags flags) { std::string output; @@ -524,7 +599,7 @@ template struct ConfigurationValue< for(std::size_t row = 0; row != rows; ++row) { for(std::size_t col = 0; col != cols; ++col) { if(!output.empty()) output += ' '; - output += ConfigurationValue::toString(value(col, row), flags); + output += ConfigurationValue::toString(value[col][row], flags); } } @@ -534,67 +609,52 @@ template struct ConfigurationValue< /** @brief Reads elements separated with whitespace */ static Magnum::Math::RectangularMatrix fromString(const std::string& stringValue, ConfigurationValueFlags flags) { Magnum::Math::RectangularMatrix result; - std::istringstream in(stringValue); - for(std::size_t row = 0; row != rows; ++row) { - for(std::size_t col = 0; col != cols; ++col) { - std::string num; - in >> num; - result(col, row) = ConfigurationValue::fromString(num, flags); + std::size_t oldpos = 0, pos = std::string::npos, i = 0; + do { + pos = stringValue.find(' ', oldpos); + std::string part = stringValue.substr(oldpos, pos-oldpos); + + if(!part.empty()) { + result[i%cols][i/cols] = ConfigurationValue::fromString(part, flags); + ++i; } - } + + oldpos = pos+1; + } while(pos != std::string::npos); return result; } }; #ifndef DOXYGEN_GENERATING_OUTPUT -/* Vectors */ -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -#ifndef MAGNUM_TARGET_GLES -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -#endif - /* Square matrices */ -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; #ifndef MAGNUM_TARGET_GLES -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; #endif /* Rectangular matrices */ -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; #ifndef MAGNUM_TARGET_GLES -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; #endif #endif }} -/* Include also Vector, so the definition is complete */ -#include "Vector.h" - #endif diff --git a/src/Math/Swizzle.h b/src/Math/Swizzle.h new file mode 100644 index 000000000..a36234206 --- /dev/null +++ b/src/Math/Swizzle.h @@ -0,0 +1,83 @@ +#ifndef Magnum_Math_Swizzle_h +#define Magnum_Math_Swizzle_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::Math::swizzle() + */ + +#include "Vector.h" + +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 struct Component {}; + template struct Component: public ComponentAtPosition {}; + template struct Component: public ComponentAtPosition {}; + 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 struct Component { + template inline constexpr static T value(const Math::Vector&) { return T(1); } + }; +} +#endif + +/** +@brief Swizzle Vector components + +Creates new vector from given components. Example: +@code +Vector4 original(-1, 2, 3, 4); + +auto vec = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); +// vec == { 4, 1, 0, -1, 2, 3 } +@endcode +You can use letters `x`, `y`, `z`, `w` for addressing components or letters +`0` and `1` for zero and one. Count of elements is unlimited, but must be at +least one. + +See also Magnum::swizzle() which has some added convenience features not +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) { + return {Implementation::Component::value(vector)...}; +} + +}} + +#endif diff --git a/src/Math/Test/AngleTest.cpp b/src/Math/Test/AngleTest.cpp new file mode 100644 index 000000000..cac78bda1 --- /dev/null +++ b/src/Math/Test/AngleTest.cpp @@ -0,0 +1,138 @@ +/* + 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/Angle.h" + +namespace Magnum { namespace Math { namespace Test { + +class AngleTest: public Corrade::TestSuite::Tester { + public: + explicit AngleTest(); + + void construct(); + void literals(); + void conversion(); + + void debugDeg(); + void debugRad(); +}; + +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Deg Degd; +typedef Math::Rad Radd; + +AngleTest::AngleTest() { + addTests({&AngleTest::construct, + &AngleTest::literals, + &AngleTest::conversion, + + &AngleTest::debugDeg, + &AngleTest::debugRad}); +} + +void AngleTest::construct() { + /* Default constructor */ + constexpr Degd a; + constexpr Deg m; + CORRADE_COMPARE(Double(a), 0.0f); + CORRADE_COMPARE(Float(m), 0.0f); + + /* Value constructor */ + constexpr Deg b(25.0); + constexpr Radd n(3.14); + CORRADE_COMPARE(Float(b), 25.0); + CORRADE_COMPARE(Double(n), 3.14); + + /* Copy constructor */ + constexpr Deg c(b); + constexpr Radd o(n); + CORRADE_COMPARE(c, b); + CORRADE_COMPARE(o, n); + + /* Conversion operator */ + constexpr Degd d(b); + constexpr Rad p(n); + CORRADE_COMPARE(Double(d), 25.0); + CORRADE_COMPARE(Float(p), 3.14f); +} + +void AngleTest::literals() { + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr auto a = 25.0_deg; + constexpr auto b = 25.0_degf; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_COMPARE(Double(a), 25.0); + CORRADE_COMPARE(Float(b), 25.0f); + + constexpr auto m = 3.14_rad; + constexpr auto n = 3.14_radf; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_COMPARE(Double(m), 3.14); + CORRADE_COMPARE(Float(n), 3.14f); + #else + CORRADE_SKIP("User-defined literals are not available on GCC < 4.7."); + #endif +} + +void AngleTest::conversion() { + constexpr Deg a(Rad(1.57079633f)); + CORRADE_COMPARE(Float(a), 90.0f); + + constexpr Rad b(Deg(90.0f)); + CORRADE_COMPARE(Float(b), 1.57079633f); +} + +void AngleTest::debugDeg() { + std::ostringstream o; + + Debug(&o) << Deg(90.0f); + CORRADE_COMPARE(o.str(), "Deg(90)\n"); + + /* Verify that this compiles */ + o.str({}); + Debug(&o) << Deg(56.0f) - Deg(34.0f); + CORRADE_COMPARE(o.str(), "Deg(22)\n"); +} + +void AngleTest::debugRad() { + std::ostringstream o; + + Debug(&o) << Rad(1.5708f); + CORRADE_COMPARE(o.str(), "Rad(1.5708)\n"); + + /* Verify that this compiles */ + o.str({}); + Debug(&o) << Rad(1.5708f) - Rad(3.1416f); + CORRADE_COMPARE(o.str(), "Rad(-1.5708)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::AngleTest) diff --git a/src/Math/Test/BoolVectorTest.cpp b/src/Math/Test/BoolVectorTest.cpp new file mode 100644 index 000000000..1063726e6 --- /dev/null +++ b/src/Math/Test/BoolVectorTest.cpp @@ -0,0 +1,214 @@ +/* + 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/BoolVector.h" + +namespace Magnum { namespace Math { namespace Test { + +class BoolVectorTest: public Corrade::TestSuite::Tester { + public: + explicit BoolVectorTest(); + + void constructDefault(); + void constructOneValue(); + void constructOneElement(); + void data(); + + void constExpressions(); + + void compare(); + void compareUndefined(); + void all(); + void none(); + void any(); + + void bitInverse(); + void bitAndOrXor(); + + void debug(); +}; + +static_assert(BoolVector<15>::DataSize == 2, "Improper DataSize"); +static_assert(BoolVector<16>::DataSize == 2, "Improper DataSize"); +static_assert(BoolVector<17>::DataSize == 3, "Improper DataSize"); + +typedef Math::BoolVector<19> BoolVector19; + +BoolVectorTest::BoolVectorTest() { + addTests({&BoolVectorTest::constructDefault, + &BoolVectorTest::constructOneValue, + &BoolVectorTest::constructOneElement, + &BoolVectorTest::data, + + &BoolVectorTest::constExpressions, + + &BoolVectorTest::compare, + &BoolVectorTest::compareUndefined, + &BoolVectorTest::all, + &BoolVectorTest::none, + &BoolVectorTest::any, + + &BoolVectorTest::bitInverse, + &BoolVectorTest::bitAndOrXor, + + &BoolVectorTest::debug}); +} + +void BoolVectorTest::constructDefault() { + CORRADE_COMPARE(BoolVector19(), BoolVector19(0x00, 0x00, 0x00)); +} + +void BoolVectorTest::constructOneValue() { + CORRADE_COMPARE(BoolVector19(false), BoolVector19(0x00, 0x00, 0x00)); + CORRADE_COMPARE(BoolVector19(true), BoolVector19(0xff, 0xff, 0x07)); +} + +void BoolVectorTest::constructOneElement() { + typedef BoolVector<1> BoolVector1; + + BoolVector1 a = 0x01; + CORRADE_COMPARE(a, BoolVector1(0x01)); +} + +void BoolVectorTest::data() { + BoolVector19 a(0x08, 0x03, 0x04); + + CORRADE_VERIFY(!a[0] && !a[1] && !a[2]); + CORRADE_VERIFY(a[3]); + CORRADE_VERIFY(!a[4] && !a[5] && !a[6] && !a[7]); + CORRADE_VERIFY(a[8]); + CORRADE_VERIFY(a[9]); + CORRADE_VERIFY(!a[10] && !a[11] && !a[12] && !a[13] && !a[14] && !a[15] && !a[16] && !a[17]); + CORRADE_VERIFY(a[18]); + + a.set(15, true); + CORRADE_VERIFY(a[15]); + + CORRADE_COMPARE(a, BoolVector19(0x08, 0x83, 0x04)); +} + +void BoolVectorTest::constExpressions() { + /* Default constructor */ + constexpr BoolVector19 a; + CORRADE_COMPARE(a, BoolVector19(0x00, 0x00, 0x00)); + + /* Value constructor */ + constexpr BoolVector19 b(0xa5, 0x5f, 0x07); + CORRADE_COMPARE(b, BoolVector19(0xa5, 0x5f, 0x07)); + + /* One-value constructor, not constexpr under GCC < 4.7 */ + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr BoolVector19 c(true); + CORRADE_COMPARE(c, BoolVector19(0xff, 0xff, 0x07)); + #endif + + /* Copy constructor */ + constexpr BoolVector19 d(b); + CORRADE_COMPARE(d, BoolVector19(0xa5, 0x5f, 0x07)); + + /* Data access, pointer chasings, i.e. *(b.data()[3]), are not possible */ + constexpr bool e = b[2]; + constexpr UnsignedByte f = *b.data(); + CORRADE_COMPARE(e, true); + CORRADE_COMPARE(f, 0xa5); +} + +void BoolVectorTest::compare() { + BoolVector19 a(0xa5, 0x5f, 0x07); + CORRADE_VERIFY(a == a); + + /* Change in full segments */ + BoolVector19 b(0xa3, 0x5f, 0x07); + BoolVector19 c(0xa5, 0x98, 0x07); + CORRADE_VERIFY(a != b); + CORRADE_VERIFY(a != c); + + /* Change in last bit */ + BoolVector19 d(0xa5, 0x5f, 0x06); + CORRADE_VERIFY(a != d); +} + +void BoolVectorTest::compareUndefined() { + BoolVector19 a(0xa5, 0x5f, 0x07); + + /* Change in unused part of last segment */ + BoolVector19 b(0xa5, 0x5f, 0x0f); + CORRADE_VERIFY(a == b); + + /* Change in used part of last segment */ + BoolVector19 c(0xa5, 0x5f, 0x03); + CORRADE_VERIFY(a != c); +} + +void BoolVectorTest::all() { + CORRADE_VERIFY(BoolVector19(0xff, 0xff, 0x07).all()); + + /* Last segment - bit in used and unused part */ + CORRADE_VERIFY(BoolVector19(0xff, 0xff, 0x0f).all()); + CORRADE_VERIFY(!BoolVector19(0xff, 0xff, 0x04).all()); +} + +void BoolVectorTest::none() { + CORRADE_VERIFY(BoolVector19(0x00, 0x00, 0x00).none()); + + /* Last segment - bit in used and unused part */ + CORRADE_VERIFY(BoolVector19(0x00, 0x00, 0x08).none()); + CORRADE_VERIFY(!BoolVector19(0x00, 0x00, 0x04).none()); +} + +void BoolVectorTest::any() { + CORRADE_VERIFY(BoolVector19(0x00, 0x01, 0x00).any()); + + /* Last segment - bit in used and unused part */ + CORRADE_VERIFY(BoolVector19(0x00, 0x00, 0x04).any()); + CORRADE_VERIFY(!BoolVector19(0x00, 0x00, 0x08).any()); +} + +void BoolVectorTest::bitInverse() { + CORRADE_COMPARE(~BoolVector19(0xa5, 0x5f, 0x03), BoolVector19(0x5a, 0xa0, 0x04)); +} + +void BoolVectorTest::bitAndOrXor() { + BoolVector19 a(0xa5, 0x5f, 0x03); + BoolVector19 b(0x37, 0xf3, 0x06); + + CORRADE_COMPARE(a & b, BoolVector19(0x25, 0x53, 0x02)); + CORRADE_COMPARE(a | b, BoolVector19(0xb7, 0xff, 0x07)); + CORRADE_COMPARE(a ^ b, BoolVector19(0x92, 0xac, 0x05)); +} + +void BoolVectorTest::debug() { + std::ostringstream o; + + Debug(&o) << BoolVector19(0x25, 0x53, 0x02); + + CORRADE_COMPARE(o.str(), "BoolVector(10100100 11001010 010)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::BoolVectorTest) diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index c641a04a5..65fe5141c 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/src/Math/Test/CMakeLists.txt @@ -1,19 +1,59 @@ -corrade_add_test2(MathConstantsTest ConstantsTest.cpp) -corrade_add_test2(MathTest MathTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathMathTypeTraitsTest MathTypeTraitsTest.cpp) +# +# 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. +# -corrade_add_test2(MathRectangularMatrixTest RectangularMatrixTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathBoolVectorTest BoolVectorTest.cpp) +corrade_add_test(MathConstantsTest ConstantsTest.cpp) +corrade_add_test(MathFunctionsTest FunctionsTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathTypeTraitsTest TypeTraitsTest.cpp) -corrade_add_test2(MathVectorTest VectorTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathVector2Test Vector2Test.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathVector3Test Vector3Test.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathVector4Test Vector4Test.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathVectorTest VectorTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathVector2Test Vector2Test.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathVector3Test Vector3Test.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathVector4Test Vector4Test.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathPoint2DTest Point2DTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathPoint3DTest Point3DTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathRectangularMatrixTest RectangularMatrixTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathMatrixTest MatrixTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathMatrix3Test Matrix3Test.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathMatrix4Test Matrix4Test.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathMatrixTest MatrixTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathMatrix3Test Matrix3Test.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MathMatrix4Test Matrix4Test.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathSwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathUnitTest UnitTest.cpp) +corrade_add_test(MathAngleTest AngleTest.cpp LIBRARIES MagnumMathTestLib) -set_target_properties(MathVectorTest MathMatrix4Test PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) +corrade_add_test(MathDualTest DualTest.cpp) +corrade_add_test(MathComplexTest ComplexTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathDualComplexTest DualComplexTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathQuaternionTest QuaternionTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathDualQuaternionTest DualQuaternionTest.cpp LIBRARIES MagnumMathTestLib) + +set_target_properties( + MathVectorTest + MathMatrixTest + MathMatrix3Test + MathMatrix4Test + MathComplexTest + MathDualComplexTest + MathQuaternionTest + MathDualQuaternionTest + PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) diff --git a/src/Math/Test/ComplexTest.cpp b/src/Math/Test/ComplexTest.cpp new file mode 100644 index 000000000..ecf939ada --- /dev/null +++ b/src/Math/Test/ComplexTest.cpp @@ -0,0 +1,306 @@ +/* + 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/Complex.h" +#include "Math/Matrix3.h" + +namespace Magnum { namespace Math { namespace Test { + +class ComplexTest: public Corrade::TestSuite::Tester { + public: + explicit ComplexTest(); + + void construct(); + void constructDefault(); + void constructFromVector(); + void constructCopy(); + + void compare(); + void isNormalized(); + + void addSubtract(); + void negated(); + void multiplyDivideScalar(); + void multiply(); + + void dot(); + void dotSelf(); + void length(); + void normalized(); + + void conjugated(); + void inverted(); + void invertedNormalized(); + + void angle(); + void rotation(); + void matrix(); + void transformVector(); + + void debug(); +}; + +ComplexTest::ComplexTest() { + addTests({&ComplexTest::construct, + &ComplexTest::constructDefault, + &ComplexTest::constructFromVector, + &ComplexTest::constructCopy, + + &ComplexTest::compare, + &ComplexTest::isNormalized, + + &ComplexTest::addSubtract, + &ComplexTest::negated, + &ComplexTest::multiplyDivideScalar, + &ComplexTest::multiply, + + &ComplexTest::dot, + &ComplexTest::dotSelf, + &ComplexTest::length, + &ComplexTest::normalized, + + &ComplexTest::conjugated, + &ComplexTest::inverted, + &ComplexTest::invertedNormalized, + + &ComplexTest::angle, + &ComplexTest::rotation, + &ComplexTest::matrix, + &ComplexTest::transformVector, + + &ComplexTest::debug}); +} + +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Complex Complex; +typedef Math::Vector2 Vector2; +typedef Math::Matrix3 Matrix3; +typedef Math::Matrix<2, Float> Matrix2; + +void ComplexTest::construct() { + constexpr Complex a(0.5f, -3.7f); + CORRADE_COMPARE(a, Complex(0.5f, -3.7f)); + + constexpr Float b = a.real(); + constexpr Float c = a.imaginary(); + CORRADE_COMPARE(b, 0.5f); + CORRADE_COMPARE(c, -3.7f); +} + +void ComplexTest::constructDefault() { + constexpr Complex a; + CORRADE_COMPARE(a, Complex(1.0f, 0.0f)); + CORRADE_COMPARE(a.length(), 1.0f); +} + +void ComplexTest::constructFromVector() { + constexpr Vector2 vec(1.5f, -3.0f); + + constexpr Complex a(vec); + CORRADE_COMPARE(a, Complex(1.5f, -3.0f)); + + constexpr Vector2 b(a); + CORRADE_COMPARE(b, vec); +} + +void ComplexTest::constructCopy() { + constexpr Complex a(2.5f, -5.0f); + constexpr Complex b(a); + CORRADE_COMPARE(b, Complex(2.5f, -5.0f)); +} + +void ComplexTest::compare() { + CORRADE_VERIFY(Complex(3.7f, -1.0f+TypeTraits::epsilon()/2) == Complex(3.7f, -1.0f)); + CORRADE_VERIFY(Complex(3.7f, -1.0f+TypeTraits::epsilon()*2) != Complex(3.7f, -1.0f)); + CORRADE_VERIFY(Complex(1.0f+TypeTraits::epsilon()/2, 3.7f) == Complex(1.0f, 3.7f)); + CORRADE_VERIFY(Complex(1.0f+TypeTraits::epsilon()*2, 3.7f) != Complex(1.0f, 3.7f)); +} + +void ComplexTest::isNormalized() { + CORRADE_VERIFY(!Complex(2.5f, -3.7f).isNormalized()); + CORRADE_VERIFY(Complex::rotation(Deg(23.0f)).isNormalized()); +} + +void ComplexTest::addSubtract() { + Complex a( 1.7f, -3.7f); + Complex b(-3.6f, 0.2f); + Complex c(-1.9f, -3.5f); + + CORRADE_COMPARE(a + b, c); + CORRADE_COMPARE(c - b, a); +} + +void ComplexTest::negated() { + CORRADE_COMPARE(-Complex(2.5f, -7.4f), Complex(-2.5f, 7.4f)); +} + +void ComplexTest::multiplyDivideScalar() { + Complex a( 2.5f, -0.5f); + Complex b(-7.5f, 1.5f); + + CORRADE_COMPARE(a*-3.0f, b); + CORRADE_COMPARE(-3.0f*a, b); + CORRADE_COMPARE(b/-3.0f, a); + + Complex c(-0.8f, 4.0f); + CORRADE_COMPARE(-2.0f/a, c); +} + +void ComplexTest::multiply() { + Complex a( 5.0f, 3.0f); + Complex b( 6.0f, -7.0f); + Complex c(51.0f, -17.0f); + + CORRADE_COMPARE(a*b, c); + CORRADE_COMPARE(b*a, c); +} + +void ComplexTest::dot() { + Complex a(5.0f, 3.0f); + Complex b(6.0f, -7.0f); + + CORRADE_COMPARE(Complex::dot(a, b), 9.0f); +} + +void ComplexTest::dotSelf() { + CORRADE_COMPARE(Complex(-4.0f, 3.0f).dot(), 25.0f); +} + +void ComplexTest::length() { + CORRADE_COMPARE(Complex(-4.0f, 3.0f).length(), 5.0f); +} + +void ComplexTest::normalized() { + Complex a(-3.0f, 4.0f); + Complex b(-0.6f, 0.8f); + + CORRADE_COMPARE(a.normalized(), b); + CORRADE_COMPARE(a.normalized().length(), 1.0f); +} + +void ComplexTest::conjugated() { + CORRADE_COMPARE(Complex(-3.0f, 4.5f).conjugated(), Complex(-3.0f, -4.5f)); +} + +void ComplexTest::inverted() { + Complex a(-3.0f, 4.0f); + Complex b(-0.12f, -0.16f); + + Complex inverted = a.inverted(); + CORRADE_COMPARE(a*inverted, Complex()); + CORRADE_COMPARE(inverted*a, Complex()); + CORRADE_COMPARE(inverted, b); +} + +void ComplexTest::invertedNormalized() { + std::ostringstream o; + Error::setOutput(&o); + + Complex a(-0.6f, 0.8f); + Complex b(-0.6f, -0.8f); + + Complex notInverted = (a*2).invertedNormalized(); + CORRADE_VERIFY(notInverted != notInverted); + CORRADE_COMPARE(o.str(), "Math::Complex::invertedNormalized(): complex number must be normalized\n"); + + Complex inverted = a.invertedNormalized(); + CORRADE_COMPARE(a*inverted, Complex()); + CORRADE_COMPARE(inverted*a, Complex()); + CORRADE_COMPARE(inverted, b); +} + +void ComplexTest::angle() { + std::ostringstream o; + Error::setOutput(&o); + auto angle = Complex::angle(Complex(1.5f, -2.0f).normalized(), {-4.0f, 3.5f}); + CORRADE_VERIFY(angle != angle); + CORRADE_COMPARE(o.str(), "Math::Complex::angle(): complex numbers must be normalized\n"); + + o.str({}); + angle = Complex::angle({1.5f, -2.0f}, Complex(-4.0f, 3.5f).normalized()); + CORRADE_VERIFY(angle != angle); + CORRADE_COMPARE(o.str(), "Math::Complex::angle(): complex numbers must be normalized\n"); + + /* Verify also that the angle is the same as angle between 2D vectors */ + angle = Complex::angle(Complex( 1.5f, -2.0f).normalized(), + Complex(-4.0f, 3.5f).normalized()); + CORRADE_COMPARE(angle, Vector2::angle(Vector2( 1.5f, -2.0f).normalized(), + Vector2(-4.0f, 3.5f).normalized())); + CORRADE_COMPARE(angle, Rad(2.933128f)); +} + +void ComplexTest::rotation() { + Complex a = Complex::rotation(Deg(120.0f)); + CORRADE_COMPARE(a.length(), 1.0f); + CORRADE_COMPARE(a, Complex(-0.5f, 0.8660254f)); + CORRADE_COMPARE_AS(a.angle(), Deg(120.0f), Rad); + + /* Verify negative angle */ + Complex b = Complex::rotation(Deg(-240.0f)); + CORRADE_COMPARE(b, Complex(-0.5f, 0.8660254f)); + CORRADE_COMPARE_AS(b.angle(), Deg(120.0f), Rad); + + /* Default-constructed complex number has zero angle */ + CORRADE_COMPARE_AS(Complex().angle(), Deg(0.0f), Rad); +} + +void ComplexTest::matrix() { + Complex a = Complex::rotation(Deg(37.0f)); + Matrix2 m = Matrix3::rotation(Deg(37.0f)).rotationScaling(); + + CORRADE_COMPARE(a.toMatrix(), m); + + std::ostringstream o; + Error::setOutput(&o); + Complex::fromMatrix(m*2); + CORRADE_COMPARE(o.str(), "Math::Complex::fromMatrix(): the matrix is not orthogonal\n"); + + Complex b = Complex::fromMatrix(m); + CORRADE_COMPARE(b, a); +} + +void ComplexTest::transformVector() { + Complex a = Complex::rotation(Deg(23.0f)); + Matrix3 m = Matrix3::rotation(Deg(23.0f)); + Vector2 v(-3.6f, 0.7f); + + Vector2 rotated = a.transformVector(v); + CORRADE_COMPARE(rotated, m.transformVector(v)); + CORRADE_COMPARE(rotated, Vector2(-3.58733f, -0.762279f)); +} + +void ComplexTest::debug() { + std::ostringstream o; + + Debug(&o) << Complex(2.5f, -7.5f); + CORRADE_COMPARE(o.str(), "Complex(2.5, -7.5)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::ComplexTest) diff --git a/src/Math/Test/ConstantsTest.cpp b/src/Math/Test/ConstantsTest.cpp index 4a780de5c..eef26316f 100644 --- a/src/Math/Test/ConstantsTest.cpp +++ b/src/Math/Test/ConstantsTest.cpp @@ -1,44 +1,57 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ConstantsTest.h" - -#include "Constants.h" -#include "Math.h" +#include -CORRADE_TEST_MAIN(Magnum::Math::Test::ConstantsTest) +#include "Math/Constants.h" +#include "Math/Functions.h" namespace Magnum { namespace Math { namespace Test { -ConstantsTest::ConstantsTest() { - addTests(&ConstantsTest::constants, - &ConstantsTest::degrad); -} +class ConstantsTest: public Corrade::TestSuite::Tester { + public: + ConstantsTest(); -void ConstantsTest::constants() { - CORRADE_COMPARE(Math::pow<2>(Constants::sqrt2()), 2.0f); - CORRADE_COMPARE(Math::pow<2>(Constants::sqrt3()), 3.0f); + void constants(); +}; - CORRADE_COMPARE(Math::pow<2>(Constants::sqrt2()), 2.0); - CORRADE_COMPARE(Math::pow<2>(Constants::sqrt3()), 3.0); +ConstantsTest::ConstantsTest() { + addTests({&ConstantsTest::constants}); } -void ConstantsTest::degrad() { - CORRADE_COMPARE(deg(90.0), Constants::pi()/2); - CORRADE_COMPARE(deg(90.0f), Constants::pi()/2); - CORRADE_COMPARE(rad(Constants::pi()/2), Constants::pi()/2); +void ConstantsTest::constants() { + constexpr Float a = Constants::sqrt2(); + constexpr Float b = Constants::sqrt3(); + CORRADE_COMPARE(Math::pow<2>(a), 2.0f); + CORRADE_COMPARE(Math::pow<2>(b), 3.0f); + + constexpr Double c = Constants::sqrt2(); + constexpr Double d = Constants::sqrt3(); + CORRADE_COMPARE(Math::pow<2>(c), 2.0); + CORRADE_COMPARE(Math::pow<2>(d), 3.0); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::ConstantsTest) diff --git a/src/Math/Test/ConstantsTest.h b/src/Math/Test/ConstantsTest.h deleted file mode 100644 index a52c49543..000000000 --- a/src/Math/Test/ConstantsTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Math_Test_ConstantsTest_h -#define Magnum_Math_Test_ConstantsTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class ConstantsTest: public Corrade::TestSuite::Tester { - public: - ConstantsTest(); - - void constants(); - void degrad(); -}; - -}}} - -#endif diff --git a/src/Math/Test/DualComplexTest.cpp b/src/Math/Test/DualComplexTest.cpp new file mode 100644 index 000000000..d0ddce9f5 --- /dev/null +++ b/src/Math/Test/DualComplexTest.cpp @@ -0,0 +1,272 @@ +/* + 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/DualComplex.h" +#include "Math/DualQuaternion.h" + +namespace Magnum { namespace Math { namespace Test { + +class DualComplexTest: public Corrade::TestSuite::Tester { + public: + explicit DualComplexTest(); + + void construct(); + void constructDefault(); + void constructFromVector(); + void constructCopy(); + + void isNormalized(); + + void multiply(); + + void lengthSquared(); + void length(); + void normalized(); + + void complexConjugated(); + void dualConjugated(); + void conjugated(); + void inverted(); + void invertedNormalized(); + + void rotation(); + void translation(); + void combinedTransformParts(); + void matrix(); + void transformPoint(); + + void debug(); +}; + +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Complex Complex; +typedef Math::Dual Dual; +typedef Math::DualComplex DualComplex; +typedef Math::Matrix3 Matrix3; +typedef Math::Vector2 Vector2; + +DualComplexTest::DualComplexTest() { + addTests({&DualComplexTest::construct, + &DualComplexTest::constructDefault, + &DualComplexTest::constructFromVector, + &DualComplexTest::constructCopy, + + &DualComplexTest::isNormalized, + + &DualComplexTest::multiply, + + &DualComplexTest::lengthSquared, + &DualComplexTest::length, + &DualComplexTest::normalized, + + &DualComplexTest::complexConjugated, + &DualComplexTest::dualConjugated, + &DualComplexTest::conjugated, + &DualComplexTest::inverted, + &DualComplexTest::invertedNormalized, + + &DualComplexTest::rotation, + &DualComplexTest::translation, + &DualComplexTest::combinedTransformParts, + &DualComplexTest::matrix, + &DualComplexTest::transformPoint, + + &DualComplexTest::debug}); +} + +void DualComplexTest::construct() { + constexpr DualComplex a({-1.0f, 2.5f}, {3.0f, -7.5f}); + CORRADE_COMPARE(a, DualComplex({-1.0f, 2.5f}, {3.0f, -7.5f})); + + constexpr Complex b = a.real(); + constexpr Complex c = a.dual(); + CORRADE_COMPARE(b, Complex(-1.0f, 2.5f)); + CORRADE_COMPARE(c, Complex(3.0f, -7.5f)); + + constexpr DualComplex d(Complex(-1.0f, 2.5f)); + CORRADE_COMPARE(d, DualComplex({-1.0f, 2.5f}, {0.0f, 0.0f})); +} + +void DualComplexTest::constructDefault() { + constexpr DualComplex a; + CORRADE_COMPARE(a, DualComplex({1.0f, 0.0f}, {0.0f, 0.0f})); + CORRADE_COMPARE(a.length(), 1.0f); +} + +void DualComplexTest::constructFromVector() { + constexpr DualComplex a(Vector2(1.5f, -3.0f)); + CORRADE_COMPARE(a, DualComplex({1.0f, 0.0f}, {1.5f, -3.0f})); +} + +void DualComplexTest::constructCopy() { + constexpr DualComplex a({-1.0f, 2.5f}, {3.0f, -7.5f}); + constexpr DualComplex b(a); + CORRADE_COMPARE(a, DualComplex({-1.0f, 2.5f}, {3.0f, -7.5f})); +} + +void DualComplexTest::isNormalized() { + CORRADE_VERIFY(!DualComplex({2.0f, 1.0f}, {}).isNormalized()); + CORRADE_VERIFY((DualComplex::rotation(Deg(23.0f))*DualComplex::translation({6.0f, 3.0f})).isNormalized()); +} + +void DualComplexTest::multiply() { + DualComplex a({-1.5f, 2.0f}, { 3.0f, -6.5f}); + DualComplex b({ 2.0f, -7.5f}, {-0.5f, 1.0f});; + CORRADE_COMPARE(a*b, DualComplex({12.0f, 15.25f}, {1.75f, -9.0f})); +} + +void DualComplexTest::lengthSquared() { + DualComplex a({-1.0f, 3.0f}, {0.5f, -2.0f}); + CORRADE_COMPARE(a.lengthSquared(), 10.0f); +} + +void DualComplexTest::length() { + DualComplex a({-1.0f, 3.0f}, {0.5f, -2.0f}); + CORRADE_COMPARE(a.length(), 3.162278f); +} + +void DualComplexTest::normalized() { + DualComplex a({-1.0f, 3.0f}, {0.5f, -2.0f}); + DualComplex b({-0.316228f, 0.948683f}, {0.5f, -2.0f}); + CORRADE_COMPARE(a.normalized().length(), 1.0f); + CORRADE_COMPARE(a.normalized(), b); +} + +void DualComplexTest::complexConjugated() { + DualComplex a({-1.0f, 2.5f}, {3.0f, -7.5f}); + DualComplex b({-1.0f, -2.5f}, {3.0f, 7.5f}); + CORRADE_COMPARE(a.complexConjugated(), b); +} + +void DualComplexTest::dualConjugated() { + DualComplex a({-1.0f, 2.5f}, { 3.0f, -7.5f}); + DualComplex b({-1.0f, 2.5f}, {-3.0f, 7.5f}); + CORRADE_COMPARE(a.dualConjugated(), b); +} + +void DualComplexTest::conjugated() { + DualComplex a({-1.0f, 2.5f}, { 3.0f, -7.5f}); + DualComplex b({-1.0f, -2.5f}, {-3.0f, -7.5f}); + CORRADE_COMPARE(a.conjugated(), b); +} + +void DualComplexTest::inverted() { + DualComplex a({-1.0f, 1.5f}, {3.0f, -7.5f}); + DualComplex b({-0.307692f, -0.461538f}, {4.384616f, -0.923077f}); + CORRADE_COMPARE(a*a.inverted(), DualComplex()); + CORRADE_COMPARE(a.inverted(), b); +} + +void DualComplexTest::invertedNormalized() { + DualComplex a({-0.316228f, 0.9486831f}, { 3.0f, -2.5f}); + DualComplex b({-0.316228f, -0.9486831f}, {3.320391f, 2.05548f}); + + std::ostringstream o; + Error::setOutput(&o); + DualComplex notInverted = DualComplex({-1.0f, -2.5f}, {}).invertedNormalized(); + CORRADE_VERIFY(notInverted != notInverted); + CORRADE_COMPARE(o.str(), "Math::Complex::invertedNormalized(): complex number must be normalized\n"); + + DualComplex inverted = a.invertedNormalized(); + CORRADE_COMPARE(a*inverted, DualComplex()); + CORRADE_COMPARE(inverted*a, DualComplex()); + CORRADE_COMPARE(inverted, b); +} + +void DualComplexTest::rotation() { + DualComplex a = DualComplex::rotation(Deg(120.0f)); + CORRADE_COMPARE(a.length(), 1.0f); + CORRADE_COMPARE(a, DualComplex({-0.5f, 0.8660254f}, {0.0f, 0.0f})); + CORRADE_COMPARE_AS(a.rotation().angle(), Deg(120.0f), Rad); + + /* Constexpr access to rotation */ + constexpr DualComplex b({-1.0f, 2.0f}, {}); + constexpr Complex c = b.rotation(); + CORRADE_COMPARE(c, Complex(-1.0f, 2.0f)); +} + +void DualComplexTest::translation() { + Vector2 vec(1.5f, -3.5f); + DualComplex a = DualComplex::translation(vec); + CORRADE_COMPARE(a.length(), 1.0f); + CORRADE_COMPARE(a, DualComplex({}, {1.5f, -3.5f})); + CORRADE_COMPARE(a.translation(), vec); +} + +void DualComplexTest::combinedTransformParts() { + Vector2 translation = Vector2(-1.5f, 2.75f); + DualComplex a = DualComplex::translation(translation)*DualComplex::rotation(Deg(23.0f)); + DualComplex b = DualComplex::rotation(Deg(23.0f))*DualComplex::translation(translation); + + CORRADE_COMPARE_AS(a.rotation().angle(), Deg(23.0f), Rad); + CORRADE_COMPARE_AS(b.rotation().angle(), Deg(23.0f), Rad); + CORRADE_COMPARE(a.translation(), translation); + CORRADE_COMPARE(b.translation(), Complex::rotation(Deg(23.0f)).transformVector(translation)); +} + +void DualComplexTest::matrix() { + DualComplex a = DualComplex::rotation(Deg(23.0f))*DualComplex::translation({2.0f, 3.0f}); + Matrix3 m = Matrix3::rotation(Deg(23.0f))*Matrix3::translation({2.0f, 3.0f}); + + CORRADE_COMPARE(a.toMatrix(), m); + + std::ostringstream o; + Error::setOutput(&o); + DualComplex::fromMatrix(m*2); + CORRADE_COMPARE(o.str(), "Math::DualComplex::fromMatrix(): the matrix doesn't represent rigid transformation\n"); + + DualComplex b = DualComplex::fromMatrix(m); + CORRADE_COMPARE(b, a); +} + +void DualComplexTest::transformPoint() { + DualComplex a = DualComplex::translation({2.0f, 3.0f})*DualComplex::rotation(Deg(23.0f)); + DualComplex b = DualComplex::rotation(Deg(23.0f))*DualComplex::translation({2.0f, 3.0f}); + Matrix3 m = Matrix3::translation({2.0f, 3.0f})*Matrix3::rotation(Deg(23.0f)); + Matrix3 n = Matrix3::rotation(Deg(23.0f))*Matrix3::translation({2.0f, 3.0f}); + Vector2 v(-3.6f, 0.7f); + + Vector2 transformedA = a.transformPoint(v); + CORRADE_COMPARE(transformedA, m.transformPoint(v)); + CORRADE_COMPARE(transformedA, Vector2(-1.58733f, 2.237721f)); + + Vector2 transformedB = b.transformPoint(v); + CORRADE_COMPARE(transformedB, n.transformPoint(v)); + CORRADE_COMPARE(transformedB, Vector2(-2.918512f, 2.780698f)); +} + +void DualComplexTest::debug() { + std::ostringstream o; + + Debug(&o) << DualComplex({-1.0f, -2.5f}, {-3.0f, -7.5f}); + CORRADE_COMPARE(o.str(), "DualComplex({-1, -2.5}, {-3, -7.5})\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::DualComplexTest) diff --git a/src/Math/Test/DualQuaternionTest.cpp b/src/Math/Test/DualQuaternionTest.cpp new file mode 100644 index 000000000..d0dc65039 --- /dev/null +++ b/src/Math/Test/DualQuaternionTest.cpp @@ -0,0 +1,304 @@ +/* + 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/DualQuaternion.h" + +namespace Magnum { namespace Math { namespace Test { + +class DualQuaternionTest: public Corrade::TestSuite::Tester { + public: + explicit DualQuaternionTest(); + + void construct(); + void constructDefault(); + void constructFromVector(); + void constructCopy(); + + void isNormalized(); + + void lengthSquared(); + void length(); + void normalized(); + + void quaternionConjugated(); + void dualConjugated(); + void conjugated(); + void inverted(); + void invertedNormalized(); + + void rotation(); + void translation(); + void combinedTransformParts(); + void matrix(); + void transformPoint(); + void transformPointNormalized(); + + void debug(); +}; + +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Dual Dual; +typedef Math::Matrix4 Matrix4; +typedef Math::DualQuaternion DualQuaternion; +typedef Math::Quaternion Quaternion; +typedef Math::Vector3 Vector3; + +DualQuaternionTest::DualQuaternionTest() { + addTests({&DualQuaternionTest::construct, + &DualQuaternionTest::constructDefault, + &DualQuaternionTest::constructFromVector, + &DualQuaternionTest::constructCopy, + + &DualQuaternionTest::isNormalized, + + &DualQuaternionTest::lengthSquared, + &DualQuaternionTest::length, + &DualQuaternionTest::normalized, + + &DualQuaternionTest::quaternionConjugated, + &DualQuaternionTest::dualConjugated, + &DualQuaternionTest::conjugated, + &DualQuaternionTest::inverted, + &DualQuaternionTest::invertedNormalized, + + &DualQuaternionTest::rotation, + &DualQuaternionTest::translation, + &DualQuaternionTest::combinedTransformParts, + &DualQuaternionTest::matrix, + &DualQuaternionTest::transformPoint, + &DualQuaternionTest::transformPointNormalized, + + &DualQuaternionTest::debug}); +} + +void DualQuaternionTest::construct() { + constexpr DualQuaternion a({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.1f, 3.3f}, 2.0f}); + CORRADE_COMPARE(a, DualQuaternion({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.1f, 3.3f}, 2.0f})); + + constexpr Quaternion b = a.real(); + CORRADE_COMPARE(b, Quaternion({1.0f, 2.0f, 3.0f}, -4.0f)); + + constexpr Quaternion c = a.dual(); + CORRADE_COMPARE(c, Quaternion({0.5f, -3.1f, 3.3f}, 2.0f)); + + constexpr DualQuaternion d({{1.0f, 2.0f, 3.0f}, -4.0f}); + CORRADE_COMPARE(d, DualQuaternion({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.0f, 0.0f, 0.0f}, 0.0f})); +} + +void DualQuaternionTest::constructDefault() { + constexpr DualQuaternion a; + CORRADE_COMPARE(a, DualQuaternion({{0.0f, 0.0f, 0.0f}, 1.0f}, {{0.0f, 0.0f, 0.0f}, 0.0f})); + CORRADE_COMPARE(a.length(), 1.0f); +} + +void DualQuaternionTest::constructFromVector() { + constexpr DualQuaternion a(Vector3(1.0f, 2.0f, 3.0f)); + CORRADE_COMPARE(a, DualQuaternion({{0.0f, 0.0f, 0.0f}, 1.0f}, {{1.0f, 2.0f, 3.0f}, 0.0f})); +} + +void DualQuaternionTest::constructCopy() { + constexpr DualQuaternion a({{1.0f, 2.0f, -3.0f}, -3.5f}, {{4.5f, -7.0f, 2.0f}, 1.0f}); + constexpr DualQuaternion b(a); + CORRADE_COMPARE(a, DualQuaternion({{1.0f, 2.0f, -3.0f}, -3.5f}, {{4.5f, -7.0f, 2.0f}, 1.0f})); +} + +void DualQuaternionTest::isNormalized() { + CORRADE_VERIFY(!DualQuaternion({{1.0f, 2.0f, 3.0f}, 4.0f}, {}).isNormalized()); + CORRADE_VERIFY((DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({3.0f, 1.0f, -0.5f})).isNormalized()); +} + +void DualQuaternionTest::lengthSquared() { + DualQuaternion a({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.0f, 3.0f}, 2.0f}); + CORRADE_COMPARE(a.lengthSquared(), Dual(30.0f, -9.0f)); +} + +void DualQuaternionTest::length() { + DualQuaternion a({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.0f, 3.0f}, 2.0f}); + CORRADE_COMPARE(a.length(), Dual(5.477226f, -0.821584f)); +} + +void DualQuaternionTest::normalized() { + DualQuaternion a({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.0f, 3.0f}, 2.0f}); + DualQuaternion b({{0.182574f, 0.365148f, 0.547723f}, -0.730297f}, {{0.118673f, -0.49295f, 0.629881f}, 0.255604f}); + CORRADE_COMPARE(a.normalized().length(), 1.0f); + CORRADE_COMPARE(a.normalized(), b); +} + +void DualQuaternionTest::quaternionConjugated() { + DualQuaternion a({{ 1.0f, 2.0f, 3.0f}, -4.0f}, {{ 0.5f, -3.1f, 3.3f}, 2.0f}); + DualQuaternion b({{-1.0f, -2.0f, -3.0f}, -4.0f}, {{-0.5f, 3.1f, -3.3f}, 2.0f}); + + CORRADE_COMPARE(a.quaternionConjugated(), b); +} + +void DualQuaternionTest::dualConjugated() { + DualQuaternion a({{1.0f, 2.0f, 3.0f}, -4.0f}, {{ 0.5f, -3.1f, 3.3f}, 2.0f}); + DualQuaternion b({{1.0f, 2.0f, 3.0f}, -4.0f}, {{-0.5f, 3.1f, -3.3f}, -2.0f}); + + CORRADE_COMPARE(a.dualConjugated(), b); +} + +void DualQuaternionTest::conjugated() { + DualQuaternion a({{ 1.0f, 2.0f, 3.0f}, -4.0f}, {{ 0.5f, -3.1f, 3.3f}, 2.0f}); + DualQuaternion b({{-1.0f, -2.0f, -3.0f}, -4.0f}, {{ 0.5f, -3.1f, 3.3f}, -2.0f}); + + CORRADE_COMPARE(a.conjugated(), b); +} + +void DualQuaternionTest::inverted() { + DualQuaternion a({{ 1.0f, 2.0f, 3.0f}, -4.0f}, {{ 2.5f, -3.1f, 3.3f}, 2.0f}); + DualQuaternion b({{-1.0f, -2.0f, -3.0f}, -4.0f}, {{-2.5f, 3.1f, -3.3f}, 2.0f}); + + CORRADE_COMPARE(a*a.inverted(), DualQuaternion()); + CORRADE_COMPARE(a.inverted(), b/Dual(30.0f, -3.6f)); +} + +void DualQuaternionTest::invertedNormalized() { + DualQuaternion a({{ 1.0f, 2.0f, 3.0f}, -4.0f}, {{ 2.5f, -3.1f, 3.3f}, 2.0f}); + DualQuaternion b({{-1.0f, -2.0f, -3.0f}, -4.0f}, {{-2.5f, 3.1f, -3.3f}, 2.0f}); + + std::ostringstream o; + Error::setOutput(&o); + CORRADE_COMPARE(a.invertedNormalized(), DualQuaternion()); + CORRADE_COMPARE(o.str(), "Math::DualQuaternion::invertedNormalized(): dual quaternion must be normalized\n"); + + DualQuaternion normalized = a.normalized(); + DualQuaternion inverted = normalized.invertedNormalized(); + CORRADE_COMPARE(normalized*inverted, DualQuaternion()); + CORRADE_COMPARE(inverted*normalized, DualQuaternion()); + CORRADE_COMPARE(inverted, b/Math::sqrt(Dual(30.0f, -3.6f))); +} + +void DualQuaternionTest::rotation() { + std::ostringstream o; + Error::setOutput(&o); + + Vector3 axis(1.0f/Constants::sqrt3()); + + CORRADE_COMPARE(DualQuaternion::rotation(Deg(120.0f), axis*2.0f), DualQuaternion()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::rotation(): axis must be normalized\n"); + + DualQuaternion q = DualQuaternion::rotation(Deg(120.0f), axis); + CORRADE_COMPARE(q.length(), 1.0f); + CORRADE_COMPARE(q, DualQuaternion({Vector3(0.5f, 0.5f, 0.5f), 0.5f}, {{}, 0.0f})); + CORRADE_COMPARE_AS(q.rotation().angle(), Deg(120.0f), Deg); + CORRADE_COMPARE(q.rotation().axis(), axis); + + /* Constexpr access to rotation */ + constexpr DualQuaternion b({{-1.0f, 2.0f, 3.0f}, 4.0f}, {}); + constexpr Quaternion c = b.rotation(); + CORRADE_COMPARE(c, Quaternion({-1.0f, 2.0f, 3.0f}, 4.0f)); +} + +void DualQuaternionTest::translation() { + Vector3 vec(1.0f, -3.5f, 0.5f); + DualQuaternion q = DualQuaternion::translation(vec); + CORRADE_COMPARE(q.length(), 1.0f); + CORRADE_COMPARE(q, DualQuaternion({}, {{0.5f, -1.75f, 0.25f}, 0.0f})); + CORRADE_COMPARE(q.translation(), vec); +} + +void DualQuaternionTest::combinedTransformParts() { + Vector3 translation = Vector3(-1.0f, 2.0f, 3.0f); + DualQuaternion a = DualQuaternion::translation(translation)*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis()); + DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation(translation); + + CORRADE_COMPARE(a.rotation().axis(), Vector3::xAxis()); + CORRADE_COMPARE(b.rotation().axis(), Vector3::xAxis()); + CORRADE_COMPARE_AS(a.rotation().angle(), Deg(23.0f), Rad); + CORRADE_COMPARE_AS(b.rotation().angle(), Deg(23.0f), Rad); + + CORRADE_COMPARE(a.translation(), translation); + CORRADE_COMPARE(b.translation(), Quaternion::rotation(Deg(23.0f), Vector3::xAxis()).transformVector(translation)); +} + +void DualQuaternionTest::matrix() { + DualQuaternion q = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); + Matrix4 m = Matrix4::rotationX(Deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); + + /* Verify that negated dual quaternion gives the same transformation */ + CORRADE_COMPARE(q.toMatrix(), m); + CORRADE_COMPARE((-q).toMatrix(), m); + + std::ostringstream o; + Error::setOutput(&o); + DualQuaternion::fromMatrix(m*2); + CORRADE_COMPARE(o.str(), "Math::DualQuaternion::fromMatrix(): the matrix doesn't represent rigid transformation\n"); + + DualQuaternion p = DualQuaternion::fromMatrix(m); + CORRADE_COMPARE(p, q); +} + +void DualQuaternionTest::transformPoint() { + DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis()); + DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); + Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(Deg(23.0f)); + Matrix4 n = Matrix4::rotationX(Deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); + Vector3 v(0.0f, -3.6f, 0.7f); + + Vector3 transformedA = (a*Dual(2)).transformPoint(v); + CORRADE_COMPARE(transformedA, m.transformPoint(v)); + CORRADE_COMPARE(transformedA, Vector3(-1.0f, -1.58733f, 2.237721f)); + + Vector3 transformedB = (b*Dual(2)).transformPoint(v); + CORRADE_COMPARE(transformedB, n.transformPoint(v)); + CORRADE_COMPARE(transformedB, Vector3(-1.0f, -2.918512f, 2.780698f)); +} + +void DualQuaternionTest::transformPointNormalized() { + DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis()); + DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); + Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(Deg(23.0f)); + Matrix4 n = Matrix4::rotationX(Deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); + Vector3 v(0.0f, -3.6f, 0.7f); + + std::ostringstream o; + Corrade::Utility::Error::setOutput(&o); + Vector3 notTransformed = (a*Dual(2)).transformPointNormalized(v); + CORRADE_VERIFY(notTransformed != notTransformed); + CORRADE_COMPARE(o.str(), "Math::DualQuaternion::transformPointNormalized(): dual quaternion must be normalized\n"); + + Vector3 transformedA = a.transformPointNormalized(v); + CORRADE_COMPARE(transformedA, m.transformPoint(v)); + CORRADE_COMPARE(transformedA, Vector3(-1.0f, -1.58733f, 2.237721f)); + + Vector3 transformedB = b.transformPointNormalized(v); + CORRADE_COMPARE(transformedB, n.transformPoint(v)); + CORRADE_COMPARE(transformedB, Vector3(-1.0f, -2.918512f, 2.780698f)); +} + +void DualQuaternionTest::debug() { + std::ostringstream o; + + Debug(&o) << DualQuaternion({{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.1f, 3.3f}, 2.0f}); + CORRADE_COMPARE(o.str(), "DualQuaternion({{1, 2, 3}, -4}, {{0.5, -3.1, 3.3}, 2})\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::DualQuaternionTest) diff --git a/src/Math/Test/DualTest.cpp b/src/Math/Test/DualTest.cpp new file mode 100644 index 000000000..1bf0c2da7 --- /dev/null +++ b/src/Math/Test/DualTest.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 +#include + +#include "Math/Dual.h" + +namespace Magnum { namespace Math { namespace Test { + +class DualTest: public Corrade::TestSuite::Tester { + public: + explicit DualTest(); + + void construct(); + void constructDefault(); + void constructCopy(); + + void compare(); + + void addSubtract(); + void negated(); + void multiplyDivide(); + + void conjugated(); + void sqrt(); + + void debug(); +}; + +typedef Math::Dual Dual; + +DualTest::DualTest() { + addTests({&DualTest::construct, + &DualTest::constructDefault, + &DualTest::constructCopy, + + &DualTest::compare, + + &DualTest::addSubtract, + &DualTest::negated, + &DualTest::multiplyDivide, + + &DualTest::conjugated, + &DualTest::sqrt, + + &DualTest::debug}); +} + +void DualTest::construct() { + constexpr Dual a(2.0f, -7.5f); + constexpr Float b = a.real(); + constexpr Float c = a.dual(); + CORRADE_COMPARE(b, 2.0f); + CORRADE_COMPARE(c, -7.5f); + + constexpr Dual d(3.0f); + CORRADE_COMPARE(d.real(), 3.0f); + CORRADE_COMPARE(d.dual(), 0.0f); +} + +void DualTest::constructDefault() { + constexpr Dual a; + CORRADE_COMPARE(a, Dual(0.0f, 0.0f)); +} + +void DualTest::constructCopy() { + constexpr Dual a(2.0f, 3.0f); + constexpr Dual b(a); + CORRADE_COMPARE(b, Dual(2.0f, 3.0f)); +} + +void DualTest::compare() { + CORRADE_VERIFY(Dual(1.0f, 1.0f+TypeTraits::epsilon()/2) == Dual(1.0f, 1.0f)); + CORRADE_VERIFY(Dual(1.0f, 1.0f+TypeTraits::epsilon()*2) != Dual(1.0f, 1.0f)); + CORRADE_VERIFY(Dual(1.0f+TypeTraits::epsilon()/2, 1.0f) == Dual(1.0f, 1.0f)); + CORRADE_VERIFY(Dual(1.0f+TypeTraits::epsilon()*2, 1.0f) != Dual(1.0f, 1.0f)); + + /* Compare to real part only */ + CORRADE_VERIFY(Dual(1.0f, 0.0f) == 1.0f); + CORRADE_VERIFY(Dual(1.0f, 3.0f) != 1.0f); +} + +void DualTest::addSubtract() { + Dual a(2.0f, -7.5f); + Dual b(-3.3f, 0.2f); + Dual c(-1.3f, -7.3f); + + CORRADE_COMPARE(a + b, c); + CORRADE_COMPARE(c - b, a); +} + +void DualTest::negated() { + CORRADE_COMPARE(-Dual(1.0f, -6.5f), Dual(-1.0f, 6.5f)); +} + +void DualTest::multiplyDivide() { + Dual a(1.5f, -4.0f); + Dual b(-2.0f, 0.5f); + Dual c(-3.0f, 8.75f); + + CORRADE_COMPARE(a*b, c); + CORRADE_COMPARE(c/b, a); +} + +void DualTest::conjugated() { + CORRADE_COMPARE(Dual(1.0f, -6.5f).conjugated(), Dual(1.0f, 6.5f)); +} + +void DualTest::sqrt() { + CORRADE_COMPARE(Math::sqrt(Dual(16.0f, 2.0f)), Dual(4.0f, 0.25f)); +} + +void DualTest::debug() { + std::ostringstream o; + + Debug(&o) << Dual(2.5f, -0.3f); + CORRADE_COMPARE(o.str(), "Dual(2.5, -0.3)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::DualTest) diff --git a/src/Math/Test/FunctionsTest.cpp b/src/Math/Test/FunctionsTest.cpp new file mode 100644 index 000000000..2d178c166 --- /dev/null +++ b/src/Math/Test/FunctionsTest.cpp @@ -0,0 +1,293 @@ +/* + 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/Functions.h" +#include "Math/Vector3.h" + +namespace Magnum { namespace Math { namespace Test { + +class FunctionsTest: public Corrade::TestSuite::Tester { + public: + FunctionsTest(); + + void min(); + void max(); + void abs(); + void sqrt(); + void clamp(); + void lerp(); + void normalizeUnsigned(); + void normalizeSigned(); + void denormalizeUnsigned(); + void denormalizeSigned(); + void renormalizeUnsinged(); + void renormalizeSinged(); + + void normalizeTypeDeduction(); + + void pow(); + void log(); + void log2(); + void trigonometric(); +}; + +typedef Math::Constants Constants; +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Vector3 Vector3; +typedef Math::Vector3 Vector3ub; +typedef Math::Vector3 Vector3b; +typedef Math::Vector3 Vector3i; + +FunctionsTest::FunctionsTest() { + addTests({&FunctionsTest::min, + &FunctionsTest::max, + &FunctionsTest::abs, + &FunctionsTest::sqrt, + &FunctionsTest::clamp, + &FunctionsTest::lerp, + &FunctionsTest::normalizeUnsigned, + &FunctionsTest::normalizeSigned, + &FunctionsTest::denormalizeUnsigned, + &FunctionsTest::denormalizeSigned, + &FunctionsTest::renormalizeUnsinged, + &FunctionsTest::renormalizeSinged, + + &FunctionsTest::normalizeTypeDeduction, + + &FunctionsTest::pow, + &FunctionsTest::log, + &FunctionsTest::log2, + &FunctionsTest::trigonometric}); +} + +void FunctionsTest::min() { + CORRADE_COMPARE(Math::min(5, 9), 5); + CORRADE_COMPARE(Math::min(Vector3i(5, -3, 2), Vector3i(9, -5, 18)), Vector3i(5, -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::abs() { + CORRADE_COMPARE(Math::abs(-5), 5); + CORRADE_COMPARE(Math::abs(5), 5); + CORRADE_COMPARE(Math::abs(Vector3i(5, -3, 2)), Vector3i(5, 3, 2)); +} + +void FunctionsTest::sqrt() { + CORRADE_COMPARE(Math::sqrt(16), 4); + CORRADE_COMPARE(Math::sqrt(Vector3i(256, 1, 0)), Vector3i(16, 1, 0)); +} + +void FunctionsTest::clamp() { + CORRADE_COMPARE(Math::clamp(0.5f, -1.0f, 5.0f), 0.5f); + CORRADE_COMPARE(Math::clamp(-1.6f, -1.0f, 5.0f), -1.0f); + CORRADE_COMPARE(Math::clamp(9.5f, -1.0f, 5.0f), 5.0f); + + CORRADE_COMPARE(Math::clamp(Vector3(0.5f, -1.6f, 9.5f), -1.0f, 5.0f), Vector3(0.5f, -1.0f, 5.0f)); +} + +void FunctionsTest::lerp() { + /* Floating-point / integral scalar */ + CORRADE_COMPARE(Math::lerp(2.0f, 5.0f, 0.5f), 3.5f); + CORRADE_COMPARE(Math::lerp(2, 5, 0.5f), 3); + + /* Floating-point vector */ + Vector3 a(-1.0f, 2.0f, 3.0f); + Vector3 b(3.0f, -2.0f, 11.0f); + CORRADE_COMPARE(Math::lerp(a, b, 0.25f), Vector3(0.0f, 1.0f, 5.0f)); + + /* Integer vector */ + typedef Math::Vector<3, Int> Vector3ub; + Vector3ub c(0, 128, 64); + Vector3ub d(16, 0, 32); + CORRADE_COMPARE(Math::lerp(c, d, 0.25f), Vector3ub(4, 96, 56)); +} + +void FunctionsTest::normalizeUnsigned() { + CORRADE_COMPARE((Math::normalize(0)), 0.0f); + CORRADE_COMPARE((Math::normalize(255)), 1.0f); + + CORRADE_COMPARE((Math::normalize(0)), 0.0); + CORRADE_COMPARE((Math::normalize(std::numeric_limits::max())), 1.0); + + CORRADE_COMPARE((Math::normalize(0)), 0.0); + CORRADE_COMPARE((Math::normalize(std::numeric_limits::max())), 1.0); + + CORRADE_COMPARE((Math::normalize(0)), 0.0f); + CORRADE_COMPARE((Math::normalize(std::numeric_limits::max())), 1.0f); + + CORRADE_COMPARE((Math::normalize(8192)), 0.125002f); + CORRADE_COMPARE((Math::normalize(49152)), 0.750011f); + + CORRADE_COMPARE(Math::normalize(Vector3ub(0, 127, 255)), Vector3(0.0f, 0.498039f, 1.0f)); +} + +void FunctionsTest::normalizeSigned() { + CORRADE_COMPARE((Math::normalize(127)), 1.0f); + CORRADE_COMPARE((Math::normalize(0)), 0.0f); + CORRADE_COMPARE((Math::normalize(-128)), -1.0f); + + CORRADE_COMPARE((Math::normalize(std::numeric_limits::min())), -1.0f); + CORRADE_COMPARE((Math::normalize(0)), 0.0f); + CORRADE_COMPARE((Math::normalize(std::numeric_limits::max())), 1.0f); + + CORRADE_COMPARE((Math::normalize(std::numeric_limits::min())), -1.0); + CORRADE_COMPARE((Math::normalize(0)), 0.0); + CORRADE_COMPARE((Math::normalize(std::numeric_limits::max())), 1.0); + + CORRADE_COMPARE((Math::normalize(std::numeric_limits::min())), -1.0); + CORRADE_COMPARE((Math::normalize(0)), 0.0); + CORRADE_COMPARE((Math::normalize(std::numeric_limits::max())), 1.0); + + CORRADE_COMPARE((Math::normalize(16384)), 0.500015f); + CORRADE_COMPARE((Math::normalize(-16384)), -0.500015f); + + CORRADE_COMPARE(Math::normalize(Vector3b(0, -127, 64)), Vector3(0.0f, -1.0f, 0.503937f)); +} + +void FunctionsTest::denormalizeUnsigned() { + CORRADE_COMPARE(Math::denormalize(0.0f), 0); + CORRADE_COMPARE(Math::denormalize(1.0f), 255); + + CORRADE_COMPARE(Math::denormalize(0.0f), 0); + CORRADE_COMPARE(Math::denormalize(1.0f), std::numeric_limits::max()); + + CORRADE_COMPARE(Math::denormalize(0.0), 0); + CORRADE_COMPARE(Math::denormalize(1.0), std::numeric_limits::max()); + + CORRADE_COMPARE(Math::denormalize(0.0), 0); + { + CORRADE_EXPECT_FAIL("Wrong result with GCC and non-optimized code."); + CORRADE_VERIFY(false); + //CORRADE_COMPARE(Math::denormalize(1.0), std::numeric_limits::max()); + } + + CORRADE_COMPARE(Math::denormalize(0.33f), 21626); + CORRADE_COMPARE(Math::denormalize(0.66f), 43253); + + CORRADE_COMPARE(Math::denormalize(Vector3(0.0f, 0.5f, 1.0f)), Vector3ub(0, 127, 255)); +} + +void FunctionsTest::denormalizeSigned() { + CORRADE_COMPARE(Math::denormalize(-1.0f), -127); + CORRADE_COMPARE(Math::denormalize(0.0f), 0); + CORRADE_COMPARE(Math::denormalize(1.0f), 127); + + CORRADE_COMPARE(Math::denormalize(-1.0f), std::numeric_limits::min()+1); + CORRADE_COMPARE(Math::denormalize(0.0f), 0); + CORRADE_COMPARE(Math::denormalize(1.0f), std::numeric_limits::max()); + + CORRADE_COMPARE(Math::denormalize(-1.0), std::numeric_limits::min()+1); + CORRADE_COMPARE(Math::denormalize(0.0), 0); + CORRADE_COMPARE(Math::denormalize(1.0), std::numeric_limits::max()); + + CORRADE_COMPARE(Math::denormalize(-1.0l), std::numeric_limits::min()+1); + CORRADE_COMPARE(Math::denormalize(0.0l), 0); + CORRADE_COMPARE(Math::denormalize(1.0l), std::numeric_limits::max()); + + CORRADE_COMPARE(Math::denormalize(-0.33f), -10813); + CORRADE_COMPARE(Math::denormalize(0.66f), 21626); + + CORRADE_COMPARE(Math::denormalize(Vector3(0.0f, -1.0f, 0.5f)), Vector3b(0, -127, 63)); +} + +void FunctionsTest::renormalizeUnsinged() { + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0f)), 0.0f); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0f)), 1.0f); + + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0f)), 0.0f); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0f)), 1.0f); + + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0)), 0.0); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0)), 1.0); + + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0l)), 0.0l); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0l)), 1.0l); +} + +void FunctionsTest::renormalizeSinged() { + CORRADE_COMPARE(Math::normalize(Math::denormalize(-1.0f)), -1.0f); + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0f)), 0.0f); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0f)), 1.0f); + + CORRADE_COMPARE(Math::normalize(Math::denormalize(-1.0f)), -1.0f); + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0f)), 0.0f); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0f)), 1.0f); + + CORRADE_COMPARE(Math::normalize(Math::denormalize(-1.0)), -1.0); + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0)), 0.0); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0)), 1.0); + + CORRADE_COMPARE(Math::normalize(Math::denormalize(-1.0l)), -1.0l); + CORRADE_COMPARE(Math::normalize(Math::denormalize(0.0l)), 0.0l); + CORRADE_COMPARE(Math::normalize(Math::denormalize(1.0l)), 1.0l); +} + +void FunctionsTest::normalizeTypeDeduction() { + CORRADE_COMPARE(Math::normalize('\x7F'), 1.0f); + CORRADE_COMPARE((Math::normalize('\x7F')), 1.0f); +} + +void FunctionsTest::pow() { + CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul); + CORRADE_COMPARE(Math::pow<0>(3ul), 1ul); + CORRADE_COMPARE(Math::pow<2>(2.0f), 4.0f); + + /* Constant expression */ + constexpr Int a = Math::pow<3>(5); + CORRADE_COMPARE(a, 125); +} + +void FunctionsTest::log() { + CORRADE_COMPARE(Math::log(2, 256), 8ul); + CORRADE_COMPARE(Math::log(256, 2), 0ul); +} + +void FunctionsTest::log2() { + CORRADE_COMPARE(Math::log2(2153), 11); +} + +void FunctionsTest::trigonometric() { + CORRADE_COMPARE(Math::sin(Deg(30.0f)), 0.5f); + CORRADE_COMPARE(Math::sin(Rad(Constants::pi()/6)), 0.5f); + CORRADE_COMPARE_AS(Math::asin(0.5f), Deg(30.0f), Deg); + + CORRADE_COMPARE(Math::cos(Deg(60.0f)), 0.5f); + CORRADE_COMPARE(Math::cos(Rad(Constants::pi()/3)), 0.5f); + CORRADE_COMPARE_AS(Math::acos(0.5f), Deg(60.0f), Deg); + + CORRADE_COMPARE(Math::tan(Deg(45.0f)), 1.0f); + CORRADE_COMPARE(Math::tan(Rad(Constants::pi()/4)), 1.0f); + CORRADE_COMPARE_AS(Math::atan(1.0f), Deg(45.0f), Deg); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::FunctionsTest) diff --git a/src/Math/Test/MathTest.cpp b/src/Math/Test/MathTest.cpp deleted file mode 100644 index 3aa7348ed..000000000 --- a/src/Math/Test/MathTest.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "MathTest.h" - -#include "Math.h" - -using namespace std; - -CORRADE_TEST_MAIN(Magnum::Math::Test::MathTest) - -namespace Magnum { namespace Math { namespace Test { - -MathTest::MathTest() { - addTests(&MathTest::normalize, - &MathTest::denormalize, - &MathTest::clamp, - &MathTest::pow, - &MathTest::log); -} - -void MathTest::normalize() { - /* Range for signed and unsigned */ - CORRADE_COMPARE((Math::normalize(-128)), 0.0f); - CORRADE_COMPARE((Math::normalize(127)), 1.0f); - CORRADE_COMPARE((Math::normalize(0)), 0.0f); - CORRADE_COMPARE((Math::normalize(255)), 1.0f); - - /* Between */ - CORRADE_COMPARE((Math::normalize(16384)), 0.750011f); - CORRADE_COMPARE((Math::normalize(-16384)), 0.250004f); - - /* Test overflow for large types */ - CORRADE_COMPARE((Math::normalize(numeric_limits::min())), 0.0f); - CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0f); - CORRADE_COMPARE((Math::normalize(0)), 0.0f); - CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0f); - - CORRADE_COMPARE((Math::normalize(numeric_limits::min())), 0.0); - CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0); - CORRADE_COMPARE((Math::normalize(0)), 0.0); - CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0); -} - -void MathTest::denormalize() { - /* Range for signed and unsigned */ - CORRADE_COMPARE(Math::denormalize(0.0f), -128); - CORRADE_COMPARE(Math::denormalize(1.0f), 127); - CORRADE_COMPARE(Math::denormalize(0.0f), 0); - CORRADE_COMPARE(Math::denormalize(1.0f), 255); - - /* Between */ - CORRADE_COMPARE(Math::denormalize(0.33f), -11141); - CORRADE_COMPARE(Math::denormalize(0.66f), 10485); - - /* Test overflow for large types */ - CORRADE_COMPARE(Math::denormalize(0.0f), numeric_limits::min()); - CORRADE_COMPARE(Math::denormalize(0.0f), 0); - CORRADE_COMPARE(Math::denormalize(0.0), numeric_limits::min()); - CORRADE_COMPARE(Math::denormalize(0.0), 0); - - CORRADE_COMPARE(Math::denormalize(1.0), numeric_limits::max()); - CORRADE_COMPARE(Math::denormalize(1.0), numeric_limits::max()); - -// { -// CORRADE_EXPECT_FAIL("Denormalize doesn't work for large types well"); -// CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); -// CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); -// } -} - -void MathTest::clamp() { - CORRADE_COMPARE(Math::clamp(0.5f, -1.0f, 5.0f), 0.5f); - CORRADE_COMPARE(Math::clamp(-1.6f, -1.0f, 5.0f), -1.0f); - CORRADE_COMPARE(Math::clamp(9.5f, -1.0f, 5.0f), 5.0f); -} - -void MathTest::pow() { - CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul); - CORRADE_COMPARE(Math::pow<0>(3ul), 1ul); - CORRADE_COMPARE(Math::pow<2>(2.0f), 4.0f); -} - -void MathTest::log() { - CORRADE_COMPARE(Math::log(2, 256), 8ul); - CORRADE_COMPARE(Math::log(256, 2), 0ul); -} - -}}} diff --git a/src/Math/Test/MathTest.h b/src/Math/Test/MathTest.h deleted file mode 100644 index 658d47690..000000000 --- a/src/Math/Test/MathTest.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef Magnum_Math_Test_MathTest_h -#define Magnum_Math_Test_MathTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class MathTest: public Corrade::TestSuite::Tester { - public: - MathTest(); - - void normalize(); - void denormalize(); - void clamp(); - void pow(); - void log(); -}; - -}}} - -#endif diff --git a/src/Math/Test/MathTypeTraitsTest.cpp b/src/Math/Test/MathTypeTraitsTest.cpp deleted file mode 100644 index cae312032..000000000 --- a/src/Math/Test/MathTypeTraitsTest.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "MathTypeTraitsTest.h" - -#include - -#include "MathTypeTraits.h" - -CORRADE_TEST_MAIN(Magnum::Math::Test::MathTypeTraitsTest) - -using namespace std; - -namespace Magnum { namespace Math { namespace Test { - -MathTypeTraitsTest::MathTypeTraitsTest() { - addTests(&MathTypeTraitsTest::equalsIntegral, - &MathTypeTraitsTest::equalsFloatingPoint); -} - -void MathTypeTraitsTest::equalsIntegral() { - _equalsIntegral(); - _equalsIntegral(); - _equalsIntegral(); - _equalsIntegral(); - _equalsIntegral(); - _equalsIntegral(); - _equalsIntegral(); - _equalsIntegral(); -} - -void MathTypeTraitsTest::equalsFloatingPoint() { - _equalsFloatingPoint(); - _equalsFloatingPoint(); -} - -template void MathTypeTraitsTest::_equalsIntegral() { - CORRADE_VERIFY(!MathTypeTraits::equals(1, 1+MathTypeTraits::epsilon())); -} - -template void MathTypeTraitsTest::_equalsFloatingPoint() { - CORRADE_VERIFY(MathTypeTraits::equals(T(1)+MathTypeTraits::epsilon()/T(2), T(1))); - CORRADE_VERIFY(!MathTypeTraits::equals(T(1)+MathTypeTraits::epsilon()*T(2), T(1))); - - { - CORRADE_EXPECT_FAIL("Comparing to infinity is broken"); - CORRADE_VERIFY(MathTypeTraits::equals(std::numeric_limits::infinity(), - std::numeric_limits::infinity())); - } - - CORRADE_VERIFY(!MathTypeTraits::equals(std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN())); -} - -}}} diff --git a/src/Math/Test/MathTypeTraitsTest.h b/src/Math/Test/MathTypeTraitsTest.h deleted file mode 100644 index 76a4f8882..000000000 --- a/src/Math/Test/MathTypeTraitsTest.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Magnum_Math_Test_MathTypeTraitsTest_h -#define Magnum_Math_Test_MathTypeTraitsTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class MathTypeTraitsTest: public Corrade::TestSuite::Tester { - public: - MathTypeTraitsTest(); - - void equalsFloatingPoint(); - void equalsIntegral(); - - private: - template void _equalsFloatingPoint(); - template void _equalsIntegral(); -}; - -}}} - -#endif diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index e25c020b0..eeaa8dd8b 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -1,146 +1,307 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Matrix3Test.h" - +#include +#include #include -#include "Constants.h" -#include "Matrix3.h" - -CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix3Test) - -using namespace std; -using namespace Corrade::Utility; +#include "Math/Matrix3.h" namespace Magnum { namespace Math { namespace Test { -typedef Math::Matrix3 Matrix3; -typedef Math::Matrix<2, float> Matrix2; -typedef Math::Vector2 Vector2; +class Matrix3Test: public Corrade::TestSuite::Tester { + public: + Matrix3Test(); + + void construct(); + void constructIdentity(); + void constructZero(); + void constructConversion(); + void constructCopy(); + + void isRigidTransformation(); + + void translation(); + void scaling(); + void rotation(); + void reflection(); + void projection(); + void fromParts(); + void rotationScalingPart(); + void rotationPart(); + void vectorParts(); + void invertedRigid(); + void transform(); + + void debug(); + void configuration(); +}; + +typedef Math::Deg Deg; +typedef Math::Matrix3 Matrix3; +typedef Math::Matrix3 Matrix3i; +typedef Math::Matrix<2, Float> Matrix2; +typedef Math::Vector2 Vector2; Matrix3Test::Matrix3Test() { - addTests(&Matrix3Test::constructIdentity, - &Matrix3Test::translation, - &Matrix3Test::scaling, - &Matrix3Test::rotation, - &Matrix3Test::rotationScalingPart, - &Matrix3Test::rotationPart, - &Matrix3Test::vectorParts, - &Matrix3Test::debug, - &Matrix3Test::configuration); + addTests({&Matrix3Test::construct, + &Matrix3Test::constructIdentity, + &Matrix3Test::constructZero, + &Matrix3Test::constructConversion, + &Matrix3Test::constructCopy, + + &Matrix3Test::isRigidTransformation, + + &Matrix3Test::translation, + &Matrix3Test::scaling, + &Matrix3Test::rotation, + &Matrix3Test::reflection, + &Matrix3Test::projection, + &Matrix3Test::fromParts, + &Matrix3Test::rotationScalingPart, + &Matrix3Test::rotationPart, + &Matrix3Test::vectorParts, + &Matrix3Test::invertedRigid, + &Matrix3Test::transform, + + &Matrix3Test::debug, + &Matrix3Test::configuration}); +} + +void Matrix3Test::construct() { + constexpr Matrix3 a({3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {7.9f, -1.0f, 8.0f}); + CORRADE_COMPARE(a, Matrix3({3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {7.9f, -1.0f, 8.0f})); } void Matrix3Test::constructIdentity() { - Matrix3 identity; - Matrix3 identity2(Matrix3::Identity); - Matrix3 identity3(Matrix3::Identity, 4.0f); - - Matrix3 identityExpected( - 1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f - ); - - Matrix3 identity3Expected( - 4.0f, 0.0f, 0.0f, - 0.0f, 4.0f, 0.0f, - 0.0f, 0.0f, 4.0f - ); + constexpr Matrix3 identity; + constexpr Matrix3 identity2(Matrix3::Identity); + constexpr Matrix3 identity3(Matrix3::Identity, 4.0f); + + Matrix3 identityExpected({1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}); + + Matrix3 identity3Expected({4.0f, 0.0f, 0.0f}, + {0.0f, 4.0f, 0.0f}, + {0.0f, 0.0f, 4.0f}); CORRADE_COMPARE(identity, identityExpected); CORRADE_COMPARE(identity2, identityExpected); CORRADE_COMPARE(identity3, identity3Expected); } -void Matrix3Test::translation() { - Matrix3 matrix( - 1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 3.0f, 1.0f, 1.0f - ); +void Matrix3Test::constructZero() { + constexpr Matrix3 a(Matrix3::Zero); + CORRADE_COMPARE(a, Matrix3({0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f})); +} - CORRADE_COMPARE(Matrix3::translation({3.0f, 1.0f}), matrix); +void Matrix3Test::constructConversion() { + constexpr Matrix3 a({3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {7.9f, -1.0f, 8.0f}); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Matrix3i b(a); + #else + Matrix3i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(b, Matrix3i({3, 5, 8}, + {4, 4, 7}, + {7, -1, 8})); } -void Matrix3Test::scaling() { - Matrix3 matrix( - 3.0f, 0.0f, 0.0f, - 0.0f, 1.5f, 0.0f, - 0.0f, 0.0f, 1.0f - ); +void Matrix3Test::constructCopy() { + constexpr Matrix3 a({3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {7.9f, -1.0f, 8.0f}); + constexpr Matrix3 b(a); + CORRADE_COMPARE(b, Matrix3({3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {7.9f, -1.0f, 8.0f})); +} + +void Matrix3Test::isRigidTransformation() { + CORRADE_VERIFY(!Matrix3({1.0f, 0.0f, 0.0f}, + {0.1f, 1.0f, 0.0f}, + {5.0f, 4.0f, 1.0f}).isRigidTransformation()); + CORRADE_VERIFY(!Matrix3({1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 1.0f}, + {5.0f, 4.0f, 0.0f}).isRigidTransformation()); + CORRADE_VERIFY(Matrix3({1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {5.0f, 4.0f, 1.0f}).isRigidTransformation()); +} - CORRADE_COMPARE(Matrix3::scaling({3.0f, 1.5f}), matrix); +void Matrix3Test::translation() { + constexpr Matrix3 a = Matrix3::translation({3.0f, 1.0f}); + CORRADE_COMPARE(a, Matrix3({1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {3.0f, 1.0f, 1.0f})); +} + +void Matrix3Test::scaling() { + constexpr Matrix3 a = Matrix3::scaling({3.0f, 1.5f}); + CORRADE_COMPARE(a, Matrix3({3.0f, 0.0f, 0.0f}, + {0.0f, 1.5f, 0.0f}, + {0.0f, 0.0f, 1.0f})); } void Matrix3Test::rotation() { - Matrix3 matrix( - 0.965926f, 0.258819f, 0.0f, - -0.258819f, 0.965926f, 0.0f, - 0.0f, 0.0f, 1.0f - ); + Matrix3 matrix({ 0.965926f, 0.258819f, 0.0f}, + {-0.258819f, 0.965926f, 0.0f}, + { 0.0f, 0.0f, 1.0f}); - CORRADE_COMPARE(Matrix3::rotation(deg(15.0f)), matrix); + CORRADE_COMPARE(Matrix3::rotation(Deg(15.0f)), matrix); } -void Matrix3Test::rotationScalingPart() { - Matrix3 m( - 3.0f, 5.0f, 8.0f, - 4.0f, 4.0f, 7.0f, - 7.0f, -1.0f, 8.0f - ); +void Matrix3Test::reflection() { + std::ostringstream o; + Error::setOutput(&o); + + Vector2 normal(-1.0f, 2.0f); + + CORRADE_COMPARE(Matrix3::reflection(normal), Matrix3()); + CORRADE_COMPARE(o.str(), "Math::Matrix3::reflection(): normal must be normalized\n"); - Matrix2 expected( - 3.0f, 5.0f, - 4.0f, 4.0f - ); + Matrix3 actual = Matrix3::reflection(normal.normalized()); + Matrix3 expected({0.6f, 0.8f, 0.0f}, + {0.8f, -0.6f, 0.0f}, + {0.0f, 0.0f, 1.0f}); - CORRADE_COMPARE(m.rotationScaling(), expected); + CORRADE_COMPARE(actual*actual, Matrix3()); + CORRADE_COMPARE(actual.transformVector(normal), -normal); + CORRADE_COMPARE(actual, expected); } -void Matrix3Test::rotationPart() { - Matrix2 expectedRotationPart( - 0.965926f, 0.258819f, - -0.258819f, 0.965926f - ); +void Matrix3Test::projection() { + Matrix3 expected({2.0f/4.0f, 0.0f, 0.0f}, + { 0.0f, 2.0f/3.0f, 0.0f}, + { 0.0f, 0.0f, 1.0f}); + + CORRADE_COMPARE(Matrix3::projection({4.0f, 3.0f}), expected); +} + +void Matrix3Test::fromParts() { + constexpr Matrix2 rotationScaling(Vector2(3.0f, 5.0f), + Vector2(4.0f, 4.0f)); + constexpr Vector2 translation(7.0f, -1.0f); + constexpr Matrix3 a = Matrix3::from(rotationScaling, translation); - Matrix3 rotation = Matrix3::rotation(deg(15.0f)); - CORRADE_COMPARE(rotation.rotation(), expectedRotationPart); + CORRADE_COMPARE(a, Matrix3({3.0f, 5.0f, 0.0f}, + {4.0f, 4.0f, 0.0f}, + {7.0f, -1.0f, 1.0f})); +} + +void Matrix3Test::rotationScalingPart() { + constexpr Matrix3 a({3.0f, 5.0f, 8.0f}, + {4.0f, 4.0f, 7.0f}, + {7.0f, -1.0f, 8.0f}); + constexpr Matrix2 b = a.rotationScaling(); - Matrix3 rotationTransformed = Matrix3::translation({2.0f, 5.0f})*rotation*Matrix3::scaling(Vector2(9.0f)); - CORRADE_COMPARE(rotationTransformed.rotation(), expectedRotationPart); + CORRADE_COMPARE(b, Matrix2(Vector2(3.0f, 5.0f), + Vector2(4.0f, 4.0f))); +} + +void Matrix3Test::rotationPart() { + Matrix3 rotation = Matrix3::rotation(Deg(15.0f)); + Matrix2 expectedRotationPart(Vector2( 0.965926f, 0.258819f), + Vector2(-0.258819f, 0.965926f)); + + /* For rotation and translation this is the same as rotationScaling() */ + Matrix3 rotationTranslation = rotation*Matrix3::translation({2.0f, 5.0f}); + Matrix2 rotationTranslationPart = rotationTranslation.rotation(); + CORRADE_COMPARE(rotationTranslationPart, rotationTranslation.rotationScaling()); + CORRADE_COMPARE(rotationTranslationPart, expectedRotationPart); + + /* Test uniform scaling */ + Matrix3 rotationScaling = rotation*Matrix3::scaling(Vector2(9.0f)); + Matrix2 rotationScalingPart = rotationScaling.rotation(); + CORRADE_COMPARE(rotationScalingPart.determinant(), 1.0f); + CORRADE_COMPARE(rotationScalingPart*rotationScalingPart.transposed(), Matrix2()); + CORRADE_COMPARE(rotationScalingPart, expectedRotationPart); + + /* Fails on non-uniform scaling */ + { + CORRADE_EXPECT_FAIL("Assertion on uniform scaling is not implemented yet."); + std::ostringstream o; + Error::setOutput(&o); + Matrix3 rotationScaling2 = rotation*Matrix3::scaling(Vector2::yScale(3.5f)); + CORRADE_COMPARE(o.str(), "Math::Matrix3::rotation(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(rotationScaling2, Matrix3(Matrix3::Zero)); + } } void Matrix3Test::vectorParts() { - Matrix3 m(15.0f, 0.0f, 0.0f, - 0.0f, -3.0f, 0.0f, - -5.0f, 12.0f, 1.0f); + constexpr Matrix3 a({15.0f, 0.0f, 0.0f}, + { 0.0f, -3.0f, 0.0f}, + {-5.0f, 12.0f, 1.0f}); + constexpr Vector2 right = a.right(); + constexpr Vector2 up = a.up(); + constexpr Vector2 translation = a.translation(); + + CORRADE_COMPARE(right, Vector2::xAxis(15.0f)); + CORRADE_COMPARE(up, Vector2::yAxis(-3.0f)); + CORRADE_COMPARE(translation, Vector2(-5.0f, 12.0f)); +} - CORRADE_COMPARE(m.right(), Vector2::xAxis(15.0f)); - CORRADE_COMPARE(m.up(), Vector2::yAxis(-3.0f)); - CORRADE_COMPARE(m.translation(), Vector2(-5.0f, 12.0f)); +void Matrix3Test::invertedRigid() { + Matrix3 actual = Matrix3::rotation(Deg(-74.0f))* + Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())* + Matrix3::translation({2.0f, -3.0f}); + Matrix3 expected = Matrix3::translation({-2.0f, 3.0f})* + Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())* + Matrix3::rotation(Deg(74.0f)); + + std::ostringstream o; + Error::setOutput(&o); + (2*actual).invertedRigid(); + CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation\n"); + + CORRADE_COMPARE(actual.invertedRigid(), expected); + CORRADE_COMPARE(actual.invertedRigid(), actual.inverted()); +} + +void Matrix3Test::transform() { + Matrix3 a = Matrix3::translation({1.0f, -5.0f})*Matrix3::rotation(Deg(90.0f)); + Vector2 v(1.0f, -2.0f); + + CORRADE_COMPARE(a.transformVector(v), Vector2(2.0f, 1.0f)); + CORRADE_COMPARE(a.transformPoint(v), Vector2(3.0f, -4.0f)); } void Matrix3Test::debug() { - Matrix3 m( - 3.0f, 5.0f, 8.0f, - 4.0f, 4.0f, 7.0f, - 7.0f, -1.0f, 8.0f - ); + Matrix3 m({3.0f, 5.0f, 8.0f}, + {4.0f, 4.0f, 7.0f}, + {7.0f, -1.0f, 8.0f}); - ostringstream o; + std::ostringstream o; Debug(&o) << m; CORRADE_COMPARE(o.str(), "Matrix(3, 4, 7,\n" " 5, 4, -1,\n" @@ -148,18 +309,18 @@ void Matrix3Test::debug() { } void Matrix3Test::configuration() { - Configuration c; + Corrade::Utility::Configuration c; - Matrix3 m( - 5.0f, 8.0f, 4.0f, - 4.0f, 7.0f, 3.125f, - 4.0f, 5.0f, 9.55f - ); - string value("5 4 4 8 7 5 4 3.125 9.55"); + Matrix3 m({5.0f, 8.0f, 4.0f}, + {4.0f, 7.0f, 3.125f}, + {4.0f, 5.0f, 9.55f}); + std::string value("5 4 4 8 7 5 4 3.125 9.55"); c.setValue("matrix", m); - CORRADE_COMPARE(c.value("matrix"), value); + CORRADE_COMPARE(c.value("matrix"), value); CORRADE_COMPARE(c.value("matrix"), m); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix3Test) diff --git a/src/Math/Test/Matrix3Test.h b/src/Math/Test/Matrix3Test.h deleted file mode 100644 index ede0d7fca..000000000 --- a/src/Math/Test/Matrix3Test.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef Magnum_Math_Test_Matrix3Test_h -#define Magnum_Math_Test_Matrix3Test_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Matrix3Test: public Corrade::TestSuite::Tester { - public: - Matrix3Test(); - - void constructIdentity(); - - void translation(); - void scaling(); - void rotation(); - void rotationScalingPart(); - void rotationPart(); - void vectorParts(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index 7ecac7095..771b5dba7 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -1,196 +1,392 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Matrix4Test.h" - +#include +#include #include -#include "Constants.h" -#include "Matrix4.h" - -CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix4Test) - -using namespace std; -using namespace Corrade::Utility; +#include "Math/Matrix4.h" namespace Magnum { namespace Math { namespace Test { -typedef Math::Matrix4 Matrix4; -typedef Math::Matrix<3, float> Matrix3; -typedef Math::Vector3 Vector3; +class Matrix4Test: public Corrade::TestSuite::Tester { + public: + Matrix4Test(); + + void construct(); + void constructIdentity(); + void constructZero(); + void constructConversion(); + void constructCopy(); + + void isRigidTransformation(); + + void translation(); + void scaling(); + void rotation(); + void rotationX(); + void rotationY(); + void rotationZ(); + void reflection(); + void orthographicProjection(); + void perspectiveProjection(); + void perspectiveProjectionFov(); + void fromParts(); + void rotationScalingPart(); + void rotationPart(); + void vectorParts(); + void invertedRigid(); + void transform(); + + void debug(); + void configuration(); +}; + +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Matrix4 Matrix4; +typedef Math::Matrix4 Matrix4i; +typedef Math::Matrix<3, Float> Matrix3; +typedef Math::Vector3 Vector3; Matrix4Test::Matrix4Test() { - addTests(&Matrix4Test::constructIdentity, - &Matrix4Test::translation, - &Matrix4Test::scaling, - &Matrix4Test::rotation, - &Matrix4Test::rotationX, - &Matrix4Test::rotationY, - &Matrix4Test::rotationZ, - &Matrix4Test::rotationScalingPart, - &Matrix4Test::rotationPart, - &Matrix4Test::vectorParts, - &Matrix4Test::debug, - &Matrix4Test::configuration); + addTests({&Matrix4Test::construct, + &Matrix4Test::constructIdentity, + &Matrix4Test::constructZero, + &Matrix4Test::constructConversion, + &Matrix4Test::constructCopy, + + &Matrix4Test::isRigidTransformation, + + &Matrix4Test::translation, + &Matrix4Test::scaling, + &Matrix4Test::rotation, + &Matrix4Test::rotationX, + &Matrix4Test::rotationY, + &Matrix4Test::rotationZ, + &Matrix4Test::reflection, + &Matrix4Test::orthographicProjection, + &Matrix4Test::perspectiveProjection, + &Matrix4Test::perspectiveProjectionFov, + &Matrix4Test::fromParts, + &Matrix4Test::rotationScalingPart, + &Matrix4Test::rotationPart, + &Matrix4Test::vectorParts, + &Matrix4Test::invertedRigid, + &Matrix4Test::transform, + + &Matrix4Test::debug, + &Matrix4Test::configuration}); +} + +void Matrix4Test::construct() { + constexpr Matrix4 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}); + CORRADE_COMPARE(a, Matrix4({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})); } void Matrix4Test::constructIdentity() { - Matrix4 identity; - Matrix4 identity2(Matrix4::Identity); - Matrix4 identity3(Matrix4::Identity, 4.0f); - - Matrix4 identityExpected( - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - - Matrix4 identity3Expected( - 4.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 4.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 4.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 4.0f - ); + constexpr Matrix4 identity; + constexpr Matrix4 identity2(Matrix4::Identity); + constexpr Matrix4 identity3(Matrix4::Identity, 4.0f); + + Matrix4 identityExpected({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); + + Matrix4 identity3Expected({4.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 4.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 4.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 4.0f}); CORRADE_COMPARE(identity, identityExpected); CORRADE_COMPARE(identity2, identityExpected); CORRADE_COMPARE(identity3, identity3Expected); } -void Matrix4Test::translation() { - Matrix4 matrix( - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 3.0f, 1.0f, 2.0f, 1.0f - ); +void Matrix4Test::constructZero() { + /* Zero constructor */ + constexpr Matrix4 a(Matrix4::Zero); + CORRADE_COMPARE(a, Matrix4({0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f})); +} - CORRADE_COMPARE(Matrix4::translation({3.0f, 1.0f, 2.0f}), matrix); +void Matrix4Test::constructConversion() { + constexpr Matrix4 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}); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Matrix4i b(a); + #else + Matrix4i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(b, Matrix4i({3, 5, 8, -3}, + {4, 4, 7, 2}, + {1, 2, 3, -1}, + {7, -1, 8, -1})); } -void Matrix4Test::scaling() { - Matrix4 matrix( - 3.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 2.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); +void Matrix4Test::constructCopy() { + constexpr Matrix4 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(a); + CORRADE_COMPARE(b, Matrix4({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})); +} + +void Matrix4Test::isRigidTransformation() { + CORRADE_VERIFY(!Matrix4({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.1f, 1.0f, 0.0f}, + {5.0f, 4.0f, 0.5f, 1.0f}).isRigidTransformation()); + CORRADE_VERIFY(!Matrix4({1.0f, 0.0f, 0.0f, 0.0f}, + {0.1f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 1.0f}, + {5.0f, 4.0f, 0.5f, 0.0f}).isRigidTransformation()); + CORRADE_VERIFY(Matrix4({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {5.0f, 4.0f, 0.5f, 1.0f}).isRigidTransformation()); +} - CORRADE_COMPARE(Matrix4::scaling({3.0f, 1.5f, 2.0f}), matrix); +void Matrix4Test::translation() { + constexpr Matrix4 a = Matrix4::translation({3.0f, 1.0f, 2.0f}); + CORRADE_COMPARE(a, Matrix4({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {3.0f, 1.0f, 2.0f, 1.0f})); +} + +void Matrix4Test::scaling() { + constexpr Matrix4 a = Matrix4::scaling({3.0f, 1.5f, 2.0f}); + CORRADE_COMPARE(a, Matrix4({3.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.5f, 0.0f, 0.0f}, + {0.0f, 0.0f, 2.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f})); } void Matrix4Test::rotation() { - ostringstream o; + std::ostringstream o; Error::setOutput(&o); - CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Matrix4()); + CORRADE_COMPARE(Matrix4::rotation(Deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Matrix4()); CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): axis must be normalized\n"); - Matrix4 matrix( - 0.35612214f, -0.80181062f, 0.47987163f, 0.0f, - 0.47987163f, 0.59757638f, 0.6423595f, 0.0f, - -0.80181062f, 0.0015183985f, 0.59757638f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()), matrix); + Matrix4 matrix({ 0.35612214f, -0.80181062f, 0.47987163f, 0.0f}, + { 0.47987163f, 0.59757638f, 0.6423595f, 0.0f}, + {-0.80181062f, 0.0015183985f, 0.59757638f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE(Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()), matrix); } void Matrix4Test::rotationX() { - Matrix4 matrix(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.90096887f, 0.43388374f, 0.0f, - 0.0f, -0.43388374f, 0.90096887f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants::pi()/7), Vector3::xAxis()), matrix); - CORRADE_COMPARE(Matrix4::rotationX(rad(Math::Constants::pi()/7)), matrix); + Matrix4 matrix({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.90096887f, 0.43388374f, 0.0f}, + {0.0f, -0.43388374f, 0.90096887f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE(Matrix4::rotation(Rad(Math::Constants::pi()/7), Vector3::xAxis()), matrix); + CORRADE_COMPARE(Matrix4::rotationX(Rad(Math::Constants::pi()/7)), matrix); } void Matrix4Test::rotationY() { - Matrix4 matrix(0.90096887f, 0.0f, -0.43388374f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.43388374f, 0.0f, 0.90096887f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants::pi()/7), Vector3::yAxis()), matrix); - CORRADE_COMPARE(Matrix4::rotationY(rad(Math::Constants::pi()/7)), matrix); + Matrix4 matrix({0.90096887f, 0.0f, -0.43388374f, 0.0f}, + { 0.0f, 1.0f, 0.0f, 0.0f}, + {0.43388374f, 0.0f, 0.90096887f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE(Matrix4::rotation(Rad(Math::Constants::pi()/7), Vector3::yAxis()), matrix); + CORRADE_COMPARE(Matrix4::rotationY(Rad(Math::Constants::pi()/7)), matrix); } void Matrix4Test::rotationZ() { - Matrix4 matrix( 0.90096887f, 0.43388374f, 0.0f, 0.0f, - -0.43388374f, 0.90096887f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants::pi()/7), Vector3::zAxis()), matrix); - CORRADE_COMPARE(Matrix4::rotationZ(rad(Math::Constants::pi()/7)), matrix); + Matrix4 matrix({ 0.90096887f, 0.43388374f, 0.0f, 0.0f}, + {-0.43388374f, 0.90096887f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 1.0f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE(Matrix4::rotation(Rad(Math::Constants::pi()/7), Vector3::zAxis()), matrix); + CORRADE_COMPARE(Matrix4::rotationZ(Rad(Math::Constants::pi()/7)), matrix); } -void Matrix4Test::rotationScalingPart() { - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f - ); +void Matrix4Test::reflection() { + std::ostringstream o; + Error::setOutput(&o); + + Vector3 normal(-1.0f, 2.0f, 2.0f); - Matrix3 expected( - 3.0f, 5.0f, 8.0f, - 4.0f, 4.0f, 7.0f, - 7.0f, -1.0f, 8.0f - ); + CORRADE_COMPARE(Matrix4::reflection(normal), Matrix4()); + CORRADE_COMPARE(o.str(), "Math::Matrix4::reflection(): normal must be normalized\n"); - CORRADE_COMPARE(m.rotationScaling(), expected); + Matrix4 actual = Matrix4::reflection(normal.normalized()); + Matrix4 expected({0.777778f, 0.444444f, 0.444444f, 0.0f}, + {0.444444f, 0.111111f, -0.888889f, 0.0f}, + {0.444444f, -0.888889f, 0.111111f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); + + CORRADE_COMPARE(actual*actual, Matrix4()); + CORRADE_COMPARE(actual.transformVector(normal), -normal); + CORRADE_COMPARE(actual, expected); } -void Matrix4Test::rotationPart() { - Matrix3 expectedRotationPart( - 0.35612214f, -0.80181062f, 0.47987163f, - 0.47987163f, 0.59757638f, 0.6423595f, - -0.80181062f, 0.0015183985f, 0.59757638f - ); +void Matrix4Test::orthographicProjection() { + Matrix4 expected({0.4f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.5f, 0.0f, 0.0f}, + {0.0f, 0.0f, -0.25f, 0.0f}, + {0.0f, 0.0f, -1.25f, 1.0f}); + CORRADE_COMPARE(Matrix4::orthographicProjection({5.0f, 4.0f}, 1, 9), expected); +} - Matrix4 rotation = Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()); - CORRADE_COMPARE(rotation.rotation().determinant(), 1.0f); - CORRADE_COMPARE(rotation.rotation()*rotation.rotation().transposed(), Matrix3()); - CORRADE_COMPARE(rotation.rotation(), expectedRotationPart); +void Matrix4Test::perspectiveProjection() { + Matrix4 expected({4.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 7.111111f, 0.0f, 0.0f}, + {0.0f, 0.0f, -1.9411764f, -1.0f}, + {0.0f, 0.0f, -94.1176452f, 0.0f}); + CORRADE_COMPARE(Matrix4::perspectiveProjection({16.0f, 9.0f}, 32.0f, 100), expected); +} + +void Matrix4Test::perspectiveProjectionFov() { + Matrix4 expected({4.1652994f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 9.788454f, 0.0f, 0.0f}, + { 0.0f, 0.0f, -1.9411764f, -1.0f}, + { 0.0f, 0.0f, -94.1176452f, 0.0f}); + CORRADE_COMPARE(Matrix4::perspectiveProjection(Deg(27.0f), 2.35f, 32.0f, 100), expected); +} + +void Matrix4Test::fromParts() { + constexpr Matrix3 rotationScaling(Vector3(3.0f, 5.0f, 8.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, 8.0f)); + constexpr Vector3 translation(9.0f, 4.0f, 5.0f); + constexpr Matrix4 a = Matrix4::from(rotationScaling, translation); + + CORRADE_COMPARE(a, Matrix4({3.0f, 5.0f, 8.0f, 0.0f}, + {4.0f, 4.0f, 7.0f, 0.0f}, + {7.0f, -1.0f, 8.0f, 0.0f}, + {9.0f, 4.0f, 5.0f, 1.0f})); +} + +void Matrix4Test::rotationScalingPart() { + constexpr Matrix4 a({3.0f, 5.0f, 8.0f, 4.0f}, + {4.0f, 4.0f, 7.0f, 3.0f}, + {7.0f, -1.0f, 8.0f, 0.0f}, + {9.0f, 4.0f, 5.0f, 9.0f}); + constexpr Matrix3 b = a.rotationScaling(); + + CORRADE_COMPARE(b, Matrix3(Vector3(3.0f, 5.0f, 8.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, 8.0f))); +} - Matrix4 rotationTransformed = Matrix4::translation({2.0f, 5.0f, -3.0f})*rotation*Matrix4::scaling(Vector3(9.0f)); - CORRADE_COMPARE(rotationTransformed.rotation().determinant(), 1.0f); - CORRADE_COMPARE(rotationTransformed.rotation()*rotationTransformed.rotation().transposed(), Matrix3()); - CORRADE_COMPARE(rotationTransformed.rotation(), expectedRotationPart); +void Matrix4Test::rotationPart() { + Matrix4 rotation = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()); + Matrix3 expectedRotationPart(Vector3( 0.35612214f, -0.80181062f, 0.47987163f), + Vector3( 0.47987163f, 0.59757638f, 0.6423595f), + Vector3(-0.80181062f, 0.0015183985f, 0.59757638f)); + + /* For rotation and translation this is the same as rotationScaling() */ + Matrix4 rotationTranslation = rotation*Matrix4::translation({2.0f, 5.0f, -3.0f}); + Matrix3 rotationTranslationPart = rotationTranslation.rotation(); + CORRADE_COMPARE(rotationTranslationPart, rotationTranslation.rotationScaling()); + CORRADE_COMPARE(rotationTranslationPart, expectedRotationPart); + + /* Test uniform scaling */ + Matrix4 rotationScaling = rotation*Matrix4::scaling(Vector3(9.0f)); + Matrix3 rotationScalingPart = rotationScaling.rotation(); + CORRADE_COMPARE(rotationScalingPart.determinant(), 1.0f); + CORRADE_COMPARE(rotationScalingPart*rotationScalingPart.transposed(), Matrix3()); + CORRADE_COMPARE(rotationScalingPart, expectedRotationPart); + + /* Fails on non-uniform scaling */ + { + CORRADE_EXPECT_FAIL("Assertion on uniform scaling is not implemented yet."); + std::ostringstream o; + Error::setOutput(&o); + Matrix4 rotationScaling2 = rotation*Matrix4::scaling(Vector3::yScale(3.5f)); + CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(rotationScaling2, Matrix4(Matrix4::Zero)); + } } void Matrix4Test::vectorParts() { - Matrix4 m(-1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 12.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 35.0f, 0.0f, - -5.0f, 12.0f, 0.5f, 1.0f); + constexpr Matrix4 a({-1.0f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 12.0f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 35.0f, 0.0f}, + {-5.0f, 12.0f, 0.5f, 1.0f}); + constexpr Vector3 right = a.right(); + constexpr Vector3 up = a.up(); + constexpr Vector3 backward = a.backward(); + constexpr Vector3 translation = a.translation(); + + CORRADE_COMPARE(right, Vector3::xAxis(-1.0f)); + CORRADE_COMPARE(up, Vector3::yAxis(12.0f)); + CORRADE_COMPARE(backward, Vector3::zAxis(35.0f)); + CORRADE_COMPARE(translation, Vector3(-5.0f, 12.0f, 0.5f)); +} + +void Matrix4Test::invertedRigid() { + Matrix4 actual = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized())* + Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())* + Matrix4::translation({1.0f, 2.0f, -3.0f}); + Matrix4 expected = Matrix4::translation({-1.0f, -2.0f, 3.0f})* + Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())* + Matrix4::rotation(Deg(74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized()); - CORRADE_COMPARE(m.right(), Vector3::xAxis(-1.0f)); - CORRADE_COMPARE(m.up(), Vector3::yAxis(12.0f)); - CORRADE_COMPARE(m.backward(), Vector3::zAxis(35.0f)); - CORRADE_COMPARE(m.translation(), Vector3(-5.0f, 12.0f, 0.5f)); + std::ostringstream o; + Error::setOutput(&o); + (2*actual).invertedRigid(); + CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation\n"); + + CORRADE_COMPARE(actual.invertedRigid(), expected); + CORRADE_COMPARE(actual.invertedRigid(), actual.inverted()); +} + +void Matrix4Test::transform() { + Matrix4 a = Matrix4::translation({1.0f, -5.0f, 3.5f})*Matrix4::rotation(Deg(90.0f), Vector3::zAxis()); + Vector3 v(1.0f, -2.0f, 5.5f); + + CORRADE_COMPARE(a.transformVector(v), Vector3(2.0f, 1.0f, 5.5f)); + CORRADE_COMPARE(a.transformPoint(v), Vector3(3.0f, -4.0f, 9.0f)); } void Matrix4Test::debug() { - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f - ); - - ostringstream o; + Matrix4 m({3.0f, 5.0f, 8.0f, 4.0f}, + {4.0f, 4.0f, 7.0f, 3.0f}, + {7.0f, -1.0f, 8.0f, 0.0f}, + {9.0f, 4.0f, 5.0f, 9.0f}); + + std::ostringstream o; Debug(&o) << m; CORRADE_COMPARE(o.str(), "Matrix(3, 4, 7, 9,\n" " 5, 4, -1, 4,\n" @@ -199,19 +395,19 @@ void Matrix4Test::debug() { } void Matrix4Test::configuration() { - Configuration c; + Corrade::Utility::Configuration c; - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.125f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.55f - ); - string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55"); + Matrix4 m({3.0f, 5.0f, 8.0f, 4.0f}, + {4.0f, 4.0f, 7.0f, 3.125f}, + {7.0f, -1.0f, 8.0f, 0.0f}, + {9.0f, 4.0f, 5.0f, 9.55f}); + std::string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55"); c.setValue("matrix", m); - CORRADE_COMPARE(c.value("matrix"), value); + CORRADE_COMPARE(c.value("matrix"), value); CORRADE_COMPARE(c.value("matrix"), m); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix4Test) diff --git a/src/Math/Test/Matrix4Test.h b/src/Math/Test/Matrix4Test.h deleted file mode 100644 index 7c360f618..000000000 --- a/src/Math/Test/Matrix4Test.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef Magnum_Math_Test_Matrix4Test_h -#define Magnum_Math_Test_Matrix4Test_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Matrix4Test: public Corrade::TestSuite::Tester { - public: - Matrix4Test(); - - void constructIdentity(); - - void translation(); - void scaling(); - void rotation(); - void rotationX(); - void rotationY(); - void rotationZ(); - void rotationScalingPart(); - void rotationPart(); - void vectorParts(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index cc902f199..62973756f 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -1,63 +1,93 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "MatrixTest.h" - +#include +#include #include -#include "Matrix.h" +#include "Math/Matrix.h" -CORRADE_TEST_MAIN(Magnum::Math::Test::MatrixTest) +namespace Magnum { namespace Math { namespace Test { -using namespace std; -using namespace Corrade::Utility; +class MatrixTest: public Corrade::TestSuite::Tester { + public: + MatrixTest(); -namespace Magnum { namespace Math { namespace Test { + void construct(); + void constructIdentity(); + void constructZero(); + void constructConversion(); + void constructCopy(); + + void isOrthogonal(); + + void trace(); + void ij(); + void determinant(); + void inverted(); + void invertedOrthogonal(); -typedef Matrix<4, float> Matrix4; -typedef Matrix<3, float> Matrix3; -typedef Vector<4, float> Vector4; + void debug(); + void configuration(); +}; + +typedef Matrix<4, Float> Matrix4; +typedef Matrix<4, Int> Matrix4i; +typedef Matrix<3, Float> Matrix3; +typedef Vector<4, Float> Vector4; +typedef Vector<4, Int> Vector4i; +typedef Vector<3, Float> Vector3; +typedef Math::Constants Constants; MatrixTest::MatrixTest() { - addTests(&MatrixTest::construct, - &MatrixTest::constructIdentity, - &MatrixTest::constructZero, - &MatrixTest::trace, - &MatrixTest::ij, - &MatrixTest::determinant, - &MatrixTest::inverted, - &MatrixTest::debug, - &MatrixTest::configuration); + addTests({&MatrixTest::construct, + &MatrixTest::constructIdentity, + &MatrixTest::constructZero, + &MatrixTest::constructConversion, + &MatrixTest::constructCopy, + + &MatrixTest::isOrthogonal, + + &MatrixTest::trace, + &MatrixTest::ij, + &MatrixTest::determinant, + &MatrixTest::inverted, + &MatrixTest::invertedOrthogonal, + &MatrixTest::debug, + &MatrixTest::configuration}); } void MatrixTest::construct() { - float m[] = { - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f - }; - - Matrix4 expected( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f - ); - - CORRADE_COMPARE(Matrix4::from(m), expected); + /* Value constructor */ + constexpr Matrix4 a(Vector4(3.0f, 5.0f, 8.0f, -3.0f), + Vector4(4.5f, 4.0f, 7.0f, 2.0f), + Vector4(1.0f, 2.0f, 3.0f, -1.0f), + Vector4(7.9f, -1.0f, 8.0f, -1.5f)); + CORRADE_COMPARE(a, Matrix4(Vector4(3.0f, 5.0f, 8.0f, -3.0f), + Vector4(4.5f, 4.0f, 7.0f, 2.0f), + Vector4(1.0f, 2.0f, 3.0f, -1.0f), + Vector4(7.9f, -1.0f, 8.0f, -1.5f))); } void MatrixTest::constructIdentity() { @@ -65,19 +95,15 @@ void MatrixTest::constructIdentity() { Matrix4 identity2(Matrix4::Identity); Matrix4 identity3(Matrix4::Identity, 4.0f); - Matrix4 identityExpected( - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); + Matrix4 identityExpected(Vector4(1.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 1.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 1.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 1.0f)); - Matrix4 identity3Expected( - 4.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 4.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 4.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 4.0f - ); + Matrix4 identity3Expected(Vector4(4.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 4.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 4.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 4.0f)); CORRADE_COMPARE(identity, identityExpected); CORRADE_COMPARE(identity2, identityExpected); @@ -85,73 +111,100 @@ void MatrixTest::constructIdentity() { } void MatrixTest::constructZero() { - Matrix4 zero(Matrix4::Zero); + constexpr Matrix4 a(Matrix4::Zero); + CORRADE_COMPARE(a, Matrix4(Vector4(0.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 0.0f))); +} - Matrix4 zeroExpected( - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f - ); +void MatrixTest::constructConversion() { + constexpr Matrix4 a(Vector4(3.0f, 5.0f, 8.0f, -3.0f), + Vector4(4.5f, 4.0f, 7.0f, 2.0f), + Vector4(1.0f, 2.0f, 3.0f, -1.0f), + Vector4(7.9f, -1.0f, 8.0f, -1.5f)); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Matrix4i b(a); + #else + Matrix4i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(b, Matrix4i(Vector4i(3, 5, 8, -3), + Vector4i(4, 4, 7, 2), + Vector4i(1, 2, 3, -1), + Vector4i(7, -1, 8, -1))); +} + +void MatrixTest::constructCopy() { + constexpr Matrix4 a(Vector4(3.0f, 5.0f, 8.0f, -3.0f), + Vector4(4.5f, 4.0f, 7.0f, 2.0f), + Vector4(1.0f, 2.0f, 3.0f, -1.0f), + Vector4(7.9f, -1.0f, 8.0f, -1.5f)); + constexpr Matrix4 b(a); + CORRADE_COMPARE(b, Matrix4(Vector4(3.0f, 5.0f, 8.0f, -3.0f), + Vector4(4.5f, 4.0f, 7.0f, 2.0f), + Vector4(1.0f, 2.0f, 3.0f, -1.0f), + Vector4(7.9f, -1.0f, 8.0f, -1.5f))); +} - CORRADE_COMPARE(zero, zeroExpected); +void MatrixTest::isOrthogonal() { + CORRADE_VERIFY(!Matrix3(Vector3(1.0f, 0.0f, 0.0f), + Vector3(0.0f, 1.0f, 0.0f), + Vector3(0.0f, 0.1f, 1.0f)).isOrthogonal()); + CORRADE_VERIFY(!Matrix3(Vector3(1.0f, 0.0f, 0.0f), + Vector3(0.0f, 1.0f, 0.0f), + Vector3(0.0f, 1.0f, 0.0f)).isOrthogonal()); + CORRADE_VERIFY(Matrix3(Vector3(1.0f, 0.0f, 0.0f), + Vector3(0.0f, 1.0f, 0.0f), + Vector3(0.0f, 0.0f, 1.0f)).isOrthogonal()); } void MatrixTest::trace() { - Matrix<5, int32_t> m( - 1, 2, 3, 0, 0, - 2, 3, 2, 1, -2, - 1, 1, -20, 1, 0, - 2, 0, 0, 10, 2, - 3, 1, 0, 1, -2 + Matrix<5, Int> m( + Vector<5, Int>(1, 2, 3, 0, 0), + Vector<5, Int>(2, 3, 2, 1, -2), + Vector<5, Int>(1, 1, -20, 1, 0), + Vector<5, Int>(2, 0, 0, 10, 2), + Vector<5, Int>(3, 1, 0, 1, -2) ); CORRADE_COMPARE(m.trace(), -8); } void MatrixTest::ij() { - Matrix4 original( - 0.0f, 1.0f, 2.0f, 3.0f, - 4.0f, 5.0f, 6.0f, 7.0f, - 8.0f, 9.0f, 10.0f, 11.0f, - 12.0f, 13.0f, 14.0f, 15.0f - ); + Matrix4 original(Vector4( 0.0f, 1.0f, 2.0f, 3.0f), + Vector4( 4.0f, 5.0f, 6.0f, 7.0f), + Vector4( 8.0f, 9.0f, 10.0f, 11.0f), + Vector4(12.0f, 13.0f, 14.0f, 15.0f)); - Matrix3 skipped( - 0.0f, 1.0f, 3.0f, - 8.0f, 9.0f, 11.0f, - 12.0f, 13.0f, 15.0f - ); + Matrix3 skipped(Vector3( 0.0f, 1.0f, 3.0f), + Vector3( 8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); CORRADE_COMPARE(original.ij(1, 2), skipped); } void MatrixTest::determinant() { - Matrix<5, int32_t> m( - 1, 2, 2, 1, 0, - 2, 3, 2, 1, -2, - 1, 1, 1, 1, 0, - 2, 0, 0, 1, 2, - 3, 1, 0, 1, -2 + Matrix<5, Int> m( + Vector<5, Int>(1, 2, 2, 1, 0), + Vector<5, Int>(2, 3, 2, 1, -2), + Vector<5, Int>(1, 1, 1, 1, 0), + Vector<5, Int>(2, 0, 0, 1, 2), + Vector<5, Int>(3, 1, 0, 1, -2) ); CORRADE_COMPARE(m.determinant(), -2); } void MatrixTest::inverted() { - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f - ); + Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); - Matrix4 inverse( - -60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f, - -66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f, - 177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f, - 259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f - ); + Matrix4 inverse(Vector4(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f), + Vector4(-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f), + Vector4(177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f), + Vector4(259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f)); Matrix4 _inverse = m.inverted(); @@ -159,22 +212,34 @@ void MatrixTest::inverted() { CORRADE_COMPARE(_inverse*m, Matrix4()); } +void MatrixTest::invertedOrthogonal() { + std::ostringstream o; + Error::setOutput(&o); + + Matrix3 a(Vector3(Constants::sqrt3()/2.0f, 0.5f, 0.0f), + Vector3(-0.5f, Constants::sqrt3()/2.0f, 0.0f), + Vector3(0.0f, 0.0f, 1.0f)); + (a*2).invertedOrthogonal(); + CORRADE_COMPARE(o.str(), "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal\n"); + + CORRADE_COMPARE(a.invertedOrthogonal()*a, Matrix3()); + CORRADE_COMPARE(a.invertedOrthogonal(), a.inverted()); +} + void MatrixTest::debug() { - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.0f - ); + Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); - ostringstream o; + std::ostringstream o; Debug(&o) << m; CORRADE_COMPARE(o.str(), "Matrix(3, 4, 7, 9,\n" " 5, 4, -1, 4,\n" " 8, 7, 8, 5,\n" " 4, 3, 0, 9)\n"); - o.str(""); + o.str({}); Debug(&o) << "a" << Matrix4() << "b" << Matrix4(); CORRADE_COMPARE(o.str(), "a Matrix(1, 0, 0, 0,\n" " 0, 1, 0, 0,\n" @@ -186,19 +251,19 @@ void MatrixTest::debug() { } void MatrixTest::configuration() { - Configuration c; + Corrade::Utility::Configuration c; - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.125f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.55f - ); - string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55"); + Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.125f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.55f)); + std::string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55"); c.setValue("matrix", m); - CORRADE_COMPARE(c.value("matrix"), value); + CORRADE_COMPARE(c.value("matrix"), value); CORRADE_COMPARE(c.value("matrix"), m); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::MatrixTest) diff --git a/src/Math/Test/MatrixTest.h b/src/Math/Test/MatrixTest.h deleted file mode 100644 index ba1cb02ee..000000000 --- a/src/Math/Test/MatrixTest.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef Magnum_Math_Test_MatrixTest_h -#define Magnum_Math_Test_MatrixTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class MatrixTest: public Corrade::TestSuite::Tester { - public: - MatrixTest(); - - void construct(); - void constructIdentity(); - void constructZero(); - void trace(); - void ij(); - void determinant(); - void inverted(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/Point2DTest.cpp b/src/Math/Test/Point2DTest.cpp deleted file mode 100644 index 63a93c345..000000000 --- a/src/Math/Test/Point2DTest.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "Point2DTest.h" - -#include - -#include "Point2D.h" - -CORRADE_TEST_MAIN(Magnum::Math::Test::Point2DTest) - -using namespace std; -using namespace Corrade::Utility; - -namespace Magnum { namespace Math { namespace Test { - -typedef Math::Point2D Point2D; - -Point2DTest::Point2DTest() { - addTests(&Point2DTest::construct, - &Point2DTest::debug, - &Point2DTest::configuration); -} - -void Point2DTest::construct() { - CORRADE_COMPARE(Point2D(), (Vector<3, float>(0.0f, 0.0f, 1.0f))); - CORRADE_COMPARE(Point2D(1, 2), (Vector<3, float>(1.0f, 2.0f, 1.0f))); - CORRADE_COMPARE(Point2D(Vector<2, float>(1.0f, 2.0f), 3), (Vector<3, float>(1.0f, 2.0f, 3.0f))); -} - -void Point2DTest::debug() { - ostringstream o; - Debug(&o) << Point2D(0.5f, 15.0f, 1.0f); - CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1)\n"); -} - -void Point2DTest::configuration() { - Configuration c; - - Point2D vec(3.0f, 3.125f, 9.55f); - string value("3 3.125 9.55"); - - c.setValue("point", vec); - CORRADE_COMPARE(c.value("point"), value); - CORRADE_COMPARE(c.value("point"), vec); -} - -}}} diff --git a/src/Math/Test/Point2DTest.h b/src/Math/Test/Point2DTest.h deleted file mode 100644 index 39ec72d3b..000000000 --- a/src/Math/Test/Point2DTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_Math_Test_Point2DTest_h -#define Magnum_Math_Test_Point2DTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Point2DTest: public Corrade::TestSuite::Tester { - public: - Point2DTest(); - - void construct(); - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/Point3DTest.cpp b/src/Math/Test/Point3DTest.cpp deleted file mode 100644 index e4f24920f..000000000 --- a/src/Math/Test/Point3DTest.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "Point3DTest.h" - -#include - -#include "Point3D.h" - -CORRADE_TEST_MAIN(Magnum::Math::Test::Point3DTest) - -using namespace std; -using namespace Corrade::Utility; - -namespace Magnum { namespace Math { namespace Test { - -typedef Math::Point3D Point3D; - -Point3DTest::Point3DTest() { - addTests(&Point3DTest::construct, - &Point3DTest::debug, - &Point3DTest::configuration); -} - -void Point3DTest::construct() { - CORRADE_COMPARE(Point3D(), Point3D(0.0f, 0.0f, 0.0f, 1.0f)); - CORRADE_COMPARE(Point3D(1, 2, 3, 4), (Vector<4, float>(1.0f, 2.0f, 3.0f, 4.0f))); - CORRADE_COMPARE(Point3D(Vector<3, float>(1.0f, 2.0f, 3.0f), 4), (Vector<4, float>(1.0f, 2.0f, 3.0f, 4.0f))); -} - -void Point3DTest::debug() { - ostringstream o; - Debug(&o) << Point3D(0.5f, 15.0f, 1.0f, 1.0f); - CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n"); -} - -void Point3DTest::configuration() { - Configuration c; - - Point3D vec(3.0f, 3.125f, 9.0f, 9.55f); - string value("3 3.125 9 9.55"); - - c.setValue("point", vec); - CORRADE_COMPARE(c.value("point"), value); - CORRADE_COMPARE(c.value("point"), vec); -} - -}}} diff --git a/src/Math/Test/Point3DTest.h b/src/Math/Test/Point3DTest.h deleted file mode 100644 index 9560e01d5..000000000 --- a/src/Math/Test/Point3DTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_Math_Test_Point3DTest_h -#define Magnum_Math_Test_Point3DTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Point3DTest: public Corrade::TestSuite::Tester { - public: - Point3DTest(); - - void construct(); - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/QuaternionTest.cpp b/src/Math/Test/QuaternionTest.cpp new file mode 100644 index 000000000..7cd6fc1d1 --- /dev/null +++ b/src/Math/Test/QuaternionTest.cpp @@ -0,0 +1,384 @@ +/* + 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 "Math/Quaternion.h" + +namespace Magnum { namespace Math { namespace Test { + +class QuaternionTest: public Corrade::TestSuite::Tester { + public: + explicit QuaternionTest(); + + void construct(); + void constructDefault(); + void constructFromVector(); + void constructCopy(); + + void compare(); + void isNormalized(); + + void addSubtract(); + void negated(); + void multiplyDivideScalar(); + void multiply(); + + void dot(); + void dotSelf(); + void length(); + void normalized(); + + void conjugated(); + void inverted(); + void invertedNormalized(); + + void rotation(); + void angle(); + void matrix(); + void lerp(); + void slerp(); + void transformVector(); + void transformVectorNormalized(); + + void debug(); +}; + +typedef Math::Deg Deg; +typedef Math::Rad Rad; +typedef Math::Matrix<3, Float> Matrix3; +typedef Math::Matrix4 Matrix4; +typedef Math::Quaternion Quaternion; +typedef Math::Vector3 Vector3; +typedef Math::Vector4 Vector4; + +QuaternionTest::QuaternionTest() { + addTests({&QuaternionTest::construct, + &QuaternionTest::constructDefault, + &QuaternionTest::constructFromVector, + &QuaternionTest::constructCopy, + + &QuaternionTest::compare, + &QuaternionTest::isNormalized, + + &QuaternionTest::addSubtract, + &QuaternionTest::negated, + &QuaternionTest::multiplyDivideScalar, + &QuaternionTest::multiply, + + &QuaternionTest::dot, + &QuaternionTest::dotSelf, + &QuaternionTest::length, + &QuaternionTest::normalized, + + &QuaternionTest::conjugated, + &QuaternionTest::inverted, + &QuaternionTest::invertedNormalized, + + &QuaternionTest::rotation, + &QuaternionTest::angle, + &QuaternionTest::matrix, + &QuaternionTest::lerp, + &QuaternionTest::slerp, + &QuaternionTest::transformVector, + &QuaternionTest::transformVectorNormalized, + + &QuaternionTest::debug}); +} + +void QuaternionTest::construct() { + constexpr Quaternion a({1.0f, 2.0f, 3.0f}, -4.0f); + CORRADE_COMPARE(a, Quaternion({1.0f, 2.0f, 3.0f}, -4.0f)); + + constexpr Vector3 b = a.vector(); + constexpr Float c = a.scalar(); + CORRADE_COMPARE(b, Vector3(1.0f, 2.0f, 3.0f)); + CORRADE_COMPARE(c, -4.0f); +} + +void QuaternionTest::constructDefault() { + constexpr Quaternion a; + CORRADE_COMPARE(a, Quaternion({0.0f, 0.0f, 0.0f}, 1.0f)); + CORRADE_COMPARE(a.length(), 1.0f); +} + +void QuaternionTest::constructFromVector() { + constexpr Quaternion a(Vector3(1.0f, 2.0f, 3.0f)); + CORRADE_COMPARE(a, Quaternion({1.0f, 2.0f, 3.0f}, 0.0f)); +} + +void QuaternionTest::constructCopy() { + constexpr Quaternion a({1.0f, -3.0f, 7.0f}, 2.5f); + constexpr Quaternion b(a); + CORRADE_COMPARE(b, Quaternion({1.0f, -3.0f, 7.0f}, 2.5f)); +} + +void QuaternionTest::compare() { + CORRADE_VERIFY(Quaternion({1.0f+TypeTraits::epsilon()/2, 2.0f, 3.0f}, -4.0f) == Quaternion({1.0f, 2.0f, 3.0f}, -4.0f)); + CORRADE_VERIFY(Quaternion({1.0f+TypeTraits::epsilon()*2, 2.0f, 3.0f}, -4.0f) != Quaternion({1.0f, 2.0f, 3.0f}, -4.0f)); + CORRADE_VERIFY(Quaternion({4.0f, 2.0f, 3.0f}, -1.0f+TypeTraits::epsilon()/2) == Quaternion({4.0f, 2.0f, 3.0f}, -1.0f)); + CORRADE_VERIFY(Quaternion({4.0f, 2.0f, 3.0f}, -1.0f+TypeTraits::epsilon()*2) != Quaternion({4.0f, 2.0f, 3.0f}, -1.0f)); +} + +void QuaternionTest::isNormalized() { + CORRADE_VERIFY(!Quaternion({1.0f, 2.0f, 3.0f}, 4.0f).isNormalized()); + CORRADE_VERIFY(Quaternion::rotation(Deg(23.0f), Vector3::xAxis()).isNormalized()); +} + +void QuaternionTest::addSubtract() { + Quaternion a({ 1.0f, 3.0f, -2.0f}, -4.0f); + Quaternion b({-0.5f, 1.4f, 3.0f}, 12.0f); + Quaternion c({ 0.5f, 4.4f, 1.0f}, 8.0f); + + CORRADE_COMPARE(a + b, c); + CORRADE_COMPARE(c - b, a); +} + +void QuaternionTest::negated() { + CORRADE_COMPARE(-Quaternion({1.0f, 2.0f, -3.0f}, -4.0f), Quaternion({-1.0f, -2.0f, 3.0f}, 4.0f)); +} + +void QuaternionTest::multiplyDivideScalar() { + Quaternion a({ 1.0f, 3.0f, -2.0f}, -4.0f); + Quaternion b({-1.5f, -4.5f, 3.0f}, 6.0f); + + CORRADE_COMPARE(a*-1.5f, b); + CORRADE_COMPARE(-1.5f*a, b); + CORRADE_COMPARE(b/-1.5f, a); + + CORRADE_COMPARE(2.0f/a, Quaternion({2.0f, 0.666666f, -1.0f}, -0.5f)); +} + +void QuaternionTest::multiply() { + CORRADE_COMPARE(Quaternion({-6.0f, -9.0f, 15.0f}, 0.5f)*Quaternion({2.0f, 3.0f, -5.0f}, 2.0f), + Quaternion({-11.0f, -16.5f, 27.5f}, 115.0f)); +} + +void QuaternionTest::dot() { + Quaternion a({ 1.0f, 3.0f, -2.0f}, -4.0f); + Quaternion b({-0.5f, 1.5f, 3.0f}, 12.0f); + + CORRADE_COMPARE(Quaternion::dot(a, b), -50.0f); +} + +void QuaternionTest::dotSelf() { + CORRADE_COMPARE(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).dot(), 30.0f); +} + +void QuaternionTest::length() { + CORRADE_COMPARE(Quaternion({1.0f, 3.0f, -2.0f}, -4.0f).length(), std::sqrt(30.0f)); +} + +void QuaternionTest::normalized() { + Quaternion normalized = Quaternion({1.0f, 3.0f, -2.0f}, -4.0f).normalized(); + CORRADE_COMPARE(normalized.length(), 1.0f); + CORRADE_COMPARE(normalized, Quaternion({1.0f, 3.0f, -2.0f}, -4.0f)/std::sqrt(30.0f)); +} + +void QuaternionTest::conjugated() { + CORRADE_COMPARE(Quaternion({ 1.0f, 3.0f, -2.0f}, -4.0f).conjugated(), + Quaternion({-1.0f, -3.0f, 2.0f}, -4.0f)); +} + +void QuaternionTest::inverted() { + Quaternion a = Quaternion({1.0f, 3.0f, -2.0f}, -4.0f); + Quaternion inverted = a.inverted(); + + CORRADE_COMPARE(a*inverted, Quaternion()); + CORRADE_COMPARE(inverted*a, Quaternion()); + CORRADE_COMPARE(inverted, Quaternion({-1.0f, -3.0f, 2.0f}, -4.0f)/30.0f); +} + +void QuaternionTest::invertedNormalized() { + Quaternion a = Quaternion({1.0f, 3.0f, -2.0f}, -4.0f); + + std::ostringstream o; + Error::setOutput(&o); + Quaternion notInverted = a.invertedNormalized(); + CORRADE_COMPARE(notInverted.vector(), Vector3()); + CORRADE_COMPARE(notInverted.scalar(), std::numeric_limits::quiet_NaN()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::invertedNormalized(): quaternion must be normalized\n"); + + Quaternion aNormalized = a.normalized(); + Quaternion inverted = aNormalized.invertedNormalized(); + CORRADE_COMPARE(aNormalized*inverted, Quaternion()); + CORRADE_COMPARE(inverted*aNormalized, Quaternion()); + CORRADE_COMPARE(inverted, Quaternion({-1.0f, -3.0f, 2.0f}, -4.0f)/std::sqrt(30.0f)); +} + +void QuaternionTest::rotation() { + std::ostringstream o; + Error::setOutput(&o); + + Vector3 axis(1.0f/Constants::sqrt3()); + + CORRADE_COMPARE(Quaternion::rotation(Deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Quaternion()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::rotation(): axis must be normalized\n"); + + Quaternion q = Quaternion::rotation(Deg(120.0f), axis); + CORRADE_COMPARE(q.length(), 1.0f); + CORRADE_COMPARE(q, Quaternion(Vector3(0.5f, 0.5f, 0.5f), 0.5f)); + CORRADE_COMPARE_AS(q.angle(), Deg(120.0f), Deg); + CORRADE_COMPARE(q.axis(), axis); + CORRADE_COMPARE(q.axis().length(), 1.0f); + + /* Verify negative angle */ + Quaternion q2 = Quaternion::rotation(Deg(-120.0f), axis); + CORRADE_COMPARE(q2, Quaternion(Vector3(-0.5f, -0.5f, -0.5f), 0.5f)); + CORRADE_COMPARE_AS(q2.angle(), Deg(120.0f), Deg); + CORRADE_COMPARE(q2.axis(), -axis); + + /* Default-constructed quaternion has zero angle and NaN axis */ + CORRADE_COMPARE_AS(Quaternion().angle(), Deg(0.0f), Deg); + CORRADE_VERIFY(Quaternion().axis() != Quaternion().axis()); +} + +void QuaternionTest::angle() { + std::ostringstream o; + Error::setOutput(&o); + auto angle = Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), {{4.0f, -3.0f, 2.0f}, -1.0f}); + CORRADE_VERIFY(angle != angle); + CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n"); + + o.str({}); + angle = Quaternion::angle({{1.0f, 2.0f, -3.0f}, -4.0f}, Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()); + CORRADE_VERIFY(angle != angle); + CORRADE_COMPARE(o.str(), "Math::Quaternion::angle(): quaternions must be normalized\n"); + + /* Verify also that the angle is the same as angle between 4D vectors */ + angle = Quaternion::angle(Quaternion({1.0f, 2.0f, -3.0f}, -4.0f).normalized(), + Quaternion({4.0f, -3.0f, 2.0f}, -1.0f).normalized()); + CORRADE_COMPARE(angle, Vector4::angle(Vector4(1.0f, 2.0f, -3.0f, -4.0f).normalized(), + Vector4(4.0f, -3.0f, 2.0f, -1.0f).normalized())); + CORRADE_COMPARE(angle, Rad(1.704528f)); +} + +void QuaternionTest::matrix() { + Vector3 axis = Vector3(1.0f, -3.0f, 5.0f).normalized(); + + Quaternion q = Quaternion::rotation(Deg(37.0f), axis); + Matrix3 m = Matrix4::rotation(Deg(37.0f), axis).rotationScaling(); + + /* Verify that negated quaternion gives the same rotation */ + CORRADE_COMPARE(q.toMatrix(), m); + CORRADE_COMPARE((-q).toMatrix(), m); + + std::ostringstream o; + Error::setOutput(&o); + Quaternion::fromMatrix(m*2); + CORRADE_COMPARE(o.str(), "Math::Quaternion::fromMatrix(): the matrix is not orthogonal\n"); + + /* Trace > 0 */ + CORRADE_VERIFY(m.trace() > 0.0f); + CORRADE_COMPARE(Quaternion::fromMatrix(m), q); + + /* Trace < 0 */ + Matrix3 m2 = Matrix4::rotation(Deg(130.0f), axis).rotationScaling(); + Quaternion q2 = Quaternion::rotation(Deg(130.0f), axis); + CORRADE_VERIFY(m2.trace() < 0.0f); + CORRADE_COMPARE(Quaternion::fromMatrix(m2), q2); +} + +void QuaternionTest::lerp() { + Quaternion a = Quaternion::rotation(Deg(15.0f), Vector3(1.0f/Constants::sqrt3())); + Quaternion b = Quaternion::rotation(Deg(23.0f), Vector3::xAxis()); + + std::ostringstream o; + Corrade::Utility::Error::setOutput(&o); + + Quaternion notLerpA = Quaternion::lerp(a*3.0f, b, 0.35f); + CORRADE_COMPARE(notLerpA.vector(), Vector3()); + CORRADE_COMPARE(notLerpA.scalar(), std::numeric_limits::quiet_NaN()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::lerp(): quaternions must be normalized\n"); + + o.str({}); + Quaternion notLerpB = Quaternion::lerp(a, b*-3.0f, 0.35f); + CORRADE_COMPARE(notLerpB.vector(), Vector3()); + CORRADE_COMPARE(notLerpB.scalar(), std::numeric_limits::quiet_NaN()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::lerp(): quaternions must be normalized\n"); + + Quaternion lerp = Quaternion::lerp(a, b, 0.35f); + CORRADE_COMPARE(lerp, Quaternion({0.119127f, 0.049134f, 0.049134f}, 0.990445f)); +} + +void QuaternionTest::slerp() { + Quaternion a = Quaternion::rotation(Deg(15.0f), Vector3(1.0f/Constants::sqrt3())); + Quaternion b = Quaternion::rotation(Deg(23.0f), Vector3::xAxis()); + + std::ostringstream o; + Corrade::Utility::Error::setOutput(&o); + + Quaternion notSlerpA = Quaternion::slerp(a*3.0f, b, 0.35f); + CORRADE_COMPARE(notSlerpA.vector(), Vector3()); + CORRADE_COMPARE(notSlerpA.scalar(), std::numeric_limits::quiet_NaN()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::slerp(): quaternions must be normalized\n"); + + o.str({}); + Quaternion notSlerpB = Quaternion::slerp(a, b*-3.0f, 0.35f); + CORRADE_COMPARE(notSlerpB.vector(), Vector3()); + CORRADE_COMPARE(notSlerpB.scalar(), std::numeric_limits::quiet_NaN()); + CORRADE_COMPARE(o.str(), "Math::Quaternion::slerp(): quaternions must be normalized\n"); + + Quaternion slerp = Quaternion::slerp(a, b, 0.35f); + CORRADE_COMPARE(slerp, Quaternion({0.119165f, 0.0491109f, 0.0491109f}, 0.990442f)); +} + +void QuaternionTest::transformVector() { + Quaternion a = Quaternion::rotation(Deg(23.0f), Vector3::xAxis()); + Matrix4 m = Matrix4::rotationX(Deg(23.0f)); + Vector3 v(5.0f, -3.6f, 0.7f); + + Vector3 rotated = a.transformVector(v); + CORRADE_COMPARE(rotated, m.transformVector(v)); + CORRADE_COMPARE(rotated, Vector3(5.0f, -3.58733f, -0.762279f)); +} + +void QuaternionTest::transformVectorNormalized() { + Quaternion a = Quaternion::rotation(Deg(23.0f), Vector3::xAxis()); + Matrix4 m = Matrix4::rotationX(Deg(23.0f)); + Vector3 v(5.0f, -3.6f, 0.7f); + + std::ostringstream o; + Error::setOutput(&o); + Vector3 notRotated = (a*2).transformVectorNormalized(v); + CORRADE_VERIFY(notRotated != notRotated); + CORRADE_COMPARE(o.str(), "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized\n"); + + Vector3 rotated = a.transformVectorNormalized(v); + CORRADE_COMPARE(rotated, m.transformVector(v)); + CORRADE_COMPARE(rotated, a.transformVector(v)); +} + +void QuaternionTest::debug() { + std::ostringstream o; + + Debug(&o) << Quaternion({1.0f, 2.0f, 3.0f}, -4.0f); + CORRADE_COMPARE(o.str(), "Quaternion({1, 2, 3}, -4)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::QuaternionTest) diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 344e2fcd1..d311231c3 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -1,232 +1,400 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "RectangularMatrixTest.h" - +#include +#include #include -#include "RectangularMatrix.h" - -CORRADE_TEST_MAIN(Magnum::Math::Test::RectangularMatrixTest) - -using namespace std; -using namespace Corrade::Utility; +#include "Math/RectangularMatrix.h" namespace Magnum { namespace Math { namespace Test { -typedef RectangularMatrix<4, 3, float> Matrix4x3; -typedef RectangularMatrix<3, 4, float> Matrix3x4; -typedef RectangularMatrix<2, 2, float> Matrix2; -typedef RectangularMatrix<2, 2, int32_t> Matrix2i; -typedef Vector<4, float> Vector4; +class RectangularMatrixTest: public Corrade::TestSuite::Tester { + public: + RectangularMatrixTest(); + + void construct(); + void constructDefault(); + void constructConversion(); + void constructFromData(); + void constructFromDiagonal(); + void constructCopy(); + + void data(); + void row(); + + void compare(); + + void negative(); + void addSubtract(); + void multiplyDivide(); + void multiply(); + + void transposed(); + void diagonal(); + + void sum(); + void product(); + void min(); + void minAbs(); + void max(); + void maxAbs(); + + void debug(); + void configuration(); +}; + +typedef RectangularMatrix<4, 3, Float> Matrix4x3; +typedef RectangularMatrix<3, 4, Float> Matrix3x4; +typedef RectangularMatrix<2, 2, Float> Matrix2; +typedef RectangularMatrix<2, 2, Int> Matrix2i; +typedef Vector<4, Float> Vector4; +typedef Vector<3, Float> Vector3; +typedef Vector<2, Float> Vector2; +typedef Vector<2, Int> Vector2i; RectangularMatrixTest::RectangularMatrixTest() { - addTests(&RectangularMatrixTest::construct, - &RectangularMatrixTest::constructFromVectors, - &RectangularMatrixTest::constructFrom, - &RectangularMatrixTest::constructZero, - &RectangularMatrixTest::data, + addTests({&RectangularMatrixTest::construct, + &RectangularMatrixTest::constructDefault, + &RectangularMatrixTest::constructConversion, + &RectangularMatrixTest::constructFromData, + &RectangularMatrixTest::constructFromDiagonal, + &RectangularMatrixTest::constructCopy, + + &RectangularMatrixTest::data, + &RectangularMatrixTest::row, + + &RectangularMatrixTest::compare, + + &RectangularMatrixTest::negative, + &RectangularMatrixTest::addSubtract, + &RectangularMatrixTest::multiplyDivide, + &RectangularMatrixTest::multiply, + + &RectangularMatrixTest::transposed, + &RectangularMatrixTest::diagonal, + + &RectangularMatrixTest::sum, + &RectangularMatrixTest::product, + &RectangularMatrixTest::min, + &RectangularMatrixTest::minAbs, + &RectangularMatrixTest::max, + &RectangularMatrixTest::maxAbs, + + &RectangularMatrixTest::debug, + &RectangularMatrixTest::configuration}); +} - &RectangularMatrixTest::negative, - &RectangularMatrixTest::addSubtract, - &RectangularMatrixTest::multiplyDivide, - &RectangularMatrixTest::multiply, +void RectangularMatrixTest::construct() { + constexpr Matrix3x4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f)); + CORRADE_COMPARE(a, Matrix3x4(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f))); +} - &RectangularMatrixTest::transposed, +void RectangularMatrixTest::constructDefault() { + constexpr Matrix4x3 a; + CORRADE_COMPARE(a, Matrix4x3(Vector3(0.0f, 0.0f, 0.0f), + Vector3(0.0f, 0.0f, 0.0f), + Vector3(0.0f, 0.0f, 0.0f), + Vector3(0.0f, 0.0f, 0.0f))); +} - &RectangularMatrixTest::debug, - &RectangularMatrixTest::configuration); +void RectangularMatrixTest::constructConversion() { + constexpr Matrix2 a(Vector2( 1.3f, 2.7f), + Vector2(-15.0f, 7.0f)); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Matrix2i b(a); + #else + Matrix2i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + + CORRADE_COMPARE(b, Matrix2i(Vector2i( 1, 2), + Vector2i(-15, 7))); } -void RectangularMatrixTest::construct() { - float m[] = { +void RectangularMatrixTest::constructFromData() { + Float m[] = { 3.0f, 5.0f, 8.0f, 4.0f, 4.0f, 4.0f, 7.0f, 3.0f, 7.0f, -1.0f, 8.0f, 0.0f }; - Matrix3x4 expected( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f - ); + Matrix3x4 expected(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f)); CORRADE_COMPARE(Matrix3x4::from(m), expected); } -void RectangularMatrixTest::constructFromVectors() { - Matrix3x4 actual = Matrix3x4::from(Vector4(1.0f, 2.0f, 3.0f, 4.0f), - Vector4(5.0f, 6.0f, 7.0f, 8.0f), - Vector4(9.0f, 10.0f, 11.0f, 12.0f)); +void RectangularMatrixTest::constructFromDiagonal() { + Vector3 diagonal(-1.0f, 5.0f, 11.0f); - Matrix3x4 expected(1.0f, 2.0f, 3.0f, 4.0f, - 5.0f, 6.0f, 7.0f, 8.0f, - 9.0f, 10.0f, 11.0f, 12.0f); + Matrix3x4 expectedA(Vector4(-1.0f, 0.0f, 0.0f, 0.0f), + Vector4( 0.0f, 5.0f, 0.0f, 0.0f), + Vector4( 0.0f, 0.0f, 11.0f, 0.0f)); + CORRADE_COMPARE(Matrix3x4::fromDiagonal(diagonal), expectedA); - CORRADE_COMPARE(actual, expected); + Matrix4x3 expectedB(Vector3(-1.0f, 0.0f, 0.0f), + Vector3( 0.0f, 5.0f, 0.0f), + Vector3( 0.0f, 0.0f, 11.0f), + Vector3( 0.0f, 0.0f, 0.0f)); + CORRADE_COMPARE(Matrix4x3::fromDiagonal(diagonal), expectedB); } - -void RectangularMatrixTest::constructFrom() { - Matrix2 floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); - Matrix2 floatingPointRounded(1.0f, 2.0f, -15.0f, 7.0f); - Matrix2i integral(1, 2, -15, 7); - - CORRADE_COMPARE(Matrix2i::from(floatingPoint), integral); - CORRADE_COMPARE(Matrix2::from(integral), floatingPointRounded); -} - -void RectangularMatrixTest::constructZero() { - Matrix4x3 zero; - - Matrix4x3 zeroExpected( - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f - ); - - CORRADE_COMPARE(zero, zeroExpected); +void RectangularMatrixTest::constructCopy() { + constexpr Matrix3x4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f)); + constexpr Matrix3x4 b(a); + CORRADE_COMPARE(b, Matrix3x4(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f))); } void RectangularMatrixTest::data() { Matrix3x4 m; - Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); m[2] = vector; m[1][1] = 1.0f; + m[0][2] = 1.5f; - m(0, 2) = 1.5f; - - CORRADE_COMPARE(m(1, 1), 1.0f); + CORRADE_COMPARE(m[1][1], 1.0f); CORRADE_COMPARE(m[0][2], 1.5f); CORRADE_COMPARE(m[2], vector); - Matrix3x4 expected( - 0.0f, 0.0f, 1.5f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 4.0f, 5.0f, 6.0f, 7.0f - ); + CORRADE_COMPARE(m, Matrix3x4(Vector4(0.0f, 0.0f, 1.5f, 0.0f), + Vector4(0.0f, 1.0f, 0.0f, 0.0f), + Vector4(4.0f, 5.0f, 6.0f, 7.0f))); + + /* Pointer chasings, i.e. *(b.data()[1]), are not possible */ + constexpr Matrix3x4 a(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.5f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.7f, 8.0f, 0.0f)); + constexpr Vector4 b = a[2]; + constexpr Float c = a[1][2]; + constexpr Float d = *a.data(); + CORRADE_COMPARE(b, Vector4(7.0f, -1.7f, 8.0f, 0.0f)); + CORRADE_COMPARE(c, 7.0f); + CORRADE_COMPARE(d, 3.0f); +} + +void RectangularMatrixTest::row() { + const Matrix3x4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f)); - CORRADE_COMPARE(m, expected); + CORRADE_COMPARE(a.row(1), Vector3(2.0f, 6.0f, 10.0f)); +} + +void RectangularMatrixTest::compare() { + Matrix2 a(Vector2(1.0f, -3.0f), + Vector2(5.0f, -10.0f)); + Matrix2 b(Vector2(1.0f + TypeTraits::epsilon()/2, -3.0f), + Vector2(5.0f, -10.0f)); + Matrix2 c(Vector2(1.0f, -1.0f + TypeTraits::epsilon()*2), + Vector2(5.0f, -10.0f)); + CORRADE_VERIFY(a == b); + CORRADE_VERIFY(a != c); + + Matrix2i ai(Vector2i(1, -3), + Vector2i(5, -10)); + Matrix2i bi(Vector2i(1, -2), + Vector2i(5, -10)); + CORRADE_VERIFY(ai == ai); + CORRADE_VERIFY(ai != bi); } void RectangularMatrixTest::negative() { - CORRADE_COMPARE(-Matrix2(1.0f, -3.0f, 5.0f, -10.0f), Matrix2(-1.0f, 3.0f, -5.0f, 10.0f)); + Matrix2 matrix(Vector2(1.0f, -3.0f), + Vector2(5.0f, -10.0f)); + Matrix2 negated(Vector2(-1.0f, 3.0f), + Vector2(-5.0f, 10.0f)); + CORRADE_COMPARE(-matrix, negated); } void RectangularMatrixTest::addSubtract() { - Matrix4x3 a(0.0f, 1.0f, 3.0f, - 4.0f, 5.0f, 7.0f, - 8.0f, 9.0f, 11.0f, - 12.0f, 13.0f, 15.0f); - Matrix4x3 b(-4.0f, 0.5f, 9.0f, - -9.0f, 11.0f, 0.25f, - 0.0f, -8.0f, 19.0f, - -3.0f, -5.0f, 2.0f); - Matrix4x3 e(-4.0f, 1.5f, 12.0f, - -5.0f, 16.0f, 7.25f, - 8.0f, 1.0f, 30.0f, - 9.0f, 8.0f, 17.0f); - - CORRADE_COMPARE(a + b, e); - CORRADE_COMPARE(e - b, a); + Matrix4x3 a(Vector3(0.0f, 1.0f, 3.0f), + Vector3(4.0f, 5.0f, 7.0f), + Vector3(8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); + Matrix4x3 b(Vector3(-4.0f, 0.5f, 9.0f), + Vector3(-9.0f, 11.0f, 0.25f), + Vector3( 0.0f, -8.0f, 19.0f), + Vector3(-3.0f, -5.0f, 2.0f)); + Matrix4x3 c(Vector3(-4.0f, 1.5f, 12.0f), + Vector3(-5.0f, 16.0f, 7.25f), + Vector3( 8.0f, 1.0f, 30.0f), + Vector3( 9.0f, 8.0f, 17.0f)); + + CORRADE_COMPARE(a + b, c); + CORRADE_COMPARE(c - b, a); } void RectangularMatrixTest::multiplyDivide() { - Matrix2 vec(1.0f, 2.0f, 3.0f, 4.0f); - Matrix2 multiplied(-1.5f, -3.0f, -4.5f, -6.0f); + Matrix2 matrix(Vector2(1.0f, 2.0f), + Vector2(3.0f, 4.0f)); + Matrix2 multiplied(Vector2(-1.5f, -3.0f), + Vector2(-4.5f, -6.0f)); - CORRADE_COMPARE(vec*-1.5f, multiplied); - CORRADE_COMPARE(-1.5f*vec, multiplied); - CORRADE_COMPARE(multiplied/-1.5f, vec); + CORRADE_COMPARE(matrix*-1.5f, multiplied); + CORRADE_COMPARE(-1.5f*matrix, multiplied); + CORRADE_COMPARE(multiplied/-1.5f, matrix); - Math::RectangularMatrix<1, 1, int8_t> vecChar(32); - Math::RectangularMatrix<1, 1, int8_t> multipliedChar(-48); - CORRADE_COMPARE(vecChar*-1.5f, multipliedChar); - CORRADE_COMPARE(multipliedChar/-1.5f, vecChar); - CORRADE_COMPARE(-1.5f*vecChar, multipliedChar); + Math::RectangularMatrix<1, 1, Byte> matrixChar(32); + Math::RectangularMatrix<1, 1, Byte> multipliedChar(-48); + CORRADE_COMPARE(matrixChar*-1.5f, multipliedChar); + CORRADE_COMPARE(multipliedChar/-1.5f, matrixChar); + CORRADE_COMPARE(-1.5f*matrixChar, multipliedChar); /* Divide vector with number and inverse */ - Matrix2 divisor(1.0f, 2.0f, -4.0f, 8.0f); - Matrix2 result(1.0f, 0.5f, -0.25f, 0.125f); + Matrix2 divisor(Vector2( 1.0f, 2.0f), + Vector2(-4.0f, 8.0f)); + Matrix2 result(Vector2( 1.0f, 0.5f), + Vector2(-0.25f, 0.125f)); CORRADE_COMPARE(1.0f/divisor, result); - CORRADE_COMPARE(-1550.0f/multipliedChar, vecChar); + CORRADE_COMPARE(-1550.0f/multipliedChar, matrixChar); } void RectangularMatrixTest::multiply() { - RectangularMatrix<4, 6, int32_t> left( - -5, 27, 10, 33, 0, -15, - 7, 56, 66, 1, 0, -24, - 4, 41, 4, 0, 1, -4, - 9, -100, 19, -49, 1, 9 + RectangularMatrix<4, 6, Int> left( + Vector<6, Int>(-5, 27, 10, 33, 0, -15), + Vector<6, Int>( 7, 56, 66, 1, 0, -24), + Vector<6, Int>( 4, 41, 4, 0, 1, -4), + Vector<6, Int>( 9, -100, 19, -49, 1, 9) ); - RectangularMatrix<5, 4, int32_t> right( - 1, -7, 0, 158, - 2, 24, -3, 40, - 3, -15, -2, -50, - 4, 17, -1, -284, - 5, 30, 4, 18 + RectangularMatrix<5, 4, Int> right( + Vector<4, Int>(1, -7, 0, 158), + Vector<4, Int>(2, 24, -3, 40), + Vector<4, Int>(3, -15, -2, -50), + Vector<4, Int>(4, 17, -1, -284), + Vector<4, Int>(5, 30, 4, 18) ); - RectangularMatrix<5, 6, int32_t> expected( - 1368, -16165, 2550, -7716, 158, 1575, - 506, -2725, 2352, -1870, 37, -234, - -578, 4159, -1918, 2534, -52, -127, - -2461, 29419, -4238, 14065, -285, -3020, - 363, 179, 2388, -687, 22, -649 + RectangularMatrix<5, 6, Int> expected( + Vector<6, Int>( 1368, -16165, 2550, -7716, 158, 1575), + Vector<6, Int>( 506, -2725, 2352, -1870, 37, -234), + Vector<6, Int>( -578, 4159, -1918, 2534, -52, -127), + Vector<6, Int>(-2461, 29419, -4238, 14065, -285, -3020), + Vector<6, Int>( 363, 179, 2388, -687, 22, -649) ); CORRADE_COMPARE(left*right, expected); } void RectangularMatrixTest::transposed() { - Matrix4x3 original( - 0.0f, 1.0f, 3.0f, - 4.0f, 5.0f, 7.0f, - 8.0f, 9.0f, 11.0f, - 12.0f, 13.0f, 15.0f - ); + Matrix4x3 original(Vector3( 0.0f, 1.0f, 3.0f), + Vector3( 4.0f, 5.0f, 7.0f), + Vector3( 8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); - Matrix3x4 transposed( - 0.0f, 4.0f, 8.0f, 12.0f, - 1.0f, 5.0f, 9.0f, 13.0f, - 3.0f, 7.0f, 11.0f, 15.0f - ); + Matrix3x4 transposed(Vector4(0.0f, 4.0f, 8.0f, 12.0f), + Vector4(1.0f, 5.0f, 9.0f, 13.0f), + Vector4(3.0f, 7.0f, 11.0f, 15.0f)); CORRADE_COMPARE(original.transposed(), transposed); } +void RectangularMatrixTest::diagonal() { + Vector3 diagonal(-1.0f, 5.0f, 11.0f); + + Matrix4x3 a(Vector3(-1.0f, 1.0f, 3.0f), + Vector3( 4.0f, 5.0f, 7.0f), + Vector3( 8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); + CORRADE_COMPARE(a.diagonal(), diagonal); + + Matrix3x4 b(Vector4(-1.0f, 4.0f, 8.0f, 12.0f), + Vector4( 1.0f, 5.0f, 9.0f, 13.0f), + Vector4( 3.0f, 7.0f, 11.0f, 15.0f)); + CORRADE_COMPARE(b.diagonal(), diagonal); +} + +void RectangularMatrixTest::sum() { + Matrix2 matrix(Vector2(1.0f, 2.0f), + Vector2(3.0f, 4.0f)); + CORRADE_COMPARE(matrix.sum(), 10.0f); +} + +void RectangularMatrixTest::product() { + Matrix2 matrix(Vector2(1.0f, 2.0f), + Vector2(3.0f, 4.0f)); + CORRADE_COMPARE(matrix.product(), 24.0f); +} + +void RectangularMatrixTest::min() { + /* Check also that initial value isn't initialized to 0 */ + Matrix2 matrix(Vector2(-2.0f, 1.0f), + Vector2(3.0f, 4.0f)); + CORRADE_COMPARE(matrix.min(), -2.0f); +} + +void RectangularMatrixTest::minAbs() { + /* Check that initial value is absolute and also all others */ + Matrix2 a(Vector2(-2.0f, 1.0f), + Vector2(3.0f, 4.0f)); + Matrix2 b(Vector2(3.0f, 4.0f), + Vector2(-2.0f, 1.0f)); + CORRADE_COMPARE(a.minAbs(), 1.0f); + CORRADE_COMPARE(a.minAbs(), 1.0f); +} + +void RectangularMatrixTest::max() { + /* Check also that initial value isn't initialized to 0 */ + Matrix2 matrix(Vector2(-2.0f, -1.0f), + Vector2(-3.0f, -4.0f)); + CORRADE_COMPARE(matrix.max(), -1.0f); +} + +void RectangularMatrixTest::maxAbs() { + /* Check that initial value is absolute and also all others */ + Matrix2 a(Vector2(2.0f, 1.0f), + Vector2(3.0f, -4.0f)); + Matrix2 b(Vector2(3.0f, -4.0f), + Vector2(2.0f, 1.0f)); + CORRADE_COMPARE(a.maxAbs(), 4.0f); + CORRADE_COMPARE(b.maxAbs(), 4.0f); +} + void RectangularMatrixTest::debug() { - Matrix3x4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f - ); + Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f)); - ostringstream o; + std::ostringstream o; Debug(&o) << m; CORRADE_COMPARE(o.str(), "Matrix(3, 4, 7,\n" " 5, 4, -1,\n" " 8, 7, 8,\n" " 4, 3, 0)\n"); - o.str(""); - Debug(&o) << "a" << Matrix3x4() << "b" << RectangularMatrix<4, 3, int8_t>(); + o.str({}); + Debug(&o) << "a" << Matrix3x4() << "b" << RectangularMatrix<4, 3, Byte>(); CORRADE_COMPARE(o.str(), "a Matrix(0, 0, 0,\n" " 0, 0, 0,\n" " 0, 0, 0,\n" @@ -236,18 +404,18 @@ void RectangularMatrixTest::debug() { } void RectangularMatrixTest::configuration() { - Matrix3x4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.125f, - 7.0f, -1.0f, 8.0f, 9.55f - ); - string value("3 4 7 5 4 -1 8 7 8 4 3.125 9.55"); + Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.125f), + Vector4(7.0f, -1.0f, 8.0f, 9.55f)); + std::string value("3 4 7 5 4 -1 8 7 8 4 3.125 9.55"); - Configuration c; + Corrade::Utility::Configuration c; c.setValue("matrix", m); - CORRADE_COMPARE(c.value("matrix"), value); + CORRADE_COMPARE(c.value("matrix"), value); CORRADE_COMPARE(c.value("matrix"), m); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::RectangularMatrixTest) diff --git a/src/Math/Test/RectangularMatrixTest.h b/src/Math/Test/RectangularMatrixTest.h deleted file mode 100644 index 469762177..000000000 --- a/src/Math/Test/RectangularMatrixTest.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef Magnum_Math_Test_RectangularMatrixTest_h -#define Magnum_Math_Test_RectangularMatrixTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class RectangularMatrixTest: public Corrade::TestSuite::Tester { - public: - RectangularMatrixTest(); - - void construct(); - void constructFromVectors(); - void constructFrom(); - void constructZero(); - void data(); - - void negative(); - void addSubtract(); - void multiplyDivide(); - void multiply(); - - void transposed(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/SwizzleTest.cpp b/src/Math/Test/SwizzleTest.cpp new file mode 100644 index 000000000..cb7596beb --- /dev/null +++ b/src/Math/Test/SwizzleTest.cpp @@ -0,0 +1,77 @@ +/* + 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/Swizzle.h" + +namespace Magnum { namespace Math { namespace Test { + +class SwizzleTest: public Corrade::TestSuite::Tester { + public: + SwizzleTest(); + + void components(); + void constants(); + void sizes(); + void constExpressions(); +}; + +typedef Vector<4, Int> Vector4i; + +SwizzleTest::SwizzleTest() { + addTests({&SwizzleTest::components, + &SwizzleTest::constants, + &SwizzleTest::sizes, + &SwizzleTest::constExpressions}); +} + +void SwizzleTest::components() { + CORRADE_COMPARE((swizzle<'z', 'x', 'w', 'y'>(Vector4i(2, 4, 5, 7))), Vector4i(5, 2, 7, 4)); +} + +void SwizzleTest::constants() { + CORRADE_COMPARE((swizzle<'1', 'w', '0', 'y'>(Vector4i(2, 4, 5, 7))), Vector4i(1, 7, 0, 4)); +} + +void SwizzleTest::sizes() { + CORRADE_COMPARE((swizzle<'y', 'x', 'x'>(Math::Vector<2, Int>(1, 2))), + (Math::Vector<3, Int>(2, 1, 1))); + CORRADE_COMPARE(swizzle<'z'>(Vector4i(1, 2, 3, 4)), + (Math::Vector<1, Int>(3))); + CORRADE_COMPARE((swizzle<'z', 'x', 'w', 'y', 'z', 'y', 'x'>(Vector4i(1, 2, 3, 4))), + (Math::Vector<7, Int>(3, 1, 4, 2, 3, 2, 1))); +} + +void SwizzleTest::constExpressions() { + constexpr auto a = swizzle<'z', 'x', 'w', 'y'>(Vector4i(2, 4, 5, 7)); + CORRADE_COMPARE(a, Vector4i(5, 2, 7, 4)); + + constexpr auto b = swizzle<'1', 'w', '0', 'y'>(Vector4i(2, 4, 5, 7)); + CORRADE_COMPARE(b, Vector4i(1, 7, 0, 4)); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::SwizzleTest) diff --git a/src/Math/Test/TypeTraitsTest.cpp b/src/Math/Test/TypeTraitsTest.cpp new file mode 100644 index 000000000..63a6fbace --- /dev/null +++ b/src/Math/Test/TypeTraitsTest.cpp @@ -0,0 +1,85 @@ +/* + 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/TypeTraits.h" + +namespace Magnum { namespace Math { namespace Test { + +class TypeTraitsTest: public Corrade::TestSuite::Tester { + public: + TypeTraitsTest(); + + void equalsFloatingPoint(); + void equalsIntegral(); + + private: + template void _equalsFloatingPoint(); + template void _equalsIntegral(); +}; + +TypeTraitsTest::TypeTraitsTest() { + addTests({&TypeTraitsTest::equalsIntegral, + &TypeTraitsTest::equalsFloatingPoint}); +} + +void TypeTraitsTest::equalsIntegral() { + _equalsIntegral(); + _equalsIntegral(); + _equalsIntegral(); + _equalsIntegral(); + _equalsIntegral(); + _equalsIntegral(); + _equalsIntegral(); + _equalsIntegral(); +} + +void TypeTraitsTest::equalsFloatingPoint() { + _equalsFloatingPoint(); + _equalsFloatingPoint(); +} + +template void TypeTraitsTest::_equalsIntegral() { + CORRADE_VERIFY(!TypeTraits::equals(1, 1+TypeTraits::epsilon())); +} + +template void TypeTraitsTest::_equalsFloatingPoint() { + CORRADE_VERIFY(TypeTraits::equals(T(1)+TypeTraits::epsilon()/T(2), T(1))); + CORRADE_VERIFY(!TypeTraits::equals(T(1)+TypeTraits::epsilon()*T(2), T(1))); + + { + CORRADE_EXPECT_FAIL("Comparing to infinity is broken"); + CORRADE_VERIFY(TypeTraits::equals(std::numeric_limits::infinity(), + std::numeric_limits::infinity())); + } + + CORRADE_VERIFY(!TypeTraits::equals(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN())); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::TypeTraitsTest) diff --git a/src/Math/Test/UnitTest.cpp b/src/Math/Test/UnitTest.cpp new file mode 100644 index 000000000..d1d687a9a --- /dev/null +++ b/src/Math/Test/UnitTest.cpp @@ -0,0 +1,147 @@ +/* + 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/Unit.h" + +namespace Magnum { namespace Math { namespace Test { + +class UnitTest: public Corrade::TestSuite::Tester { + public: + explicit UnitTest(); + + void construct(); + void constructDefault(); + void constructConversion(); + void compare(); + + void negated(); + void addSubtract(); + void multiplyDivide(); +}; + +UnitTest::UnitTest() { + addTests({&UnitTest::construct, + &UnitTest::constructDefault, + &UnitTest::constructConversion, + &UnitTest::compare, + + &UnitTest::negated, + &UnitTest::addSubtract, + &UnitTest::multiplyDivide}); +} + +template struct Sec_; +typedef Unit Sec; +typedef Unit Secd; + +inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, Sec value) { + return debug << Float(value); +} + +void UnitTest::construct() { + constexpr Sec a(25.0f); + CORRADE_COMPARE(Float(a), 25.0f); +} + +void UnitTest::constructDefault() { + constexpr Sec b; + CORRADE_COMPARE(b, Sec(0.0f)); +} + +void UnitTest::constructConversion() { + constexpr Secd a(25.0); + constexpr Sec b(a); + CORRADE_COMPARE(b, Sec(25.0f)); +} + +void UnitTest::compare() { + CORRADE_VERIFY(Sec(25.0f + TypeTraits::epsilon()/2) == Sec(25.0f)); + CORRADE_VERIFY(Sec(25.0f + TypeTraits::epsilon()*2) != Sec(25.0f)); + + constexpr bool c = Sec(3.0f) < Sec(3.0f); + constexpr bool d = Sec(3.0f) <= Sec(3.0f); + constexpr bool e = Sec(3.0f) >= Sec(3.0f); + constexpr bool f = Sec(3.0f) > Sec(3.0f); + CORRADE_VERIFY(!c); + CORRADE_VERIFY(d); + CORRADE_VERIFY(e); + CORRADE_VERIFY(!f); + + constexpr bool h = Sec(2.0f) < Sec(3.0f); + constexpr bool i = Sec(2.0f) <= Sec(3.0f); + constexpr bool j = Sec(3.0f) >= Sec(2.0f); + constexpr bool k = Sec(3.0f) > Sec(2.0f); + CORRADE_VERIFY(h); + CORRADE_VERIFY(i); + CORRADE_VERIFY(j); + CORRADE_VERIFY(k); + + constexpr bool l = Sec(3.0f) < Sec(2.0f); + constexpr bool m = Sec(3.0f) <= Sec(2.0f); + constexpr bool n = Sec(2.0f) >= Sec(3.0f); + constexpr bool o = Sec(2.0f) > Sec(3.0f); + CORRADE_VERIFY(!l); + CORRADE_VERIFY(!m); + CORRADE_VERIFY(!n); + CORRADE_VERIFY(!o); +} + +void UnitTest::negated() { + constexpr Sec a(25.0f); + constexpr Sec b(-a); + CORRADE_COMPARE(b, Sec(-25.0f)); +} + +void UnitTest::addSubtract() { + constexpr Sec a(3.0f); + constexpr Sec b(-4.0f); + constexpr Sec c(-1.0f); + + constexpr Sec d = a + b; + constexpr Sec e = c - a; + CORRADE_COMPARE(d, c); + CORRADE_COMPARE(e, b); +} + +void UnitTest::multiplyDivide() { + constexpr Sec a(3.0f); + constexpr Sec b(-4.5f); + constexpr Sec c(5.0f); + + constexpr Sec d = a*-1.5f; + constexpr Sec e = -1.5f*a; + constexpr Sec f = b/-1.5f; + CORRADE_COMPARE(d, b); + CORRADE_COMPARE(e, b); + CORRADE_COMPARE(f, a); + + constexpr Float g = b/a; + CORRADE_COMPARE(g, -1.5f); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::UnitTest) diff --git a/src/Math/Test/Vector2Test.cpp b/src/Math/Test/Vector2Test.cpp index 297e0e67a..1a4183445 100644 --- a/src/Math/Test/Vector2Test.cpp +++ b/src/Math/Test/Vector2Test.cpp @@ -1,70 +1,181 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Vector2Test.h" - +#include +#include #include -#include "Vector2.h" +#include "Math/Vector2.h" -CORRADE_TEST_MAIN(Magnum::Math::Test::Vector2Test) +struct Vec2 { + float x, y; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct VectorConverter<2, float, Vec2> { + inline constexpr static Vector<2, float> from(const Vec2& other) { + return {other.x, other.y}; + } + + inline constexpr static Vec2 to(const Vector<2, float>& other) { + return {other[0], other[1]}; + } +}; -using namespace std; -using namespace Corrade::Utility; +} + +namespace Test { + +class Vector2Test: public Corrade::TestSuite::Tester { + public: + Vector2Test(); + + void construct(); + void constructDefault(); + void constructOneValue(); + void constructConversion(); + void constructCopy(); -namespace Magnum { namespace Math { namespace Test { + void convert(); -typedef Math::Vector2 Vector2; + void access(); + void axes(); + void scales(); + + void debug(); + void configuration(); +}; + +typedef Math::Vector2 Vector2; +typedef Math::Vector2 Vector2i; Vector2Test::Vector2Test() { - addTests(&Vector2Test::construct, - &Vector2Test::axes, - &Vector2Test::scales, - &Vector2Test::debug, - &Vector2Test::configuration); + addTests({&Vector2Test::construct, + &Vector2Test::constructDefault, + &Vector2Test::constructOneValue, + &Vector2Test::constructConversion, + &Vector2Test::constructCopy, + + &Vector2Test::convert, + + &Vector2Test::access, + &Vector2Test::axes, + &Vector2Test::scales, + + &Vector2Test::debug, + &Vector2Test::configuration}); } void Vector2Test::construct() { - CORRADE_COMPARE(Vector2(1, 2), (Vector<2, float>(1.0f, 2.0f))); + constexpr Vector2 a(1.5f, 2.5f); + CORRADE_COMPARE(a, (Vector<2, Float>(1.5f, 2.5f))); +} + +void Vector2Test::constructDefault() { + constexpr Vector2 a; + CORRADE_COMPARE(a, Vector2(0.0f, 0.0f)); +} + +void Vector2Test::constructOneValue() { + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector2 a(3.0f); + #else + Vector2 a(3.0f); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(a, Vector2(3.0f, 3.0f)); +} + +void Vector2Test::constructConversion() { + constexpr Vector2 a(1.5f, 2.5f); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector2i b(a); + #else + Vector2i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(b, Vector2i(1, 2)); +} + +void Vector2Test::constructCopy() { + constexpr Vector2 a(1.5f, 2.5f); + constexpr Vector2 b(a); + CORRADE_COMPARE(b, Vector2(1.5f, 2.5f)); +} + +void Vector2Test::convert() { + Vec2 a{1.5f, 2.0f}; + Vector2 b(1.5f, 2.0f); + CORRADE_COMPARE(Vector2(a), b); + CORRADE_COMPARE(Vec2(b).x, a.x); + CORRADE_COMPARE(Vec2(b).y, a.y); +} + +void Vector2Test::access() { + Vector2 vec(1.0f, -2.0f); + CORRADE_COMPARE(vec.x(), 1.0f); + CORRADE_COMPARE(vec.y(), -2.0f); + + constexpr Vector2 cvec(1.0f, -2.0f); + constexpr Float x = cvec.x(); + constexpr Float y = cvec.y(); + CORRADE_COMPARE(x, 1.0f); + CORRADE_COMPARE(y, -2.0f); } void Vector2Test::axes() { - CORRADE_COMPARE(Vector2::xAxis(5.0f), Vector2(5.0f, 0.0f)); - CORRADE_COMPARE(Vector2::yAxis(6.0f), Vector2(0.0f, 6.0f)); + constexpr Vector2 x = Vector2::xAxis(5.0f); + constexpr Vector2 y = Vector2::yAxis(6.0f); + CORRADE_COMPARE(x, Vector2(5.0f, 0.0f)); + CORRADE_COMPARE(y, Vector2(0.0f, 6.0f)); } void Vector2Test::scales() { - CORRADE_COMPARE(Vector2::xScale(-5.0f), Vector2(-5.0f, 1.0f)); - CORRADE_COMPARE(Vector2::yScale(-0.2f), Vector2(1.0f, -0.2f)); + constexpr Vector2 x = Vector2::xScale(-5.0f); + constexpr Vector2 y = Vector2::yScale(-0.2f); + CORRADE_COMPARE(x, Vector2(-5.0f, 1.0f)); + CORRADE_COMPARE(y, Vector2(1.0f, -0.2f)); } void Vector2Test::debug() { - ostringstream o; + std::ostringstream o; Debug(&o) << Vector2(0.5f, 15.0f); CORRADE_COMPARE(o.str(), "Vector(0.5, 15)\n"); } void Vector2Test::configuration() { - Configuration c; + Corrade::Utility::Configuration c; Vector2 vec(3.125f, 9.0f); - string value("3.125 9"); + std::string value("3.125 9"); c.setValue("vector", vec); - CORRADE_COMPARE(c.value("vector"), value); + CORRADE_COMPARE(c.value("vector"), value); CORRADE_COMPARE(c.value("vector"), vec); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::Vector2Test) diff --git a/src/Math/Test/Vector2Test.h b/src/Math/Test/Vector2Test.h deleted file mode 100644 index 48bcc1b9f..000000000 --- a/src/Math/Test/Vector2Test.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Magnum_Math_Test_Vector2Test_h -#define Magnum_Math_Test_Vector2Test_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Vector2Test: public Corrade::TestSuite::Tester { - public: - Vector2Test(); - - void construct(); - void axes(); - void scales(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/Vector3Test.cpp b/src/Math/Test/Vector3Test.cpp index 7ef022ff7..05d5a697d 100644 --- a/src/Math/Test/Vector3Test.cpp +++ b/src/Math/Test/Vector3Test.cpp @@ -1,48 +1,165 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Vector3Test.h" - +#include +#include #include -#include "Vector3.h" +#include "Math/Vector3.h" -CORRADE_TEST_MAIN(Magnum::Math::Test::Vector3Test) +struct Vec3 { + float x, y, z; +}; -using namespace std; -using namespace Corrade::Utility; +namespace Magnum { namespace Math { -namespace Magnum { namespace Math { namespace Test { +namespace Implementation { + +template<> struct VectorConverter<3, float, Vec3> { + inline 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) { + return {other[0], other[1], other[2]}; + } +}; + +} -typedef Math::Vector3 Vector3; -typedef Math::Vector2 Vector2; +namespace Test { + +class Vector3Test: public Corrade::TestSuite::Tester { + public: + Vector3Test(); + + void construct(); + void constructDefault(); + void constructOneValue(); + void constructParts(); + void constructConversion(); + void constructCopy(); + + void convert(); + + void access(); + void cross(); + void axes(); + void scales(); + void twoComponent(); + + void debug(); + void configuration(); +}; + +typedef Math::Vector3 Vector3; +typedef Math::Vector3 Vector3i; +typedef Math::Vector2 Vector2; Vector3Test::Vector3Test() { - addTests(&Vector3Test::construct, - &Vector3Test::cross, - &Vector3Test::axes, - &Vector3Test::scales, - &Vector3Test::twoComponent, - &Vector3Test::debug, - &Vector3Test::configuration); + addTests({&Vector3Test::construct, + &Vector3Test::constructDefault, + &Vector3Test::constructOneValue, + &Vector3Test::constructParts, + &Vector3Test::constructConversion, + &Vector3Test::constructCopy, + + &Vector3Test::convert, + + &Vector3Test::access, + &Vector3Test::cross, + &Vector3Test::axes, + &Vector3Test::scales, + &Vector3Test::twoComponent, + + &Vector3Test::debug, + &Vector3Test::configuration}); } void Vector3Test::construct() { - CORRADE_COMPARE(Vector3(), Vector3(0.0f, 0.0f, 0.0f)); - CORRADE_COMPARE(Vector3(1, 2, 3), (Vector<3, float>(1.0f, 2.0f, 3.0f))); - CORRADE_COMPARE(Vector3(Vector<2, float>(1.0f, 2.0f), 3), (Vector<3, float>(1.0f, 2.0f, 3.0f))); + constexpr Vector3 a(1.0f, 2.5f, -3.0f); + CORRADE_COMPARE(a, (Vector<3, Float>(1.0f, 2.5f, -3.0f))); +} + +void Vector3Test::constructDefault() { + constexpr Vector3 a; + CORRADE_COMPARE(a, Vector3(0.0f, 0.0f, 0.0f)); +} + +void Vector3Test::constructOneValue() { + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector3 a(-3.0f); + #else + Vector3 a(-3.0f); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(a, Vector3(-3.0f, -3.0f, -3.0f)); +} + +void Vector3Test::constructParts() { + constexpr Vector2 a(1.0f, 2.0f); + constexpr Vector3 b(a, 3.0f); + CORRADE_COMPARE(b, Vector3(1.0f, 2.0f, 3.0f)); +} + +void Vector3Test::constructConversion() { + constexpr Vector3 a(1.0f, 2.5f, -3.0f); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector3i b(a); + #else + Vector3i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(b, Vector3i(1, 2, -3)); +} + +void Vector3Test::constructCopy() { + constexpr Vector3 a(1.0f, 2.5f, -3.0f); + constexpr Vector3 b(a); + CORRADE_COMPARE(b, Vector3(1.0f, 2.5f, -3.0f)); +} + +void Vector3Test::convert() { + Vec3 a{1.5f, 2.0f, -3.5f}; + Vector3 b(1.5f, 2.0f, -3.5f); + CORRADE_COMPARE(Vector3(a), b); + CORRADE_COMPARE(Vec3(b).x, a.x); + CORRADE_COMPARE(Vec3(b).y, a.y); + CORRADE_COMPARE(Vec3(b).z, a.z); +} + +void Vector3Test::access() { + Vector3 vec(1.0f, -2.0f, 5.0f); + CORRADE_COMPARE(vec.x(), 1.0f); + CORRADE_COMPARE(vec.y(), -2.0f); + CORRADE_COMPARE(vec.z(), 5.0f); + + constexpr Vector3 cvec(1.0f, -2.0f, 5.0f); + constexpr Float x = cvec.x(); + constexpr Float y = cvec.y(); + constexpr Float z = cvec.z(); + CORRADE_COMPARE(x, 1.0f); + CORRADE_COMPARE(y, -2.0f); + CORRADE_COMPARE(z, 5.0f); } void Vector3Test::cross() { @@ -53,36 +170,51 @@ void Vector3Test::cross() { } void Vector3Test::axes() { - CORRADE_COMPARE(Vector3::xAxis(5.0f), Vector3(5.0f, 0.0f, 0.0f)); - CORRADE_COMPARE(Vector3::yAxis(6.0f), Vector3(0.0f, 6.0f, 0.0f)); - CORRADE_COMPARE(Vector3::zAxis(7.0f), Vector3(0.0f, 0.0f, 7.0f)); + constexpr Vector3 x = Vector3::xAxis(5.0f); + constexpr Vector3 y = Vector3::yAxis(6.0f); + constexpr Vector3 z = Vector3::zAxis(7.0f); + CORRADE_COMPARE(x, Vector3(5.0f, 0.0f, 0.0f)); + CORRADE_COMPARE(y, Vector3(0.0f, 6.0f, 0.0f)); + CORRADE_COMPARE(z, Vector3(0.0f, 0.0f, 7.0f)); } void Vector3Test::scales() { - CORRADE_COMPARE(Vector3::xScale(-5.0f), Vector3(-5.0f, 1.0f, 1.0f)); - CORRADE_COMPARE(Vector3::yScale(-0.2f), Vector3(1.0f, -0.2f, 1.0f)); - CORRADE_COMPARE(Vector3::zScale(71.0f), Vector3(1.0f, 1.0f, 71.0f)); + constexpr Vector3 x = Vector3::xScale(-5.0f); + constexpr Vector3 y = Vector3::yScale(-0.2f); + constexpr Vector3 z = Vector3::zScale(71.0f); + CORRADE_COMPARE(x, Vector3(-5.0f, 1.0f, 1.0f)); + CORRADE_COMPARE(y, Vector3(1.0f, -0.2f, 1.0f)); + CORRADE_COMPARE(z, Vector3(1.0f, 1.0f, 71.0f)); } void Vector3Test::twoComponent() { - CORRADE_COMPARE(Vector3(1.0f, 2.0f, 3.0f).xy(), Vector2(1.0f, 2.0f)); + Vector3 a(1.0f, 2.0f, 3.0f); + CORRADE_COMPARE(a.xy(), Vector2(1.0f, 2.0f)); + + constexpr Vector3 b(1.0f, 2.0f, 3.0f); + constexpr Vector2 c = b.xy(); + constexpr Float d = b.xy().y(); + CORRADE_COMPARE(c, Vector2(1.0f, 2.0f)); + CORRADE_COMPARE(d, 2.0f); } void Vector3Test::debug() { - ostringstream o; + std::ostringstream o; Debug(&o) << Vector3(0.5f, 15.0f, 1.0f); CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1)\n"); } void Vector3Test::configuration() { - Configuration c; + Corrade::Utility::Configuration c; Vector3 vec(3.0f, 3.125f, 9.55f); - string value("3 3.125 9.55"); + std::string value("3 3.125 9.55"); c.setValue("vector", vec); - CORRADE_COMPARE(c.value("vector"), value); + CORRADE_COMPARE(c.value("vector"), value); CORRADE_COMPARE(c.value("vector"), vec); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::Vector3Test) diff --git a/src/Math/Test/Vector3Test.h b/src/Math/Test/Vector3Test.h deleted file mode 100644 index 1542c6a06..000000000 --- a/src/Math/Test/Vector3Test.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Magnum_Math_Test_Vector3Test_h -#define Magnum_Math_Test_Vector3Test_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Vector3Test: public Corrade::TestSuite::Tester { - public: - Vector3Test(); - - void construct(); - void cross(); - void axes(); - void scales(); - void twoComponent(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/Vector4Test.cpp b/src/Math/Test/Vector4Test.cpp index 33d52deb0..8e09b296c 100644 --- a/src/Math/Test/Vector4Test.cpp +++ b/src/Math/Test/Vector4Test.cpp @@ -1,72 +1,207 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Vector4Test.h" - +#include +#include #include -#include "Vector4.h" +#include "Math/Vector4.h" -CORRADE_TEST_MAIN(Magnum::Math::Test::Vector4Test) +struct Vec4 { + float x, y, z, w; +}; + +namespace Magnum { namespace Math { -using namespace std; -using namespace Corrade::Utility; +namespace Implementation { + +template<> struct VectorConverter<4, float, Vec4> { + inline 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) { + return {other[0], other[1], other[2], other[3]}; + } +}; + +} -namespace Magnum { namespace Math { namespace Test { +namespace Test { -typedef Math::Vector4 Vector4; -typedef Math::Vector3 Vector3; -typedef Math::Vector2 Vector2; +class Vector4Test: public Corrade::TestSuite::Tester { + public: + Vector4Test(); + + void construct(); + void constructDefault(); + void constructOneValue(); + void constructParts(); + void constructConversion(); + void constructCopy(); + + void convert(); + + void access(); + void threeComponent(); + void twoComponent(); + + void debug(); + void configuration(); +}; + +typedef Math::Vector4 Vector4; +typedef Math::Vector4 Vector4i; +typedef Math::Vector3 Vector3; +typedef Math::Vector2 Vector2; Vector4Test::Vector4Test() { - addTests(&Vector4Test::construct, - &Vector4Test::threeComponent, - &Vector4Test::twoComponent, - &Vector4Test::debug, - &Vector4Test::configuration); + addTests({&Vector4Test::construct, + &Vector4Test::constructDefault, + &Vector4Test::constructOneValue, + &Vector4Test::constructParts, + &Vector4Test::constructConversion, + &Vector4Test::constructCopy, + + &Vector4Test::convert, + + &Vector4Test::access, + &Vector4Test::threeComponent, + &Vector4Test::twoComponent, + + &Vector4Test::debug, + &Vector4Test::configuration}); } void Vector4Test::construct() { - CORRADE_COMPARE(Vector4(), Vector4(0.0f, 0.0f, 0.0f, 0.0f)); - CORRADE_COMPARE(Vector4(1, 2, 3, 4), (Vector<4, float>(1.0f, 2.0f, 3.0f, 4.0f))); - CORRADE_COMPARE(Vector4(Vector<3, float>(1.0f, 2.0f, 3.0f), 4), (Vector<4, float>(1.0f, 2.0f, 3.0f, 4.0f))); + constexpr Vector4 a(1.0f, -2.5f, 3.0f, 4.1f); + CORRADE_COMPARE(a, (Vector<4, Float>(1.0f, -2.5f, 3.0f, 4.1f))); +} + +void Vector4Test::constructDefault() { + constexpr Vector4 a; + CORRADE_COMPARE(a, Vector4(0.0f, 0.0f, 0.0f, 0.0f)); +} + +void Vector4Test::constructOneValue() { + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector4 a(4.3f); + #else + Vector4 a(4.3f); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(a, Vector4(4.3f, 4.3f, 4.3f, 4.3f)); +} + +void Vector4Test::constructParts() { + constexpr Vector3 a(1.0f, 2.0f, 3.0f); + constexpr Vector4 b(a, 4.0f); + CORRADE_COMPARE(b, Vector4(1.0f, 2.0f, 3.0f, 4.0f)); +} + +void Vector4Test::constructConversion() { + constexpr Vector4 a(1.0f, -2.5f, 3.0f, 4.1f); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector4i b(a); + #else + Vector4i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + CORRADE_COMPARE(b, Vector4i(1, -2, 3, 4)); +} + +void Vector4Test::constructCopy() { + constexpr Vector4 a(1.0f, -2.5f, 3.0f, 4.1f); + constexpr Vector4 b(a); + CORRADE_COMPARE(b, Vector4(1.0f, -2.5f, 3.0f, 4.1f)); +} + +void Vector4Test::convert() { + Vec4 a{1.5f, 2.0f, -3.5f, -0.5f}; + Vector4 b(1.5f, 2.0f, -3.5f, -0.5f); + CORRADE_COMPARE(Vector4(a), b); + CORRADE_COMPARE(Vec4(b).x, a.x); + CORRADE_COMPARE(Vec4(b).y, a.y); + CORRADE_COMPARE(Vec4(b).z, a.z); + CORRADE_COMPARE(Vec4(b).w, a.w); +} + +void Vector4Test::access() { + Vector4 vec(1.0f, -2.0f, 5.0f, 0.5f); + CORRADE_COMPARE(vec.x(), 1.0f); + CORRADE_COMPARE(vec.y(), -2.0f); + CORRADE_COMPARE(vec.z(), 5.0f); + CORRADE_COMPARE(vec.w(), 0.5f); + + constexpr Vector4 cvec(1.0f, -2.0f, 5.0f, 0.5f); + constexpr Float x = cvec.x(); + constexpr Float y = cvec.y(); + constexpr Float z = cvec.z(); + constexpr Float w = cvec.w(); + CORRADE_COMPARE(x, 1.0f); + CORRADE_COMPARE(y, -2.0f); + CORRADE_COMPARE(z, 5.0f); + CORRADE_COMPARE(w, 0.5f); } void Vector4Test::threeComponent() { - CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).xyz(), Vector3(1.0f, 2.0f, 3.0f)); + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + CORRADE_COMPARE(a.xyz(), Vector3(1.0f, 2.0f, 3.0f)); + + constexpr Vector4 b(1.0f, 2.0f, 3.0f, 4.0f); + constexpr Vector3 c = b.xyz(); + constexpr Float d = b.xyz().y(); + CORRADE_COMPARE(c, Vector3(1.0f, 2.0f, 3.0f)); + CORRADE_COMPARE(d, 2.0f); } void Vector4Test::twoComponent() { - CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).xy(), Vector2(1.0f, 2.0f)); + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + CORRADE_COMPARE(a.xy(), Vector2(1.0f, 2.0f)); + + constexpr Vector4 b(1.0f, 2.0f, 3.0f, 4.0f); + constexpr Vector2 c = b.xy(); + constexpr Float d = b.xy().x(); + CORRADE_COMPARE(c, Vector2(1.0f, 2.0f)); + CORRADE_COMPARE(d, 1.0f); } void Vector4Test::debug() { - ostringstream o; + std::ostringstream o; Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f); CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n"); } void Vector4Test::configuration() { - Configuration c; + Corrade::Utility::Configuration c; Vector4 vec(3.0f, 3.125f, 9.0f, 9.55f); - string value("3 3.125 9 9.55"); + std::string value("3 3.125 9 9.55"); c.setValue("vector", vec); - CORRADE_COMPARE(c.value("vector"), value); + CORRADE_COMPARE(c.value("vector"), value); CORRADE_COMPARE(c.value("vector"), vec); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::Vector4Test) diff --git a/src/Math/Test/Vector4Test.h b/src/Math/Test/Vector4Test.h deleted file mode 100644 index e06ce248a..000000000 --- a/src/Math/Test/Vector4Test.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Magnum_Math_Test_Vector4Test_h -#define Magnum_Math_Test_Vector4Test_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class Vector4Test: public Corrade::TestSuite::Tester { - public: - Vector4Test(); - - void construct(); - void threeComponent(); - void twoComponent(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index f9a86cc62..9b492efcd 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -1,75 +1,276 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "VectorTest.h" - +#include +#include #include -#include "Constants.h" -#include "Vector.h" +#include "Math/Vector.h" -CORRADE_TEST_MAIN(Magnum::Math::Test::VectorTest) +struct Vec3 { + float x, y, z; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct VectorConverter<3, float, Vec3> { + inline static Vector<3, Float> from(const Vec3& other) { + return {other.x, other.y, other.z}; + } + + inline static Vec3 to(const Vector<3, Float>& other) { + return {other[0], other[1], other[2]}; + } +}; + +} + +namespace Test { + +class VectorTest: public Corrade::TestSuite::Tester { + public: + VectorTest(); + + void construct(); + void constructFromData(); + void constructDefault(); + void constructOneValue(); + void constructOneComponent(); + void constructConversion(); + void constructCopy(); + + void isNormalized(); + + void convert(); + void data(); + + void negative(); + void addSubtract(); + void multiplyDivide(); + void multiplyDivideComponentWise(); + + void compare(); + void compareComponentWise(); -using namespace std; -using namespace Corrade::Utility; + void dot(); + void dotSelf(); + void length(); + void normalized(); -namespace Magnum { namespace Math { namespace Test { + void sum(); + void product(); + void min(); + void minAbs(); + void max(); + void maxAbs(); -typedef Vector<4, float> Vector4; -typedef Vector<3, float> Vector3; + void projected(); + void projectedOntoNormalized(); + void angle(); + + void debug(); + void configuration(); +}; + +typedef Math::Rad Rad; +typedef Vector<3, Float> Vector3; +typedef Vector<4, Float> Vector4; +typedef Vector<4, Int> Vector4i; VectorTest::VectorTest() { - addTests(&VectorTest::construct, - &VectorTest::compareComponentWise, - &VectorTest::dot, - &VectorTest::multiplyDivideComponentWise, - &VectorTest::dotSelf, - &VectorTest::length, - &VectorTest::normalized, - &VectorTest::sum, - &VectorTest::product, - &VectorTest::min, - &VectorTest::max, - &VectorTest::angle, - &VectorTest::debug, - &VectorTest::configuration); + addTests({&VectorTest::construct, + &VectorTest::constructFromData, + &VectorTest::constructDefault, + &VectorTest::constructOneValue, + &VectorTest::constructOneComponent, + &VectorTest::constructConversion, + &VectorTest::constructCopy, + + &VectorTest::isNormalized, + + &VectorTest::convert, + &VectorTest::data, + + &VectorTest::negative, + &VectorTest::addSubtract, + &VectorTest::multiplyDivide, + &VectorTest::multiplyDivideComponentWise, + + &VectorTest::compare, + &VectorTest::compareComponentWise, + + &VectorTest::dot, + &VectorTest::dotSelf, + &VectorTest::length, + &VectorTest::normalized, + + &VectorTest::sum, + &VectorTest::product, + &VectorTest::min, + &VectorTest::minAbs, + &VectorTest::max, + &VectorTest::maxAbs, + + &VectorTest::projected, + &VectorTest::projectedOntoNormalized, + &VectorTest::angle, + + &VectorTest::debug, + &VectorTest::configuration}); } void VectorTest::construct() { - CORRADE_COMPARE(Vector4(), Vector4(0.0f, 0.0f, 0.0f, 0.0f)); + constexpr Vector4 a(1.0f, 2.0f, -3.0f, 4.5f); + CORRADE_COMPARE(a, Vector4(1.0f, 2.0f, -3.0f, 4.5f)); +} + +void VectorTest::constructDefault() { + constexpr Vector4 a; + CORRADE_COMPARE(a, Vector4(0.0f, 0.0f, 0.0f, 0.0f)); +} - float data[] = { 1.0f, 2.0f, 3.0f, 4.0f }; +void VectorTest::constructFromData() { + Float data[] = { 1.0f, 2.0f, 3.0f, 4.0f }; CORRADE_COMPARE(Vector4::from(data), Vector4(1.0f, 2.0f, 3.0f, 4.0f)); } +void VectorTest::constructOneValue() { + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector4 a(7.25f); + #else + Vector4 a(7.25f); /* Not constexpr under GCC < 4.7 */ + #endif + + CORRADE_COMPARE(a, Vector4(7.25f, 7.25f, 7.25f, 7.25f)); +} + +void VectorTest::constructOneComponent() { + typedef Vector<1, Float> Vector1; + + /* Implicit constructor must work */ + constexpr Vector1 vec = 1.0f; + CORRADE_COMPARE(vec, Vector1(1)); +} + +void VectorTest::constructConversion() { + constexpr Vector4 a(1.3f, 2.7f, -15.0f, 7.0f); + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr Vector4i b(a); + #else + Vector4i b(a); /* Not constexpr under GCC < 4.7 */ + #endif + + CORRADE_COMPARE(b, Vector4i(1, 2, -15, 7)); +} + +void VectorTest::constructCopy() { + constexpr Vector4 a(1.0f, 3.5f, 4.0f, -2.7f); + constexpr Vector4 b(a); + CORRADE_COMPARE(b, Vector4(1.0f, 3.5f, 4.0f, -2.7f)); +} + +void VectorTest::isNormalized() { + CORRADE_VERIFY(!Vector3(1.0f, 2.0f, -1.0f).isNormalized()); + CORRADE_VERIFY(Vector3(0.0f, 1.0f, 0.0f).isNormalized()); +} + +void VectorTest::convert() { + Vec3 a{1.5f, 2.0f, -3.5f}; + Vector3 b(1.5f, 2.0f, -3.5f); + CORRADE_COMPARE(Vector3(a), b); + CORRADE_COMPARE(Vec3(b).x, a.x); + CORRADE_COMPARE(Vec3(b).y, a.y); + CORRADE_COMPARE(Vec3(b).z, a.z); +} + +void VectorTest::data() { + Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); + vector[2] = 1.0f; + vector[3] = 1.5f; + + CORRADE_COMPARE(vector[2], 1.0f); + CORRADE_COMPARE(vector[3], 1.5f); + CORRADE_COMPARE(vector, Vector4(4.0f, 5.0f, 1.0f, 1.5f)); + + /* Pointer chasings, i.e. *(b.data()[3]), are not possible */ + constexpr Vector4 a(1.0f, 2.0f, -3.0f, 4.5f); + constexpr Float f = a[3]; + constexpr Float g = *a.data(); + CORRADE_COMPARE(f, 4.5f); + CORRADE_COMPARE(g, 1.0f); +} + +void VectorTest::compare() { + CORRADE_VERIFY(Vector4(1.0f, -3.5f, 5.0f, -10.0f) == Vector4(1.0f + TypeTraits::epsilon()/2, -3.5f, 5.0f, -10.0f)); + CORRADE_VERIFY(Vector4(1.0f, -1.0f, 5.0f, -10.0f) != Vector4(1.0f, -1.0f + TypeTraits::epsilon()*2, 5.0f, -10.0f)); + + CORRADE_VERIFY(Vector4i(1, -3, 5, -10) == Vector4i(1, -3, 5, -10)); + CORRADE_VERIFY(Vector4i(1, -3, 5, -10) != Vector4i(1, -2, 5, -10)); +} + void VectorTest::compareComponentWise() { - CORRADE_VERIFY(Vector4(1.0f, -2.0f, -5.0f, 7.0f) < Vector4(1.1f, -1.0f, 3.0f, 8.0f)); - CORRADE_VERIFY(!(Vector4(1.0f, -2.0f, -5.0f, 7.0f) < Vector4(1.1f, -1.0f, 3.0f, 7.0f))); + typedef BoolVector<3> BoolVector3; + CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) < Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x1)); + CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) <= Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x3)); + CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) >= Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x6)); + CORRADE_COMPARE(Vector3(1.0f, -1.0f, 5.0f) > Vector3(1.1f, -1.0f, 3.0f), BoolVector3(0x4)); +} - CORRADE_VERIFY(Vector4(1.0f, -2.0f, -5.0f, 7.0f) <= Vector4(1.1f, -1.0f, 3.0f, 7.0f)); - CORRADE_VERIFY(!(Vector4(1.0f, -2.0f, -5.0f, 7.0f) <= Vector4(1.0f, -2.0f, -5.0f, 6.0f))); +void VectorTest::negative() { + CORRADE_COMPARE(-Vector4(1.0f, -3.0f, 5.0f, -10.0f), Vector4(-1.0f, 3.0f, -5.0f, 10.0f)); +} - CORRADE_VERIFY(Vector4(1.1f, -1.0f, 3.0f, 7.0f) >= Vector4(1.0f, -2.0f, -5.0f, 7.0f)); - CORRADE_VERIFY(!(Vector4(1.0f, -2.0f, -5.0f, 6.0f) >= Vector4(1.0f, -2.0f, -5.0f, 7.0f))); +void VectorTest::addSubtract() { + Vector4 a(1.0f, -3.0f, 5.0f, -10.0f); + Vector4 b(7.5f, 33.0f, -15.0f, 0.0f); + Vector4 c(8.5f, 30.0f, -10.0f, -10.0f); - CORRADE_VERIFY(Vector4(1.1f, -1.0f, 3.0f, 8.0f) > Vector4(1.0f, -2.0f, -5.0f, 7.0f)); - CORRADE_VERIFY(!(Vector4(1.1f, -1.0f, 3.0f, 7.0f) > Vector4(1.0f, -2.0f, -5.0f, 7.0f))); + CORRADE_COMPARE(a + b, c); + CORRADE_COMPARE(c - b, a); } -void VectorTest::dot() { - CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); +void VectorTest::multiplyDivide() { + Vector4 vector(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f); + + CORRADE_COMPARE(vector*-1.5f, multiplied); + CORRADE_COMPARE(-1.5f*vector, multiplied); + CORRADE_COMPARE(multiplied/-1.5f, vector); + + Math::Vector<1, Byte> vectorChar(32); + Math::Vector<1, Byte> multipliedChar(-48); + CORRADE_COMPARE(vectorChar*-1.5f, multipliedChar); + CORRADE_COMPARE(multipliedChar/-1.5f, vectorChar); + CORRADE_COMPARE(-1.5f*vectorChar, multipliedChar); + + /* Divide vector with number and inverse */ + Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f); + Vector4 result(1.0f, 0.5f, -0.25f, 0.125f); + CORRADE_COMPARE(1.0f/divisor, result); + CORRADE_COMPARE(-1550.0f/multipliedChar, vectorChar); } void VectorTest::multiplyDivideComponentWise() { @@ -81,6 +282,10 @@ void VectorTest::multiplyDivideComponentWise() { CORRADE_COMPARE(multiplied/multiplier, vec); } +void VectorTest::dot() { + CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); +} + void VectorTest::dotSelf() { CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).dot(), 30.0f); } @@ -102,43 +307,89 @@ void VectorTest::product() { } void VectorTest::min() { + /* Check also that initial value isn't initialized to 0 */ CORRADE_COMPARE(Vector3(1.0f, -2.0f, 3.0f).min(), -2.0f); } +void VectorTest::minAbs() { + /* Check that initial value is absolute and also all others */ + CORRADE_COMPARE(Vector3(-2.0f, 1.0f, 3.0f).minAbs(), 1.0f); + CORRADE_COMPARE(Vector3(1.0f, -2.0f, 3.0f).minAbs(), 1.0f); +} + void VectorTest::max() { - CORRADE_COMPARE(Vector3(1.0f, -2.0f, 3.0f).max(), 3.0f); + /* Check also that initial value isn't initialized to 0 */ + CORRADE_COMPARE(Vector3(-1.0f, -2.0f, -3.0f).max(), -1.0f); +} + +void VectorTest::maxAbs() { + /* Check that initial value is absolute and also all others */ + CORRADE_COMPARE(Vector3(-5.0f, 1.0f, 3.0f).maxAbs(), 5.0f); + CORRADE_COMPARE(Vector3(1.0f, -5.0f, 3.0f).maxAbs(), 5.0f); +} + +void VectorTest::projected() { + Vector3 line(1.0f, -1.0f, 0.5f); + Vector3 projected = Vector3(1.0f, 2.0f, 3.0f).projected(line); + + CORRADE_COMPARE(projected, Vector3(0.222222f, -0.222222f, 0.111111f)); + CORRADE_COMPARE(projected.normalized(), line.normalized()); +} + +void VectorTest::projectedOntoNormalized() { + std::ostringstream o; + Error::setOutput(&o); + + Vector3 vector(1.0f, 2.0f, 3.0f); + Vector3 line(1.0f, -1.0f, 0.5f); + Vector3 projected = vector.projectedOntoNormalized(line); + CORRADE_VERIFY(projected != projected); + CORRADE_COMPARE(o.str(), "Math::Vector::projectedOntoNormalized(): line must be normalized\n"); + + projected = vector.projectedOntoNormalized(line.normalized()); + CORRADE_COMPARE(projected, Vector3(0.222222f, -0.222222f, 0.111111f)); + CORRADE_COMPARE(projected.normalized(), line.normalized()); + CORRADE_COMPARE(projected, vector.projected(line)); } void VectorTest::angle() { - ostringstream o; + std::ostringstream o; Error::setOutput(&o); - /* Both vectors must be normalized, otherwise NaN is returned */ - CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), {1.0f, -2.0f, 3.0f}), numeric_limits::quiet_NaN()); + auto angle = Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), {1.0f, -2.0f, 3.0f}); + CORRADE_VERIFY(angle != angle); CORRADE_COMPARE(o.str(), "Math::Vector::angle(): vectors must be normalized\n"); - CORRADE_COMPARE(Vector3::angle({2.0f, 3.0f, 4.0f}, Vector3(1.0f, -2.0f, 3.0f).normalized()), numeric_limits::quiet_NaN()); - CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), Vector3(1.0f, -2.0f, 3.0f).normalized()), rad(1.162514f)); + o.str({}); + angle = Vector3::angle({2.0f, 3.0f, 4.0f}, Vector3(1.0f, -2.0f, 3.0f).normalized()); + CORRADE_VERIFY(angle != angle); + CORRADE_COMPARE(o.str(), "Math::Vector::angle(): vectors must be normalized\n"); + + CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), + Vector3(1.0f, -2.0f, 3.0f).normalized()), + Rad(1.162514f)); } void VectorTest::debug() { - ostringstream o; + std::ostringstream o; Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f); CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n"); - o.str(""); + o.str({}); Debug(&o) << "a" << Vector4() << "b" << Vector4(); CORRADE_COMPARE(o.str(), "a Vector(0, 0, 0, 0) b Vector(0, 0, 0, 0)\n"); } void VectorTest::configuration() { - Configuration c; + Corrade::Utility::Configuration c; Vector4 vec(3.0f, 3.125f, 9.0f, 9.55f); - string value("3 3.125 9 9.55"); + std::string value("3 3.125 9 9.55"); c.setValue("vector", vec); - CORRADE_COMPARE(c.value("vector"), value); + CORRADE_COMPARE(c.value("vector"), value); CORRADE_COMPARE(c.value("vector"), vec); } }}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::VectorTest) diff --git a/src/Math/Test/VectorTest.h b/src/Math/Test/VectorTest.h deleted file mode 100644 index ca8f48e48..000000000 --- a/src/Math/Test/VectorTest.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef Magnum_Math_Test_VectorTest_h -#define Magnum_Math_Test_VectorTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Math { namespace Test { - -class VectorTest: public Corrade::TestSuite::Tester { - public: - VectorTest(); - - void construct(); - void compareComponentWise(); - void dot(); - void multiplyDivideComponentWise(); - void dotSelf(); - void length(); - void normalized(); - void sum(); - void product(); - void min(); - void max(); - void angle(); - - void debug(); - void configuration(); -}; - -}}} - -#endif diff --git a/src/Math/TypeTraits.h b/src/Math/TypeTraits.h new file mode 100644 index 000000000..84a566ff2 --- /dev/null +++ b/src/Math/TypeTraits.h @@ -0,0 +1,195 @@ +#ifndef Magnum_Math_TypeTraits_h +#define Magnum_Math_TypeTraits_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::Math::TypeTraits + */ + +#include +#include + +#include "Types.h" + +/** @brief Precision when testing floats for equality */ +#ifndef FLOAT_EQUALITY_PRECISION +#define FLOAT_EQUALITY_PRECISION 1.0e-6 +#endif + +/** @brief Precision when testing doubles for equality */ +#ifndef DOUBLE_EQUALITY_PRECISION +#define DOUBLE_EQUALITY_PRECISION 1.0e-12 +#endif + +/** +@brief Precision when testing long doubles for equality +@todo some proper value please +*/ +#ifndef LONG_DOUBLE_EQUALITY_PRECISION +#define LONG_DOUBLE_EQUALITY_PRECISION 1.0e-18 +#endif + +namespace Magnum { namespace Math { + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct TypeTraitsDefault { + TypeTraitsDefault() = delete; + + inline constexpr static bool equals(T a, T b) { + return a == b; + } + }; +} +#endif + +/** +@brief Traits class for numeric types + +Traits classes are usable for detecting type features at compile time without +the need for repeated code such as method overloading or template +specialization for given types. +*/ +template struct TypeTraits: Implementation::TypeTraitsDefault { + /* + * The following values are implemented as inline functions, not as + * static const variables, because the compiler will inline the return + * values instead of referencing to static data and unlike static const + * variables the functions can be overloaded, deleted and hidden. + */ + + #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Corresponding floating-point type for normalization + * + * If the type is not already floating-point, defines smallest larger + * floating-point type. + */ + typedef U FloatingPointType; + + /** + * @brief Epsilon value for fuzzy compare + * + * Returns minimal difference between numbers to be considered + * inequal. Returns 1 for integer types and reasonably small value for + * floating-point types. Not implemented for arbitrary types. + */ + inline constexpr static T epsilon(); + + /** + * @brief Fuzzy compare + * + * Uses fuzzy compare for floating-point types (using epsilon() value), + * pure equality comparison everywhere else. + */ + static bool equals(T a, T b); + #endif +}; + +/** @bug Infinity comparison! */ + +/** + * @todo Implement better fuzzy comparison algorithm, like at + * http://floating-point-gui.de/errors/comparison/ or + * 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); } + }; +} + +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef Float FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef Float FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef Float FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef Float FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef Double FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef Double FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef long double FloatingPointType; +}; +template<> struct TypeTraits: Implementation::TypeTraitsIntegral { + typedef long double FloatingPointType; +}; + +/* Floating-point scalar types */ +namespace Implementation { + template struct TypeTraitsFloatingPoint { + TypeTraitsFloatingPoint() = delete; + + inline static bool equals(T a, T b) { + return std::abs(a - b) < TypeTraits::epsilon(); + } + }; +} + +template<> struct TypeTraits: Implementation::TypeTraitsFloatingPoint { + typedef Float FloatingPointType; + + inline constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; } +}; +template<> struct TypeTraits: Implementation::TypeTraitsFloatingPoint { + typedef Double FloatingPointType; + + inline constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; } +}; +template<> struct TypeTraits: Implementation::TypeTraitsFloatingPoint { + typedef long double FloatingPointType; + + inline constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; } +}; + +/* Comparing squared length to 1 is not sufficient to compare within range + [1 - epsilon, 1 + epsilon], as e.g. Quaternion with dot() = 1 + 1e-7 when + converted to matrix has column vectors with dot() = 1 + 1e-6, which is just + above 1 + epsilon. Thus it's needed to compare sqrt(dot()) in range + [1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon + epsilon^2, + 1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision, + it's omitted. */ +namespace Implementation { + template inline bool isNormalizedSquared(T lengthSquared) { + return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits::epsilon(); + } +} +#endif + +}} + +#endif diff --git a/src/Math/Unit.h b/src/Math/Unit.h new file mode 100644 index 000000000..7a586ec6e --- /dev/null +++ b/src/Math/Unit.h @@ -0,0 +1,156 @@ +#ifndef Magnum_Math_Unit_h +#define Magnum_Math_Unit_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::Math::Unit + */ + +#include "Math/TypeTraits.h" + +namespace Magnum { namespace Math { + +/** +@brief Base class for units +@tparam T Underlying data type + +@see Deg, Rad +*/ +template class Derived, class T> class Unit { + template class, class> friend class Unit; + + public: + typedef T Type; /**< @brief Underlying data type */ + + /** @brief Default constructor */ + inline constexpr /*implicit*/ Unit(): value(T(0)) {} + + /** @brief Explicit conversion from unitless type */ + inline constexpr explicit Unit(T value): value(value) {} + + /** @brief Construct from another underlying type */ + template inline constexpr explicit Unit(Unit value): value(value.value) {} + + /** @brief Explicit conversion to underlying type */ + inline constexpr explicit operator T() const { return value; } + + /** @brief Equality comparison */ + inline constexpr bool operator==(Unit other) const { + return TypeTraits::equals(value, other.value); + } + + /** @brief Non-equality comparison */ + inline constexpr bool operator!=(Unit other) const { + return !operator==(other); + } + + /** @brief Less than comparison */ + inline constexpr bool operator<(Unit other) const { + return value < other.value; + } + + /** @brief Greater than comparison */ + inline constexpr bool operator>(Unit other) const { + return value > other.value; + } + + /** @brief Less than or equal comparison */ + inline constexpr bool operator<=(Unit other) const { + return !operator>(other); + } + + /** @brief Greater than or equal comparison */ + inline constexpr bool operator>=(Unit other) const { + return !operator<(other); + } + + /** @brief Negated value */ + inline constexpr Unit operator-() const { + return Unit(-value); + } + + /** @brief Add and assign value */ + inline Unit& operator+=(Unit other) { + value += other.value; + return *this; + } + + /** @brief Add value */ + inline constexpr Unit operator+(Unit other) const { + return Unit(value + other.value); + } + + /** @brief Subtract and assign value */ + inline Unit& operator-=(Unit other) { + value -= other.value; + return *this; + } + + /** @brief Subtract value */ + inline constexpr Unit operator-(Unit other) const { + return Unit(value - other.value); + } + + /** @brief Multiply with number and assign */ + inline Unit& operator*=(T number) { + value *= number; + return *this; + } + + /** @brief Multiply with number */ + inline constexpr Unit operator*(T number) const { + return Unit(value*number); + } + + /** @brief Divide with number and assign */ + inline Unit& operator/=(T number) { + value /= number; + return *this; + } + + /** @brief Divide with number */ + inline constexpr Unit operator/(T number) const { + return Unit(value/number); + } + + /** @brief Ratio of two values */ + inline constexpr T operator/(Unit other) const { + return value/other.value; + } + + private: + T value; +}; + +/** @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) { + return value*number; +} + +}} + +#endif diff --git a/src/Math/Vector.cpp b/src/Math/Vector.cpp index 0004c854e..615eeba28 100644 --- a/src/Math/Vector.cpp +++ b/src/Math/Vector.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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" @@ -18,20 +27,42 @@ 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, unsigned int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<3, unsigned int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::Vector<4, unsigned int>&); +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 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>&); +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; #endif #endif }} + diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 3ed1f71b3..5ef5b508a 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -1,208 +1,440 @@ #ifndef Magnum_Math_Vector_h #define Magnum_Math_Vector_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Math::Vector */ -#include "RectangularMatrix.h" +#include +#include +#include +#include +#include + +#include "Math/Angle.h" +#include "Math/BoolVector.h" +#include "Math/TypeTraits.h" + +#include "magnumVisibility.h" namespace Magnum { namespace Math { +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct VectorConverter; +} +#endif + /** @brief %Vector @tparam size %Vector size -@tparam T Data type +@tparam T Underlying data type See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector} */ -template class Vector: public RectangularMatrix<1, size, T> { +template class Vector { + static_assert(size != 0, "Vector cannot have zero elements"); + + template friend class Vector; + public: - const static std::size_t Size = size; /**< @brief %Vector size */ + typedef T Type; /**< @brief Underlying data type */ + const static std::size_t Size = size; /**< @brief %Vector size */ + + /** + * @brief %Vector from array + * @return Reference to the data as if it was Vector, thus doesn't + * perform any copying. + * + * @attention Use with caution, the function doesn't check whether the + * array is long enough. + */ + inline constexpr static Vector& from(T* data) { + return *reinterpret_cast*>(data); + } + /** @overload */ + inline constexpr static const Vector& from(const T* data) { + return *reinterpret_cast*>(data); + } /** * @brief Dot product * * @f[ - * a \cdot b = \sum_{i=0}^{n-1} a_ib_i + * \boldsymbol a \cdot \boldsymbol b = \sum_{i=0}^{n-1} \boldsymbol a_i \boldsymbol b_i * @f] * @see dot() const */ - static T dot(const Vector& a, const Vector& b) { - T out(0); - - for(std::size_t i = 0; i != size; ++i) - out += a[i]*b[i]; - - return out; + inline static T dot(const Vector& a, const Vector& b) { + return (a*b).sum(); } /** - * @brief Angle between normalized vectors (in radians) + * @brief Angle between normalized vectors * - * @f[ - * \phi = acos \left(\frac{a \cdot b}{|a| \cdot |b|} \right) + * Expects that both vectors are normalized. @f[ + * \theta = acos \left( \frac{\boldsymbol a \cdot \boldsymbol b}{|\boldsymbol a| |\boldsymbol b|} \right) = acos (\boldsymbol a \cdot \boldsymbol b) * @f] - * @attention Both vectors must be normalized. + * @see isNormalized(), Quaternion::angle(), Complex::angle() */ - inline static T angle(const Vector& normalizedA, const Vector& normalizedB) { - CORRADE_ASSERT(MathTypeTraits::equals(normalizedA.dot(), T(1)) && MathTypeTraits::equals(normalizedB.dot(), T(1)), - "Math::Vector::angle(): vectors must be normalized", std::numeric_limits::quiet_NaN()); - return std::acos(dot(normalizedA, normalizedB)); + 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))); } - /** @brief Default constructor */ - inline constexpr Vector() {} + /** + * @brief Default constructor + * + * @f[ + * \boldsymbol v = \boldsymbol 0 + * @f] + */ + inline constexpr /*implicit*/ Vector(): _data() {} /** @todo Creating Vector from combination of vector and scalar types */ /** - * @brief Initializer-list constructor + * @brief Construct vector from values * @param first First value * @param next Next values */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr Vector(T first, U... next): RectangularMatrix<1, size, T>(first, next...) {} + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline constexpr /*implicit*/ Vector(T first, U... next); + #else + template::type> inline 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); + #else + #ifndef CORRADE_GCC46_COMPATIBILITY + template::value && size != 1, T>::type> inline constexpr explicit Vector(U value): Vector(typename Implementation::GenerateSequence::Type(), value) {} #else - template inline constexpr Vector(T first, U... next); + template::value && size != 1, T>::type> inline explicit Vector(U value) { + *this = Vector(typename Implementation::GenerateSequence::Type(), value); + } + #endif #endif /** - * @brief Constructor - * @param value Value for all fields + * @brief Construct vector from another of different type + * + * Performs only default casting on the values, no rounding or + * anything else. Example usage: + * @code + * Vector<4, Float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); + * Vector<4, Byte> integral(floatingPoint); + * // integral == {1, 2, -15, 7} + * @endcode */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline explicit Vector(typename std::enable_if::value && size != 1, U>::type value) { + #ifndef CORRADE_GCC46_COMPATIBILITY + template inline constexpr explicit Vector(const Vector& other): Vector(typename Implementation::GenerateSequence::Type(), other) {} #else - inline explicit Vector(T value) { - #endif - for(std::size_t i = 0; i != size; ++i) - (*this)[i] = value; + template inline explicit Vector(const Vector& other) { + *this = Vector(typename Implementation::GenerateSequence::Type(), other); } + #endif + + /** @brief Construct vector from external representation */ + template::from(std::declval()))> inline constexpr explicit Vector(const U& other): Vector(Implementation::VectorConverter::from(other)) {} /** @brief Copy constructor */ - inline constexpr Vector(const RectangularMatrix<1, size, T>& other): RectangularMatrix<1, size, T>(other) {} + inline constexpr Vector(const Vector&) = default; - /** @brief Value at given position */ - inline T& operator[](std::size_t pos) { return RectangularMatrix<1, size, T>::_data[pos]; } - inline constexpr T operator[](std::size_t pos) const { return RectangularMatrix<1, size, T>::_data[pos]; } /**< @overload */ + /** @brief Assignment operator */ + inline Vector& operator=(const Vector&) = default; + + /** @brief Convert vector to external representation */ + template::to(std::declval>()))> inline constexpr explicit operator U() const { + return Implementation::VectorConverter::to(*this); + } + + /** + * @brief Raw data + * @return One-dimensional array of `size*size` length. + * + * @see operator[]() + */ + inline T* data() { return _data; } + inline constexpr const T* data() const { return _data; } /**< @overload */ /** - * @brief Component-wise less than - * @return `True` if all components are smaller than their - * counterparts in @p other, `false` otherwise + * @brief Value at given position + * + * @see data() */ - inline bool operator<(const Vector& other) const { + inline T& operator[](std::size_t pos) { return _data[pos]; } + inline constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ + + /** @brief Equality comparison */ + inline bool operator==(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) - if((*this)[i] >= other[i]) return false; + if(!TypeTraits::equals(_data[i], other._data[i])) return false; return true; } + /** @brief Non-equality comparison */ + inline 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; + } + + /** @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; + } + + /** @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; + } + + /** @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; + } + + /** + * @brief Whether the vector is normalized + * + * The vector is normalized if it has unit length: @f[ + * |\boldsymbol a|^2 = |\boldsymbol a| = 1 + * @f] + * @see dot(), normalized() + */ + inline bool isNormalized() const { + return Implementation::isNormalizedSquared(dot()); + } + /** - * @brief Component-wise less than or equal - * @return `True` if all components are smaller than or equal to their - * counterparts in @p other, `false` otherwise + * @brief Negated vector + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = -\boldsymbol a_i + * @f] */ - inline bool operator<=(const Vector& other) const { + Vector operator-() const { + Vector out; + for(std::size_t i = 0; i != size; ++i) - if((*this)[i] > other[i]) return false; + out._data[i] = -_data[i]; - return true; + return out; + } + + /** + * @brief Add and assign vector + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i + * @f] + */ + Vector& operator+=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] += other._data[i]; + + return *this; } /** - * @brief Component-wise greater than or equal - * @return `True` if all components are larger than or equal to their - * counterparts in @p other, `false` otherwise + * @brief Add vector + * + * @see operator+=() + */ + inline Vector operator+(const Vector& other) const { + return Vector(*this) += other; + } + + /** + * @brief Subtract and assign vector + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = \boldsymbol a_i - \boldsymbol b_i + * @f] */ - inline bool operator>=(const Vector& other) const { + Vector& operator-=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) - if((*this)[i] < other[i]) return false; + _data[i] -= other._data[i]; - return true; + return *this; + } + + /** + * @brief Subtract vector + * + * @see operator-=() + */ + inline Vector operator-(const Vector& other) const { + return Vector(*this) -= other; } /** - * @brief Component-wise greater than - * @return `True` if all components are larger than their - * counterparts in @p other, `false` otherwise + * @brief Multiply vector with number and assign + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = b \boldsymbol a_i + * @f] */ - inline bool operator>(const Vector& other) const { + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& operator*=(U number) { + #else + template inline typename std::enable_if::value, Vector&>::type operator*=(U number) { + #endif for(std::size_t i = 0; i != size; ++i) - if((*this)[i] <= other[i]) return false; + _data[i] *= number; - return true; + return *this; } /** - * @brief Multiply vector component-wise + * @brief Multiply vector with number * - * @see operator*=(const Vector&) + * @see operator*=(U), operator*(U, const Vector&) */ - inline Vector operator*(const Vector& other) const { - return Vector(*this)*=other; + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline Vector operator*(U number) const { + #else + template inline typename std::enable_if::value, Vector>::type operator*(U number) const { + #endif + return Vector(*this) *= number; + } + + /** + * @brief Divide vector with number and assign + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = \frac{\boldsymbol a_i} b + * @f] + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& operator/=(U number) { + #else + template inline typename std::enable_if::value, Vector&>::type operator/=(U number) { + #endif + for(std::size_t i = 0; i != size; ++i) + _data[i] /= number; + + return *this; + } + + /** + * @brief Divide vector with number + * + * @see operator/=(), operator/(U, const Vector&) + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline Vector operator/(U number) const { + #else + template inline typename std::enable_if::value, Vector>::type operator/(U number) const { + #endif + return Vector(*this) /= number; } /** * @brief Multiply vector component-wise and assign * - * More efficient than operator*(const Vector&) const, - * because it does the computation in-place. + * The computation is done in-place. @f[ + * \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i + * @f] */ - Vector& operator*=(const Vector& other) { + template Vector& operator*=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) - (*this)[i] *= other[i]; + _data[i] *= other._data[i]; return *this; } /** - * @brief Divide vector component-wise + * @brief Multiply vector component-wise * - * @see operator/=(const Vector&) + * @see operator*=(const Vector&) */ - inline Vector operator/(const Vector& other) const { - return Vector(*this)/=other; + template inline Vector operator*(const Vector& other) const { + return Vector(*this) *= other; } /** * @brief Divide vector component-wise and assign * - * More efficient than operator/(const Vector&) const, - * because it does the computation in-place. + * The computation is done in-place. @f[ + * \boldsymbol a_i = \frac{\boldsymbol a_i}{\boldsymbol b_i} + * @f] */ - Vector& operator/=(const Vector& other) { + template Vector& operator/=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) - (*this)[i] /= other[i]; + _data[i] /= other._data[i]; return *this; } + /** + * @brief Divide vector component-wise + * + * @see operator/=(const Vector&) + */ + template inline Vector operator/(const Vector& other) const { + return Vector(*this) /= other; + } + /** * @brief Dot product of the vector * * Should be used instead of length() for comparing vector length with - * other values, because it doesn't compute the square root, just the - * dot product: @f$ a \cdot a < length \cdot length @f$ is faster - * than @f$ \sqrt{a \cdot a} < length @f$. - * - * @see dot(const Vector&, const Vector&) + * other values, because it doesn't compute the square root. @f[ + * \boldsymbol a \cdot \boldsymbol a = \sum_{i=0}^{n-1} \boldsymbol a_i^2 + * @f] + * @see dot(const Vector&, const Vector&), isNormalized() */ inline T dot() const { return dot(*this, *this); @@ -211,82 +443,155 @@ template class Vector: public RectangularMatrix<1, si /** * @brief %Vector length * - * @see dot() const + * See also dot() const which is faster for comparing length with other + * values. @f[ + * |\boldsymbol a| = \sqrt{\boldsymbol a \cdot \boldsymbol a} + * @f] + * @see isNormalized() + * @todo something like std::hypot() for possibly better precision? */ inline T length() const { return std::sqrt(dot()); } - /** @brief Normalized vector (of length 1) */ + /** + * @brief Normalized vector (of unit length) + * + * @see isNormalized() + */ inline Vector normalized() const { return *this/length(); } + /** + * @brief %Vector projected onto line + * + * Returns vector projected onto @p line. @f[ + * \boldsymbol a_1 = \frac{\boldsymbol a \cdot \boldsymbol b}{\boldsymbol b \cdot \boldsymbol b} \boldsymbol b + * @f] + * @see projectedOntoNormalized() + */ + inline Vector projected(const Vector& line) const { + return line*dot(*this, line)/line.dot(); + } + + /** + * @brief %Vector projected onto normalized line + * + * Slightly faster alternative to projected(), expects @p line to be + * normalized. @f[ + * \boldsymbol a_1 = \frac{\boldsymbol a \cdot \boldsymbol b}{\boldsymbol b \cdot \boldsymbol b} \boldsymbol b = + * (\boldsymbol a \cdot \boldsymbol b) \boldsymbol b + * @f] + */ + 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); + } + /** @brief Sum of values in the vector */ T sum() const { - T out(0); + T out(_data[0]); - for(std::size_t i = 0; i != size; ++i) - out += (*this)[i]; + for(std::size_t i = 1; i != size; ++i) + out += _data[i]; return out; } /** @brief Product of values in the vector */ T product() const { - T out(1); + T out(_data[0]); - for(std::size_t i = 0; i != size; ++i) - out *= (*this)[i]; + for(std::size_t i = 1; i != size; ++i) + out *= _data[i]; return out; } /** @brief Minimal value in the vector */ T min() const { - T out((*this)[0]); + T out(_data[0]); + + for(std::size_t i = 1; i != size; ++i) + out = std::min(out, _data[i]); + + return out; + } + + /** @brief Minimal absolute value in the vector */ + T minAbs() const { + T out(std::abs(_data[0])); for(std::size_t i = 1; i != size; ++i) - out = std::min(out, (*this)[i]); + out = std::min(out, std::abs(_data[i])); return out; } /** @brief Maximal value in the vector */ T max() const { - T out((*this)[0]); + T out(_data[0]); for(std::size_t i = 1; i != size; ++i) - out = std::max(out, (*this)[i]); + out = std::max(out, _data[i]); return out; } - #ifndef DOXYGEN_GENERATING_OUTPUT - /* Reimplementation of functions to return correct type */ - template inline RectangularMatrix operator*(const RectangularMatrix& other) const { - return RectangularMatrix<1, size, T>::operator*(other); + /** @brief Maximal absolute value in the vector */ + T maxAbs() const { + T out(std::abs(_data[0])); + + for(std::size_t i = 1; i != size; ++i) + out = std::max(out, std::abs(_data[i])); + + return out; } - MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector) - #endif private: - /* Hiding unused things from RectangularMatrix */ - using RectangularMatrix<1, size, T>::Cols; - using RectangularMatrix<1, size, T>::Rows; - using RectangularMatrix<1, size, T>::operator[]; - using RectangularMatrix<1, size, T>::operator(); + /* Implementation for Vector::Vector(const Vector&) */ + template inline 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)...} {} + + T _data[size]; }; -#ifndef DOXYGEN_GENERATING_OUTPUT +/** @relates Vector +@brief Multiply number with vector + +Same as Vector::operator*(U) const. +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline Vector operator*(U number, const Vector& vector) { +#else template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { - return number*RectangularMatrix<1, size, T>(vector); +#endif + return vector*number; } + +/** @relates Vector +@brief Divide vector with number and invert + +@f[ + \boldsymbol c_i = \frac b {\boldsymbol a_i} +@f] +@see Vector::operator/() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline Vector operator/(U number, const Vector& vector) { +#else template inline typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { - return number/RectangularMatrix<1, size, T>(vector); -} #endif + Vector out; + + for(std::size_t i = 0; i != size; ++i) + out[i] = number/vector[i]; + + return out; +} /** @debugoperator{Magnum::Math::Vector} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector& value) { @@ -294,28 +599,28 @@ template Corrade::Utility::Debug operator<<(Corrade:: debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); for(std::size_t i = 0; i != size; ++i) { if(i != 0) debug << ", "; - debug << typename MathTypeTraits::NumericType(value[i]); + debug << value[i]; } - debug << ')'; + debug << ")"; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); return debug; } /* Explicit instantiation for types used in OpenGL */ #ifndef DOXYGEN_GENERATING_OUTPUT -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, unsigned int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, unsigned int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, unsigned int>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, Float>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, Int>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, Int>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, Int>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, UnsignedInt>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, UnsignedInt>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, UnsignedInt>&); #ifndef MAGNUM_TARGET_GLES -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, Double>&); +extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, Double>&); #endif #endif @@ -326,9 +631,6 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit } \ inline constexpr static const Type& from(const T* data) { \ return *reinterpret_cast*>(data); \ - } \ - template inline constexpr static Type from(const Math::Vector& other) { \ - return Math::Vector::from(other); \ } \ \ inline Type& operator=(const Type& other) { \ @@ -336,25 +638,56 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit return *this; \ } \ \ - template inline Math::RectangularMatrix operator*(const Math::RectangularMatrix& other) const { \ - return Math::Vector::operator*(other); \ + inline Type operator-() const { \ + return Math::Vector::operator-(); \ } \ - inline Type operator*(const Math::Vector& other) const { \ - return Math::Vector::operator*(other); \ + inline Type& operator+=(const Math::Vector& other) { \ + Math::Vector::operator+=(other); \ + return *this; \ + } \ + inline Type operator+(const Math::Vector& other) const { \ + return Math::Vector::operator+(other); \ + } \ + inline Type& operator-=(const Math::Vector& other) { \ + Math::Vector::operator-=(other); \ + return *this; \ + } \ + inline Type operator-(const Math::Vector& other) const { \ + return Math::Vector::operator-(other); \ } \ - inline Type& operator*=(const Math::Vector& other) { \ + template inline 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 { \ + return Math::Vector::operator*(number); \ + } \ + template inline 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 { \ + return Math::Vector::operator/(number); \ + } \ + template inline Type& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ - inline Type operator/(const Math::Vector& other) const { \ - return Math::Vector::operator/(other); \ + template inline Type operator*(const Math::Vector& other) const { \ + return Math::Vector::operator*(other); \ } \ - inline Type& operator/=(const Math::Vector& other) { \ + template inline Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ + } \ + template inline Type operator/(const Math::Vector& other) const { \ + return Math::Vector::operator/(other); \ } \ \ - inline Type normalized() const { return Math::Vector::normalized(); } + inline Type normalized() const { return Math::Vector::normalized(); } \ + inline Type projected(const Math::Vector& other) const { \ + return Math::Vector::projected(other); \ + } #define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& vector) { \ @@ -369,8 +702,60 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit namespace Corrade { namespace Utility { -/** @configurationvalue{Magnum::Math::Vector} */ -template struct ConfigurationValue>: public ConfigurationValue> {}; +/** @configurationvalue{Magnum::Math::RectangularMatrix} */ +template struct ConfigurationValue> { + ConfigurationValue() = delete; + + /** @brief Writes elements separated with spaces */ + static std::string toString(const Magnum::Math::Vector& value, ConfigurationValueFlags flags) { + std::string output; + + for(std::size_t i = 0; i != size; ++i) { + if(!output.empty()) output += ' '; + output += ConfigurationValue::toString(value[i], flags); + } + + return output; + } + + /** @brief Reads elements separated with whitespace */ + static Magnum::Math::Vector fromString(const std::string& stringValue, ConfigurationValueFlags flags) { + Magnum::Math::Vector result; + + std::size_t oldpos = 0, pos = std::string::npos, i = 0; + do { + pos = stringValue.find(' ', oldpos); + std::string part = stringValue.substr(oldpos, pos-oldpos); + + if(!part.empty()) { + result[i] = ConfigurationValue::fromString(part, flags); + ++i; + } + + oldpos = pos+1; + } while(pos != std::string::npos); + + return result; + } +}; + +#ifndef DOXYGEN_GENERATING_OUTPUT +/* Vectors */ +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +#endif +#endif }} diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index 61534e2a8..148174cfb 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -1,18 +1,27 @@ #ifndef Magnum_Math_Vector2_h #define Magnum_Math_Vector2_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 2 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 2 for more details. + 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 @@ -28,7 +37,7 @@ namespace Magnum { namespace Math { @tparam T Data type See @ref matrix-vector for brief introduction. -@see Magnum::Vector2 +@see Magnum::Vector2, Magnum::Vector2i, Magnum::Vector2ui, Magnum::Vector2d @configurationvalueref{Magnum::Math::Vector2} */ template class Vector2: public Vector<2, T> { @@ -72,20 +81,28 @@ template class Vector2: public Vector<2, T> { inline constexpr static Vector2 yScale(T scale) { return Vector2(T(1), scale); } /** @copydoc Vector::Vector() */ - inline constexpr Vector2() {} + inline constexpr /*implicit*/ Vector2() {} /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector2(T value): Vector<2, T>(value, value) {} - - /** @brief Copy constructor */ - inline constexpr Vector2(const RectangularMatrix<1, 2, T>& other): Vector<2, T>(other) {} + inline constexpr explicit Vector2(T value): Vector<2, T>(value) {} /** * @brief Constructor - * @param x X component - * @param y Y component + * + * @f[ + * \boldsymbol v = \begin{pmatrix} x \\ y \end{pmatrix} + * @f] */ - inline constexpr Vector2(T x, T y): Vector<2, T>(x, y) {} + inline 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) {} + + /** @brief Construct vector from external representation */ + template::from(std::declval()))> inline constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {} + + /** @brief Copy constructor */ + inline 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 */ @@ -93,7 +110,6 @@ template class Vector2: public Vector<2, T> { inline constexpr T y() const { return (*this)[1]; } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 2, Vector2) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector2, 2) diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index 84ff16050..cbab75330 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -1,18 +1,27 @@ #ifndef Magnum_Math_Vector3_h #define Magnum_Math_Vector3_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -20,6 +29,7 @@ */ #include "Vector2.h" +#include "Swizzle.h" namespace Magnum { namespace Math { @@ -27,9 +37,8 @@ namespace Magnum { namespace Math { @brief Three-component vector @tparam T Data type -See @ref matrix-vector for brief introduction. See also Point2D for -homogeneous two-dimensional coordinates. -@see Magnum::Vector3 +See @ref matrix-vector for brief introduction. +@see Magnum::Vector3, Magnum::Vector3i, Magnum::Vector3ui, Magnum::Vector3d @configurationvalueref{Magnum::Math::Vector3} */ template class Vector3: public Vector<3, T> { @@ -40,7 +49,7 @@ template class Vector3: public Vector<3, T> { * Usable for translation or rotation along given axis, for example: * @code * Matrix4::translation(Vector3::xAxis(5.0f)); // same as Matrix4::translation({5.0f, 0.0f, 0.0f}); - * Matrix4::rotation(deg(30.0f), Vector3::xAxis()); // same as Matrix::rotation(deg(30.0f), {1.0f, 0.0f, 0.0f}); + * Matrix4::rotation(30.0_degf, Vector3::xAxis()); // same as Matrix::rotation(30.0_degf, {1.0f, 0.0f, 0.0f}); * @endcode * @see yAxis(), zAxis(), xScale(), Matrix4::right() */ @@ -93,39 +102,48 @@ template class Vector3: public Vector<3, T> { * @brief Cross product * * @f[ + * \boldsymbol a \times \boldsymbol b = * \begin{pmatrix} c_0 \\ c_1 \\ c_2 \end{pmatrix} = * \begin{pmatrix}a_1b_2 - a_2b_1 \\ a_2b_0 - a_0b_2 \\ a_0b_1 - a_1b_0 \end{pmatrix} * @f] */ inline constexpr static Vector3 cross(const Vector3& a, const Vector3& b) { - return Vector3(a[1]*b[2]-a[2]*b[1], - a[2]*b[0]-a[0]*b[2], - a[0]*b[1]-a[1]*b[0]); + 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 Vector3() {} + inline constexpr /*implicit*/ Vector3() {} /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector3(T value): Vector<3, T>(value, value, value) {} - - /** @brief Copy constructor */ - inline constexpr Vector3(const RectangularMatrix<1, 3, T>& other): Vector<3, T>(other) {} + inline constexpr explicit Vector3(T value): Vector<3, T>(value) {} /** * @brief Constructor - * @param x X component - * @param y Y component - * @param z Z component + * + * @f[ + * \boldsymbol v = \begin{pmatrix} x \\ y \\ z \end{pmatrix} + * @f] */ - inline constexpr Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {} + inline constexpr /*implicit*/ Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {} /** * @brief Constructor - * @param xy Two-component vector - * @param z Z component + * + * @f[ + * \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ z \end{pmatrix} + * @f] */ - inline constexpr Vector3(const Vector2& xy, T z): Vector<3, T>(xy[0], xy[1], z) {} + inline 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) {} + + /** @brief Construct vector from external representation */ + template::from(std::declval()))> inline constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {} + + /** @brief Copy constructor */ + inline 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 */ @@ -141,10 +159,9 @@ template class Vector3: public Vector<3, T> { * @see swizzle() */ inline Vector2& xy() { return Vector2::from(Vector<3, T>::data()); } - inline constexpr Vector2 xy() const { return Vector2::from(Vector<3, T>::data()); } /**< @overload */ + inline constexpr const Vector2 xy() const { return {x(), y()}; } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Vector3) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector3, 3) diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index 94a680fac..6e40b12be 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -1,18 +1,27 @@ #ifndef Magnum_Math_Vector4_h #define Magnum_Math_Vector4_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -27,37 +36,44 @@ namespace Magnum { namespace Math { @brief Four-component vector @tparam T Data type -See @ref matrix-vector for brief introduction. See also Point3D for -homogeneous three-dimensional coordinates. -@see Magnum::Vector4 +See @ref matrix-vector for brief introduction. +@see Magnum::Vector4, Magnum::Vector4i, Magnum::Vector4ui, Magnum::Vector4d @configurationvalueref{Magnum::Math::Vector4} */ template class Vector4: public Vector<4, T> { public: /** @copydoc Vector::Vector() */ - inline constexpr Vector4() {} + inline constexpr /*implicit*/ Vector4() {} /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector4(T value): Vector<4, T>(value, value, value, value) {} - - /** @brief Copy constructor */ - inline constexpr Vector4(const RectangularMatrix<1, 4, T>& other): Vector<4, T>(other) {} + inline constexpr explicit Vector4(T value): Vector<4, T>(value) {} /** * @brief Constructor - * @param x X component - * @param y Y component - * @param z Z component - * @param w W component + * + * @f[ + * \boldsymbol v = \begin{pmatrix} x \\ y \\ z \\ w \end{pmatrix} + * @f] */ - inline constexpr Vector4(T x, T y, T z, T w): Vector<4, T>(x, y, z, w) {} + inline constexpr /*implicit*/ Vector4(T x, T y, T z, T w): Vector<4, T>(x, y, z, w) {} /** * @brief Constructor - * @param xyz Three-component vector - * @param w W component + * + * @f[ + * \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ v_z \\ w \end{pmatrix} + * @f] */ - inline constexpr Vector4(const Vector3& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {} + inline 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) {} + + /** @brief Construct vector from external representation */ + template::from(std::declval()))> inline constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {} + + /** @brief Copy constructor */ + inline 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 */ @@ -75,7 +91,7 @@ template class Vector4: public Vector<4, T> { * @see swizzle() */ inline Vector3& xyz() { return Vector3::from(Vector<4, T>::data()); } - inline constexpr Vector3 xyz() const { return Vector3::from(Vector<4, T>::data()); } /**< @overload */ + inline constexpr const Vector3 xyz() const { return {x(), y(), z()}; } /**< @overload */ /** * @brief XY part of the vector @@ -84,10 +100,9 @@ template class Vector4: public Vector<4, T> { * @see swizzle() */ inline Vector2& xy() { return Vector2::from(Vector<4, T>::data()); } - inline constexpr Vector2 xy() const { return Vector2::from(Vector<4, T>::data()); } /**< @overload */ + inline constexpr const Vector2 xy() const { return {x(), y()}; } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Vector4) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index a11fcbd4a..c9c28e39b 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Mesh.h" @@ -20,11 +29,10 @@ #include "Buffer.h" #include "Context.h" #include "Extensions.h" +#include "Implementation/BufferState.h" #include "Implementation/MeshState.h" #include "Implementation/State.h" -using namespace std; - namespace Magnum { Mesh::CreateImplementation Mesh::createImplementation = &Mesh::createImplementationDefault; @@ -36,9 +44,29 @@ Mesh::AttributeIPointerImplementation Mesh::attributeIPointerImplementation = &M Mesh::AttributeLPointerImplementation Mesh::attributeLPointerImplementation = &Mesh::attributePointerImplementationDefault; #endif #endif +Mesh::BindIndexBufferImplementation Mesh::bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationDefault; Mesh::BindImplementation Mesh::bindImplementation = &Mesh::bindImplementationDefault; Mesh::UnbindImplementation Mesh::unbindImplementation = &Mesh::unbindImplementationDefault; +std::size_t Mesh::indexSize(IndexType type) { + switch(type) { + case IndexType::UnsignedByte: return 1; + case IndexType::UnsignedShort: return 2; + case IndexType::UnsignedInt: return 4; + } + + CORRADE_INTERNAL_ASSERT(false); +} + +Mesh::Mesh(Primitive primitive): _primitive(primitive), _vertexCount(0), _indexCount(0) + #ifndef MAGNUM_TARGET_GLES2 + , indexStart(0), indexEnd(0) + #endif + , indexOffset(0), indexType(IndexType::UnsignedInt), indexBuffer(nullptr) +{ + (this->*createImplementation)(); +} + Mesh::~Mesh() { /* Remove current vao from the state */ GLuint& current = Context::current()->state()->mesh->currentVAO; @@ -47,7 +75,11 @@ Mesh::~Mesh() { (this->*destroyImplementation)(); } -Mesh::Mesh(Mesh&& other): vao(other.vao), _primitive(other._primitive), _vertexCount(other._vertexCount), attributes(std::move(other.attributes)) +Mesh::Mesh(Mesh&& other): vao(other.vao), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount) + #ifndef MAGNUM_TARGET_GLES2 + , indexStart(other.indexStart), indexEnd(other.indexEnd) + #endif + , indexOffset(other.indexOffset), indexType(other.indexType), indexBuffer(other.indexBuffer), attributes(std::move(other.attributes)) #ifndef MAGNUM_TARGET_GLES2 , integerAttributes(std::move(other.integerAttributes)) #ifndef MAGNUM_TARGET_GLES @@ -64,6 +96,14 @@ Mesh& Mesh::operator=(Mesh&& other) { vao = other.vao; _primitive = other._primitive; _vertexCount = other._vertexCount; + _indexCount = other._indexCount; + #ifndef MAGNUM_TARGET_GLES2 + indexStart = other.indexStart; + indexEnd = other.indexEnd; + #endif + indexOffset = other.indexOffset; + indexType = other.indexType; + indexBuffer = other.indexBuffer; attributes = std::move(other.attributes); #ifndef MAGNUM_TARGET_GLES2 integerAttributes = std::move(other.integerAttributes); @@ -77,27 +117,41 @@ Mesh& Mesh::operator=(Mesh&& other) { return *this; } -Mesh* Mesh::setVertexCount(GLsizei vertexCount) { - _vertexCount = vertexCount; - attributes.clear(); +Mesh* Mesh::setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) { + indexOffset = offset; + indexType = type; #ifndef MAGNUM_TARGET_GLES2 - integerAttributes.clear(); - #ifndef MAGNUM_TARGET_GLES - longAttributes.clear(); - #endif + indexStart = start; + indexEnd = end; + #else + static_cast(start); + static_cast(end); #endif + (this->*bindIndexBufferImplementation)(buffer); return this; } void Mesh::draw() { - if(!_vertexCount) return; + /* Nothing to draw */ + if(!_vertexCount && !_indexCount) return; + + (this->*bindImplementation)(); - bind(); + /* Non-indexed mesh */ + if(!_indexCount) + glDrawArrays(static_cast(_primitive), 0, _vertexCount); - /** @todo Start at given index */ - glDrawArrays(static_cast(_primitive), 0, _vertexCount); + #ifndef MAGNUM_TARGET_GLES2 + /* Indexed mesh with specified range */ + else if(indexEnd) + glDrawRangeElements(static_cast(_primitive), indexStart, indexEnd, _indexCount, static_cast(indexType), reinterpret_cast(indexOffset)); + #endif - unbind(); + /* Indexed mesh without specified range */ + else + glDrawElements(static_cast(_primitive), _indexCount, static_cast(indexType), reinterpret_cast(indexOffset)); + + (this->*unbindImplementation)(); } void Mesh::bindVAO(GLuint vao) { @@ -110,12 +164,6 @@ void Mesh::bindVAO(GLuint vao) { #endif } -void Mesh::bind() { - CORRADE_ASSERT((_vertexCount != 0) || !attributes.empty(), "Mesh: attributes are bound but vertex count is zero", ); - - (this->*bindImplementation)(); -} - void Mesh::vertexAttribPointer(const Attribute& attribute) { glEnableVertexAttribArray(attribute.location); attribute.buffer->bind(Buffer::Target::Array); @@ -159,6 +207,7 @@ void Mesh::initializeContextBasedFunctionality(Context* context) { attributeLPointerImplementation = &Mesh::attributePointerImplementationVAO; } + bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationVAO; bindImplementation = &Mesh::bindImplementationVAO; unbindImplementation = &Mesh::unbindImplementationVAO; } @@ -185,7 +234,9 @@ void Mesh::destroyImplementationVAO() { #endif } -void Mesh::attributePointerImplementationDefault(const Attribute&) {} +void Mesh::attributePointerImplementationDefault(const Attribute& attribute) { + attributes.push_back(attribute); +} void Mesh::attributePointerImplementationVAO(const Attribute& attribute) { bindVAO(vao); @@ -200,7 +251,9 @@ void Mesh::attributePointerImplementationDSA(const Attribute& attribute) { #endif #ifndef MAGNUM_TARGET_GLES2 -void Mesh::attributePointerImplementationDefault(const IntegerAttribute&) {} +void Mesh::attributePointerImplementationDefault(const IntegerAttribute& attribute) { + integerAttributes.push_back(attribute); +} void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute) { bindVAO(vao); @@ -215,7 +268,9 @@ void Mesh::attributePointerImplementationDSA(const IntegerAttribute& attribute) #endif #ifndef MAGNUM_TARGET_GLES -void Mesh::attributePointerImplementationDefault(const LongAttribute&) {} +void Mesh::attributePointerImplementationDefault(const LongAttribute& attribute) { + longAttributes.push_back(attribute); +} void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) { bindVAO(vao); @@ -229,7 +284,22 @@ void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) { #endif #endif +void Mesh::bindIndexBufferImplementationDefault(Buffer* buffer) { + indexBuffer = buffer; +} + +void Mesh::bindIndexBufferImplementationVAO(Buffer* buffer) { + bindVAO(vao); + + /* Reset ElementArray binding to force explicit glBindBuffer call later */ + /** @todo Do this cleaner way */ + Context::current()->state()->buffer->bindings[Implementation::BufferState::indexForTarget(Buffer::Target::ElementArray)] = 0; + + buffer->bind(Buffer::Target::ElementArray); +} + void Mesh::bindImplementationDefault() { + /* Specify vertex attributes */ for(auto it = attributes.begin(); it != attributes.end(); ++it) vertexAttribPointer(*it); @@ -242,6 +312,9 @@ void Mesh::bindImplementationDefault() { vertexAttribPointer(*it); #endif #endif + + /* Bind index buffer, if the mesh is indexed */ + if(_indexCount) indexBuffer->bind(Buffer::Target::ElementArray); } void Mesh::bindImplementationVAO() { @@ -281,6 +354,18 @@ Debug operator<<(Debug debug, Mesh::Primitive value) { return debug << "Mesh::Primitive::(invalid)"; } + +Debug operator<<(Debug debug, Mesh::IndexType value) { + switch(value) { + #define _c(value) case Mesh::IndexType::value: return debug << "Mesh::IndexType::" #value; + _c(UnsignedByte) + _c(UnsignedShort) + _c(UnsignedInt) + #undef _c + } + + return debug << "Mesh::IndexType::(invalid)"; +} #endif } @@ -300,7 +385,7 @@ std::string ConfigurationValue::toString(Magnum::Mesh:: #undef _c } - return ""; + return {}; } Magnum::Mesh::Primitive ConfigurationValue::fromString(const std::string& stringValue, ConfigurationValueFlags) { @@ -316,4 +401,26 @@ Magnum::Mesh::Primitive ConfigurationValue::fromString( return Magnum::Mesh::Primitive::Points; } +std::string ConfigurationValue::toString(Magnum::Mesh::IndexType value, ConfigurationValueFlags) { + switch(value) { + #define _c(value) case Magnum::Mesh::IndexType::value: return #value; + _c(UnsignedByte) + _c(UnsignedShort) + _c(UnsignedInt) + #undef _c + } + + return {}; +} + +Magnum::Mesh::IndexType ConfigurationValue::fromString(const std::string& stringValue, ConfigurationValueFlags) { + #define _c(value) if(stringValue == #value) return Magnum::Mesh::IndexType::value; + _c(UnsignedByte) + _c(UnsignedShort) + _c(UnsignedInt) + #undef _c + + return Magnum::Mesh::IndexType::UnsignedInt; +} + }} diff --git a/src/Mesh.h b/src/Mesh.h index 4f78a4fcc..7f7d47b8d 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -1,18 +1,27 @@ #ifndef Magnum_Mesh_h #define Magnum_Mesh_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -20,89 +29,198 @@ */ #include -#include +#include +#include #include "AbstractShaderProgram.h" -#include "TypeTraits.h" namespace Magnum { /** -@brief Non-indexed mesh +@brief %Mesh @section Mesh-configuration Mesh configuration -To properly configure mesh, you have to set primitive either in constructor or -using setPrimitive() and call setVertexCount(). Then create vertex buffers and -fill them with vertex data. You can also use MeshTools::interleave() to -conveniently set vertex count and buffer data. At last assign them to mesh and -@ref AbstractShaderProgram::Attribute "shader attributes" using -addVertexBuffer(), addInterleavedVertexBuffer() or addVertexBufferStride(). +You have to specify at least primitive and vertex count using setPrimitive() +and setVertexCount(). Then fill your vertex buffers with data, add them to the +mesh and specify @ref AbstractShaderProgram::Attribute "shader attribute" layout +inside the buffers using addVertexBuffer(), addInterleavedVertexBuffer() or +addVertexBufferStride(). You can also use MeshTools::interleave() in +combination with addInterleavedVertexBuffer() to conveniently fill interleaved +vertex buffer(s). The function itself calls setVertexCount(), so you don't +have to do it again. + +If you have indexed mesh, you need to call setIndexCount() instead of +setVertexCount(). Then fill your index buffer with data and specify its layout +using setIndexBuffer(). You can also use MeshTools::compressIndices() to +conveniently compress the indices, fill the index buffer and configure the +mesh instead of calling setIndexCount() and setIndexBuffer() manually. + +Note that neither vertex buffers nor index buffer is managed (e.g. deleted on +destruction) by the mesh, so you have to manage them on your own. On the other +hand it allows you to use one buffer for more meshes (each mesh for example +configured for different shader) or store data for more meshes in one buffer. -Note that the buffer is not managed (e.g. deleted on destruction) by the mesh, -so you have to manage it on your own. On the other hand it allows you to use -one buffer for more meshes (each mesh for example configured for different -shader) or store more than only vertex data in one buffer. +If the mesh has non-zero index count, it is treated as indexed mesh, otherwise +it is treated as non-indexed mesh. If both index and vertex count is zero, the +mesh is empty and no draw commands are issued when calling draw(). + +@subsection Mesh-configuration-examples Example mesh configuration + +@subsubsection Mesh-configuration-examples-nonindexed Basic non-indexed mesh -Example usage -- filling buffer with position data, configuring the mesh and -assigning the buffer to mesh to use with custom shader: @code +// Custom shader, needing only position data class MyShader: public AbstractShaderProgram { public: - typedef Attribute<0, Point3D> Position; + typedef Attribute<0, Vector3> Position; // ... }; -Buffer* buffer; Mesh* mesh; +Buffer* vertexBuffer; -static constexpr Point3D positions[30] = { +// Fill vertex buffer with position data +static constexpr Vector3 positions[30] = { // ... }; -buffer->setData(positions, Buffer::Usage::StaticDraw); +vertexBuffer->setData(positions, Buffer::Usage::StaticDraw); -mesh->setPrimitve(Mesh::Primitive::Triangles) +// Set primitive and vertex count, add the buffer and specify its layout +mesh->setPrimitive(Mesh::Primitive::Triangles) ->setVertexCount(30) - ->addVertexBuffer(buffer, MyShader::Position()); + ->addVertexBuffer(vertexBuffer, 0, MyShader::Position()); @endcode -Example usage -- creating a plane mesh and assigning buffer with interleaved -vertex attributes for use with Shaders::PhongShader: +@subsubsection Mesh-configuration-examples-nonindexed-phong Interleaved vertex data + @code -Buffer* buffer; +// Non-indexed primitive with positions and normals +Primitives::Plane plane; Mesh* mesh; +Buffer* vertexBuffer; -Primitives::Plane plane; -MeshTools::interleave(mesh, buffer, Buffer::Usage::StaticDraw, *plane.positions(0), *plane.normals(0)); +// Fill vertex buffer with interleaved position and normal data +MeshTools::interleave(mesh, buffer, Buffer::Usage::StaticDraw, + *plane.positions(0), *plane.normals(0)); + +// Set primitive and specify layout of interleaved vertex buffer, vertex count +// has been already set by MeshTools::interleave() +mesh->setPrimitive(plane.primitive()) + ->addInterleavedVertexBuffer(buffer, 0, + Shaders::PhongShader::Position(), + Shaders::PhongShader::Normal()); +@endcode + +@subsubsection Mesh-configuration-examples-indexed-phong Indexed mesh + +@code +// Custom shader +class MyShader: public AbstractShaderProgram { + public: + typedef Attribute<0, Vector3> Position; + + // ... +}; +Buffer *vertexBuffer, *indexBuffer; +Mesh* mesh; + +// Fill vertex buffer with position data +static constexpr Vector3 positions[300] = { + // ... +}; +vertexBuffer->setData(positions, Buffer::Usage::StaticDraw); + +// Fill index buffer with index data +static constexpr GLubyte indices[75] = { + // ... +}; +indexBuffer->setData(indices, Buffer::Usage::StaticDraw); + +// Set primitive, index count, specify the buffers +mesh->setPrimitive(Mesh::Primitive::Triangles) + ->setIndexCount(75) + ->addVertexBuffer(vertexBuffer, 0, MyShader::Position()) + ->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 176, 229); +@endcode + +@code +// Indexed primitive +Primitives::Cube cube; +Buffer *vertexBuffer, *indexBuffer; +Mesh* mesh; + +// Fill vertex buffer with interleaved position and normal data +MeshTools::interleave(mesh, vertexBuffer, Buffer::Usage::StaticDraw, + *cube.positions(0), *cube.normals(0)); + +// Fill index buffer with compressed index data +MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, + *cube.indices()); + +// Set primitive and specify layout of interleaved vertex buffer. Index count +// and index buffer has been already specified by MeshTools::compressIndices(). mesh->setPrimitive(plane.primitive()) - ->addInterleavedVertexBuffer(buffer, 0, Shaders::PhongShader::Position(), Shaders::PhongShader::Normal()); + ->addInterleavedVertexBuffer(vertexBuffer, 0, + Shaders::PhongShader::Position(), + Shaders::PhongShader::Normal()); @endcode -Example usage -- passing color attribute as normalized unsigned byte with BGRA -component ordering (e.g. directly from @ref Trade::TgaImporter "TGA file"): +@subsubsection Mesh-configuration-examples-data-options Specific formats of vertex data + @code +// Custom shader with colors specified as four floating-point values class MyShader: public AbstractShaderProgram { public: + typedef Attribute<0, Vector3> Position; typedef Attribute<1, Color4<>> Color; // ... }; -Buffer* buffer; Mesh* mesh; -mesh->addVertexBuffer(buffer, MyShader::Color(Type::UsignedByte, MyShader::Color::Normalized|MyShader::Color::BGRA)); +// Fill position buffer with positions specified as two-component XY (i.e., +// no Z component, which is meant to be always 0) +Buffer* positionBuffer; +Vector2 positions[30] = { + // ... +}; + +// Specify layout of positions buffer -- only two components, unspecified Z +// component will be automatically set to 0 +mesh->addVertexBuffer(positionBuffer, 0, + MyShader::Position(MyShader::Position::Components::Two)); + +// Fill color buffer with colors specified as four-byte BGRA (e.g. directly +// from TGA file) +Buffer* colorBuffer; +GLubyte colors[4*30] = { + // ... +}; +colorBuffer.setData(colors, Buffer::Usage::StaticDraw); + +// Specify layout of color buffer -- BGRA, each component unsigned byte and we +// want to normalize them from [0, 255] to [0.0f, 1.0f] +mesh->addVertexBuffer(colorBuffer, 0, MyShader::Color( + MyShader::Color::Components::BGRA, + MyShader::Color::DataType::UnsignedByte, + MyShader::Color::DataOption::Normalized)); @endcode @section Mesh-drawing Rendering meshes -Basic workflow is to set up respective shader (see @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" for more infromation) and call Mesh::draw(). +Basic workflow is: bind specific framebuffer for drawing (if needed), set up +respective shader, bind required textures (see +@ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" +for more infromation) and call Mesh::draw(). @section Mesh-performance-optimization Performance optimizations -If @extension{APPLE,vertex_array_object} is supported, VAOs are used instead -of binding the buffers and specifying vertex attribute pointers in each -draw() call. The engine tracks currently bound VAO to avoid unnecessary calls -to @fn_gl{BindVertexArray}. +If @extension{APPLE,vertex_array_object}, OpenGL ES 3.0 or +@es_extension{OES,vertex_array_object} on OpenGL ES 2.0 is supported, VAOs are +used instead of binding the buffers and specifying vertex attribute pointers +in each draw() call. The engine tracks currently bound VAO to avoid +unnecessary calls to @fn_gl{BindVertexArray}. If extension @extension{EXT,direct_state_access} and VAOs are available, DSA functions are used for specifying attribute locations to avoid unnecessary @@ -110,13 +228,16 @@ calls to @fn_gl{BindBuffer} and @fn_gl{BindVertexArray}. See documentation of addVertexBuffer(), addInterleavedVertexBuffer(), addVertexBufferStride() for more information. +If index range is specified in setIndexBuffer(), range-based version of +drawing commands are used on desktop OpenGL and OpenGL ES 3.0. See also draw() +for more information. + @todo Support for indirect draw buffer (OpenGL 4.0, @extension{ARB,draw_indirect}) @todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc. -@todo Allow unbinding all vertex buffers with some function (not as side effect), - similarly to unbinding index buffer in IndexedMesh +@todo test vertex specification & drawing +@todo How to glDrawElementsBaseVertex()/vertex offset -- in draw()? */ class MAGNUM_EXPORT Mesh { - friend class IndexedMesh; friend class Context; Mesh(const Mesh& other) = delete; @@ -153,11 +274,11 @@ class MAGNUM_EXPORT Mesh { * @brief Provoking vertex * * @see setProvokingVertex() - * @requires_gl OpenGL ES behaves always like - * ProvokingMode::%LastVertexConvention. - * @requires_gl32 Extension @extension{ARB,provoking_vertex}. Older + * @requires_gl32 %Extension @extension{ARB,provoking_vertex}. Older * versions behave always like - * ProvokingMode::%LastVertexConvention. + * @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. */ @@ -170,11 +291,11 @@ class MAGNUM_EXPORT Mesh { /** * @brief Set provoking vertex * - * Initial value is ProvokingMode::%LastVertexConvention. + * Initial value is @ref ProvokingVertex "ProvokingVertex::LastVertexConvention". * @see @fn_gl{ProvokingVertex} - * @requires_gl OpenGL ES behaves always like the default. - * @requires_gl32 Extension @extension{ARB,provoking_vertex}. Older + * @requires_gl32 %Extension @extension{ARB,provoking_vertex}. Older * versions behave always like the default. + * @requires_gl OpenGL ES behaves always like the default. */ inline static void setProvokingVertex(ProvokingVertex mode) { glProvokingVertex(static_cast(mode)); @@ -186,9 +307,8 @@ class MAGNUM_EXPORT Mesh { * @brief Polygon mode * * @see setPolygonMode() - * @requires_gl OpenGL ES behaves always like - * PolygonMode::%Fill. See setPrimitive() for possible - * workaround. + * @requires_gl OpenGL ES behaves always like @ref Magnum::Mesh::PolygonMode "PolygonMode::Fill". + * See setPrimitive() for possible workaround. */ enum class PolygonMode: GLenum { /** @@ -213,7 +333,7 @@ class MAGNUM_EXPORT Mesh { /** * @brief Set polygon drawing mode * - * Initial value is `PolygonMode::%Fill`. + * 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. @@ -237,13 +357,15 @@ class MAGNUM_EXPORT Mesh { /** * Offset lines. - * @requires_gl Only PolygonOffset::%Fill is supported. + * @requires_gl Only @ref Magnum::Mesh::PolygonOffsetMode "PolygonOffsetMode::Fill" + * is available in OpenGL ES. */ Line = GL_POLYGON_OFFSET_LINE, /** * Offset points. - * @requires_gl Only PolygonOffset::%Fill is supported. + * @requires_gl Only @ref Magnum::Mesh::PolygonOffsetMode "PolygonOffsetMode::Fill" + * is available in OpenGL ES. */ Point = GL_POLYGON_OFFSET_POINT #endif @@ -268,7 +390,7 @@ class MAGNUM_EXPORT Mesh { * polygon offset for desired polygon modes. * @see @fn_gl{PolygonOffset} */ - inline static void setPolygonOffset(GLfloat factor, GLfloat units) { + inline static void setPolygonOffset(Float factor, Float units) { glPolygonOffset(factor, units); } @@ -278,7 +400,7 @@ class MAGNUM_EXPORT Mesh { * Initial value is `1.0f`. * @see @fn_gl{LineWidth} */ - inline static void setLineWidth(GLfloat width) { + inline static void setLineWidth(Float width) { glLineWidth(width); } @@ -291,7 +413,7 @@ class MAGNUM_EXPORT Mesh { * @requires_gl Set directly in vertex shader using @c gl_PointSize * builtin variable. */ - inline static void setPointSize(GLfloat size) { + inline static void setPointSize(Float size) { glPointSize(size); } @@ -355,6 +477,25 @@ class MAGNUM_EXPORT Mesh { TriangleFan = GL_TRIANGLE_FAN }; + /** + * @brief Index type + * + * @see setIndexBuffer(), indexSize() + */ + enum class IndexType: GLenum { + UnsignedByte = GL_UNSIGNED_BYTE, /**< Unsigned byte */ + UnsignedShort = GL_UNSIGNED_SHORT, /**< Unsigned short */ + + /** + * Unsigned int + * @requires_gles30 %Extension @es_extension{OES,element_index_uint} + */ + UnsignedInt = GL_UNSIGNED_INT + }; + + /** @brief Size of given index type */ + static std::size_t indexSize(IndexType type); + /** * @brief Constructor * @param primitive Primitive type @@ -363,9 +504,7 @@ class MAGNUM_EXPORT Mesh { * @see setPrimitive(), setVertexCount(), @fn_gl{GenVertexArrays} (if * @extension{APPLE,vertex_array_object} is available) */ - inline Mesh(Primitive primitive = Primitive::Triangles): _primitive(primitive), _vertexCount(0) { - (this->*createImplementation)(); - } + explicit Mesh(Primitive primitive = Primitive::Triangles); /** @brief Move constructor */ Mesh(Mesh&& other); @@ -376,7 +515,7 @@ class MAGNUM_EXPORT Mesh { * @see @fn_gl{DeleteVertexArrays} (if * @extension{APPLE,vertex_array_object} is available) */ - virtual ~Mesh(); + ~Mesh(); /** @brief Move assignment */ Mesh& operator=(Mesh&& other); @@ -389,6 +528,8 @@ class MAGNUM_EXPORT Mesh { * @return Pointer to self (for method chaining) * * Default is @ref Primitive "Primitive::Triangles". + * @see setVertexCount(), addVertexBuffer(), + * addInterleavedVertexBuffer(), addVertexBufferStride() */ inline Mesh* setPrimitive(Primitive primitive) { _primitive = primitive; @@ -396,27 +537,43 @@ class MAGNUM_EXPORT Mesh { } /** @brief Vertex count */ - inline GLsizei vertexCount() const { return _vertexCount; } + inline Int vertexCount() const { return _vertexCount; } /** * @brief Set vertex count * @return Pointer to self (for method chaining) * * Default is zero. - * @attention All bound attributes are reset after calling this - * function, so if your mesh has any vertex attributes, be sure - * to call addVertexBuffer()/addInterleavedVertexBuffer() - * afterwards. - * @see MeshTools::interleave() + * @see setPrimitive(), addVertexBuffer(), addInterleavedVertexBuffer(), + * addVertexBufferStride(), MeshTools::interleave() + */ + inline Mesh* setVertexCount(Int vertexCount) { + _vertexCount = vertexCount; + return this; + } + + /** @brief Index count */ + inline Int indexCount() const { return _indexCount; } + + /** + * @brief Set index count + * @return Pointer to self (for method chaining) + * + * Default is zero. + * @see setIndexBuffer(), MeshTools::compressIndices() */ - Mesh* setVertexCount(GLsizei vertexCount); + inline Mesh* setIndexCount(Int count) { + _indexCount = count; + return this; + } /** * @brief Add buffer with non-interleaved vertex attributes for use with given shader + * @return Pointer to self (for method chaining) * * Attribute list is combination of * @ref AbstractShaderProgram::Attribute "attribute definitions" - * (specified in implementation of given shader) and offsets between + * (specified in implementation of given shader) and gaps between * attribute arrays. * * See @ref Mesh-configuration "class documentation" for simple usage @@ -430,7 +587,7 @@ class MAGNUM_EXPORT Mesh { * Mesh* mesh; * Buffer* buffer; * mesh->addVertexBuffer(buffer, - * 35, // skip other data + * 35, // offset of the data * Shaders::PhongShader::Position(), // position array * sizeof(Vector2)*mesh->vertexCount(), // skip texture coordinate array * Shaders::PhongShader::Normal()); // normal array @@ -444,28 +601,32 @@ class MAGNUM_EXPORT Mesh { * mesh->vertexCount(), Shaders::PhongShader::Normal()); * @endcode * - * @attention Non-zero vertex count must be set before calling this - * function. + * @attention If specifying more than one attribute the actual vertex + * count must be set before calling this function. Otherwise + * vertex data positions in the buffer will be miscalculated. * @attention The buffer passed as parameter is not managed by the * mesh, you must ensure it will exist for whole lifetime of the * mesh and delete it afterwards. * * @see addInterleavedVertexBuffer(), addVertexBufferStride(), - * @fn_gl{BindVertexArray}, @fn_gl{EnableVertexAttribArray}, - * @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer} or + * setPrimitive(), setVertexCount(), @fn_gl{BindVertexArray}, + * @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer}, + * @fn_gl{VertexAttribPointer} or * @fn_gl_extension{EnableVertexArrayAttrib,EXT,direct_state_access}, * @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access} * if @extension{APPLE,vertex_array_object} is available */ - template inline Mesh* addVertexBuffer(Buffer* buffer, const T&... attributes) { - CORRADE_ASSERT(_vertexCount != 0, "Mesh: vertex count must be set before binding attributes", this); + 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, 0, attributes...); + addVertexBufferInternal(buffer, offset, attributes...); return this; } /** * @brief Add buffer with interleaved vertex attributes for use with given shader + * @return Pointer to self (for method chaining) * * Parameter @p offset is offset of the interleaved array from the * beginning, attribute list is combination of @@ -486,7 +647,7 @@ class MAGNUM_EXPORT Mesh { * Buffer* buffer; * mesh->addInterleavedVertexBuffer(buffer, * 35, // skip other data - * sizeof(GLfloat), // skip vertex weight + * sizeof(Float), // skip vertex weight * Shaders::PhongShader::Position(), // vertex position * sizeof(Vector2), // skip texture coordinates * Shaders::PhongShader::Normal()); // vertex normal @@ -497,14 +658,14 @@ class MAGNUM_EXPORT Mesh { * between vertex attributes: * @code * GLsizei stride = // size of one vertex - * sizeof(GLfloat) + + * sizeof(Float) + * sizeof(Shaders::PhongShader::Position::Type) + * sizeof(Vector2) + * sizeof(Shaders::PhongShader::Normal::Type); * - * mesh->addVertexBufferStride(buffer, 35 + sizeof(GLfloat), + * mesh->addVertexBufferStride(buffer, 35 + sizeof(Float), * stride, Shaders::PhongShader::Position()); - * ->addVertexBufferStride(buffer, 35 + sizeof(GLfloat) + + * ->addVertexBufferStride(buffer, 35 + sizeof(Float) + * sizeof(Shaders::PhongShader::Position::Type) + sizeof(Vector2), * stride, Shaders::PhongShader::Normal()); * @endcode @@ -513,9 +674,10 @@ class MAGNUM_EXPORT Mesh { * mesh, you must ensure it will exist for whole lifetime of the * mesh and delete it afterwards. * - * @see addVertexBufferStride(), addVertexBuffer(), - * @fn_gl{BindVertexArray}, @fn_gl{EnableVertexAttribArray}, - * @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer} or + * @see addVertexBufferStride(), addVertexBuffer(), setPrimitive(), + * setVertexCount(), @fn_gl{BindVertexArray}, + * @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer}, + * @fn_gl{VertexAttribPointer} or * @fn_gl_extension{EnableVertexArrayAttrib,EXT,direct_state_access}, * @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access} * if @extension{APPLE,vertex_array_object} is available @@ -527,14 +689,54 @@ class MAGNUM_EXPORT Mesh { /** * @brief Add buffer with interleaved vertex attributes for use with given shader + * @return Pointer to self (for method chaining) * * See addInterleavedVertexBuffer() for more information. */ - template inline Mesh* addVertexBufferStride(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute) { + template inline Mesh* addVertexBufferStride(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute) { addInterleavedVertexBufferInternal(buffer, offset, stride, attribute); return this; } + /** + * @brief Set index buffer + * @param buffer Index buffer + * @param offset Offset into the buffer + * @param type Index data type + * @param start Minimum array index contained in the buffer + * @param end Maximum array index contained in the buffer + * @return Pointer to self (for method chaining) + * + * The smaller range is specified with @p start and @p end the less + * memory operations are needed (and possibly some optimizations), + * improving draw performance. Specifying `0` for both parameters + * behaves the same as setIndexBuffer(Buffer*, GLintptr, IndexType). + * On OpenGL ES 2.0 this function behaves always as + * setIndexBuffer(Buffer*, GLintptr, IndexType), as this functionality + * is not available there. + * @see setIndexCount(), MeshTools::compressIndices(), + * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if + * @extension{APPLE,vertex_array_object} is available) + */ + Mesh* setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end); + + /** + * @brief Set index buffer + * @param buffer Index buffer + * @param offset Offset into the buffer + * @param type Index data type + * @return Pointer to self (for method chaining) + * + * Prefer to use setIndexBuffer(Buffer*, GLintptr, IndexType, UnsignedInt, UnsignedInt) + * for better performance. + * @see setIndexCount(), MeshTools::compressIndices(), + * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if + * @extension{APPLE,vertex_array_object} is available) + */ + inline Mesh* setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type) { + return setIndexBuffer(buffer, offset, type, 0, 0); + } + /** * @brief Draw the mesh * @@ -544,9 +746,9 @@ class MAGNUM_EXPORT Mesh { * @see @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer}, * @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray} * or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object} - * is available), @fn_gl{DrawArrays} + * is available), @fn_gl{DrawArrays} or @fn_gl{DrawElements}/@fn_gl{DrawRangeElements}. */ - virtual void draw(); + void draw(); private: #ifndef DOXYGEN_GENERATING_OUTPUT @@ -586,11 +788,11 @@ class MAGNUM_EXPORT Mesh { static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); /* Adding non-interleaved vertex attributes */ - template inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { + template inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { addVertexAttribute(buffer, attribute, offset, 0); /* Add size of this attribute array to offset for next attribute */ - addVertexBufferInternal(buffer, offset+TypeTraits::count()*TypeTraits::size()*_vertexCount, attributes...); + addVertexBufferInternal(buffer, offset+attribute.dataSize()*_vertexCount, attributes...); } template inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, GLintptr gap, const T&... attributes) { /* Add the gap to offset for next attribute */ @@ -599,8 +801,8 @@ class MAGNUM_EXPORT Mesh { inline void addVertexBufferInternal(Buffer*, GLintptr) {} /* Computing stride of interleaved vertex attributes */ - template inline static GLsizei strideOfInterleaved(const AbstractShaderProgram::Attribute&, const U&... attributes) { - return TypeTraits::count()*TypeTraits::size() + strideOfInterleaved(attributes...); + template inline static GLsizei strideOfInterleaved(const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { + return attribute.dataSize() + strideOfInterleaved(attributes...); } template inline static GLsizei strideOfInterleaved(GLintptr gap, const T&... attributes) { return gap + strideOfInterleaved(attributes...); @@ -608,11 +810,11 @@ class MAGNUM_EXPORT Mesh { inline static GLsizei strideOfInterleaved() { return 0; } /* Adding interleaved vertex attributes */ - template inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { + template inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { addVertexAttribute(buffer, attribute, offset, stride); /* Add size of this attribute to offset for next attribute */ - addInterleavedVertexBufferInternal(buffer, offset+TypeTraits::count()*TypeTraits::size(), stride, attributes...); + addInterleavedVertexBufferInternal(buffer, offset+attribute.dataSize(), stride, attributes...); } template inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) { /* Add the gap to offset for next attribute */ @@ -620,62 +822,48 @@ class MAGNUM_EXPORT Mesh { } inline void addInterleavedVertexBufferInternal(Buffer*, GLsizei, GLintptr) {} - template inline void addVertexAttribute(typename std::enable_if::AttributeType, GLfloat>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { - for(GLuint i = 0; i != Implementation::Attribute::vectorCount(); ++i) { - attributes.push_back(Attribute{ + template inline void addVertexAttribute(typename std::enable_if::Type, Float>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + for(UnsignedInt i = 0; i != Implementation::Attribute::vectorCount(); ++i) + (this->*attributePointerImplementation)(Attribute{ buffer, location+i, - Implementation::Attribute::size(attribute.dataOptions()), + static_cast(attribute.components()), static_cast(attribute.dataType()), - !!(attribute.dataOptions() & AbstractShaderProgram::Attribute::DataOption::Normalized), + bool(attribute.dataOptions() & AbstractShaderProgram::Attribute::DataOption::Normalized), offset, stride }); - } - - (this->*attributePointerImplementation)(attributes.back()); } #ifndef MAGNUM_TARGET_GLES2 - template inline void addVertexAttribute(typename std::enable_if::AttributeType>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { - integerAttributes.push_back(IntegerAttribute{ + template inline void addVertexAttribute(typename std::enable_if::Type>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + (this->*attributeIPointerImplementation)(IntegerAttribute{ buffer, location, - Implementation::Attribute::size(), + static_cast(attribute.components()), static_cast(attribute.dataType()), offset, stride }); - - (this->*attributeIPointerImplementation)(integerAttributes.back()); } #ifndef MAGNUM_TARGET_GLES - template inline void addVertexAttribute(typename std::enable_if::AttributeType, GLdouble>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { - for(GLuint i = 0; i != Implementation::Attribute::vectorCount(); ++i) { - longAttributes.push_back(LongAttribute{ + template inline void addVertexAttribute(typename std::enable_if::Type, Double>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + for(UnsignedInt i = 0; i != Implementation::Attribute::vectorCount(); ++i) + (this->*attributeLPointerImplementation)(LongAttribute{ buffer, location+i, - Implementation::Attribute::size(), + static_cast(attribute.components()), static_cast(attribute.dataType()), offset, stride }); - - (this->*attributeLPointerImplementation)(longAttributes.back()); - } } #endif #endif static void MAGNUM_LOCAL bindVAO(GLuint vao); - void MAGNUM_LOCAL bind(); - - inline void unbind() { - (this->*unbindImplementation)(); - } - void MAGNUM_LOCAL vertexAttribPointer(const Attribute& attribute); #ifndef MAGNUM_TARGET_GLES2 void MAGNUM_LOCAL vertexAttribPointer(const IntegerAttribute& attribute); @@ -687,7 +875,7 @@ class MAGNUM_EXPORT Mesh { typedef void(Mesh::*CreateImplementation)(); void MAGNUM_LOCAL createImplementationDefault(); void MAGNUM_LOCAL createImplementationVAO(); - static CreateImplementation createImplementation; + static MAGNUM_LOCAL CreateImplementation createImplementation; typedef void(Mesh::*DestroyImplementation)(); void MAGNUM_LOCAL destroyImplementationDefault(); @@ -720,6 +908,11 @@ class MAGNUM_EXPORT Mesh { #endif #endif + typedef void(Mesh::*BindIndexBufferImplementation)(Buffer*); + void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer* buffer); + void MAGNUM_LOCAL bindIndexBufferImplementationVAO(Buffer* buffer); + static MAGNUM_LOCAL BindIndexBufferImplementation bindIndexBufferImplementation; + typedef void(Mesh::*BindImplementation)(); void MAGNUM_LOCAL bindImplementationDefault(); void MAGNUM_LOCAL bindImplementationVAO(); @@ -732,7 +925,13 @@ class MAGNUM_EXPORT Mesh { GLuint vao; Primitive _primitive; - GLsizei _vertexCount; + Int _vertexCount, _indexCount; + #ifndef MAGNUM_TARGET_GLES2 + UnsignedInt indexStart, indexEnd; + #endif + GLintptr indexOffset; + IndexType indexType; + Buffer* indexBuffer; std::vector attributes; #ifndef MAGNUM_TARGET_GLES2 @@ -746,12 +945,17 @@ class MAGNUM_EXPORT Mesh { /** @debugoperator{Magnum::Mesh} */ Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::Primitive value); +/** @debugoperator{Magnum::Mesh} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::IndexType value); + } namespace Corrade { namespace Utility { /** @configurationvalue{Magnum::Mesh} */ template<> struct MAGNUM_EXPORT ConfigurationValue { + ConfigurationValue() = delete; + /** * @brief Writes enum value as string * @@ -767,6 +971,25 @@ template<> struct MAGNUM_EXPORT ConfigurationValue { static Magnum::Mesh::Primitive fromString(const std::string& stringValue, ConfigurationValueFlags); }; +/** @configurationvalue{Magnum::Mesh} */ +template<> struct MAGNUM_EXPORT ConfigurationValue { + ConfigurationValue() = delete; + + /** + * @brief Write enum value as string + * + * If the value is invalid, returns empty string. + */ + static std::string toString(Magnum::Mesh::IndexType value, ConfigurationValueFlags); + + /** + * @brief Read enum value as string + * + * If the value is invalid, returns @ref Magnum::Mesh::IndexType "Mesh::IndexType::UnsignedInt". + */ + static Magnum::Mesh::IndexType fromString(const std::string& stringValue, ConfigurationValueFlags); +}; + }} #endif diff --git a/src/MeshTools/CMakeLists.txt b/src/MeshTools/CMakeLists.txt index 7384e1c8f..b28bd7c77 100644 --- a/src/MeshTools/CMakeLists.txt +++ b/src/MeshTools/CMakeLists.txt @@ -1,7 +1,37 @@ +# +# 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. +# + # Files shared between main library and unit test library set(MagnumMeshTools_SRCS CompressIndices.cpp Tipsify.cpp) + +# Files compiled with different flags for main library and unit test library +set(MagnumMeshTools_GracefulAssert_SRCS + FlipNormals.cpp + GenerateFlatNormals.cpp) + set(MagnumMeshTools_HEADERS Clean.h CombineIndexedArrays.h @@ -14,50 +44,27 @@ set(MagnumMeshTools_HEADERS Transform.h magnumMeshToolsVisibility.h) -if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(MagnumMeshToolsObjects OBJECT ${MagnumMeshTools_SRCS}) -endif() # 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 -if(NOT CMAKE_NO_OBJECT_TARGET) - set_target_properties(MagnumMeshToolsObjects PROPERTIES COMPILE_FLAGS "-DMagnumMeshToolsObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") -endif() - -# Files compiled with different flags for main library and unit test library -set(MagnumMeshTools_GracefulAssert_SRCS - FlipNormals.cpp - GenerateFlatNormals.cpp) +add_library(MagnumMeshToolsObjects OBJECT ${MagnumMeshTools_SRCS}) +set_target_properties(MagnumMeshToolsObjects PROPERTIES COMPILE_FLAGS "-DMagnumMeshToolsObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") # Main library -if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(MagnumMeshTools SHARED - $ - ${MagnumMeshTools_GracefulAssert_SRCS}) -else() - add_library(MagnumMeshTools SHARED - ${MagnumMeshTools_SRCS} - ${MagnumMeshTools_GracefulAssert_SRCS}) -endif() +add_library(MagnumMeshTools SHARED + $ + ${MagnumMeshTools_GracefulAssert_SRCS}) target_link_libraries(MagnumMeshTools Magnum) install(TARGETS MagnumMeshTools DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumMeshTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/MeshTools) if(BUILD_TESTS) - enable_testing() - # Library with graceful assert for testing - if(NOT CMAKE_NO_OBJECT_TARGET) - add_library(MagnumMeshToolsTestLib SHARED - $ - ${MagnumMeshTools_GracefulAssert_SRCS}) - else() - add_library(MagnumMeshToolsTestLib SHARED - ${MagnumMeshTools_SRCS} - ${MagnumMeshTools_GracefulAssert_SRCS}) - endif() - set_target_properties(MagnumMeshToolsTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) + add_library(MagnumMeshToolsTestLib SHARED + $ + ${MagnumMeshTools_GracefulAssert_SRCS}) + set_target_properties(MagnumMeshToolsTestLib PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumMeshTools_EXPORTS") target_link_libraries(MagnumMeshToolsTestLib Magnum) add_subdirectory(Test) diff --git a/src/MeshTools/Clean.h b/src/MeshTools/Clean.h index 47dde00e7..cc4504e08 100644 --- a/src/MeshTools/Clean.h +++ b/src/MeshTools/Clean.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_Clean_h #define Magnum_MeshTools_Clean_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -24,7 +33,6 @@ #include #include "Math/Vector.h" -#include "TypeTraits.h" namespace Magnum { namespace MeshTools { @@ -33,9 +41,9 @@ namespace Implementation { template class Clean { public: - inline Clean(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} + inline Clean(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} - void operator()(typename Vertex::Type epsilon = TypeTraits::epsilon()) { + void operator()(typename Vertex::Type epsilon = Math::TypeTraits::epsilon()) { if(indices.empty()) return; /* Get mesh bounds */ @@ -111,12 +119,12 @@ template class Clean { }; struct HashedVertex { - std::uint32_t oldIndex, newIndex; + UnsignedInt oldIndex, newIndex; - HashedVertex(std::uint32_t oldIndex, std::uint32_t newIndex): oldIndex(oldIndex), newIndex(newIndex) {} + HashedVertex(UnsignedInt oldIndex, UnsignedInt newIndex): oldIndex(oldIndex), newIndex(newIndex) {} }; - std::vector& indices; + std::vector& indices; std::vector& vertices; }; @@ -140,7 +148,7 @@ Removes duplicate vertices from the mesh. @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 = TypeTraits::epsilon()) { +template inline void clean(std::vector& indices, std::vector& vertices, typename Vertex::Type epsilon = Math::TypeTraits::epsilon()) { Implementation::Clean(indices, vertices)(epsilon); } diff --git a/src/MeshTools/CombineIndexedArrays.h b/src/MeshTools/CombineIndexedArrays.h index a5d229614..1650b443d 100644 --- a/src/MeshTools/CombineIndexedArrays.h +++ b/src/MeshTools/CombineIndexedArrays.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_CombineIndexedArrays_h #define Magnum_MeshTools_CombineIndexedArrays_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -33,17 +42,17 @@ namespace Implementation { class CombineIndexedArrays { public: - template std::vector operator()(const std::tuple&, std::vector&>&... indexedArrays) { + template std::vector operator()(const std::tuple&, std::vector&>&... indexedArrays) { /* Compute index count */ std::size_t _indexCount = indexCount(std::get<0>(indexedArrays)...); /* Resulting index array */ - std::vector result; + std::vector result; result.resize(_indexCount); std::iota(result.begin(), result.end(), 0); /* All index combinations */ - std::vector > indexCombinations(_indexCount); + std::vector > indexCombinations(_indexCount); writeCombinedIndices(indexCombinations, std::get<0>(indexedArrays)...); /* Make the combinations unique */ @@ -56,13 +65,13 @@ class CombineIndexedArrays { } private: - template inline static std::size_t indexCount(const std::vector& first, const std::vector&... next) { + template inline 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(); } - template static void writeCombinedIndices(std::vector>& output, const std::vector& first, const std::vector&... next) { + template static void writeCombinedIndices(std::vector>& output, const std::vector& first, const std::vector&... next) { /* Copy the data to output */ for(std::size_t i = 0; i != output.size(); ++i) output[i][size-sizeof...(next)-1] = first[i]; @@ -70,7 +79,7 @@ class CombineIndexedArrays { writeCombinedIndices(output, next...); } - template static void writeCombinedArrays(const std::vector>& combinedIndices, std::vector& first, std::vector&... next) { + template static void writeCombinedArrays(const std::vector>& combinedIndices, std::vector& first, std::vector&... next) { /* Rewrite output array */ std::vector output; for(std::size_t i = 0; i != combinedIndices.size(); ++i) @@ -82,8 +91,8 @@ 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>&) {} + template inline static void writeCombinedIndices(std::vector>&) {} + template inline static void writeCombinedArrays(const std::vector>&) {} }; } @@ -92,7 +101,7 @@ class CombineIndexedArrays { /** @brief Combine indexed arrays @param[in,out] indexedArrays Index and attribute arrays -@return Array with resulting indices +@return %Array with resulting indices When you have e.g. vertex, normal and texture array, each indexed with different indices, you can use this function to combine them to use the same @@ -105,13 +114,13 @@ avoid explicit verbose specification of tuple type, you can write it with help of some STL functions like shown below. Also if one index array is shader by more than one attribute array, just pass the index array more times. Example: @code -std::vector vertexIndices; -std::vector positions; -std::vector normalTextureIndices; +std::vector vertexIndices; +std::vector positions; +std::vector normalTextureIndices; std::vector normals; std::vector textureCoordinates; -std::vector indices = MeshTools::combineIndexedArrays( +std::vector indices = MeshTools::combineIndexedArrays( std::make_tuple(std::cref(vertexIndices), std::ref(positions)), std::make_tuple(std::cref(normalTextureIndices), std::ref(normals)), std::make_tuple(std::cref(normalTextureIndices), std::ref(textureCoordinates)) @@ -120,14 +129,12 @@ std::vector indices = MeshTools::combineIndexedArrays( `positions`, `normals` and `textureCoordinates` will then contain combined attributes indexed with `indices`. -@attention All index arrays should have the same size, otherwise zero-length - output is generated. - -@internal Implementation note: It's done using tuples because it is more clear - which parameter is index array and which is attribute array, mainly when - both are of the same type. +@attention The function expects that all arrays have the same size. */ -template std::vector combineIndexedArrays(const std::tuple&, std::vector&>&... indexedArrays) { +/* Implementation note: It's done using tuples because it is more clear which + parameter is index array and which is attribute array, mainly when both are + of the same type. */ +template std::vector combineIndexedArrays(const std::tuple&, std::vector&>&... indexedArrays) { return Implementation::CombineIndexedArrays()(indexedArrays...); } diff --git a/src/MeshTools/CompressIndices.cpp b/src/MeshTools/CompressIndices.cpp index f507bdf64..2506fb346 100644 --- a/src/MeshTools/CompressIndices.cpp +++ b/src/MeshTools/CompressIndices.cpp @@ -1,68 +1,91 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CompressIndices.h" #include -#include #include -#include "IndexedMesh.h" -#include "SizeTraits.h" - -using namespace std; +#include "Math/Functions.h" namespace Magnum { namespace MeshTools { #ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - -std::tuple CompressIndices::operator()() const { - #ifndef CORRADE_GCC44_COMPATIBILITY - return SizeBasedCall(*std::max_element(indices.begin(), indices.end()))(indices); - #else - return SizeBasedCall, Compressor>(*std::max_element(indices.begin(), indices.end()))(indices); - #endif +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 inline std::tuple compress(const std::vector& indices) { + char* buffer = new char[indices.size()*sizeof(T)]; + for(std::size_t i = 0; i != indices.size(); ++i) { + T index = static_cast(indices[i]); + std::memcpy(buffer+i*sizeof(T), &index, sizeof(T)); + } + + return std::make_tuple(indices.size(), indexType(), buffer); } -void CompressIndices::operator()(IndexedMesh* mesh, Buffer* buffer, Buffer::Usage usage) const { - size_t indexCount; - Type indexType; - char* data; - std::tie(indexCount, indexType, data) = operator()(); +std::tuple compressIndicesInternal(const std::vector& indices, UnsignedInt max) { + switch(Math::log(256, max)) { + case 0: + return compress(indices); + case 1: + return compress(indices); + case 2: + case 3: + return compress(indices); + + default: + CORRADE_ASSERT(false, "MeshTools::compressIndices(): no type able to index" << max << "elements.", {}); + } +} - mesh->setIndexBuffer(buffer) - ->setIndexType(indexType) - ->setIndexCount(indices.size()); - buffer->setData(indexCount*TypeInfo::sizeOf(indexType), data, usage); +} +#endif - delete[] data; +std::tuple compressIndices(const std::vector& indices) { + return compressIndicesInternal(indices, *std::max_element(indices.begin(), indices.end())); } -template std::tuple CompressIndices::Compressor::run(const std::vector& indices) { - /* Create smallest possible version of index buffer */ - char* buffer = new char[indices.size()*sizeof(IndexType)]; - for(size_t i = 0; i != indices.size(); ++i) { - IndexType index = indices[i]; - memcpy(buffer+i*sizeof(IndexType), reinterpret_cast(&index), sizeof(IndexType)); - } +void compressIndices(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector& indices) { + auto minmax = std::minmax_element(indices.begin(), indices.end()); - return std::make_tuple(indices.size(), TypeTraits::indexType(), buffer); -} + /** @todo Performance hint when range can be represented by smaller value? */ + std::size_t indexCount; + Mesh::IndexType indexType; + char* data; + std::tie(indexCount, indexType, data) = compressIndicesInternal(indices, *minmax.second); + + mesh->setIndexCount(indices.size()) + ->setIndexBuffer(buffer, 0, indexType, *minmax.first, *minmax.second); + buffer->setData(indexCount*Mesh::indexSize(indexType), data, usage); + + delete[] data; } -#endif }} diff --git a/src/MeshTools/CompressIndices.h b/src/MeshTools/CompressIndices.h index 34ccb7991..80cd544ef 100644 --- a/src/MeshTools/CompressIndices.h +++ b/src/MeshTools/CompressIndices.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_CompressIndices_h #define Magnum_MeshTools_CompressIndices_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,34 +31,12 @@ #include #include "Buffer.h" -#include "TypeTraits.h" +#include "Mesh.h" #include "magnumMeshToolsVisibility.h" namespace Magnum { namespace MeshTools { -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - -class MAGNUM_MESHTOOLS_EXPORT CompressIndices { - public: - CompressIndices(const std::vector& indices): indices(indices) {} - - std::tuple operator()() const; - - void operator()(IndexedMesh* mesh, Buffer* buffer, Buffer::Usage usage) const; - - private: - struct Compressor { - template static std::tuple run(const std::vector& indices); - }; - - const std::vector& indices; -}; - -} -#endif - /** @brief Compress vertex indices @param indices Index array @@ -63,20 +50,18 @@ sufficient. Size of the buffer can be computed from index count and type, as shown below. Example usage: @code std::size_t indexCount; -Type indexType; +Mesh::IndexType indexType; char* data; std::tie(indexCount, indexType, data) = MeshTools::compressIndices(indices); -std::size_t dataSize = indexCount*TypeInfo::sizeOf(indexType); +std::size_t dataSize = indexCount*Mesh::indexSize(indexType); // ... delete[] data; @endcode -See also compressIndices(IndexedMesh*, Buffer::Usage, const std::vector&), +See also compressIndices(Mesh*, Buffer*, Buffer::Usage, const std::vector&), which writes the compressed data directly into index buffer of given mesh. */ -inline std::tuple compressIndices(const std::vector& indices) { - return Implementation::CompressIndices{indices}(); -} +std::tuple MAGNUM_MESHTOOLS_EXPORT compressIndices(const std::vector& indices); /** @brief Compress vertex indices and write them to index buffer @@ -85,17 +70,14 @@ inline std::tuple compressIndices(const std::vector&), but this -function writes the output to given index buffer and updates index count and -type in the mesh accordingly, so you don't have to call -IndexedMesh::setIndexBuffer(), IndexedMesh::setIndexCount() and -IndexedMesh::setIndexType() on your own. +The same as compressIndices(const std::vector&), but this +function writes the output to given buffer, updates index count and specifies +index buffer with proper index range in the mesh, so you don't have to call +Mesh::setIndexCount() and Mesh::setIndexBuffer() on your own. @see MeshTools::interleave() */ -inline void compressIndices(IndexedMesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector& indices) { - return Implementation::CompressIndices{indices}(mesh, buffer, usage); -} +void MAGNUM_MESHTOOLS_EXPORT compressIndices(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector& indices); }} diff --git a/src/MeshTools/FlipNormals.cpp b/src/MeshTools/FlipNormals.cpp index acbc98d27..25776a537 100644 --- a/src/MeshTools/FlipNormals.cpp +++ b/src/MeshTools/FlipNormals.cpp @@ -1,34 +1,41 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "FlipNormals.h" #include "Math/Vector3.h" -using namespace std; - namespace Magnum { namespace MeshTools { -void flipFaceWinding(vector& indices) { +void flipFaceWinding(std::vector& indices) { CORRADE_ASSERT(!(indices.size()%3), "MeshTools::flipNormals(): index count is not divisible by 3!", ); - for(size_t i = 0; i != indices.size(); i += 3) - swap(indices[i+1], indices[i+2]); + for(std::size_t i = 0; i != indices.size(); i += 3) + std::swap(indices[i+1], indices[i+2]); } -void flipNormals(vector& normals) { +void flipNormals(std::vector& normals) { for(auto it = normals.begin(); it != normals.end(); ++it) *it = -*it; } diff --git a/src/MeshTools/FlipNormals.h b/src/MeshTools/FlipNormals.h index 98d71eb08..6bdbe705b 100644 --- a/src/MeshTools/FlipNormals.h +++ b/src/MeshTools/FlipNormals.h @@ -1,25 +1,33 @@ #ifndef Magnum_MeshTools_FlipNormals_h #define Magnum_MeshTools_FlipNormals_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::flipNormals() */ -#include #include #include "Magnum.h" @@ -31,15 +39,15 @@ namespace Magnum { namespace MeshTools { /** @brief Flip face winding -The same as flipNormals(std::vector&, std::vector&), +The same as flipNormals(std::vector&, std::vector&), but flips only face winding. */ -void MAGNUM_MESHTOOLS_EXPORT flipFaceWinding(std::vector& indices); +void MAGNUM_MESHTOOLS_EXPORT flipFaceWinding(std::vector& indices); /** @brief Flip mesh normals -The same as flipNormals(std::vector&, std::vector&), +The same as flipNormals(std::vector&, std::vector&), but flips only normals, not face winding. */ void MAGNUM_MESHTOOLS_EXPORT flipNormals(std::vector& normals); @@ -56,7 +64,7 @@ flipFaceWinding(), which flip normals or face winding only. @attention The function requires the mesh to have triangle faces, thus index count must be divisible by 3. */ -inline void flipNormals(std::vector& indices, std::vector& normals) { +inline void flipNormals(std::vector& indices, std::vector& normals) { flipFaceWinding(indices); flipNormals(normals); } diff --git a/src/MeshTools/GenerateFlatNormals.cpp b/src/MeshTools/GenerateFlatNormals.cpp index 918d19d68..64e152d1c 100644 --- a/src/MeshTools/GenerateFlatNormals.cpp +++ b/src/MeshTools/GenerateFlatNormals.cpp @@ -1,38 +1,45 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "GenerateFlatNormals.h" -#include "Math/Point3D.h" +#include "Math/Vector3.h" #include "MeshTools/Clean.h" -using namespace std; - namespace Magnum { namespace MeshTools { -tuple, vector> generateFlatNormals(const vector& indices, const vector& positions) { - CORRADE_ASSERT(!(indices.size()%3), "MeshTools::generateFlatNormals(): index count is not divisible by 3!", (tuple, vector>())); +std::tuple, std::vector> generateFlatNormals(const std::vector& indices, const std::vector& positions) { + CORRADE_ASSERT(!(indices.size()%3), "MeshTools::generateFlatNormals(): index count is not divisible by 3!", (std::tuple, std::vector>())); /* Create normal for every triangle (assuming counterclockwise winding) */ - vector normalIndices; + std::vector normalIndices; normalIndices.reserve(indices.size()); - vector normals; + std::vector normals; normals.reserve(indices.size()/3); - for(size_t i = 0; i != indices.size(); i += 3) { - Vector3 normal = Vector3::cross(positions[indices[i+2]].xyz()-positions[indices[i+1]].xyz(), - positions[indices[i]].xyz()-positions[indices[i+1]].xyz()).normalized(); + for(std::size_t i = 0; i != indices.size(); i += 3) { + Vector3 normal = Vector3::cross(positions[indices[i+2]]-positions[indices[i+1]], + positions[indices[i]]-positions[indices[i+1]]).normalized(); /* Use the same normal for all three vertices of the face */ normalIndices.push_back(normals.size()); @@ -42,8 +49,8 @@ tuple, vector> generateFlatNormals(const vector - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::generateFlatNormals() */ -#include #include #include @@ -38,10 +46,10 @@ namespace Magnum { namespace MeshTools { For each face generates one normal vector, removes duplicates before returning. Example usage: @code -std::vector vertexIndices; -std::vector positions; +std::vector vertexIndices; +std::vector positions; -std::vector normalIndices; +std::vector normalIndices; std::vector normals; std::tie(normalIndices, normals) = MeshTools::generateFlatNormals(vertexIndices, positions); @endcode @@ -51,7 +59,7 @@ use the same indices. @attention Index count must be divisible by 3, otherwise zero length result is generated. */ -std::tuple, std::vector> MAGNUM_MESHTOOLS_EXPORT generateFlatNormals(const std::vector& indices, const std::vector& positions); +std::tuple, std::vector> MAGNUM_MESHTOOLS_EXPORT generateFlatNormals(const std::vector& indices, const std::vector& positions); }} diff --git a/src/MeshTools/Interleave.h b/src/MeshTools/Interleave.h index 6f85ef2b2..42c907cdc 100644 --- a/src/MeshTools/Interleave.h +++ b/src/MeshTools/Interleave.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_Interleave_h #define Magnum_MeshTools_Interleave_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -39,7 +48,7 @@ class Interleave { template std::tuple operator()(const T&... attributes) { /* Compute buffer size and stride */ _attributeCount = attributeCount(attributes...); - if(_attributeCount) { + if(_attributeCount && _attributeCount != ~std::size_t(0)) { _stride = stride(attributes...); /* Create output buffer */ @@ -62,29 +71,55 @@ class Interleave { } /* Specialization for only one attribute array */ - template void operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const T& attribute) { + template typename std::enable_if::value, void>::type operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const T& attribute) { mesh->setVertexCount(attribute.size()); buffer->setData(attribute, usage); } - template inline static std::size_t attributeCount(const T& first, const U&... next) { - CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size(), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.", 0); + template inline 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 stride(const T&, const U&... next) { + template inline static std::size_t attributeCount(std::size_t, const T&... next) { + return attributeCount(next...); + } + + template inline 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) { return sizeof(typename T::value_type) + stride(next...); } + template inline static std::size_t stride(std::size_t gap, const T&... next) { + return gap + stride(next...); + } + private: - template void write(char* startingOffset, const T& first, const U&... next) { - /* Copy the data to the buffer */ - auto it = first.begin(); + template inline void write(char* startingOffset, const T& first, const U&... next) { + write(startingOffset+writeOne(startingOffset, first), next...); + } + + /* Copy data to the buffer */ + template typename std::enable_if::value, std::size_t>::type writeOne(char* startingOffset, const T& attributeList) { + auto it = attributeList.begin(); for(std::size_t i = 0; i != _attributeCount; ++i, ++it) memcpy(startingOffset+i*_stride, reinterpret_cast(&*it), sizeof(typename T::value_type)); - write(startingOffset+sizeof(typename T::value_type), next...); + return sizeof(typename T::value_type); + } + + /* Fill gap with zeros */ + std::size_t writeOne(char* startingOffset, std::size_t gap) { + char* data = new char[gap](); + for(std::size_t i = 0; i != _attributeCount; ++i) + memcpy(startingOffset+i*_stride, data, gap); + + delete[] data; + return gap; } /* Terminator functions for recursive calls */ @@ -102,15 +137,14 @@ class Interleave { /** @brief %Interleave vertex attributes -@param attribute First attribute array -@param attributes Next attribute arrays -@return Attribute count, stride and interleaved attribute array. Deleting the - array is user responsibility. - -This function takes two or more attribute arrays and returns them interleaved, -so data for each attribute are in continuous place in memory. Size of the data -buffer can be computed from attribute count and stride, as shown below. Example -usage: + +This function takes list of attribute arrays and returns them interleaved, so +data for each attribute are in continuous place in memory. Returned tuple +contains attribute count, stride and data array. Deleting the data array is up +to the user. + +Size of the data buffer can be computed from attribute count and stride, as +shown below. Example usage: @code std::vector positions; std::vector textureCoordinates; @@ -123,28 +157,41 @@ std::size_t dataSize = attributeCount*stride; delete[] data; @endcode -The only requirements to attribute array type is that it must have typedef -`T::value_type`, forward iterator (to be used with range-based for) and -function `size()` returning count of elements. In most cases it will be -`std::vector` or `std::array`. +It's often desirable to align data for one vertex on 32bit boundaries. To +achieve that, you can specify gaps between the attributes: +@code +std::vector positions; +std::vector weights; +std::vector> vertexColors; +std::size_t attributeCount; +std::size_t stride; +char* data; +std::tie(attributeCount, stride, data) = MeshTools::interleave(positions, weights, 2, textureCoordinates, 1); +@endcode +This way vertex stride is 24 bytes, without gaps it would be 21 bytes, causing +possible performance loss. + +@attention The function expects that all arrays have the same size. + +@note The only requirements to attribute array type is that it must have + typedef `T::value_type`, forward iterator (to be used with range-based + for) and function `size()` returning count of elements. In most cases it + will be `std::vector` or `std::array`. See also interleave(Mesh*, Buffer*, Buffer::Usage, const T&...), which writes the interleaved array directly into buffer of given mesh. - -@attention Each passed array should have the same size, if not, resulting - array has zero length. */ /* enable_if to avoid clash with overloaded function below */ -template inline typename std::enable_if::value, std::tuple>::type interleave(const T& attribute, const U&... attributes) { - return Implementation::Interleave()(attribute, attributes...); +template inline typename std::enable_if::value, std::tuple>::type interleave(const T& first, const U&... next) { + return Implementation::Interleave()(first, next...); } /** @brief %Interleave vertex attributes and write them to array buffer -@param attributes Attribute arrays @param mesh Output mesh -@param buffer Output array buffer -@param usage Array buffer usage +@param buffer Output vertex buffer +@param usage Vertex buffer usage +@param attributes Attribute arrays and gaps The same as interleave(const T&, const U&...), but this function writes the output to given array buffer and updates vertex count in the mesh accordingly, diff --git a/src/MeshTools/Subdivide.h b/src/MeshTools/Subdivide.h index 8993bb4da..371aeca24 100644 --- a/src/MeshTools/Subdivide.h +++ b/src/MeshTools/Subdivide.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_Subdivide_h #define Magnum_MeshTools_Subdivide_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -29,7 +38,7 @@ namespace Implementation { template class Subdivide { public: - inline Subdivide(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} + 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!", ); @@ -40,7 +49,7 @@ template class Subdivide { /* Subdivide each face to four new */ for(std::size_t i = 0; i != indexCount; i += 3) { /* Interpolate each side */ - std::uint32_t newVertices[3]; + UnsignedInt newVertices[3]; for(int j = 0; j != 3; ++j) newVertices[j] = addVertex(interpolator(vertices[indices[i+j]], vertices[indices[i+(j+1)%3]])); @@ -66,15 +75,15 @@ template class Subdivide { } private: - std::vector& indices; + std::vector& indices; std::vector& vertices; - std::uint32_t addVertex(const Vertex& v) { + UnsignedInt addVertex(const Vertex& v) { vertices.push_back(v); return vertices.size()-1; } - void addFace(std::uint32_t first, std::uint32_t second, std::uint32_t third) { + void addFace(UnsignedInt first, UnsignedInt second, UnsignedInt third) { indices.push_back(first); indices.push_back(second); indices.push_back(third); @@ -96,7 +105,7 @@ template class Subdivide { Goes through all triangle faces and subdivides them into four new. Cleaning duplicate vertices in the mesh is up to user. */ -template inline void subdivide(std::vector& indices, std::vector& vertices, Interpolator interpolator) { +template inline void subdivide(std::vector& indices, std::vector& vertices, Interpolator interpolator) { Implementation::Subdivide(indices, vertices)(interpolator); } diff --git a/src/MeshTools/Test/CMakeLists.txt b/src/MeshTools/Test/CMakeLists.txt index 0a4608faf..a0a5626e5 100644 --- a/src/MeshTools/Test/CMakeLists.txt +++ b/src/MeshTools/Test/CMakeLists.txt @@ -1,12 +1,40 @@ -corrade_add_test2(MeshToolsCleanTest CleanTest.cpp) -corrade_add_test2(MeshToolsCombineIndexedArraysTest CombineIndexedArraysTest.cpp) -corrade_add_test2(MeshToolsCompressIndicesTest CompressIndicesTest.cpp LIBRARIES MagnumMeshTools) -corrade_add_test2(MeshToolsFlipNormalsTest FlipNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib) -corrade_add_test2(MeshToolsGenerateFlatNormalsTest GenerateFlatNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib) -corrade_add_test2(MeshToolsInterleaveTest InterleaveTest.cpp) -corrade_add_test2(MeshToolsSubdivideTest SubdivideTest.cpp) +# +# 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. +# + +corrade_add_test(MeshToolsCleanTest CleanTest.cpp) +corrade_add_test(MeshToolsCombineIndexedArraysTest CombineIndexedArraysTest.cpp) +corrade_add_test(MeshToolsCompressIndicesTest CompressIndicesTest.cpp LIBRARIES MagnumMeshTools) +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(MeshToolsSubdivideTest SubdivideTest.cpp) # corrade_add_test(MeshToolsSubdivideCleanBenchmark SubdivideCleanBenchmark.h SubdivideCleanBenchmark.cpp MagnumPrimitives) -corrade_add_test2(MeshToolsTipsifyTest TipsifyTest.cpp LIBRARIES MagnumMeshTools) +corrade_add_test(MeshToolsTipsifyTest TipsifyTest.cpp LIBRARIES MagnumMeshTools) +corrade_add_test(MeshToolsTransformTest TransformTest.cpp LIBRARIES MagnumMeshTools) # Graceful assert for testing -set_target_properties(MeshToolsCombineIndexedArraysTest MeshToolsInterleaveTest MeshToolsSubdivideTest PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) +set_target_properties(MeshToolsCombineIndexedArraysTest + MeshToolsInterleaveTest + MeshToolsSubdivideTest + PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) diff --git a/src/MeshTools/Test/CleanTest.cpp b/src/MeshTools/Test/CleanTest.cpp index a180be5f3..8e15281c9 100644 --- a/src/MeshTools/Test/CleanTest.cpp +++ b/src/MeshTools/Test/CleanTest.cpp @@ -1,40 +1,70 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CleanTest.h" +#include #include "MeshTools/Clean.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CleanTest) +namespace Magnum { namespace MeshTools { namespace Test { -using namespace std; +class CleanTest: public Corrade::TestSuite::Tester { + public: + CleanTest(); -namespace Magnum { namespace MeshTools { namespace Test { + 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; +}; CleanTest::CleanTest() { - addTests(&CleanTest::cleanMesh); + addTests({&CleanTest::cleanMesh}); } void CleanTest::cleanMesh() { - vector positions{1, 2, 1, 4}; - vector indices{0, 1, 2, 1, 2, 3}; + std::vector positions{1, 2, 1, 4}; + std::vector indices{0, 1, 2, 1, 2, 3}; MeshTools::clean(indices, positions); /* Verify cleanup */ - CORRADE_VERIFY(positions == (vector{1, 2, 4})); - CORRADE_COMPARE(indices, (vector{0, 1, 0, 1, 0, 2})); + CORRADE_VERIFY(positions == (std::vector{1, 2, 4})); + CORRADE_COMPARE(indices, (std::vector{0, 1, 0, 1, 0, 2})); } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CleanTest) diff --git a/src/MeshTools/Test/CleanTest.h b/src/MeshTools/Test/CleanTest.h deleted file mode 100644 index 57169d736..000000000 --- a/src/MeshTools/Test/CleanTest.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef Magnum_MeshTools_Test_CleanTest_h -#define Magnum_MeshTools_Test_CleanTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class CleanTest: public Corrade::TestSuite::Tester { - public: - CleanTest(); - - void cleanMesh(); - - private: - class Vector1 { - public: - static const std::size_t Size = 1; - typedef std::int32_t 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; - }; -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/CombineIndexedArraysTest.cpp b/src/MeshTools/Test/CombineIndexedArraysTest.cpp index 57211078b..9473a4123 100644 --- a/src/MeshTools/Test/CombineIndexedArraysTest.cpp +++ b/src/MeshTools/Test/CombineIndexedArraysTest.cpp @@ -1,61 +1,76 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CombineIndexedArraysTest.h" - #include +#include +#include "Types.h" #include "MeshTools/CombineIndexedArrays.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CombineIndexedArraysTest) +namespace Magnum { namespace MeshTools { namespace Test { -using namespace std; +class CombineIndexedArraysTest: public Corrade::TestSuite::Tester { + public: + CombineIndexedArraysTest(); -namespace Magnum { namespace MeshTools { namespace Test { + void wrongIndexCount(); + void combine(); +}; CombineIndexedArraysTest::CombineIndexedArraysTest() { - addTests(&CombineIndexedArraysTest::wrongIndexCount, - &CombineIndexedArraysTest::combine); + addTests({&CombineIndexedArraysTest::wrongIndexCount, + &CombineIndexedArraysTest::combine}); } void CombineIndexedArraysTest::wrongIndexCount() { - stringstream ss; + std::stringstream ss; Error::setOutput(&ss); - vector array; - vector result = MeshTools::combineIndexedArrays( - tuple&, vector&>(vector{0, 1, 0}, array), - tuple&, vector&>(vector{3, 4}, array)); + 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)); 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() { - vector array1{ 0, 1 }; - vector array2{ 0, 1, 2, 3, 4 }; - vector array3{ 0, 1, 2, 3, 4, 5, 6, 7 }; - - vector result = MeshTools::combineIndexedArrays( - tuple&, vector&>(vector{0, 1, 0}, array1), - tuple&, vector&>(vector{3, 4, 3}, array2), - tuple&, vector&>(vector{6, 7, 6}, array3)); - - CORRADE_COMPARE(result, (vector{0, 1, 0})); - CORRADE_COMPARE(array1, (vector{0, 1})); - CORRADE_COMPARE(array2, (vector{3, 4})); - CORRADE_COMPARE(array3, (vector{6, 7})); + 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)); + + CORRADE_COMPARE(result, (std::vector{0, 1, 0})); + CORRADE_COMPARE(array1, (std::vector{0, 1})); + CORRADE_COMPARE(array2, (std::vector{3, 4})); + CORRADE_COMPARE(array3, (std::vector{6, 7})); } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CombineIndexedArraysTest) diff --git a/src/MeshTools/Test/CombineIndexedArraysTest.h b/src/MeshTools/Test/CombineIndexedArraysTest.h deleted file mode 100644 index df90f02f8..000000000 --- a/src/MeshTools/Test/CombineIndexedArraysTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_MeshTools_Test_CombineIndexedArraysTest_h -#define Magnum_MeshTools_Test_CombineIndexedArraysTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class CombineIndexedArraysTest: public Corrade::TestSuite::Tester { - public: - CombineIndexedArraysTest(); - - void wrongIndexCount(); - void combine(); -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/CompressIndicesTest.cpp b/src/MeshTools/Test/CompressIndicesTest.cpp index f50b7ce49..a433c1413 100644 --- a/src/MeshTools/Test/CompressIndicesTest.cpp +++ b/src/MeshTools/Test/CompressIndicesTest.cpp @@ -1,70 +1,84 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CompressIndicesTest.h" - +#include #include #include "MeshTools/CompressIndices.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CompressIndicesTest) - -using namespace std; using Corrade::Utility::Endianness; namespace Magnum { namespace MeshTools { namespace Test { +class CompressIndicesTest: public Corrade::TestSuite::Tester { + public: + CompressIndicesTest(); + + void compressChar(); + void compressShort(); + void compressInt(); +}; + CompressIndicesTest::CompressIndicesTest() { - addTests(&CompressIndicesTest::compressChar, - &CompressIndicesTest::compressShort, - &CompressIndicesTest::compressInt); + addTests({&CompressIndicesTest::compressChar, + &CompressIndicesTest::compressShort, + &CompressIndicesTest::compressInt}); } void CompressIndicesTest::compressChar() { - size_t indexCount; - Type indexType; + std::size_t indexCount; + Mesh::IndexType indexType; char* data; - tie(indexCount, indexType, data) = MeshTools::compressIndices( - vector{1, 2, 3, 0, 4}); + std::tie(indexCount, indexType, data) = MeshTools::compressIndices( + std::vector{1, 2, 3, 0, 4}); CORRADE_COMPARE(indexCount, 5); - CORRADE_VERIFY(indexType == Type::UnsignedByte); - CORRADE_COMPARE(vector(data, data+indexCount*TypeInfo::sizeOf(indexType)), - (vector{ 0x01, 0x02, 0x03, 0x00, 0x04 })); + CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedByte); + CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), + (std::vector{ 0x01, 0x02, 0x03, 0x00, 0x04 })); delete[] data; } void CompressIndicesTest::compressShort() { - size_t indexCount; - Type indexType; + std::size_t indexCount; + Mesh::IndexType indexType; char* data; - tie(indexCount, indexType, data) = MeshTools::compressIndices( - vector{1, 256, 0, 5}); + std::tie(indexCount, indexType, data) = MeshTools::compressIndices( + std::vector{1, 256, 0, 5}); CORRADE_COMPARE(indexCount, 4); - CORRADE_VERIFY(indexType == Type::UnsignedShort); + CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedShort); if(!Endianness::isBigEndian()) { - CORRADE_COMPARE(vector(data, data+indexCount*TypeInfo::sizeOf(indexType)), - (vector{ 0x01, 0x00, + CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), + (std::vector{ 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00 })); } else { - CORRADE_COMPARE(vector(data, data+indexCount*TypeInfo::sizeOf(indexType)), - (vector{ 0x00, 0x01, + CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), + (std::vector{ 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05 })); @@ -74,23 +88,23 @@ void CompressIndicesTest::compressShort() { } void CompressIndicesTest::compressInt() { - size_t indexCount; - Type indexType; + std::size_t indexCount; + Mesh::IndexType indexType; char* data; - tie(indexCount, indexType, data) = MeshTools::compressIndices( - vector{65536, 3, 2}); + std::tie(indexCount, indexType, data) = MeshTools::compressIndices( + std::vector{65536, 3, 2}); CORRADE_COMPARE(indexCount, 3); - CORRADE_VERIFY(indexType == Type::UnsignedInt); + CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedInt); if(!Endianness::isBigEndian()) { - CORRADE_COMPARE(vector(data, data+indexCount*TypeInfo::sizeOf(indexType)), - (vector{ 0x00, 0x00, 0x01, 0x00, + CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), + (std::vector{ 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 })); } else { - CORRADE_COMPARE(vector(data, data+indexCount*TypeInfo::sizeOf(indexType)), - (vector{ 0x00, 0x01, 0x00, 0x00, + CORRADE_COMPARE(std::vector(data, data+indexCount*Mesh::indexSize(indexType)), + (std::vector{ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02 })); } @@ -99,3 +113,5 @@ void CompressIndicesTest::compressInt() { } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CompressIndicesTest) diff --git a/src/MeshTools/Test/CompressIndicesTest.h b/src/MeshTools/Test/CompressIndicesTest.h deleted file mode 100644 index fcbcc85dd..000000000 --- a/src/MeshTools/Test/CompressIndicesTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_MeshTools_Test_CompressIndicesTest_h -#define Magnum_MeshTools_Test_CompressIndicesTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class CompressIndicesTest: public Corrade::TestSuite::Tester { - public: - CompressIndicesTest(); - - void compressChar(); - void compressShort(); - void compressInt(); -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/FlipNormalsTest.cpp b/src/MeshTools/Test/FlipNormalsTest.cpp index b900f39d5..47c648827 100644 --- a/src/MeshTools/Test/FlipNormalsTest.cpp +++ b/src/MeshTools/Test/FlipNormalsTest.cpp @@ -1,65 +1,80 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "FlipNormalsTest.h" - #include +#include #include "Math/Vector3.h" #include "MeshTools/FlipNormals.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::FlipNormalsTest) +namespace Magnum { namespace MeshTools { namespace Test { -using namespace std; +class FlipNormalsTest: public Corrade::TestSuite::Tester { + public: + FlipNormalsTest(); -namespace Magnum { namespace MeshTools { namespace Test { + void wrongIndexCount(); + void flipFaceWinding(); + void flipNormals(); +}; FlipNormalsTest::FlipNormalsTest() { - addTests(&FlipNormalsTest::wrongIndexCount, - &FlipNormalsTest::flipFaceWinding, - &FlipNormalsTest::flipNormals); + addTests({&FlipNormalsTest::wrongIndexCount, + &FlipNormalsTest::flipFaceWinding, + &FlipNormalsTest::flipNormals}); } void FlipNormalsTest::wrongIndexCount() { - stringstream ss; + std::stringstream ss; Error::setOutput(&ss); - vector indices{0, 1}; + std::vector indices{0, 1}; MeshTools::flipFaceWinding(indices); CORRADE_COMPARE(ss.str(), "MeshTools::flipNormals(): index count is not divisible by 3!\n"); } void FlipNormalsTest::flipFaceWinding() { - vector indices{0, 1, 2, - 3, 4, 5}; + std::vector indices{0, 1, 2, + 3, 4, 5}; MeshTools::flipFaceWinding(indices); - CORRADE_COMPARE(indices, (vector{0, 2, 1, - 3, 5, 4})); + CORRADE_COMPARE(indices, (std::vector{0, 2, 1, + 3, 5, 4})); } void FlipNormalsTest::flipNormals() { - vector normals{Vector3::xAxis(), - Vector3::yAxis(), - Vector3::zAxis()}; + std::vector normals{Vector3::xAxis(), + Vector3::yAxis(), + Vector3::zAxis()}; MeshTools::flipNormals(normals); - CORRADE_COMPARE(normals, (vector{-Vector3::xAxis(), - -Vector3::yAxis(), - -Vector3::zAxis()})); + CORRADE_COMPARE(normals, (std::vector{-Vector3::xAxis(), + -Vector3::yAxis(), + -Vector3::zAxis()})); } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::FlipNormalsTest) diff --git a/src/MeshTools/Test/FlipNormalsTest.h b/src/MeshTools/Test/FlipNormalsTest.h deleted file mode 100644 index f6f0422cd..000000000 --- a/src/MeshTools/Test/FlipNormalsTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_MeshTools_Test_FlipNormalsTest_h -#define Magnum_MeshTools_Test_FlipNormalsTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class FlipNormalsTest: public Corrade::TestSuite::Tester { - public: - FlipNormalsTest(); - - void wrongIndexCount(); - void flipFaceWinding(); - void flipNormals(); -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/GenerateFlatNormalsTest.cpp b/src/MeshTools/Test/GenerateFlatNormalsTest.cpp index 37ceeb245..cbac567da 100644 --- a/src/MeshTools/Test/GenerateFlatNormalsTest.cpp +++ b/src/MeshTools/Test/GenerateFlatNormalsTest.cpp @@ -1,42 +1,54 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ + 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: -#include "GenerateFlatNormalsTest.h" + 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/Point3D.h" +#include "Math/Vector3.h" #include "MeshTools/GenerateFlatNormals.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::GenerateFlatNormalsTest) +namespace Magnum { namespace MeshTools { namespace Test { -using namespace std; +class GenerateFlatNormalsTest: public Corrade::TestSuite::Tester { + public: + GenerateFlatNormalsTest(); -namespace Magnum { namespace MeshTools { namespace Test { + void wrongIndexCount(); + void generate(); +}; GenerateFlatNormalsTest::GenerateFlatNormalsTest() { - addTests(&GenerateFlatNormalsTest::wrongIndexCount, - &GenerateFlatNormalsTest::generate); + addTests({&GenerateFlatNormalsTest::wrongIndexCount, + &GenerateFlatNormalsTest::generate}); } void GenerateFlatNormalsTest::wrongIndexCount() { - stringstream ss; + std::stringstream ss; Error::setOutput(&ss); - vector indices; - vector normals; - tie(indices, normals) = MeshTools::generateFlatNormals({ + std::vector indices; + std::vector normals; + std::tie(indices, normals) = MeshTools::generateFlatNormals({ 0, 1 }, {}); @@ -47,26 +59,28 @@ void GenerateFlatNormalsTest::wrongIndexCount() { void GenerateFlatNormalsTest::generate() { /* Two vertices connected by one edge, each winded in another direction */ - vector indices; - vector normals; - tie(indices, normals) = MeshTools::generateFlatNormals({ + std::vector indices; + std::vector normals; + std::tie(indices, normals) = MeshTools::generateFlatNormals({ 0, 1, 2, 1, 2, 3 - }, vector{ + }, std::vector{ {-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f} }); - CORRADE_COMPARE(indices, (vector{ + CORRADE_COMPARE(indices, (std::vector{ 0, 0, 0, 1, 1, 1 })); - CORRADE_COMPARE(normals, (vector{ + CORRADE_COMPARE(normals, (std::vector{ Vector3::zAxis(), -Vector3::zAxis() })); } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::GenerateFlatNormalsTest) diff --git a/src/MeshTools/Test/GenerateFlatNormalsTest.h b/src/MeshTools/Test/GenerateFlatNormalsTest.h deleted file mode 100644 index 130636498..000000000 --- a/src/MeshTools/Test/GenerateFlatNormalsTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_MeshTools_Test_GenerateFlatNormalsTest_h -#define Magnum_MeshTools_Test_GenerateFlatNormalsTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class GenerateFlatNormalsTest: public Corrade::TestSuite::Tester { - public: - GenerateFlatNormalsTest(); - - void wrongIndexCount(); - void generate(); -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/InterleaveTest.cpp b/src/MeshTools/Test/InterleaveTest.cpp index b734ea39a..fe525edda 100644 --- a/src/MeshTools/Test/InterleaveTest.cpp +++ b/src/MeshTools/Test/InterleaveTest.cpp @@ -1,76 +1,108 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "InterleaveTest.h" - #include +#include #include "Utility/Endianness.h" #include "Utility/Debug.h" #include "MeshTools/Interleave.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::InterleaveTest) - -using namespace std; using Corrade::Utility::Endianness; namespace Magnum { namespace MeshTools { namespace Test { +class InterleaveTest: public Corrade::TestSuite::Tester { + public: + InterleaveTest(); + + void attributeCount(); + void attributeCountGaps(); + void stride(); + void strideGaps(); + void write(); + void writeGaps(); +}; + InterleaveTest::InterleaveTest() { - addTests(&InterleaveTest::attributeCount, - &InterleaveTest::stride, - &InterleaveTest::write); + addTests({&InterleaveTest::attributeCount, + &InterleaveTest::attributeCountGaps, + &InterleaveTest::stride, + &InterleaveTest::strideGaps, + &InterleaveTest::write, + &InterleaveTest::writeGaps}); } void InterleaveTest::attributeCount() { - stringstream ss; + std::stringstream ss; Error::setOutput(&ss); - CORRADE_COMPARE((Implementation::Interleave::attributeCount(vector{0, 1, 2}, - vector{0, 1, 2, 3, 4, 5})), size_t(0)); + CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector{0, 1, 2}, + std::vector{0, 1, 2, 3, 4, 5})), std::size_t(0)); CORRADE_COMPARE(ss.str(), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.\n"); - CORRADE_COMPARE((Implementation::Interleave::attributeCount(vector{0, 1, 2}, - vector{3, 4, 5})), size_t(3)); + CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector{0, 1, 2}, + std::vector{3, 4, 5})), std::size_t(3)); +} + +void InterleaveTest::attributeCountGaps() { + CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector{0, 1, 2}, 3, + std::vector{3, 4, 5}, 5)), std::size_t(3)); + + /* No arrays from which to get size */ + CORRADE_COMPARE(Implementation::Interleave::attributeCount(3, 5), ~std::size_t(0)); } void InterleaveTest::stride() { - CORRADE_COMPARE(Implementation::Interleave::stride(vector()), size_t(1)); - CORRADE_COMPARE(Implementation::Interleave::stride(vector()), size_t(4)); - CORRADE_COMPARE((Implementation::Interleave::stride(vector(), vector())), size_t(5)); + CORRADE_COMPARE(Implementation::Interleave::stride(std::vector()), std::size_t(1)); + CORRADE_COMPARE(Implementation::Interleave::stride(std::vector()), std::size_t(4)); + CORRADE_COMPARE((Implementation::Interleave::stride(std::vector(), std::vector())), std::size_t(5)); +} + +void InterleaveTest::strideGaps() { + CORRADE_COMPARE((Implementation::Interleave::stride(2, std::vector(), 1, std::vector(), 12)), std::size_t(20)); } void InterleaveTest::write() { - size_t attributeCount; - size_t stride; + std::size_t attributeCount; + std::size_t stride; char* data; - tie(attributeCount, stride, data) = MeshTools::interleave( - vector{0, 1, 2}, - vector{3, 4, 5}, - vector{6, 7, 8}); - - CORRADE_COMPARE(attributeCount, size_t(3)); - CORRADE_COMPARE(stride, size_t(7)); - size_t size = attributeCount*stride; + std::tie(attributeCount, stride, data) = MeshTools::interleave( + std::vector{0, 1, 2}, + std::vector{3, 4, 5}, + std::vector{6, 7, 8}); + + CORRADE_COMPARE(attributeCount, std::size_t(3)); + CORRADE_COMPARE(stride, std::size_t(7)); + std::size_t size = attributeCount*stride; if(!Endianness::isBigEndian()) { - CORRADE_COMPARE(vector(data, data+size), (vector{ + CORRADE_COMPARE(std::vector(data, data+size), (std::vector{ 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00 })); } else { - CORRADE_COMPARE(vector(data, data+size), (vector{ + CORRADE_COMPARE(std::vector(data, data+size), (std::vector{ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08 @@ -80,4 +112,35 @@ void InterleaveTest::write() { delete[] data; } +void InterleaveTest::writeGaps() { + std::size_t attributeCount; + std::size_t stride; + char* data; + std::tie(attributeCount, stride, data) = MeshTools::interleave( + std::vector{0, 1, 2}, 3, + std::vector{3, 4, 5}, + std::vector{6, 7, 8}, 2); + + CORRADE_COMPARE(attributeCount, std::size_t(3)); + CORRADE_COMPARE(stride, std::size_t(12)); + std::size_t size = attributeCount*stride; + if(!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, + 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 + })); + } else { + CORRADE_COMPARE(std::vector(data, data+size), (std::vector{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00 + })); + } + + delete[] data; +} + }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::InterleaveTest) diff --git a/src/MeshTools/Test/InterleaveTest.h b/src/MeshTools/Test/InterleaveTest.h deleted file mode 100644 index e360d0554..000000000 --- a/src/MeshTools/Test/InterleaveTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_MeshTools_Test_InterleaveTest_h -#define Magnum_MeshTools_Test_InterleaveTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class InterleaveTest: public Corrade::TestSuite::Tester { - public: - InterleaveTest(); - - void attributeCount(); - void stride(); - void write(); -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/SubdivideCleanBenchmark.cpp b/src/MeshTools/Test/SubdivideCleanBenchmark.cpp index fd56ef292..01f3ebd36 100644 --- a/src/MeshTools/Test/SubdivideCleanBenchmark.cpp +++ b/src/MeshTools/Test/SubdivideCleanBenchmark.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "SubdivideCleanBenchmark.h" diff --git a/src/MeshTools/Test/SubdivideCleanBenchmark.h b/src/MeshTools/Test/SubdivideCleanBenchmark.h index 390cb54e2..fe3af344e 100644 --- a/src/MeshTools/Test/SubdivideCleanBenchmark.h +++ b/src/MeshTools/Test/SubdivideCleanBenchmark.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_Test_SubdivideCleanBenchmark_h #define Magnum_MeshTools_Test_SubdivideCleanBenchmark_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 diff --git a/src/MeshTools/Test/SubdivideTest.cpp b/src/MeshTools/Test/SubdivideTest.cpp index 965c3ad36..9271e3d60 100644 --- a/src/MeshTools/Test/SubdivideTest.cpp +++ b/src/MeshTools/Test/SubdivideTest.cpp @@ -1,55 +1,86 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "SubdivideTest.h" - #include +#include #include "MeshTools/Clean.h" #include "MeshTools/Subdivide.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::SubdivideTest) +namespace Magnum { namespace MeshTools { namespace Test { -using namespace std; +class SubdivideTest: public Corrade::TestSuite::Tester { + public: + SubdivideTest(); -namespace Magnum { namespace MeshTools { namespace Test { + void wrongIndexCount(); + void subdivide(); + + private: + 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; + }; + + inline static Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; } +}; SubdivideTest::SubdivideTest() { - addTests(&SubdivideTest::wrongIndexCount, - &SubdivideTest::subdivide); + addTests({&SubdivideTest::wrongIndexCount, + &SubdivideTest::subdivide}); } void SubdivideTest::wrongIndexCount() { - stringstream ss; + std::stringstream ss; Error::setOutput(&ss); - vector positions; - vector indices{0, 1}; + std::vector positions; + std::vector indices{0, 1}; MeshTools::subdivide(indices, positions, interpolator); CORRADE_COMPARE(ss.str(), "MeshTools::subdivide(): index count is not divisible by 3!\n"); } void SubdivideTest::subdivide() { - vector positions{0, 2, 6, 8}; - vector indices{0, 1, 2, 1, 2, 3}; + std::vector positions{0, 2, 6, 8}; + std::vector indices{0, 1, 2, 1, 2, 3}; MeshTools::subdivide(indices, positions, interpolator); CORRADE_COMPARE(indices.size(), 24); - CORRADE_VERIFY(positions == (vector{0, 2, 6, 8, 1, 4, 3, 4, 7, 5})); - CORRADE_COMPARE(indices, (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})); + 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); @@ -58,3 +89,5 @@ void SubdivideTest::subdivide() { } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::SubdivideTest) diff --git a/src/MeshTools/Test/SubdivideTest.h b/src/MeshTools/Test/SubdivideTest.h deleted file mode 100644 index b5ff7f0ef..000000000 --- a/src/MeshTools/Test/SubdivideTest.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef Magnum_MeshTools_Test_SubdivideTest_h -#define Magnum_MeshTools_Test_SubdivideTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class SubdivideTest: public Corrade::TestSuite::Tester { - public: - SubdivideTest(); - - void wrongIndexCount(); - void subdivide(); - - private: - class Vector1 { - public: - static const std::size_t Size = 1; - typedef std::int32_t 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; - }; - - inline static Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; } -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/TipsifyTest.cpp b/src/MeshTools/Test/TipsifyTest.cpp index fc0a7c243..096b2fe2e 100644 --- a/src/MeshTools/Test/TipsifyTest.cpp +++ b/src/MeshTools/Test/TipsifyTest.cpp @@ -1,27 +1,44 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "TipsifyTest.h" +#include #include "MeshTools/Tipsify.h" -CORRADE_TEST_MAIN(Magnum::MeshTools::Test::TipsifyTest) +namespace Magnum { namespace MeshTools { namespace Test { -using namespace std; +class TipsifyTest: public Corrade::TestSuite::Tester { + public: + TipsifyTest(); -namespace Magnum { namespace MeshTools { namespace Test { + void buildAdjacency(); + void tipsify(); + + private: + std::vector indices; + std::size_t vertexCount; +}; /* @@ -62,15 +79,15 @@ TipsifyTest::TipsifyTest(): indices{ 16, 17, 18 }, vertexCount(19) { - addTests(&TipsifyTest::buildAdjacency, - &TipsifyTest::tipsify); + addTests({&TipsifyTest::buildAdjacency, + &TipsifyTest::tipsify}); } void TipsifyTest::buildAdjacency() { - vector liveTriangleCount, neighborOffset, neighbors; + std::vector liveTriangleCount, neighborOffset, neighbors; Implementation::Tipsify(indices, vertexCount).buildAdjacency(liveTriangleCount, neighborOffset, neighbors); - CORRADE_COMPARE(liveTriangleCount, (vector{ + CORRADE_COMPARE(liveTriangleCount, (std::vector{ 1, 3, 3, 2, 4, 6, 6, 2, 2, 6, 6, 4, @@ -78,7 +95,7 @@ void TipsifyTest::buildAdjacency() { 1, 1, 1 })); - CORRADE_COMPARE(neighborOffset, (vector{ + CORRADE_COMPARE(neighborOffset, (std::vector{ 0, 1, 4, 7, 9, 13, 19, 25, 27, 29, 35, 41, @@ -86,7 +103,7 @@ void TipsifyTest::buildAdjacency() { 54, 55, 56, 57 })); - CORRADE_COMPARE(neighbors, (vector{ + CORRADE_COMPARE(neighbors, (std::vector{ 0, 0, 7, 11, 2, 7, 13, @@ -114,7 +131,7 @@ void TipsifyTest::buildAdjacency() { void TipsifyTest::tipsify() { MeshTools::tipsify(indices, vertexCount, 3); - CORRADE_COMPARE(indices, (vector{ + CORRADE_COMPARE(indices, (std::vector{ 4, 1, 0, 9, 5, 4, 1, 4, 5, @@ -138,3 +155,5 @@ void TipsifyTest::tipsify() { } }}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::TipsifyTest) diff --git a/src/MeshTools/Test/TipsifyTest.h b/src/MeshTools/Test/TipsifyTest.h deleted file mode 100644 index 978b60122..000000000 --- a/src/MeshTools/Test/TipsifyTest.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef Magnum_MeshTools_Test_TipsifyTest_h -#define Magnum_MeshTools_Test_TipsifyTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include -#include - -namespace Magnum { namespace MeshTools { namespace Test { - -class TipsifyTest: public Corrade::TestSuite::Tester { - public: - TipsifyTest(); - - void buildAdjacency(); - void tipsify(); - - private: - std::vector indices; - std::size_t vertexCount; -}; - -}}} - -#endif diff --git a/src/MeshTools/Test/TransformTest.cpp b/src/MeshTools/Test/TransformTest.cpp new file mode 100644 index 000000000..7d632c879 --- /dev/null +++ b/src/MeshTools/Test/TransformTest.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 + +#include "Math/Matrix3.h" +#include "Magnum.h" +#include "MeshTools/Transform.h" + +namespace Magnum { namespace MeshTools { namespace Test { + +class TransformTest: public Corrade::TestSuite::Tester { + public: + explicit TransformTest(); + + void transformVectors2D(); + void transformVectors3D(); + + void transformPoints2D(); + void transformPoints3D(); +}; + +TransformTest::TransformTest() { + addTests({&TransformTest::transformVectors2D, + &TransformTest::transformVectors3D, + + &TransformTest::transformPoints2D, + &TransformTest::transformPoints3D}); +} + +/* GCC < 4.7 doesn't like constexpr here, don't know why */ +#ifdef CORRADE_GCC46_COMPATIBILITY +#define constexpr const +#endif + +constexpr static std::array points2D{{ + {-3.0f, 4.0f}, + { 2.5f, -15.0f} +}}; + +constexpr static std::array points2DRotated{{ + {-4.0f, -3.0f}, + {15.0f, 2.5f} +}}; + +constexpr static std::array points2DRotatedTranslated{{ + {-4.0f, -4.0f}, + {15.0f, 1.5f} +}}; + +constexpr static std::array points3D{{ + {-3.0f, 4.0f, 34.0f}, + { 2.5f, -15.0f, 1.5f} +}}; + +constexpr static std::array points3DRotated{{ + {-4.0f, -3.0f, 34.0f}, + {15.0f, 2.5f, 1.5f} +}}; + +constexpr static std::array points3DRotatedTranslated{{ + {-4.0f, -4.0f, 34.0f}, + {15.0f, 1.5f, 1.5f} +}}; + +#ifdef CORRADE_GCC46_COMPATIBILITY +#undef constexpr +#endif + +void TransformTest::transformVectors2D() { + auto matrix = MeshTools::transformVectors(Matrix3::rotation(Deg(90.0f)), points2D); + auto complex = MeshTools::transformVectors(Complex::rotation(Deg(90.0f)), points2D); + + CORRADE_COMPARE(matrix, points2DRotated); + CORRADE_COMPARE(complex, points2DRotated); +} + +void TransformTest::transformVectors3D() { + auto matrix = MeshTools::transformVectors(Matrix4::rotationZ(Deg(90.0f)), points3D); + auto quaternion = MeshTools::transformVectors(Quaternion::rotation(Deg(90.0f), Vector3::zAxis()), points3D); + + CORRADE_COMPARE(matrix, points3DRotated); + CORRADE_COMPARE(quaternion, points3DRotated); +} + +void TransformTest::transformPoints2D() { + auto matrix = MeshTools::transformPoints( + Matrix3::translation(Vector2::yAxis(-1.0f))*Matrix3::rotation(Deg(90.0f)), points2D); + auto complex = MeshTools::transformPoints( + DualComplex::translation(Vector2::yAxis(-1.0f))*DualComplex::rotation(Deg(90.0f)), points2D); + + CORRADE_COMPARE(matrix, points2DRotatedTranslated); + CORRADE_COMPARE(complex, points2DRotatedTranslated); +} + +void TransformTest::transformPoints3D() { + auto matrix = MeshTools::transformPoints( + Matrix4::translation(Vector3::yAxis(-1.0f))*Matrix4::rotationZ(Deg(90.0f)), points3D); + auto quaternion = MeshTools::transformPoints( + DualQuaternion::translation(Vector3::yAxis(-1.0f))*DualQuaternion::rotation(Deg(90.0f), Vector3::zAxis()), points3D); + + CORRADE_COMPARE(matrix, points3DRotatedTranslated); + CORRADE_COMPARE(quaternion, points3DRotatedTranslated); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::MeshTools::Test::TransformTest) diff --git a/src/MeshTools/Tipsify.cpp b/src/MeshTools/Tipsify.cpp index 62514767e..e1f222a92 100644 --- a/src/MeshTools/Tipsify.cpp +++ b/src/MeshTools/Tipsify.cpp @@ -1,60 +1,67 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Tipsify.h" #include -using namespace std; - #ifndef DOXYGEN_GENERATING_OUTPUT namespace Magnum { namespace MeshTools { namespace Implementation { -void Tipsify::operator()(size_t cacheSize) { +void Tipsify::operator()(std::size_t cacheSize) { /* Neighboring triangles for each vertex, per-vertex live triangle count */ - std::vector liveTriangleCount, neighborPosition, neighbors; + std::vector liveTriangleCount, neighborPosition, neighbors; buildAdjacency(liveTriangleCount, neighborPosition, neighbors); /* Global time, per-vertex caching timestamps, per-triangle emmited flag */ - uint32_t time = cacheSize+1; - std::vector timestamp(vertexCount); + UnsignedInt time = cacheSize+1; + std::vector timestamp(vertexCount); std::vector emitted(indices.size()/3); /* Dead-end vertex stack */ - std::stack deadEndStack; + std::stack deadEndStack; /* Output index buffer */ - std::vector outputIndices; + std::vector outputIndices; outputIndices.reserve(indices.size()); /* Starting vertex for fanning, cursor */ - uint32_t fanningVertex = 0; - uint32_t i = 0; + UnsignedInt fanningVertex = 0; + UnsignedInt i = 0; while(fanningVertex != 0xFFFFFFFFu) { /* Array with candidates for next fanning vertex (in 1-ring around fanning vertex) */ - std::vector candidates; + std::vector candidates; /* For all neighbors of fanning vertex */ - for(uint32_t ti = neighborPosition[fanningVertex], t = neighbors[ti]; ti != neighborPosition[fanningVertex+1]; t = neighbors[++ti]) { + for(UnsignedInt ti = neighborPosition[fanningVertex], t = neighbors[ti]; ti != neighborPosition[fanningVertex+1]; t = neighbors[++ti]) { /* Continue if already emitted */ if(emitted[t]) continue; emitted[t] = true; /* Write all vertices of the triangle to output buffer */ - for(uint32_t vi = 0, v = indices[t*3]; vi != 3; v = indices[++vi+t*3]) { + for(UnsignedInt vi = 0, v = indices[t*3]; vi != 3; v = indices[++vi+t*3]) { outputIndices.push_back(v); /* Add to dead end stack and candidates array */ @@ -75,9 +82,9 @@ void Tipsify::operator()(size_t cacheSize) { fanningVertex = 0xFFFFFFFFu; /* Go through candidates in 1-ring around fanning vertex */ - int32_t candidatePriority = -1; + Int candidatePriority = -1; for(auto it = candidates.begin(); it != candidates.end(); ++it) { - uint32_t v = *it; + UnsignedInt v = *it; /* Skip if it doesn't have any live triangles */ if(!liveTriangleCount[v]) continue; @@ -85,7 +92,7 @@ void Tipsify::operator()(size_t cacheSize) { /* Get most fresh candidate which will still be in cache even after fanning. Every fanned triangle will generate at most two cache misses, thus 2*liveTriangleCount */ - int32_t priority = 0; + Int priority = 0; if(time-timestamp[v]+2*liveTriangleCount[v] <= cacheSize) priority = time-timestamp[v]; if(priority > candidatePriority) { @@ -121,12 +128,12 @@ void Tipsify::operator()(size_t cacheSize) { std::swap(indices, outputIndices); } -void Tipsify::buildAdjacency(std::vector& liveTriangleCount, std::vector& neighborOffset, std::vector& neighbors) const { +void Tipsify::buildAdjacency(std::vector& liveTriangleCount, std::vector& neighborOffset, std::vector& neighbors) const { /* How many times is each vertex referenced == count of neighboring triangles for each vertex */ liveTriangleCount.clear(); liveTriangleCount.resize(vertexCount); - for(size_t i = 0; i != indices.size(); ++i) + for(std::size_t i = 0; i != indices.size(); ++i) ++liveTriangleCount[indices[i]]; /* Building offset array from counts. Neighbors for i-th vertex will at @@ -136,8 +143,8 @@ void Tipsify::buildAdjacency(std::vector& liveTriangleCount, std::vect neighborOffset.clear(); neighborOffset.reserve(vertexCount+1); neighborOffset.push_back(0); - uint32_t sum = 0; - for(size_t i = 0; i != vertexCount; ++i) { + UnsignedInt sum = 0; + for(std::size_t i = 0; i != vertexCount; ++i) { neighborOffset.push_back(sum); sum += liveTriangleCount[i]; } @@ -146,7 +153,7 @@ void Tipsify::buildAdjacency(std::vector& liveTriangleCount, std::vect positioning */ neighbors.clear(); neighbors.resize(sum); - for(size_t i = 0; i != indices.size(); ++i) + for(std::size_t i = 0; i != indices.size(); ++i) neighbors[neighborOffset[indices[i]+1]++] = i/3; } diff --git a/src/MeshTools/Tipsify.h b/src/MeshTools/Tipsify.h index 69d65082e..057b76b96 100644 --- a/src/MeshTools/Tipsify.h +++ b/src/MeshTools/Tipsify.h @@ -1,27 +1,36 @@ #ifndef Magnum_MeshTools_Tipsify_h #define Magnum_MeshTools_Tipsify_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::tipsify() */ -#include #include +#include "Types.h" #include "magnumMeshToolsVisibility.h" namespace Magnum { namespace MeshTools { @@ -31,7 +40,7 @@ namespace Implementation { class MAGNUM_MESHTOOLS_EXPORT Tipsify { public: - inline Tipsify(std::vector& indices, std::uint32_t vertexCount): indices(indices), vertexCount(vertexCount) {} + inline Tipsify(std::vector& indices, UnsignedInt vertexCount): indices(indices), vertexCount(vertexCount) {} void operator()(std::size_t cacheSize); @@ -42,11 +51,11 @@ class MAGNUM_MESHTOOLS_EXPORT Tipsify { * (used internally). * @todo Export only for unit test, hide otherwise */ - void buildAdjacency(std::vector& liveTriangleCount, std::vector& neighborOffset, std::vector& neighbors) const; + void buildAdjacency(std::vector& liveTriangleCount, std::vector& neighborOffset, std::vector& neighbors) const; private: - std::vector& indices; - const std::uint32_t vertexCount; + std::vector& indices; + const UnsignedInt vertexCount; }; } @@ -64,7 +73,7 @@ array for beter usage of post-transform vertex cache. Algorithm used: for Vertex Locality and Reduced Overdraw, SIGGRAPH 2007, http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/index.php*. */ -inline void tipsify(std::vector& indices, std::uint32_t vertexCount, std::size_t cacheSize) { +inline void tipsify(std::vector& indices, UnsignedInt vertexCount, std::size_t cacheSize) { Implementation::Tipsify(indices, vertexCount)(cacheSize); } diff --git a/src/MeshTools/Transform.h b/src/MeshTools/Transform.h index c269fe71a..d04260275 100644 --- a/src/MeshTools/Transform.h +++ b/src/MeshTools/Transform.h @@ -1,42 +1,144 @@ #ifndef Magnum_MeshTools_Transform_h #define Magnum_MeshTools_Transform_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::transform() + * @brief Function Magnum::MeshTools::transformVectorsInPlace(), Magnum::MeshTools::transformVectors(), Magnum::MeshTools::transformPointsInPlace(), Magnum::MeshTools::transformPoints() */ -#include "Math/Matrix.h" +#include "Math/DualQuaternion.h" +#include "Math/DualComplex.h" namespace Magnum { namespace MeshTools { /** -@brief Transform vertices using given matrix +@brief Transform vectors in-place using given transformation -Usable for mesh transformations that would otherwise negatively affect -dependent objects, such as (uneven) scaling. Example usage: +Usable for one-time mesh transformations that would otherwise negatively affect +dependent objects, such as (uneven) scaling. Accepts any forward-iterable type +with compatible vector type as @p vectors. Expects that @ref Math::Quaternion "Quaternion" +is normalized, no further requirements are for other transformation +representations. +Unlike in transformPointsInPlace(), the transformation does not involve +translation. + +Example usage: @code -std::vector vertices; -MeshTools::transform(Matrix4::scaling({2.0f, 0.5f, 0.0f}), vertices); +std::vector vectors; +auto transformation = Quaternion::rotation(35.0_degf, Vector3::yAxis()); +MeshTools::transformVectorsInPlace(rotation, vectors); @endcode + +@see transformVectors(), Matrix3::transformVector(), Matrix4::transformVector(), + Complex::transformVectorNormalized(), Quaternion::transformVectorNormalized() +@todo GPU transform feedback implementation (otherwise this is only bad joke) +*/ +template void transformVectorsInPlace(const Math::Quaternion& normalizedQuaternion, U& vectors) { + for(auto& vector: vectors) vector = normalizedQuaternion.transformVectorNormalized(vector); +} + +/** @overload */ +template void transformVectorsInPlace(const Math::Complex& complex, U& vectors) { + for(auto& vector: vectors) vector = complex.transformVector(vector); +} + +/** @overload */ +template void transformVectorsInPlace(const Math::Matrix3& matrix, U& vectors) { + for(auto& vector: vectors) vector = matrix.transformVector(vector); +} + +/** @overload */ +template void transformVectorsInPlace(const Math::Matrix4& matrix, U& vectors) { + for(auto& vector: vectors) vector = matrix.transformVector(vector); +} + +/** +@brief Transform vectors using given transformation + +Returns transformed vectors instead of modifying them in-place. See +transformVectorsInPlace() for more information. +*/ +template U transformVectors(const T& transformation, U vectors) { + U result(std::move(vectors)); + transformVectorsInPlace(transformation, result); + return result; +} + +/** +@brief Transform points in-place using given transformation + +Usable for one-time mesh transformations that would otherwise negatively affect +dependent objects, such as (uneven) scaling. Accepts any forward-iterable type +with compatible vector type as @p vectors. Expects that +@ref Math::DualQuaternion "DualQuaternion" is normalized, no further +requirements are for other transformation representations. + +Unlike in transformVectorsInPlace(), the transformation also involves +translation. + +Example usage: +@code +std::vector points; +auto transformation = DualQuaternion::rotation(35.0_degf, Vector3::yAxis())* + DualQuaternion::translation({0.5f, -1.0f, 3.0f}); +MeshTools::transformPointsInPlace(rotation, points); +@endcode + +@see transformPoints(), Matrix3::transformPoint(), Matrix4::transformPoint(), + DualQuaternion::transformPointNormalized() +*/ +template void transformPointsInPlace(const Math::DualQuaternion& normalizedDualQuaternion, U& points) { + for(auto& point: points) point = normalizedDualQuaternion.transformPointNormalized(point); +} + +/** @overload */ +template void transformPointsInPlace(const Math::DualComplex& dualComplex, U& points) { + for(auto& point: points) point = dualComplex.transformPoint(point); +} + +/** @overload */ +template void transformPointsInPlace(const Math::Matrix3& matrix, U& points) { + for(auto& point: points) point = matrix.transformPoint(point); +} + +/** @overload */ +template void transformPointsInPlace(const Math::Matrix4& matrix, U& points) { + for(auto& point: points) point = matrix.transformPoint(point); +} + +/** +@brief Transform points using given transformation + +Returns transformed points instead of modifying them in-place. See +transformPointsInPlace() for more information. */ -template inline void transform(const Math::Matrix& matrix, U& vertices) { - for(auto it = vertices.begin(); it != vertices.end(); ++it) - *it = matrix**it; +template U transformPoints(const T& transformation, U vectors) { + U result(std::move(vectors)); + transformPointsInPlace(transformation, result); + return result; } }} diff --git a/src/MeshTools/magnumMeshToolsVisibility.h b/src/MeshTools/magnumMeshToolsVisibility.h index ebef4ae43..2c4934962 100644 --- a/src/MeshTools/magnumMeshToolsVisibility.h +++ b/src/MeshTools/magnumMeshToolsVisibility.h @@ -1,18 +1,27 @@ #ifndef Magnum_MeshTools_magnumMeshToolsVisibility_h #define Magnum_MeshTools_magnumMeshToolsVisibility_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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. */ #ifdef _WIN32 diff --git a/src/OpenGL.cpp b/src/OpenGL.cpp new file mode 100644 index 000000000..7a0dbeee2 --- /dev/null +++ b/src/OpenGL.cpp @@ -0,0 +1,44 @@ +/* + 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 "OpenGL.h" +#include "Types.h" + +namespace Magnum { + +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"); +static_assert(std::is_same::value, "GLshort is not the same as Short"); +static_assert(std::is_same::value, "GLuint is not the same as UnsignedInt"); +static_assert(std::is_same::value, "GLint is not the same as Int"); +static_assert(std::is_same::value, "GLsizei is not the same as Int"); +static_assert(std::is_same::value, "GLfloat is not the same as Float"); +#ifndef MAGNUM_TARGET_GLES +static_assert(std::is_same::value, "GLdouble is not the same as Double"); +#endif + +} diff --git a/src/OpenGL.h b/src/OpenGL.h new file mode 100644 index 000000000..c166dea07 --- /dev/null +++ b/src/OpenGL.h @@ -0,0 +1,45 @@ +#ifndef Magnum_OpenGL_h +#define Magnum_OpenGL_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 OpenGL headers + */ + +#include "magnumConfigure.h" + +#ifndef MAGNUM_TARGET_GLES +#include +#include +#else +#ifndef MAGNUM_TARGET_GLES2 +#include +#else +#include +#include +#endif +#endif + +#endif diff --git a/src/Physics/AbstractShape.cpp b/src/Physics/AbstractShape.cpp index 5ce4474bd..2321bd481 100644 --- a/src/Physics/AbstractShape.cpp +++ b/src/Physics/AbstractShape.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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" @@ -19,7 +28,7 @@ namespace Magnum { namespace Physics { -template bool AbstractShape::collides(const AbstractShape* other) const { +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); @@ -31,7 +40,9 @@ template class AbstractShape<2>; template class AbstractShape<3>; #ifndef DOXYGEN_GENERATING_OUTPUT -Debug operator<<(Debug debug, AbstractShape2D::Type value) { +namespace Implementation { + +Debug operator<<(Debug debug, ShapeDimensionTraits<2>::Type value) { switch(value) { #define _val(value) case AbstractShape2D::Type::value: return debug << "AbstractShape2D::Type::" #value; _val(Point) @@ -48,7 +59,7 @@ Debug operator<<(Debug debug, AbstractShape2D::Type value) { return debug << "AbstractShape2D::Type::(unknown)"; } -Debug operator<<(Debug debug, AbstractShape3D::Type value) { +Debug operator<<(Debug debug, ShapeDimensionTraits<3>::Type value) { switch(value) { #define _val(value) case AbstractShape3D::Type::value: return debug << "AbstractShape3D::Type::" #value; _val(Point) @@ -65,6 +76,8 @@ Debug operator<<(Debug debug, AbstractShape3D::Type value) { return debug << "AbstractShape2D::Type::(unknown)"; } + +} #endif }} diff --git a/src/Physics/AbstractShape.h b/src/Physics/AbstractShape.h index cebb5f61e..ea5083982 100644 --- a/src/Physics/AbstractShape.h +++ b/src/Physics/AbstractShape.h @@ -1,22 +1,31 @@ #ifndef Magnum_Physics_AbstractShape_h #define Magnum_Physics_AbstractShape_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 + * @brief Class Magnum::Physics::AbstractShape, typedef Magnum::Physics::AbstractShape2D, Magnum::Physics::AbstractShape3D */ #include "Magnum.h" @@ -28,7 +37,7 @@ namespace Magnum { namespace Physics { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - template struct ShapeDimensionTraits {}; + template struct ShapeDimensionTraits {}; template<> struct ShapeDimensionTraits<2> { enum class Type { @@ -56,6 +65,9 @@ namespace Implementation { Plane }; }; + + Debug MAGNUM_PHYSICS_EXPORT operator<<(Debug debug, ShapeDimensionTraits<2>::Type value); + Debug MAGNUM_PHYSICS_EXPORT operator<<(Debug debug, ShapeDimensionTraits<3>::Type value); } #endif @@ -65,10 +77,10 @@ namespace Implementation { See @ref collision-detection for brief introduction. @see AbstractShape2D, AbstractShape3D */ -template class MAGNUM_PHYSICS_EXPORT AbstractShape { +template class MAGNUM_PHYSICS_EXPORT AbstractShape { public: /** @brief Dimension count */ - static const std::uint8_t Dimensions = dimensions; + static const UnsignedInt Dimensions = dimensions; /** * @brief Shape type @@ -93,7 +105,7 @@ template class MAGNUM_PHYSICS_EXPORT AbstractShape { typedef typename Implementation::ShapeDimensionTraits::Type Type; #endif - /** @brief Destructor */ + explicit AbstractShape() = default; virtual inline ~AbstractShape() {} /** @brief Shape type */ @@ -118,18 +130,16 @@ template class MAGNUM_PHYSICS_EXPORT AbstractShape { virtual bool collides(const AbstractShape* other) const; }; + /** @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} */ -#ifndef DOXYGEN_GENERATING_OUTPUT -Debug MAGNUM_PHYSICS_EXPORT operator<<(Debug debug, AbstractShape2D::Type value); -Debug MAGNUM_PHYSICS_EXPORT operator<<(Debug debug, AbstractShape3D::Type value); -#else -template Debug operator<<(Debug debug, typename AbstractShape::Type value); +template Debug operator<<(Debug debug, typename AbstractShape::Type value); #endif }} diff --git a/src/Physics/AxisAlignedBox.cpp b/src/Physics/AxisAlignedBox.cpp index 9c2f004cf..5b7a5d7bb 100644 --- a/src/Physics/AxisAlignedBox.cpp +++ b/src/Physics/AxisAlignedBox.cpp @@ -1,31 +1,55 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AxisAlignedBox.h" #include "Math/Matrix3.h" #include "Math/Matrix4.h" +#include "Physics/Point.h" namespace Magnum { namespace Physics { -template void AxisAlignedBox::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedPosition = (matrix*typename DimensionTraits::PointType(_position)).vector(); - _transformedSize = matrix.rotationScaling()*_size; +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 bool AxisAlignedBox::operator%(const Point& other) const { + return (other.transformedPosition() >= _transformedMin).all() && + (other.transformedPosition() < _transformedMax).all(); } -template class AxisAlignedBox<2>; -template class AxisAlignedBox<3>; +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox<2>; +template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox<3>; +#endif }} diff --git a/src/Physics/AxisAlignedBox.h b/src/Physics/AxisAlignedBox.h index 15f96d1c3..bcb164434 100644 --- a/src/Physics/AxisAlignedBox.h +++ b/src/Physics/AxisAlignedBox.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_AxisAlignedBox_h #define Magnum_Physics_AxisAlignedBox_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -20,7 +29,8 @@ */ #include "Math/Vector3.h" -#include "AbstractShape.h" +#include "Physics/AbstractShape.h" +#include "Physics/Physics.h" #include "corradeCompatibility.h" @@ -30,11 +40,12 @@ namespace Magnum { namespace Physics { @brief Axis-aligned box @see AxisAlignedBox2D, AxisAlignedBox3D +@todo Assert for rotation */ -template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox: public AbstractShape { +template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox: public AbstractShape { public: /** @brief Constructor */ - inline AxisAlignedBox(const typename DimensionTraits::VectorType& position, const typename DimensionTraits::VectorType& size): _position(position), _transformedPosition(position), _size(size), _transformedSize(size) {} + 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; @@ -42,37 +53,42 @@ template class MAGNUM_PHYSICS_EXPORT AxisAlignedBox: pu void applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) override; - /** @brief Position */ - inline typename DimensionTraits::VectorType position() const { - return _position; + bool collides(const AbstractShape* other) const override; + + /** @brief Minimal coordinates */ + inline typename DimensionTraits::VectorType min() const { + return _min; } - /** @brief Set position */ - inline void setPosition(const typename DimensionTraits::VectorType& position) { - _position = position; + /** @brief Set minimal coordinates */ + inline void setMin(const typename DimensionTraits::VectorType& min) { + _min = min; } - /** @brief Size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + /** @brief Maximal coordinates */ + inline typename DimensionTraits::VectorType max() const { return _max; } - /** @brief Set size */ - inline void setSize(const typename DimensionTraits::VectorType& size) { - _size = size; + /** @brief Set maximal coordinates */ + inline void setMax(const typename DimensionTraits::VectorType& max) { + _max = max; } - /** @brief Transformed position */ - inline typename DimensionTraits::VectorType transformedPosition() const { - return _transformedPosition; + /** @brief Transformed minimal coordinates */ + inline typename DimensionTraits::VectorType transformedMin() const { + return _transformedMin; } - /** @brief Transformed size */ - inline typename DimensionTraits::VectorType transformedSize() const { - return _transformedSize; + /** @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 _position, _transformedPosition, - _size, _transformedSize; + typename DimensionTraits::VectorType _min, _max, + _transformedMin, _transformedMax; }; /** @brief Two-dimensional axis-aligned box */ @@ -81,6 +97,9 @@ typedef AxisAlignedBox<2> AxisAlignedBox2D; /** @brief Three-dimensional axis-aligned box */ typedef AxisAlignedBox<3> AxisAlignedBox3D; +/** @collisionoperator{Point,AxisAlignedBox} */ +template inline bool operator%(const Point& a, const AxisAlignedBox& b) { return b % a; } + }} #endif diff --git a/src/Physics/Box.cpp b/src/Physics/Box.cpp index d71c6d570..3f724793e 100644 --- a/src/Physics/Box.cpp +++ b/src/Physics/Box.cpp @@ -1,26 +1,34 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Box.h" #include "Math/Matrix4.h" -#include "Math/Point3D.h" namespace Magnum { namespace Physics { -template void Box::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { +template void Box::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { _transformedTransformation = matrix*_transformation; } diff --git a/src/Physics/Box.h b/src/Physics/Box.h index 272236540..e442e915d 100644 --- a/src/Physics/Box.h +++ b/src/Physics/Box.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Box_h #define Magnum_Physics_Box_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -32,11 +41,12 @@ namespace Magnum { namespace Physics { @todo Use quat + position + size instead? @see Box2D, Box3D +@todo Assert for skew */ -template class MAGNUM_PHYSICS_EXPORT Box: public AbstractShape { +template class MAGNUM_PHYSICS_EXPORT Box: public AbstractShape { public: /** @brief Constructor */ - inline Box(const typename DimensionTraits::MatrixType& transformation): _transformation(transformation), _transformedTransformation(transformation) {} + inline explicit Box(const typename DimensionTraits::MatrixType& transformation): _transformation(transformation), _transformedTransformation(transformation) {} inline typename AbstractShape::Type type() const override { return AbstractShape::Type::Box; diff --git a/src/Physics/CMakeLists.txt b/src/Physics/CMakeLists.txt index c2b35ce8a..aa4a2afe2 100644 --- a/src/Physics/CMakeLists.txt +++ b/src/Physics/CMakeLists.txt @@ -1,28 +1,45 @@ +# +# 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. +# + set(MagnumPhysics_SRCS AbstractShape.cpp AxisAlignedBox.cpp Box.cpp Capsule.cpp - DebugDrawResourceManager.cpp Line.cpp Plane.cpp Point.cpp ObjectShape.cpp ObjectShapeGroup.cpp ShapeGroup.cpp - Sphere.cpp - - Implementation/AbstractBoxRenderer.cpp - Implementation/AbstractDebugRenderer.cpp - Implementation/AxisAlignedBoxRenderer.cpp - Implementation/BoxRenderer.cpp) + Sphere.cpp) set(MagnumPhysics_HEADERS AbstractShape.h AxisAlignedBox.h Box.h Capsule.h - DebugDrawResourceManager.h Line.h LineSegment.h ObjectShape.h @@ -36,13 +53,11 @@ set(MagnumPhysics_HEADERS magnumPhysicsVisibility.h) add_library(MagnumPhysics SHARED ${MagnumPhysics_SRCS}) - -target_link_libraries(MagnumPhysics Magnum MagnumPrimitives MagnumSceneGraph MagnumShaders) +target_link_libraries(MagnumPhysics Magnum MagnumSceneGraph) install(TARGETS MagnumPhysics DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumPhysics_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Physics) if(BUILD_TESTS) - enable_testing() add_subdirectory(Test) endif() diff --git a/src/Physics/Capsule.cpp b/src/Physics/Capsule.cpp index 8fc516ba6..09823df5d 100644 --- a/src/Physics/Capsule.cpp +++ b/src/Physics/Capsule.cpp @@ -1,22 +1,30 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Capsule.h" -#include "Math/Constants.h" -#include "Math/Math.h" +#include "Math/Functions.h" #include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Math/Geometry/Distance.h" @@ -27,14 +35,14 @@ using namespace Magnum::Math::Geometry; namespace Magnum { namespace Physics { -template void Capsule::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedA = (matrix*typename DimensionTraits::PointType(_a)).vector(); - _transformedB = (matrix*typename DimensionTraits::PointType(_b)).vector(); - float scaling = (matrix.rotationScaling()*typename DimensionTraits::VectorType(1/Constants::sqrt3())).length(); +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 { +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) @@ -43,17 +51,19 @@ template bool Capsule::collides(const Abstr return AbstractShape::collides(other); } -template bool Capsule::operator%(const Point& other) const { +template bool Capsule::operator%(const Point& other) const { return Distance::lineSegmentPointSquared(transformedA(), transformedB(), other.transformedPosition()) < Math::pow<2>(transformedRadius()); } -template bool Capsule::operator%(const Sphere& other) const { +template bool Capsule::operator%(const Sphere& other) const { return Distance::lineSegmentPointSquared(transformedA(), transformedB(), other.transformedPosition()) < Math::pow<2>(transformedRadius()+other.transformedRadius()); } -template class Capsule<2>; -template class Capsule<3>; +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PHYSICS_EXPORT Capsule<2>; +template class MAGNUM_PHYSICS_EXPORT Capsule<3>; +#endif }} diff --git a/src/Physics/Capsule.h b/src/Physics/Capsule.h index e2ff9da69..bdb9975d7 100644 --- a/src/Physics/Capsule.h +++ b/src/Physics/Capsule.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Capsule_h #define Magnum_Physics_Capsule_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -33,11 +42,12 @@ namespace Magnum { namespace Physics { Unlike other elements the capsule doesn't support asymmetric scaling. When applying transformation, the scale factor is averaged from all axes. @see Capsule2D, Capsule3D +@todo Assert for asymmetric scaling */ -template class MAGNUM_PHYSICS_EXPORT Capsule: public AbstractShape { +template class MAGNUM_PHYSICS_EXPORT Capsule: public AbstractShape { public: /** @brief Constructor */ - inline 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 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; @@ -68,10 +78,10 @@ template class MAGNUM_PHYSICS_EXPORT Capsule: public Ab } /** @brief Radius */ - inline float radius() const { return _radius; } + inline Float radius() const { return _radius; } /** @brief Set radius */ - inline void setRadius(float radius) { _radius = radius; } + inline void setRadius(Float radius) { _radius = radius; } /** @brief Transformed first point */ inline typename DimensionTraits::VectorType transformedA() const { @@ -84,7 +94,7 @@ template class MAGNUM_PHYSICS_EXPORT Capsule: public Ab } /** @brief Transformed radius */ - inline float transformedRadius() const { + inline Float transformedRadius() const { return _transformedRadius; } @@ -97,7 +107,7 @@ template class MAGNUM_PHYSICS_EXPORT Capsule: public Ab private: typename DimensionTraits::VectorType _a, _transformedA, _b, _transformedB; - float _radius, _transformedRadius; + Float _radius, _transformedRadius; }; /** @brief Two-dimensional capsule */ @@ -107,10 +117,10 @@ typedef Capsule<2> Capsule2D; typedef Capsule<3> Capsule3D; /** @collisionoperator{Point,Capsule} */ -template inline bool operator%(const Point& a, const Capsule& b) { return b % a; } +template inline bool operator%(const Point& a, const Capsule& b) { return b % a; } /** @collisionoperator{Sphere,Capsule} */ -template inline bool operator%(const Sphere& a, const Capsule& b) { return b % a; } +template inline bool operator%(const Sphere& a, const Capsule& b) { return b % a; } }} diff --git a/src/Physics/DebugDrawResourceManager.cpp b/src/Physics/DebugDrawResourceManager.cpp deleted file mode 100644 index ba2560e02..000000000 --- a/src/Physics/DebugDrawResourceManager.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#define MAGNUM_RESOURCEMANAGER_DEFINE_INTERNALINSTANCE - -#include "DebugDrawResourceManager.h" - -#include "AbstractShaderProgram.h" -#include "Buffer.h" -#include "Mesh.h" -#include "ResourceManager.h" -#include "Shaders/FlatShader.h" -#include "AbstractShape.h" -#include "AxisAlignedBox.h" -#include "Box.h" -#include "ObjectShape.h" -#include "ShapeGroup.h" -#include "Implementation/AxisAlignedBoxRenderer.h" -#include "Implementation/BoxRenderer.h" -#include "Implementation/DebugRenderer.h" - -namespace Magnum { - -template class ResourceManager; - -namespace Physics { - -template SceneGraph::Drawable* DebugDrawResourceManager::createDebugRenderer(ObjectShape* shape, ResourceKey options) { - Implementation::DebugRenderer* renderer = new Implementation::DebugRenderer(shape->object(), instance()->get(options)); - createDebugMesh(renderer, shape->shape()); - return renderer; -} - -template SceneGraph::Drawable<2> MAGNUM_PHYSICS_EXPORT * DebugDrawResourceManager::createDebugRenderer(ObjectShape<2>* shape, ResourceKey options); -template SceneGraph::Drawable<3> MAGNUM_PHYSICS_EXPORT * DebugDrawResourceManager::createDebugRenderer(ObjectShape<3>* shape, ResourceKey options); - -void DebugDrawResourceManager::createDebugMesh(Implementation::DebugRenderer<2>* renderer, AbstractShape2D* shape) { - switch(shape->type()) { - case AbstractShape2D::Type::AxisAlignedBox: - renderer->addRenderer(new Implementation::AxisAlignedBoxRenderer<2>(*static_cast(shape))); - case AbstractShape2D::Type::Box: - renderer->addRenderer(new Implementation::BoxRenderer<2>(*static_cast(shape))); - break; - case AbstractShape2D::Type::ShapeGroup: { - ShapeGroup2D* group = static_cast(shape); - if(group->first()) createDebugMesh(renderer, group->first()); - if(group->second()) createDebugMesh(renderer, group->second()); - break; - } - default: - Warning() << "Physics::DebugDrawResourceManager::createDebugRenderer(): type" << shape->type() << "not implemented"; - } -} - -void DebugDrawResourceManager::createDebugMesh(Implementation::DebugRenderer<3>*, AbstractShape3D*) {} - -DebugDrawResourceManager::DebugDrawResourceManager() { - setFallback(new Options); - set("shader2d", new Shaders::FlatShader<2>, ResourceDataState::Final, ResourcePolicy::Resident); -} - -DebugDrawResourceManager::~DebugDrawResourceManager() {} - -}} diff --git a/src/Physics/DebugDrawResourceManager.h b/src/Physics/DebugDrawResourceManager.h deleted file mode 100644 index ffabe9350..000000000 --- a/src/Physics/DebugDrawResourceManager.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef Magnum_Physics_DebugDrawResourceManager_h -#define Magnum_Physics_DebugDrawResourceManager_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file - * @brief Class Magnum::Physics::DebugDrawResourceManager - */ - -#include "Magnum.h" -#include "Color.h" - -#ifndef MAGNUM_RESOURCEMANAGER_DEFINE_INTERNALINSTANCE -#define MAGNUM_RESOURCEMANAGER_DONT_DEFINE_INTERNALINSTANCE -#endif -#include "ResourceManager.h" - -#include "SceneGraph/SceneGraph.h" -#include "Physics.h" - -#include "magnumPhysicsVisibility.h" - -namespace Magnum { - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Physics { namespace Implementation { - struct Options { - Color3<> color; - }; - template class DebugRenderer; -}} -#endif - -extern template ResourceManager MAGNUM_PHYSICS_EXPORT *& ResourceManager::internalInstance(); - -namespace Physics { - -/** -@brief %Resource manager for physics debug draw - -Can create objects which draw object collision shape for debugging purposes. - -@section DebugDrawResourceManager-usage Basic usage -The manager must be instanced for the whole lifetime of debug draw objects. -To create debug renderers, call createDebugRenderer() and add the resulting -drawable to some group. You can specify options via Options struct - add it to -the manager and then create debug renderer with the same options key. This way -you can easily share the same options with more renderers. If no options for -given key exist, default is used. - -Example code: -@code -// Group of drawables,preferrably dedicated for debug renderers, so you can -// easily enable or disable debug draw -DrawableGroup2D group; - -// Instance the manager at first -DebugDrawResourceManager manager; - -// Create some options -auto o = new DebugDrawResourceManager::Options { - {1.0f, 0.0f, 0.0f} // Red color -}; -manager->set("red", o, ResourceDataState::Final, ResourcePolicy::Persistent); - -// Create debug renderer for given shape, use "red" options for it. Don't -// forget to add it to some drawable group. -ObjectShape2D* shape; -group.add(DebugDrawResourceManager::createDebugRenderer(shape, "red")); -@endcode -*/ -class MAGNUM_PHYSICS_EXPORT DebugDrawResourceManager: public ResourceManager { - public: - #ifdef DOXYGEN_GENERATING_OUTPUT - /** @brief %Options */ - struct Options { - Color3<> color; /**< @brief Color */ - }; - #else - typedef Implementation::Options Options; - #endif - - /** - * @brief Create debug renderer for given shape - * @param shape Shape for which to create debug renderer - * @param options Options resource key. See - * @ref DebugDrawResourceManager-usage "class documentation" for - * more information. - * - * Returned drawable is not part of any group, you have to add it to - * one yourself. - */ - template static SceneGraph::Drawable* createDebugRenderer(ObjectShape* shape, ResourceKey options = ResourceKey()); - - DebugDrawResourceManager(); - ~DebugDrawResourceManager(); - - private: - static void createDebugMesh(Implementation::DebugRenderer<2>* renderer, AbstractShape2D* shape); - static void createDebugMesh(Implementation::DebugRenderer<3>* renderer, AbstractShape3D* shape); -}; - -}} - -#endif diff --git a/src/Physics/Implementation/AbstractBoxRenderer.cpp b/src/Physics/Implementation/AbstractBoxRenderer.cpp deleted file mode 100644 index 95e7cdaeb..000000000 --- a/src/Physics/Implementation/AbstractBoxRenderer.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AbstractBoxRenderer.h" - -#include "Buffer.h" -#include "Physics/DebugDrawResourceManager.h" -#include "Primitives/Cube.h" -#include "Primitives/Square.h" -#include "Shaders/FlatShader.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -namespace { - template struct BoxMesh {}; - - template<> struct BoxMesh<2> { - static ResourceKey shader() { return {"shader2d"}; } - static ResourceKey key() { return {"box2d"}; } - - static Mesh* mesh(Buffer* buffer) { - Primitives::Square square; - Mesh* mesh = new Mesh; - buffer->setData(*square.positions(0), Buffer::Usage::StaticDraw); - return mesh->setPrimitive(square.primitive()) - ->setVertexCount(square.positions(0)->size()) - ->addVertexBuffer(buffer, Shaders::FlatShader<2>::Position()); - } - }; - - template<> struct BoxMesh<3> { - static ResourceKey shader() { return {"shader3d"}; } - static ResourceKey key() { return {"box3d"}; } - - static Mesh* mesh(Buffer* buffer) { - Primitives::Cube cube; - Mesh* mesh = new Mesh; - buffer->setData(*cube.positions(0), Buffer::Usage::StaticDraw); - return mesh->setPrimitive(cube.primitive()) - ->setVertexCount(cube.positions(0)->size()) - ->addVertexBuffer(buffer, Shaders::FlatShader<2>::Position()); - } - }; -} - -template AbstractBoxRenderer::AbstractBoxRenderer(): AbstractDebugRenderer(BoxMesh::shader(), BoxMesh::key()), buffer(DebugDrawResourceManager::instance()->get(BoxMesh::key())) { - if(!this->mesh) { - DebugDrawResourceManager::instance()->set(this->buffer.key(), new Buffer, ResourceDataState::Final, ResourcePolicy::Manual); - DebugDrawResourceManager::instance()->set(this->mesh.key(), BoxMesh::mesh(buffer), ResourceDataState::Final, ResourcePolicy::Manual); - } -} - -template AbstractBoxRenderer::~AbstractBoxRenderer() {} - -template class AbstractBoxRenderer<2>; -template class AbstractBoxRenderer<3>; - -}}} diff --git a/src/Physics/Implementation/AbstractBoxRenderer.h b/src/Physics/Implementation/AbstractBoxRenderer.h deleted file mode 100644 index 2c7bcea28..000000000 --- a/src/Physics/Implementation/AbstractBoxRenderer.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Magnum_Physics_Implementation_AbstractBoxRenderer_h -#define Magnum_Physics_Implementation_AbstractBoxRenderer_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AbstractDebugRenderer.h" - -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template class AbstractBoxRenderer: public AbstractDebugRenderer { - public: - AbstractBoxRenderer(); - - ~AbstractBoxRenderer(); - - protected: - Resource buffer; -}; - -}}} - -#endif diff --git a/src/Physics/Implementation/AbstractDebugRenderer.cpp b/src/Physics/Implementation/AbstractDebugRenderer.cpp deleted file mode 100644 index dbd41dcd7..000000000 --- a/src/Physics/Implementation/AbstractDebugRenderer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AbstractDebugRenderer.h" - -#include "AbstractShaderProgram.h" -#include "Mesh.h" -#include "Physics/DebugDrawResourceManager.h" -#include "Shaders/FlatShader.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template AbstractDebugRenderer::AbstractDebugRenderer(ResourceKey shader, ResourceKey mesh): shader(DebugDrawResourceManager::instance()->get>(shader)), mesh(DebugDrawResourceManager::instance()->get(mesh)) {} - -template AbstractDebugRenderer::~AbstractDebugRenderer() {} - -template class AbstractDebugRenderer<2>; -template class AbstractDebugRenderer<3>; - -}}} diff --git a/src/Physics/Implementation/AbstractDebugRenderer.h b/src/Physics/Implementation/AbstractDebugRenderer.h deleted file mode 100644 index 04e7a8a6b..000000000 --- a/src/Physics/Implementation/AbstractDebugRenderer.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef Magnum_Physics_Implementation_AbstractDebugRenderer_h -#define Magnum_Physics_Implementation_AbstractDebugRenderer_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "DimensionTraits.h" -#include "ResourceManager.h" -#include "SceneGraph/SceneGraph.h" -#include "Shaders/Shaders.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -struct Options; - -template class AbstractDebugRenderer { - public: - AbstractDebugRenderer(ResourceKey shader, ResourceKey mesh); - - virtual ~AbstractDebugRenderer(); - - virtual void draw(Resource& options, const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) = 0; - - protected: - Resource> shader; - Resource mesh; -}; - -}}} - -#endif diff --git a/src/Physics/Implementation/AbstractShapeRenderer.cpp b/src/Physics/Implementation/AbstractShapeRenderer.cpp deleted file mode 100644 index ee4d3596e..000000000 --- a/src/Physics/Implementation/AbstractShapeRenderer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AbstractShapeRenderer.h" - -#include "AbstractShaderProgram.h" -#include "Mesh.h" -#include "Physics/DebugDrawResourceManager.h" -#include "Shaders/FlatShader.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template AbstractShapeRenderer::AbstractShapeRenderer(ResourceKey shader, ResourceKey mesh): shader(DebugDrawResourceManager::instance()->get>(shader)), mesh(DebugDrawResourceManager::instance()->get(mesh)) {} - -template AbstractShapeRenderer::~AbstractShapeRenderer() {} - -template class AbstractShapeRenderer<2>; -template class AbstractShapeRenderer<3>; - -}}} diff --git a/src/Physics/Implementation/AbstractShapeRenderer.h b/src/Physics/Implementation/AbstractShapeRenderer.h deleted file mode 100644 index 737e29895..000000000 --- a/src/Physics/Implementation/AbstractShapeRenderer.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef Magnum_Physics_Implementation_AbstractShapeRenderer_h -#define Magnum_Physics_Implementation_AbstractShapeRenderer_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "DimensionTraits.h" -#include "ResourceManager.h" -#include "SceneGraph/SceneGraph.h" - -namespace Magnum { - -class AbstractShaderProgram; -class Mesh; - -namespace Shaders { - template class FlatShader; -} - -namespace Physics { namespace Implementation { - -struct Options; - -template class AbstractShapeRenderer { - public: - AbstractShapeRenderer(ResourceKey shader, ResourceKey mesh); - - virtual ~AbstractShapeRenderer(); - - virtual void draw(Resource& options, const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) = 0; - - protected: - Resource> shader; - Resource mesh; -}; - -}}} - -#endif diff --git a/src/Physics/Implementation/AxisAlignedBoxRenderer.cpp b/src/Physics/Implementation/AxisAlignedBoxRenderer.cpp deleted file mode 100644 index 97102bf35..000000000 --- a/src/Physics/Implementation/AxisAlignedBoxRenderer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AxisAlignedBoxRenderer.h" - -#include "Mesh.h" -#include "Physics/DebugDrawResourceManager.h" -#include "SceneGraph/AbstractCamera.h" -#include "Shaders/FlatShader.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template void AxisAlignedBoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType&, typename SceneGraph::AbstractCamera* camera) { - typename DimensionTraits::MatrixType transformation = - DimensionTraits::MatrixType::translation(axisAlignedBox.transformedPosition())* - DimensionTraits::MatrixType::scaling(axisAlignedBox.transformedSize()); - this->shader->setTransformationProjectionMatrix(camera->projectionMatrix()*camera->cameraMatrix()*transformation) - ->setColor(options->color) - ->use(); - this->mesh->draw(); -} - -template class AxisAlignedBoxRenderer<2>; -template class AxisAlignedBoxRenderer<3>; - -}}} diff --git a/src/Physics/Implementation/AxisAlignedBoxRenderer.h b/src/Physics/Implementation/AxisAlignedBoxRenderer.h deleted file mode 100644 index 7eae09acf..000000000 --- a/src/Physics/Implementation/AxisAlignedBoxRenderer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Magnum_Physics_Implementation_AxisAlignedBoxRenderer_h -#define Magnum_Physics_Implementation_AxisAlignedBoxRenderer_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AbstractBoxRenderer.h" - -#include "Physics/AxisAlignedBox.h" - -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template class AxisAlignedBoxRenderer: public AbstractBoxRenderer { - public: - inline AxisAlignedBoxRenderer(AxisAlignedBox& axisAlignedBox): axisAlignedBox(axisAlignedBox) {} - - void draw(Resource& options, const typename DimensionTraits::MatrixType& transformation, typename SceneGraph::AbstractCamera* camera) override; - - private: - AxisAlignedBox& axisAlignedBox; -}; - -}}} - -#endif diff --git a/src/Physics/Implementation/BoxRenderer.cpp b/src/Physics/Implementation/BoxRenderer.cpp deleted file mode 100644 index 840c6b306..000000000 --- a/src/Physics/Implementation/BoxRenderer.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "BoxRenderer.h" - -#include "Mesh.h" -#include "Physics/DebugDrawResourceManager.h" -#include "SceneGraph/AbstractCamera.h" -#include "Shaders/FlatShader.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template void BoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType&, typename SceneGraph::AbstractCamera* camera) { - this->shader->setTransformationProjectionMatrix(camera->projectionMatrix()*camera->cameraMatrix()*box.transformedTransformation()) - ->setColor(options->color) - ->use(); - this->mesh->draw(); -} - -template class BoxRenderer<2>; -template class BoxRenderer<3>; - -}}} diff --git a/src/Physics/Implementation/BoxRenderer.h b/src/Physics/Implementation/BoxRenderer.h deleted file mode 100644 index ef67869fd..000000000 --- a/src/Physics/Implementation/BoxRenderer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Magnum_Physics_Implementation_BoxRenderer_h -#define Magnum_Physics_Implementation_BoxRenderer_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "AbstractBoxRenderer.h" - -#include "Physics/Box.h" - -#include "corradeCompatibility.h" - -namespace Magnum { namespace Physics { namespace Implementation { - -template class BoxRenderer: public AbstractBoxRenderer { - public: - inline BoxRenderer(Box& box): box(box) {} - - void draw(Resource& options, const typename DimensionTraits::MatrixType& transformation, typename SceneGraph::AbstractCamera* camera) override; - - private: - Box& box; -}; - -}}} - -#endif diff --git a/src/Physics/Implementation/DebugRenderer.h b/src/Physics/Implementation/DebugRenderer.h deleted file mode 100644 index 454c0df3c..000000000 --- a/src/Physics/Implementation/DebugRenderer.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef Magnum_Physics_Implementation_DebugRenderer_h -#define Magnum_Physics_Implementation_DebugRenderer_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "ResourceManager.h" -#include "SceneGraph/Drawable.h" -#include "AbstractDebugRenderer.h" - -namespace Magnum { - -class AbstractShaderProgram; -class Mesh; - -namespace Shaders { - template class FlatShader; -} - -namespace Physics { namespace Implementation { - -struct Options; - -template class DebugRenderer: public SceneGraph::Drawable { - public: - DebugRenderer(SceneGraph::AbstractObject* object, Resource&& options): SceneGraph::Drawable(object), options(options) {} - - inline ~DebugRenderer() { - for(auto it = renderers.begin(); it != renderers.end(); ++it) - delete *it; - } - - inline void addRenderer(AbstractDebugRenderer* renderer) { - renderers.push_back(renderer); - } - - inline void draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera* camera) override { - for(auto it = renderers.begin(); it != renderers.end(); ++it) - (*it)->draw(options, transformationMatrix, camera); - } - - private: - Resource options; - std::vector*> renderers; -}; - -}}} - -#endif diff --git a/src/Physics/Line.cpp b/src/Physics/Line.cpp index 49fbe566e..bcb5f9a15 100644 --- a/src/Physics/Line.cpp +++ b/src/Physics/Line.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Line.h" @@ -20,9 +29,9 @@ namespace Magnum { namespace Physics { -template void Line::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedA = (matrix*typename DimensionTraits::PointType(_a)).vector(); - _transformedB = (matrix*typename DimensionTraits::PointType(_b)).vector(); +template void Line::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { + _transformedA = matrix.transformPoint(_a); + _transformedB = matrix.transformPoint(_b); } /* Explicitly instantiate the templates */ diff --git a/src/Physics/Line.h b/src/Physics/Line.h index 9230be376..0c9abb333 100644 --- a/src/Physics/Line.h +++ b/src/Physics/Line.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Line_h #define Magnum_Physics_Line_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -32,10 +41,10 @@ namespace Magnum { namespace Physics { @see Line2D, Line3D @todo collision detection of two Line2D */ -template class MAGNUM_PHYSICS_EXPORT Line: public AbstractShape { +template class MAGNUM_PHYSICS_EXPORT Line: public AbstractShape { public: /** @brief Constructor */ - inline Line(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b): _a(a), _transformedA(a), _b(b), _transformedB(b) {} + 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; diff --git a/src/Physics/LineSegment.h b/src/Physics/LineSegment.h index 4ed4b9449..ab1684480 100644 --- a/src/Physics/LineSegment.h +++ b/src/Physics/LineSegment.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_LineSegment_h #define Magnum_Physics_LineSegment_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -28,10 +37,10 @@ namespace Magnum { namespace Physics { @see LineSegment2D, LineSegment3D */ -template class LineSegment: public Line { +template class LineSegment: public Line { public: /** @brief Constructor */ - inline LineSegment(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b): Line(a, b) {} + inline explicit 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; diff --git a/src/Physics/ObjectShape.cpp b/src/Physics/ObjectShape.cpp index 766a475a9..a5eb93791 100644 --- a/src/Physics/ObjectShape.cpp +++ b/src/Physics/ObjectShape.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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" @@ -20,27 +29,35 @@ #include "AbstractShape.h" #include "ObjectShapeGroup.h" -using namespace std; - namespace Magnum { namespace Physics { -template ObjectShape::ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group), _shape(nullptr) { +template ObjectShape::ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group): SceneGraph::AbstractGroupedFeature>(object, group), _shape(nullptr) { this->setCachedTransformations(SceneGraph::AbstractFeature::CachedTransformation::Absolute); } -template ObjectShape::~ObjectShape() { +template ObjectShape::~ObjectShape() { delete _shape; } -template void ObjectShape::markDirty() { +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) { +template void ObjectShape::clean(const typename DimensionTraits::MatrixType& absoluteTransformationMatrix) { if(_shape) _shape->applyTransformationMatrix(absoluteTransformationMatrix); } -template class ObjectShape<2>; -template class ObjectShape<3>; +#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 index b1d04e1fd..b940c23e1 100644 --- a/src/Physics/ObjectShape.h +++ b/src/Physics/ObjectShape.h @@ -1,26 +1,35 @@ #ifndef Magnum_Physics_ObjectShape_h #define Magnum_Physics_ObjectShape_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 + * @brief Class Magnum::Physics::ObjectShape, typedef Magnum::Physics::ObjectShape2D, Magnum::Physics::ObjectShape3D */ #include "SceneGraph/AbstractGroupedFeature.h" -#include "ObjectShapeGroup.h" +#include "Physics/Physics.h" #include "magnumPhysicsVisibility.h" @@ -29,10 +38,27 @@ namespace Magnum { namespace Physics { /** @brief Object shape -Adds shape for collision detection to object. -@see ObjectShape2D, ObjectShape3D +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> { +template class MAGNUM_PHYSICS_EXPORT ObjectShape: public SceneGraph::AbstractGroupedFeature> { public: /** * @brief Constructor @@ -42,7 +68,7 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShape: publi * Creates empty object shape. * @see setShape() */ - ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr); + explicit ObjectShape(SceneGraph::AbstractObject* object, ObjectShapeGroup* group = nullptr); /** * @brief Destructor @@ -65,13 +91,32 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShape: publi return this; } - inline ObjectShapeGroup* group() { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); + /** + * @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))); } - inline const ObjectShapeGroup* group() const { - return static_cast*>(SceneGraph::AbstractGroupedFeature>::group()); - } + /** + * @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 */ diff --git a/src/Physics/ObjectShapeGroup.cpp b/src/Physics/ObjectShapeGroup.cpp index 013bf4d78..994f71a02 100644 --- a/src/Physics/ObjectShapeGroup.cpp +++ b/src/Physics/ObjectShapeGroup.cpp @@ -1,25 +1,35 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ObjectShapeGroup.h" -#include "ObjectShape.h" +#include "Physics/AbstractShape.h" +#include "Physics/ObjectShape.h" namespace Magnum { namespace Physics { -template void ObjectShapeGroup::setClean() { +template void ObjectShapeGroup::setClean() { /* Clean all objects */ if(!this->isEmpty()) { std::vector*> objects(this->size()); @@ -32,7 +42,21 @@ template void ObjectShapeGroup::setClean() dirty = false; } -template class ObjectShapeGroup<2>; -template class ObjectShapeGroup<3>; +template ObjectShape* ObjectShapeGroup::firstCollision(const ObjectShape* shape) { + /* Nothing to test with, done */ + if(!shape->shape()) return nullptr; + + setClean(); + for(std::size_t i = 0; i != this->size(); ++i) + if((*this)[i] != shape && (*this)[i]->shape() && (*this)[i]->shape()->collides(shape->shape())) + return (*this)[i]; + + return nullptr; +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup<2>; +template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup<3>; +#endif }} diff --git a/src/Physics/ObjectShapeGroup.h b/src/Physics/ObjectShapeGroup.h index 4e2c1a188..9d674b0be 100644 --- a/src/Physics/ObjectShapeGroup.h +++ b/src/Physics/ObjectShapeGroup.h @@ -1,29 +1,37 @@ #ifndef Magnum_Physics_ObjectShapeGroup_h #define Magnum_Physics_ObjectShapeGroup_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::ObjectShapeGroup + * @brief Class Magnum::Physics::ObjectShapeGroup, typedef Magnum::Physics::ObjectShapeGroup2D, Magnum::Physics::ObjectShapeGroup3D */ -#include #include +#include "Physics/ObjectShape.h" #include "SceneGraph/FeatureGroup.h" -#include "Physics.h" #include "magnumPhysicsVisibility.h" @@ -32,9 +40,10 @@ namespace Magnum { namespace Physics { /** @brief Group of object shapes -@see ObjectShapeGroup2D, ObjectShapeGroup3D +See ObjectShape for more information. +@see @ref scenegraph, ObjectShapeGroup2D, ObjectShapeGroup3D */ -template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup> { +template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: public SceneGraph::FeatureGroup> { friend class ObjectShape; public: @@ -43,7 +52,7 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: * * Marks the group as dirty. */ - inline ObjectShapeGroup(): dirty(true) {} + inline explicit ObjectShapeGroup(): dirty(true) {} /** * @brief Whether the group is dirty @@ -70,19 +79,35 @@ template class MAGNUM_PHYSICS_EXPORT ObjectShapeGroup: */ void setClean(); + /** + * @brief First collision of given shape with other shapes in the group + * + * Returns first shape colliding with given one. If there aren't any + * collisions, returns `nullptr`. Calls setClean() before the + * operation. + */ + ObjectShape* firstCollision(const ObjectShape* shape); + private: bool dirty; }; -/** @brief Group of two-dimensional shaped objects */ +/** +@brief Group of two-dimensional shaped objects + +See ObjectShape for more information. +@see ObjectShapeGroup3D +*/ typedef ObjectShapeGroup<2> ObjectShapeGroup2D; -/** @brief Group of three-dimensional shaped objects */ +/** +@brief Group of three-dimensional shaped objects + +See ObjectShape for more information. +@see ObjectShapeGroup2D +*/ typedef ObjectShapeGroup<3> ObjectShapeGroup3D; }} -/* Make the definition complete */ -#include "ObjectShape.h" - #endif diff --git a/src/Physics/Physics.h b/src/Physics/Physics.h index aca5325fe..d0a297bc5 100644 --- a/src/Physics/Physics.h +++ b/src/Physics/Physics.h @@ -1,75 +1,85 @@ #ifndef Magnum_Physics_Physics_h #define Magnum_Physics_Physics_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 - /** @file * @brief Forward declarations for Magnum::Physics namespace */ +#include "Types.h" + namespace Magnum { namespace Physics { -template class AbstractShape; +/** @todoc remove when doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT +template class AbstractShape; typedef AbstractShape<2> AbstractShape2D; typedef AbstractShape<3> AbstractShape3D; -template class AxisAlignedBox; +template class AxisAlignedBox; typedef AxisAlignedBox<2> AxisAlignedBox2D; typedef AxisAlignedBox<3> AxisAlignedBox3D; -template class Box; +template class Box; typedef Box<2> Box2D; typedef Box<3> Box3D; -template class Capsule; +template class Capsule; typedef Capsule<2> Capsule2D; typedef Capsule<3> Capsule3D; -class DebugDrawResourceManager; - -template class Line; +template class Line; typedef Line<2> Line2D; typedef Line<3> Line3D; -template class LineSegment; +template class LineSegment; typedef LineSegment<2> LineSegment2D; typedef LineSegment<3> LineSegment3D; -template class ObjectShape; +template class ObjectShape; typedef ObjectShape<2> ObjectShape2D; typedef ObjectShape<3> ObjectShape3D; -template class ObjectShapeGroup; +template class ObjectShapeGroup; typedef ObjectShapeGroup<2> ObjectShapeGroup2D; typedef ObjectShapeGroup<3> ObjectShapeGroup3D; class Plane; -template class Point; +template class Point; typedef Point<2> Point2D; typedef Point<3> Point3D; -template class ShapeGroup; +template class ShapeGroup; typedef ShapeGroup<2> ShapeGroup2D; typedef ShapeGroup<3> ShapeGroup3D; -template class Sphere; +template class Sphere; typedef Sphere<2> Sphere2D; typedef Sphere<3> Sphere3D; +#endif }} diff --git a/src/Physics/Plane.cpp b/src/Physics/Plane.cpp index 4798b991c..8c3ae2b50 100644 --- a/src/Physics/Plane.cpp +++ b/src/Physics/Plane.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Plane.h" @@ -18,17 +27,15 @@ #include #include "Math/Matrix4.h" -#include "Math/Point3D.h" #include "Math/Geometry/Intersection.h" #include "LineSegment.h" -using namespace std; using namespace Magnum::Math::Geometry; namespace Magnum { namespace Physics { void Plane::applyTransformationMatrix(const Matrix4& matrix) { - _transformedPosition = (matrix*Magnum::Point3D(_position)).xyz(); + _transformedPosition = matrix.transformPoint(_position); _transformedNormal = matrix.rotation()*_normal; } @@ -42,12 +49,12 @@ bool Plane::collides(const AbstractShape<3>* other) const { } bool Plane::operator%(const Line3D& other) const { - float t = Intersection::planeLine(transformedPosition(), transformedNormal(), other.transformedA(), other.transformedB()); - return t != t || (t != numeric_limits::infinity() && t != -numeric_limits::infinity()); + Float t = Intersection::planeLine(transformedPosition(), transformedNormal(), other.transformedA(), other.transformedB()); + 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()); + Float t = Intersection::planeLine(transformedPosition(), transformedNormal(), other.transformedA(), other.transformedB()); return t > 0.0f && t < 1.0f; } diff --git a/src/Physics/Plane.h b/src/Physics/Plane.h index 07cc7ad68..7dbf76e22 100644 --- a/src/Physics/Plane.h +++ b/src/Physics/Plane.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Plane_h #define Magnum_Physics_Plane_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -31,7 +40,7 @@ namespace Magnum { namespace Physics { class MAGNUM_PHYSICS_EXPORT Plane: public AbstractShape<3> { public: /** @brief Constructor */ - inline Plane(const Vector3& position, const Vector3& normal): _position(position), _transformedPosition(position), _normal(normal), _transformedNormal(normal) {} + inline explicit Plane(const Vector3& position, const Vector3& normal): _position(position), _transformedPosition(position), _normal(normal), _transformedNormal(normal) {} inline Type type() const override { return Type::Plane; } diff --git a/src/Physics/Point.cpp b/src/Physics/Point.cpp index 53f697109..fb52d3b7e 100644 --- a/src/Physics/Point.cpp +++ b/src/Physics/Point.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Point.h" @@ -20,8 +29,8 @@ namespace Magnum { namespace Physics { -template void Point::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedPosition = (matrix*typename DimensionTraits::PointType(_position)).vector(); +template void Point::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { + _transformedPosition = matrix.transformPoint(_position); } template class Point<2>; diff --git a/src/Physics/Point.h b/src/Physics/Point.h index 741874ad6..2ab8f362e 100644 --- a/src/Physics/Point.h +++ b/src/Physics/Point.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Point_h #define Magnum_Physics_Point_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -31,10 +40,10 @@ namespace Magnum { namespace Physics { @see Point2D, Point3D */ -template class MAGNUM_PHYSICS_EXPORT Point: public AbstractShape { +template class MAGNUM_PHYSICS_EXPORT Point: public AbstractShape { public: /** @brief Constructor */ - inline Point(const typename DimensionTraits::VectorType& position): _position(position), _transformedPosition(position) {} + inline explicit Point(const typename DimensionTraits::VectorType& position): _position(position), _transformedPosition(position) {} inline typename AbstractShape::Type type() const override { return AbstractShape::Type::Point; diff --git a/src/Physics/ShapeGroup.cpp b/src/Physics/ShapeGroup.cpp index d77a0ce18..5d6777c4b 100644 --- a/src/Physics/ShapeGroup.cpp +++ b/src/Physics/ShapeGroup.cpp @@ -1,34 +1,43 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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) { +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() { +template ShapeGroup::~ShapeGroup() { if(!(operation & Implementation::GroupOperation::RefA)) delete a; if(!(operation & Implementation::GroupOperation::RefB)) delete b; } -template ShapeGroup& ShapeGroup::operator=(ShapeGroup&& other) { +template ShapeGroup& ShapeGroup::operator=(ShapeGroup&& other) { if(!(operation & Implementation::GroupOperation::RefA)) delete a; if(!(operation & Implementation::GroupOperation::RefB)) delete b; @@ -43,12 +52,12 @@ template ShapeGroup& ShapeGroup return *this; } -template void ShapeGroup::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { +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 { +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); diff --git a/src/Physics/ShapeGroup.h b/src/Physics/ShapeGroup.h index d1ed8bce6..40e222936 100644 --- a/src/Physics/ShapeGroup.h +++ b/src/Physics/ShapeGroup.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_ShapeGroup_h #define Magnum_Physics_ShapeGroup_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,6 +30,7 @@ #include "AbstractShape.h" +#include #include #include @@ -57,7 +67,7 @@ Result of logical operations on shapes. See @ref collision-detection for brief introduction. @see ShapeGroup2D, ShapeGroup3D */ -template class MAGNUM_PHYSICS_EXPORT ShapeGroup: public AbstractShape { +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; @@ -90,7 +100,7 @@ template class MAGNUM_PHYSICS_EXPORT ShapeGroup: public public: /** @brief Default constructor */ - inline ShapeGroup(): operation(Implementation::GroupOperation::AlwaysFalse), a(nullptr), b(nullptr) {} + inline explicit ShapeGroup(): operation(Implementation::GroupOperation::AlwaysFalse), a(nullptr), b(nullptr) {} /** @brief Move constructor */ ShapeGroup(ShapeGroup&& other); @@ -185,7 +195,7 @@ 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); +template inline constexpr ShapeGroup operator&&(T a, U b); /** @relates ShapeGroup @brief Logical OR of two shapes @@ -194,7 +204,7 @@ template inline constexpr ShapeGroup< 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); +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 { \ diff --git a/src/Physics/Sphere.cpp b/src/Physics/Sphere.cpp index 9bd6f754e..4eebd8c49 100644 --- a/src/Physics/Sphere.cpp +++ b/src/Physics/Sphere.cpp @@ -1,22 +1,30 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Sphere.h" -#include "Math/Constants.h" -#include "Math/Math.h" +#include "Math/Functions.h" #include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Math/Geometry/Distance.h" @@ -28,7 +36,7 @@ using namespace Magnum::Math::Geometry; namespace Magnum { namespace Physics { namespace { - template static typename DimensionTraits::VectorType unitVector(); + template static typename DimensionTraits::VectorType unitVector(); template<> inline Vector2 unitVector<2>() { return Vector2(1/Constants::sqrt2()); @@ -39,13 +47,13 @@ namespace { } } -template void Sphere::applyTransformationMatrix(const typename DimensionTraits::MatrixType& matrix) { - _transformedPosition = (matrix*typename DimensionTraits::PointType(_position)).vector(); - float scaling = (matrix.rotationScaling()*unitVector()).length(); +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 { +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) @@ -58,27 +66,29 @@ template bool Sphere::collides(const Abstra return AbstractShape::collides(other); } -template bool Sphere::operator%(const Point& other) const { +template bool Sphere::operator%(const Point& other) const { return (other.transformedPosition()-transformedPosition()).dot() < Math::pow<2>(transformedRadius()); } -template bool Sphere::operator%(const Line& other) const { +template bool Sphere::operator%(const Line& other) const { return Distance::linePointSquared(other.transformedA(), other.transformedB(), transformedPosition()) < Math::pow<2>(transformedRadius()); } -template bool Sphere::operator%(const LineSegment& other) const { +template bool Sphere::operator%(const LineSegment& other) const { return Distance::lineSegmentPointSquared(other.transformedA(), other.transformedB(), transformedPosition()) < Math::pow<2>(transformedRadius()); } -template bool Sphere::operator%(const Sphere& other) const { +template bool Sphere::operator%(const Sphere& other) const { return (other.transformedPosition()-transformedPosition()).dot() < Math::pow<2>(transformedRadius()+other.transformedRadius()); } -template class Sphere<2>; -template class Sphere<3>; +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PHYSICS_EXPORT Sphere<2>; +template class MAGNUM_PHYSICS_EXPORT Sphere<3>; +#endif }} diff --git a/src/Physics/Sphere.h b/src/Physics/Sphere.h index 24b4dd074..c1324c550 100644 --- a/src/Physics/Sphere.h +++ b/src/Physics/Sphere.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Sphere_h #define Magnum_Physics_Sphere_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -33,11 +42,12 @@ namespace Magnum { namespace Physics { Unlike other elements the sphere doesn't support asymmetric scaling. When applying transformation, the scale factor is averaged from all axes. @see Sphere2D, Sphere3D +@todo Assert for asymmetric scaling */ -template class MAGNUM_PHYSICS_EXPORT Sphere: public AbstractShape { +template class MAGNUM_PHYSICS_EXPORT Sphere: public AbstractShape { public: /** @brief Constructor */ - inline Sphere(const typename DimensionTraits::VectorType& position, float radius): _position(position), _transformedPosition(position), _radius(radius), _transformedRadius(radius) {} + 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; @@ -58,10 +68,10 @@ template class MAGNUM_PHYSICS_EXPORT Sphere: public Abs } /** @brief Radius */ - inline float radius() const { return _radius; } + inline Float radius() const { return _radius; } /** @brief Set radius */ - inline void setRadius(float radius) { _radius = radius; } + inline void setRadius(Float radius) { _radius = radius; } /** @brief Transformed position */ inline typename DimensionTraits::VectorType transformedPosition() const { @@ -69,7 +79,7 @@ template class MAGNUM_PHYSICS_EXPORT Sphere: public Abs } /** @brief Transformed radius */ - inline float transformedRadius() const { + inline Float transformedRadius() const { return _transformedRadius; } @@ -88,7 +98,7 @@ template class MAGNUM_PHYSICS_EXPORT Sphere: public Abs private: typename DimensionTraits::VectorType _position, _transformedPosition; - float _radius, _transformedRadius; + Float _radius, _transformedRadius; }; /** @brief Two-dimensional sphere */ @@ -98,13 +108,13 @@ typedef Sphere<2> Sphere2D; typedef Sphere<3> Sphere3D; /** @collisionoperator{Point,Sphere} */ -template inline bool operator%(const Point& a, const Sphere& b) { return b % a; } +template inline bool operator%(const Point& a, const Sphere& b) { return b % a; } /** @collisionoperator{Line,Sphere} */ -template inline bool operator%(const Line& a, const Sphere& b) { return b % a; } +template inline bool operator%(const Line& a, const Sphere& b) { return b % a; } /** @collisionoperator{LineSegment,Sphere} */ -template inline bool operator%(const LineSegment& a, const Sphere& b) { return b % a; } +template inline bool operator%(const LineSegment& a, const Sphere& b) { return b % a; } }} diff --git a/src/Physics/Test/AbstractShapeTest.cpp b/src/Physics/Test/AbstractShapeTest.cpp index a7979c8ae..0b451e78d 100644 --- a/src/Physics/Test/AbstractShapeTest.cpp +++ b/src/Physics/Test/AbstractShapeTest.cpp @@ -1,31 +1,43 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AbstractShapeTest.h" - #include -#include +#include #include "Physics/AbstractShape.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::AbstractShapeTest) - namespace Magnum { namespace Physics { namespace Test { +class AbstractShapeTest: public Corrade::TestSuite::Tester { + public: + AbstractShapeTest(); + + void debug(); +}; + AbstractShapeTest::AbstractShapeTest() { - addTests(&AbstractShapeTest::debug); + addTests({&AbstractShapeTest::debug}); } void AbstractShapeTest::debug() { @@ -33,9 +45,11 @@ void AbstractShapeTest::debug() { Debug(&o) << AbstractShape2D::Type::ShapeGroup; CORRADE_COMPARE(o.str(), "AbstractShape2D::Type::ShapeGroup\n"); - o.str(""); + o.str({}); Debug(&o) << AbstractShape3D::Type::Plane; CORRADE_COMPARE(o.str(), "AbstractShape3D::Type::Plane\n"); } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::AbstractShapeTest) diff --git a/src/Physics/Test/AbstractShapeTest.h b/src/Physics/Test/AbstractShapeTest.h deleted file mode 100644 index 1fa4c4531..000000000 --- a/src/Physics/Test/AbstractShapeTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Physics_Test_AbstractShapeTest_h -#define Magnum_Physics_Test_AbstractShapeTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class AbstractShapeTest: public Corrade::TestSuite::Tester { - public: - AbstractShapeTest(); - - void debug(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/AxisAlignedBoxTest.cpp b/src/Physics/Test/AxisAlignedBoxTest.cpp index a3b8595d8..cf45bf009 100644 --- a/src/Physics/Test/AxisAlignedBoxTest.cpp +++ b/src/Physics/Test/AxisAlignedBoxTest.cpp @@ -1,42 +1,71 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AxisAlignedBoxTest.h" +#include -#include "Math/Constants.h" #include "Math/Matrix4.h" #include "Physics/AxisAlignedBox.h" +#include "Physics/Point.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::AxisAlignedBoxTest) +#include "ShapeTestBase.h" namespace Magnum { namespace Physics { namespace Test { +class AxisAlignedBoxTest: public Corrade::TestSuite::Tester, ShapeTestBase { + public: + AxisAlignedBoxTest(); + + void applyTransformation(); + void collisionPoint(); +}; + AxisAlignedBoxTest::AxisAlignedBoxTest() { - addTests(&AxisAlignedBoxTest::applyTransformation); + addTests({&AxisAlignedBoxTest::applyTransformation, + &AxisAlignedBoxTest::collisionPoint}); } void AxisAlignedBoxTest::applyTransformation() { Physics::AxisAlignedBox3D box({-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}); - box.applyTransformationMatrix(Matrix4::scaling({2.0f, -1.0f, 1.5f})); - CORRADE_COMPARE(box.transformedPosition(), Vector3(-2.0f, 2.0f, -4.5f)); - CORRADE_COMPARE(box.transformedSize(), Vector3(2.0f, -2.0f, 4.5f)); + 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::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}); - box.applyTransformationMatrix(Matrix4::translation(Vector3(1.0f))*Matrix4::rotation(deg(90.0f), Vector3::xAxis())); - CORRADE_COMPARE(box.transformedPosition(), Vector3(0.0f, 4.0f, -1.0f)); - CORRADE_COMPARE(box.transformedSize(), Vector3(1.0f, -3.0f, 2.0f)); + randomTransformation(box); + randomTransformation(point1); + randomTransformation(point2); + + VERIFY_NOT_COLLIDES(box, point1); + VERIFY_COLLIDES(box, point2); } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::AxisAlignedBoxTest) diff --git a/src/Physics/Test/AxisAlignedBoxTest.h b/src/Physics/Test/AxisAlignedBoxTest.h deleted file mode 100644 index bbbbd1083..000000000 --- a/src/Physics/Test/AxisAlignedBoxTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Physics_Test_AxisAlignedBoxTest_h -#define Magnum_Physics_Test_AxisAlignedBoxTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class AxisAlignedBoxTest: public Corrade::TestSuite::Tester { - public: - AxisAlignedBoxTest(); - - void applyTransformation(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/BoxTest.cpp b/src/Physics/Test/BoxTest.cpp index 824ce34d9..33bc2781b 100644 --- a/src/Physics/Test/BoxTest.cpp +++ b/src/Physics/Test/BoxTest.cpp @@ -1,29 +1,43 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "BoxTest.h" +#include #include "Math/Matrix4.h" #include "Physics/Box.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::BoxTest) - namespace Magnum { namespace Physics { namespace Test { +class BoxTest: public Corrade::TestSuite::Tester { + public: + BoxTest(); + + void applyTransformation(); +}; + BoxTest::BoxTest() { - addTests(&BoxTest::applyTransformation); + addTests({&BoxTest::applyTransformation}); } void BoxTest::applyTransformation() { @@ -34,3 +48,5 @@ void BoxTest::applyTransformation() { } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::BoxTest) diff --git a/src/Physics/Test/BoxTest.h b/src/Physics/Test/BoxTest.h deleted file mode 100644 index 48781ad08..000000000 --- a/src/Physics/Test/BoxTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Physics_Test_BoxTest_h -#define Magnum_Physics_Test_BoxTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class BoxTest: public Corrade::TestSuite::Tester { - public: - BoxTest(); - - void applyTransformation(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/CMakeLists.txt b/src/Physics/Test/CMakeLists.txt index 5c6c5f2a5..2467787cc 100644 --- a/src/Physics/Test/CMakeLists.txt +++ b/src/Physics/Test/CMakeLists.txt @@ -1,11 +1,35 @@ -corrade_add_test2(PhysicsAbstractShapeTest AbstractShapeTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsAxisAlignedBoxTest AxisAlignedBoxTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsBoxTest BoxTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsLineTest LineTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsPlaneTest PlaneTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsPointTest PointTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsShapeGroupTest ShapeGroupTest.cpp LIBRARIES MagnumPhysics) -corrade_add_test2(PhysicsSphereTest SphereTest.cpp LIBRARIES MagnumPhysics) +# +# 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. +# -corrade_add_test2(PhysicsObjectShapeTest ObjectShapeTest.cpp LIBRARIES MagnumPhysics) +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(PhysicsObjectShapeTest ObjectShapeTest.cpp LIBRARIES MagnumPhysics) diff --git a/src/Physics/Test/CapsuleTest.cpp b/src/Physics/Test/CapsuleTest.cpp index 04c85235b..8f1bc43d3 100644 --- a/src/Physics/Test/CapsuleTest.cpp +++ b/src/Physics/Test/CapsuleTest.cpp @@ -1,38 +1,53 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CapsuleTest.h" - -#include "Math/Constants.h" #include "Physics/Capsule.h" #include "Physics/Point.h" #include "Physics/Sphere.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::CapsuleTest) +#include "ShapeTestBase.h" namespace Magnum { namespace Physics { namespace Test { +class CapsuleTest: public Corrade::TestSuite::Tester, ShapeTestBase { + public: + CapsuleTest(); + + void applyTransformation(); + void collisionPoint(); + void collisionSphere(); +}; + CapsuleTest::CapsuleTest() { - addTests(&CapsuleTest::applyTransformation, - &CapsuleTest::collisionPoint); + addTests({&CapsuleTest::applyTransformation, + &CapsuleTest::collisionPoint}); } void CapsuleTest::applyTransformation() { Physics::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())); + 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.radius(), 7.0f); @@ -75,3 +90,5 @@ void CapsuleTest::collisionSphere() { } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::CapsuleTest) diff --git a/src/Physics/Test/CapsuleTest.h b/src/Physics/Test/CapsuleTest.h deleted file mode 100644 index 88dec80df..000000000 --- a/src/Physics/Test/CapsuleTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_Physics_Test_CapsuleTest_h -#define Magnum_Physics_Test_CapsuleTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "ShapeTestBase.h" - -namespace Magnum { namespace Physics { namespace Test { - -class CapsuleTest: public Corrade::TestSuite::Tester, ShapeTestBase { - public: - CapsuleTest(); - - void applyTransformation(); - void collisionPoint(); - void collisionSphere(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/LineTest.cpp b/src/Physics/Test/LineTest.cpp index 2de48f44a..6f0f2cd9d 100644 --- a/src/Physics/Test/LineTest.cpp +++ b/src/Physics/Test/LineTest.cpp @@ -1,37 +1,52 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "LineTest.h" +#include -#include "Math/Constants.h" #include "Math/Matrix4.h" #include "Physics/Line.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::LineTest) - namespace Magnum { namespace Physics { namespace Test { +class LineTest: public Corrade::TestSuite::Tester { + public: + LineTest(); + + void applyTransformation(); +}; + LineTest::LineTest() { - addTests(&LineTest::applyTransformation); + addTests({&LineTest::applyTransformation}); } 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())); + 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)); } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::LineTest) diff --git a/src/Physics/Test/LineTest.h b/src/Physics/Test/LineTest.h deleted file mode 100644 index fd264747b..000000000 --- a/src/Physics/Test/LineTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Physics_Test_LineTest_h -#define Magnum_Physics_Test_LineTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class LineTest: public Corrade::TestSuite::Tester { - public: - LineTest(); - - void applyTransformation(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/ObjectShapeTest.cpp b/src/Physics/Test/ObjectShapeTest.cpp index dd5b438bd..056c680f1 100644 --- a/src/Physics/Test/ObjectShapeTest.cpp +++ b/src/Physics/Test/ObjectShapeTest.cpp @@ -1,35 +1,52 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ObjectShapeTest.h" +#include #include "Physics/ObjectShapeGroup.h" #include "Physics/ObjectShape.h" #include "Physics/Point.h" +#include "Physics/Sphere.h" #include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/Scene.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::ObjectShapeTest) - namespace Magnum { namespace Physics { namespace Test { +class ObjectShapeTest: public Corrade::TestSuite::Tester { + public: + ObjectShapeTest(); + + void clean(); + void firstCollision(); +}; + typedef SceneGraph::Scene> Scene3D; typedef SceneGraph::Object> Object3D; ObjectShapeTest::ObjectShapeTest() { - addTests(&ObjectShapeTest::clean); + addTests({&ObjectShapeTest::clean, + &ObjectShapeTest::firstCollision}); } void ObjectShapeTest::clean() { @@ -38,7 +55,7 @@ void ObjectShapeTest::clean() { Object3D a(&scene); ObjectShape3D* shape = new ObjectShape3D(&a, &group); - shape->setShape(new Physics::Point3D({1.0f, -2.0f, 3.0f})); + shape->setShape(Physics::Point3D({1.0f, -2.0f, 3.0f})); a.scale(Vector3(-2.0f)); Object3D b(&scene); @@ -73,4 +90,41 @@ void ObjectShapeTest::clean() { CORRADE_VERIFY(b.isDirty()); } +void ObjectShapeTest::firstCollision() { + Scene3D scene; + ObjectShapeGroup3D group; + + Object3D a(&scene); + ObjectShape3D* aShape = new ObjectShape3D(&a, &group); + aShape->setShape(Physics::Sphere3D({1.0f, -2.0f, 3.0f}, 1.5f)); + + Object3D b(&scene); + ObjectShape3D* bShape = new ObjectShape3D(&b, &group); + bShape->setShape(Physics::Point3D({3.0f, -2.0f, 3.0f})); + + 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()); + + /* No collisions initially */ + CORRADE_VERIFY(!group.firstCollision(aShape)); + CORRADE_VERIFY(!group.firstCollision(bShape)); + CORRADE_VERIFY(!group.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_TEST_MAIN(Magnum::Physics::Test::ObjectShapeTest) diff --git a/src/Physics/Test/ObjectShapeTest.h b/src/Physics/Test/ObjectShapeTest.h deleted file mode 100644 index 65d051da1..000000000 --- a/src/Physics/Test/ObjectShapeTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Physics_Test_ObjectShapeTest_h -#define Magnum_Physics_Test_ObjectShapeTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class ObjectShapeTest: public Corrade::TestSuite::Tester { - public: - ObjectShapeTest(); - - void clean(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/PlaneTest.cpp b/src/Physics/Test/PlaneTest.cpp index 2ec0ab9d0..028ccb770 100644 --- a/src/Physics/Test/PlaneTest.cpp +++ b/src/Physics/Test/PlaneTest.cpp @@ -1,39 +1,54 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "PlaneTest.h" - -#include "Math/Constants.h" #include "Physics/LineSegment.h" #include "Physics/Point.h" #include "Physics/Plane.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::PlaneTest) +#include "ShapeTestBase.h" namespace Magnum { namespace Physics { namespace Test { +class PlaneTest: public Corrade::TestSuite::Tester, ShapeTestBase { + public: + PlaneTest(); + + void applyTransformation(); + void collisionLine(); + void collisionLineSegment(); +}; + PlaneTest::PlaneTest() { - addTests(&PlaneTest::applyTransformation, - &PlaneTest::collisionLine, - &PlaneTest::collisionLineSegment); + addTests({&PlaneTest::applyTransformation, + &PlaneTest::collisionLine, + &PlaneTest::collisionLineSegment}); } void PlaneTest::applyTransformation() { Physics::Plane plane({1.0f, 2.0f, 3.0f}, {Constants::sqrt2(), -Constants::sqrt2(), 0}); - plane.applyTransformationMatrix(Matrix4::rotation(deg(90.0f), Vector3::xAxis())); + 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())); @@ -76,3 +91,5 @@ void PlaneTest::collisionLineSegment() { } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::PlaneTest) diff --git a/src/Physics/Test/PlaneTest.h b/src/Physics/Test/PlaneTest.h deleted file mode 100644 index 4381e3dc6..000000000 --- a/src/Physics/Test/PlaneTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef Magnum_Physics_Test_PlaneTest_h -#define Magnum_Physics_Test_PlaneTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "ShapeTestBase.h" - -namespace Magnum { namespace Physics { namespace Test { - -class PlaneTest: public Corrade::TestSuite::Tester, ShapeTestBase { - public: - PlaneTest(); - - void applyTransformation(); - void collisionLine(); - void collisionLineSegment(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/PointTest.cpp b/src/Physics/Test/PointTest.cpp index 25c36bf53..f2e10188c 100644 --- a/src/Physics/Test/PointTest.cpp +++ b/src/Physics/Test/PointTest.cpp @@ -1,29 +1,43 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "PointTest.h" +#include #include "Math/Matrix4.h" #include "Physics/Point.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::PointTest) - namespace Magnum { namespace Physics { namespace Test { +class PointTest: public Corrade::TestSuite::Tester { + public: + PointTest(); + + void applyTransformation(); +}; + PointTest::PointTest() { - addTests(&PointTest::applyTransformation); + addTests({&PointTest::applyTransformation}); } void PointTest::applyTransformation() { @@ -33,3 +47,5 @@ void PointTest::applyTransformation() { } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::PointTest) diff --git a/src/Physics/Test/PointTest.h b/src/Physics/Test/PointTest.h deleted file mode 100644 index f158954fb..000000000 --- a/src/Physics/Test/PointTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Magnum_Physics_Test_PointTest_h -#define Magnum_Physics_Test_PointTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class PointTest: public Corrade::TestSuite::Tester { - public: - PointTest(); - - void applyTransformation(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/ShapeGroupTest.cpp b/src/Physics/Test/ShapeGroupTest.cpp index 0dcf6d728..b4f559a8d 100644 --- a/src/Physics/Test/ShapeGroupTest.cpp +++ b/src/Physics/Test/ShapeGroupTest.cpp @@ -1,19 +1,28 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ShapeGroupTest.h" +#include #include @@ -22,15 +31,19 @@ #include "Physics/LineSegment.h" #include "Physics/ShapeGroup.h" -using namespace std; +namespace Magnum { namespace Physics { namespace Test { -CORRADE_TEST_MAIN(Magnum::Physics::Test::ShapeGroupTest) +class ShapeGroupTest: public Corrade::TestSuite::Tester { + public: + ShapeGroupTest(); -namespace Magnum { namespace Physics { namespace Test { + void copy(); + void reference(); +}; ShapeGroupTest::ShapeGroupTest() { - addTests(&ShapeGroupTest::copy, - &ShapeGroupTest::reference); + addTests({&ShapeGroupTest::copy, + &ShapeGroupTest::reference}); } void ShapeGroupTest::copy() { @@ -52,7 +65,7 @@ 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 = !(ref(point) || ref(segment)); + ShapeGroup3D group = !(std::ref(point) || std::ref(segment)); group.applyTransformationMatrix(Matrix4::translation(Vector3(1.0f))); @@ -61,3 +74,5 @@ void ShapeGroupTest::reference() { } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::ShapeGroupTest) diff --git a/src/Physics/Test/ShapeGroupTest.h b/src/Physics/Test/ShapeGroupTest.h deleted file mode 100644 index 7e12a3633..000000000 --- a/src/Physics/Test/ShapeGroupTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Physics_Test_ShapeGroupTest_h -#define Magnum_Physics_Test_ShapeGroupTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Physics { namespace Test { - -class ShapeGroupTest: public Corrade::TestSuite::Tester { - public: - ShapeGroupTest(); - - void copy(); - void reference(); -}; - -}}} - -#endif diff --git a/src/Physics/Test/ShapeTestBase.h b/src/Physics/Test/ShapeTestBase.h index b1a3bfe29..66ead8d97 100644 --- a/src/Physics/Test/ShapeTestBase.h +++ b/src/Physics/Test/ShapeTestBase.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_Test_ShapeTestBase_h #define Magnum_Physics_Test_ShapeTestBase_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 diff --git a/src/Physics/Test/SphereTest.cpp b/src/Physics/Test/SphereTest.cpp index 3b8414e79..ba50a5b15 100644 --- a/src/Physics/Test/SphereTest.cpp +++ b/src/Physics/Test/SphereTest.cpp @@ -1,41 +1,58 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "SphereTest.h" - -#include "Math/Constants.h" #include "Physics/LineSegment.h" #include "Physics/Point.h" #include "Physics/Sphere.h" -CORRADE_TEST_MAIN(Magnum::Physics::Test::SphereTest) +#include "ShapeTestBase.h" namespace Magnum { namespace Physics { namespace Test { +class SphereTest: public Corrade::TestSuite::Tester, ShapeTestBase { + public: + SphereTest(); + + void applyTransformation(); + void collisionPoint(); + void collisionLine(); + void collisionLineSegment(); + void collisionSphere(); +}; + SphereTest::SphereTest() { - addTests(&SphereTest::applyTransformation, - &SphereTest::collisionPoint, - &SphereTest::collisionLine, - &SphereTest::collisionLineSegment, - &SphereTest::collisionSphere); + addTests({&SphereTest::applyTransformation, + &SphereTest::collisionPoint, + &SphereTest::collisionLine, + &SphereTest::collisionLineSegment, + &SphereTest::collisionSphere}); } void SphereTest::applyTransformation() { Physics::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 7.0f); - sphere.applyTransformationMatrix(Matrix4::rotation(deg(90.0f), Vector3::yAxis())); + 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); @@ -102,3 +119,5 @@ void SphereTest::collisionSphere() { } }}} + +CORRADE_TEST_MAIN(Magnum::Physics::Test::SphereTest) diff --git a/src/Physics/Test/SphereTest.h b/src/Physics/Test/SphereTest.h deleted file mode 100644 index 48a2d2d3c..000000000 --- a/src/Physics/Test/SphereTest.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef Magnum_Physics_Test_SphereTest_h -#define Magnum_Physics_Test_SphereTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "ShapeTestBase.h" - -namespace Magnum { namespace Physics { namespace Test { - -class SphereTest: public Corrade::TestSuite::Tester, ShapeTestBase { - public: - SphereTest(); - - void applyTransformation(); - void collisionPoint(); - void collisionLine(); - void collisionLineSegment(); - void collisionSphere(); -}; - -}}} - -#endif diff --git a/src/Physics/magnumPhysicsVisibility.h b/src/Physics/magnumPhysicsVisibility.h index a2e487560..07d22128b 100644 --- a/src/Physics/magnumPhysicsVisibility.h +++ b/src/Physics/magnumPhysicsVisibility.h @@ -1,18 +1,27 @@ #ifndef Magnum_Physics_magnumPhysicsVisibility_h #define Magnum_Physics_magnumPhysicsVisibility_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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. */ #ifdef _WIN32 diff --git a/src/Platform/AbstractContextHandler.h b/src/Platform/AbstractContextHandler.h index 81adb561b..e4bb876a9 100644 --- a/src/Platform/AbstractContextHandler.h +++ b/src/Platform/AbstractContextHandler.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_AbstractContextHandler_h #define Magnum_Platform_AbstractContextHandler_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -23,7 +32,11 @@ namespace Magnum { namespace Platform { -/** @brief Base for OpenGL context handlers */ +/** +@brief Base for OpenGL context handlers + +@todo GLX_MESA_query_renderer, EGL_MESA_query_renderer +*/ template class AbstractContextHandler { public: /** @@ -33,6 +46,8 @@ template class AbstractContextHandl */ virtual VisualId getVisualId(Display nativeDisplay) = 0; + explicit AbstractContextHandler() = default; + /** * @brief Destructor * diff --git a/src/Platform/AbstractXApplication.cpp b/src/Platform/AbstractXApplication.cpp index 9379d7492..37aa4fcc1 100644 --- a/src/Platform/AbstractXApplication.cpp +++ b/src/Platform/AbstractXApplication.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AbstractXApplication.h" @@ -25,11 +34,9 @@ /* Mask for X events */ #define INPUT_MASK KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|StructureNotifyMask -using namespace std; - namespace Magnum { namespace Platform { -AbstractXApplication::AbstractXApplication(AbstractContextHandler* contextHandler, int&, char**, const string& title, const Math::Vector2& size): contextHandler(contextHandler), viewportSize(size), flags(Flag::Redraw) { +AbstractXApplication::AbstractXApplication(AbstractContextHandler* contextHandler, int&, char**, const std::string& title, const Vector2i& size): contextHandler(contextHandler), viewportSize(size), flags(Flag::Redraw) { /* Get default X display */ display = XOpenDisplay(0); @@ -108,7 +115,7 @@ int AbstractXApplication::exec() { switch(event.type) { /* Window resizing */ case ConfigureNotify: { - Math::Vector2 size(event.xconfigure.width, event.xconfigure.height); + Vector2i size(event.xconfigure.width, event.xconfigure.height); if(size != viewportSize) { viewportSize = size; viewportEvent(size); @@ -118,22 +125,21 @@ int AbstractXApplication::exec() { /* Key/mouse events */ case KeyPress: - keyPressEvent(static_cast(XLookupKeysym(&event.xkey, 0)), static_cast(event.xkey.state), {event.xkey.x, event.xkey.y}); - break; - case KeyRelease: - keyReleaseEvent(static_cast(XLookupKeysym(&event.xkey, 0)), static_cast(event.xkey.state), {event.xkey.x, event.xkey.y}); - break; + case KeyRelease: { + KeyEvent e(static_cast(XLookupKeysym(&event.xkey, 0)), static_cast(event.xkey.state), {event.xkey.x, event.xkey.y}); + event.type == KeyPress ? keyPressEvent(e) : keyReleaseEvent(e); + } break; case ButtonPress: - mousePressEvent(static_cast(event.xbutton.button), static_cast(event.xkey.state), {event.xbutton.x, event.xbutton.y}); - break; - case ButtonRelease: - mouseReleaseEvent(static_cast(event.xbutton.button), static_cast(event.xkey.state), {event.xbutton.x, event.xbutton.y}); - break; + case ButtonRelease: { + MouseEvent e(static_cast(event.xbutton.button), static_cast(event.xkey.state), {event.xbutton.x, event.xbutton.y}); + event.type == ButtonPress ? mousePressEvent(e) : mouseReleaseEvent(e); + } break; /* Mouse move events */ - case MotionNotify: - mouseMotionEvent(static_cast(event.xmotion.state), {event.xmotion.x, event.xmotion.y}); - break; + case MotionNotify: { + MouseMoveEvent e(static_cast(event.xmotion.state), {event.xmotion.x, event.xmotion.y}); + mouseMoveEvent(e); + } break; } } diff --git a/src/Platform/AbstractXApplication.h b/src/Platform/AbstractXApplication.h index 783f7c479..1de097e9a 100644 --- a/src/Platform/AbstractXApplication.h +++ b/src/Platform/AbstractXApplication.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_AbstractXApplication_h #define Magnum_Platform_AbstractXApplication_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -47,6 +56,11 @@ Supports keyboard and mouse handling. */ class AbstractXApplication { public: + class InputEvent; + class KeyEvent; + class MouseEvent; + class MouseMoveEvent; + /** * @brief Constructor * @param contextHandler OpenGL context handler @@ -57,7 +71,7 @@ class AbstractXApplication { * * Creates window with double-buffered OpenGL ES 2 context. */ - AbstractXApplication(AbstractContextHandler* contextHandler, int& argc, char** argv, const std::string& title = "Magnum X application", const Math::Vector2& size = Math::Vector2(800, 600)); + explicit AbstractXApplication(AbstractContextHandler* contextHandler, int& argc, char** argv, const std::string& title = "Magnum X application", const Vector2i& size = Vector2i(800, 600)); /** * @brief Destructor @@ -75,11 +89,11 @@ class AbstractXApplication { /** @brief Exit application main loop */ inline void exit() { flags |= Flag::Exit; } + protected: /** @{ @name Drawing functions */ - protected: /** @copydoc GlutApplication::viewportEvent() */ - virtual void viewportEvent(const Math::Vector2& size) = 0; + virtual void viewportEvent(const Vector2i& size) = 0; /** @copydoc GlutApplication::drawEvent() */ virtual void drawEvent() = 0; @@ -94,12 +108,70 @@ class AbstractXApplication { /** @{ @name Keyboard handling */ + /** @copydoc Sdl2Application::keyPressEvent() */ + virtual void keyPressEvent(KeyEvent& event); + + /** @copydoc Sdl2Application::keyReleaseEvent() */ + virtual void keyReleaseEvent(KeyEvent& event); + + /*@}*/ + + /** @{ @name Mouse handling */ + + /** @copydoc Sdl2Application::mousePressEvent() */ + virtual void mousePressEvent(MouseEvent& event); + + /** @copydoc Sdl2Application::mouseReleaseEvent() */ + virtual void mouseReleaseEvent(MouseEvent& event); + + /** @copydoc Sdl2Application::mouseMoveEvent() */ + virtual void mouseMoveEvent(MouseMoveEvent& event); + + /*@}*/ + + private: + enum class Flag: unsigned int { + Redraw = 1 << 0, + Exit = 1 << 1 + }; + + typedef Corrade::Containers::EnumSet Flags; + CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) + + Display* display; + Window window; + Atom deleteWindow; + + AbstractContextHandler* contextHandler; + + Context* c; + + /** @todo Get this from the created window */ + Vector2i viewportSize; + + Flags flags; +}; + +CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Flags) + +/** +@brief Base for input events + +@see KeyEvent, MouseEvent, MouseMoveEvent, keyPressEvent(), keyReleaseEvent(), + mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent() +*/ +class AbstractXApplication::InputEvent { + InputEvent(const InputEvent& other) = delete; + InputEvent(InputEvent&& other) = delete; + InputEvent& operator=(const InputEvent& other) = delete; + InputEvent& operator=(InputEvent&& other) = delete; + + public: public: /** * @brief %Modifier * - * @see Modifiers, keyPressEvent(), keyReleaseEvent(), - * mousePressEvent(), mouseReleaseEvent(), mouseMotionEvent() + * @see Modifiers, modifiers() */ enum class Modifier: unsigned int { Shift = ShiftMask, /**< Shift */ @@ -118,14 +190,46 @@ class AbstractXApplication { /** * @brief Set of modifiers * - * @see keyPressEvent(), keyReleaseEvent() + * @see modifiers() */ typedef Corrade::Containers::EnumSet Modifiers; + inline virtual ~InputEvent() {} + + /** @copydoc GlutApplication::InputEvent::setAccepted() */ + inline void setAccepted(bool accepted = true) { _accepted = accepted; } + + /** @copydoc GlutApplication::InputEvent::isAccepted() */ + inline bool isAccepted() { return _accepted; } + + /** @brief Modifiers */ + inline Modifiers modifiers() const { return _modifiers; } + + #ifndef DOXYGEN_GENERATING_OUTPUT + protected: + inline InputEvent(Modifiers modifiers): _modifiers(modifiers), _accepted(false) {} + #endif + + private: + Modifiers _modifiers; + bool _accepted; +}; + +CORRADE_ENUMSET_OPERATORS(AbstractXApplication::InputEvent::Modifiers) + +/** +@brief Key event + +@see keyPressEvent(), keyReleaseEvent() +*/ +class AbstractXApplication::KeyEvent: public AbstractXApplication::InputEvent { + friend class AbstractXApplication; + + public: /** * @brief Key * - * @see keyPressEvent(), keyReleaseEvent() + * @see key() */ enum class Key: KeySym { Enter = XK_Return, /**< Enter */ @@ -200,38 +304,34 @@ class AbstractXApplication { Z = XK_z /**< Small letter Z */ }; - protected: - /** - * @brief Key press event - * @param key Key pressed - * @param modifiers Active modifiers - * @param position Cursor position - * - * Called when an key is pressed. Default implementation does nothing. - */ - virtual void keyPressEvent(Key key, Modifiers modifiers, const Math::Vector2& position); + /** @brief Key */ + inline Key key() const { return _key; } - /** - * @brief Key press event - * @param key Key released - * @param modifiers Active modifiers - * @param position Cursor position - * - * Called when an key is released. Default implementation does nothing. - */ - virtual void keyReleaseEvent(Key key, Modifiers modifiers, const Math::Vector2& position); + /** @brief Position */ + inline Vector2i position() const { return _position; } - /*@}*/ + private: + inline KeyEvent(Key key, Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _key(key), _position(position) {} - /** @{ @name Mouse handling */ + const Key _key; + const Vector2i _position; +}; + +/** +@brief Mouse event + +@see MouseMoveEvent, mousePressEvent(), mouseReleaseEvent() +*/ +class AbstractXApplication::MouseEvent: public AbstractXApplication::InputEvent { + friend class AbstractXApplication; public: /** * @brief Mouse button * - * @see mousePressEvent(), mouseReleaseEvent() + * @see button() */ - enum class MouseButton: unsigned int { + enum class Button: unsigned int { Left = Button1, /**< Left button */ Middle = Button2, /**< Middle button */ Right = Button3, /**< Right button */ @@ -239,68 +339,44 @@ class AbstractXApplication { WheelDown = Button5 /**< Wheel down */ }; - protected: - /** - * @brief Mouse press event - * @param button Button pressed - * @param modifiers Active modifiers - * @param position Cursor position - * - * Called when mouse button is pressed. Default implementation does - * nothing. - */ - virtual void mousePressEvent(MouseButton button, Modifiers modifiers, const Math::Vector2& position); - - /** - * @brief Mouse release event - * @param button Button released - * @param modifiers Active modifiers - * @param position Cursor position - * - * Called when mouse button is released. Default implementation does - * nothing. - */ - virtual void mouseReleaseEvent(MouseButton button, Modifiers modifiers, const Math::Vector2& position); - - /** - * @brief Mouse motion event - * @param modifiers Active modifiers - * @param position Cursor position - * - * Called when mouse is moved. - */ - virtual void mouseMotionEvent(Modifiers modifiers, const Math::Vector2& position); + /** @brief Button */ + inline Button button() const { return _button; } - /*@}*/ + /** @brief Position */ + inline Vector2i position() const { return _position; } private: - enum class Flag: unsigned int { - Redraw = 1 << 0, - Exit = 1 << 1 - }; + inline MouseEvent(Button button, Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _button(button), _position(position) {} - typedef Corrade::Containers::EnumSet Flags; - CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) + const Button _button; + const Vector2i _position; +}; - Display* display; - Window window; - Atom deleteWindow; +/** +@brief Mouse move event - AbstractContextHandler* contextHandler; +@see MouseEvent, mouseMoveEvent() +*/ +class AbstractXApplication::MouseMoveEvent: public AbstractXApplication::InputEvent { + friend class AbstractXApplication; - Context* c; + public: + /** @brief Position */ + inline Vector2i position() const { return _position; } - /** @todo Get this from the created window */ - Math::Vector2 viewportSize; + private: + inline MouseMoveEvent(Modifiers modifiers, const Vector2i& position): InputEvent(modifiers), _position(position) {} - Flags flags; + const Vector2i _position; }; /** @hideinitializer +@brief Entry point for X11-based applications @param className Class name -Can be used as equivalent to the following code to achieve better portability, -see @ref portability-applications for more information. +Can be used with AbstractXApplication subclasses as equivalent to the +following code to achieve better portability, see @ref portability-applications +for more information. @code int main(int argc, char** argv) { className app(argc, argv); @@ -324,15 +400,12 @@ When no other application header is included this macro is also aliased to #endif #endif -CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Modifiers) -CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Flags) - /* Implementations for inline functions with unused parameters */ -inline void AbstractXApplication::keyPressEvent(Key, Modifiers, const Math::Vector2&) {} -inline void AbstractXApplication::keyReleaseEvent(Key, Modifiers, const Math::Vector2&) {} -inline void AbstractXApplication::mousePressEvent(MouseButton, Modifiers, const Math::Vector2&) {} -inline void AbstractXApplication::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2&) {} -inline void AbstractXApplication::mouseMotionEvent(Modifiers, const Math::Vector2&) {} +inline void AbstractXApplication::keyPressEvent(KeyEvent&) {} +inline void AbstractXApplication::keyReleaseEvent(KeyEvent&) {} +inline void AbstractXApplication::mousePressEvent(MouseEvent&) {} +inline void AbstractXApplication::mouseReleaseEvent(MouseEvent&) {} +inline void AbstractXApplication::mouseMoveEvent(MouseMoveEvent&) {} }} diff --git a/src/Platform/CMakeLists.txt b/src/Platform/CMakeLists.txt index f441d40be..378c14cbc 100644 --- a/src/Platform/CMakeLists.txt +++ b/src/Platform/CMakeLists.txt @@ -1,9 +1,34 @@ -# Extension wrangler -add_library(MagnumPlatformExtensionWrangler OBJECT ExtensionWrangler.cpp) +# +# 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. +# set(MagnumPlatform_HEADERS AbstractContextHandler.h ExtensionWrangler.h) + +# Extension wrangler +add_library(MagnumPlatformExtensionWrangler OBJECT ExtensionWrangler.cpp) + install(FILES ${MagnumPlatform_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) # GLUT application @@ -16,7 +41,7 @@ if(WITH_GLUTAPPLICATION) install(FILES GlutApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) install(TARGETS MagnumGlutApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) else() - message(FATAL_ERROR "GLUT library, required by GlutApplication, was not found. Set WITH_GLUTWINDOWCONTEXT to OFF to skip building it.") + message(FATAL_ERROR "GLUT library, required by GlutApplication, was not found. Set WITH_GLUTAPPLICATION to OFF to skip building it.") endif() endif() @@ -31,7 +56,7 @@ if(WITH_SDL2APPLICATION) install(FILES Sdl2Application.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) install(TARGETS MagnumSdl2Application DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) else() - message(FATAL_ERROR "SDL2 library, required by Sdl2Application, was not found. Set WITH_SDL2WINDOWCONTEXT to OFF to skip building it.") + message(FATAL_ERROR "SDL2 library, required by Sdl2Application, was not found. Set WITH_SDL2APPLICATION to OFF to skip building it.") endif() endif() @@ -59,8 +84,8 @@ if(WITH_GLXAPPLICATION) install(TARGETS MagnumGlxApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) endif() -# X/EGL window context -if(WITH_XEGLWINDOWCONTEXT) +# X/EGL application +if(WITH_XEGLAPPLICATION) set(NEED_ABSTRACTXAPPLICATION 1) set(NEED_EGLCONTEXT 1) add_library(MagnumXEglApplication STATIC @@ -71,12 +96,26 @@ if(WITH_XEGLWINDOWCONTEXT) install(TARGETS MagnumXEglApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) endif() -# Abstract X application -if(NEED_ABSTRACTXAPPLICATION) +if(WITH_WINDOWLESSGLXAPPLICATION OR NEED_ABSTRACTXAPPLICATION) find_package(X11) if(NOT X11_FOUND) - message(FATAL_ERROR "X11 library, required by some contexts, was not found. Set WITH_*X*WINDOWCONTEXT to OFF to skip building them.") + message(FATAL_ERROR "X11 library, required by some contexts, was not found. Set WITH_*X*APPLICATION to OFF to skip building them.") endif() +endif() + +# Windowless GLX application +if(WITH_WINDOWLESSGLXAPPLICATION) + add_library(MagnumWindowlessGlxApplication STATIC + WindowlessGlxApplication.cpp + $) + # X11 macros are a mess, disable warnings for C-style casts + set_target_properties(MagnumWindowlessGlxApplication PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") + install(FILES WindowlessGlxApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) + install(TARGETS MagnumWindowlessGlxApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +endif() + +# Abstract X application +if(NEED_ABSTRACTXAPPLICATION) add_library(MagnumAbstractXApplication OBJECT AbstractXApplication.cpp) # X11 macros are a mess, disable warnings for C-style casts set_target_properties(MagnumAbstractXApplication PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") @@ -95,10 +134,21 @@ endif() if(NEED_EGLCONTEXT) find_package(EGL) if(NOT EGL_FOUND) - message(FATAL_ERROR "EGL library, required by some window contexts, was not found. Set WITH_*EGL*WINDOWCONTEXT to OFF to skip building them.") + message(FATAL_ERROR "EGL library, required by some window contexts, was not found. Set WITH_*EGL*APPLICATION to OFF to skip building them.") endif() add_library(MagnumEglContextHandler OBJECT EglContextHandler.cpp) # X11 macros are a mess, disable warnings for C-style casts set_target_properties(MagnumEglContextHandler PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") install(FILES EglContextHandler.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) endif() + +# Magnum Info +if(WITH_MAGNUMINFO) + if(UNIX) + add_executable(magnum-info magnum-info.cpp) + target_link_libraries(magnum-info Magnum MagnumWindowlessGlxApplication ${X11_LIBRARIES}) + install(TARGETS magnum-info DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}) + else() + message(WARNING "magnum-info is currently available only on Unix. Set WITH_MAGNUMINFO to OFF to suppress this warning.") + endif() +endif() diff --git a/src/Platform/EglContextHandler.cpp b/src/Platform/EglContextHandler.cpp index 6f0c9884d..75a1f05d4 100644 --- a/src/Platform/EglContextHandler.cpp +++ b/src/Platform/EglContextHandler.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "EglContextHandler.h" @@ -32,7 +41,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) { display = eglGetDisplay(nativeDisplay); if(!eglInitialize(display, nullptr, nullptr)) { Error() << "Cannot initialize EGL:" << errorString(eglGetError()); - exit(1); + std::exit(1); } #ifndef MAGNUM_TARGET_GLES @@ -42,7 +51,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) { #endif if(!eglBindAPI(api)) { Error() << "Cannot bind EGL API:" << errorString(eglGetError()); - exit(1); + std::exit(1); } /* Choose EGL config */ @@ -61,19 +70,19 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) { EGLint configCount; if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) { Error() << "Cannot get EGL visual config:" << errorString(eglGetError()); - exit(1); + std::exit(1); } if(!configCount) { Error() << "No matching EGL visual config available"; - exit(1); + std::exit(1); } /* Get visual ID */ EGLint visualId; if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) { Error() << "Cannot get native visual ID:" << errorString(eglGetError()); - exit(1); + std::exit(1); } return visualId; @@ -88,11 +97,11 @@ void EglContextHandler::createContext(EGLNativeWindowType window) { }; if(!eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes)) { Error() << "Cannot create EGL context:" << errorString(eglGetError()); - exit(1); + std::exit(1); } if(!(surface = eglCreateWindowSurface(display, config, window, NULL))) { Error() << "Cannot create window surface:" << errorString(eglGetError()); - exit(1); + std::exit(1); } /** @bug Fixme: On desktop OpenGL and Mesa EGL implementation OpenGL version is 1.0, which is wrong */ @@ -119,7 +128,7 @@ const char* EglContextHandler::errorString(EGLint error) { #undef _error } - return ""; + return {}; } }} diff --git a/src/Platform/EglContextHandler.h b/src/Platform/EglContextHandler.h index 878e5d3ab..a67d709e0 100644 --- a/src/Platform/EglContextHandler.h +++ b/src/Platform/EglContextHandler.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_EglContextHandler_h #define Magnum_Platform_EglContextHandler_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -51,6 +60,7 @@ Used in XEglApplication. */ class EglContextHandler: public AbstractContextHandler { public: + explicit EglContextHandler() = default; ~EglContextHandler(); VisualId getVisualId(EGLNativeDisplayType nativeDisplay) override; diff --git a/src/Platform/ExtensionWrangler.cpp b/src/Platform/ExtensionWrangler.cpp index c84795546..4db476384 100644 --- a/src/Platform/ExtensionWrangler.cpp +++ b/src/Platform/ExtensionWrangler.cpp @@ -1,23 +1,34 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ExtensionWrangler.h" +#include #include #include "Magnum.h" +#include "OpenGL.h" namespace Magnum { namespace Platform { @@ -31,7 +42,7 @@ void ExtensionWrangler::initialize(ExperimentalFeatures experimentalFeatures) { GLenum err = glewInit(); if(err != GLEW_OK) { Error() << "ExtensionWrangler: cannot initialize GLEW:" << glewGetErrorString(err); - exit(1); + std::exit(1); } #else static_cast(experimentalFeatures); /* Shut up about unused parameter */ diff --git a/src/Platform/ExtensionWrangler.h b/src/Platform/ExtensionWrangler.h index f9353b3fc..39ad83bce 100644 --- a/src/Platform/ExtensionWrangler.h +++ b/src/Platform/ExtensionWrangler.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_ExtensionWrangler_h #define Magnum_Platform_ExtensionWrangler_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,9 +30,11 @@ namespace Magnum { namespace Platform { -/** @brief Extension wrangler interface */ +/** @brief %Extension wrangler interface */ class ExtensionWrangler { public: + ExtensionWrangler() = delete; + /** @brief Whether to enable or disable experimental features */ enum class ExperimentalFeatures { Disable, diff --git a/src/Platform/GlutApplication.cpp b/src/Platform/GlutApplication.cpp index 321d51c2b..cdf7dd5c9 100644 --- a/src/Platform/GlutApplication.cpp +++ b/src/Platform/GlutApplication.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "GlutApplication.h" @@ -22,7 +31,7 @@ namespace Magnum { namespace Platform { GlutApplication* GlutApplication::instance = nullptr; -GlutApplication::GlutApplication(int& argc, char** argv, const std::string& title, const Math::Vector2& size) { +GlutApplication::GlutApplication(int& argc, char** argv, const std::string& title, const Vector2i& size) { /* Save global instance */ instance = this; @@ -35,7 +44,7 @@ GlutApplication::GlutApplication(int& argc, char** argv, const std::string& titl glutReshapeFunc(staticViewportEvent); glutSpecialFunc(staticKeyEvent); glutMouseFunc(staticMouseEvent); - glutMotionFunc(staticMouseMotionEvent); + glutMotionFunc(staticMouseMoveEvent); glutDisplayFunc(staticDrawEvent); ExtensionWrangler::initialize(); @@ -47,4 +56,22 @@ GlutApplication::~GlutApplication() { delete c; } +void GlutApplication::staticKeyEvent(int key, int x, int y){ + KeyEvent e(static_cast(key), {x, y}); + instance->keyPressEvent(e); +} + +void GlutApplication::staticMouseEvent(int button, int state, int x, int y) { + MouseEvent e(static_cast(button), {x, y}); + if(state == GLUT_DOWN) + instance->mousePressEvent(e); + else + instance->mouseReleaseEvent(e); +} + +void GlutApplication::staticMouseMoveEvent(int x, int y) { + MouseMoveEvent e({x, y}); + instance->mouseMoveEvent(e); +} + }} diff --git a/src/Platform/GlutApplication.h b/src/Platform/GlutApplication.h index 07e5c4572..15921fb12 100644 --- a/src/Platform/GlutApplication.h +++ b/src/Platform/GlutApplication.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_GlutApplication_h #define Magnum_Platform_GlutApplication_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -23,6 +32,7 @@ #include "Math/Vector2.h" #include "Magnum.h" +#include "OpenGL.h" #include @@ -35,13 +45,14 @@ namespace Platform { /** @nosubgrouping @brief GLUT application -Supports keyboard handling for limited subset of keys, mouse handling with -support for changing cursor and mouse tracking and warping. +Creates double-buffered RGBA window with depth and stencil buffers. Supports +keyboard handling for limited subset of keys, mouse handling with support for +changing cursor and mouse tracking and warping. @section GlutApplication-usage Usage You need to implement at least drawEvent() and viewportEvent() to be able to -draw on the screen. The subclass can be then used directly in `main()` - see +draw on the screen. The subclass can be then used directly in `main()` -- see convenience macro MAGNUM_GLUTAPPLICATION_MAIN(). @code class MyApplication: public Magnum::Platform::GlutApplication { @@ -52,16 +63,19 @@ MAGNUM_GLUTAPPLICATION_MAIN(MyApplication) */ class GlutApplication { public: + class InputEvent; + class KeyEvent; + class MouseEvent; + class MouseMoveEvent; + /** * @brief Constructor * @param argc Count of arguments of `main()` function * @param argv Arguments of `main()` function * @param title Window title * @param size Window size - * - * Creates double-buffered RGBA window with depth and stencil buffers. */ - GlutApplication(int& argc, char** argv, const std::string& title = "Magnum GLUT application", const Math::Vector2& size = Math::Vector2(800, 600)); + explicit GlutApplication(int& argc, char** argv, const std::string& title = "Magnum GLUT application", const Vector2i& size = Vector2i(800, 600)); virtual ~GlutApplication(); @@ -80,11 +94,11 @@ class GlutApplication { /** * @brief Viewport event * - * Called when viewport size changes. You should pass the new size to - * Framebuffer::setViewport() (and SceneGraph::AbstractCamera::setViewport(), - * if using scene graph). + * Called when window size changes. You should pass the new size to + * DefaultFramebuffer::setViewport() and possibly elsewhere (cameras, + * other framebuffers...). */ - virtual void viewportEvent(const Math::Vector2& size) = 0; + virtual void viewportEvent(const Vector2i& size) = 0; /** * @brief Draw event @@ -120,63 +134,18 @@ class GlutApplication { /** @{ @name Keyboard handling */ - public: - /** - * @brief Key - * - * @see keyPressEvent() - */ - enum class Key: int { - Up = GLUT_KEY_UP, /**< Up arrow */ - Down = GLUT_KEY_DOWN, /**< Down arrow */ - Left = GLUT_KEY_LEFT, /**< Left arrow */ - Right = GLUT_KEY_RIGHT, /**< Right arrow */ - F1 = GLUT_KEY_F1, /**< F1 */ - F2 = GLUT_KEY_F2, /**< F2 */ - F3 = GLUT_KEY_F3, /**< F3 */ - F4 = GLUT_KEY_F4, /**< F4 */ - F5 = GLUT_KEY_F5, /**< F5 */ - F6 = GLUT_KEY_F6, /**< F6 */ - F7 = GLUT_KEY_F7, /**< F7 */ - F8 = GLUT_KEY_F8, /**< F8 */ - F9 = GLUT_KEY_F9, /**< F9 */ - F10 = GLUT_KEY_F10, /**< F10 */ - F11 = GLUT_KEY_F11, /**< F11 */ - F12 = GLUT_KEY_F12, /**< F12 */ - Home = GLUT_KEY_HOME, /**< Home */ - End = GLUT_KEY_END, /**< End */ - PageUp = GLUT_KEY_PAGE_UP, /**< Page up */ - PageDown = GLUT_KEY_PAGE_DOWN /**< Page down */ - }; - - protected: /** * @brief Key press event - * @param key Key pressed - * @param position Cursor position * * Called when an key is pressed. Default implementation does nothing. */ - virtual void keyPressEvent(Key key, const Math::Vector2& position); + virtual void keyPressEvent(KeyEvent& event); /*@}*/ /** @{ @name Mouse handling */ public: - /** - * @brief Mouse button - * - * @see mousePressEvent(), mouseReleaseEvent() - */ - enum class MouseButton: int { - Left = GLUT_LEFT_BUTTON, /**< Left button */ - Middle = GLUT_MIDDLE_BUTTON, /**< Middle button */ - Right = GLUT_RIGHT_BUTTON, /**< Right button */ - WheelUp = 3, /**< Wheel up */ - WheelDown = 4 /**< Wheel down */ - }; - /** * @brief Mouse cursor * @@ -194,7 +163,7 @@ class GlutApplication { * when no button is pressed. Mouse tracking is disabled by default. */ inline void setMouseTracking(bool enabled) { - glutPassiveMotionFunc(enabled ? staticMouseMotionEvent : nullptr); + glutPassiveMotionFunc(enabled ? staticMouseMoveEvent : nullptr); } /** @brief Set mouse cursor */ @@ -203,7 +172,7 @@ class GlutApplication { } /** @brief Warp mouse cursor to given coordinates */ - inline void warpMouseCursor(const Math::Vector2& position) { + inline void warpMouseCursor(const Vector2i& position) { glutWarpPointer(position.x(), position.y()); } @@ -214,7 +183,7 @@ class GlutApplication { * Called when mouse button is pressed. Default implementation does * nothing. */ - virtual void mousePressEvent(MouseButton button, const Math::Vector2& position); + virtual void mousePressEvent(MouseEvent& event); /** * @brief Mouse release event @@ -222,16 +191,16 @@ class GlutApplication { * Called when mouse button is released. Default implementation does * nothing. */ - virtual void mouseReleaseEvent(MouseButton button, const Math::Vector2& position); + virtual void mouseReleaseEvent(MouseEvent& event); /** - * @brief Mouse motion event + * @brief Mouse move event * * Called when any mouse button is pressed and mouse is moved. Default * implementation does nothing. * @see setMouseTracking() */ - virtual void mouseMotionEvent(const Math::Vector2& position); + virtual void mouseMoveEvent(MouseMoveEvent& event); /*@}*/ @@ -240,20 +209,11 @@ class GlutApplication { instance->viewportEvent({x, y}); } - inline static void staticKeyEvent(int key, int x, int y) { - instance->keyPressEvent(static_cast(key), {x, y}); - } + static void staticKeyEvent(int key, int x, int y); - inline static void staticMouseEvent(int button, int state, int x, int y) { - if(state == GLUT_DOWN) - instance->mousePressEvent(static_cast(button), {x, y}); - else - instance->mouseReleaseEvent(static_cast(button), {x, y}); - } + static void staticMouseEvent(int button, int state, int x, int y); - inline static void staticMouseMotionEvent(int x, int y) { - instance->mouseMotionEvent({x, y}); - } + static void staticMouseMoveEvent(int x, int y); inline static void staticDrawEvent() { instance->drawEvent(); @@ -264,11 +224,151 @@ class GlutApplication { Context* c; }; +/** +@brief Base for input events + +@see KeyEvent, MouseEvent, MouseMoveEvent, keyPressEvent(), mousePressEvent(), + mouseReleaseEvent(), mouseMoveEvent() +*/ +class GlutApplication::InputEvent { + InputEvent(const InputEvent& other) = delete; + InputEvent(InputEvent&& other) = delete; + InputEvent& operator=(const InputEvent& other) = delete; + InputEvent& operator=(InputEvent&& other) = 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; } + + /** @brief Whether the event is accepted */ + inline bool isAccepted() { return _accepted; } + + #ifndef DOXYGEN_GENERATING_OUTPUT + protected: + inline InputEvent(): _accepted(false) {} + #endif + + private: + bool _accepted; +}; + +/** +@brief Key event + +@see keyPressEvent() +*/ +class GlutApplication::KeyEvent: public GlutApplication::InputEvent { + friend class GlutApplication; + + public: + /** + * @brief Key + * + * @see key() + */ + enum class Key: int { + Up = GLUT_KEY_UP, /**< Up arrow */ + Down = GLUT_KEY_DOWN, /**< Down arrow */ + Left = GLUT_KEY_LEFT, /**< Left arrow */ + Right = GLUT_KEY_RIGHT, /**< Right arrow */ + F1 = GLUT_KEY_F1, /**< F1 */ + F2 = GLUT_KEY_F2, /**< F2 */ + F3 = GLUT_KEY_F3, /**< F3 */ + F4 = GLUT_KEY_F4, /**< F4 */ + F5 = GLUT_KEY_F5, /**< F5 */ + F6 = GLUT_KEY_F6, /**< F6 */ + F7 = GLUT_KEY_F7, /**< F7 */ + F8 = GLUT_KEY_F8, /**< F8 */ + F9 = GLUT_KEY_F9, /**< F9 */ + F10 = GLUT_KEY_F10, /**< F10 */ + F11 = GLUT_KEY_F11, /**< F11 */ + F12 = GLUT_KEY_F12, /**< F12 */ + Home = GLUT_KEY_HOME, /**< Home */ + End = GLUT_KEY_END, /**< End */ + PageUp = GLUT_KEY_PAGE_UP, /**< Page up */ + PageDown = GLUT_KEY_PAGE_DOWN /**< Page down */ + }; + + /** @brief Key */ + inline Key key() const { return _key; } + + /** @brief Position */ + inline Vector2i position() const { return _position; } + + private: + inline KeyEvent(Key key, const Vector2i& position): _key(key), _position(position) {} + + const Key _key; + const Vector2i _position; +}; + +/** +@brief Mouse event + +@see MouseMoveEvent, mousePressEvent(), mouseReleaseEvent() +*/ +class GlutApplication::MouseEvent: public GlutApplication::InputEvent { + friend class GlutApplication; + + public: + /** + * @brief Mouse button + * + * @see button() + */ + enum class Button: int { + Left = GLUT_LEFT_BUTTON, /**< Left button */ + Middle = GLUT_MIDDLE_BUTTON, /**< Middle button */ + Right = GLUT_RIGHT_BUTTON, /**< Right button */ + WheelUp = 3, /**< Wheel up */ + WheelDown = 4 /**< Wheel down */ + }; + + /** @brief Button */ + inline Button button() const { return _button; } + + /** @brief Position */ + inline Vector2i position() const { return _position; } + + private: + inline MouseEvent(Button button, const Vector2i& position): _button(button), _position(position) {} + + const Button _button; + const Vector2i _position; +}; + +/** +@brief Mouse move event + +@see MouseEvent, mouseMoveEvent() +*/ +class GlutApplication::MouseMoveEvent: public GlutApplication::InputEvent { + friend class GlutApplication; + + public: + /** @brief Position */ + inline Vector2i position() const { return _position; } + + private: + inline MouseMoveEvent(const Vector2i& position): _position(position) {} + + const Vector2i _position; +}; + /** @hideinitializer +@brief Entry point for GLUT-based applications @param className Class name -Can be used as equivalent to the following code to achieve better portability, -see @ref portability-applications for more information. +Can be with GlutApplication subclasses used as equivalent to the following +code to achieve better portability, see @ref portability-applications for more +information. @code int main(int argc, char** argv) { className app(argc, argv); @@ -293,10 +393,10 @@ When no other application header is included this macro is also aliased to #endif /* Implementations for inline functions with unused parameters */ -inline void GlutApplication::keyPressEvent(Key, const Math::Vector2&) {} -inline void GlutApplication::mousePressEvent(MouseButton, const Math::Vector2&) {} -inline void GlutApplication::mouseReleaseEvent(MouseButton, const Math::Vector2&) {} -inline void GlutApplication::mouseMotionEvent(const Math::Vector2&) {} +inline void GlutApplication::keyPressEvent(KeyEvent&) {} +inline void GlutApplication::mousePressEvent(MouseEvent&) {} +inline void GlutApplication::mouseReleaseEvent(MouseEvent&) {} +inline void GlutApplication::mouseMoveEvent(MouseMoveEvent&) {} }} diff --git a/src/Platform/GlxApplication.h b/src/Platform/GlxApplication.h index f17d683be..1f1f4ea5f 100644 --- a/src/Platform/GlxApplication.h +++ b/src/Platform/GlxApplication.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_GlxApplication_h #define Magnum_Platform_GlxApplication_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -27,7 +36,8 @@ namespace Magnum { namespace Platform { /** @brief GLX application -Uses GlxContextHandler. +Creates window with double-buffered OpenGL or OpenGL ES 2.0 context, if +targetting OpenGL ES. Uses GlxContextHandler. @section GlxApplication-usage Usage @@ -49,11 +59,8 @@ class GlxApplication: public AbstractXApplication { * @param argv Arguments of `main()` function * @param title Window title * @param size Window size - * - * Creates window with double-buffered OpenGL 3.2 core context or - * OpenGL ES 2.0 context, if targetting OpenGL ES. */ - inline GlxApplication(int& argc, char** argv, const std::string& title = "Magnum GLX application", const Math::Vector2& size = Math::Vector2(800, 600)): AbstractXApplication(new GlxContextHandler, argc, argv, title, size) {} + inline explicit GlxApplication(int& argc, char** argv, const std::string& title = "Magnum GLX application", const Vector2i& size = Vector2i(800, 600)): AbstractXApplication(new GlxContextHandler, argc, argv, title, size) {} }; }} diff --git a/src/Platform/GlxContextHandler.cpp b/src/Platform/GlxContextHandler.cpp index cc6ab5698..f39cd2db4 100644 --- a/src/Platform/GlxContextHandler.cpp +++ b/src/Platform/GlxContextHandler.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "GlxContextHandler.h" @@ -32,7 +41,7 @@ VisualID GlxContextHandler::getVisualId(Display* nativeDisplay) { glXQueryVersion(nativeDisplay, &major, &minor); if(major == 1 && minor < 4) { Error() << "GlxContextHandler: GLX version 1.4 or greater is required."; - exit(1); + std::exit(1); } /* Choose config */ @@ -50,7 +59,7 @@ VisualID GlxContextHandler::getVisualId(Display* nativeDisplay) { configs = glXChooseFBConfig(nativeDisplay, DefaultScreen(nativeDisplay), attributes, &configCount); if(!configCount) { Error() << "GlxContextHandler: no supported framebuffer configuration found."; - exit(1); + std::exit(1); } /* Get visual ID */ @@ -65,11 +74,7 @@ void GlxContextHandler::createContext(Window nativeWindow) { window = nativeWindow; GLint attributes[] = { - #ifndef MAGNUM_TARGET_GLES - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - #else + #ifdef MAGNUM_TARGET_GLES GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, @@ -83,7 +88,7 @@ void GlxContextHandler::createContext(Window nativeWindow) { XFree(configs); if(!context) { Error() << "GlxContextHandler: cannot create context."; - exit(1); + std::exit(1); } } diff --git a/src/Platform/GlxContextHandler.h b/src/Platform/GlxContextHandler.h index 8922f9bf5..d5455c5d0 100644 --- a/src/Platform/GlxContextHandler.h +++ b/src/Platform/GlxContextHandler.h @@ -1,27 +1,37 @@ #ifndef Magnum_Platform_GlxContextHandler_h #define Magnum_Platform_GlxContextHandler_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Platform::GlxContextHandler */ -#include "Magnum.h" +#include "OpenGL.h" #include /* undef Xlib nonsense to avoid conflicts */ +#undef Complex #undef None #undef Always @@ -34,13 +44,12 @@ namespace Magnum { namespace Platform { /** @brief GLX context -Creates OpenGL 3.2 core context or OpenGL ES 2.0 context, if targetting -OpenGL ES. - -Used in GlxApplication. +Creates OpenGL or OpenGL ES 2.0 context, if targetting OpenGL ES. Used in +GlxApplication. */ class GlxContextHandler: public AbstractContextHandler { public: + explicit GlxContextHandler() = default; ~GlxContextHandler(); VisualID getVisualId(Display* nativeDisplay) override; diff --git a/src/Platform/NaClApplication.cpp b/src/Platform/NaClApplication.cpp index 909aea265..87a442ccc 100644 --- a/src/Platform/NaClApplication.cpp +++ b/src/Platform/NaClApplication.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "NaClApplication.h" @@ -23,8 +32,8 @@ namespace Magnum { namespace Platform { -NaClApplication::NaClApplication(PP_Instance instance, const Math::Vector2& size): Instance(instance), Graphics3DClient(this), MouseLock(this), viewportSize(size) { - int32_t attributes[] = { +NaClApplication::NaClApplication(PP_Instance instance, const Vector2i& size): Instance(instance), Graphics3DClient(this), MouseLock(this), viewportSize(size) { + std::int32_t attributes[] = { PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8, @@ -38,11 +47,11 @@ NaClApplication::NaClApplication(PP_Instance instance, const Math::Vector2is_null()) { Error() << "Platform::NaClApplication::NaClApplication(): cannot create graphics"; - exit(1); + std::exit(1); } if(!BindGraphics(*graphics)) { Error() << "Platform::NaClApplication::NaClApplication(): cannot bind graphics"; - exit(1); + std::exit(1); } fullscreen = new pp::Fullscreen(this); @@ -101,7 +110,7 @@ void NaClApplication::DidChangeView(const pp::View& view) { else return; } - Math::Vector2 size(view.GetRect().width(), view.GetRect().height()); + Vector2i size(view.GetRect().width(), view.GetRect().height()); /* Canvas resized */ if(viewportSize != size) { @@ -195,7 +204,7 @@ void NaClApplication::setMouseLocked(bool enabled) { else UnlockMouse(); } -void NaClApplication::mouseLockCallback(void* applicationInstance, int32_t) { +void NaClApplication::mouseLockCallback(void* applicationInstance, std::int32_t) { NaClApplication* instance = static_cast(applicationInstance); instance->flags |= Flag::MouseLocked; } diff --git a/src/Platform/NaClApplication.h b/src/Platform/NaClApplication.h index aabdb6c9a..bd3145b0d 100644 --- a/src/Platform/NaClApplication.h +++ b/src/Platform/NaClApplication.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_NaClApplication_h #define Magnum_Platform_NaClApplication_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -44,7 +53,8 @@ namespace Magnum { namespace Platform { @brief NaCl application Application running in [Google Chrome Native Client](https://developers.google.com/native-client/). -Supports keyboard and mouse handling. +Creates double-buffered RGBA canvas with depth and stencil buffers. Supports +keyboard and mouse handling. @section NaClApplication-usage Usage @@ -69,10 +79,8 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public * @brief Constructor * @param instance Module instance * @param size Rendering size - * - * Creates double-buffered RGBA canvas with depth and stencil buffers. */ - explicit NaClApplication(PP_Instance instance, const Math::Vector2& size = Math::Vector2(640, 480)); + explicit NaClApplication(PP_Instance instance, const Vector2i& size = Vector2i(640, 480)); ~NaClApplication(); @@ -94,7 +102,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public /** @{ @name Drawing functions */ /** @copydoc GlutApplication::viewportEvent() */ - virtual void viewportEvent(const Math::Vector2& size) = 0; + virtual void viewportEvent(const Vector2i& size) = 0; /** @copydoc GlutApplication::drawEvent() */ virtual void drawEvent() = 0; @@ -177,7 +185,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public /*@}*/ private: - enum class Flag: std::uint8_t { + enum class Flag: UnsignedByte { ViewportUpdated = 1 << 0, SwapInProgress = 1 << 1, Redraw = 1 << 2, @@ -185,7 +193,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public WillBeFullscreen = 1 << 4, MouseLocked = 1 << 5 }; - typedef Corrade::Containers::EnumSet Flags; + typedef Corrade::Containers::EnumSet Flags; inline void Graphics3DContextLost() override { CORRADE_ASSERT(false, "NaClApplication: context unexpectedly lost", ); @@ -205,7 +213,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public pp::Graphics3D* graphics; pp::Fullscreen* fullscreen; Context* c; - Math::Vector2 viewportSize; + Vector2i viewportSize; Flags flags; CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) @@ -262,7 +270,8 @@ class NaClApplication::InputEvent { * @brief Set event as accepted * * If the event is ignored (i.e., not set as accepted), it is - * propagated to the browser. By default is each event ignored. + * propagated elsewhere (e.g. to the browser). By default is each + * event ignored. */ inline void setAccepted(bool accepted = true) { _accepted = accepted; } @@ -399,13 +408,13 @@ class NaClApplication::MouseEvent: public NaClApplication::InputEvent { inline Button button() const { return _button; } /** @brief Position */ - inline Math::Vector2 position() const { return _position; } + inline Vector2i position() const { return _position; } private: - inline MouseEvent(Button button, const Math::Vector2& position, Modifiers modifiers): InputEvent(modifiers), _button(button), _position(position) {} + inline MouseEvent(Button button, const Vector2i& position, Modifiers modifiers): InputEvent(modifiers), _button(button), _position(position) {} const Button _button; - const Math::Vector2 _position; + const Vector2i _position; }; /** @@ -419,19 +428,19 @@ class NaClApplication::MouseMoveEvent: public NaClApplication::InputEvent { public: /** @brief Position */ - inline Math::Vector2 position() const { return _position; } + inline Vector2i position() const { return _position; } /** * @brief Relative position * * Position relative to previous event. */ - inline Math::Vector2 relativePosition() const { return _relativePosition; } + inline Vector2i relativePosition() const { return _relativePosition; } private: - inline MouseMoveEvent(const Math::Vector2& position, const Math::Vector2& relativePosition, Modifiers modifiers): InputEvent(modifiers), _position(position), _relativePosition(relativePosition) {} + inline MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition, Modifiers modifiers): InputEvent(modifiers), _position(position), _relativePosition(relativePosition) {} - const Math::Vector2 _position, _relativePosition; + const Vector2i _position, _relativePosition; }; CORRADE_ENUMSET_OPERATORS(NaClApplication::Flags) diff --git a/src/Platform/Sdl2Application.cpp b/src/Platform/Sdl2Application.cpp index cf6a31b34..6ed239158 100644 --- a/src/Platform/Sdl2Application.cpp +++ b/src/Platform/Sdl2Application.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Sdl2Application.h" @@ -40,10 +49,10 @@ Sdl2Application::InputEvent::Modifiers fixedModifiers(Uint16 mod) { } -Sdl2Application::Sdl2Application(int, char**, const std::string& name, const Math::Vector2& size): _redraw(true) { +Sdl2Application::Sdl2Application(int, char**, const std::string& name, const Vector2i& size): flags(Flag::Redraw) { if(SDL_Init(SDL_INIT_VIDEO) < 0) { Error() << "Cannot initialize SDL."; - exit(1); + std::exit(1); } /* Enable double buffering and 24bt depth buffer */ @@ -54,7 +63,7 @@ Sdl2Application::Sdl2Application(int, char**, const std::string& name, const Mat size.x(), size.y(), SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); if(!window) { Error() << "Cannot create window."; - exit(2); + std::exit(2); } context = SDL_GL_CreateContext(window); @@ -83,7 +92,7 @@ Sdl2Application::~Sdl2Application() { } int Sdl2Application::exec() { - for(;;) { + while(!(flags & Flag::Exit)) { SDL_Event event; while(SDL_PollEvent(&event)) { @@ -92,10 +101,10 @@ int Sdl2Application::exec() { switch(event.window.event) { case SDL_WINDOWEVENT_RESIZED: viewportEvent({event.window.data1, event.window.data2}); - _redraw = true; + flags |= Flag::Redraw; break; case SDL_WINDOWEVENT_EXPOSED: - _redraw = true; + flags |= Flag::Redraw; break; } break; @@ -103,15 +112,13 @@ int Sdl2Application::exec() { 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; - } + } 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; - } + } break; case SDL_MOUSEWHEEL: if(event.wheel.y != 0) { @@ -129,8 +136,8 @@ int Sdl2Application::exec() { } } - if(_redraw) { - _redraw = false; + if(flags & Flag::Redraw) { + flags &= ~Flag::Redraw; drawEvent(); } else Corrade::Utility::sleep(5); } diff --git a/src/Platform/Sdl2Application.h b/src/Platform/Sdl2Application.h index c7b634d31..7a4d783cf 100644 --- a/src/Platform/Sdl2Application.h +++ b/src/Platform/Sdl2Application.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_Sdl2Application_h #define Magnum_Platform_Sdl2Application_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,6 +31,9 @@ #include "Math/Vector2.h" #include "Magnum.h" +#ifdef _WIN32 /* Windows version of SDL2 redefines main(), we don't want that */ +#define SDL_MAIN_HANDLED +#endif #include #include #include @@ -42,7 +54,7 @@ buffer. Supports keyboard and mouse handling. @section Sdl2Application-usage Usage You need to implement at least drawEvent() and viewportEvent() to be able to -draw on the screen. The subclass can be then used directly in `main()` - see +draw on the screen. The subclass can be then used directly in `main()` -- see convenience macro MAGNUM_SDL2APPLICATION_MAIN(). @code class MyApplication: public Magnum::Platform::Sdl2Application { @@ -65,7 +77,7 @@ class Sdl2Application { * @param title Window title * @param size Window size */ - Sdl2Application(int argc, char** argv, const std::string& title = "Magnum SDL2 application", const Math::Vector2& size = Math::Vector2(800, 600)); + explicit Sdl2Application(int argc, char** argv, const std::string& title = "Magnum SDL2 application", const Vector2i& size = Vector2i(800, 600)); /** * @brief Destructor @@ -80,12 +92,15 @@ class Sdl2Application { */ int exec(); + /** @brief Exit application main loop */ + inline void exit() { flags |= Flag::Exit; } + protected: /** @{ @name Drawing functions */ /** @copydoc GlutApplication::viewportEvent() */ - virtual void viewportEvent(const Math::Vector2& size) = 0; + virtual void viewportEvent(const Vector2i& size) = 0; /** @copydoc GlutApplication::drawEvent() */ virtual void drawEvent() = 0; @@ -94,17 +109,13 @@ class Sdl2Application { inline void swapBuffers() { SDL_GL_SwapWindow(window); } /** @copydoc GlutApplication::redraw() */ - inline void redraw() { _redraw = true; } + inline void redraw() { flags |= Flag::Redraw; } /*@}*/ /** @{ @name Keyboard handling */ - /** - * @brief Key press event - * - * Called when an key is pressed. Default implementation does nothing. - */ + /** @copydoc GlutApplication::keyPressEvent() */ virtual void keyPressEvent(KeyEvent& event); /** @@ -134,20 +145,10 @@ class Sdl2Application { void setMouseLocked(bool enabled); protected: - /** - * @brief Mouse press event - * - * Called when mouse button is pressed. Default implementation does - * nothing. - */ + /** @copydoc GlutApplication::mousePressEvent() */ virtual void mousePressEvent(MouseEvent& event); - /** - * @brief Mouse release event - * - * Called when mouse button is released. Default implementation does - * nothing. - */ + /** @copydoc GlutApplication::mouseReleaseEvent() */ virtual void mouseReleaseEvent(MouseEvent& event); /** @@ -160,14 +161,24 @@ class Sdl2Application { /*@}*/ private: + enum class Flag: UnsignedByte { + Redraw = 1 << 0, + Exit = 1 << 1 + }; + + typedef Corrade::Containers::EnumSet Flags; + CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) + SDL_Window* window; SDL_GLContext context; Context* c; - bool _redraw; + Flags flags; }; +CORRADE_ENUMSET_OPERATORS(Sdl2Application::Flags) + /** @brief Base for input events @@ -184,7 +195,8 @@ class Sdl2Application::InputEvent { /** * @brief %Modifier * - * @see Modifiers, KeyEvent::modifiers() + * @see Modifiers, KeyEvent::modifiers(), MouseEvent::modifiers(), + * MouseMoveEvent::modifiers() */ enum class Modifier: Uint16 { Shift = KMOD_SHIFT, /**< Shift */ @@ -199,21 +211,17 @@ class Sdl2Application::InputEvent { /** * @brief Set of modifiers * - * @see KeyEvent::modifiers() + * @see KeyEvent::modifiers(), MouseEvent::modifiers(), + * MouseMoveEvent::modifiers() */ typedef Corrade::Containers::EnumSet Modifiers; 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. - */ + /** @copydoc GlutApplication::InputEvent::setAccepted() */ inline void setAccepted(bool accepted = true) { _accepted = accepted; } - /** @brief Whether the event is accepted */ + /** @copydoc GlutApplication::InputEvent::isAccepted() */ inline bool isAccepted() { return _accepted; } #ifndef DOXYGEN_GENERATING_OUTPUT @@ -351,7 +359,7 @@ class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { inline Button button() const { return _button; } /** @brief Position */ - inline Math::Vector2 position() const { return _position; } + inline Vector2i position() const { return _position; } /** * @brief Modifiers @@ -361,10 +369,10 @@ class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - inline MouseEvent(Button button, const Math::Vector2& position): _button(button), _position(position), modifiersLoaded(false) {} + inline MouseEvent(Button button, const Vector2i& position): _button(button), _position(position), modifiersLoaded(false) {} const Button _button; - const Math::Vector2 _position; + const Vector2i _position; bool modifiersLoaded; Modifiers _modifiers; }; @@ -379,14 +387,14 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { public: /** @brief Position */ - inline Math::Vector2 position() const { return _position; } + inline Vector2i position() const { return _position; } /** * @brief Relative position * * Position relative to previous event. */ - inline Math::Vector2 relativePosition() const { return _relativePosition; } + inline Vector2i relativePosition() const { return _relativePosition; } /** * @brief Modifiers @@ -396,18 +404,20 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - inline MouseMoveEvent(const Math::Vector2& position, const Math::Vector2& relativePosition): _position(position), _relativePosition(relativePosition), modifiersLoaded(false) {} + inline MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition): _position(position), _relativePosition(relativePosition), modifiersLoaded(false) {} - const Math::Vector2 _position, _relativePosition; + const Vector2i _position, _relativePosition; bool modifiersLoaded; Modifiers _modifiers; }; /** @hideinitializer +@brief Entry point for SDL2-based applications @param className Class name -Can be used as equivalent to the following code to achieve better portability, -see @ref portability-applications for more information. +Can be used with Sdl2Application subclasses as equivalent to the following +code to achieve better portability, see @ref portability-applications for more +information. @code int main(int argc, char** argv) { className app(argc, argv); diff --git a/src/Platform/WindowlessGlxApplication.cpp b/src/Platform/WindowlessGlxApplication.cpp new file mode 100644 index 000000000..36370c686 --- /dev/null +++ b/src/Platform/WindowlessGlxApplication.cpp @@ -0,0 +1,99 @@ +/* + 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 "WindowlessGlxApplication.h" + +#include + +#include "Context.h" + +#define None 0L // redef Xlib nonsense + +namespace Magnum { namespace Platform { + +WindowlessGlxApplication::WindowlessGlxApplication(int&, char**) { + display = XOpenDisplay(nullptr); + + /* Check version */ + int major, minor; + glXQueryVersion(display, &major, &minor); + if(major == 1 && minor < 4) { + Error() << "WindowlessGlxApplication: GLX version 1.4 or greater is required."; + std::exit(1); + } + + /* Choose config */ + int configCount = 0; + static const int fbAttributes[] = { None }; + GLXFBConfig* configs = glXChooseFBConfig(display, DefaultScreen(display), fbAttributes, &configCount); + if(!configCount) { + Error() << "WindowlessGlxApplication: no supported framebuffer configuration found."; + std::exit(1); + } + + GLint contextAttributes[] = { + #ifdef MAGNUM_TARGET_GLES + GLX_CONTEXT_MAJOR_VERSION_ARB, 2, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, + #endif + 0 + }; + + /** @todo Use some extension wrangler for this, not GLEW, as it apparently needs context to create context, yo dawg wtf. */ + PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); + context = glXCreateContextAttribsARB(display, configs[0], 0, True, contextAttributes); + if(!context) { + Error() << "WindowlessGlxApplication: cannot create context."; + std::exit(1); + } + + /* Create pbuffer */ + int pbufferAttributes[] = { + GLX_PBUFFER_WIDTH, 32, + GLX_PBUFFER_HEIGHT, 32, + None + }; + pbuffer = glXCreatePbuffer(display, configs[0], pbufferAttributes); + + XFree(configs); + + /* Set OpenGL context as current */ + if(!glXMakeContextCurrent(display, pbuffer, pbuffer, context)) { + Error() << "WindowlessGlxApplication: cannot make context current"; + std::exit(1); + } + + /* Initialize extension wrangler */ + ExtensionWrangler::initialize(ExtensionWrangler::ExperimentalFeatures::Enable); + + c = new Context; +} + +WindowlessGlxApplication::~WindowlessGlxApplication() { + glXMakeCurrent(display, None, nullptr); + glXDestroyContext(display, context); +} + +}} diff --git a/src/Platform/WindowlessGlxApplication.h b/src/Platform/WindowlessGlxApplication.h new file mode 100644 index 000000000..71569af0a --- /dev/null +++ b/src/Platform/WindowlessGlxApplication.h @@ -0,0 +1,118 @@ +#ifndef Magnum_Platform_WindowlessGlxApplication_h +#define Magnum_Platform_WindowlessGlxApplication_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::Platform::WindowlessGlxApplication + */ + +#include "OpenGL.h" +#include +#include +#include +/* undef Xlib nonsense to avoid conflicts */ +#undef Complex +#undef None +#undef Always + +#include "Magnum.h" +#include "Platform/AbstractContextHandler.h" + +namespace Magnum { namespace Platform { + +/** +@brief Windowless GLX application + +@section WindowlessGlxApplication-usage Usage + +Place your code into exec(). The subclass can be then used directly in +`main()` -- see convenience macro MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN(). +@code +class MyApplication: public Magnum::Platform::WindowlessGlxApplication { + // implement required methods... +}; +MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN(MyApplication) +@endcode +*/ +class WindowlessGlxApplication { + public: + /** + * @brief Constructor + * @param argc Count of arguments of `main()` function + * @param argv Arguments of `main()` function + * + * Creates window with double-buffered OpenGL 3.2 core context or + * OpenGL ES 2.0 context, if targetting OpenGL ES. + */ + explicit WindowlessGlxApplication(int& argc, char** argv); + + ~WindowlessGlxApplication(); + + /** + * @brief Execute application + * @return Value for returning from `main()`. + */ + virtual int exec() = 0; + + private: + Display* display; + GLXContext context; + GLXPbuffer pbuffer; + + Context* c; +}; + +/** @hideinitializer +@brief Entry point for windowless GLX application +@param className Class name + +Can be used as equivalent to the following code to achieve better portability, +see @ref portability-applications for more information. +@code +int main(int argc, char** argv) { + className app(argc, argv); + return app.exec(); +} +@endcode +When no other application header is included this macro is also aliased to +`MAGNUM_APPLICATION_MAIN()`. +*/ +#define MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN(className) \ + int main(int argc, char** argv) { \ + className app(argc, argv); \ + return app.exec(); \ + } + +#ifndef DOXYGEN_GENERATING_OUTPUT +#ifndef MAGNUM_APPLICATION_MAIN +#define MAGNUM_APPLICATION_MAIN(className) MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN(className) +#else +#undef MAGNUM_APPLICATION_MAIN +#endif +#endif + +}} + +#endif diff --git a/src/Platform/XEglApplication.h b/src/Platform/XEglApplication.h index 7fdcfe1f4..b37ac0328 100644 --- a/src/Platform/XEglApplication.h +++ b/src/Platform/XEglApplication.h @@ -1,18 +1,27 @@ #ifndef Magnum_Platform_XEglApplication_h #define Magnum_Platform_XEglApplication_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -27,7 +36,8 @@ namespace Magnum { namespace Platform { /** @brief X/EGL application -Uses EglContextHandler. +Creates window with double-buffered OpenGL ES 2 context. Uses +EglContextHandler. @section XEglApplication-usage Usage @@ -49,10 +59,8 @@ class XEglApplication: public AbstractXApplication { * @param argv Arguments of `main()` function * @param title Window title * @param size Window size - * - * Creates window with double-buffered OpenGL ES 2 context. */ - inline XEglApplication(int& argc, char** argv, const std::string& title = "Magnum X/EGL application", const Math::Vector2& size = Math::Vector2(800, 600)): AbstractXApplication(new EglContextHandler, argc, argv, title, size) {} + inline explicit XEglApplication(int& argc, char** argv, const std::string& title = "Magnum X/EGL application", const Vector2i& size = Vector2i(800, 600)): AbstractXApplication(new EglContextHandler, argc, argv, title, size) {} }; }} diff --git a/src/Platform/magnum-info.cpp b/src/Platform/magnum-info.cpp new file mode 100644 index 000000000..7aa18126b --- /dev/null +++ b/src/Platform/magnum-info.cpp @@ -0,0 +1,125 @@ +/* + 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 "Context.h" +#include "Platform/WindowlessGlxApplication.h" + +namespace Magnum { + +class MagnumInfo: public Platform::WindowlessGlxApplication { + public: + MagnumInfo(int& argc, char** argv); + + inline int exec() override { return 0; } +}; + +MagnumInfo::MagnumInfo(int& argc, char** argv): WindowlessGlxApplication(argc, argv) { + Context* c = Context::current(); + + Debug() << ""; + Debug() << " +---------------------------------------------------------+"; + Debug() << " | Information about Magnum engine and OpenGL capabilities |"; + Debug() << " +---------------------------------------------------------+"; + Debug() << ""; + + Debug() << "Used application: Platform::WindowlessGlxApplication"; + { + Debug d; + d << "Compilation flags:"; + #ifdef CORRADE_GCC46_COMPATIBILITY + d << "CORRADE_GCC46_COMPATIBILITY"; + #endif + #ifdef MAGNUM_TARGET_GLES + d << "MAGNUM_TARGET_GLES"; + #endif + #ifdef MAGNUM_TARGET_GLES2 + d << "MAGNUM_TARGET_GLES2"; + #endif + #ifdef MAGNUM_TARGET_DESKTOP_GLES + d << "MAGNUM_TARGET_DESKTOP_GLES"; + #endif + #ifdef MAGNUM_TARGET_NACL + d << "MAGNUM_TARGET_NACL"; + #endif + #ifdef MAGNUM_USE_HARFBUZZ + d << "MAGNUM_USE_HARFBUZZ"; + #endif + } + Debug() << ""; + + Debug() << "Vendor:" << c->vendorString(); + Debug() << "Renderer:" << c->rendererString(); + Debug() << "OpenGL version:" << c->version() << '(' + c->versionString() + ')'; + Debug() << "GLSL version:" << c->version() << '(' + c->shadingLanguageVersionString() + ')'; + Debug() << ""; + + /* Get first future (not supported) version */ + std::vector versions{ + #ifndef MAGNUM_TARGET_GLES + Version::GL300, + Version::GL310, + Version::GL320, + Version::GL330, + Version::GL400, + Version::GL410, + Version::GL420, + Version::GL430, + #else + Version::GLES200, + Version::GLES300, + #endif + Version::None + }; + std::size_t future = 0; + while(versions[future] != Version::None && c->isVersionSupported(versions[future])) + ++future; + + /* Display supported OpenGL extensions from unsupported versions */ + for(std::size_t i = future; i != versions.size(); ++i) { + if(versions[i] != Version::None) + Debug() << versions[i] << "extension support:"; + else Debug() << "Vendor extension support:"; + + for(const auto& extension: Extension::extensions(versions[i])) { + std::string extensionName = extension.string(); + Debug d; + d << " " << extensionName << std::string(60-extensionName.size(), ' '); + if(c->isExtensionSupported(extension)) + d << "SUPPORTED"; + else if(c->isVersionSupported(extension.requiredVersion())) + d << " -"; + else + d << " ---"; + } + + Debug() << ""; + } +} + +} + +MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN(Magnum::MagnumInfo) diff --git a/src/Primitives/CMakeLists.txt b/src/Primitives/CMakeLists.txt index 10d36351e..a3c2efd95 100644 --- a/src/Primitives/CMakeLists.txt +++ b/src/Primitives/CMakeLists.txt @@ -1,28 +1,55 @@ +# +# 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. +# + set(MagnumPrimitives_SRCS Capsule.cpp + Crosshair.cpp Cube.cpp Cylinder.cpp Icosphere.cpp Plane.cpp Square.cpp UVSphere.cpp) + set(MagnumPrimitives_HEADERS Capsule.h + Crosshair.h Cube.h Cylinder.h Icosphere.h Plane.h Square.h - UVSphere.h) + UVSphere.h + + magnumPrimitivesVisibility.h) -add_library(MagnumPrimitives STATIC ${MagnumPrimitives_SRCS}) -set_target_properties(MagnumPrimitives PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") +add_library(MagnumPrimitives SHARED ${MagnumPrimitives_SRCS}) target_link_libraries(MagnumPrimitives Magnum) install(TARGETS MagnumPrimitives DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumPrimitives_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Primitives) if(BUILD_TESTS) - enable_testing() add_subdirectory(Test) endif() diff --git a/src/Primitives/Capsule.cpp b/src/Primitives/Capsule.cpp index c7d6568c7..fdab14a66 100644 --- a/src/Primitives/Capsule.cpp +++ b/src/Primitives/Capsule.cpp @@ -1,39 +1,46 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Capsule.h" -#include "Math/Constants.h" -#include "Math/Point3D.h" - -using namespace std; +#include "Math/Functions.h" +#include "Math/Vector3.h" namespace Magnum { namespace Primitives { -Capsule::Capsule(std::uint32_t hemisphereRings, std::uint32_t cylinderRings, std::uint32_t segments, GLfloat length, TextureCoords textureCoords): MeshData3D("", Mesh::Primitive::Triangles, new vector, {new vector()}, {new vector()}, textureCoords == TextureCoords::Generate ? vector*>{new vector()} : vector*>()), segments(segments), textureCoords(textureCoords) { +Capsule::Capsule(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords): MeshData3D(Mesh::Primitive::Triangles, new std::vector, {new std::vector()}, {new std::vector()}, textureCoords == TextureCoords::Generate ? std::vector*>{new std::vector()} : std::vector*>()), segments(segments), textureCoords(textureCoords) { CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 3, "Capsule must have at least one hemisphere ring, one cylinder ring and three segments", ); - GLfloat height = 2.0f+length; - GLfloat hemisphereTextureCoordsVIncrement = 1.0f/(hemisphereRings*height); - GLfloat hemisphereRingAngleIncrement = Constants::pi()/(2*hemisphereRings); + Float height = 2.0f+length; + Float hemisphereTextureCoordsVIncrement = 1.0f/(hemisphereRings*height); + Rad hemisphereRingAngleIncrement = Rad(Constants::pi())/(2*hemisphereRings); /* Bottom cap vertex */ capVertex(-height/2, -1.0f, 0.0f); /* Rings of bottom hemisphere */ - hemisphereVertexRings(hemisphereRings-1, -length/2, -Constants::pi()/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); + hemisphereVertexRings(hemisphereRings-1, -length/2, -Rad(Constants::pi())/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); /* Rings of cylinder */ cylinderVertexRings(cylinderRings+1, -length/2, length/cylinderRings, 1.0f/height, length/(cylinderRings*height)); @@ -50,9 +57,9 @@ Capsule::Capsule(std::uint32_t hemisphereRings, std::uint32_t cylinderRings, std topFaceRing(); } -Capsule::Capsule(uint32_t segments, TextureCoords textureCoords): MeshData3D("", Mesh::Primitive::Triangles, new std::vector, {new std::vector()}, {new std::vector()}, textureCoords == TextureCoords::Generate ? std::vector*>{new std::vector()} : std::vector*>()), segments(segments), textureCoords(textureCoords) {} +Capsule::Capsule(UnsignedInt segments, TextureCoords textureCoords): MeshData3D(Mesh::Primitive::Triangles, new std::vector, {new std::vector()}, {new std::vector()}, textureCoords == TextureCoords::Generate ? std::vector*>{new std::vector()} : std::vector*>()), segments(segments), textureCoords(textureCoords) {} -void Capsule::capVertex(GLfloat y, GLfloat normalY, GLfloat textureCoordsV) { +void Capsule::capVertex(Float y, Float normalY, Float textureCoordsV) { positions(0)->push_back({0.0f, y, 0.0f}); normals(0)->push_back({0.0f, normalY, 0.0f}); @@ -60,18 +67,18 @@ void Capsule::capVertex(GLfloat y, GLfloat normalY, GLfloat textureCoordsV) { textureCoords2D(0)->push_back({0.5, textureCoordsV}); } -void Capsule::hemisphereVertexRings(uint32_t count, GLfloat centerY, GLfloat startRingAngle, GLfloat ringAngleIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement) { - GLfloat segmentAngleIncrement = 2*Constants::pi()/segments; - GLfloat x, y, z; - for(uint32_t i = 0; i != count; ++i) { - GLfloat ringAngle = startRingAngle + i*ringAngleIncrement; - x = z = cos(ringAngle); - y = sin(ringAngle); +void Capsule::hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement) { + Rad segmentAngleIncrement = 2*Rad(Constants::pi())/segments; + Float x, y, z; + for(UnsignedInt i = 0; i != count; ++i) { + Rad ringAngle = startRingAngle + i*ringAngleIncrement; + x = z = Math::cos(ringAngle); + y = Math::sin(ringAngle); - for(uint32_t j = 0; j != segments; ++j) { - GLfloat segmentAngle = j*segmentAngleIncrement; - positions(0)->push_back({x*sin(segmentAngle), centerY+y, z*cos(segmentAngle)}); - normals(0)->push_back({x*sin(segmentAngle), y, z*cos(segmentAngle)}); + for(UnsignedInt j = 0; j != segments; ++j) { + Rad segmentAngle = j*segmentAngleIncrement; + positions(0)->push_back({x*Math::sin(segmentAngle), centerY+y, z*Math::cos(segmentAngle)}); + normals(0)->push_back({x*Math::sin(segmentAngle), y, z*Math::cos(segmentAngle)}); if(textureCoords == TextureCoords::Generate) textureCoords2D(0)->push_back({j*1.0f/segments, startTextureCoordsV + i*textureCoordsVIncrement}); @@ -86,13 +93,13 @@ void Capsule::hemisphereVertexRings(uint32_t count, GLfloat centerY, GLfloat sta } } -void Capsule::cylinderVertexRings(uint32_t count, GLfloat startY, GLfloat yIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement) { - GLfloat segmentAngleIncrement = 2*Constants::pi()/segments; - for(uint32_t i = 0; i != count; ++i) { - for(uint32_t j = 0; j != segments; ++j) { - GLfloat segmentAngle = j*segmentAngleIncrement; - positions(0)->push_back({sin(segmentAngle), startY, cos(segmentAngle)}); - normals(0)->push_back({sin(segmentAngle), 0.0f, cos(segmentAngle)}); +void Capsule::cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement) { + Rad segmentAngleIncrement = 2*Rad(Constants::pi())/segments; + for(UnsignedInt i = 0; i != count; ++i) { + for(UnsignedInt j = 0; j != segments; ++j) { + Rad segmentAngle = j*segmentAngleIncrement; + positions(0)->push_back({Math::sin(segmentAngle), startY, Math::cos(segmentAngle)}); + normals(0)->push_back({Math::sin(segmentAngle), 0.0f, Math::cos(segmentAngle)}); if(textureCoords == TextureCoords::Generate) textureCoords2D(0)->push_back({j*1.0f/segments, startTextureCoordsV + i*textureCoordsVIncrement}); @@ -110,7 +117,7 @@ void Capsule::cylinderVertexRings(uint32_t count, GLfloat startY, GLfloat yIncre } void Capsule::bottomFaceRing() { - for(uint32_t j = 0; j != segments; ++j) { + for(UnsignedInt j = 0; j != segments; ++j) { /* Bottom vertex */ indices()->push_back(0); @@ -123,16 +130,16 @@ void Capsule::bottomFaceRing() { } } -void Capsule::faceRings(uint32_t count, uint32_t offset) { - uint32_t vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0); +void Capsule::faceRings(UnsignedInt count, UnsignedInt offset) { + UnsignedInt vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0); - for(uint32_t i = 0; i != count; ++i) { - for(uint32_t j = 0; j != segments; ++j) { - uint32_t bottomLeft = i*vertexSegments+j+offset; - uint32_t bottomRight = ((j != segments-1 || textureCoords == TextureCoords::Generate) ? + for(UnsignedInt i = 0; i != count; ++i) { + for(UnsignedInt j = 0; j != segments; ++j) { + UnsignedInt bottomLeft = i*vertexSegments+j+offset; + UnsignedInt bottomRight = ((j != segments-1 || textureCoords == TextureCoords::Generate) ? i*vertexSegments+j+1+offset : i*segments+offset); - uint32_t topLeft = bottomLeft+vertexSegments; - uint32_t topRight = bottomRight+vertexSegments; + UnsignedInt topLeft = bottomLeft+vertexSegments; + UnsignedInt topRight = bottomRight+vertexSegments; indices()->push_back(bottomLeft); indices()->push_back(bottomRight); @@ -145,9 +152,9 @@ void Capsule::faceRings(uint32_t count, uint32_t offset) { } void Capsule::topFaceRing() { - uint32_t vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0); + UnsignedInt vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0); - for(uint32_t j = 0; j != segments; ++j) { + for(UnsignedInt j = 0; j != segments; ++j) { /* Bottom left vertex */ indices()->push_back(normals(0)->size()-vertexSegments+j-1); diff --git a/src/Primitives/Capsule.h b/src/Primitives/Capsule.h index 1d9e118a6..00111ae74 100644 --- a/src/Primitives/Capsule.h +++ b/src/Primitives/Capsule.h @@ -1,18 +1,27 @@ #ifndef Magnum_Primitives_Capsule_h #define Magnum_Primitives_Capsule_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,12 +30,14 @@ #include "Trade/MeshData3D.h" +#include "Primitives/magnumPrimitivesVisibility.h" + namespace Magnum { namespace Primitives { /** @brief 3D capsule primitive -%Cylinder along Y axis with hemispheres instead of caps. Indexed triangle mesh +%Cylinder along Y axis with hemispheres instead of caps. Indexed @ref Mesh::Primitive "Triangles" with normals and optional 2D texture coordinates. */ class Capsule: public Trade::MeshData3D { @@ -53,19 +64,19 @@ class Capsule: public Trade::MeshData3D { * If texture coordinates are generated, vertices of one segment are * duplicated for texture wrapping. */ - Capsule(std::uint32_t hemisphereRings, std::uint32_t cylinderRings, std::uint32_t segments, GLfloat length, TextureCoords textureCoords = TextureCoords::DontGenerate); + explicit MAGNUM_PRIMITIVES_EXPORT Capsule(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords = TextureCoords::DontGenerate); private: - Capsule(std::uint32_t segments, TextureCoords textureCoords); + Capsule(UnsignedInt segments, TextureCoords textureCoords); - void capVertex(GLfloat y, GLfloat normalY, GLfloat textureCoordsV); - void hemisphereVertexRings(std::uint32_t count, GLfloat centerY, GLfloat startRingAngle, GLfloat ringAngleIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement); - void cylinderVertexRings(std::uint32_t count, GLfloat startY, GLfloat yIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement); + void capVertex(Float y, Float normalY, Float textureCoordsV); + void hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement); + void cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement); void bottomFaceRing(); - void faceRings(std::uint32_t count, std::uint32_t offset = 1); + void faceRings(UnsignedInt count, UnsignedInt offset = 1); void topFaceRing(); - std::uint32_t segments; + UnsignedInt segments; TextureCoords textureCoords; }; diff --git a/src/Primitives/Crosshair.cpp b/src/Primitives/Crosshair.cpp new file mode 100644 index 000000000..c20fe61fe --- /dev/null +++ b/src/Primitives/Crosshair.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 "Crosshair.h" + +#include "Math/Vector3.h" +#include "Trade/MeshData2D.h" +#include "Trade/MeshData3D.h" + +namespace Magnum { namespace Primitives { + +Trade::MeshData2D Crosshair2D::wireframe() { + return Trade::MeshData2D(Mesh::Primitive::Lines, nullptr, {new std::vector{ + {-1.0f, 0.0f}, {1.0f, 0.0f}, + { 0.0f, -1.0f}, {0.0f, 1.0f} + }}, {}); +} + +Trade::MeshData3D Crosshair3D::wireframe() { + return Trade::MeshData3D(Mesh::Primitive::Lines, nullptr, {new std::vector{ + {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, + { 0.0f, -1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, + { 0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f} + }}, {}, {}); +} + +}} diff --git a/src/Primitives/Crosshair.h b/src/Primitives/Crosshair.h new file mode 100644 index 000000000..b8d1a2783 --- /dev/null +++ b/src/Primitives/Crosshair.h @@ -0,0 +1,67 @@ +#ifndef Magnum_Primitives_Cube_h +#define Magnum_Primitives_Cube_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::Primitives::Crosshair2D, Magnum::Primitives::Crosshair3D + */ + +#include "Trade/Trade.h" + +#include "Primitives/magnumPrimitivesVisibility.h" + +namespace Magnum { namespace Primitives { + +/** +@brief 2D crosshair primitive + +2x2 wireframe crosshair (two crossed lines), non-indexed +@ref Mesh::Primitive "Lines". +*/ +class MAGNUM_PRIMITIVES_EXPORT Crosshair2D { + public: + /** @brief Wireframe crosshair */ + static Trade::MeshData2D wireframe(); + + Crosshair2D() = delete; +}; + +/** +@brief 3D crosshair primitive + +2x2x2 wireframe crosshair (three crossed lines), non-indexed +@ref Mesh::Primitive "Lines". +*/ +class MAGNUM_PRIMITIVES_EXPORT Crosshair3D { + public: + /** @brief Wireframe crosshair */ + static Trade::MeshData3D wireframe(); + + Crosshair3D() = delete; +}; + +}} + +#endif diff --git a/src/Primitives/Cube.cpp b/src/Primitives/Cube.cpp index 12d92139f..eb369ce23 100644 --- a/src/Primitives/Cube.cpp +++ b/src/Primitives/Cube.cpp @@ -1,111 +1,122 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Cube.h" -#include "Math/Point3D.h" - -using namespace std; +#include "Math/Vector3.h" +#include "Trade/MeshData3D.h" namespace Magnum { namespace Primitives { -Cube::Cube(): MeshData3D("", Mesh::Primitive::Triangles, nullptr, {new vector{ - {-1.0f, -1.0f, 1.0f}, - { 1.0f, -1.0f, 1.0f}, - { 1.0f, 1.0f, 1.0f}, /* +Z */ - {-1.0f, -1.0f, 1.0f}, - { 1.0f, 1.0f, 1.0f}, - {-1.0f, 1.0f, 1.0f}, - - { 1.0f, -1.0f, 1.0f}, - { 1.0f, -1.0f, -1.0f}, - { 1.0f, 1.0f, -1.0f}, /* +X */ - { 1.0f, -1.0f, 1.0f}, - { 1.0f, 1.0f, -1.0f}, - { 1.0f, 1.0f, 1.0f}, - - {-1.0f, 1.0f, 1.0f}, - { 1.0f, 1.0f, 1.0f}, - { 1.0f, 1.0f, -1.0f}, /* +Y */ - {-1.0f, 1.0f, 1.0f}, - { 1.0f, 1.0f, -1.0f}, - {-1.0f, 1.0f, -1.0f}, - - { 1.0f, -1.0f, -1.0f}, - {-1.0f, -1.0f, -1.0f}, - {-1.0f, 1.0f, -1.0f}, /* -Z */ - { 1.0f, -1.0f, -1.0f}, - {-1.0f, 1.0f, -1.0f}, - { 1.0f, 1.0f, -1.0f}, - - {-1.0f, -1.0f, -1.0f}, - { 1.0f, -1.0f, -1.0f}, - { 1.0f, -1.0f, 1.0f}, /* -Y */ - {-1.0f, -1.0f, -1.0f}, - { 1.0f, -1.0f, 1.0f}, - {-1.0f, -1.0f, 1.0f}, - - {-1.0f, -1.0f, -1.0f}, - {-1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, 1.0f}, /* -X */ - {-1.0f, -1.0f, -1.0f}, - {-1.0f, 1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f} -}}, {new vector{ - { 0.0f, 0.0f, 1.0f}, - { 0.0f, 0.0f, 1.0f}, - { 0.0f, 0.0f, 1.0f}, /* +Z */ - { 0.0f, 0.0f, 1.0f}, - { 0.0f, 0.0f, 1.0f}, - { 0.0f, 0.0f, 1.0f}, - - { 1.0f, 0.0f, 0.0f}, - { 1.0f, 0.0f, 0.0f}, - { 1.0f, 0.0f, 0.0f}, /* +X */ - { 1.0f, 0.0f, 0.0f}, - { 1.0f, 0.0f, 0.0f}, - { 1.0f, 0.0f, 0.0f}, - - { 0.0f, 1.0f, 0.0f}, - { 0.0f, 1.0f, 0.0f}, - { 0.0f, 1.0f, 0.0f}, /* +Y */ - { 0.0f, 1.0f, 0.0f}, - { 0.0f, 1.0f, 0.0f}, - { 0.0f, 1.0f, 0.0f}, - - { 0.0f, 0.0f, -1.0f}, - { 0.0f, 0.0f, -1.0f}, - { 0.0f, 0.0f, -1.0f}, /* -Z */ - { 0.0f, 0.0f, -1.0f}, - { 0.0f, 0.0f, -1.0f}, - { 0.0f, 0.0f, -1.0f}, - - { 0.0f, -1.0f, 0.0f}, - { 0.0f, -1.0f, 0.0f}, - { 0.0f, -1.0f, 0.0f}, /* -Y */ - { 0.0f, -1.0f, 0.0f}, - { 0.0f, -1.0f, 0.0f}, - { 0.0f, -1.0f, 0.0f}, - - {-1.0f, 0.0f, 0.0f}, - {-1.0f, 0.0f, 0.0f}, - {-1.0f, 0.0f, 0.0f}, /* -X */ - {-1.0f, 0.0f, 0.0f}, - {-1.0f, 0.0f, 0.0f}, - {-1.0f, 0.0f, 0.0f} -}}, {}) { +Trade::MeshData3D Cube::solid() { + return Trade::MeshData3D(Mesh::Primitive::Triangles, new std::vector{ + 0, 1, 2, 0, 2, 3, /* +Z */ + 4, 5, 6, 4, 6, 7, /* +X */ + 8, 9, 10, 8, 10, 11, /* +Y */ + 12, 13, 14, 12, 14, 15, /* -Z */ + 16, 17, 18, 16, 18, 19, /* -Y */ + 20, 21, 22, 20, 22, 23 /* -X */ + }, {new std::vector{ + {-1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, /* +Z */ + {-1.0f, 1.0f, 1.0f}, + + { 1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, 1.0f, -1.0f}, /* +X */ + { 1.0f, 1.0f, 1.0f}, + + {-1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, -1.0f}, /* +Y */ + {-1.0f, 1.0f, -1.0f}, + + { 1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, /* -Z */ + { 1.0f, 1.0f, -1.0f}, + + {-1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, 1.0f}, /* -Y */ + {-1.0f, -1.0f, 1.0f}, + + {-1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, 1.0f}, /* -X */ + {-1.0f, 1.0f, -1.0f} + }}, {new std::vector{ + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, /* +Z */ + { 0.0f, 0.0f, 1.0f}, + + { 1.0f, 0.0f, 0.0f}, + { 1.0f, 0.0f, 0.0f}, + { 1.0f, 0.0f, 0.0f}, /* +X */ + { 1.0f, 0.0f, 0.0f}, + + { 0.0f, 1.0f, 0.0f}, + { 0.0f, 1.0f, 0.0f}, + { 0.0f, 1.0f, 0.0f}, /* +Y */ + { 0.0f, 1.0f, 0.0f}, + + { 0.0f, 0.0f, -1.0f}, + { 0.0f, 0.0f, -1.0f}, + { 0.0f, 0.0f, -1.0f}, /* -Z */ + { 0.0f, 0.0f, -1.0f}, + + { 0.0f, -1.0f, 0.0f}, + { 0.0f, -1.0f, 0.0f}, + { 0.0f, -1.0f, 0.0f}, /* -Y */ + { 0.0f, -1.0f, 0.0f}, + + {-1.0f, 0.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, /* -X */ + {-1.0f, 0.0f, 0.0f} + }}, {}); +} + +Trade::MeshData3D Cube::wireframe() { + return Trade::MeshData3D(Mesh::Primitive::Lines, new std::vector{ + 0, 1, 1, 2, 2, 3, 3, 0, /* +Z */ + 4, 5, 5, 6, 6, 7, 7, 4, /* -Z */ + 1, 5, 2, 6, /* +X */ + 0, 4, 3, 7 /* -X */ + }, {new std::vector{ + {-1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + {-1.0f, 1.0f, 1.0f}, + + {-1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f} + }}, {}, {}); } }} diff --git a/src/Primitives/Cube.h b/src/Primitives/Cube.h index cf390389f..52cdee061 100644 --- a/src/Primitives/Cube.h +++ b/src/Primitives/Cube.h @@ -1,37 +1,61 @@ #ifndef Magnum_Primitives_Cube_h #define Magnum_Primitives_Cube_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Primitives::Cube */ -#include "Trade/MeshData3D.h" +#include "Trade/Trade.h" + +#include "Primitives/magnumPrimitivesVisibility.h" namespace Magnum { namespace Primitives { /** @brief 3D cube primitive -2x2x2 cube. Non-indexed triangle mesh with flat normals. +2x2x2 cube. */ -class Cube: public Trade::MeshData3D { +class MAGNUM_PRIMITIVES_EXPORT Cube { public: - /** @brief Constructor */ - Cube(); + /** + * @brief Solid cube + * + * Indexed @ref Mesh::Primitive "Triangles" with flat normals. + */ + static Trade::MeshData3D solid(); + + /** + * @brief Wireframe cube + * + * Indexed @ref Mesh::Primitive "Lines". + */ + static Trade::MeshData3D wireframe(); + + Cube() = delete; }; }} diff --git a/src/Primitives/Cylinder.cpp b/src/Primitives/Cylinder.cpp index 0d8460107..1a924b0d3 100644 --- a/src/Primitives/Cylinder.cpp +++ b/src/Primitives/Cylinder.cpp @@ -1,31 +1,39 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Cylinder.h" -#include "Math/Constants.h" - -using namespace std; +#include "Math/Functions.h" +#include "Math/Vector3.h" namespace Magnum { namespace Primitives { -Cylinder::Cylinder(uint32_t rings, uint32_t segments, GLfloat length, Flags flags): Capsule(segments, flags & Flag::GenerateTextureCoords ? TextureCoords::Generate : TextureCoords::DontGenerate) { +Cylinder::Cylinder(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags): Capsule(segments, flags & Flag::GenerateTextureCoords ? TextureCoords::Generate : TextureCoords::DontGenerate) { CORRADE_ASSERT(rings >= 1 && segments >= 3, "Cylinder must have at least one ring and three segments", ); - GLfloat y = length*0.5f; - GLfloat textureCoordsV = flags & Flag::CapEnds ? 1.0f/(length+2.0f) : 0.0f; + Float y = length*0.5f; + Float textureCoordsV = flags & Flag::CapEnds ? 1.0f/(length+2.0f) : 0.0f; /* Bottom cap */ if(flags & Flag::CapEnds) { @@ -48,12 +56,12 @@ Cylinder::Cylinder(uint32_t rings, uint32_t segments, GLfloat length, Flags flag if(flags & Flag::CapEnds) topFaceRing(); } -void Cylinder::capVertexRing(GLfloat y, GLfloat textureCoordsV, const Vector3& normal) { - GLfloat segmentAngleIncrement = 2*Constants::pi()/segments; +void Cylinder::capVertexRing(Float y, Float textureCoordsV, const Vector3& normal) { + Rad segmentAngleIncrement = 2*Rad(Constants::pi())/segments; - for(uint32_t i = 0; i != segments; ++i) { - GLfloat segmentAngle = i*segmentAngleIncrement; - positions(0)->push_back({sin(segmentAngle), y, cos(segmentAngle)}); + for(UnsignedInt i = 0; i != segments; ++i) { + Rad segmentAngle = i*segmentAngleIncrement; + positions(0)->push_back({Math::sin(segmentAngle), y, Math::cos(segmentAngle)}); normals(0)->push_back(normal); if(textureCoords == TextureCoords::Generate) diff --git a/src/Primitives/Cylinder.h b/src/Primitives/Cylinder.h index 29da7a73b..eac16de9d 100644 --- a/src/Primitives/Cylinder.h +++ b/src/Primitives/Cylinder.h @@ -1,35 +1,46 @@ #ifndef Magnum_Primitives_Cylinder_h #define Magnum_Primitives_Cylinder_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Primitives::UVSphere + * @brief Class Magnum::Primitives::Cylinder */ #include #include "Primitives/Capsule.h" +#include "Primitives/magnumPrimitivesVisibility.h" + namespace Magnum { namespace Primitives { /** @brief 3D cylinder primitive -Indexed triangle mesh with normals, optional 2D texture coordinates and -optional capped ends. +Indexed @ref Mesh::Primitive "Triangles" with normals, optional 2D texture +coordinates and optional capped ends. */ class Cylinder: public Capsule { public: @@ -58,10 +69,10 @@ class Cylinder: public Capsule { * If texture coordinates are generated, vertices of one segment are * duplicated for texture wrapping. */ - Cylinder(std::uint32_t rings, std::uint32_t segments, GLfloat length, Flags flags = Flags()); + explicit MAGNUM_PRIMITIVES_EXPORT Cylinder(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags = Flags()); private: - void capVertexRing(GLfloat y, GLfloat textureCoordsV, const Vector3& normal); + void capVertexRing(Float y, Float textureCoordsV, const Vector3& normal); }; CORRADE_ENUMSET_OPERATORS(Cylinder::Flags) diff --git a/src/Primitives/Icosphere.cpp b/src/Primitives/Icosphere.cpp index 379365e18..b5ddc86ea 100644 --- a/src/Primitives/Icosphere.cpp +++ b/src/Primitives/Icosphere.cpp @@ -1,27 +1,34 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Icosphere.h" -#include "Math/Vector4.h" - -using namespace std; +#include "Math/Vector3.h" namespace Magnum { namespace Primitives { -Icosphere<0>::Icosphere(): MeshData3D("", Mesh::Primitive::Triangles, new vector{ +Icosphere<0>::Icosphere(): MeshData3D(Mesh::Primitive::Triangles, new std::vector{ 1, 2, 6, 1, 7, 2, 3, 4, 5, @@ -42,19 +49,19 @@ Icosphere<0>::Icosphere(): MeshData3D("", Mesh::Primitive::Triangles, new vector 7, 1, 0, 3, 9, 8, 4, 8, 0 -}, {new vector}, {new vector{ - Vector3(0, -0.525731f, 0.850651f), - Vector3(0.850651f, 0, 0.525731f), - Vector3(0.850651f, 0, -0.525731f), - Vector3(-0.850651f, 0, -0.525731f), - Vector3(-0.850651f, 0, 0.525731f), - Vector3(-0.525731f, 0.850651f, 0), - Vector3(0.525731f, 0.850651f, 0), - Vector3(0.525731f, -0.850651f, 0), - Vector3(-0.525731f, -0.850651f, 0), - Vector3(0, -0.525731f, -0.850651f), - Vector3(0, 0.525731f, -0.850651f), - Vector3(0, 0.525731f, 0.850651f) +}, {new std::vector}, {new std::vector{ + {0.0f, -0.525731f, 0.850651f}, + {0.850651f, 0.0f, 0.525731f}, + {0.850651f, 0.0f, -0.525731f}, + {-0.850651f, 0.0f, -0.525731f}, + {-0.850651f, 0.0f, 0.525731f}, + {-0.525731f, 0.850651f, 0.0f}, + {0.525731f, 0.850651f, 0.0f}, + {0.525731f, -0.850651f, 0.0f}, + {-0.525731f, -0.850651f, 0.0f}, + {0.0f, -0.525731f, -0.850651f}, + {0.0f, 0.525731f, -0.850651f}, + {0.0f, 0.525731f, 0.850651f} }}, {}) { positions(0)->assign(normals(0)->begin(), normals(0)->end()); } diff --git a/src/Primitives/Icosphere.h b/src/Primitives/Icosphere.h index a9e050f68..76a8197a4 100644 --- a/src/Primitives/Icosphere.h +++ b/src/Primitives/Icosphere.h @@ -1,18 +1,27 @@ #ifndef Magnum_Primitives_Icosphere_h #define Magnum_Primitives_Icosphere_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -24,28 +33,31 @@ #include "MeshTools/Clean.h" #include "Trade/MeshData3D.h" +#include "Primitives/magnumPrimitivesVisibility.h" + namespace Magnum { namespace Primitives { -template class Icosphere; +/** @todoc Remove `ifndef` when Doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_PRIMITIVES_EXPORT Icosphere; +#endif /** @brief 3D icosphere primitive with zero subdivisions -Indexed triangle mesh with normals. -@todo Use own computed (and more precise) icosahedron data, not these stolen -from Blender. +Indexed @ref Mesh::Primitive "Triangles" with normals. */ template<> class Icosphere<0>: public Trade::MeshData3D { public: /** @brief Constructor */ - Icosphere(); + explicit Icosphere(); }; /** @brief 3D icosphere primitive @tparam subdivisions Number of subdivisions -Indexed triangle mesh with normals. +Indexed @ref Mesh::Primitive "Triangles" with normals. */ #ifndef DOXYGEN_GENERATING_OUTPUT template class Icosphere: public Icosphere<0> { @@ -54,7 +66,7 @@ template class Icosphere { #endif public: /** @brief Constructor */ - Icosphere() { + explicit Icosphere() { for(std::size_t i = 0; i != subdivisions; ++i) MeshTools::subdivide(*indices(), *normals(0), interpolator); diff --git a/src/Primitives/Plane.cpp b/src/Primitives/Plane.cpp index 99627bab1..3ff7488a5 100644 --- a/src/Primitives/Plane.cpp +++ b/src/Primitives/Plane.cpp @@ -1,36 +1,55 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Plane.h" -#include "Math/Point3D.h" - -using namespace std; +#include "Math/Vector3.h" +#include "Trade/MeshData3D.h" namespace Magnum { namespace Primitives { -Plane::Plane(): MeshData3D("", Mesh::Primitive::TriangleStrip, nullptr, {new vector{ - {1.0f, -1.0f, 0.0f}, - {1.0f, 1.0f, 0.0f}, - {-1.0f, -1.0f, 0.0f}, - {-1.0f, 1.0f, 0.0f} -}}, {new vector{ - {0.0f, 0.0f, 1.0f}, - {0.0f, 0.0f, 1.0f}, - {0.0f, 0.0f, 1.0f}, - {0.0f, 0.0f, 1.0f} -}}, {}) {} +Trade::MeshData3D Plane::solid() { + return Trade::MeshData3D(Mesh::Primitive::TriangleStrip, nullptr, {new std::vector{ + {1.0f, -1.0f, 0.0f}, + {1.0f, 1.0f, 0.0f}, + {-1.0f, -1.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f} + }}, {new std::vector{ + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f} + }}, {}); +} + +Trade::MeshData3D Plane::wireframe() { + return Trade::MeshData3D(Mesh::Primitive::LineLoop, nullptr, {new std::vector{ + {-1.0f, -1.0f, 0.0f}, + {1.0f, -1.0f, 0.0f}, + {1.0f, 1.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f} + }}, {}, {}); +} }} diff --git a/src/Primitives/Plane.h b/src/Primitives/Plane.h index 1cdb6f104..163d2cdf8 100644 --- a/src/Primitives/Plane.h +++ b/src/Primitives/Plane.h @@ -1,37 +1,62 @@ #ifndef Magnum_Primitives_Plane_h #define Magnum_Primitives_Plane_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Primitives::Plane */ -#include "Trade/MeshData3D.h" +#include "Trade/Trade.h" + +#include "Primitives/magnumPrimitivesVisibility.h" namespace Magnum { namespace Primitives { /** @brief 3D plane primitive -2x2 plane as triangle strip, non-indexed with normals in positive Z direction. +2x2 plane. */ -class Plane: public Trade::MeshData3D { +class MAGNUM_PRIMITIVES_EXPORT Plane { public: - /** @brief Constructor */ - Plane(); + /** + * @brief Solid plane + * + * Non-indexed @ref Mesh::Primitive "TriangleStrip" with normals in + * positive Z direction. + */ + static Trade::MeshData3D solid(); + + /** + * @brief Wireframe plane + * + * Non-indexed @ref Mesh::Primitive "LineLoop". + */ + static Trade::MeshData3D wireframe(); + + Plane() = delete; }; }} diff --git a/src/Primitives/Square.cpp b/src/Primitives/Square.cpp index 1855bcd6e..f17646966 100644 --- a/src/Primitives/Square.cpp +++ b/src/Primitives/Square.cpp @@ -1,31 +1,50 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Square.h" -#include "Math/Point2D.h" - -using namespace std; +#include "Math/Vector2.h" +#include "Trade/MeshData2D.h" namespace Magnum { namespace Primitives { -Square::Square(): MeshData2D("", Mesh::Primitive::TriangleStrip, nullptr, {new vector{ - {1.0f, -1.0f}, - {1.0f, 1.0f}, - {-1.0f, -1.0f}, - {-1.0f, 1.0f} -}}, {}) {} +Trade::MeshData2D Square::solid() { + return Trade::MeshData2D(Mesh::Primitive::TriangleStrip, nullptr, {new std::vector{ + {1.0f, -1.0f}, + {1.0f, 1.0f}, + {-1.0f, -1.0f}, + {-1.0f, 1.0f} + }}, {}); +} + +Trade::MeshData2D Square::wireframe() { + return Trade::MeshData2D(Mesh::Primitive::LineLoop, nullptr, {new std::vector{ + {-1.0f, -1.0f}, + {1.0f, -1.0f}, + {1.0f, 1.0f}, + {-1.0f, 1.0f} + }}, {}); +} }} diff --git a/src/Primitives/Square.h b/src/Primitives/Square.h index d83520580..5ba34f1ec 100644 --- a/src/Primitives/Square.h +++ b/src/Primitives/Square.h @@ -1,37 +1,61 @@ #ifndef Magnum_Primitives_Square_h #define Magnum_Primitives_Square_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Primitives::Square */ -#include "Trade/MeshData2D.h" +#include "Trade/Trade.h" + +#include "Primitives/magnumPrimitivesVisibility.h" namespace Magnum { namespace Primitives { /** @brief 2D square primitive -2x2 square as triangle strip, non-indexed. +2x2 square. */ -class Square: public Trade::MeshData2D { +class MAGNUM_PRIMITIVES_EXPORT Square { public: - /** @brief Constructor */ - Square(); + /** + * @brief Solid square + * + * Non-indexed @ref Mesh::Primitive "TriangleStrip". + */ + static Trade::MeshData2D solid(); + + /** + * @brief Wireframe square + * + * Non-indexed @ref Mesh::Primitive "LineLoop." + */ + static Trade::MeshData2D wireframe(); + + Square() = delete; }; }} diff --git a/src/Primitives/Test/CMakeLists.txt b/src/Primitives/Test/CMakeLists.txt index c8374ccd0..987d1e01e 100644 --- a/src/Primitives/Test/CMakeLists.txt +++ b/src/Primitives/Test/CMakeLists.txt @@ -1,3 +1,27 @@ -corrade_add_test2(PrimitivesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPrimitives) -corrade_add_test2(PrimitivesUVSphereTest UVSphereTest.cpp LIBRARIES MagnumPrimitives) -corrade_add_test2(PrimitivesCylinderTest CylinderTest.cpp LIBRARIES MagnumPrimitives) +# +# 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. +# + +corrade_add_test(PrimitivesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPrimitives) +corrade_add_test(PrimitivesUVSphereTest UVSphereTest.cpp LIBRARIES MagnumPrimitives) +corrade_add_test(PrimitivesCylinderTest CylinderTest.cpp LIBRARIES MagnumPrimitives) diff --git a/src/Primitives/Test/CapsuleTest.cpp b/src/Primitives/Test/CapsuleTest.cpp index 1f6fb6183..3d74a2680 100644 --- a/src/Primitives/Test/CapsuleTest.cpp +++ b/src/Primitives/Test/CapsuleTest.cpp @@ -1,44 +1,57 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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. */ /* Less precision */ #define FLOAT_EQUALITY_PRECISION 1.0e-5 -#include "CapsuleTest.h" - +#include #include -#include "Math/Point3D.h" +#include "Math/Vector3.h" #include "Primitives/Capsule.h" -using namespace std; using Corrade::TestSuite::Compare::Container; -CORRADE_TEST_MAIN(Magnum::Primitives::Test::CapsuleTest) - namespace Magnum { namespace Primitives { namespace Test { +class CapsuleTest: public Corrade::TestSuite::Tester { + public: + CapsuleTest(); + + void withoutTextureCoords(); + void withTextureCoords(); +}; + CapsuleTest::CapsuleTest() { - addTests(&CapsuleTest::withoutTextureCoords, - &CapsuleTest::withTextureCoords); + addTests({&CapsuleTest::withoutTextureCoords, + &CapsuleTest::withTextureCoords}); } void CapsuleTest::withoutTextureCoords() { Capsule capsule(2, 2, 3, 1.0f); - CORRADE_COMPARE_AS(*capsule.positions(0), (vector{ + CORRADE_COMPARE_AS(*capsule.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, {0.0f, -1.20711f, 0.707107f}, @@ -64,7 +77,7 @@ void CapsuleTest::withoutTextureCoords() { {0.0f, 1.5f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*capsule.normals(0), (vector{ + CORRADE_COMPARE_AS(*capsule.normals(0), (std::vector{ {0.0f, -1.0f, 0.0f}, {0.0f, -0.707107f, 0.707107f}, @@ -90,7 +103,7 @@ void CapsuleTest::withoutTextureCoords() { {0.0f, 1.0f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*capsule.indices(), (vector{ + CORRADE_COMPARE_AS(*capsule.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, 8, 4, 8, 7, 5, 6, 9, 5, 9, 8, 6, 4, 7, 6, 7, 9, @@ -103,7 +116,7 @@ void CapsuleTest::withoutTextureCoords() { void CapsuleTest::withTextureCoords() { Capsule capsule(2, 2, 3, 1.0f, Capsule::TextureCoords::Generate); - CORRADE_COMPARE_AS(*capsule.positions(0), (vector{ + CORRADE_COMPARE_AS(*capsule.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, {0.0f, -1.20711f, 0.707107f}, @@ -134,7 +147,7 @@ void CapsuleTest::withTextureCoords() { {0.0f, 1.5f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*capsule.textureCoords2D(0), (vector{ + CORRADE_COMPARE_AS(*capsule.textureCoords2D(0), (std::vector{ {0.5f, 0.0f}, {0.0f, 0.166667f}, @@ -165,7 +178,7 @@ void CapsuleTest::withTextureCoords() { {0.5f, 1.0f} }), Container); - CORRADE_COMPARE_AS(*capsule.indices(), (vector{ + CORRADE_COMPARE_AS(*capsule.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, @@ -176,3 +189,5 @@ void CapsuleTest::withTextureCoords() { } }}} + +CORRADE_TEST_MAIN(Magnum::Primitives::Test::CapsuleTest) diff --git a/src/Primitives/Test/CapsuleTest.h b/src/Primitives/Test/CapsuleTest.h deleted file mode 100644 index e8bc1f495..000000000 --- a/src/Primitives/Test/CapsuleTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Primitives_Test_CapsuleTest_h -#define Magnum_Primitives_Test_CapsuleTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Primitives { namespace Test { - -class CapsuleTest: public Corrade::TestSuite::Tester { - public: - CapsuleTest(); - - void withoutTextureCoords(); - void withTextureCoords(); -}; - -}}} - -#endif diff --git a/src/Primitives/Test/CylinderTest.cpp b/src/Primitives/Test/CylinderTest.cpp index f7f919cae..938162fab 100644 --- a/src/Primitives/Test/CylinderTest.cpp +++ b/src/Primitives/Test/CylinderTest.cpp @@ -1,41 +1,54 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CylinderTest.h" - +#include #include -#include "Math/Point3D.h" +#include "Math/Vector3.h" #include "Primitives/Cylinder.h" -using namespace std; using Corrade::TestSuite::Compare::Container; -CORRADE_TEST_MAIN(Magnum::Primitives::Test::CylinderTest) - namespace Magnum { namespace Primitives { namespace Test { +class CylinderTest: public Corrade::TestSuite::Tester { + public: + CylinderTest(); + + void withoutAnything(); + void withTextureCoordsAndCaps(); +}; + CylinderTest::CylinderTest() { - addTests(&CylinderTest::withoutAnything, - &CylinderTest::withTextureCoordsAndCaps); + addTests({&CylinderTest::withoutAnything, + &CylinderTest::withTextureCoordsAndCaps}); } void CylinderTest::withoutAnything() { Cylinder cylinder(2, 3, 3.0f); - CORRADE_COMPARE_AS(*cylinder.positions(0), (vector{ + CORRADE_COMPARE_AS(*cylinder.positions(0), (std::vector{ {0.0f, -1.5f, 1.0f}, {0.866025f, -1.5f, -0.5f}, {-0.866025f, -1.5f, -0.5f}, @@ -49,7 +62,7 @@ void CylinderTest::withoutAnything() { {-0.866025f, 1.5f, -0.5f} }), Container); - CORRADE_COMPARE_AS(*cylinder.normals(0), (vector{ + CORRADE_COMPARE_AS(*cylinder.normals(0), (std::vector{ {0.0f, 0.0f, 1.0f}, {0.866025f, 0.0f, -0.5f}, {-0.866025f, 0.0f, -0.5f}, @@ -63,7 +76,7 @@ void CylinderTest::withoutAnything() { {-0.866025f, 0.0f, -0.5f} }), Container); - CORRADE_COMPARE_AS(*cylinder.indices(), (vector{ + 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); @@ -72,7 +85,7 @@ void CylinderTest::withoutAnything() { void CylinderTest::withTextureCoordsAndCaps() { Cylinder cylinder(2, 3, 3.0f, Cylinder::Flag::GenerateTextureCoords|Cylinder::Flag::CapEnds); - CORRADE_COMPARE_AS(*cylinder.positions(0), (vector{ + CORRADE_COMPARE_AS(*cylinder.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, {0.0f, -1.5f, 1.0f}, @@ -103,7 +116,7 @@ void CylinderTest::withTextureCoordsAndCaps() { {0.0f, 1.5f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*cylinder.normals(0), (vector{ + CORRADE_COMPARE_AS(*cylinder.normals(0), (std::vector{ {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, @@ -134,7 +147,7 @@ void CylinderTest::withTextureCoordsAndCaps() { {0.0f, 1.0f, 0.0f}, }), Container); - CORRADE_COMPARE_AS(*cylinder.textureCoords2D(0), (vector{ + CORRADE_COMPARE_AS(*cylinder.textureCoords2D(0), (std::vector{ {0.5f, 0.0f}, {0.0f, 0.2f}, @@ -165,7 +178,7 @@ void CylinderTest::withTextureCoordsAndCaps() { {0.5f, 1.0f} }), Container); - CORRADE_COMPARE_AS(*cylinder.indices(), (vector{ + 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, @@ -174,3 +187,5 @@ void CylinderTest::withTextureCoordsAndCaps() { } }}} + +CORRADE_TEST_MAIN(Magnum::Primitives::Test::CylinderTest) diff --git a/src/Primitives/Test/CylinderTest.h b/src/Primitives/Test/CylinderTest.h deleted file mode 100644 index 0d575bc23..000000000 --- a/src/Primitives/Test/CylinderTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Primitives_Test_CylinderTest_h -#define Magnum_Primitives_Test_CylinderTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Primitives { namespace Test { - -class CylinderTest: public Corrade::TestSuite::Tester { - public: - CylinderTest(); - - void withoutAnything(); - void withTextureCoordsAndCaps(); -}; - -}}} - -#endif diff --git a/src/Primitives/Test/UVSphereTest.cpp b/src/Primitives/Test/UVSphereTest.cpp index 1599eeb0d..beaa6b46f 100644 --- a/src/Primitives/Test/UVSphereTest.cpp +++ b/src/Primitives/Test/UVSphereTest.cpp @@ -1,41 +1,54 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "UVSphereTest.h" - +#include #include -#include "Math/Point3D.h" +#include "Math/Vector3.h" #include "Primitives/UVSphere.h" -using namespace std; using Corrade::TestSuite::Compare::Container; -CORRADE_TEST_MAIN(Magnum::Primitives::Test::UVSphereTest) - namespace Magnum { namespace Primitives { namespace Test { +class UVSphereTest: public Corrade::TestSuite::Tester { + public: + UVSphereTest(); + + void withoutTextureCoords(); + void withTextureCoords(); +}; + UVSphereTest::UVSphereTest() { - addTests(&UVSphereTest::withoutTextureCoords, - &UVSphereTest::withTextureCoords); + addTests({&UVSphereTest::withoutTextureCoords, + &UVSphereTest::withTextureCoords}); } void UVSphereTest::withoutTextureCoords() { UVSphere sphere(3, 3); - CORRADE_COMPARE_AS(*sphere.positions(0), (vector{ + CORRADE_COMPARE_AS(*sphere.positions(0), (std::vector{ {0.0f, -1.0f, 0.0f}, {0.0f, -0.5f, 0.866025f}, @@ -49,7 +62,7 @@ void UVSphereTest::withoutTextureCoords() { {0.0f, 1.0f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*sphere.normals(0), (vector{ + CORRADE_COMPARE_AS(*sphere.normals(0), (std::vector{ {0.0f, -1.0f, 0.0f}, {0.0f, -0.5f, 0.866025f}, @@ -63,7 +76,7 @@ void UVSphereTest::withoutTextureCoords() { {0.0f, 1.0f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*sphere.indices(), (vector{ + 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 @@ -73,7 +86,7 @@ void UVSphereTest::withoutTextureCoords() { void UVSphereTest::withTextureCoords() { UVSphere sphere(3, 3, UVSphere::TextureCoords::Generate); - CORRADE_COMPARE_AS(*sphere.positions(0), (vector{ + CORRADE_COMPARE_AS(*sphere.positions(0), (std::vector{ {0.0f, -1.0f, 0.0f}, {0.0f, -0.5f, 0.866025f}, @@ -89,7 +102,7 @@ void UVSphereTest::withTextureCoords() { {0.0f, 1.0f, 0.0f} }), Container); - CORRADE_COMPARE_AS(*sphere.textureCoords2D(0), (vector{ + CORRADE_COMPARE_AS(*sphere.textureCoords2D(0), (std::vector{ {0.5f, 0.0f}, {0.0f, 0.333333f}, @@ -105,7 +118,7 @@ void UVSphereTest::withTextureCoords() { {0.5f, 1.0f} }), Container); - CORRADE_COMPARE_AS(*sphere.indices(), (vector{ + 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 @@ -113,3 +126,5 @@ void UVSphereTest::withTextureCoords() { } }}} + +CORRADE_TEST_MAIN(Magnum::Primitives::Test::UVSphereTest) diff --git a/src/Primitives/Test/UVSphereTest.h b/src/Primitives/Test/UVSphereTest.h deleted file mode 100644 index 8afd27522..000000000 --- a/src/Primitives/Test/UVSphereTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Primitives_Test_UVSphereTest_h -#define Magnum_Primitives_Test_UVSphereTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Primitives { namespace Test { - -class UVSphereTest: public Corrade::TestSuite::Tester { - public: - UVSphereTest(); - - void withoutTextureCoords(); - void withTextureCoords(); -}; - -}}} - -#endif diff --git a/src/Primitives/UVSphere.cpp b/src/Primitives/UVSphere.cpp index 920ac2dd3..91fa8c2bc 100644 --- a/src/Primitives/UVSphere.cpp +++ b/src/Primitives/UVSphere.cpp @@ -1,39 +1,44 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "UVSphere.h" -#include - -#include "Math/Constants.h" - -using namespace std; +#include "Math/Angle.h" namespace Magnum { namespace Primitives { -UVSphere::UVSphere(uint32_t rings, uint32_t segments, TextureCoords textureCoords): Capsule(segments, textureCoords) { +UVSphere::UVSphere(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords): Capsule(segments, textureCoords) { CORRADE_ASSERT(rings >= 2 && segments >= 3, "UVSphere must have at least two rings and three segments", ); - GLfloat textureCoordsVIncrement = 1.0f/rings; - GLfloat ringAngleIncrement = Constants::pi()/rings; + Float textureCoordsVIncrement = 1.0f/rings; + Rad ringAngleIncrement = Rad(Constants::pi())/rings; /* Bottom cap vertex */ capVertex(-1.0f, -1.0f, 0.0f); /* Vertex rings */ - hemisphereVertexRings(rings-1, 0.0f, -Constants::pi()/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement); + hemisphereVertexRings(rings-1, 0.0f, -Rad(Constants::pi())/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement); /* Top cap vertex */ capVertex(1.0f, 1.0f, 1.0f); diff --git a/src/Primitives/UVSphere.h b/src/Primitives/UVSphere.h index 8d2f01054..8b6266c45 100644 --- a/src/Primitives/UVSphere.h +++ b/src/Primitives/UVSphere.h @@ -1,18 +1,27 @@ #ifndef Magnum_Primitives_UVSphere_h #define Magnum_Primitives_UVSphere_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,12 +30,15 @@ #include "Primitives/Capsule.h" +#include "Primitives/magnumPrimitivesVisibility.h" + namespace Magnum { namespace Primitives { /** @brief 3D UV sphere primitive -Indexed triangle mesh with normals and optional 2D texture coordinates. +Indexed @ref Mesh::Primitive "Triangles" with normals and optional 2D texture +coordinates. */ class UVSphere: public Capsule { public: @@ -39,7 +51,7 @@ class UVSphere: public Capsule { * If texture coordinates are generated, vertices of one segment are * duplicated for texture wrapping. */ - UVSphere(std::uint32_t rings, std::uint32_t segments, TextureCoords textureCoords = TextureCoords::DontGenerate); + explicit MAGNUM_PRIMITIVES_EXPORT UVSphere(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords = TextureCoords::DontGenerate); }; }} diff --git a/src/Primitives/magnumPrimitivesVisibility.h b/src/Primitives/magnumPrimitivesVisibility.h new file mode 100644 index 000000000..13a5c93cb --- /dev/null +++ b/src/Primitives/magnumPrimitivesVisibility.h @@ -0,0 +1,37 @@ +#ifndef Magnum_Primitives_magnumPrimitivesVisibility_h +#define Magnum_Primitives_magnumPrimitivesVisibility_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. +*/ + +#ifdef _WIN32 + #ifdef MagnumPrimitives_EXPORTS + #define MAGNUM_PRIMITIVES_EXPORT __declspec(dllexport) + #else + #define MAGNUM_PRIMITIVES_EXPORT __declspec(dllimport) + #endif +#else + #define MAGNUM_PRIMITIVES_EXPORT __attribute__ ((visibility ("default"))) +#endif + +#endif diff --git a/src/Profiler.cpp b/src/Profiler.cpp deleted file mode 100644 index 0afb8779f..000000000 --- a/src/Profiler.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "Profiler.h" - -#include -#include -#include - -using namespace std; - -namespace Magnum { - -Profiler::Section Profiler::addSection(const string& name) { - CORRADE_ASSERT(!enabled, "Profiler: cannot add section when profiling is enabled", 0); - sections.push_back(name); - return sections.size()-1; -} - -void Profiler::setMeasureDuration(size_t frames) { - CORRADE_ASSERT(!enabled, "Profiler: cannot set measure duration when profiling is enabled", ); - measureDuration = frames; -} - -void Profiler::enable() { - enabled = true; - frameData.assign(measureDuration*sections.size(), chrono::high_resolution_clock::duration::zero()); - totalData.assign(sections.size(), chrono::high_resolution_clock::duration::zero()); - frameCount = 0; -} - -void Profiler::disable() { - enabled = false; -} - -void Profiler::start(Section section) { - if(!enabled) return; - CORRADE_ASSERT(section < sections.size(), "Profiler: unknown section passed to start()", ); - - save(); - - currentSection = section; -} - -void Profiler::stop() { - if(!enabled) return; - - save(); - - previousTime = chrono::high_resolution_clock::time_point(); -} - -void Profiler::save() { - auto now = chrono::high_resolution_clock::now(); - - /* If the profiler is already running, add time to given section */ - if(previousTime != chrono::high_resolution_clock::time_point()) - frameData[currentFrame*sections.size()+currentSection] += now-previousTime; - - /* Set current time as previous for next section */ - previousTime = now; -} - -void Profiler::nextFrame() { - if(!enabled) return; - - /* Next frame index */ - size_t nextFrame = (currentFrame+1) % measureDuration; - - /* Add times of current frame to total */ - for(size_t i = 0; i != sections.size(); ++i) - totalData[i] += frameData[currentFrame*sections.size()+i]; - - /* Subtract times of next frame from total and erase them */ - for(size_t i = 0; i != sections.size(); ++i) { - totalData[i] -= frameData[nextFrame*sections.size()+i]; - frameData[nextFrame*sections.size()+i] = chrono::high_resolution_clock::duration::zero(); - } - - /* Advance to next frame */ - currentFrame = nextFrame; - - if(frameCount < measureDuration) ++frameCount; -} - -void Profiler::printStatistics() { - if(!enabled) return; - - vector totalSorted(sections.size()); - iota(totalSorted.begin(), totalSorted.end(), 0); - - #ifndef CORRADE_GCC44_COMPATIBILITY - sort(totalSorted.begin(), totalSorted.end(), [this](size_t i, size_t j){return totalData[i] > totalData[j];}); - #else - sort(totalSorted.begin(), totalSorted.end(), Compare(this)); - #endif - - Corrade::Utility::Debug() << "Statistics for last" << measureDuration << "frames:"; - for(size_t i = 0; i != sections.size(); ++i) - Corrade::Utility::Debug() << ' ' << sections[totalSorted[i]] - << chrono::microseconds(totalData[totalSorted[i]]).count()/frameCount - #ifndef CORRADE_GCC44_COMPATIBILITY - << u8"µs"; - #else - << "µs"; - #endif -} - -} diff --git a/src/Query.cpp b/src/Query.cpp index 1b9fc86bc..072fad307 100644 --- a/src/Query.cpp +++ b/src/Query.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Query.h" @@ -39,10 +48,10 @@ template<> bool AbstractQuery::result() { #endif } -template<> GLuint AbstractQuery::result() { +template<> UnsignedInt AbstractQuery::result() { /** @todo Re-enable when extension wrangler is available for ES */ #ifndef MAGNUM_TARGET_GLES2 - GLuint result; + UnsignedInt result; glGetQueryObjectuiv(_id, GL_QUERY_RESULT, &result); return result; #else @@ -51,20 +60,20 @@ template<> GLuint AbstractQuery::result() { } #ifndef MAGNUM_TARGET_GLES -template<> GLint AbstractQuery::result() { - GLint result; +template<> Int AbstractQuery::result() { + Int result; glGetQueryObjectiv(_id, GL_QUERY_RESULT, &result); return result; } -template<> GLuint64 AbstractQuery::result() { - GLuint64 result; +template<> UnsignedLong AbstractQuery::result() { + UnsignedLong result; glGetQueryObjectui64v(_id, GL_QUERY_RESULT, &result); return result; } -template<> GLint64 AbstractQuery::result() { - GLint64 result; +template<> Long AbstractQuery::result() { + Long result; glGetQueryObjecti64v(_id, GL_QUERY_RESULT, &result); return result; } diff --git a/src/Query.h b/src/Query.h index 934f92e8d..76ad04a55 100644 --- a/src/Query.h +++ b/src/Query.h @@ -1,18 +1,27 @@ #ifndef Magnum_Query_h #define Magnum_Query_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -20,7 +29,7 @@ */ #include "Magnum.h" - +#include "OpenGL.h" #include "magnumVisibility.h" namespace Magnum { @@ -40,7 +49,7 @@ class MAGNUM_EXPORT AbstractQuery { * Generates one OpenGL query. * @see @fn_gl{GenQueries} */ - inline AbstractQuery() { + inline explicit AbstractQuery() { /** @todo Get some extension wrangler instead to avoid undeclared glGenQueries() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glGenQueries(1, &_id); @@ -72,15 +81,17 @@ class MAGNUM_EXPORT AbstractQuery { /** * @brief Result - * @tparam T Result type. Can be either `bool`, `GLuint`, - * `GLint`, `GLuint64` or `GLint64`. + * @tparam T Result type. Can be either `bool`, @ref UnsignedInt, + * @ref Int, @ref UnsignedLong or @ref Long. * * Note that this function is blocking until the result is available. * See resultAvailable(). * @see @fn_gl{GetQueryObject} with @def_gl{QUERY_RESULT} - * @requires_gl33 Extension @extension{ARB,timer_query} (result type `GLuint64` and `GLint64`) - * @requires_gl Result types @c GLint, @c GLuint64 and @c GLint64 are - * not available in OpenGL ES. + * @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. */ template T result(); @@ -91,11 +102,11 @@ class MAGNUM_EXPORT AbstractQuery { #ifndef DOXYGEN_GENERATING_OUTPUT template<> bool MAGNUM_EXPORT AbstractQuery::result(); -template<> GLuint MAGNUM_EXPORT AbstractQuery::result(); +template<> UnsignedInt MAGNUM_EXPORT AbstractQuery::result(); #ifndef MAGNUM_TARGET_GLES -template<> GLint MAGNUM_EXPORT AbstractQuery::result(); -template<> GLuint64 MAGNUM_EXPORT AbstractQuery::result(); -template<> GLint64 MAGNUM_EXPORT AbstractQuery::result(); +template<> Int MAGNUM_EXPORT AbstractQuery::result(); +template<> UnsignedLong MAGNUM_EXPORT AbstractQuery::result(); +template<> Long MAGNUM_EXPORT AbstractQuery::result(); #endif #endif @@ -117,9 +128,9 @@ if(!q.resultAvailable()) { } // ...or block until the result is available -GLuint primitiveCount = q.result(); +UnsignedInt primitiveCount = q.result(); @endcode -@requires_gl30 Extension @extension{EXT,transform_feedback} +@requires_gl30 %Extension @extension{EXT,transform_feedback} @requires_gles30 Only sample queries are available on OpenGL ES 2.0. */ class MAGNUM_EXPORT Query: public AbstractQuery { @@ -144,7 +155,7 @@ class MAGNUM_EXPORT Query: public AbstractQuery { /** * Elapsed time - * @requires_gl33 Extension @extension{ARB,timer_query} + * @requires_gl33 %Extension @extension{ARB,timer_query} * @requires_gl Only transform feedback query is available in * OpenGL ES. */ @@ -152,7 +163,7 @@ class MAGNUM_EXPORT Query: public AbstractQuery { #endif }; - inline Query(): target(nullptr) {} + inline explicit Query(): target(nullptr) {} inline ~Query() { delete target; } @@ -227,7 +238,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { /** * Whether any samples passed from fragment shader - * @requires_gl33 Extension @extension{ARB,occlusion_query2} + * @requires_gl33 %Extension @extension{ARB,occlusion_query2} */ #ifndef MAGNUM_TARGET_GLES2 AnySamplesPassed = GL_ANY_SAMPLES_PASSED, @@ -240,7 +251,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { * * An implementation may choose a less precise version of the * test at the expense of some false positives. - * @requires_gl43 Extension @extension{ARB,ES3_compatibility} + * @requires_gl43 %Extension @extension{ARB,ES3_compatibility} */ #ifndef MAGNUM_TARGET_GLES2 AnySamplesPassedConservative = GL_ANY_SAMPLES_PASSED_CONSERVATIVE @@ -253,7 +264,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { /** * @brief Conditional render mode * - * @requires_gl30 Extension @extension{NV,conditional_render} + * @requires_gl30 %Extension @extension{NV,conditional_render} * @requires_gl Conditional rendering is not available in OpenGL ES. */ enum class ConditionalRenderMode: GLenum { @@ -283,7 +294,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { }; #endif - inline SampleQuery(): target(nullptr) {} + inline explicit SampleQuery(): target(nullptr) {} inline ~SampleQuery() { delete target; } @@ -298,7 +309,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { * @brief Begin conditional rendering based on result value * * @see @fn_gl{BeginConditionalRender} - * @requires_gl30 Extension @extension{NV,conditional_render} + * @requires_gl30 %Extension @extension{NV,conditional_render} * @requires_gl Conditional rendering is not available in OpenGL ES. */ inline void beginConditionalRender(ConditionalRenderMode mode) { @@ -309,7 +320,7 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { * @brief End conditional render * * @see @fn_gl{EndConditionalRender} - * @requires_gl30 Extension @extension{NV,conditional_render} + * @requires_gl30 %Extension @extension{NV,conditional_render} * @requires_gl Conditional rendering is not available in OpenGL ES. */ inline void endConditionalRender() { @@ -326,9 +337,9 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { @brief %Query for elapsed time Queries timestamp after all previous OpenGL calls have been processed. It is -similar to Query::Target::TimeElapsed query, but this query just retrieves -timestamp, not time duration between Query::begin() and Query::end() calls. -Example usage, compared to Query::Target::TimeElapsed: +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": @code Query q1, q2; q1.begin(Query::Target::TimeElapsed); @@ -337,8 +348,8 @@ q1.end(); q2.begin(Query::Target::TimeElapsed); // another rendering... q2.end(); -GLuint timeElapsed1 = q1.result(); -GLuint timeElapsed2 = q2.result(); +UnsignedInt timeElapsed1 = q1.result(); +UnsignedInt timeElapsed2 = q2.result(); @endcode @code TimeQuery q1, q2, q3; @@ -347,16 +358,19 @@ q1.timestamp(); q2.timestamp(); // another rendering... q3.timestamp(); -GLuint tmp = q2.result(); -GLuint timeElapsed1 = tmp-q1.result(); -GLuint timeElapsed2 = q3.result()-tmp; +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. -@requires_gl33 Extension @extension{ARB,timer_query} +@requires_gl33 %Extension @extension{ARB,timer_query} @requires_gl Timer query is not available in OpenGL ES. +@todo timestamp with glGet + example usage */ class TimeQuery: public AbstractQuery { public: + explicit TimeQuery() = default; + /** * @brief Query timestamp * diff --git a/src/Renderbuffer.cpp b/src/Renderbuffer.cpp index bb5be459b..0ca1a724c 100644 --- a/src/Renderbuffer.cpp +++ b/src/Renderbuffer.cpp @@ -1,76 +1,76 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Renderbuffer.h" +#include "Context.h" +#include "Extensions.h" + +#include "Implementation/State.h" +#include "Implementation/FramebufferState.h" + namespace Magnum { -#ifndef MAGNUM_TARGET_GLES2 -Renderbuffer::InternalFormat::InternalFormat(Components components, ComponentType type) { +Renderbuffer::StorageImplementation Renderbuffer::storageImplementation = &Renderbuffer::storageImplementationDefault; + +Renderbuffer::~Renderbuffer() { + /* If bound, remove itself from state */ + GLuint& binding = Context::current()->state()->framebuffer->renderbufferBinding; + if(binding == _id) binding = 0; + + glDeleteRenderbuffers(1, &_id); +} + +void Renderbuffer::bind() { + GLuint& binding = Context::current()->state()->framebuffer->renderbufferBinding; + + if(binding == _id) return; + + binding = _id; + glBindRenderbuffer(GL_RENDERBUFFER, _id); +} + +void Renderbuffer::initializeContextBasedFunctionality(Context* context) { #ifndef MAGNUM_TARGET_GLES - #define internalFormatSwitch(c) switch(type) { \ - case ComponentType::UnsignedByte: \ - internalFormat = GL_##c##8UI; break; \ - case ComponentType::Byte: \ - internalFormat = GL_##c##8I; break; \ - case ComponentType::UnsignedShort: \ - internalFormat = GL_##c##16UI; break; \ - case ComponentType::Short: \ - internalFormat = GL_##c##16I; break; \ - case ComponentType::UnsignedInt: \ - internalFormat = GL_##c##32UI; break; \ - case ComponentType::Int: \ - internalFormat = GL_##c##32I; break; \ - case ComponentType::Half: \ - internalFormat = GL_##c##16F; break; \ - case ComponentType::Float: \ - internalFormat = GL_##c##32F; break; \ - case ComponentType::NormalizedUnsignedByte: \ - internalFormat = GL_##c##8; break; \ - case ComponentType::NormalizedUnsignedShort: \ - internalFormat = GL_##c##16; break; \ + if(context->isExtensionSupported()) { + Debug() << "Renderbuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + storageImplementation = &Renderbuffer::storageImplementationDSA; } #else - #define internalFormatSwitch(c) switch(type) { \ - case ComponentType::UnsignedByte: \ - internalFormat = GL_##c##8UI; break; \ - case ComponentType::Byte: \ - internalFormat = GL_##c##8I; break; \ - case ComponentType::UnsignedShort: \ - internalFormat = GL_##c##16UI; break; \ - case ComponentType::Short: \ - internalFormat = GL_##c##16I; break; \ - case ComponentType::UnsignedInt: \ - internalFormat = GL_##c##32UI; break; \ - case ComponentType::Int: \ - internalFormat = GL_##c##32I; break; \ - case ComponentType::Half: \ - internalFormat = GL_##c##16F; break; \ - case ComponentType::Float: \ - internalFormat = GL_##c##32F; break; \ - case ComponentType::NormalizedUnsignedByte: \ - internalFormat = GL_##c##8; break; \ - } + static_cast(context); #endif - if(components == Components::Red) - internalFormatSwitch(R) - else if(components == Components::RedGreen) - internalFormatSwitch(RG) - else if(components == Components::RGBA) - internalFormatSwitch(RGBA) - #undef internalFormatSwitch +} + +void Renderbuffer::storageImplementationDefault(Renderbuffer::InternalFormat 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) { + glNamedRenderbufferStorageEXT(_id, GLenum(internalFormat), size.x(), size.y()); } #endif diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index 23b03e657..20420056b 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -1,27 +1,35 @@ #ifndef Magnum_Renderbuffer_h #define Magnum_Renderbuffer_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Renderbuffer */ -#include "Math/Vector2.h" #include "Magnum.h" - +#include "OpenGL.h" #include "magnumVisibility.h" namespace Magnum { @@ -29,167 +37,494 @@ namespace Magnum { /** @brief %Renderbuffer -Attachable to Framebuffer as render target. +Attachable to framebuffer as render target, see Framebuffer documentation +for more information. + +@section Renderbuffer-performance-optimization Performance optimizations + +The engine tracks currently bound renderbuffer to avoid unnecessary calls to +@fn_gl{BindRenderbuffer} in setStorage(). + +If extension @extension{EXT,direct_state_access} is available, function +setStorage() uses DSA to avoid unnecessary calls to @fn_gl{BindFramebuffer}. +See its documentation for more information. -@requires_gl30 Extension @extension{EXT,framebuffer_object} +@requires_gl30 %Extension @extension{EXT,framebuffer_object} */ -class Renderbuffer { +class MAGNUM_EXPORT Renderbuffer { + friend class Context; + Renderbuffer(const Renderbuffer& other) = delete; Renderbuffer(Renderbuffer&& other) = delete; Renderbuffer& operator=(const Renderbuffer& other) = delete; Renderbuffer& operator=(Renderbuffer&& other) = delete; public: - /** @{ @name Internal renderbuffer formats */ - - #ifndef MAGNUM_TARGET_GLES2 /** - * @copybrief AbstractTexture::Components + * @brief Internal format * - * Like AbstractTexture::Components, without three-component RGB. - * @requires_gles30 (no extension providing this functionality) + * @see setStorage() + * @todo RGB, RGB8 ES only (ES3 + @es_extension{OES,rgb8_rgba8}) */ - enum class Components { - Red, RedGreen, RGBA - }; + 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 - /** - * @copybrief AbstractTexture::ComponentType - * - * Like AbstractTexture::ComponentType, without normalized signed - * types. - * @requires_gles30 (no extension providing this functionality) - */ - enum class ComponentType { - UnsignedByte, Byte, UnsignedShort, Short, UnsignedInt, Int, Half, - Float, NormalizedUnsignedByte + /** + * 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 - , NormalizedUnsignedShort + /** + * 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 - }; - #endif - /** - * @copybrief AbstractTexture::Format - * - * Like AbstractTexture::Format without - * AbstractTexture::Format::RGB9Intensity5, three-component and - * compressed formats, but with added separate stencil index. - */ - enum class Format: GLenum { + /** + * 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 - Red = GL_RED, RedGreen = GL_RG, + 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 - BGRA = GL_BGRA, + /** + * 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 - SRGBA = GL_SRGB8_ALPHA8, RGB10Alpha2 = GL_RGB10_A2, - RGB10AlphaUnsigned2 = GL_RGB10_A2UI, + /** + * 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 - RGB5Alpha1 = GL_RGB5_A1, - RGBA4 = GL_RGBA4, + #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 - RFloat11GFloat11BFloat10 = GL_R11F_G11F_B10F, + /** + * 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 - #ifndef MAGNUM_TARGET_GLES /** - * Depth component, at least 16bit. - * - * Prefer to use the exactly specified version of this format, in - * this case e.g. `Format::%Depth16`. - * @requires_gl Use exactly specified format Format::%Depth16 instead. + * sRGBA, each component normalized unsigned byte. + * @requires_gles30 %Extension @es_extension{EXT,sRGB} */ - Depth = GL_DEPTH_COMPONENT, + #ifndef MAGNUM_TARGET_GLES2 + SRGB8Alpha8 = GL_SRGB8_ALPHA8, + #else + SRGB8Alpha8 = GL_SRGB8_ALPHA8_EXT, + #endif - DepthStencil = GL_DEPTH_STENCIL, + #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 - Depth16 = GL_DEPTH_COMPONENT16, + /** 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 + + /** + * Depth component, 32bit. + * @requires_es_extension %Extension @es_extension{OES,depth32} + */ #ifndef MAGNUM_TARGET_GLES - Depth24 = GL_DEPTH_COMPONENT24, - DepthFloat = GL_DEPTH_COMPONENT32F, + DepthComponent32 = GL_DEPTH_COMPONENT32, + #else + DepthComponent32 = GL_DEPTH_COMPONENT32_OES, + #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 (unspecified size). - * - * Prefer to use the exactly specified version of this format, in - * this case e.g. `Format::%Stencil8`. - * @requires_gl Use exactly specified format Format::%Stencil8 instead. + * 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. */ - Stencil = GL_STENCIL_INDEX, + StencilIndex = GL_STENCIL_INDEX, + #endif /** * 1-bit stencil index. - * - * @requires_gl Use Format::%Stencil8 instead. + * @requires_es_extension %Extension @es_extension{OES,stencil1} */ - Stencil1 = GL_STENCIL_INDEX1, + #ifndef MAGNUM_TARGET_GLES + StencilIndex1 = GL_STENCIL_INDEX1, + #else + StencilIndex1 = GL_STENCIL_INDEX1_OES, + #endif /** * 4-bit stencil index. - * - * @requires_gl Use Format::%Stencil8 instead. + * @requires_es_extension %Extension @es_extension{OES,stencil4} */ - Stencil4 = GL_STENCIL_INDEX4, + #ifndef MAGNUM_TARGET_GLES + StencilIndex4 = GL_STENCIL_INDEX4, + #else + StencilIndex4 = GL_STENCIL_INDEX4_OES, #endif /** 8-bit stencil index. */ - Stencil8 = GL_STENCIL_INDEX8 + StencilIndex8 = GL_STENCIL_INDEX8, #ifndef MAGNUM_TARGET_GLES - , - /** * 16-bit stencil index. - * - * @requires_gl Use Format::%Stencil8 instead. + * @requires_gl At most 8bit stencil index is available in OpenGL + * ES. */ - Stencil16 = GL_STENCIL_INDEX1, + StencilIndex16 = GL_STENCIL_INDEX16, - Depth24Stencil8 = GL_DEPTH24_STENCIL8, - DepthFloatStencil8 = GL_DEPTH32F_STENCIL8 + /** + * 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 - }; - /** @copydoc AbstractTexture::InternalFormat */ - class MAGNUM_EXPORT InternalFormat { - public: - #ifndef MAGNUM_TARGET_GLES2 - /** @copydoc AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components, AbstractTexture::ComponentType) */ - InternalFormat(Components components, ComponentType type); - #endif - - /** @copydoc AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Format) */ - inline constexpr InternalFormat(Format format): internalFormat(static_cast(format)) {} - - /** - * @brief OpenGL internal format ID - * - * @todoc Remove workaround when Doxygen supports \@copydoc for conversion operators - */ - inline constexpr operator GLenum() const { return internalFormat; } - - private: - GLenum internalFormat; - }; + /** + * 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 @@ -197,8 +532,8 @@ class Renderbuffer { * Generates new OpenGL renderbuffer. * @see @fn_gl{GenRenderbuffers} */ - inline Renderbuffer() { - glGenRenderbuffers(1, &renderbuffer); + inline explicit Renderbuffer() { + glGenRenderbuffers(1, &_id); } /** @@ -207,54 +542,40 @@ class Renderbuffer { * Deletes associated OpenGL renderbuffer. * @see @fn_gl{DeleteRenderbuffers} */ - inline ~Renderbuffer() { - glDeleteRenderbuffers(1, &renderbuffer); - } + ~Renderbuffer(); /** @brief OpenGL internal renderbuffer ID */ - inline GLuint id() const { return renderbuffer; } - - /** - * @brief Bind renderbuffer - * - * @see @fn_gl{BindRenderbuffer} - */ - inline void bind() { - glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); - } + inline GLuint id() const { return _id; } /** * @brief Set renderbuffer storage * @param internalFormat Internal format * @param size Renderbuffer size * - * @see bind(), @fn_gl{RenderbufferStorage} + * 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} */ - inline void setStorage(InternalFormat internalFormat, const Math::Vector2& size) { - bind(); - glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, size.x(), size.y()); + inline void setStorage(InternalFormat internalFormat, const Vector2i& size) { + (this->*storageImplementation)(internalFormat, size); } private: - GLuint renderbuffer; -}; + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); -#ifndef MAGNUM_TARGET_GLES2 -/** @relates Renderbuffer -@brief Convertor of component count and data type to InternalFormat + typedef void(Renderbuffer::*StorageImplementation)(InternalFormat, const Vector2i&); + void MAGNUM_LOCAL storageImplementationDefault(InternalFormat internalFormat, const Vector2i& size); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageImplementationDSA(InternalFormat internalFormat, const Vector2i& size); + #endif + static StorageImplementation storageImplementation; -@requires_gles30 (no extension providing this functionality) -*/ -inline Renderbuffer::InternalFormat operator|(Renderbuffer::Components components, Renderbuffer::ComponentType type) { - return Renderbuffer::InternalFormat(components, type); -} -/** @relates Renderbuffer - * @overload - */ -inline Renderbuffer::InternalFormat operator|(Renderbuffer::ComponentType type, Renderbuffer::Components components) { - return Renderbuffer::InternalFormat(components, type); -} -#endif + void MAGNUM_LOCAL bind(); + + GLuint _id; +}; } diff --git a/src/Renderer.h b/src/Renderer.h new file mode 100644 index 000000000..5edbd0db2 --- /dev/null +++ b/src/Renderer.h @@ -0,0 +1,658 @@ +#ifndef Magnum_Renderer_h +#define Magnum_Renderer_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::Renderer + */ + +#include + +#include "AbstractImage.h" +#include "Buffer.h" +#include "CubeMapTexture.h" +#include "Color.h" +#include "Renderbuffer.h" + +namespace Magnum { + +/** @nosubgrouping +@brief %Renderer + +Access to global renderer configuration. +@todo @extension{ARB,viewport_array} +*/ +class MAGNUM_EXPORT Renderer { + public: + Renderer() = delete; + + /** + * @brief Affected polygon facing for culling, stencil operations and masks + * + * @see setFaceCullingMode(), + * setStencilFunction(PolygonFacing, StencilFunction, Int, UnsignedInt), + * setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation), + * setStencilMask(PolygonFacing, UnsignedInt) + */ + enum class PolygonFacing: GLenum { + Front = GL_FRONT, /**< Front-facing polygons */ + Back = GL_BACK, /**< Back-facing polygons */ + FrontAndBack = GL_FRONT_AND_BACK /**< Front- and back-facing polygons */ + }; + + /** @{ @name Renderer features */ + + /** + * @brief Features + * + * If not specified otherwise, all features are disabled by default. + * @see setFeature() + */ + enum class Feature: GLenum { + /** + * Blending + * @see setBlendEquation(), setBlendFunction(), setBlendColor() + */ + Blending = GL_BLEND, + + #ifndef MAGNUM_TARGET_GLES + /** + * Logical operation + * @see setLogicOperation() + * @requires_gl Logical operations on framebuffer are not + * available in OpenGL ES. + */ + LogicOperation = GL_COLOR_LOGIC_OP, + + /** + * 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 + + /** + * Scissor test + * @see setScissor() + */ + ScissorTest = GL_SCISSOR_TEST, + DepthTest = GL_DEPTH_TEST, /**< Depth test */ + StencilTest = GL_STENCIL_TEST, /**< Stencil test */ + Dithering = GL_DITHER, /**< Dithering (enabled by default) */ + FaceCulling = GL_CULL_FACE /**< Back face culling */ + }; + + /** + * @brief Set feature + * + * @see @fn_gl{Enable}/@fn_gl{Disable} + */ + inline static void setFeature(Feature feature, bool enabled) { + enabled ? glEnable(static_cast(feature)) : glDisable(static_cast(feature)); + } + + /** + * @brief Which polygon facing to cull + * + * 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} + */ + inline static void setFaceCullingMode(PolygonFacing mode) { + glCullFace(static_cast(mode)); + } + + /*@}*/ + + /** @{ @name Clearing values */ + + /** + * @brief Set clear color + * + * Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`. + * @see @fn_gl{ClearColor} + */ + inline static void setClearColor(const Color4<>& color) { + glClearColor(color.r(), color.g(), color.b(), color.a()); + } + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Set clear depth + * + * Initial value is `1.0`. + * @see @fn_gl{ClearDepth} + * @requires_gl See setClearDepth(Float), which is available in OpenGL ES. + */ + inline static void setClearDepth(Double depth) { glClearDepth(depth); } + #endif + + /** + * @overload + * + * @see @fn_gl{ClearDepth} + * @requires_gl41 %Extension @extension{ARB,ES2_compatibility} + * @todo Call double version if the extension is not available + */ + inline static void setClearDepth(Float depth) { glClearDepthf(depth); } + + /** + * @brief Set clear stencil + * + * Initial value is `0`. + * @see @fn_gl{ClearStencil} + */ + inline static void setClearStencil(Int stencil) { glClearStencil(stencil); } + + /*@}*/ + + /** @{ @name Scissor operations */ + + /** + * @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} + */ + inline static void setScissor(const Vector2i& bottomLeft, const Vector2i& size) { + glScissor(bottomLeft.x(), bottomLeft.y(), size.x(), size.y()); + } + + /*@}*/ + + /** @{ @name Stencil operations */ + + /** + * @brief Stencil function + * + * @see setStencilFunction() + */ + enum class StencilFunction: GLenum { + Never = GL_NEVER, /**< Never pass the test. */ + Always = GL_ALWAYS, /**< Always pass the test. */ + Less = GL_LESS, /**< Pass when reference value is less than buffer value. */ + LessOrEqual = GL_LEQUAL, /**< Pass when reference value is less than or equal to buffer value. */ + Equal = GL_EQUAL, /**< Pass when reference value is equal to buffer value. */ + NotEqual = GL_NOTEQUAL, /**< Pass when reference value is not equal to buffer value. */ + GreaterOrEqual = GL_GEQUAL, /**< Pass when reference value is greater than or equal to buffer value. */ + Greater = GL_GREATER /**< Pass when reference value is greater than buffer value. */ + }; + + /** + * @brief Stencil operation + * + * @see setStencilOperation() + */ + enum class StencilOperation: GLenum { + Keep = GL_KEEP, /**< Keep the current value. */ + Zero = GL_ZERO, /**< Set the stencil buffer value to `0`. */ + + /** + * Set the stencil value to reference value specified by + * setStencilFunction(). + */ + Replace = GL_REPLACE, + + /** + * Increment the current stencil buffer value, clamp to maximum + * possible value on overflow. + */ + Increment = GL_INCR, + + /** + * Increment the current stencil buffer value, wrap to zero on + * overflow. + */ + IncrementWrap = GL_INCR_WRAP, + + /** + * Increment the current stencil buffer value, clamp to minimum + * possible value on underflow. + */ + Decrement = GL_DECR, + + /** + * Decrement the current stencil buffer value, wrap to maximum + * possible value on underflow. + */ + DecrementWrap = GL_DECR_WRAP, + + /** + * Bitwise invert the current stencil buffer value. + */ + Invert = GL_INVERT + }; + + /** + * @brief Set stencil function + * @param facing Affected polygon facing + * @param function Stencil function. Initial value is + * `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), + * @fn_gl{StencilFuncSeparate} + */ + inline static void setStencilFunction(PolygonFacing facing, StencilFunction function, Int referenceValue, UnsignedInt mask) { + glStencilFuncSeparate(static_cast(facing), static_cast(function), referenceValue, mask); + } + + /** + * @brief Set stencil function + * + * The same as setStencilFunction(PolygonFacing, StencilFunction, Int, UnsignedInt) + * with `facing` set to `PolygonFacing::FrontAndBack`. + * @see @fn_gl{StencilFunc} + */ + inline static void setStencilFunction(StencilFunction function, Int referenceValue, UnsignedInt mask) { + glStencilFunc(static_cast(function), referenceValue, mask); + } + + /** + * @brief Set stencil operation + * @param facing Affected polygon facing + * @param stencilFail Action when stencil test fails + * @param depthFail Action when stencil test passes, but depth + * test fails + * @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} + */ + 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)); + } + + /** + * @brief Set stencil operation + * + * The same as setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation) + * with `facing` set to `PolygonFacing::FrontAndBack`. + * @see @fn_gl{StencilOp} + */ + inline static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) { + glStencilOp(static_cast(stencilFail), static_cast(depthFail), static_cast(depthPass)); + } + + /*@}*/ + + /** @{ @name Depth testing */ + + /** + * @brief Depth function + * + * @see setDepthFunction() + */ + typedef StencilFunction DepthFunction; + + /** + * @brief Set depth function + * + * Initial value is `DepthFunction::Less`. + * @attention You have to enable depth test with setFeature() first. + * @see @fn_gl{DepthFunc} + */ + inline static void setDepthFunction(DepthFunction function) { + glDepthFunc(static_cast(function)); + } + + /*@}*/ + + /** @{ @name Masking writes */ + + /** + * @brief Mask color writes + * + * Set to `false` to disallow writing to given color channel. Initial + * values are all `true`. + * @see @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); + } + + /** + * @brief Mask depth writes + * + * Set to `false` to disallow writing to depth buffer. Initial value + * is `true`. + * @see @fn_gl{DepthMask} + */ + inline static void setDepthMask(GLboolean allow) { + glDepthMask(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} + */ + inline static void setStencilMask(PolygonFacing facing, UnsignedInt allowBits) { + glStencilMaskSeparate(static_cast(facing), allowBits); + } + + /** + * @brief Mask stencil writes + * + * The same as setStencilMask(PolygonFacing, UnsignedInt) with `facing` set + * to `PolygonFacing::FrontAndBack`. + * @see @fn_gl{StencilMask} + */ + inline static void setStencilMask(UnsignedInt allowBits) { + glStencilMask(allowBits); + } + + /*@}*/ + + /** @{ @name Blending + * You have to enable blending with setFeature() first. + * @todo Blending for given draw buffer + */ + + /** + * @brief Blend equation + * + * @see setBlendEquation() + */ + enum class BlendEquation: GLenum { + Add = GL_FUNC_ADD, /**< `source + destination` */ + Subtract = GL_FUNC_SUBTRACT, /**< `source - destination` */ + ReverseSubtract = GL_FUNC_REVERSE_SUBTRACT /**< `destination - source` */ + + #ifndef MAGNUM_TARGET_GLES2 + , + /** + * `min(source, destination)` + * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax} + */ + Min = GL_MIN, + + /** + * `max(source, destination)` + * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax} + */ + Max = GL_MAX + #endif + }; + + /** + * @brief Blend function + * + * @see setBlendFunction() + */ + enum class BlendFunction: GLenum { + /** Zero (@f$ RGB = (0.0, 0.0, 0.0); A = 0.0 @f$) */ + Zero = GL_ZERO, + + /** One (@f$ RGB = (1.0, 1.0, 1.0); A = 1.0 @f$) */ + One = GL_ONE, + + /** + * Constant color (@f$ RGB = (R_c, G_c, B_c); A = A_c @f$) + * + * @see setBlendColor() + */ + ConstantColor = GL_CONSTANT_COLOR, + + /** + * One minus constant color (@f$ RGB = (1.0 - R_c, 1.0 - G_c, 1.0 - B_c); A = 1.0 - A_c @f$) + * + * @see setBlendColor() + */ + OneMinusConstantColor = GL_ONE_MINUS_CONSTANT_COLOR, + + /** + * Constant alpha (@f$ RGB = (A_c, A_c, A_c); A = A_c @f$) + * + * @see setBlendColor() + */ + ConstantAlpha = GL_CONSTANT_ALPHA, + + /** + * One minus constant alpha (@f$ RGB = (1.0 - A_c, 1.0 - A_c, 1.0 - A_c); A = 1.0 - A_c @f$) + * + * @see setBlendColor() + */ + OneMinusConstantAlpha = GL_ONE_MINUS_CONSTANT_ALPHA, + + /** Source color (@f$ RGB = (R_{s0}, G_{s0}, B_{s0}); A = A_{s0} @f$) */ + SourceColor = GL_SRC_COLOR, + + #ifndef MAGNUM_TARGET_GLES + /** + * Second source color (@f$ RGB = (R_{s1}, G_{s1}, B_{s1}); A = A_{s1} @f$) + * + * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() + * @requires_gl33 %Extension @extension{ARB,blend_func_extended} + * @requires_gl Multiple blending inputs are not available in + * OpenGL ES. + */ + SecondSourceColor = GL_SRC1_COLOR, + #endif + + /** + * One minus source color (@f$ RGB = (1.0 - R_{s0}, 1.0 - G_{s0}, 1.0 - B_{s0}); A = 1.0 - A_{s0} @f$) + */ + OneMinusSourceColor = GL_ONE_MINUS_SRC_COLOR, + + #ifndef MAGNUM_TARGET_GLES + /** + * One minus second source color (@f$ RGB = (1.0 - R_{s1}, 1.0 - G_{s1}, 1.0 - B_{s1}); A = 1.0 - A_{s1} @f$) + * + * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() + * @requires_gl33 %Extension @extension{ARB,blend_func_extended} + * @requires_gl Multiple blending inputs are not available in + * OpenGL ES. + */ + OneMinusSecondSourceColor = GL_ONE_MINUS_SRC1_COLOR, + #endif + + /** Source alpha (@f$ RGB = (A_{s0}, A_{s0}, A_{s0}); A = A_{s0} @f$) */ + SourceAlpha = GL_SRC_ALPHA, + + /** + * Saturate source alpha (@f$ RGB = (f, f, f); A = 1.0; f = min(A_s, 1.0 - A_d) @f$) + * + * Can be used only in source parameter of setBlendFunction(). + */ + SourceAlphaSaturate = GL_SRC_ALPHA_SATURATE, + + #ifndef MAGNUM_TARGET_GLES + /** + * Second source alpha (@f$ RGB = (A_{s1}, A_{s1}, A_{s1}); A = A_{s1} @f$) + * + * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() + * @requires_gl33 %Extension @extension{ARB,blend_func_extended} + * @requires_gl Multiple blending inputs are not available in + * OpenGL ES. + */ + SecondSourceAlpha = GL_SRC1_ALPHA, + #endif + + /** + * One minus source alpha (@f$ RGB = (1.0 - A_{s0}, 1.0 - A_{s0}, 1.0 - A_{s0}); A = 1.0 - A_{s0} @f$) + */ + OneMinusSourceAlpha = GL_ONE_MINUS_SRC_ALPHA, + + #ifndef MAGNUM_TARGET_GLES + /** + * One minus second source alpha (@f$ RGB = (1.0 - A_{s1}, 1.0 - A_{s1}, 1.0 - A_{s1}); A = 1.0 - A_{s1} @f$) + * + * @see AbstractShaderProgram::bindFragmentDataLocationIndexed() + * @requires_gl33 %Extension @extension{ARB,blend_func_extended} + * @requires_gl Multiple blending inputs are not available in + * OpenGL ES. + */ + OneMinusSecondSourceAlpha = GL_ONE_MINUS_SRC1_ALPHA, + #endif + + /** Destination color (@f$ RGB = (R_d, G_d, B_d); A = A_d @f$) */ + DestinationColor = GL_DST_COLOR, + + /** + * One minus source color (@f$ RGB = (1.0 - R_d, 1.0 - G_d, 1.0 - B_d); A = 1.0 - A_d @f$) + */ + OneMinusDestinationColor = GL_ONE_MINUS_DST_COLOR, + + /** Destination alpha (@f$ RGB = (A_d, A_d, A_d); A = A_d @f$) */ + DestinationAlpha = GL_DST_ALPHA, + + /** + * One minus source alpha (@f$ RGB = (1.0 - A_d, 1.0 - A_d, 1.0 - A_d); A = 1.0 - A_d @f$) + */ + OneMinusDestinationAlpha = GL_ONE_MINUS_DST_ALPHA + }; + + /** + * @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} + */ + inline static void setBlendEquation(BlendEquation equation) { + glBlendEquation(static_cast(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} + */ + inline static void setBlendEquation(BlendEquation rgb, BlendEquation alpha) { + glBlendEquationSeparate(static_cast(rgb), static_cast(alpha)); + } + + /** + * @brief Set blend function + * @param source How the source blending factor is computed + * from pixel value. Initial value is `BlendFunction::One`. + * @param destination How the destination blending factor is + * computed from framebuffer. Initial value is + * `BlendFunction::Zero`. + * + * @attention You have to enable blending with setFeature() first. + * @see setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction), + * @fn_gl{BlendFunc} + */ + inline static void setBlendFunction(BlendFunction source, BlendFunction destination) { + glBlendFunc(static_cast(source), static_cast(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} + */ + 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)); + } + + /** + * @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()); + } + + /*@}*/ + + #ifndef MAGNUM_TARGET_GLES + /** @{ @name Logical operation */ + + /** + * @brief Logical operation + * + * @see setLogicOperation() + * @requires_gl Logical operations on framebuffer are not available in + * OpenGL ES. + */ + enum class LogicOperation: GLenum { + Clear = GL_CLEAR, /**< `0` */ + Set = GL_SET, /**< `1` */ + Copy = GL_COPY, /**< `source` */ + CopyInverted = GL_COPY_INVERTED,/**< `~source` */ + Noop = GL_NOOP, /**< `destination` */ + Invert = GL_INVERT, /**< `~destination` */ + And = GL_AND, /**< `source & destination` */ + AndReverse = GL_AND_REVERSE, /**< `source & ~destination` */ + AndInverted = GL_AND_INVERTED, /**< `~source & destination` */ + Nand = GL_NAND, /**< `~(source & destination)` */ + Or = GL_OR, /**< `source | destination` */ + OrReverse = GL_OR_REVERSE, /**< `source | ~destination` */ + OrInverted = GL_OR_INVERTED, /**< `~source | destination` */ + Nor = GL_NOR, /**< `~(source | destination)` */ + Xor = GL_XOR, /**< `source ^ destination` */ + Equivalence = GL_EQUIV /**< `~(source ^ destination)` */ + }; + + /** + * @brief Set logical operation + * + * @attention You have to enable logical operation with setFeature() first. + * @see @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)); + } + + /*@}*/ + #endif +}; + +} + +#endif diff --git a/src/Resource.cpp b/src/Resource.cpp index 6093091d4..ac0c89ffa 100644 --- a/src/Resource.cpp +++ b/src/Resource.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Resource.h" diff --git a/src/Resource.h b/src/Resource.h index 33085cb7c..6848bbb12 100644 --- a/src/Resource.h +++ b/src/Resource.h @@ -1,24 +1,34 @@ #ifndef Magnum_Resource_h #define Magnum_Resource_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 /Resource.h * @brief Class Magnum::ResourceKey, Magnum::Resource, enum Magnum::ResourceState */ +#include #include #include "Magnum.h" @@ -32,7 +42,7 @@ namespace Magnum { * * @see Resource::state(), ResourceManager::state() */ -enum class ResourceState: std::uint8_t { +enum class ResourceState: UnsignedByte { /** The resource is not yet loaded (and no fallback is available). */ NotLoaded, @@ -64,6 +74,7 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, ResourceState value); /** @brief Key for accessing resource +See ResourceManager for more information. @see ResourceManager::referenceCount(), ResourceManager::state(), ResourceManager::get(), ResourceManager::set(), Resource::key() */ @@ -88,7 +99,7 @@ class ResourceKey: public Corrade::Utility::MurmurHash2::Digest { }; /** @debugoperator{Magnum::ResourceKey} */ -inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const ResourceKey& value) { +inline Debug operator<<(Debug debug, const ResourceKey& value) { return debug << static_cast&>(value); } @@ -118,7 +129,7 @@ class Resource { * Creates empty resource. Resources are acquired from the manager by * calling ResourceManager::get(). */ - inline Resource(): manager(nullptr), lastCheck(0), _state(ResourceState::Final), data(nullptr) {} + inline 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) { diff --git a/src/ResourceManager.h b/src/ResourceManager.h index 2a3b9ce2b..ac49cd889 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -1,21 +1,30 @@ #ifndef Magnum_ResourceManager_h #define Magnum_ResourceManager_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 +/** @file /ResourceManager.h * @brief Class Magnum::ResourceManager, enum Magnum::ResourceDataState, Magnum::ResourcePolicy */ @@ -30,18 +39,18 @@ namespace Magnum { * * @see ResourceManager::set(), ResourceState */ -enum class ResourceDataState: std::uint8_t { +enum class ResourceDataState: UnsignedByte { /** * The resource is currently loading. Parameter @p data in ResourceManager::set() * should be set to `null`. */ - Loading = int(ResourceState::Loading), + Loading = UnsignedByte(ResourceState::Loading), /** * The resource was not found. Parameter @p data in ResourceManager::set() * should be set to `null`. */ - NotFound = int(ResourceState::NotFound), + NotFound = UnsignedByte(ResourceState::NotFound), /** * The resource can be changed by the manager in the future. This is @@ -49,14 +58,14 @@ enum class ResourceDataState: std::uint8_t { * the data are accessed, but allows changing the data for e.g. debugging * purposes. */ - Mutable = std::uint8_t(ResourceState::Mutable), + Mutable = UnsignedByte(ResourceState::Mutable), /** * The resource cannot be changed by the manager in the future. This is * faster, as Resource instances will ask for the data only one time, thus * suitable for production code. */ - Final = std::uint8_t(ResourceState::Final) + Final = UnsignedByte(ResourceState::Final) }; /** @relates ResourceManager @@ -64,7 +73,7 @@ enum class ResourceDataState: std::uint8_t { @see ResourceManager::set(), ResourceManager::free() */ -enum class ResourcePolicy: std::uint8_t { +enum class ResourcePolicy: UnsignedByte { /** The resource will stay resident for whole lifetime of resource manager. */ Resident, @@ -90,7 +99,7 @@ namespace Implementation { }; template class ResourceManagerData { - template friend class Resource; + template friend class Magnum::Resource; friend class AbstractResourceLoader; ResourceManagerData(const ResourceManagerData&) = delete; @@ -158,7 +167,7 @@ namespace Implementation { /* Cannot change resource with already final state */ CORRADE_ASSERT(it == _data.end() || it->second.state != ResourceDataState::Final, - "ResourceManager::set(): cannot change already final resource", ); + "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)) { @@ -239,7 +248,8 @@ namespace Implementation { } inline ~Data() { - CORRADE_ASSERT(referenceCount == 0, "ResourceManager: cannot destruct it while data are still referenced", ); + CORRADE_ASSERT(referenceCount == 0, + "ResourceManager::~ResourceManager(): destroyed while data are still referenced", ); delete data; } @@ -335,6 +345,8 @@ cube->draw(); @endcode - Destroying resource references and deleting manager instance when nothing references the resources anymore. + +@see AbstractResourceLoader */ /* Due to too much work involved with explicit template instantiation (all Resource combinations, all ResourceManagerData...), this class doesn't have @@ -432,6 +444,16 @@ template class ResourceManager: private Implementation::Resource this->Implementation::ResourceManagerData::set(key, data, state, policy); } + /** + * @brief Set resource data + * + * 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) { + this->Implementation::ResourceManagerData::set(key, data, ResourceDataState::Final, ResourcePolicy::Resident); + } + /** @brief Fallback for not found resources */ template inline T* fallback() { return this->Implementation::ResourceManagerData::fallback(); @@ -470,8 +492,7 @@ template class ResourceManager: private Implementation::Resource /** * @brief Set loader for given type of resources * - * The loader will affect only loading of resources requested after - * that. + * See AbstractResourceLoader documentation for more information. */ template inline void setLoader(AbstractResourceLoader* loader) { return this->Implementation::ResourceManagerData::setLoader(loader); diff --git a/src/SceneGraph/AbstractCamera.h b/src/SceneGraph/AbstractCamera.h index 8af0eec73..f1128651a 100644 --- a/src/SceneGraph/AbstractCamera.h +++ b/src/SceneGraph/AbstractCamera.h @@ -1,22 +1,31 @@ #ifndef Magnum_SceneGraph_AbstractCamera_h #define Magnum_SceneGraph_AbstractCamera_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::SceneGraph::AbstractCamera, enum AspectRatioPolicy, alias Magnum::SceneGraph::AbstractCamera2D, Magnum::SceneGraph::AbstractCamera3D + * @brief Class Magnum::SceneGraph::AbstractCamera, enum Magnum::SceneGraph::AspectRatioPolicy, alias Magnum::SceneGraph::AbstractCamera2D, Magnum::SceneGraph::AbstractCamera3D */ #include "Math/Matrix3.h" @@ -32,7 +41,7 @@ namespace Magnum { namespace SceneGraph { @see AbstractCamera::setAspectRatioPolicy() */ -enum class AspectRatioPolicy: std::uint8_t { +enum class AspectRatioPolicy: UnsignedByte { NotPreserved, /**< Don't preserve aspect ratio (default) */ Extend, /**< Extend on larger side of view */ Clip /**< Clip on smaller side of view */ @@ -40,7 +49,7 @@ enum class AspectRatioPolicy: std::uint8_t { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - template typename DimensionTraits::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2& projectionScale, const Math::Vector2& viewport); + template typename DimensionTraits::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2& projectionScale, const Vector2i& viewport); } #endif @@ -53,21 +62,22 @@ instantiatable, use Camera2D or Camera3D subclasses instead. @section AbstractCamera-explicit-specializations Explicit template specializations The following specialization are explicitly compiled into SceneGraph library. -For other specializations you have to use AbstractCamera.hpp implementation -file to avoid linker errors. See also relevant sections in +For other specializations (e.g. using Double type) you have to use +AbstractCamera.hpp implementation file to avoid linker errors. See also +relevant sections in @ref Camera2D-explicit-specializations "Camera2D" and @ref Camera3D-explicit-specializations "Camera3D" class documentation or @ref compilation-speedup-hpp for more information. - - @ref AbstractCamera "AbstractCamera<2>" - - @ref AbstractCamera "AbstractCamera<3>" + - @ref AbstractCamera "AbstractCamera<2, Float>" + - @ref AbstractCamera "AbstractCamera<3, Float>" -@see Drawable, DrawableGroup, AbstractCamera2D, AbstractCamera3D +@see @ref scenegraph, Drawable, DrawableGroup, AbstractCamera2D, AbstractCamera3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template +template #else -template +template #endif class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature { public: @@ -75,9 +85,7 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature* object): AbstractFeature(object), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) { - AbstractFeature::setCachedTransformations(AbstractFeature::CachedTransformation::InvertedAbsolute); - } + explicit AbstractCamera(AbstractObject* object); virtual ~AbstractCamera() = 0; @@ -121,7 +129,7 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature viewport() const { return _viewport; } + inline Vector2i viewport() const { return _viewport; } /** * @brief Set viewport size @@ -130,7 +138,7 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature& size); + virtual void setViewport(const Vector2i& size); /** * @brief Draw @@ -158,11 +166,10 @@ class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature::MatrixType _projectionMatrix; typename DimensionTraits::MatrixType _cameraMatrix; - Math::Vector2 _viewport; + Vector2i _viewport; }; -template inline AbstractCamera::~AbstractCamera() {} - +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base for two-dimensional cameras @@ -170,15 +177,13 @@ Convenience alternative to %AbstractCamera<2, T>. See AbstractCamera for more information. @note Not available on GCC < 4.7. Use %AbstractCamera<2, T> instead. @see AbstractCamera3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractCamera2D = AbstractCamera<2, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractCamera<2, T = GLfloat> AbstractCamera2D; +template #endif +using AbstractCamera2D = AbstractCamera<2, T>; /** @brief Base for three-dimensional cameras @@ -187,14 +192,13 @@ Convenience alternative to %AbstractCamera<3, T>. See AbstractCamera for more information. @note Not available on GCC < 4.7. Use %AbstractCamera<3, T> instead. @see AbstractCamera2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractCamera3D = AbstractCamera<3, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractCamera<3, T = GLfloat> AbstractCamera3D; +template +#endif +using AbstractCamera3D = AbstractCamera<3, T>; #endif }} diff --git a/src/SceneGraph/AbstractCamera.hpp b/src/SceneGraph/AbstractCamera.hpp index bbd6166e1..f2ecd960b 100644 --- a/src/SceneGraph/AbstractCamera.hpp +++ b/src/SceneGraph/AbstractCamera.hpp @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractCamera_hpp #define Magnum_SceneGraph_AbstractCamera_hpp /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -30,7 +39,7 @@ namespace Magnum { namespace SceneGraph { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { -template class Camera {}; +template class Camera {}; template class Camera<2, T> { public: @@ -45,12 +54,12 @@ template class Camera<3, T> { } }; -template typename DimensionTraits::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2& projectionScale, const Math::Vector2& viewport) { +template typename DimensionTraits::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2& projectionScale, const Vector2i& viewport) { /* Don't divide by zero / don't preserve anything */ if(projectionScale.x() == 0 || projectionScale.y() == 0 || viewport.x() == 0 || viewport.y() == 0 || aspectRatioPolicy == AspectRatioPolicy::NotPreserved) return {}; - Math::Vector2 relativeAspectRatio = Math::Vector2::from(viewport)*projectionScale; + Math::Vector2 relativeAspectRatio = Math::Vector2(viewport)*projectionScale; /* Extend on larger side = scale larger side down Clip on smaller side = scale smaller side up */ @@ -63,18 +72,24 @@ template typename DimensionTraits AbstractCamera* AbstractCamera::setAspectRatioPolicy(AspectRatioPolicy policy) { +template AbstractCamera::AbstractCamera(AbstractObject* object): AbstractFeature(object), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) { + AbstractFeature::setCachedTransformations(AbstractFeature::CachedTransformation::InvertedAbsolute); +} + +template AbstractCamera::~AbstractCamera() {} + +template AbstractCamera* AbstractCamera::setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; fixAspectRatio(); return this; } -template void AbstractCamera::setViewport(const Math::Vector2& size) { +template void AbstractCamera::setViewport(const Vector2i& size) { _viewport = size; fixAspectRatio(); } -template void AbstractCamera::draw(DrawableGroup& group) { +template void AbstractCamera::draw(DrawableGroup& group) { AbstractObject* scene = AbstractFeature::object()->sceneObject(); CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", ); diff --git a/src/SceneGraph/AbstractFeature.h b/src/SceneGraph/AbstractFeature.h index 4506c2d4f..e77137611 100644 --- a/src/SceneGraph/AbstractFeature.h +++ b/src/SceneGraph/AbstractFeature.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractFeature_h #define Magnum_SceneGraph_AbstractFeature_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,18 +31,19 @@ #include #include -#include "AbstractObject.h" +#include "Magnum.h" +#include "SceneGraph/AbstractObject.h" namespace Magnum { namespace SceneGraph { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - enum class FeatureCachedTransformation: std::uint8_t { + enum class FeatureCachedTransformation: UnsignedByte { Absolute = 1 << 0, InvertedAbsolute = 1 << 1 }; - typedef Corrade::Containers::EnumSet FeatureCachedTransformations; + typedef Corrade::Containers::EnumSet FeatureCachedTransformations; CORRADE_ENUMSET_OPERATORS(FeatureCachedTransformations) } @@ -118,9 +128,9 @@ which is automatically extracted from the pointer in our constructor. @see AbstractFeature2D, AbstractFeature3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template class AbstractFeature: private Corrade::Containers::LinkedListItem, AbstractObject> +template class AbstractFeature: private Corrade::Containers::LinkedListItem, AbstractObject> #else -template class AbstractFeature +template class AbstractFeature #endif { friend class Corrade::Containers::LinkedList>; @@ -132,8 +142,8 @@ template class AbstractFeature * @brief Constructor * @param object %Object holding this feature */ - inline AbstractFeature(AbstractObject* object) { - object->Corrade::Containers::LinkedList>::insert(this); + inline explicit AbstractFeature(AbstractObject* object) { + object->Corrade::Containers::template LinkedList>::insert(this); } virtual ~AbstractFeature() = 0; @@ -186,7 +196,7 @@ template class AbstractFeature #ifndef DOXYGEN_GENERATING_OUTPUT typedef Implementation::FeatureCachedTransformation CachedTransformation; #else - enum class CachedTransformation: std::uint8_t { + enum class CachedTransformation: UnsignedByte { /** * Absolute transformation is cached. * @@ -212,7 +222,7 @@ template class AbstractFeature #ifndef DOXYGEN_GENERATING_OUTPUT typedef Implementation::FeatureCachedTransformations CachedTransformations; #else - typedef Corrade::Containers::EnumSet CachedTransformations; + typedef Corrade::Containers::EnumSet CachedTransformations; #endif /** @@ -280,10 +290,11 @@ 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&) {} +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 @@ -291,15 +302,13 @@ Convenience alternative to %AbstractFeature<2, T>. See AbstractFeature for more information. @note Not available on GCC < 4.7. Use %AbstractFeature<2, T> instead. @see AbstractFeature3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractFeature2D = AbstractFeature<2, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractFeature<2, T = GLfloat> AbstractFeature2D; +template #endif +using AbstractFeature2D = AbstractFeature<2, T>; /** @brief Base for three-dimensional features @@ -308,14 +317,13 @@ Convenience alternative to %AbstractFeature<3, T>. See AbstractFeature for more information. @note Not available on GCC < 4.7. Use %AbstractFeature<3, T> instead. @see AbstractFeature2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractFeature3D = AbstractFeature<3, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractFeature<2, T = GLfloat> AbstractFeature3D; +template +#endif +using AbstractFeature3D = AbstractFeature<3, T>; #endif }} diff --git a/src/SceneGraph/AbstractGroupedFeature.h b/src/SceneGraph/AbstractGroupedFeature.h index ffe33b1be..e0273d3a0 100644 --- a/src/SceneGraph/AbstractGroupedFeature.h +++ b/src/SceneGraph/AbstractGroupedFeature.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractGroupedFeature_h #define Magnum_SceneGraph_AbstractGroupedFeature_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -44,13 +53,13 @@ class Drawable: public SceneGraph::AbstractGroupedFeature3D { typedef SceneGraph::FeatureGroup3D DrawableGroup; @endcode -@see AbstractGroupedFeature2D, AbstractGroupedFeature3D, FeatureGroup, - FeatureGroup2D, FeatureGroup3D +@see @ref scenegraph, AbstractGroupedFeature2D, AbstractGroupedFeature3D, + FeatureGroup, FeatureGroup2D, FeatureGroup3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template +template #else -template +template #endif class AbstractGroupedFeature: public AbstractFeature { friend class FeatureGroup; @@ -62,9 +71,9 @@ class AbstractGroupedFeature: public AbstractFeature { * @param group Group this feature belongs to * * Adds the feature to the object and to group, if specified. - * @see FeatureGroup::add(), FeatureGroup::remove() + * @see FeatureGroup::add() */ - inline AbstractGroupedFeature(AbstractObject* object, FeatureGroup* group = nullptr): AbstractFeature(object), _group(nullptr) { + inline explicit AbstractGroupedFeature(AbstractObject* object, FeatureGroup* group = nullptr): AbstractFeature(object), _group(nullptr) { if(group) group->add(static_cast(this)); } @@ -92,40 +101,38 @@ class AbstractGroupedFeature: public AbstractFeature { FeatureGroup* _group; }; +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base for two-dimensional grouped features Convenience alternative to %AbstractGroupedFeature<2, Derived, T>. See AbstractGroupedFeature for more information. -@see AbstractGroupedFeature3D @note Not available on GCC < 4.7. Use %AbstractGroupedFeature<2, Derived, T> instead. -@todoc Remove workaround when Doxygen supports alias template +@see AbstractGroupedFeature3D */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractGroupedFeature2D = AbstractGroupedFeature<2, Derived, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractGroupedFeature<2, Derived, T = GLfloat> AbstractGroupedFeature2D; +template #endif +using AbstractGroupedFeature2D = AbstractGroupedFeature<2, Derived, T>; /** @brief Base for three-dimensional grouped features Convenience alternative to %AbstractGroupedFeature<3, Derived, T>. See AbstractGroupedFeature for more information. -@see AbstractGroupedFeature2D @note Not available on GCC < 4.7. Use %AbstractGroupedFeature<3, Derived, T> instead. -@todoc Remove workaround when Doxygen supports alias template +@see AbstractGroupedFeature2D */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractGroupedFeature3D = AbstractGroupedFeature<3, Derived, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractGroupedFeature<3, Derived, T = GLfloat> AbstractGroupedFeature3D; +template +#endif +using AbstractGroupedFeature3D = AbstractGroupedFeature<3, Derived, T>; #endif }} diff --git a/src/SceneGraph/AbstractObject.h b/src/SceneGraph/AbstractObject.h index 08f9a4ac5..41c751230 100644 --- a/src/SceneGraph/AbstractObject.h +++ b/src/SceneGraph/AbstractObject.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractObject_h #define Magnum_SceneGraph_AbstractObject_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -25,6 +34,8 @@ #include "DimensionTraits.h" #include "SceneGraph.h" +#include "SceneGraph/magnumSceneGraphVisibility.h" + namespace Magnum { namespace SceneGraph { /** @@ -46,20 +57,21 @@ for(AbstractFeature* feature = o->firstFeature(); feature; feature = feature->ne @see AbstractObject2D, AbstractObject3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template class AbstractObject: private Corrade::Containers::LinkedList> +template class MAGNUM_SCENEGRAPH_EXPORT AbstractObject: private Corrade::Containers::LinkedList> #else -template class AbstractObject +template class AbstractObject #endif { friend class Corrade::Containers::LinkedList>; friend class Corrade::Containers::LinkedListItem, AbstractObject>; - friend AbstractFeature::AbstractFeature(AbstractObject*); + friend class AbstractFeature; public: /** @brief Feature object type */ typedef AbstractFeature FeatureType; - inline virtual ~AbstractObject() {} + explicit AbstractObject(); + virtual ~AbstractObject(); /** @brief Whether this object has features */ inline bool hasFeatures() const { @@ -101,6 +113,13 @@ template class AbstractObject /** @{ @name Object transformation */ + /** + * @brief Transformation matrix + * + * @see Object::transformation() + */ + virtual typename DimensionTraits::MatrixType transformationMatrix() const = 0; + /** * @brief Transformation matrix relative to root object * @@ -117,7 +136,7 @@ template class AbstractObject * Object type, use typesafe Object::transformations() when * possible. */ - virtual std::vector::MatrixType> transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix = typename DimensionTraits::MatrixType()) const = 0; + virtual std::vector::MatrixType> transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix = (typename DimensionTraits::MatrixType())) const = 0; /*@}*/ @@ -178,6 +197,7 @@ template class AbstractObject /*@}*/ }; +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base for two-dimensional objects @@ -185,15 +205,13 @@ Convenience alternative to %AbstractObject<2, T>. See AbstractObject for more information. @note Not available on GCC < 4.7. Use %AbstractObject<2, T> instead. @see AbstractObject3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractObject2D = AbstractObject<2, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractObject<2, T = GLfloat> AbstractObject2D; +template #endif +using AbstractObject2D = AbstractObject<2, T>; /** @brief Base for three-dimensional objects @@ -202,14 +220,13 @@ Convenience alternative to %AbstractObject<3, T>. See AbstractObject for more information. @note Not available on GCC < 4.7. Use %AbstractObject<3, T> instead. @see AbstractObject2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractObject3D = AbstractObject<3, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractObject<3, T = GLfloat> AbstractObject3D; +template +#endif +using AbstractObject3D = AbstractObject<3, T>; #endif }} diff --git a/src/SceneGraph/AbstractTransformation.h b/src/SceneGraph/AbstractTransformation.h index 718d6c09f..1717d576f 100644 --- a/src/SceneGraph/AbstractTransformation.h +++ b/src/SceneGraph/AbstractTransformation.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractTransformation_h #define Magnum_SceneGraph_AbstractTransformation_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -24,6 +33,8 @@ #include "DimensionTraits.h" #include "SceneGraph.h" +#include "SceneGraph/magnumSceneGraphVisibility.h" + namespace Magnum { namespace SceneGraph { /** @@ -34,26 +45,27 @@ for introduction. @section AbstractTransformation-subclassing Subclassing -When sublassing, you have to: +When subclassing, you have to: -- Implement all members described in **Subclass implementation** group above +- Implement all members listed in **Subclass implementation** group above - Provide implicit (parameterless) constructor -@see AbstractTransformation2D, AbstractTransformation3D +@see @ref scenegraph, AbstractTransformation2D, AbstractTransformation3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template +template #else -template +template #endif -class AbstractTransformation { +class MAGNUM_SCENEGRAPH_EXPORT AbstractTransformation { public: /** @brief Underlying floating-point type */ typedef T Type; /** @brief Dimension count */ - static const std::uint8_t Dimensions = dimensions; + static const UnsignedInt Dimensions = dimensions; + explicit AbstractTransformation(); virtual ~AbstractTransformation() = 0; #ifdef DOXYGEN_GENERATING_OUTPUT @@ -125,10 +137,16 @@ class AbstractTransformation { /*@}*/ #endif + + /** + * @brief Reset object transformation + * @return Pointer to self (for method chaining) + */ + virtual AbstractTransformation* resetTransformation() = 0; }; /** @brief Transformation type */ -enum class TransformationType: std::uint8_t { +enum class TransformationType: UnsignedByte { /** Global transformation, applied after all other transformations. */ Global = 0x00, @@ -136,8 +154,7 @@ enum class TransformationType: std::uint8_t { Local = 0x01 }; -template inline AbstractTransformation::~AbstractTransformation() {} - +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base for two-dimensional transformations @@ -146,15 +163,13 @@ AbstractTransformation for more information. @note Not available on GCC < 4.7. Use %AbstractTransformation<2, T> instead. @see AbstractTransformation3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractTransformation2D = AbstractTransformation<2, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractTransformation<2, T = GLfloat> AbstractTransformation2D; +template #endif +using AbstractTransformation2D = AbstractTransformation<2, T>; /** @brief Base for three-dimensional transformations @@ -164,14 +179,13 @@ AbstractTransformation for more information. @note Not available on GCC < 4.7. Use %AbstractTransformation<3, T> instead. @see AbstractTransformation2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractTransformation3D = AbstractTransformation<3, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef AbstractTransformation<3, T = GLfloat> AbstractTransformation3D; +template +#endif +using AbstractTransformation3D = AbstractTransformation<3, T>; #endif }} diff --git a/src/SceneGraph/AbstractTranslationRotation2D.h b/src/SceneGraph/AbstractTranslationRotation2D.h index e06566397..4186fee24 100644 --- a/src/SceneGraph/AbstractTranslationRotation2D.h +++ b/src/SceneGraph/AbstractTranslationRotation2D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractTranslationRotation2D_h #define Magnum_SceneGraph_AbstractTranslationRotation2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,15 +35,17 @@ namespace Magnum { namespace SceneGraph { /** @brief Base for two-dimensional transformations supporting translation and rotation -@see AbstractTranslationRotation3D +@see @ref scenegraph, AbstractTranslationRotation3D */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class AbstractTranslationRotation2D: public AbstractTransformation<2, T> { public: + explicit AbstractTranslationRotation2D() = default; + /** * @brief Translate object * @param vector Translation vector @@ -47,13 +58,11 @@ class AbstractTranslationRotation2D: public AbstractTransformation<2, T> { /** * @brief Rotate object - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) - * - * @see deg(), rad() */ - virtual AbstractTranslationRotation2D* rotate(T angle, TransformationType type = TransformationType::Global) = 0; + virtual AbstractTranslationRotation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) = 0; }; }} diff --git a/src/SceneGraph/AbstractTranslationRotation3D.h b/src/SceneGraph/AbstractTranslationRotation3D.h index 1175b8af2..99f735d58 100644 --- a/src/SceneGraph/AbstractTranslationRotation3D.h +++ b/src/SceneGraph/AbstractTranslationRotation3D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractTranslationRotation3D_h #define Magnum_SceneGraph_AbstractTranslationRotation3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -27,15 +36,17 @@ namespace Magnum { namespace SceneGraph { /** @brief Base for three-dimensional transformations supporting translation and rotation -@see AbstractTranslationRotation2D +@see @ref scenegraph, AbstractTranslationRotation2D */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { public: + explicit AbstractTranslationRotation3D() = default; + /** * @brief Translate object * @param vector Translation vector @@ -48,54 +59,52 @@ class AbstractTranslationRotation3D: public AbstractTransformation<3, T> { /** * @brief Rotate object - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param normalizedAxis Normalized rotation axis * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see deg(), rad(), Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis() + * @see rotateX(), rotateY(), rotateZ(), Vector3::xAxis(), + * Vector3::yAxis(), Vector3::zAxis() */ - virtual AbstractTranslationRotation3D* rotate(T angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) = 0; + virtual AbstractTranslationRotation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) = 0; /** * @brief Rotate object around X axis - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) * * In some implementations faster than calling * `rotate(angle, Vector3::xAxis())`. - * @see deg(), rad() */ - virtual AbstractTranslationRotation3D* rotateX(T angle, TransformationType type = TransformationType::Global) { + virtual AbstractTranslationRotation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { return rotate(angle, Math::Vector3::xAxis(), type); } /** * @brief Rotate object around Y axis - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) * * In some implementations faster than calling * `rotate(angle, Vector3::yAxis())`. - * @see deg(), rad() */ - virtual AbstractTranslationRotation3D* rotateY(T angle, TransformationType type = TransformationType::Global) { + virtual AbstractTranslationRotation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { return rotate(angle, Math::Vector3::yAxis(), type); } /** * @brief Rotate object around Z axis - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) * * In some implementations faster than calling * `rotate(angle, Vector3::zAxis())`. - * @see deg(), rad() */ - virtual AbstractTranslationRotation3D* rotateZ(T angle, TransformationType type = TransformationType::Global) { + virtual AbstractTranslationRotation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { return rotate(angle, Math::Vector3::zAxis(), type); } }; diff --git a/src/SceneGraph/AbstractTranslationRotationScaling2D.h b/src/SceneGraph/AbstractTranslationRotationScaling2D.h index 26da23b36..4b9458631 100644 --- a/src/SceneGraph/AbstractTranslationRotationScaling2D.h +++ b/src/SceneGraph/AbstractTranslationRotationScaling2D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractTranslationRotationScaling2D_h #define Magnum_SceneGraph_AbstractTranslationRotationScaling2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,15 +35,17 @@ namespace Magnum { namespace SceneGraph { /** @brief Base for two-dimensional transformations supporting translation, rotation and scaling -@see AbstractTranslationRotationScaling2D +@see @ref scenegraph, AbstractTranslationRotationScaling2D */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class AbstractTranslationRotationScaling2D: public AbstractTranslationRotation2D { public: + explicit AbstractTranslationRotationScaling2D() = default; + /** * @brief Scale object * @param vector Scaling vector diff --git a/src/SceneGraph/AbstractTranslationRotationScaling3D.h b/src/SceneGraph/AbstractTranslationRotationScaling3D.h index ab4ffd4f6..60049e776 100644 --- a/src/SceneGraph/AbstractTranslationRotationScaling3D.h +++ b/src/SceneGraph/AbstractTranslationRotationScaling3D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_AbstractTranslationRotationScaling3D_h #define Magnum_SceneGraph_AbstractTranslationRotationScaling3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,15 +35,17 @@ namespace Magnum { namespace SceneGraph { /** @brief Base for three-dimensional transformations supporting translation, rotation and scaling -@see AbstractTranslationRotationScaling2D +@see @ref scenegraph, AbstractTranslationRotationScaling2D */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class AbstractTranslationRotationScaling3D: public AbstractTranslationRotation3D { public: + explicit AbstractTranslationRotationScaling3D() = default; + /** * @brief Scale object * @param vector Scaling vector diff --git a/src/SceneGraph/Animable.cpp b/src/SceneGraph/Animable.cpp new file mode 100644 index 000000000..a424ef9bd --- /dev/null +++ b/src/SceneGraph/Animable.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 "Animable.hpp" + +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>; +#endif + +Debug operator<<(Debug debug, AnimationState value) { + switch(value) { + #define _c(value) case AnimationState::value: return debug << "SceneGraph::AnimationState::" #value; + _c(Stopped) + _c(Paused) + _c(Running) + #undef _c + } + + return debug << "SceneGraph::AnimationState::(invalid)"; +} + +}} diff --git a/src/SceneGraph/Animable.h b/src/SceneGraph/Animable.h new file mode 100644 index 000000000..1d5cba5a9 --- /dev/null +++ b/src/SceneGraph/Animable.h @@ -0,0 +1,368 @@ +#ifndef Magnum_SceneGraph_Animable_h +#define Magnum_SceneGraph_Animable_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::SceneGraph::Animable, enum Magnum::SceneGraph::AnimationState + */ + +#include "AbstractGroupedFeature.h" + +#include "magnumSceneGraphVisibility.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Animation state + +@see Animable::setState() +*/ +enum class AnimationState: UnsignedByte { + /** + * The animation is stopped. The animation will be started from the + * beginning when state is changed to @ref AnimationState "AnimationState::Running". + */ + Stopped, + + /** + * The animation is stopped. The animation will continue from paused + * position when state is changed to @ref AnimationState "AnimationState::Running". + */ + Paused, + + /** The animation is running. */ + Running +}; + +/** @debugoperator{Magnum::SceneGraph::Animable} */ +Debug MAGNUM_SCENEGRAPH_EXPORT operator<<(Debug debug, AnimationState value); + +/** +@brief %Animable + +Adds animation feature to object. Each %Animable is part of some AnimableGroup, +which takes care of running the animations. + +@section Animable-usage Usage + +First thing is add Animable feature to some object and implement +animationStep(). You can do it conveniently using multiple inheritance (see +@ref scenegraph-features for introduction). Override animationStep() to +implement your animation, the function provides both absolute animation +time and time delta. Example: +@code +typedef SceneGraph::Object> Object3D; +typedef SceneGraph::Scene> Scene3D; + +class AnimableObject: public Object3D, SceneGraph::Animable3D<> { + public: + AnimableObject(Object* parent = nullptr, SceneGraph::DrawableGroup3D<>* group = nullptr): Object3D(parent), SceneGraph::Animable3D<>(this, group) { + setDuration(10.0f); + // ... + } + + void animationStep(Float time, Float delta) override { + rotateX(15.0_degf*delta); // rotate at 15 degrees per second + } +} +@endcode + +Then add the object to your scene and some animation group. You can also use +AnimableGroup::add() and AnimableGroup::remove() instead of passing the group +in the constructor. The animation is initially in stopped state and without +repeat, see setState(), setRepeated() and setRepeatCount() for more information. +@code +Scene3D scene; +SceneGraph::AnimableGroup3D<> animables; + +(new AnimableObject(&scene, &animables)) + ->setState(SceneGraph::AnimationState::Running); +// ... +@endcode + +Animation step is performed by calling AnimableGroup::step() in your draw event +implementation. The function expects absolute time from relative to some fixed +point in the past and time delta (i.e. duration of the frame). You can use +Timeline for that, see its documentation for more information. +@code +Timeline timeline; +timeline.start(); + +void MyApplication::drawEvent() { + animables.step(timeline.lastFrameTime(), timeline.lastFrameDuration()); + + // ... + + timeline.nextFrame(); +} +@endcode + +@section Animable-performance Using animable groups to improve performance + +AnimableGroup is optimized for case when no animation is running - it just +puts itself to rest and waits until some animation changes its state to +@ref AnimationState "AnimationState::Running" again. If you put animations +which are not pernamently running to separate group, they will not be always +traversed when calling AnimableGroup::step(), saving precious frame time. + +@section Animable-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 +Animable.hpp implementation file to avoid linker errors. See also +@ref compilation-speedup-hpp for more information. + + - @ref Animable "Animable<2, Float>", @ref AnimableGroup "AnimableGroup<2, Float>" + - @ref Animable "Animable<3, Float>", @ref AnimableGroup "AnimableGroup<3, Float>" + +@see @ref scenegraph, Animable2D, Animable3D, AnimableGroup2D, AnimableGroup3D +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class MAGNUM_SCENEGRAPH_EXPORT Animable: public AbstractGroupedFeature, T> { + friend class AnimableGroup; + + public: + /** + * @brief Constructor + * @param object %Object this animable belongs to + * @param group Group this animable belongs to + * + * Creates stopped non-repeating animation with infinite duration, + * adds the feature to the object and also to group, if specified. + * @see setDuration(), setState(), setRepeated(), AnimableGroup::add() + */ + explicit Animable(AbstractObject* object, AnimableGroup* group = nullptr); + + ~Animable(); + + /** @brief Animation duration */ + inline Float duration() const { return _duration; } + + /** @brief Animation state */ + inline AnimationState state() const { return currentState; } + + /** + * @brief Set animation state + * @return Pointer to self (for method chaining) + * + * Note that changing state from @ref AnimationState "AnimationState::Stopped" + * to @ref AnimationState "AnimationState::Paused" is ignored and + * animation remains in @ref AnimationState "AnimationState::Stopped" + * state. See also animationStep() for more information. + * @see animationStarted(), animationPaused(), animationResumed(), + * animationStopped() + */ + Animable* setState(AnimationState state); + + /** + * @brief Whether the animation is repeated + * + * @see repeatCount() + */ + inline bool isRepeated() const { return _repeated; } + + /** + * @brief Enable/disable repeated animation + * @return Pointer to self (for method chaining) + * + * Default is `false`. + * @see setRepeatCount() + */ + inline Animable* setRepeated(bool repeated) { + _repeated = repeated; + return this; + } + + /** + * @brief Repeat count + * + * @see isRepeated() + */ + inline UnsignedShort repeatCount() const { return _repeatCount; } + + /** + * @brief Set repeat count + * @return Pointer to self (for method chaining) + * + * Has effect only if repeated animation is enabled. `0` means + * infinitely repeated animation. Default is `0`. + * @see setRepeated() + */ + inline Animable* setRepeatCount(UnsignedShort count) { + _repeatCount = count; + return this; + } + + /** + * @brief %Animable group containing this animable + * + * If the animable doesn't belong to any group, returns `nullptr`. + */ + AnimableGroup* group(); + const AnimableGroup* group() const; /**< @overload */ + + protected: + /** + * @brief Set animation duration + * @return Pointer to self (for method chaining) + * + * Sets duration of the animation cycle in seconds. Set to `0.0f` for + * infinite non-repeating animation. Default is `0.0f`. + */ + /* Protected so only animation implementer can change it */ + inline Animable* setDuration(Float duration) { + _duration = duration; + return this; + } + + /** + * @brief Perform animation step + * @param time Time from start of the animation + * @param delta Time delta for current frame + * + * This function is periodically called from AnimableGroup::step() if + * the animation state is set to @ref AnimationState "AnimationState::Running". + * After animation duration is exceeded and repeat is not enabled or + * repeat count is exceeded, the animation state is set to + * @ref AnimationState "AnimationState::Stopped". + * + * If the animation is resumed from @ref AnimationState "AnimationState::Paused", + * this function is called with @p time continuing from the point + * when it was paused. If the animation is resumed from + * @ref AnimationState "AnimationState::Stopped", @p time starts with + * zero. + * + * @see state(), duration(), isRepeated(), repeatCount() + */ + virtual void animationStep(Float time, Float delta) = 0; + + /** + * @brief Action on animation start + * + * Called from AnimableGroup::step() when state is changed from + * @ref AnimationState "AnimationState::Stopped" to + * @ref AnimationState "AnimationState::Running" and before first + * animationStep() is called. + * + * Default implementation does nothing. + * + * @see setState() + */ + inline virtual void animationStarted() {} + + /** + * @brief Action on animation pause + * + * Called from AnimableGroup::step() when state changes from + * @ref AnimationState "AnimationState::Running" to + * @ref AnimationState "AnimationState::Paused" and after last + * animationStep() is called. + * + * Default implementation does nothing. + * + * @see setState() + */ + inline virtual void animationPaused() {} + + /** + * @brief Action on animation resume + * + * Called from AnimableGroup::step() when state changes from + * @ref AnimationState "AnimationState::Paused" to + * @ref AnimationState "AnimationState::Running" and before first + * animationStep() is called. + * + * Default implementation does nothing. + * + * @see setState() + */ + inline virtual void animationResumed() {} + + /** + * @brief Action on animation stop + * + * Called from AnimableGroup::step() when state changes from either + * @ref AnimationState "AnimationState::Running" or + * @ref AnimationState "AnimationState::Paused" to + * @ref AnimationState "AnimationState::Stopped" and after last + * animationStep() is called. + * + * You may want to use this function to properly finish the animation + * in case the framerate is not high enough to have animationStep() + * called enough times. Default implementation does nothing. + * + * @see setState() + */ + inline virtual void animationStopped() {} + + private: + Float _duration; + Float startTime, pauseTime; + AnimationState previousState; + AnimationState currentState; + bool _repeated; + UnsignedShort _repeatCount; + UnsignedShort repeats; +}; + +#ifndef CORRADE_GCC46_COMPATIBILITY +/** +@brief Two-dimensional drawable + +Convenience alternative to %Animable<2, T>. See Animable for more +information. +@note Not available on GCC < 4.7. Use %Animable<2, T> instead. +@see Animable3D +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +using Animable2D = Animable<2, T>; + +/** +@brief Three-dimensional animable + +Convenience alternative to %Animable<3, T>. See Animable for more +information. +@note Not available on GCC < 4.7. Use %Animable<3, T> instead. +@see Animable2D +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +using Animable3D = Animable<3, T>; +#endif + +}} + +#endif diff --git a/src/SceneGraph/Animable.hpp b/src/SceneGraph/Animable.hpp new file mode 100644 index 000000000..598959bac --- /dev/null +++ b/src/SceneGraph/Animable.hpp @@ -0,0 +1,140 @@ +#ifndef Magnum_SceneGraph_Animable_hpp +#define Magnum_SceneGraph_Animable_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 Animable.h and AnimableGroup.h + */ + +#include "AnimableGroup.h" +#include "Animable.h" + +#include "Timeline.h" + +namespace Magnum { namespace SceneGraph { + +template Animable::Animable(AbstractObject* object, AnimableGroup* group): AbstractGroupedFeature, T>(object, group), _duration(0.0f), startTime(std::numeric_limits::infinity()), pauseTime(-std::numeric_limits::infinity()), previousState(AnimationState::Stopped), currentState(AnimationState::Stopped), _repeated(false), _repeatCount(0), repeats(0) {} + +template Animable::~Animable() {} + +template Animable* Animable::setState(AnimationState state) { + if(currentState == state) return this; + + /* Not allowed (for sanity) */ + if(previousState == AnimationState::Stopped && state == AnimationState::Paused) + return this; + + /* Wake up the group in case no animations are running */ + group()->wakeUp = true; + currentState = state; + return this; +} + +template AnimableGroup* Animable::group() { + return static_cast*>(AbstractGroupedFeature, T>::group()); +} + +template const AnimableGroup* Animable::group() const { + return static_cast*>(AbstractGroupedFeature, T>::group()); +} + +template void AnimableGroup::step(const Float time, const Float delta) { + if(!_runningCount && !wakeUp) return; + wakeUp = false; + + for(std::size_t i = 0; i != this->size(); ++i) { + Animable* animable = (*this)[i]; + + /* The animation was stopped recently, just decrease count of running + animations if the animation was running before */ + if(animable->previousState != AnimationState::Stopped && animable->currentState == AnimationState::Stopped) { + if(animable->previousState == AnimationState::Running) + --_runningCount; + animable->previousState = AnimationState::Stopped; + animable->animationStopped(); + continue; + + /* The animation was paused recently, set pause time to previous frame time */ + } else if(animable->previousState == AnimationState::Running && animable->currentState == AnimationState::Paused) { + animable->previousState = AnimationState::Paused; + animable->pauseTime = time; + --_runningCount; + animable->animationPaused(); + continue; + + /* Skip the rest for not running animations */ + } else if(animable->currentState != AnimationState::Running) { + CORRADE_INTERNAL_ASSERT(animable->previousState == animable->currentState); + continue; + + /* The animation was started recently, set start time to previous frame + time, reset repeat count */ + } else if(animable->previousState == AnimationState::Stopped) { + animable->previousState = AnimationState::Running; + animable->startTime = time; + animable->repeats = 0; + ++_runningCount; + animable->animationStarted(); + + /* The animation was resumed recently, add pause duration to start time */ + } else if(animable->previousState == AnimationState::Paused) { + animable->previousState = AnimationState::Running; + animable->startTime += time - animable->pauseTime; + ++_runningCount; + animable->animationResumed(); + } + + CORRADE_INTERNAL_ASSERT(animable->previousState == AnimationState::Running); + + /* Animation time exceeded duration */ + if(animable->_duration != 0.0f && time-animable->startTime > animable->_duration) { + /* Not repeated or repeat count exceeded, stop */ + if(!animable->_repeated || animable->repeats+1 == animable->_repeatCount) { + animable->previousState = AnimationState::Stopped; + animable->currentState = AnimationState::Stopped; + --_runningCount; + animable->animationStopped(); + continue; + } + + /* Increase repeat count and add duration to startTime */ + ++animable->repeats; + animable->startTime += animable->_duration; + } + + /* Animation is still running, perform animation step */ + CORRADE_ASSERT(time-animable->startTime >= 0.0f, + "SceneGraph::AnimableGroup::step(): animation was started in future - probably wrong time passed", ); + CORRADE_ASSERT(delta >= 0.0f, + "SceneGraph::AnimableGroup::step(): negative delta passed", ); + animable->animationStep(time - animable->startTime, delta); + } + + CORRADE_INTERNAL_ASSERT(_runningCount <= this->size()); +} + +}} + +#endif diff --git a/src/SceneGraph/AnimableGroup.h b/src/SceneGraph/AnimableGroup.h new file mode 100644 index 000000000..e70069d8a --- /dev/null +++ b/src/SceneGraph/AnimableGroup.h @@ -0,0 +1,113 @@ +#ifndef Magnum_SceneGraph_AnimableGroup_h +#define Magnum_SceneGraph_AnimableGroup_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::SceneGraph::AnimableGroup + */ + +#include "FeatureGroup.h" + +#include "magnumSceneGraphVisibility.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Group of animables + +See Animable for more information. +@see @ref scenegraph, AnimableGroup2D, AnimableGroup3D +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup: public FeatureGroup, T> { + friend class Animable; + + public: + /** + * @brief Constructor + */ + inline explicit AnimableGroup(): _runningCount(0), wakeUp(false) {} + + /** + * @brief Count of running animations + * + * @see step() + */ + inline std::size_t runningCount() const { return _runningCount; } + + /** + * @brief Perform animation step + * @param time Absolute time (e.g. Timeline::previousFrameTime()) + * @param delta Time delta for current frame (e.g. Timeline::previousFrameDuration()) + * + * If there are no running animations the function does nothing. + * @see runningCount() + */ + void step(const Float time, const Float delta); + + private: + std::size_t _runningCount; + bool wakeUp; +}; + +#ifndef CORRADE_GCC46_COMPATIBILITY +/** +@brief Two-dimensional drawable + +Convenience alternative to %AnimableGroup<2, T>. See Animable for +more information. +@note Not available on GCC < 4.7. Use %AnimableGroup<2, T> instead. +@see AnimableGroup3D +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +using AnimableGroup2D = AnimableGroup<2, T>; + +/** +@brief Three-dimensional animable + +Convenience alternative to %AnimableGroup<3, T>. See Animable for +more information. +@note Not available on GCC < 4.7. Use %AnimableGroup<3, T> instead. +@see AnimableGroup2D +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +using AnimableGroup3D = AnimableGroup<3, T>; +#endif + +}} + +#endif diff --git a/src/SceneGraph/CMakeLists.txt b/src/SceneGraph/CMakeLists.txt index 1cd0780fd..41bec81e3 100644 --- a/src/SceneGraph/CMakeLists.txt +++ b/src/SceneGraph/CMakeLists.txt @@ -1,5 +1,42 @@ +# +# 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. +# + +# Files shared between main library and unit test library set(MagnumSceneGraph_SRCS - Camera.cpp) + Animable.cpp + Camera.cpp + DualComplexTransformation.cpp + DualQuaternionTransformation.cpp + RigidMatrixTransformation2D.cpp + RigidMatrixTransformation3D.cpp + Object.cpp) + +# Files compiled with different flags for main library and unit test library +set(MagnumSceneGraph_GracefulAssert_SRCS + MatrixTransformation2D.cpp + MatrixTransformation3D.cpp) + set(MagnumSceneGraph_HEADERS AbstractCamera.h AbstractCamera.hpp @@ -11,11 +48,18 @@ set(MagnumSceneGraph_HEADERS AbstractTranslationRotation3D.h AbstractTranslationRotationScaling2D.h AbstractTranslationRotationScaling3D.h + Animable.h + Animable.hpp + AnimableGroup.h Camera2D.h Camera2D.hpp Camera3D.h Camera3D.hpp Drawable.h + DualComplexTransformation.h + DualQuaternionTransformation.h + RigidMatrixTransformation2D.h + RigidMatrixTransformation3D.h FeatureGroup.h MatrixTransformation2D.h MatrixTransformation3D.h @@ -25,15 +69,10 @@ set(MagnumSceneGraph_HEADERS SceneGraph.h magnumSceneGraphVisibility.h) -add_library(MagnumSceneGraphObjects OBJECT ${MagnumSceneGraph_SRCS}) - -# Files compiled with different flags for main library and unit test library -set(MagnumSceneGraph_GracefulAssert_SRCS - MatrixTransformation2D.cpp - MatrixTransformation3D.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 +add_library(MagnumSceneGraphObjects OBJECT ${MagnumSceneGraph_SRCS}) set_target_properties(MagnumSceneGraphObjects PROPERTIES COMPILE_FLAGS "-DMagnumSceneGraphObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") # SceneGraph library @@ -46,13 +85,11 @@ install(TARGETS MagnumSceneGraph DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumSceneGraph_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/SceneGraph) if(BUILD_TESTS) - enable_testing() - # Library with graceful assert for testing add_library(MagnumSceneGraphTestLib SHARED $ ${MagnumSceneGraph_GracefulAssert_SRCS}) - set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) + set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumSceneGraph_EXPORTS") target_link_libraries(MagnumSceneGraphTestLib Magnum) add_subdirectory(Test) diff --git a/src/SceneGraph/Camera.cpp b/src/SceneGraph/Camera.cpp index 1bdc04553..982d76a01 100644 --- a/src/SceneGraph/Camera.cpp +++ b/src/SceneGraph/Camera.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Camera2D.hpp" @@ -19,10 +28,10 @@ namespace Magnum { namespace SceneGraph { #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera<2, GLfloat>; -template class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera<3, GLfloat>; -template class MAGNUM_SCENEGRAPH_EXPORT Camera2D; -template class MAGNUM_SCENEGRAPH_EXPORT Camera3D; +template class AbstractCamera<2, Float>; +template class AbstractCamera<3, Float>; +template class Camera2D; +template class Camera3D; #endif }} diff --git a/src/SceneGraph/Camera2D.h b/src/SceneGraph/Camera2D.h index 072fc6f92..68fea359e 100644 --- a/src/SceneGraph/Camera2D.h +++ b/src/SceneGraph/Camera2D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Camera2D_h #define Magnum_SceneGraph_Camera2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,22 +35,30 @@ namespace Magnum { namespace SceneGraph { /** @brief Camera for two-dimensional scenes -See Drawable documentation for more information. +See Drawable documentation for introduction. The camera by default displays +OpenGL unit cube `[(-1, -1, -1); (1, 1, 1)]` and doesn't do any aspect ratio +correction. Common setup example: +@code +SceneGraph::Camera2D<>* camera = new SceneGraph::Camera2D<>(&cameraObject); +camera->setProjection({4.0f/3.0f, 1.0f}) + ->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend); +@endcode @section Camera2D-explicit-specializations Explicit template specializations The following specialization are explicitly compiled into SceneGraph library. -For other specializations you have to use Camera2D.hpp implementation file to -avoid linker errors. See @ref compilation-speedup-hpp for more information. +For other specializations (e.g. using Double type) you have to use +Camera2D.hpp implementation file to avoid linker errors. See +@ref compilation-speedup-hpp for more information. - - @ref Camera2D "Camera2D" + - @ref Camera2D "Camera2D" -@see Camera3D, Drawable, DrawableGroup +@see @ref scenegraph, Camera3D, Drawable, DrawableGroup */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class MAGNUM_SCENEGRAPH_EXPORT Camera2D: public AbstractCamera<2, T> { public: @@ -50,17 +67,16 @@ class MAGNUM_SCENEGRAPH_EXPORT Camera2D: public AbstractCamera<2, T> { * @param object %Object holding this feature * * Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions). - * @see setOrthographic() + * @see setProjection() */ - inline Camera2D(AbstractObject<2, T>* object): AbstractCamera<2, T>(object) {} + explicit Camera2D(AbstractObject<2, T>* object); /** * @brief Set projection * @param size Size of the view * @return Pointer to self (for method chaining) * - * The area of given size will be scaled down to range @f$ [-1; 1] @f$ - * on all directions. + * @see Matrix3::projection() */ Camera2D* setProjection(const Math::Vector2& size); diff --git a/src/SceneGraph/Camera2D.hpp b/src/SceneGraph/Camera2D.hpp index 818e5ea19..900d976b1 100644 --- a/src/SceneGraph/Camera2D.hpp +++ b/src/SceneGraph/Camera2D.hpp @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Camera2D_hpp #define Magnum_SceneGraph_Camera2D_hpp /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,9 +35,10 @@ using namespace std; namespace Magnum { namespace SceneGraph { +template Camera2D::Camera2D(AbstractObject<2, T>* object): AbstractCamera<2, T>(object) {} + template Camera2D* Camera2D::setProjection(const Math::Vector2& size) { - /* Scale the volume down so it fits in (-1, 1) in all directions */ - AbstractCamera<2, T>::rawProjectionMatrix = Math::Matrix3::scaling(2.0f/size); + AbstractCamera<2, T>::rawProjectionMatrix = Math::Matrix3::projection(size); AbstractCamera<2, T>::fixAspectRatio(); return this; diff --git a/src/SceneGraph/Camera3D.h b/src/SceneGraph/Camera3D.h index fae8579ff..bb040ebab 100644 --- a/src/SceneGraph/Camera3D.h +++ b/src/SceneGraph/Camera3D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Camera3D_h #define Magnum_SceneGraph_Camera3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,7 +30,7 @@ #include "AbstractCamera.h" -#ifdef WIN32 /* I so HATE windows.h */ +#ifdef _WIN32 /* I so HATE windows.h */ #undef near #undef far #endif @@ -31,56 +40,72 @@ namespace Magnum { namespace SceneGraph { /** @brief Camera for three-dimensional scenes -See Drawable documentation for more information. +See Drawable documentation for introduction. The camera by default displays +OpenGL unit cube `[(-1, -1, -1); (1, 1, 1)]` with orthographic projection and +doesn't do any aspect ratio correction. Common setup example: +@code +SceneGraph::Camera3D<>* camera = new SceneGraph::Camera3D<>(&cameraObject); +camera->setPerspective({}, 0.001f, 100.0f) + ->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend); +@endcode @section Camera3D-explicit-specializations Explicit template specializations The following specialization are explicitly compiled into SceneGraph library. -For other specializations you have to use Camera3D.hpp implementation file to -avoid linker errors. See @ref compilation-speedup-hpp for more information. +For other specializations (e.g. using Double type) you have to use +Camera3D.hpp implementation file to avoid linker errors. See +@ref compilation-speedup-hpp for more information. - - @ref Camera3D "Camera3D" + - @ref Camera3D "Camera3D" -@see Camera2D, Drawable, DrawableGroup +@see @ref scenegraph, Camera2D, Drawable, DrawableGroup */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class MAGNUM_SCENEGRAPH_EXPORT Camera3D: public AbstractCamera<3, T> { public: /** * @brief Constructor * @param object %Object holding this feature - * - * Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions). - * @see setOrthographic(), setPerspective() */ - inline Camera3D(AbstractObject<3, T>* object): AbstractCamera<3, T>(object), _near(0.0f), _far(0.0f) {} + explicit Camera3D(AbstractObject<3, T>* object); /** * @brief Set orthographic projection - * @param size Size of the view - * @param near Near clipping plane - * @param far Far clipping plane + * @param size Size of the view + * @param near Near clipping plane + * @param far Far clipping plane * @return Pointer to self (for method chaining) * - * The volume of given size will be scaled down to range @f$ [-1; 1] @f$ - * on all directions. + * @see setPerspective(), Matrix4::orthographicProjection() */ Camera3D* setOrthographic(const Math::Vector2& size, T near, T far); /** * @brief Set perspective projection - * @param fov Field of view angle - * @param near Near clipping plane - * @param far Far clipping plane + * @param size Size of near clipping plane + * @param near Near clipping plane + * @param far Far clipping plane + * @return Pointer to self (for method chaining) + * + * @see setOrthographic(), Matrix4::perspectiveProjection() + */ + Camera3D* setPerspective(const Math::Vector2& size, T near, T far); + + /** + * @brief Set perspective projection + * @param fov Field of view angle (horizontal) + * @param aspectRatio Aspect ratio + * @param near Near clipping plane + * @param far Far clipping plane * @return Pointer to self (for method chaining) * - * @todo Aspect ratio + * @see setOrthographic(), Matrix4::perspectiveProjection() */ - Camera3D* setPerspective(T fov, T near, T far); + Camera3D* setPerspective(Math::Rad fov, T aspectRatio, T near, T far); /** @brief Near clipping plane */ inline T near() const { return _near; } diff --git a/src/SceneGraph/Camera3D.hpp b/src/SceneGraph/Camera3D.hpp index 23bee2e44..732cba3f7 100644 --- a/src/SceneGraph/Camera3D.hpp +++ b/src/SceneGraph/Camera3D.hpp @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Camera3D_hpp #define Magnum_SceneGraph_Camera3D_hpp /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,42 +31,36 @@ #include "AbstractCamera.hpp" #include "Camera3D.h" -using namespace std; - namespace Magnum { namespace SceneGraph { +template Camera3D::Camera3D(AbstractObject<3, T>* object): AbstractCamera<3, T>(object), _near(T(0)), _far(T(0)) {} + template Camera3D* Camera3D::setOrthographic(const Math::Vector2& size, T near, T far) { + /** @todo Get near/far from the matrix */ _near = near; _far = far; - Math::Vector2 xyScale = T(2.0)/size; - T zScale = T(2.0)/(near-far); - - AbstractCamera<3, T>::rawProjectionMatrix = Math::Matrix4( - xyScale.x(), T(0.0), T(0.0), T(0.0), - T(0.0), xyScale.y(), T(0.0), T(0.0), - T(0.0), T(0.0), zScale, T(0.0), - T(0.0), T(0.0), near*zScale-1, T(1.0) - ); - + AbstractCamera<3, T>::rawProjectionMatrix = Math::Matrix4::orthographicProjection(size, near, far); AbstractCamera<3, T>::fixAspectRatio(); return this; } -template Camera3D* Camera3D::setPerspective(T fov, T near, T far) { +template Camera3D* Camera3D::setPerspective(const Math::Vector2& size, T near, T far) { + /** @todo Get near/far from the matrix */ _near = near; _far = far; - T xyScale = T(1.0)/tan(fov/2); /* == near/size */ - T zScale = T(1.0)/(near-far); + AbstractCamera<3, T>::rawProjectionMatrix = Math::Matrix4::perspectiveProjection(size, near, far); + AbstractCamera<3, T>::fixAspectRatio(); + return this; +} - AbstractCamera<3, T>::rawProjectionMatrix = Matrix4( - xyScale, T(0.0), T(0.0), T(0.0), - T(0.0), xyScale, T(0.0), T(0.0), - T(0.0), T(0.0), (far+near)*zScale, T(-1.0), - T(0.0), T(0.0), (2*far*near)*zScale, T(0.0) - ); +template Camera3D* Camera3D::setPerspective(Math::Rad fov, T aspectRatio, T near, T far) { + /** @todo Get near/far from the matrix */ + _near = near; + _far = far; + AbstractCamera<3, T>::rawProjectionMatrix = Math::Matrix4::perspectiveProjection(fov, aspectRatio, near, far); AbstractCamera<3, T>::fixAspectRatio(); return this; } diff --git a/src/SceneGraph/Drawable.h b/src/SceneGraph/Drawable.h index 9eaca737b..be31aad84 100644 --- a/src/SceneGraph/Drawable.h +++ b/src/SceneGraph/Drawable.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Drawable_h #define Magnum_SceneGraph_Drawable_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -26,7 +35,7 @@ namespace Magnum { namespace SceneGraph { /** @brief %Drawable -Adds drawing function to object. Each %Drawable is part of some DrawableGroup +Adds drawing function to the object. Each %Drawable is part of some DrawableGroup and the whole group is drawn with particular camera using AbstractCamera::draw(). @section Drawable-usage Usage @@ -52,40 +61,77 @@ class DrawableObject: public Object3D, SceneGraph::Drawable3D<> { Then you add these objects to your scene and some drawable group and transform them as you like. You can also use DrawableGroup::add() and -DrawableGroup::remove() for that. +DrawableGroup::remove(). @code Scene3D scene; -SceneGraph::DrawableGroup3D<> group; +SceneGraph::DrawableGroup3D<> drawables; -(new DrawableObject(&scene, &group)) +(new DrawableObject(&scene, &drawables)) ->translate(Vector3::yAxis(-0.3f)) - ->rotateX(deg(30.0f)); -(new AnotherDrawableObject(&scene, &group)) + ->rotateX(30.0_degf); +(new AnotherDrawableObject(&scene, &drawables)) ->translate(Vector3::zAxis(0.5f)); // ... @endcode The last thing you need is Camera attached to some object (thus using its -transformation) and with it you can perform drawing in your draw event: +transformation) and with it you can perform drawing in your draw event +implementation. See Camera2D and Camera3D documentation for more information. @code Camera3D<> camera(&cameraObject); void MyApplication::drawEvent() { - camera.draw(&group); + camera.draw(drawables); + + swapBuffers(); + // ... +} +@endcode + +@section Drawable-performance Using drawable groups to improve performance + +You can organize your drawables to multiple groups to minimize OpenGL state +changes - for example put all objects using the same shader, the same light +setup etc into one group, then put all transparent into another and set common +parameters once for whole group instead of setting them again in each draw() +implementation. Example: +@code +Shaders::PhongShader* shader; +SceneGraph::DrawableGroup3D<> phongObjects, transparentObjects; + +void MyApplication::drawEvent() { + shader->setProjectionMatrix(camera->projectionMatrix()) + ->setLightPosition(lightPosition) + ->setLightColor(lightColor) + ->setAmbientColor(ambientColor); + camera.draw(phongObjects); + + Renderer::setFeature(Renderer::Feature::Blending, true); + camera.draw(transparentObjects); + Renderer::setFeature(Renderer::Feature::Blending, false); + + // ... } @endcode -@see Drawable2D, Drawable3D, DrawableGroup2D, DrawableGroup3D +@see @ref scenegraph, Drawable2D, Drawable3D, DrawableGroup2D, DrawableGroup3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template +template #else -template +template #endif class Drawable: public AbstractGroupedFeature, T> { public: - /** @copydoc AbstractGroupedFeature::AbstractGroupedFeature() */ - inline Drawable(AbstractObject* object, DrawableGroup* group = nullptr): AbstractGroupedFeature, T>(object, group) {} + /** + * @brief Constructor + * @param object %Object this drawable belongs to + * @param drawables Group this drawable belongs to + * + * Adds the feature to the object and also to the group, if specified. + * Otherwise you can use DrawableGroup::add(). + */ + inline explicit Drawable(AbstractObject* object, DrawableGroup* drawables = nullptr): AbstractGroupedFeature, T>(object, drawables) {} /** * @brief Draw the object using given camera @@ -98,6 +144,7 @@ class Drawable: public AbstractGroupedFeature::MatrixType& transformationMatrix, AbstractCamera* camera) = 0; }; +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Two-dimensional drawable @@ -105,15 +152,13 @@ Convenience alternative to %Drawable<2, T>. See Drawable for more information. @note Not available on GCC < 4.7. Use %Drawable<2, T> instead. @see Drawable3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using Drawable2D = Drawable<2, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef Drawable<2, T = GLfloat> Drawable2D; +template #endif +using Drawable2D = Drawable<2, T>; /** @brief Three-dimensional drawable @@ -122,34 +167,38 @@ Convenience alternative to %Drawable<3, T>. See Drawable for more information. @note Not available on GCC < 4.7. Use %Drawable<3, T> instead. @see Drawable2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using Drawable3D = Drawable<3, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef Drawable<3, T = GLfloat> Drawable3D; +template +#endif +using Drawable3D = Drawable<3, T>; #endif /** @brief Group of drawables See Drawable for more information. -@see DrawableGroup2D, DrawableGroup3D -@todoc Remove workaround when Doxygen supports alias template +@see @ref scenegraph, DrawableGroup2D, DrawableGroup3D */ -#if !defined(CORRADE_GCC46_COMPATIBILITY) && !defined(DOXYGEN_GENERATING_OUTPUT) -template using DrawableGroup = FeatureGroup, T>; +#ifndef CORRADE_GCC46_COMPATIBILITY +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -#ifndef DOXYGEN_GENERATING_OUTPUT -template +template +#endif +using DrawableGroup = FeatureGroup, T>; +#else +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -template +template #endif class DrawableGroup: public FeatureGroup, T> {}; #endif +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Group of two-dimensional drawables @@ -157,15 +206,13 @@ Convenience alternative to %DrawableGroup<2, T>. See Drawable for more information. @note Not available on GCC < 4.7. Use %Drawable<2, T> instead. @see DrawableGroup3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using DrawableGroup2D = DrawableGroup<2, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef DrawableGroup<2, T = GLfloat> DrawableGroup2D; +template #endif +using DrawableGroup2D = DrawableGroup<2, T>; /** @brief Group of three-dimensional drawables @@ -174,14 +221,13 @@ Convenience alternative to %DrawableGroup<3, T>. See Drawable for more information. @note Not available on GCC < 4.7. Use %Drawable<3, T> instead. @see DrawableGroup2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using DrawableGroup3D = DrawableGroup<3, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef DrawableGroup<3, T = GLfloat> DrawableGroup3D; +template +#endif +using DrawableGroup3D = DrawableGroup<3, T>; #endif }} diff --git a/src/SceneGraph/DualComplexTransformation.cpp b/src/SceneGraph/DualComplexTransformation.cpp new file mode 100644 index 000000000..56a1f0af5 --- /dev/null +++ b/src/SceneGraph/DualComplexTransformation.cpp @@ -0,0 +1,35 @@ +/* + 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 "DualComplexTransformation.h" + +#include "Object.hpp" + +namespace Magnum { namespace SceneGraph { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +#endif + +}} diff --git a/src/SceneGraph/DualComplexTransformation.h b/src/SceneGraph/DualComplexTransformation.h new file mode 100644 index 000000000..8f96126cb --- /dev/null +++ b/src/SceneGraph/DualComplexTransformation.h @@ -0,0 +1,185 @@ +#ifndef Magnum_SceneGraph_DualComplexTransformation_h +#define Magnum_SceneGraph_DualComplexTransformation_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::SceneGraph::DualComplexTransformation + */ + +#include "Math/DualComplex.h" +#include "AbstractTranslationRotation2D.h" +#include "Object.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Two-dimensional transformation implemented using dual complex numbers + +This class allows only rigid transformation (i.e. only rotation and +translation). +@see @ref scenegraph, Math::DualComplex, DualQuaternionTransformation +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class DualComplexTransformation: public AbstractTranslationRotation2D { + public: + /** @brief Transformation type */ + typedef Math::DualComplex DataType; + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline static Math::DualComplex fromMatrix(const Math::Matrix3& matrix) { + return Math::DualComplex::fromMatrix(matrix); + } + + inline 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) { + return parent*child; + } + + inline static Math::DualComplex inverted(const Math::DualComplex& transformation) { + return transformation.invertedNormalized(); + } + + inline Math::DualComplex transformation() const { + return _transformation; + } + #endif + + /** + * @brief Normalize rotation part + * @return Pointer to self (for method chaining) + * + * Normalizes the rotation part to prevent rounding errors when rotating + * the object subsequently. + * @see DualComplex::normalized() + */ + DualComplexTransformation* normalizeRotation() { + setTransformationInternal(_transformation.normalized()); + return this; + } + + /** + * @brief Set transformation + * @return Pointer to self (for method chaining) + * + * Expects that the dual complex number is normalized. + * @see DualComplex::isNormalized() + */ + DualComplexTransformation* setTransformation(const Math::DualComplex& transformation) { + CORRADE_ASSERT(transformation.isNormalized(), + "SceneGraph::DualComplexTransformation::setTransformation(): the dual complex number is not normalized", this); + setTransformationInternal(transformation); + return this; + } + + inline DualComplexTransformation* resetTransformation() override { + setTransformationInternal({}); + return this; + } + + /** + * @brief Transform object + * @param transformation Transformation + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Expects that the dual complex number is normalized. + * @see DualComplex::isNormalized() + */ + inline DualComplexTransformation* transform(const Math::DualComplex& transformation, TransformationType type = TransformationType::Global) { + CORRADE_ASSERT(transformation.isNormalized(), + "SceneGraph::DualComplexTransformation::transform(): the dual complex number is not normalized", this); + transformInternal(transformation, type); + return this; + } + + /** + * @copydoc AbstractTranslationRotationScaling2D::translate() + * Same as calling transform() with DualComplex::translation(). + */ + inline DualComplexTransformation* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + transformInternal(Math::DualComplex::translation(vector), type); + return this; + } + + /** + * @brief Rotate object + * @param angle Angle (counterclockwise) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with DualComplex::rotation(). + * @see normalizeRotation() + */ + inline DualComplexTransformation* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { + transformInternal(Math::DualComplex::rotation(angle), type); + return this; + } + + /** + * @brief Move object in stacking order + * @param under Sibling object under which to move or `nullptr`, + * 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; + } + + protected: + /* Allow construction only from Object */ + inline explicit DualComplexTransformation() = default; + + private: + /* No assertions fired, for internal use */ + inline 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? */ + if(!static_cast>*>(this)->isScene()) { + _transformation = transformation; + static_cast>*>(this)->setDirty(); + } + } + + /* No assertions fired, for internal use */ + inline void transformInternal(const Math::DualComplex& transformation, TransformationType type) { + setTransformation(type == TransformationType::Global ? + transformation*_transformation : _transformation*transformation); + } + + Math::DualComplex _transformation; +}; + +}} + +#endif diff --git a/src/SceneGraph/DualQuaternionTransformation.cpp b/src/SceneGraph/DualQuaternionTransformation.cpp new file mode 100644 index 000000000..bedf48480 --- /dev/null +++ b/src/SceneGraph/DualQuaternionTransformation.cpp @@ -0,0 +1,35 @@ +/* + 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 "DualQuaternionTransformation.h" + +#include "Object.hpp" + +namespace Magnum { namespace SceneGraph { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +#endif + +}} diff --git a/src/SceneGraph/DualQuaternionTransformation.h b/src/SceneGraph/DualQuaternionTransformation.h new file mode 100644 index 000000000..811450d19 --- /dev/null +++ b/src/SceneGraph/DualQuaternionTransformation.h @@ -0,0 +1,194 @@ +#ifndef Magnum_SceneGraph_DualQuaternionTransformation_h +#define Magnum_SceneGraph_DualQuaternionTransformation_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::SceneGraph::DualQuaternionTransformation + */ + +#include "Math/DualQuaternion.h" +#include "AbstractTranslationRotation3D.h" +#include "Object.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Three-dimensional transformation implemented using dual quaternions + +This class allows only rigid transformation (i.e. only rotation and +translation). +@see @ref scenegraph, Math::DualQuaternion, DualComplexTransformation +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class DualQuaternionTransformation: public AbstractTranslationRotation3D { + public: + /** @brief Underlying transformation type */ + typedef Math::DualQuaternion DataType; + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline 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) { + return transformation.toMatrix(); + } + + inline static Math::DualQuaternion compose(const Math::DualQuaternion& parent, const Math::DualQuaternion& child) { + return parent*child; + } + + inline static Math::DualQuaternion inverted(const Math::DualQuaternion& transformation) { + return transformation.invertedNormalized(); + } + + inline Math::DualQuaternion transformation() const { + return _transformation; + } + #endif + + /** + * @brief Normalize rotation part + * @return Pointer to self (for method chaining) + * + * Normalizes the rotation part to prevent rounding errors when rotating + * the object subsequently. + * @see DualQuaternion::normalized() + */ + DualQuaternionTransformation* normalizeRotation() { + setTransformation(_transformation.normalized()); + return this; + } + + /** + * @brief Set transformation + * @return Pointer to self (for method chaining) + * + * Expects that the dual quaternion is normalized. + * @see DualQuaternion::isNormalized() + */ + DualQuaternionTransformation* setTransformation(const Math::DualQuaternion& transformation) { + CORRADE_ASSERT(transformation.isNormalized(), + "SceneGraph::DualQuaternionTransformation::setTransformation(): the dual quaternion is not normalized", this); + setTransformationInternal(transformation); + return this; + } + + inline DualQuaternionTransformation* resetTransformation() override { + setTransformation({}); + return this; + } + + /** + * @brief Multiply transformation + * @param transformation Transformation + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Expects that the dual quaternion is normalized. + * @see DualQuaternion::isNormalized() + */ + inline DualQuaternionTransformation* transform(const Math::DualQuaternion& transformation, TransformationType type = TransformationType::Global) { + CORRADE_ASSERT(transformation.isNormalized(), + "SceneGraph::DualQuaternionTransformation::transform(): the dual quaternion is not normalized", this); + transformInternal(transformation, type); + return this; + } + + /** + * @copydoc AbstractTranslationRotationScaling3D::translate() + * Same as calling transform() with DualQuaternion::translation(). + */ + inline DualQuaternionTransformation* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + transformInternal(Math::DualQuaternion::translation(vector), type); + return this; + } + + /** + * @brief Rotate object + * @param angle Angle (counterclockwise) + * @param normalizedAxis Normalized rotation axis + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with DualQuaternion::rotation(). + * @see Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), + * normalizeRotation() + */ + inline DualQuaternionTransformation* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { + transformInternal(Math::DualQuaternion::rotation(angle, normalizedAxis), type); + return 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; + } + inline DualQuaternionTransformation* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { + AbstractTranslationRotation3D::rotateY(angle, type); + return this; + } + inline DualQuaternionTransformation* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { + AbstractTranslationRotation3D::rotateZ(angle, type); + return this; + } + #endif + + protected: + /* Allow construction only from Object */ + inline explicit DualQuaternionTransformation() = default; + + private: + /* No assertions fired, for internal use */ + inline 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? */ + if(!static_cast>*>(this)->isScene()) { + _transformation = transformation; + static_cast>*>(this)->setDirty(); + } + } + + /* No assertions fired, for internal use */ + inline void transformInternal(const Math::DualQuaternion& transformation, TransformationType type) { + setTransformation(type == TransformationType::Global ? + transformation*_transformation : _transformation*transformation); + } + + Math::DualQuaternion _transformation; +}; + +}} + +#endif diff --git a/src/SceneGraph/FeatureGroup.h b/src/SceneGraph/FeatureGroup.h index 07d62da23..82f056083 100644 --- a/src/SceneGraph/FeatureGroup.h +++ b/src/SceneGraph/FeatureGroup.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_FeatureGroup_h #define Magnum_SceneGraph_FeatureGroup_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,7 +30,7 @@ #include #include -#include +#include #include "SceneGraph.h" @@ -31,27 +40,27 @@ namespace Magnum { namespace SceneGraph { @brief Group of features See AbstractGroupedFeature for more information. -@see FeatureGroup2D, FeatureGroup3D +@see @ref scenegraph, FeatureGroup2D, FeatureGroup3D */ #ifndef DOXYGEN_GENERATING_OUTPUT -template +template #else -template +template #endif class FeatureGroup { friend class AbstractGroupedFeature; public: + explicit FeatureGroup() = default; + /** * @brief Destructor * - * Deletes all features belogning to this group. + * Removes all features belogning to this group, but not deletes them. */ inline virtual ~FeatureGroup() { - for(auto it = features.begin(); it != features.end(); ++it) { + for(auto it = features.begin(); it != features.end(); ++it) (*it)->_group = nullptr; - delete *it; - } } /** @brief Whether the group is empty */ @@ -72,14 +81,12 @@ class FeatureGroup { /** * @brief Add feature to the group + * @return Pointer to self (for method chaining) * * If the features is part of another group, it is removed from it. * @see remove(), AbstractGroupedFeature::AbstractGroupedFeature() */ - void add(Feature* feature) { - /** @todo Assert the same scene for all items? -- can't easily - watch when feature object is removed from hierarchy */ - + FeatureGroup* add(Feature* feature) { /* Remove from previous group */ if(feature->_group) feature->_group->remove(feature); @@ -87,27 +94,31 @@ class FeatureGroup { /* Crossreference the feature and group together */ features.push_back(feature); feature->_group = this; + return this; } /** * @brief Remove feature from the group + * @return Pointer to self (for method chaining) * * The feature must be part of the group. * @see add() */ - void remove(Feature* feature) { + FeatureGroup* remove(Feature* feature) { CORRADE_ASSERT(feature->_group == this, - "SceneGraph::AbstractFeatureGroup::remove(): feature is not part of this group", ); + "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; }; +#ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base for two-dimensional object features @@ -116,15 +127,13 @@ AbstractGroupedFeature for more information. @note Not available on GCC < 4.7. Use %FeatureGroup<2, Feature, T> instead. @see FeatureGroup3D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using FeatureGroup2D = FeatureGroup<2, Feature, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef FeatureGroup<2, Feature, T = GLfloat> FeatureGroup2D; +template #endif +using FeatureGroup2D = FeatureGroup<2, Feature, T>; /** @brief Base for three-dimensional object features @@ -134,14 +143,13 @@ AbstractGroupedFeature for more information. @note Not available on GCC < 4.7. Use %FeatureGroup<3, Feature, T> instead. @see FeatureGroup2D -@todoc Remove workaround when Doxygen supports alias template */ -#ifndef DOXYGEN_GENERATING_OUTPUT -#ifndef CORRADE_GCC46_COMPATIBILITY -template using FeatureGroup3D = FeatureGroup<3, Feature, T>; -#endif +#ifdef DOXYGEN_GENERATING_OUTPUT +template #else -typedef FeatureGroup<3, Feature, T = GLfloat> FeatureGroup3D; +template +#endif +using FeatureGroup3D = FeatureGroup<3, Feature, T>; #endif }} diff --git a/src/SceneGraph/MatrixTransformation2D.cpp b/src/SceneGraph/MatrixTransformation2D.cpp index 7850ca48c..c546bd302 100644 --- a/src/SceneGraph/MatrixTransformation2D.cpp +++ b/src/SceneGraph/MatrixTransformation2D.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "MatrixTransformation2D.h" diff --git a/src/SceneGraph/MatrixTransformation2D.h b/src/SceneGraph/MatrixTransformation2D.h index e60dc18a6..80b1bd294 100644 --- a/src/SceneGraph/MatrixTransformation2D.h +++ b/src/SceneGraph/MatrixTransformation2D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_MatrixTransformation2D_h #define Magnum_SceneGraph_MatrixTransformation2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -28,17 +37,18 @@ namespace Magnum { namespace SceneGraph { /** @brief Two-dimensional transformation implemented using matrices -@see MatrixTransformation3D +Uses Math::Matrix3 as underlying type. +@see @ref scenegraph, RigidMatrixTransformation2D, MatrixTransformation3D */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { public: - /** @brief Transformation matrix type */ - typedef typename DimensionTraits<2, T>::MatrixType DataType; + /** @brief Underlying transformation type */ + typedef Math::Matrix3 DataType; #ifndef DOXYGEN_GENERATING_OUTPUT inline constexpr static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { @@ -90,6 +100,11 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { return this; } + inline MatrixTransformation2D* resetTransformation() override { + setTransformation({}); + return this; + } + /** * @copydoc AbstractTranslationRotationScaling2D::translate() * Same as calling transform() with Matrix3::translation(). @@ -103,7 +118,7 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { * @copydoc AbstractTranslationRotationScaling2D::rotate() * Same as calling transform() with Matrix3::rotation(). */ - inline MatrixTransformation2D* rotate(T angle, TransformationType type = TransformationType::Global) override { + inline MatrixTransformation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { transform(Math::Matrix3::rotation(angle), type); return this; } @@ -117,6 +132,20 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { return this; } + /** + * @brief Reflect object + * @param normal Normal of the line through which to reflect + * (normalized) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix3::reflection(). + */ + inline MatrixTransformation2D* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { + transform(Math::Matrix3::reflection(normal), type); + return this; + } + /** * @brief Move object in stacking order * @param under Sibling object under which to move or `nullptr`, @@ -124,13 +153,13 @@ class MatrixTransformation2D: public AbstractTranslationRotationScaling2D { * @return Pointer to self (for method chaining) */ inline MatrixTransformation2D* move(Object>* under) { - static_cast*>(this)->Corrade::Containers::LinkedList>>::move(this, under); + static_cast*>(this)->Corrade::Containers::template LinkedList>>::move(this, under); return this; } protected: /* Allow construction only from Object */ - inline MatrixTransformation2D() {} + inline explicit MatrixTransformation2D() = default; private: Math::Matrix3 _transformation; diff --git a/src/SceneGraph/MatrixTransformation3D.cpp b/src/SceneGraph/MatrixTransformation3D.cpp index bbcc227e8..d2e7e82b3 100644 --- a/src/SceneGraph/MatrixTransformation3D.cpp +++ b/src/SceneGraph/MatrixTransformation3D.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "MatrixTransformation3D.h" diff --git a/src/SceneGraph/MatrixTransformation3D.h b/src/SceneGraph/MatrixTransformation3D.h index 763acbcc3..08a36bd77 100644 --- a/src/SceneGraph/MatrixTransformation3D.h +++ b/src/SceneGraph/MatrixTransformation3D.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_MatrixTransformation3D_h #define Magnum_SceneGraph_MatrixTransformation3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -28,17 +37,18 @@ namespace Magnum { namespace SceneGraph { /** @brief Three-dimensional transformation implemented using matrices -@see MatrixTransformation2D +Uses Math::Matrix4 as underlying type. +@see @ref scenegraph, RigidMatrixTransformation3D, MatrixTransformation2D */ #ifndef DOXYGEN_GENERATING_OUTPUT template #else -template +template #endif class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { public: - /** @brief Transformation matrix type */ - typedef typename DimensionTraits<3, T>::MatrixType DataType; + /** @brief Underlying transformation type */ + typedef Math::Matrix4 DataType; #ifndef DOXYGEN_GENERATING_OUTPUT inline constexpr static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { @@ -78,6 +88,11 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { return this; } + inline MatrixTransformation3D* resetTransformation() override { + setTransformation({}); + return this; + } + /** * @brief Multiply transformation * @param transformation Transformation @@ -103,49 +118,46 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { * @copydoc AbstractTranslationRotationScaling3D::rotate() * Same as calling transform() with Matrix4::rotation(). */ - inline MatrixTransformation3D* rotate(T angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { + inline MatrixTransformation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { transform(Math::Matrix4::rotation(angle, normalizedAxis), type); return this; } /** * @brief Rotate object around X axis - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) * * Same as calling transform() with Matrix4::rotationX(). - * @see deg(), rad() */ - inline MatrixTransformation3D* rotateX(T angle, TransformationType type = TransformationType::Global) override { + inline MatrixTransformation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) override { transform(Math::Matrix4::rotationX(angle), type); return this; } /** * @brief Rotate object around Y axis - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) * * Same as calling transform() with Matrix4::rotationY(). - * @see deg(), rad() */ - inline MatrixTransformation3D* rotateY(T angle, TransformationType type = TransformationType::Global) override { + inline MatrixTransformation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { transform(Math::Matrix4::rotationY(angle), type); return this; } /** * @brief Rotate object around Z axis - * @param angle Angle in radians, counterclockwise + * @param angle Angle (counterclockwise) * @param type Transformation type * @return Pointer to self (for method chaining) * * Same as calling transform() with Matrix4::rotationZ(). - * @see deg(), rad() */ - inline MatrixTransformation3D* rotateZ(T angle, TransformationType type = TransformationType::Global) override { + inline MatrixTransformation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { transform(Math::Matrix4::rotationZ(angle), type); return this; } @@ -159,9 +171,23 @@ class MatrixTransformation3D: public AbstractTranslationRotationScaling3D { return this; } + /** + * @brief Reflect object + * @param normal Normal of the plane through which to reflect + * (normalized) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::reflection(). + */ + inline MatrixTransformation3D* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { + transform(Math::Matrix4::reflection(normal), type); + return this; + } + protected: /* Allow construction only from Object */ - inline MatrixTransformation3D() {} + inline explicit MatrixTransformation3D() = default; private: Math::Matrix4 _transformation; diff --git a/src/SceneGraph/Object.cpp b/src/SceneGraph/Object.cpp new file mode 100644 index 000000000..0a4c679c8 --- /dev/null +++ b/src/SceneGraph/Object.cpp @@ -0,0 +1,34 @@ +/* + 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 a7a2a0b02..b1c369405 100644 --- a/src/SceneGraph/Object.h +++ b/src/SceneGraph/Object.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Object_h #define Magnum_SceneGraph_Object_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -30,13 +39,13 @@ namespace Magnum { namespace SceneGraph { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { - enum class ObjectFlag: std::uint8_t { + enum class ObjectFlag: UnsignedByte { Dirty = 1 << 0, Visited = 1 << 1, Joint = 1 << 2 }; - typedef Corrade::Containers::EnumSet ObjectFlags; + typedef Corrade::Containers::EnumSet ObjectFlags; CORRADE_ENUMSET_OPERATORS(ObjectFlags) } @@ -68,15 +77,20 @@ for(Object* child = o->firstChild(); child; child = child->nextSibling()) { @section Object-explicit-specializations Explicit template specializations The following specialization are explicitly compiled into SceneGraph library. -For other specializations you have to use Object.hpp implementation file to -avoid linker errors. See @ref compilation-speedup-hpp for more information. - - - @ref MatrixTransformation2D "Object>" - - @ref MatrixTransformation3D "Object>" - -@see Scene, AbstractFeature, AbstractTransformation +For other specializations (e.g. using Double type or special transformation +class) you have to use Object.hpp implementation file to avoid linker errors. +See @ref compilation-speedup-hpp for more information. + + - @ref DualComplexTransformation "Object>" + - @ref DualQuaternionTransformation "Object>" + - @ref MatrixTransformation2D "Object>" + - @ref MatrixTransformation3D "Object>" + - @ref RigidMatrixTransformation2D "Object>" + - @ref RigidMatrixTransformation3D "Object>" + +@see Scene, AbstractFeature, AbstractTransformation, DebugTools::ObjectRenderer */ -template class Object: public AbstractObject, public Transformation +template class MAGNUM_SCENEGRAPH_EXPORT Object: public AbstractObject, public Transformation #ifndef DOXYGEN_GENERATING_OUTPUT , private Corrade::Containers::LinkedList>, private Corrade::Containers::LinkedListItem, Object> #endif @@ -105,7 +119,7 @@ template class Object: public AbstractObject* parent = nullptr): counter(0xFFFFu), flags(Flag::Dirty) { + inline explicit Object(Object* parent = nullptr): counter(0xFFFFu), flags(Flag::Dirty) { setParent(parent); } @@ -200,6 +214,10 @@ template class Object: public AbstractObject::MatrixType transformationMatrix() const override { + return Transformation::toMatrix(Transformation::transformation()); + } + inline typename DimensionTraits::MatrixType absoluteTransformationMatrix() const override { return Transformation::toMatrix(absoluteTransformation()); } @@ -239,17 +257,17 @@ template class Object: public AbstractObject* sceneObject() override; const Object* sceneObject() const override; - std::vector::MatrixType> transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix = typename DimensionTraits::MatrixType()) const override; + std::vector::MatrixType> transformationMatrices(const std::vector*>& objects, const typename DimensionTraits::MatrixType& initialTransformationMatrix = (typename DimensionTraits::MatrixType())) const override; - typename Transformation::DataType computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; + typename Transformation::DataType MAGNUM_SCENEGRAPH_LOCAL computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; void setClean(const std::vector*>& objects) const override; - void setClean(const typename Transformation::DataType& absoluteTransformation); + void MAGNUM_SCENEGRAPH_LOCAL setClean(const typename Transformation::DataType& absoluteTransformation); typedef Implementation::ObjectFlag Flag; typedef Implementation::ObjectFlags Flags; - std::uint16_t counter; + UnsignedShort counter; Flags flags; }; diff --git a/src/SceneGraph/Object.hpp b/src/SceneGraph/Object.hpp index f893352ea..cd35d9da4 100644 --- a/src/SceneGraph/Object.hpp +++ b/src/SceneGraph/Object.hpp @@ -1,24 +1,34 @@ #ifndef Magnum_SceneGraph_Object_hpp #define Magnum_SceneGraph_Object_hpp /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 Object.h */ +#include "AbstractTransformation.h" #include "Object.h" #include @@ -28,6 +38,12 @@ namespace Magnum { namespace SceneGraph { +template AbstractObject::AbstractObject() {} +template AbstractObject::~AbstractObject() {} + +template inline AbstractTransformation::AbstractTransformation() {} +template inline AbstractTransformation::~AbstractTransformation() {} + template Scene* Object::scene() { return static_cast*>(sceneObject()); } @@ -62,7 +78,7 @@ template Object* Object::s } /* Remove the object from old parent children list */ - if(this->parent()) this->parent()->Corrade::Containers::LinkedList>::cut(this); + if(this->parent()) this->parent()->Corrade::Containers::template LinkedList>::cut(this); /* Add the object to list of new parent */ if(parent) parent->Corrade::Containers::LinkedList>::insert(this); @@ -144,18 +160,39 @@ template std::vector std::vector Object::transformations(std::vector*> objects, const typename Transformation::DataType& initialTransformation) const { + CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", {}); + /* Remember object count for later */ std::size_t objectCount = objects.size(); - /* Create initial list of joints from original objects */ - std::vector*> jointObjects(objects.size()); - for(std::size_t i = 0; i != jointObjects.size(); ++i) { - jointObjects[i] = static_cast*>(objects[i]); - CORRADE_INTERNAL_ASSERT(jointObjects[i]->counter == 0xFFFFu); - jointObjects[i]->counter = i; - jointObjects[i]->flags |= Flag::Joint; + /** @bug What if there is one objects twice in the list */ + + /* Mark all original objects as joints and create initial list of joints + from them */ + for(std::size_t i = 0; i != objects.size(); ++i) { + /* Multiple occurences of one object in the array, don't overwrite it + with different counter */ + if(objects[i]->counter != 0xFFFFu) continue; + + objects[i]->counter = i; + objects[i]->flags |= Flag::Joint; } + std::vector*> jointObjects(objects); /* Scene object */ const Scene* scene = this->scene(); @@ -166,8 +203,13 @@ template std::vector Ob /* Mark all objects up the hierarchy as visited */ auto it = objects.begin(); while(!objects.empty()) { + /* Already visited, remove and continue to next (duplicate occurence) */ + if((*it)->flags & Flag::Visited) { + it = objects.erase(it); + continue; + } + /* Mark the object as visited */ - CORRADE_INTERNAL_ASSERT(!((*it)->flags & Flag::Visited)); (*it)->flags |= Flag::Visited; Object* parent = (*it)->parent(); @@ -184,6 +226,8 @@ template std::vector Ob /* If not already marked as joint, mark it as such and add it to list of joint objects */ if(!(parent->flags & Flag::Joint)) { + CORRADE_ASSERT(jointObjects.size() < 0xFFFFu, + "SceneGraph::Object::transformations(): too large scene", {}); CORRADE_INTERNAL_ASSERT(parent->counter == 0xFFFFu); parent->counter = jointObjects.size(); parent->flags |= Flag::Joint; @@ -197,8 +241,6 @@ template std::vector Ob if(it == objects.end()) it = objects.begin(); } - CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", {}); - /* Array of absolute transformations in joints */ std::vector jointTransformations(jointObjects.size()); @@ -206,9 +248,18 @@ template std::vector Ob for(std::size_t i = 0; i != jointTransformations.size(); ++i) computeJointTransformation(jointObjects, jointTransformations, i, initialTransformation); + /* Copy transformation for second or next occurences from first occurence + of duplicate object */ + for(std::size_t i = 0; i != objectCount; ++i) { + if(jointObjects[i]->counter != i) + jointTransformations[i] = jointTransformations[jointObjects[i]->counter]; + } + /* All visited marks are now cleaned, clean joint marks and counters */ for(auto it = jointObjects.begin(); it != jointObjects.end(); ++it) { - CORRADE_INTERNAL_ASSERT((*it)->flags & Flag::Joint); + /* All not-already cleaned objects (...duplicate occurences) should + have joint mark */ + CORRADE_INTERNAL_ASSERT((*it)->counter = 0xFFFFu || (*it)->flags & Flag::Joint); (*it)->flags &= ~Flag::Joint; (*it)->counter = 0xFFFFu; } @@ -221,7 +272,8 @@ template std::vector Ob template typename Transformation::DataType Object::computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const { Object* o = jointObjects[joint]; - /* Transformation already computed ("unvisited" by this function before), done */ + /* Transformation already computed ("unvisited" by this function before + either due to recursion or duplicate object occurences), done */ if(!(o->flags & Flag::Visited)) return jointTransformations[joint]; /* Initialize transformation */ diff --git a/src/SceneGraph/RigidMatrixTransformation2D.cpp b/src/SceneGraph/RigidMatrixTransformation2D.cpp new file mode 100644 index 000000000..a6e7506e9 --- /dev/null +++ b/src/SceneGraph/RigidMatrixTransformation2D.cpp @@ -0,0 +1,35 @@ +/* + 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 new file mode 100644 index 000000000..4d49c2a5b --- /dev/null +++ b/src/SceneGraph/RigidMatrixTransformation2D.h @@ -0,0 +1,204 @@ +#ifndef Magnum_SceneGraph_RigidMatrixTransformation2D_h +#define Magnum_SceneGraph_RigidMatrixTransformation2D_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::SceneGraph::RigidMatrixTransformation2D + */ + +#include "Math/Matrix3.h" +#include "Math/Algorithms/GramSchmidt.h" +#include "AbstractTranslationRotation2D.h" +#include "Object.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Two-dimensional rigid transformation implemented using matrices + +Unlike MatrixTransformation2D this class allows only rotation, reflection and +translation (no scaling or setting arbitrary transformations). This allows to +use Matrix3::invertedRigid() for faster computation of inverse transformations. +@see @ref scenegraph, RigidMatrixTransformation3D +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { + public: + /** @brief Underlying transformation type */ + typedef Math::Matrix3 DataType; + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline 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) { + return transformation; + } + + inline static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { + return parent*child; + } + + inline static Math::Matrix3 inverted(const Math::Matrix3& transformation) { + return transformation.invertedRigid(); + } + + inline Math::Matrix3 transformation() const { + return _transformation; + } + #endif + + /** + * @brief Normalize rotation part + * @return Pointer to self (for method chaining) + * + * Normalizes the rotation part using Math::Algorithms::gramSchmidt() + * to prevent rounding errors when rotating the object subsequently. + */ + RigidMatrixTransformation2D* normalizeRotation() { + setTransformationInternal(Math::Matrix3::from( + Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), + _transformation.translation())); + return this; + } + + /** + * @brief Set transformation + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix3::isRigidTransformation() + */ + RigidMatrixTransformation2D* setTransformation(const Math::Matrix3& transformation) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation2D::setTransformation(): the matrix doesn't represent rigid transformation", this); + setTransformationInternal(transformation); + return this; + } + + inline RigidMatrixTransformation2D* resetTransformation() override { + setTransformationInternal({}); + return this; + } + + /** + * @brief Transform object + * @param transformation Transformation + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix3::isRigidTransformation() + */ + inline RigidMatrixTransformation2D* transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation2D::transform(): the matrix doesn't represent rigid transformation", this); + transformInternal(transformation, type); + return this; + } + + /** + * @copydoc AbstractTranslationRotationScaling2D::translate() + * Same as calling transform() with Matrix3::translation(). + */ + inline RigidMatrixTransformation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + transformInternal(Math::Matrix3::translation(vector), type); + return this; + } + + /** + * @brief Rotate object + * @param angle Angle (counterclockwise) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix3::rotation(). + * @see normalizeRotation() + */ + inline RigidMatrixTransformation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { + transformInternal(Math::Matrix3::rotation(angle), type); + return this; + } + + /** + * @brief Reflect object + * @param normal Normal of the line through which to reflect + * (normalized) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix3::reflection(). + */ + inline RigidMatrixTransformation2D* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { + transformInternal(Math::Matrix3::reflection(normal), type); + return this; + } + + /** + * @brief Move object in stacking order + * @param under Sibling object under which to move or `nullptr`, + * 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; + } + + protected: + /* Allow construction only from Object */ + inline explicit RigidMatrixTransformation2D() = default; + + private: + /* No assertions fired, for internal use */ + inline 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? */ + if(!static_cast>*>(this)->isScene()) { + _transformation = transformation; + static_cast>*>(this)->setDirty(); + } + } + + /* No assertions fired, for internal use */ + inline void transformInternal(const Math::Matrix3& transformation, TransformationType type) { + setTransformation(type == TransformationType::Global ? + transformation*_transformation : _transformation*transformation); + } + + Math::Matrix3 _transformation; +}; + +}} + +#endif diff --git a/src/SceneGraph/RigidMatrixTransformation3D.cpp b/src/SceneGraph/RigidMatrixTransformation3D.cpp new file mode 100644 index 000000000..008f5fb5d --- /dev/null +++ b/src/SceneGraph/RigidMatrixTransformation3D.cpp @@ -0,0 +1,35 @@ +/* + 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 new file mode 100644 index 000000000..9757b2271 --- /dev/null +++ b/src/SceneGraph/RigidMatrixTransformation3D.h @@ -0,0 +1,237 @@ +#ifndef Magnum_SceneGraph_RigidMatrixTransformation3D_h +#define Magnum_SceneGraph_RigidMatrixTransformation3D_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::SceneGraph::RigidMatrixTransformation3D + */ + +#include "Math/Matrix4.h" +#include "Math/Algorithms/GramSchmidt.h" +#include "AbstractTranslationRotation3D.h" +#include "Object.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Three-dimensional rigid transformation implemented using matrices + +Unlike MatrixTransformation3D this class allows only rotation, reflection and +translation (no scaling or setting arbitrary transformations). This allows to +use Matrix4::invertedRigid() for faster computation of inverse transformations. +@see @ref scenegraph, RigidMatrixTransformation2D +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { + public: + /** @brief Underlying transformation type */ + typedef Math::Matrix4 DataType; + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline 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) { + return transformation; + } + + inline static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { + return parent*child; + } + + inline static Math::Matrix4 inverted(const Math::Matrix4& transformation) { + return transformation.invertedRigid(); + } + + inline Math::Matrix4 transformation() const { + return _transformation; + } + #endif + + /** + * @brief Normalize rotation part + * @return Pointer to self (for method chaining) + * + * Normalizes the rotation part using Math::Algorithms::gramSchmidt() + * to prevent rounding errors when rotating the object subsequently. + */ + RigidMatrixTransformation3D* normalizeRotation() { + setTransformation(Math::Matrix4::from( + Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), + _transformation.translation())); + return this; + } + + /** + * @brief Set transformation + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix4::isRigidTransformation() + */ + RigidMatrixTransformation3D* setTransformation(const Math::Matrix4& transformation) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation3D::setTransformation(): the matrix doesn't represent rigid transformation", this); + setTransformationInternal(transformation); + return this; + } + + inline RigidMatrixTransformation3D* resetTransformation() override { + setTransformation({}); + return this; + } + + /** + * @brief Multiply transformation + * @param transformation Transformation + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix4::isRigidTransformation() + */ + inline RigidMatrixTransformation3D* transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation3D::transform(): the matrix doesn't represent rigid transformation", this); + transformInternal(transformation, type); + return this; + } + + /** + * @copydoc AbstractTranslationRotationScaling3D::translate() + * Same as calling transform() with Matrix4::translation(). + */ + inline RigidMatrixTransformation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + transformInternal(Math::Matrix4::translation(vector), type); + return this; + } + + /** + * @brief Rotate object + * @param angle Angle (counterclockwise) + * @param normalizedAxis Normalized rotation axis + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::rotation(). + * @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 { + transformInternal(Math::Matrix4::rotation(angle, normalizedAxis), type); + return this; + } + + /** + * @brief Rotate object around X axis + * @param angle Angle (counterclockwise) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::rotationX(). + * @see normalizeRotation() + */ + inline RigidMatrixTransformation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) override { + transformInternal(Math::Matrix4::rotationX(angle), type); + return this; + } + + /** + * @brief Rotate object around Y axis + * @param angle Angle (counterclockwise) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::rotationY(). + * @see normalizeRotation() + */ + inline RigidMatrixTransformation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { + transformInternal(Math::Matrix4::rotationY(angle), type); + return this; + } + + /** + * @brief Rotate object around Z axis + * @param angle Angle (counterclockwise) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::rotationZ(). + * @see normalizeRotation() + */ + inline RigidMatrixTransformation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { + transformInternal(Math::Matrix4::rotationZ(angle), type); + return this; + } + + /** + * @brief Reflect object + * @param normal Normal of the plane through which to reflect + * (normalized) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::reflection(). + */ + inline RigidMatrixTransformation3D* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { + transformInternal(Math::Matrix4::reflection(normal), type); + return this; + } + + protected: + /* Allow construction only from Object */ + inline explicit RigidMatrixTransformation3D() = default; + + private: + /* No assertions fired, for internal use */ + inline 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? */ + if(!static_cast>*>(this)->isScene()) { + _transformation = transformation; + static_cast>*>(this)->setDirty(); + } + } + + /* No assertions fired, for internal use */ + inline void transformInternal(const Math::Matrix4& transformation, TransformationType type) { + setTransformation(type == TransformationType::Global ? + transformation*_transformation : _transformation*transformation); + } + + Math::Matrix4 _transformation; +}; + +}} + +#endif diff --git a/src/SceneGraph/Scene.h b/src/SceneGraph/Scene.h index eecc231f0..2ba3a552e 100644 --- a/src/SceneGraph/Scene.h +++ b/src/SceneGraph/Scene.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_Scene_h #define Magnum_SceneGraph_Scene_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -31,6 +40,8 @@ See @ref scenegraph for introduction. */ template class Scene: public Object { public: + explicit Scene() = default; + inline bool isScene() const { return true; } }; diff --git a/src/SceneGraph/SceneGraph.h b/src/SceneGraph/SceneGraph.h index 4d77c55a8..eb9d2232c 100644 --- a/src/SceneGraph/SceneGraph.h +++ b/src/SceneGraph/SceneGraph.h @@ -1,103 +1,134 @@ #ifndef Magnum_SceneGraph_SceneGraph_h #define Magnum_SceneGraph_SceneGraph_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 Forward declarations for Magnum::SceneGraph namespace */ -#include - -#include "Magnum.h" +#include "Types.h" #include "corradeCompatibility.h" namespace Magnum { namespace SceneGraph { +/** @todoc remove when doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef CORRADE_GCC45_COMPATIBILITY -enum class AspectRatioPolicy: std::uint8_t; +enum class AspectRatioPolicy: UnsignedByte; #endif -template class AbstractCamera; +template class AbstractCamera; #ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractCamera2D = AbstractCamera<2, T>; -template using AbstractCamera3D = AbstractCamera<3, T>; +template using AbstractCamera2D = AbstractCamera<2, T>; +template using AbstractCamera3D = AbstractCamera<3, T>; #endif -template class AbstractFeature; +template class AbstractFeature; #ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractFeature2D = AbstractFeature<2, T>; -template using AbstractFeature3D = AbstractFeature<3, T>; +template using AbstractFeature2D = AbstractFeature<2, T>; +template using AbstractFeature3D = AbstractFeature<3, T>; #endif -template class AbstractGroupedFeature; +template class AbstractGroupedFeature; #ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractGroupedFeature2D = AbstractGroupedFeature<2, Derived, T>; -template using AbstractGroupedFeature3D = AbstractGroupedFeature<3, Derived, T>; +template using AbstractGroupedFeature2D = AbstractGroupedFeature<2, Derived, T>; +template using AbstractGroupedFeature3D = AbstractGroupedFeature<3, Derived, T>; #endif -template class AbstractObject; +template class AbstractObject; #ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractObject2D = AbstractObject<2, T>; -template using AbstractObject3D = AbstractObject<3, T>; +template using AbstractObject2D = AbstractObject<2, T>; +template using AbstractObject3D = AbstractObject<3, T>; #endif #ifndef CORRADE_GCC45_COMPATIBILITY -enum class TransformationType: std::uint8_t; +enum class TransformationType: UnsignedByte; #endif -template class AbstractTransformation; +template class AbstractTransformation; +#ifndef CORRADE_GCC46_COMPATIBILITY +template using AbstractTransformation2D = AbstractTransformation<2, T>; +template using AbstractTransformation3D = AbstractTransformation<3, T>; +#endif + +template class AbstractTranslationRotation2D; +template class AbstractTranslationRotation3D; +template class AbstractTranslationRotationScaling2D; +template class AbstractTranslationRotationScaling3D; + +template class Animable; #ifndef CORRADE_GCC46_COMPATIBILITY -template using AbstractTransformation2D = AbstractTransformation<2, T>; -template using AbstractTransformation3D = AbstractTransformation<3, T>; +template using Animable2D = Animable<2, T>; +template using Animable3D = Animable<3, T>; #endif -template class AbstractTranslationRotation2D; -template class AbstractTranslationRotation3D; -template class AbstractTranslationRotationScaling2D; -template class AbstractTranslationRotationScaling3D; +enum class AnimationState: UnsignedByte; -template class Camera2D; -template class Camera3D; +template class AnimableGroup; +#ifndef CORRADE_GCC46_COMPATIBILITY +template using AnimableGroup2D = AnimableGroup<2, T>; +template using AnimableGroup3D = AnimableGroup<3, T>; +#endif -template class Drawable; +template class Camera2D; +template class Camera3D; + +template class Drawable; #ifndef CORRADE_GCC46_COMPATIBILITY -template using Drawable2D = Drawable<2, T>; -template using Drawable3D = Drawable<3, T>; +template using Drawable2D = Drawable<2, T>; +template using Drawable3D = Drawable<3, T>; #endif -template class FeatureGroup; +template class DualComplexTransformation; +template class DualQuaternionTransformation; + +template class FeatureGroup; #ifndef CORRADE_GCC46_COMPATIBILITY -template using FeatureGroup2D = FeatureGroup<2, Feature, T>; -template using FeatureGroup3D = FeatureGroup<3, Feature, T>; +template using FeatureGroup2D = FeatureGroup<2, Feature, T>; +template using FeatureGroup3D = FeatureGroup<3, Feature, T>; #endif #ifndef CORRADE_GCC46_COMPATIBILITY -template using DrawableGroup = FeatureGroup, T>; -template using DrawableGroup2D = DrawableGroup<2, T>; -template using DrawableGroup3D = DrawableGroup<3, T>; +template using DrawableGroup = FeatureGroup, T>; +template using DrawableGroup2D = DrawableGroup<2, T>; +template using DrawableGroup3D = DrawableGroup<3, T>; #else -template class DrawableGroup; +template class DrawableGroup; #endif -template class MatrixTransformation2D; -template class MatrixTransformation3D; +template class MatrixTransformation2D; +template class MatrixTransformation3D; template class Object; + +template class RigidMatrixTransformation2D; +template class RigidMatrixTransformation3D; + template class Scene; +#endif }} diff --git a/src/SceneGraph/Test/AnimableTest.cpp b/src/SceneGraph/Test/AnimableTest.cpp new file mode 100644 index 000000000..fb0ebb643 --- /dev/null +++ b/src/SceneGraph/Test/AnimableTest.cpp @@ -0,0 +1,359 @@ +/* + 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 "SceneGraph/Animable.h" +#include "SceneGraph/AnimableGroup.h" +#include "SceneGraph/MatrixTransformation3D.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +class AnimableTest: public Corrade::TestSuite::Tester { + public: + AnimableTest(); + + void state(); + void step(); + void duration(); + void repeat(); + void stop(); + void pause(); + + void debug(); +}; + +typedef SceneGraph::Object> Object3D; + +AnimableTest::AnimableTest() { + addTests({&AnimableTest::state, + &AnimableTest::step, + &AnimableTest::duration, + &AnimableTest::repeat, + &AnimableTest::stop, + &AnimableTest::pause, + + &AnimableTest::debug}); +} + +void AnimableTest::state() { + class StateTrackingAnimable: public SceneGraph::Animable<3> { + public: + StateTrackingAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group) { + setDuration(1.0f); + } + + std::string trackedState; + + protected: + void animationStep(Float, Float) override {} + + void animationStarted() override { trackedState += "started"; } + void animationPaused() override { trackedState += "paused"; } + void animationResumed() override { trackedState += "resumed"; } + void animationStopped() override { trackedState += "stopped"; } + }; + + Object3D object; + AnimableGroup<3> group; + CORRADE_COMPARE(group.runningCount(), 0); + + /* Verify initial state */ + StateTrackingAnimable animable(&object, &group); + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + CORRADE_VERIFY(animable.trackedState.empty()); + group.step(1.0f, 1.0f); + CORRADE_VERIFY(animable.trackedState.empty()); + CORRADE_COMPARE(group.runningCount(), 0); + + /* Stopped -> paused is not supported */ + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + animable.setState(AnimationState::Paused); + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + + /* Stopped -> running */ + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + animable.trackedState.clear(); + animable.setState(AnimationState::Running); + CORRADE_VERIFY(animable.trackedState.empty()); + group.step(1.0f, 1.0f); + CORRADE_COMPARE(animable.trackedState, "started"); + CORRADE_COMPARE(group.runningCount(), 1); + + /* Running -> paused */ + CORRADE_COMPARE(animable.state(), AnimationState::Running); + animable.trackedState.clear(); + animable.setState(AnimationState::Paused); + CORRADE_VERIFY(animable.trackedState.empty()); + group.step(1.0f, 1.0f); + CORRADE_COMPARE(animable.trackedState, "paused"); + CORRADE_COMPARE(group.runningCount(), 0); + + /* Paused -> running */ + CORRADE_COMPARE(animable.state(), AnimationState::Paused); + animable.trackedState.clear(); + animable.setState(AnimationState::Running); + CORRADE_VERIFY(animable.trackedState.empty()); + group.step(1.0f, 1.0f); + CORRADE_COMPARE(animable.trackedState, "resumed"); + CORRADE_COMPARE(group.runningCount(), 1); + + /* Running -> stopped */ + CORRADE_COMPARE(animable.state(), AnimationState::Running); + animable.trackedState.clear(); + animable.setState(AnimationState::Stopped); + CORRADE_VERIFY(animable.trackedState.empty()); + group.step(1.0f, 1.0f); + CORRADE_COMPARE(animable.trackedState, "stopped"); + CORRADE_COMPARE(group.runningCount(), 0); + + animable.setState(AnimationState::Running); + group.step(1.0f, 1.0f); + animable.setState(AnimationState::Paused); + + /* Paused -> stopped */ + CORRADE_COMPARE(animable.state(), AnimationState::Paused); + animable.trackedState.clear(); + animable.setState(AnimationState::Stopped); + CORRADE_VERIFY(animable.trackedState.empty()); + group.step(1.0f, 1.0f); + CORRADE_COMPARE(animable.trackedState, "stopped"); + CORRADE_COMPARE(group.runningCount(), 0); + + /* Verify running count can go past 0/1 */ + group.add((new StateTrackingAnimable(&object, &group))->setState(AnimationState::Running)); + group.add((new StateTrackingAnimable(&object, &group))->setState(AnimationState::Running)); + group.step(1.0f, 1.0f); + CORRADE_COMPARE(group.runningCount(), 2); +} + +class OneShotAnimable: public SceneGraph::Animable<3> { + public: + OneShotAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group), time(-1.0f) { + setDuration(10.0f); + setState(AnimationState::Running); + } + + Float time; + std::string stateChanges; + + protected: + void animationStep(Float time, Float) override { + this->time = time; + } + + void animationStarted() override { + stateChanges += "started;"; + } + + void animationStopped() override { + stateChanges += "stopped;"; + } +}; + +void AnimableTest::step() { + class InifiniteAnimable: public SceneGraph::Animable<3> { + public: + InifiniteAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group), time(-1.0f), delta(0.0f) {} + + Float time, delta; + + protected: + void animationStep(Float time, Float delta) override { + this->time = time; + this->delta = delta; + } + }; + + Object3D object; + AnimableGroup<3> group; + InifiniteAnimable animable(&object, &group); + + /* Calling step() if no object is running should do nothing */ + group.step(5.0f, 0.5f); + CORRADE_COMPARE(group.runningCount(), 0); + CORRADE_COMPARE(animable.time, -1.0f); + CORRADE_COMPARE(animable.delta, 0.0f); + + /* Calling step() with running animation should start it with zero + absolute time */ + animable.setState(AnimationState::Running); + group.step(5.0f, 0.5f); + CORRADE_COMPARE(group.runningCount(), 1); + CORRADE_COMPARE(animable.time, 0.0f); + CORRADE_COMPARE(animable.delta, 0.5f); + + /* Repeated call to step() will add to absolute animation time */ + group.step(8.0f, 0.75f); + CORRADE_COMPARE(animable.time, 3.0f); + CORRADE_COMPARE(animable.delta, 0.75f); +} + +void AnimableTest::duration() { + Object3D object; + AnimableGroup<3> group; + OneShotAnimable animable(&object, &group); + CORRADE_VERIFY(!animable.isRepeated()); + + /* First animation step is in duration, verify that animation is still + running and animationStep() is called */ + group.step(1.0f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.stateChanges, "started;"); + CORRADE_COMPARE(animable.time, 0.0f); + + /* Next animation step is out of duration and repeat is not enabled, + animationStep() shouldn't be called and animation should be stopped */ + group.step(12.75f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + CORRADE_COMPARE(animable.stateChanges, "started;stopped;"); + CORRADE_COMPARE(animable.time, 0.0f); +} + +void AnimableTest::repeat() { + class RepeatingAnimable: public SceneGraph::Animable<3> { + public: + RepeatingAnimable(AbstractObject<3>* object, AnimableGroup<3>* group = nullptr): SceneGraph::Animable<3>(object, group), time(-1.0f) { + setDuration(10.0f); + setState(AnimationState::Running); + setRepeated(true); + } + + Float time; + + protected: + void animationStep(Float time, Float) override { + this->time = time; + } + }; + + Object3D object; + AnimableGroup<3> group; + RepeatingAnimable animable(&object, &group); + CORRADE_COMPARE(animable.repeatCount(), 0); + + /* First animation steps is in first loop iteration */ + group.step(1.0f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 0.0f); + + /* Next animation step is in second loop iteration, animation should be + still running with time shifted by animation duration */ + group.step(11.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 0.5f); + + /* Third loop iteration (just to be sure) */ + group.step(25.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 4.5f); + + /* Cap repeat count to 3, the animation should be stopped now (and + animationStep() shouldn't be called)*/ + animable.setRepeatCount(3); + group.step(33.0f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + CORRADE_COMPARE(animable.time, 4.5f); + + /* Starting the animation again, should be repeatable again */ + animable.setState(AnimationState::Running); + + /* Three animation repeats */ + group.step(1.0f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + group.step(11.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + group.step(25.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + + /* Should be stopped now */ + group.step(33.0f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); +} + +void AnimableTest::stop() { + Object3D object; + AnimableGroup<3> group; + OneShotAnimable animable(&object, &group); + CORRADE_COMPARE(animable.repeatCount(), 0); + + /* Eat up some absolute time */ + group.step(1.0f, 0.5f); + group.step(1.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 0.5f); + + /* Stop the animable, nothing should be done */ + animable.setState(AnimationState::Stopped); + group.step(1.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Stopped); + CORRADE_COMPARE(animable.time, 0.5f); + + /* Restarting the animation should start with zero absolute time */ + animable.setState(AnimationState::Running); + group.step(2.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 0.0f); +} + +void AnimableTest::pause() { + Object3D object; + AnimableGroup<3> group; + OneShotAnimable animable(&object, &group); + + /* First two steps, animation is running */ + group.step(1.0f, 0.5f); + group.step(2.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 1.5f); + + /* Pausing the animation, first step should decrease count of running + animations and save paused time, next steps shouldn't affect anything */ + CORRADE_COMPARE(group.runningCount(), 1); + animable.setState(AnimationState::Paused); + CORRADE_COMPARE(group.runningCount(), 1); + group.step(3.0f, 0.5f); + CORRADE_COMPARE(group.runningCount(), 0); + group.step(4.5f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Paused); + CORRADE_COMPARE(animable.time, 1.5f); + + /* Unpausing, next step should continue from absolute time when pause + occured */ + animable.setState(AnimationState::Running); + group.step(5.0f, 0.5f); + CORRADE_COMPARE(animable.state(), AnimationState::Running); + CORRADE_COMPARE(animable.time, 2.0f); +} + +void AnimableTest::debug() { + std::ostringstream o; + Debug(&o) << AnimationState::Running; + CORRADE_COMPARE(o.str(), "SceneGraph::AnimationState::Running\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::AnimableTest) diff --git a/src/SceneGraph/Test/CMakeLists.txt b/src/SceneGraph/Test/CMakeLists.txt index e0db0910d..83101f39e 100644 --- a/src/SceneGraph/Test/CMakeLists.txt +++ b/src/SceneGraph/Test/CMakeLists.txt @@ -1,3 +1,40 @@ -corrade_add_test2(SceneGraphObjectTest ObjectTest.cpp LIBRARIES MagnumSceneGraphTestLib) -corrade_add_test2(SceneGraphCameraTest CameraTest.cpp LIBRARIES MagnumSceneGraph) -corrade_add_test2(SceneGraphSceneTest SceneTest.cpp LIBRARIES MagnumSceneGraph) +# +# 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. +# + +corrade_add_test(SceneGraphAnimableTest AnimableTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphCameraTest CameraTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphDualComplexTransforma___Test DualComplexTransformationTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphDualQuaternionTransfo___Test DualQuaternionTransformationTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphMatrixTransformation2DTest MatrixTransformation2DTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphMatrixTransformation3DTest MatrixTransformation3DTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphObjectTest ObjectTest.cpp LIBRARIES MagnumSceneGraphTestLib) +corrade_add_test(SceneGraphRigidMatrixTransfor___2DTest RigidMatrixTransformation2DTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphRigidMatrixTransfor___3DTest RigidMatrixTransformation3DTest.cpp LIBRARIES MagnumSceneGraph) +corrade_add_test(SceneGraphSceneTest SceneTest.cpp LIBRARIES MagnumSceneGraph) + +set_target_properties(SceneGraphDualComplexTransforma___Test + SceneGraphDualQuaternionTransfo___Test + SceneGraphRigidMatrixTransfor___2DTest + SceneGraphRigidMatrixTransfor___3DTest + PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT") diff --git a/src/SceneGraph/Test/CameraTest.cpp b/src/SceneGraph/Test/CameraTest.cpp index c3396e458..8c0c91e9e 100644 --- a/src/SceneGraph/Test/CameraTest.cpp +++ b/src/SceneGraph/Test/CameraTest.cpp @@ -1,21 +1,29 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "CameraTest.h" +#include -#include "Math/Constants.h" #include "SceneGraph/AbstractCamera.hpp" /* only for aspectRatioFix(), so it doesn't have to be exported */ #include "SceneGraph/Camera2D.h" #include "SceneGraph/Camera3D.h" @@ -24,10 +32,22 @@ #include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/Scene.h" -CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::CameraTest) - namespace Magnum { namespace SceneGraph { namespace Test { +class CameraTest: public Corrade::TestSuite::Tester { + public: + CameraTest(); + + void fixAspectRatio(); + void defaultProjection2D(); + void defaultProjection3D(); + void projectionSize2D(); + void projectionSizeOrthographic(); + void projectionSizePerspective(); + void projectionSizeViewport(); + void draw(); +}; + typedef SceneGraph::Object> Object2D; typedef SceneGraph::Object> Object3D; typedef SceneGraph::Scene> Scene3D; @@ -35,56 +55,56 @@ typedef SceneGraph::Camera2D<> Camera2D; typedef SceneGraph::Camera3D<> Camera3D; CameraTest::CameraTest() { - addTests(&CameraTest::fixAspectRatio, - &CameraTest::defaultProjection2D, - &CameraTest::defaultProjection3D, - &CameraTest::projection2D, - &CameraTest::orthographic, - &CameraTest::perspective, - &CameraTest::projectionSizeViewport, - &CameraTest::draw); + addTests({&CameraTest::fixAspectRatio, + &CameraTest::defaultProjection2D, + &CameraTest::defaultProjection3D, + &CameraTest::projectionSize2D, + &CameraTest::projectionSizeOrthographic, + &CameraTest::projectionSizePerspective, + &CameraTest::projectionSizeViewport, + &CameraTest::draw}); } void CameraTest::fixAspectRatio() { Vector2 projectionScale(0.5f, 1.0f/3.0f); - Math::Vector2 size(400, 300); + Vector2i size(400, 300); /* Division by zero */ Vector2 projectionScaleZeroY(0.5f, 0.0f); Vector2 projectionScaleZeroX(0.0f, 0.5f); - Math::Vector2 sizeZeroY(400, 0); - Math::Vector2 sizeZeroX(0, 300); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, projectionScaleZeroX, size)), Matrix4()); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, projectionScaleZeroY, size)), Matrix4()); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, projectionScale, sizeZeroY)), Matrix4()); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, projectionScale, sizeZeroX)), Matrix4()); + Vector2i sizeZeroY(400, 0); + Vector2i sizeZeroX(0, 300); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Clip, projectionScaleZeroX, size)), Matrix4()); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Clip, projectionScaleZeroY, size)), Matrix4()); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Clip, projectionScale, sizeZeroY)), Matrix4()); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Extend, projectionScale, sizeZeroX)), Matrix4()); /* Not preserved */ - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::NotPreserved, projectionScale, size)), Matrix4()); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::NotPreserved, projectionScale, size)), Matrix4()); /* Clip */ - Matrix4 expectedClip(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 4.0f/3.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, Vector2(0.5f), size)), expectedClip); - Matrix4 expectedClipRectangle(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 2.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, projectionScale, size)), expectedClipRectangle); + Matrix4 expectedClip({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 4.0f/3.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Clip, Vector2(0.5f), size)), expectedClip); + Matrix4 expectedClipRectangle({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 2.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Clip, projectionScale, size)), expectedClipRectangle); /* Extend */ - Matrix4 expectedExtend(3.0f/4.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, Vector2(0.5f), size)), expectedExtend); - Matrix4 expectedExtendRectangle(0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, projectionScale, size)), expectedExtendRectangle); + Matrix4 expectedExtend({3.0f/4.0f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 1.0f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 1.0f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Extend, Vector2(0.5f), size)), expectedExtend); + Matrix4 expectedExtendRectangle({0.5f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); + CORRADE_COMPARE((Implementation::aspectRatioFix<3, Float>(AspectRatioPolicy::Extend, projectionScale, size)), expectedExtendRectangle); } void CameraTest::defaultProjection2D() { @@ -101,58 +121,27 @@ void CameraTest::defaultProjection3D() { CORRADE_COMPARE(camera.projectionSize(), Vector2(2.0f)); } -void CameraTest::projection2D() { +void CameraTest::projectionSize2D() { Vector2 projectionSize(4.0f, 3.0f); Object2D o; Camera2D camera(&o); camera.setProjection(projectionSize); - - Matrix3 a(2.0f/4.0f, 0.0f, 0.0f, - 0.0f, 2.0f/3.0f, 0.0f, - 0.0f, 0.0f, 1.0f); - - CORRADE_COMPARE(camera.projectionMatrix(), a); CORRADE_COMPARE(camera.projectionSize(), projectionSize); } -void CameraTest::orthographic() { - Vector2 projectionSize(5); +void CameraTest::projectionSizeOrthographic() { + Vector2 projectionSizeRectangle(5.0f, 4.0f); Object3D o; Camera3D camera(&o); - camera.setOrthographic(projectionSize, 1, 9); - - Matrix4 a(0.4f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.4f, 0.0f, 0.0f, - 0.0f, 0.0f, -0.25f, 0.0f, - 0.0f, 0.0f, -1.25f, 1.0f); - - CORRADE_COMPARE(camera.projectionMatrix(), a); - CORRADE_COMPARE(camera.projectionSize(), projectionSize); - - Vector2 projectionSizeRectangle(5.0f, 4.0f); camera.setOrthographic(projectionSizeRectangle, 1, 9); - - Matrix4 rectangle(0.4f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, -0.25f, 0.0f, - 0.0f, 0.0f, -1.25f, 1.0f); - - CORRADE_COMPARE(camera.projectionMatrix(), rectangle); CORRADE_COMPARE(camera.projectionSize(), projectionSizeRectangle); } -void CameraTest::perspective() { +void CameraTest::projectionSizePerspective() { Object3D o; Camera3D camera(&o); - camera.setPerspective(deg(27.0f), 32.0f, 100); - - Matrix4 a(4.1652994f, 0.0f, 0.0f, 0.0f, - 0.0f, 4.1652994f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.9411764f, -1.0f, - 0.0f, 0.0f, -94.1176452f, 0.0f); - - CORRADE_COMPARE(camera.projectionMatrix(), a); - CORRADE_COMPARE(camera.projectionSize(), Vector2(0.48015756f)); + camera.setPerspective(Deg(27.0f), 2.35f, 32.0f, 100); + CORRADE_COMPARE(camera.projectionSize(), Vector2(0.48015756f, 0.204322f)); } void CameraTest::projectionSizeViewport() { @@ -209,3 +198,5 @@ void CameraTest::draw() { } }}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::CameraTest) diff --git a/src/SceneGraph/Test/CameraTest.h b/src/SceneGraph/Test/CameraTest.h deleted file mode 100644 index 1a9ab9198..000000000 --- a/src/SceneGraph/Test/CameraTest.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Magnum_SceneGraph_Test_CameraTest_h -#define Magnum_SceneGraph_Test_CameraTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace SceneGraph { namespace Test { - -class CameraTest: public Corrade::TestSuite::Tester { - public: - CameraTest(); - - void fixAspectRatio(); - void defaultProjection2D(); - void defaultProjection3D(); - void projection2D(); - void orthographic(); - void perspective(); - void projectionSizeViewport(); - void draw(); -}; - -}}} - -#endif diff --git a/src/SceneGraph/Test/DualComplexTransformationTest.cpp b/src/SceneGraph/Test/DualComplexTransformationTest.cpp new file mode 100644 index 000000000..d9c71d1c9 --- /dev/null +++ b/src/SceneGraph/Test/DualComplexTransformationTest.cpp @@ -0,0 +1,180 @@ +/* + 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 "SceneGraph/DualComplexTransformation.h" +#include "SceneGraph/Scene.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +typedef Object> Object2D; +typedef Scene> Scene2D; + +class DualComplexTransformationTest: public Corrade::TestSuite::Tester { + public: + explicit DualComplexTransformationTest(); + + void fromMatrix(); + void toMatrix(); + void compose(); + void inverted(); + + void setTransformation(); + void resetTransformation(); + void transform(); + void translate(); + void rotate(); + void normalizeRotation(); +}; + +DualComplexTransformationTest::DualComplexTransformationTest() { + addTests({&DualComplexTransformationTest::fromMatrix, + &DualComplexTransformationTest::toMatrix, + &DualComplexTransformationTest::compose, + &DualComplexTransformationTest::inverted, + + &DualComplexTransformationTest::setTransformation, + &DualComplexTransformationTest::resetTransformation, + &DualComplexTransformationTest::transform, + &DualComplexTransformationTest::translate, + &DualComplexTransformationTest::rotate, + &DualComplexTransformationTest::normalizeRotation}); +} + +void DualComplexTransformationTest::fromMatrix() { + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + DualComplex c = DualComplex::rotation(Deg(17.0f))*DualComplex::translation({1.0f, -0.3f}); + CORRADE_COMPARE(DualComplexTransformation<>::fromMatrix(m), c); +} + +void DualComplexTransformationTest::toMatrix() { + DualComplex c = DualComplex::rotation(Deg(17.0f))*DualComplex::translation({1.0f, -0.3f}); + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(DualComplexTransformation<>::toMatrix(c), m); +} + +void DualComplexTransformationTest::compose() { + DualComplex parent = DualComplex::rotation(Deg(17.0f)); + DualComplex child = DualComplex::translation({1.0f, -0.3f}); + CORRADE_COMPARE(DualComplexTransformation<>::compose(parent, child), parent*child); +} + +void DualComplexTransformationTest::inverted() { + DualComplex c = DualComplex::rotation(Deg(17.0f))*DualComplex::translation({1.0f, -0.3f}); + CORRADE_COMPARE(DualComplexTransformation<>::inverted(c)*c, DualComplex()); +} + +void DualComplexTransformationTest::setTransformation() { + Object2D o; + + /* Can't transform with non-rigid transformation */ + std::ostringstream out; + Error::setOutput(&out); + o.setTransformation(DualComplex({1.0f, 2.0f}, {})); + CORRADE_COMPARE(out.str(), "SceneGraph::DualComplexTransformation::setTransformation(): the dual complex number is not normalized\n"); + + /* Dirty after setting transformation */ + o.setClean(); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); + + /* Scene cannot be transformed */ + Scene2D s; + s.setClean(); + s.setTransformation(DualComplex::rotation(Deg(17.0f))); + CORRADE_VERIFY(!s.isDirty()); + CORRADE_COMPARE(s.transformationMatrix(), Matrix3()); +} + +void DualComplexTransformationTest::resetTransformation() { + Object2D o; + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + CORRADE_VERIFY(o.transformationMatrix() != Matrix3()); + o.resetTransformation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3()); +} + +void DualComplexTransformationTest::transform() { + { + /* Can't transform with non-rigid transformation */ + Object2D o; + std::ostringstream out; + Error::setOutput(&out); + o.transform(DualComplex({1.0f, 2.0f}, {})); + CORRADE_COMPARE(out.str(), "SceneGraph::DualComplexTransformation::transform(): the dual complex number is not normalized\n"); + } { + Object2D o; + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + o.transform(DualComplex::translation({1.0f, -0.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + o.transform(DualComplex::translation({1.0f, -0.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + +void DualComplexTransformationTest::translate() { + { + Object2D o; + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + o.translate({1.0f, -0.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + o.translate({1.0f, -0.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + +void DualComplexTransformationTest::rotate() { + { + Object2D o; + o.setTransformation(DualComplex::translation({1.0f, -0.3f})); + o.rotate(Deg(17.0f)); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } { + Object2D o; + o.setTransformation(DualComplex::translation({1.0f, -0.3f})); + o.rotate(Deg(17.0f), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } +} + +void DualComplexTransformationTest::normalizeRotation() { + Object2D o; + o.setTransformation(DualComplex::rotation(Deg(17.0f))); + o.normalizeRotation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::DualComplexTransformationTest) diff --git a/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp b/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp new file mode 100644 index 000000000..6de60f080 --- /dev/null +++ b/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp @@ -0,0 +1,197 @@ +/* + 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 "SceneGraph/DualQuaternionTransformation.h" +#include "SceneGraph/Scene.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +typedef Object> Object3D; +typedef Scene> Scene3D; + +class DualQuaternionTransformationTest: public Corrade::TestSuite::Tester { + public: + explicit DualQuaternionTransformationTest(); + + void fromMatrix(); + void toMatrix(); + void compose(); + void inverted(); + + void setTransformation(); + void resetTransformation(); + void transform(); + void translate(); + void rotate(); + void normalizeRotation(); +}; + +DualQuaternionTransformationTest::DualQuaternionTransformationTest() { + addTests({&DualQuaternionTransformationTest::fromMatrix, + &DualQuaternionTransformationTest::toMatrix, + &DualQuaternionTransformationTest::compose, + &DualQuaternionTransformationTest::inverted, + + &DualQuaternionTransformationTest::setTransformation, + &DualQuaternionTransformationTest::resetTransformation, + &DualQuaternionTransformationTest::transform, + &DualQuaternionTransformationTest::translate, + &DualQuaternionTransformationTest::rotate, + &DualQuaternionTransformationTest::normalizeRotation}); +} + +void DualQuaternionTransformationTest::fromMatrix() { + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); + DualQuaternion q = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())*DualQuaternion::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(DualQuaternionTransformation<>::fromMatrix(m), q); +} + +void DualQuaternionTransformationTest::toMatrix() { + DualQuaternion q = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())*DualQuaternion::translation({1.0f, -0.3f, 2.3f}); + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(DualQuaternionTransformation<>::toMatrix(q), m); +} + +void DualQuaternionTransformationTest::compose() { + DualQuaternion parent = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis()); + DualQuaternion child = DualQuaternion::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(DualQuaternionTransformation<>::compose(parent, child), parent*child); +} + +void DualQuaternionTransformationTest::inverted() { + DualQuaternion q = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())*DualQuaternion::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(DualQuaternionTransformation<>::inverted(q)*q, DualQuaternion()); +} + +void DualQuaternionTransformationTest::setTransformation() { + Object3D o; + + /* Can't transform with non-rigid transformation */ + std::ostringstream out; + Error::setOutput(&out); + o.setTransformation(DualQuaternion({{1.0f, 2.0f, 3.0f}, 4.0f}, {})); + CORRADE_COMPARE(out.str(), "SceneGraph::DualQuaternionTransformation::setTransformation(): the dual quaternion is not normalized\n"); + + /* Dirty after setting transformation */ + o.setClean(); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); + + /* Scene cannot be transformed */ + Scene3D s; + s.setClean(); + CORRADE_VERIFY(!s.isDirty()); + s.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + CORRADE_VERIFY(!s.isDirty()); + CORRADE_COMPARE(s.transformationMatrix(), Matrix4()); +} + +void DualQuaternionTransformationTest::resetTransformation() { + Object3D o; + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + CORRADE_VERIFY(o.transformationMatrix() != Matrix4()); + o.resetTransformation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4()); +} + +void DualQuaternionTransformationTest::transform() { + { + /* Can't transform with non-rigid transformation */ + Object3D o; + std::ostringstream out; + Error::setOutput(&out); + o.transform(DualQuaternion({{1.0f, 2.0f, 3.0f}, 4.0f}, {})); + CORRADE_COMPARE(out.str(), "SceneGraph::DualQuaternionTransformation::transform(): the dual quaternion is not normalized\n"); + } { + Object3D o; + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + o.transform(DualQuaternion::translation({1.0f, -0.3f, 2.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + o.transform(DualQuaternion::translation({1.0f, -0.3f, 2.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + +void DualQuaternionTransformationTest::translate() { + { + Object3D o; + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + o.translate({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + o.translate({1.0f, -0.3f, 2.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + +void DualQuaternionTransformationTest::rotate() { + { + Object3D o; + o.transform(DualQuaternion::translation({1.0f, -0.3f, 2.3f})); + o.rotateX(Deg(17.0f)) + ->rotateY(Deg(25.0f)) + ->rotateZ(Deg(-23.0f)) + ->rotate(Deg(96.0f), Vector3(1.0f/Constants::sqrt3())); + CORRADE_COMPARE(o.transformationMatrix(), + Matrix4::rotation(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()))* + Matrix4::rotationZ(Deg(-23.0f))* + Matrix4::rotationY(Deg(25.0f))* + Matrix4::rotationX(Deg(17.0f))* + Matrix4::translation({1.0f, -0.3f, 2.3f})); + } { + Object3D o; + o.transform(DualQuaternion::translation({1.0f, -0.3f, 2.3f})); + o.rotateX(Deg(17.0f), TransformationType::Local) + ->rotateY(Deg(25.0f), TransformationType::Local) + ->rotateZ(Deg(-23.0f), TransformationType::Local) + ->rotate(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), + Matrix4::translation({1.0f, -0.3f, 2.3f})* + Matrix4::rotationX(Deg(17.0f))* + Matrix4::rotationY(Deg(25.0f))* + Matrix4::rotationZ(Deg(-23.0f))* + Matrix4::rotation(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()))); + } +} + +void DualQuaternionTransformationTest::normalizeRotation() { + Object3D o; + o.setTransformation(DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())); + o.normalizeRotation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::DualQuaternionTransformationTest) diff --git a/src/SceneGraph/Test/MatrixTransformation2DTest.cpp b/src/SceneGraph/Test/MatrixTransformation2DTest.cpp new file mode 100644 index 000000000..91576e87f --- /dev/null +++ b/src/SceneGraph/Test/MatrixTransformation2DTest.cpp @@ -0,0 +1,187 @@ +/* + 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 "SceneGraph/MatrixTransformation2D.h" +#include "SceneGraph/Scene.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +typedef Object> Object2D; +typedef Scene> Scene2D; + +class MatrixTransformation2DTest: public Corrade::TestSuite::Tester { + public: + explicit MatrixTransformation2DTest(); + + void fromMatrix(); + void toMatrix(); + void compose(); + void inverted(); + + void setTransformation(); + void resetTransformation(); + void transform(); + void translate(); + void rotate(); + void scale(); + void reflect(); +}; + +MatrixTransformation2DTest::MatrixTransformation2DTest() { + addTests({&MatrixTransformation2DTest::fromMatrix, + &MatrixTransformation2DTest::toMatrix, + &MatrixTransformation2DTest::compose, + &MatrixTransformation2DTest::inverted, + + &MatrixTransformation2DTest::setTransformation, + &MatrixTransformation2DTest::resetTransformation, + &MatrixTransformation2DTest::transform, + &MatrixTransformation2DTest::translate, + &MatrixTransformation2DTest::rotate, + &MatrixTransformation2DTest::scale, + &MatrixTransformation2DTest::reflect}); +} + +void MatrixTransformation2DTest::fromMatrix() { + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(MatrixTransformation2D<>::fromMatrix(m), m); +} + +void MatrixTransformation2DTest::toMatrix() { + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(MatrixTransformation2D<>::toMatrix(m), m); +} + +void MatrixTransformation2DTest::compose() { + Matrix3 parent = Matrix3::rotation(Deg(17.0f)); + Matrix3 child = Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(MatrixTransformation2D<>::compose(parent, child), parent*child); +} + +void MatrixTransformation2DTest::inverted() { + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(MatrixTransformation2D<>::inverted(m)*m, Matrix3()); +} + +void MatrixTransformation2DTest::setTransformation() { + /* Dirty after setting transformation */ + Object2D o; + o.setClean(); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); + + /* Scene cannot be transformed */ + Scene2D s; + s.setClean(); + CORRADE_VERIFY(!s.isDirty()); + s.setTransformation(Matrix3::rotation(Deg(17.0f))); + CORRADE_VERIFY(!s.isDirty()); + CORRADE_COMPARE(s.transformationMatrix(), Matrix3()); +} + +void MatrixTransformation2DTest::resetTransformation() { + Object2D o; + o.rotate(Deg(17.0f)); + CORRADE_VERIFY(o.transformationMatrix() != Matrix3()); + o.resetTransformation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3()); +} + +void MatrixTransformation2DTest::transform() { + { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.transform(Matrix3::translation({1.0f, -0.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.transform(Matrix3::translation({1.0f, -0.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + +void MatrixTransformation2DTest::translate() { + { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.translate({1.0f, -0.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.translate({1.0f, -0.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + +void MatrixTransformation2DTest::rotate() { + { + Object2D o; + o.setTransformation(Matrix3::translation({1.0f, -0.3f})); + o.rotate(Deg(17.0f)); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } { + Object2D o; + o.setTransformation(Matrix3::translation({1.0f, -0.3f})); + o.rotate(Deg(17.0f), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } +} + +void MatrixTransformation2DTest::scale() { + { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.scale({1.0f, -0.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::scaling({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.scale({1.0f, -0.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::scaling({1.0f, -0.3f})); + } +} + +void MatrixTransformation2DTest::reflect() { + { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.reflect(Vector2(-1.0f/Constants::sqrt2())); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::reflection(Vector2(-1.0f/Constants::sqrt2()))*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.reflect(Vector2(-1.0f/Constants::sqrt2()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::reflection(Vector2(-1.0f/Constants::sqrt2()))); + } +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::MatrixTransformation2DTest) diff --git a/src/SceneGraph/Test/MatrixTransformation3DTest.cpp b/src/SceneGraph/Test/MatrixTransformation3DTest.cpp new file mode 100644 index 000000000..651d8101d --- /dev/null +++ b/src/SceneGraph/Test/MatrixTransformation3DTest.cpp @@ -0,0 +1,203 @@ +/* + 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 "SceneGraph/MatrixTransformation3D.h" +#include "SceneGraph/Scene.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +typedef Object> Object3D; +typedef Scene> Scene3D; + +class MatrixTransformation3DTest: public Corrade::TestSuite::Tester { + public: + explicit MatrixTransformation3DTest(); + + void fromMatrix(); + void toMatrix(); + void compose(); + void inverted(); + + void setTransformation(); + void resetTransformation(); + void transform(); + void translate(); + void rotate(); + void scale(); + void reflect(); +}; + +MatrixTransformation3DTest::MatrixTransformation3DTest() { + addTests({&MatrixTransformation3DTest::fromMatrix, + &MatrixTransformation3DTest::toMatrix, + &MatrixTransformation3DTest::compose, + &MatrixTransformation3DTest::inverted, + + &MatrixTransformation3DTest::setTransformation, + &MatrixTransformation3DTest::resetTransformation, + &MatrixTransformation3DTest::transform, + &MatrixTransformation3DTest::translate, + &MatrixTransformation3DTest::rotate, + &MatrixTransformation3DTest::scale, + &MatrixTransformation3DTest::reflect}); +} + +void MatrixTransformation3DTest::fromMatrix() { + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); + CORRADE_COMPARE(MatrixTransformation3D<>::fromMatrix(m), m); +} + +void MatrixTransformation3DTest::toMatrix() { + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); + CORRADE_COMPARE(MatrixTransformation3D<>::toMatrix(m), m); +} + +void MatrixTransformation3DTest::compose() { + Matrix4 parent = Matrix4::rotationX(Deg(17.0f)); + Matrix4 child = Matrix4::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(MatrixTransformation3D<>::compose(parent, child), parent*child); +} + +void MatrixTransformation3DTest::inverted() { + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); + CORRADE_COMPARE(MatrixTransformation3D<>::inverted(m)*m, Matrix4()); +} + +void MatrixTransformation3DTest::setTransformation() { + /* Dirty after setting transformation */ + Object3D o; + o.setClean(); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); + + /* Scene cannot be transformed */ + Scene3D s; + s.setClean(); + CORRADE_VERIFY(!s.isDirty()); + s.setTransformation(Matrix4::rotationX(Deg(17.0f))); + CORRADE_VERIFY(!s.isDirty()); + CORRADE_COMPARE(s.transformationMatrix(), Matrix4()); +} + +void MatrixTransformation3DTest::resetTransformation() { + Object3D o; + o.rotateX(Deg(17.0f)); + CORRADE_VERIFY(o.transformationMatrix() != Matrix4()); + o.resetTransformation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4()); +} + +void MatrixTransformation3DTest::transform() { + { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.transform(Matrix4::translation({1.0f, -0.3f, 2.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.transform(Matrix4::translation({1.0f, -0.3f, 2.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + +void MatrixTransformation3DTest::translate() { + { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.translate({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.translate({1.0f, -0.3f, 2.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + +void MatrixTransformation3DTest::rotate() { + { + Object3D o; + o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); + o.rotateX(Deg(17.0f)) + ->rotateY(Deg(25.0f)) + ->rotateZ(Deg(-23.0f)) + ->rotate(Deg(96.0f), Vector3(1.0f/Constants::sqrt3())); + CORRADE_COMPARE(o.transformationMatrix(), + Matrix4::rotation(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()))* + Matrix4::rotationZ(Deg(-23.0f))* + Matrix4::rotationY(Deg(25.0f))* + Matrix4::rotationX(Deg(17.0f))* + Matrix4::translation({1.0f, -0.3f, 2.3f})); + } { + Object3D o; + o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); + o.rotateX(Deg(17.0f), TransformationType::Local) + ->rotateY(Deg(25.0f), TransformationType::Local) + ->rotateZ(Deg(-23.0f), TransformationType::Local) + ->rotate(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), + Matrix4::translation({1.0f, -0.3f, 2.3f})* + Matrix4::rotationX(Deg(17.0f))* + Matrix4::rotationY(Deg(25.0f))* + Matrix4::rotationZ(Deg(-23.0f))* + Matrix4::rotation(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()))); + } +} + +void MatrixTransformation3DTest::scale() { + { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.scale({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::scaling({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.scale({1.0f, -0.3f, 2.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::scaling({1.0f, -0.3f, 2.3f})); + } +} + +void MatrixTransformation3DTest::reflect() { + { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.reflect(Vector3(-1.0f/Constants::sqrt3())); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::reflection(Vector3(-1.0f/Constants::sqrt3()))*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.reflect(Vector3(-1.0f/Constants::sqrt3()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::reflection(Vector3(-1.0f/Constants::sqrt3()))); + } +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::MatrixTransformation3DTest) diff --git a/src/SceneGraph/Test/ObjectTest.cpp b/src/SceneGraph/Test/ObjectTest.cpp index abe60f4c7..51f1187f2 100644 --- a/src/SceneGraph/Test/ObjectTest.cpp +++ b/src/SceneGraph/Test/ObjectTest.cpp @@ -1,32 +1,50 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ObjectTest.h" - #include +#include -#include "Math/Constants.h" #include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/Scene.h" -using namespace std; - -CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::ObjectTest) - namespace Magnum { namespace SceneGraph { namespace Test { +class ObjectTest: public Corrade::TestSuite::Tester { + public: + ObjectTest(); + + void parenting(); + void scene(); + void absoluteTransformation(); + void transformations(); + void transformationsRelative(); + void transformationsOrphan(); + void transformationsDuplicate(); + void setClean(); + void bulkSetClean(); +}; + typedef SceneGraph::Object> Object3D; typedef SceneGraph::Scene> Scene3D; @@ -45,12 +63,15 @@ class CachingObject: public Object3D, AbstractFeature<3> { }; ObjectTest::ObjectTest() { - addTests(&ObjectTest::parenting, - &ObjectTest::scene, - &ObjectTest::absoluteTransformation, - &ObjectTest::transformations, - &ObjectTest::setClean, - &ObjectTest::bulkSetClean); + addTests({&ObjectTest::parenting, + &ObjectTest::scene, + &ObjectTest::absoluteTransformation, + &ObjectTest::transformations, + &ObjectTest::transformationsRelative, + &ObjectTest::transformationsOrphan, + &ObjectTest::transformationsDuplicate, + &ObjectTest::setClean, + &ObjectTest::bulkSetClean}); } void ObjectTest::parenting() { @@ -103,10 +124,12 @@ void ObjectTest::absoluteTransformation() { /* Proper transformation composition */ Object3D o(&s); o.translate(Vector3::xAxis(2.0f)); + CORRADE_COMPARE(o.transformation(), Matrix4::translation(Vector3::xAxis(2.0f))); + CORRADE_COMPARE(o.transformation(), o.transformationMatrix()); Object3D o2(&o); - o2.rotateY(deg(90.0f)); + o2.rotateY(Deg(90.0f)); CORRADE_COMPARE(o2.absoluteTransformation(), - Matrix4::translation(Vector3::xAxis(2.0f))*Matrix4::rotationY(deg(90.0f))); + Matrix4::translation(Vector3::xAxis(2.0f))*Matrix4::rotationY(Deg(90.0f))); CORRADE_COMPARE(o2.absoluteTransformation(), o2.absoluteTransformationMatrix()); /* Transformation of root object */ @@ -118,74 +141,102 @@ void ObjectTest::absoluteTransformation() { void ObjectTest::transformations() { Scene3D s; - Matrix4 initial = Matrix4::rotationX(deg(90.0f)).inverted(); + Matrix4 initial = Matrix4::rotationX(Deg(90.0f)).inverted(); /* Empty list */ - CORRADE_COMPARE(s.transformations(vector(), initial), vector()); + CORRADE_COMPARE(s.transformations(std::vector(), initial), std::vector()); /* Scene alone */ - CORRADE_COMPARE(s.transformations({&s}, initial), vector{initial}); + CORRADE_COMPARE(s.transformations({&s}, initial), std::vector{initial}); /* One object */ Object3D first(&s); - first.rotateZ(deg(30.0f)); + first.rotateZ(Deg(30.0f)); Object3D second(&first); second.scale(Vector3(0.5f)); - CORRADE_COMPARE(s.transformations({&second}, initial), vector{ - initial*Matrix4::rotationZ(deg(30.0f))*Matrix4::scaling(Vector3(0.5f)) + CORRADE_COMPARE(s.transformations({&second}, initial), std::vector{ + initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)) }); /* One object and scene */ - CORRADE_COMPARE(s.transformations({&second, &s}, initial), (vector{ - initial*Matrix4::rotationZ(deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), + CORRADE_COMPARE(s.transformations({&second, &s}, initial), (std::vector{ + initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial })); /* Two objects with foreign joint */ Object3D third(&first); third.translate(Vector3::xAxis(5.0f)); - CORRADE_COMPARE(s.transformations({&second, &third}, initial), (vector{ - initial*Matrix4::rotationZ(deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), - initial*Matrix4::rotationZ(deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), + CORRADE_COMPARE(s.transformations({&second, &third}, initial), (std::vector{ + initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), + initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), })); /* Three objects with joint as one of them */ - CORRADE_COMPARE(s.transformations({&second, &third, &first}, initial), (vector{ - initial*Matrix4::rotationZ(deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), - initial*Matrix4::rotationZ(deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), - initial*Matrix4::rotationZ(deg(30.0f)), + CORRADE_COMPARE(s.transformations({&second, &third, &first}, initial), (std::vector{ + initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), + initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), + initial*Matrix4::rotationZ(Deg(30.0f)), })); +} + +void ObjectTest::transformationsRelative() { + CORRADE_EXPECT_FAIL("Transformations not relative to scene are not yet implemented."); + + Scene3D s; + Object3D first(&s); + first.rotateZ(Deg(30.0f)); + Object3D second(&first); + second.scale(Vector3(0.5f)); + Object3D third(&first); + third.translate(Vector3::xAxis(5.0f)); - { - CORRADE_EXPECT_FAIL("Transformations not relative to scene are not yet implemented."); - - /* Transformation relative to another object */ - CORRADE_COMPARE(second.transformations({&third}), vector{ - Matrix4::scaling(Vector3(0.5f)).inverted()*Matrix4::translation(Vector3::xAxis(5.0f)) - }); - - /* Transformation relative to another object, not part of any scene (but should work) */ - Object3D orphanParent1; - orphanParent1.rotate(deg(31.0f), Vector3(1.0f).normalized()); - Object3D orphanParent(&orphanParent1); - Object3D orphan1(&orphanParent); - orphan1.scale(Vector3::xScale(3.0f)); - Object3D orphan2(&orphanParent); - orphan2.translate(Vector3::zAxis(5.0f)); - CORRADE_COMPARE(orphan1.transformations({&orphan2}), vector{ - Matrix4::scaling(Vector3::xScale(3.0f)).inverted()*Matrix4::translation(Vector3::zAxis(5.0f)) - }); - } - - ostringstream o; + /* Transformation relative to another object */ + CORRADE_COMPARE(second.transformations({&third}), std::vector{ + Matrix4::scaling(Vector3(0.5f)).inverted()*Matrix4::translation(Vector3::xAxis(5.0f)) + }); + + /* Transformation relative to another object, not part of any scene (but should work) */ + Object3D orphanParent1; + orphanParent1.rotate(Deg(31.0f), Vector3(1.0f).normalized()); + Object3D orphanParent(&orphanParent1); + Object3D orphan1(&orphanParent); + orphan1.scale(Vector3::xScale(3.0f)); + Object3D orphan2(&orphanParent); + orphan2.translate(Vector3::zAxis(5.0f)); + CORRADE_COMPARE(orphan1.transformations({&orphan2}), std::vector{ + Matrix4::scaling(Vector3::xScale(3.0f)).inverted()*Matrix4::translation(Vector3::zAxis(5.0f)) + }); +} + +void ObjectTest::transformationsOrphan() { + std::ostringstream o; Error::setOutput(&o); /* Transformation of objects not part of the same scene */ + Scene3D s; Object3D orphan; - CORRADE_COMPARE(s.transformations({&orphan}), vector()); + CORRADE_COMPARE(s.transformations({&orphan}), std::vector()); CORRADE_COMPARE(o.str(), "SceneGraph::Object::transformations(): the objects are not part of the same tree\n"); } +void ObjectTest::transformationsDuplicate() { + Scene3D s; + Object3D first(&s); + first.rotateZ(Deg(30.0f)); + Object3D second(&first); + second.scale(Vector3(0.5f)); + Object3D third(&first); + third.translate(Vector3::xAxis(5.0f)); + + Matrix4 firstExpected = Matrix4::rotationZ(Deg(30.0f)); + Matrix4 secondExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)); + Matrix4 thirdExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)); + CORRADE_COMPARE(s.transformations({&second, &third, &second, &first, &third}), (std::vector{ + secondExpected, thirdExpected, secondExpected, firstExpected, thirdExpected + })); +} + void ObjectTest::setClean() { Scene3D scene; @@ -224,7 +275,7 @@ void ObjectTest::setClean() { CachingInvertedFeature* childTwoFeature2 = new CachingInvertedFeature(childTwo); CachingObject* childThree = new CachingObject(childTwo); - childThree->rotate(deg(90.0f), Vector3::yAxis()); + childThree->rotate(Deg(90.0f), Vector3::yAxis()); /* Object is dirty at the beginning */ CORRADE_VERIFY(scene.isDirty()); @@ -283,7 +334,7 @@ void ObjectTest::setClean() { void ObjectTest::bulkSetClean() { /* Verify it doesn't crash when passed empty list */ - Object3D::setClean(vector()); + Object3D::setClean(std::vector()); Scene3D scene; Object3D a(&scene); @@ -294,7 +345,7 @@ void ObjectTest::bulkSetClean() { CachingObject d(&c); d.scale(Vector3(-2.0f)); Object3D e(&scene); - vector cleanAll{&a, &b, &c, &d, &e}; + std::vector cleanAll{&a, &b, &c, &d, &e}; /* All objects should be cleaned */ CORRADE_VERIFY(a.isDirty()); @@ -314,3 +365,5 @@ void ObjectTest::bulkSetClean() { } }}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::ObjectTest) diff --git a/src/SceneGraph/Test/ObjectTest.h b/src/SceneGraph/Test/ObjectTest.h deleted file mode 100644 index 7a04a1bd5..000000000 --- a/src/SceneGraph/Test/ObjectTest.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Magnum_SceneGraph_Test_ObjectTest_h -#define Magnum_SceneGraph_Test_ObjectTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace SceneGraph { namespace Test { - -class ObjectTest: public Corrade::TestSuite::Tester { - public: - ObjectTest(); - - void parenting(); - void scene(); - void absoluteTransformation(); - void transformations(); - void setClean(); - void bulkSetClean(); -}; - -}}} - -#endif diff --git a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp new file mode 100644 index 000000000..dccefa1b3 --- /dev/null +++ b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp @@ -0,0 +1,199 @@ +/* + 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 "SceneGraph/RigidMatrixTransformation2D.h" +#include "SceneGraph/Scene.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +typedef Object> Object2D; +typedef Scene> Scene2D; + +class RigidMatrixTransformation2DTest: public Corrade::TestSuite::Tester { + public: + explicit RigidMatrixTransformation2DTest(); + + void fromMatrix(); + void toMatrix(); + void compose(); + void inverted(); + + void setTransformation(); + void resetTransformation(); + void transform(); + void translate(); + void rotate(); + void reflect(); + void normalizeRotation(); +}; + +RigidMatrixTransformation2DTest::RigidMatrixTransformation2DTest() { + addTests({&RigidMatrixTransformation2DTest::fromMatrix, + &RigidMatrixTransformation2DTest::toMatrix, + &RigidMatrixTransformation2DTest::compose, + &RigidMatrixTransformation2DTest::inverted, + + &RigidMatrixTransformation2DTest::setTransformation, + &RigidMatrixTransformation2DTest::resetTransformation, + &RigidMatrixTransformation2DTest::transform, + &RigidMatrixTransformation2DTest::translate, + &RigidMatrixTransformation2DTest::rotate, + &RigidMatrixTransformation2DTest::reflect, + &RigidMatrixTransformation2DTest::normalizeRotation}); +} + +void RigidMatrixTransformation2DTest::fromMatrix() { + std::ostringstream o; + Error::setOutput(&o); + RigidMatrixTransformation2D<>::fromMatrix(Matrix3::scaling(Vector2(4.0f))); + CORRADE_COMPARE(o.str(), "SceneGraph::RigidMatrixTransformation2D::fromMatrix(): the matrix doesn't represent rigid transformation\n"); + + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(RigidMatrixTransformation2D<>::fromMatrix(m), m); +} + +void RigidMatrixTransformation2DTest::toMatrix() { + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(RigidMatrixTransformation2D<>::toMatrix(m), m); +} + +void RigidMatrixTransformation2DTest::compose() { + Matrix3 parent = Matrix3::rotation(Deg(17.0f)); + Matrix3 child = Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(RigidMatrixTransformation2D<>::compose(parent, child), parent*child); +} + +void RigidMatrixTransformation2DTest::inverted() { + Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); + CORRADE_COMPARE(RigidMatrixTransformation2D<>::inverted(m)*m, Matrix3()); +} + +void RigidMatrixTransformation2DTest::setTransformation() { + Object2D o; + + /* Can't transform with non-rigid transformation */ + std::ostringstream out; + Error::setOutput(&out); + o.setTransformation(Matrix3::scaling(Vector2(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation2D::setTransformation(): the matrix doesn't represent rigid transformation\n"); + + /* Dirty after setting transformation */ + o.setClean(); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); + + /* Scene cannot be transformed */ + Scene2D s; + s.setClean(); + s.setTransformation(Matrix3::rotation(Deg(17.0f))); + CORRADE_VERIFY(!s.isDirty()); + CORRADE_COMPARE(s.transformationMatrix(), Matrix3()); +} + +void RigidMatrixTransformation2DTest::resetTransformation() { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + CORRADE_VERIFY(o.transformationMatrix() != Matrix3()); + o.resetTransformation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3()); +} + +void RigidMatrixTransformation2DTest::transform() { + { + /* Can't transform with non-rigid transformation */ + Object2D o; + std::ostringstream out; + Error::setOutput(&out); + o.transform(Matrix3::scaling(Vector2(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation2D::transform(): the matrix doesn't represent rigid transformation\n"); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.transform(Matrix3::translation({1.0f, -0.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.transform(Matrix3::translation({1.0f, -0.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + +void RigidMatrixTransformation2DTest::translate() { + { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.translate({1.0f, -0.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.translate({1.0f, -0.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + +void RigidMatrixTransformation2DTest::rotate() { + { + Object2D o; + o.setTransformation(Matrix3::translation({1.0f, -0.3f})); + o.rotate(Deg(17.0f)); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } { + Object2D o; + o.setTransformation(Matrix3::translation({1.0f, -0.3f})); + o.rotate(Deg(17.0f), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } +} + +void RigidMatrixTransformation2DTest::reflect() { + { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.reflect(Vector2(-1.0f/Constants::sqrt2())); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::reflection(Vector2(-1.0f/Constants::sqrt2()))*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.reflect(Vector2(-1.0f/Constants::sqrt2()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::reflection(Vector2(-1.0f/Constants::sqrt2()))); + } +} + +void RigidMatrixTransformation2DTest::normalizeRotation() { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.normalizeRotation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::RigidMatrixTransformation2DTest) diff --git a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp new file mode 100644 index 000000000..2d14c3bab --- /dev/null +++ b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp @@ -0,0 +1,216 @@ +/* + 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 "SceneGraph/RigidMatrixTransformation3D.h" +#include "SceneGraph/Scene.h" + +namespace Magnum { namespace SceneGraph { namespace Test { + +typedef Object> Object3D; +typedef Scene> Scene3D; + +class RigidMatrixTransformation3DTest: public Corrade::TestSuite::Tester { + public: + explicit RigidMatrixTransformation3DTest(); + + void fromMatrix(); + void toMatrix(); + void compose(); + void inverted(); + + void setTransformation(); + void resetTransformation(); + void transform(); + void translate(); + void rotate(); + void reflect(); + void normalizeRotation(); +}; + +RigidMatrixTransformation3DTest::RigidMatrixTransformation3DTest() { + addTests({&RigidMatrixTransformation3DTest::fromMatrix, + &RigidMatrixTransformation3DTest::toMatrix, + &RigidMatrixTransformation3DTest::compose, + &RigidMatrixTransformation3DTest::inverted, + + &RigidMatrixTransformation3DTest::setTransformation, + &RigidMatrixTransformation3DTest::resetTransformation, + &RigidMatrixTransformation3DTest::transform, + &RigidMatrixTransformation3DTest::translate, + &RigidMatrixTransformation3DTest::rotate, + &RigidMatrixTransformation3DTest::reflect, + &RigidMatrixTransformation3DTest::normalizeRotation}); +} + +void RigidMatrixTransformation3DTest::fromMatrix() { + std::ostringstream o; + Error::setOutput(&o); + RigidMatrixTransformation3D<>::fromMatrix(Matrix4::scaling(Vector3(4.0f))); + CORRADE_COMPARE(o.str(), "SceneGraph::RigidMatrixTransformation3D::fromMatrix(): the matrix doesn't represent rigid transformation\n"); + + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(RigidMatrixTransformation3D<>::fromMatrix(m), m); +} + +void RigidMatrixTransformation3DTest::toMatrix() { + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(RigidMatrixTransformation3D<>::toMatrix(m), m); +} + +void RigidMatrixTransformation3DTest::compose() { + Matrix4 parent = Matrix4::rotationX(Deg(17.0f)); + Matrix4 child = Matrix4::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(RigidMatrixTransformation3D<>::compose(parent, child), parent*child); +} + +void RigidMatrixTransformation3DTest::inverted() { + Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(RigidMatrixTransformation3D<>::inverted(m)*m, Matrix4()); +} + +void RigidMatrixTransformation3DTest::setTransformation() { + Object3D o; + + /* Can't transform with non-rigid transformation */ + std::ostringstream out; + Error::setOutput(&out); + o.setTransformation(Matrix4::scaling(Vector3(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation3D::setTransformation(): the matrix doesn't represent rigid transformation\n"); + + /* Dirty after setting transformation */ + o.setClean(); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); + + /* Scene cannot be transformed */ + Scene3D s; + s.setClean(); + CORRADE_VERIFY(!s.isDirty()); + s.setTransformation(Matrix4::rotationX(Deg(17.0f))); + CORRADE_VERIFY(!s.isDirty()); + CORRADE_COMPARE(s.transformationMatrix(), Matrix4()); +} + +void RigidMatrixTransformation3DTest::resetTransformation() { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + CORRADE_VERIFY(o.transformationMatrix() != Matrix4()); + o.resetTransformation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4()); +} + +void RigidMatrixTransformation3DTest::transform() { + { + /* Can't transform with non-rigid transformation */ + Object3D o; + std::ostringstream out; + Error::setOutput(&out); + o.transform(Matrix4::scaling(Vector3(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation3D::transform(): the matrix doesn't represent rigid transformation\n"); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.transform(Matrix4::translation({1.0f, -0.3f, 2.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.transform(Matrix4::translation({1.0f, -0.3f, 2.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + +void RigidMatrixTransformation3DTest::translate() { + { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.translate({1.0f, -0.3f, 2.3f}); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.translate({1.0f, -0.3f, 2.3f}, TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + +void RigidMatrixTransformation3DTest::rotate() { + { + Object3D o; + o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); + o.rotateX(Deg(17.0f)) + ->rotateY(Deg(25.0f)) + ->rotateZ(Deg(-23.0f)) + ->rotate(Deg(96.0f), Vector3(1.0f/Constants::sqrt3())); + CORRADE_COMPARE(o.transformationMatrix(), + Matrix4::rotation(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()))* + Matrix4::rotationZ(Deg(-23.0f))* + Matrix4::rotationY(Deg(25.0f))* + Matrix4::rotationX(Deg(17.0f))* + Matrix4::translation({1.0f, -0.3f, 2.3f})); + } { + Object3D o; + o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); + o.rotateX(Deg(17.0f), TransformationType::Local) + ->rotateY(Deg(25.0f), TransformationType::Local) + ->rotateZ(Deg(-23.0f), TransformationType::Local) + ->rotate(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), + Matrix4::translation({1.0f, -0.3f, 2.3f})* + Matrix4::rotationX(Deg(17.0f))* + Matrix4::rotationY(Deg(25.0f))* + Matrix4::rotationZ(Deg(-23.0f))* + Matrix4::rotation(Deg(96.0f), Vector3(1.0f/Constants::sqrt3()))); + } +} + +void RigidMatrixTransformation3DTest::reflect() { + { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.reflect(Vector3(-1.0f/Constants::sqrt3())); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::reflection(Vector3(-1.0f/Constants::sqrt3()))*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.reflect(Vector3(-1.0f/Constants::sqrt3()), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::reflection(Vector3(-1.0f/Constants::sqrt3()))); + } +} + +void RigidMatrixTransformation3DTest::normalizeRotation() { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.normalizeRotation(); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::RigidMatrixTransformation3DTest) diff --git a/src/SceneGraph/Test/SceneTest.cpp b/src/SceneGraph/Test/SceneTest.cpp index 301a82846..d3731a11d 100644 --- a/src/SceneGraph/Test/SceneTest.cpp +++ b/src/SceneGraph/Test/SceneTest.cpp @@ -1,34 +1,48 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "SceneTest.h" +#include -#include "Magnum.h" #include "SceneGraph/MatrixTransformation3D.h" #include "SceneGraph/Scene.h" -CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::SceneTest) - namespace Magnum { namespace SceneGraph { namespace Test { -typedef SceneGraph::Scene> Scene3D; -typedef SceneGraph::Object> Object3D; +class SceneTest: public Corrade::TestSuite::Tester { + public: + SceneTest(); + + void transformation(); + void parent(); +}; + +typedef SceneGraph::Scene> Scene3D; +typedef SceneGraph::Object> Object3D; SceneTest::SceneTest() { - addTests(&SceneTest::transformation, - &SceneTest::parent); + addTests({&SceneTest::transformation, + &SceneTest::parent}); } void SceneTest::transformation() { @@ -52,3 +66,5 @@ void SceneTest::parent() { } }}} + +CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::SceneTest) diff --git a/src/SceneGraph/Test/SceneTest.h b/src/SceneGraph/Test/SceneTest.h deleted file mode 100644 index 6d1af5c9b..000000000 --- a/src/SceneGraph/Test/SceneTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_SceneGraph_Test_SceneTest_h -#define Magnum_SceneGraph_Test_SceneTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace SceneGraph { namespace Test { - -class SceneTest: public Corrade::TestSuite::Tester { - public: - SceneTest(); - - void transformation(); - void parent(); -}; - -}}} - -#endif diff --git a/src/SceneGraph/magnumSceneGraphVisibility.h b/src/SceneGraph/magnumSceneGraphVisibility.h index cd1be31fa..b4b023eef 100644 --- a/src/SceneGraph/magnumSceneGraphVisibility.h +++ b/src/SceneGraph/magnumSceneGraphVisibility.h @@ -1,18 +1,27 @@ #ifndef Magnum_SceneGraph_magnumSceneGraphVisibility_h #define Magnum_SceneGraph_magnumSceneGraphVisibility_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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. */ #ifdef _WIN32 @@ -21,10 +30,10 @@ #else #define MAGNUM_SCENEGRAPH_EXPORT __declspec(dllimport) #endif - #define SCENEGRAPH_LOCAL + #define MAGNUM_SCENEGRAPH_LOCAL #else #define MAGNUM_SCENEGRAPH_EXPORT __attribute__ ((visibility ("default"))) - #define SCENEGRAPH_LOCAL __attribute__ ((visibility ("hidden"))) + #define MAGNUM_SCENEGRAPH_LOCAL __attribute__ ((visibility ("hidden"))) #endif #endif diff --git a/src/Shader.cpp b/src/Shader.cpp index 5695b383a..741d2b3c3 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -1,22 +1,31 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Shader.h" #include -#include +#include #define COMPILER_MESSAGE_MAX_LENGTH 1024 @@ -25,8 +34,6 @@ typedef char GLchar; #endif -using namespace std; - namespace Magnum { Shader::Shader(Version version, Type type): _type(type), _state(State::Initialized), shader(0) { @@ -34,23 +41,25 @@ Shader::Shader(Version version, Type type): _type(type), _state(State::Initializ switch(version) { #ifndef MAGNUM_TARGET_GLES - case Version::GL210: addSource("#version 120\n"); break; - case Version::GL300: addSource("#version 130\n"); break; - case Version::GL310: addSource("#version 140\n"); break; - case Version::GL320: addSource("#version 150\n"); break; - case Version::GL330: addSource("#version 330\n"); break; - case Version::GL400: addSource("#version 400\n"); break; - case Version::GL410: addSource("#version 410\n"); break; - case Version::GL420: addSource("#version 420\n"); break; - case Version::GL430: addSource("#version 430\n"); break; + 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; #else - case Version::GLES200: addSource("#version 100\n"); break; - case Version::GLES300: addSource("#version 300\n"); break; + case Version::GLES200: addSource("#version 100\n"); return; + case Version::GLES300: addSource("#version 300\n"); return; #endif - default: - CORRADE_ASSERT(false, "Shader::Shader(): unsupported version" << GLint(version), ); + case Version::None: + CORRADE_ASSERT(false, "Shader::Shader(): unsupported version" << version, ); } + + CORRADE_INTERNAL_ASSERT(false); } Shader::Shader(Shader&& other): _type(other._type), _state(other._state), sources(other.sources), shader(other.shader) { @@ -72,7 +81,7 @@ Shader& Shader::operator=(Shader&& other) { bool Shader::addFile(const std::string& filename) { /* Open file */ - ifstream file(filename.c_str()); + std::ifstream file(filename.c_str()); if(!file.good()) { file.close(); @@ -81,13 +90,13 @@ bool Shader::addFile(const std::string& filename) { } /* Get size of shader and initialize buffer */ - file.seekg(0, ios::end); - size_t size = file.tellg(); + file.seekg(0, std::ios::end); + std::size_t size = file.tellg(); char* source = new char[size+1]; source[size] = '\0'; /* Read data, close */ - file.seekg(0, ios::beg); + file.seekg(0, std::ios::beg); file.read(source, size); file.close(); @@ -104,7 +113,7 @@ GLuint Shader::compile() { /* Array of sources */ const GLchar** _sources = new const GLchar*[sources.size()]; - for(size_t i = 0; i != sources.size(); ++i) + for(std::size_t i = 0; i != sources.size(); ++i) _sources[i] = static_cast(sources[i].c_str()); /* Create shader and set its source */ diff --git a/src/Shader.h b/src/Shader.h index 643674b77..5332b0e7b 100644 --- a/src/Shader.h +++ b/src/Shader.h @@ -1,18 +1,27 @@ #ifndef Magnum_Shader_h #define Magnum_Shader_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -30,11 +39,10 @@ namespace Magnum { /** - * @brief %Shader - * - * Allows loading and compiling the shader from file or directly from source - * string. Compiled shaders are then passed to AbstractShaderProgram subclasses - * for linking and usage. +@brief %Shader + +Allows loading and compiling the shader from file or directly from source +string. See AbstractShaderProgram for more information. */ class MAGNUM_EXPORT Shader { Shader(const Shader& other) = delete; @@ -48,28 +56,28 @@ class MAGNUM_EXPORT Shader { #ifndef MAGNUM_TARGET_GLES /** * Tessellation control shader - * @requires_gl40 Extension @extension{ARB,tessellation_shader} + * @requires_gl40 %Extension @extension{ARB,tessellation_shader} * @requires_gl Tessellation shaders are not available in OpenGL ES. */ TessellationControl = GL_TESS_CONTROL_SHADER, /** * Tessellation evaluation shader - * @requires_gl40 Extension @extension{ARB,tessellation_shader} + * @requires_gl40 %Extension @extension{ARB,tessellation_shader} * @requires_gl Tessellation shaders are not available in OpenGL ES. */ TessellationEvaluation = GL_TESS_EVALUATION_SHADER, /** * Geometry shader - * @requires_gl32 Extension @extension{ARB,geometry_shader4} + * @requires_gl32 %Extension @extension{ARB,geometry_shader4} * @requires_gl Geometry shaders are not available in OpenGL ES. */ Geometry = GL_GEOMETRY_SHADER, /** * Compute shader - * @requires_gl43 Extension @extension{ARB,compute_shader} + * @requires_gl43 %Extension @extension{ARB,compute_shader} * @requires_gl Compute shaders are not available in OpenGL ES. */ Compute = GL_COMPUTE_SHADER, @@ -136,7 +144,7 @@ class MAGNUM_EXPORT Shader { * beginning. Sources can be added with addSource() or addFile(). * @see fromData(), fromFile(), @fn_gl{CreateShader} */ - Shader(Version version, Type type); + explicit Shader(Version version, Type type); /** * @brief Destructor diff --git a/src/Shaders/AbstractVectorShader.h b/src/Shaders/AbstractVectorShader.h new file mode 100644 index 000000000..75d2f6e23 --- /dev/null +++ b/src/Shaders/AbstractVectorShader.h @@ -0,0 +1,67 @@ +#ifndef Magnum_Shaders_AbstractVectorShader_h +#define Magnum_Shaders_AbstractVectorShader_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::AbstractVectorShader, typedef Magnum::Shaders::AbstractVectorShader2D, Magnum::Shaders::AbstractVectorShader3D + */ + +#include "AbstractShaderProgram.h" +#include "Color.h" +#include "DimensionTraits.h" + +namespace Magnum { namespace Shaders { + +/** +@brief Base for vector shaders + +@see AbstractVectorShader2D, AbstractVectorShader3D +*/ +template class AbstractVectorShader: public AbstractShaderProgram { + public: + /** @brief Vertex position */ + typedef Attribute<0, typename DimensionTraits::VectorType> Position; + + /** @brief Texture coordinates */ + typedef Attribute<1, Vector2> TextureCoordinates; + + enum: Int { + VectorTextureLayer = 16 /**< Layer for vector texture */ + }; + + virtual ~AbstractVectorShader() = 0; +}; + +template inline AbstractVectorShader::~AbstractVectorShader() {} + +/** @brief Base for two-dimensional text shaders */ +typedef AbstractVectorShader<2> AbstractVectorShader2D; + +/** @brief Base for three-dimensional text shader */ +typedef AbstractVectorShader<3> AbstractVectorShader3D; + +}} + +#endif diff --git a/src/Shaders/AbstractVectorShader2D.vert b/src/Shaders/AbstractVectorShader2D.vert new file mode 100644 index 000000000..6f0f9baa4 --- /dev/null +++ b/src/Shaders/AbstractVectorShader2D.vert @@ -0,0 +1,49 @@ +/* + 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 attribute +#define out varying +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat3 transformationProjectionMatrix; +#else +uniform highp mat3 transformationProjectionMatrix; +#endif + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 0) in highp vec2 position; +layout(location = 1) in mediump vec2 textureCoordinates; +#else +in highp vec2 position; +in mediump vec2 textureCoordinates; +#endif + +out vec2 fragmentTextureCoordinates; + +void main() { + gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); + fragmentTextureCoordinates = textureCoordinates; +} diff --git a/src/Shaders/AbstractVectorShader3D.vert b/src/Shaders/AbstractVectorShader3D.vert new file mode 100644 index 000000000..f74fb0989 --- /dev/null +++ b/src/Shaders/AbstractVectorShader3D.vert @@ -0,0 +1,49 @@ +/* + 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 attribute +#define out varying +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat4 transformationProjectionMatrix; +#else +uniform highp mat4 transformationProjectionMatrix; +#endif + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 0) in highp vec4 position; +layout(location = 1) in mediump vec2 textureCoordinates; +#else +in highp vec4 position; +in mediump vec2 textureCoordinates; +#endif + +out vec2 fragmentTextureCoordinates; + +void main() { + gl_Position = transformationProjectionMatrix*position; + fragmentTextureCoordinates = textureCoordinates; +} diff --git a/src/Shaders/CMakeLists.txt b/src/Shaders/CMakeLists.txt index 5ef7001c6..225b1b0c0 100644 --- a/src/Shaders/CMakeLists.txt +++ b/src/Shaders/CMakeLists.txt @@ -1,23 +1,55 @@ +# +# 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. +# + corrade_add_resource(MagnumShaders_RCS MagnumShaders - FlatShader2D.vert FlatShader2D.frag + AbstractVectorShader2D.vert AbstractVectorShader3D.vert + FlatShader2D.vert FlatShader3D.vert FlatShader.frag PhongShader.vert PhongShader.frag - VertexColorShader2D.vert VertexColorShader2D.frag + VectorShader.frag DistanceFieldVectorShader.frag + VertexColorShader2D.vert VertexColorShader3D.vert VertexColorShader.frag compatibility.glsl) + set(MagnumShaders_SRCS + DistanceFieldVectorShader.cpp FlatShader.cpp PhongShader.cpp + VectorShader.cpp VertexColorShader.cpp ${MagnumShaders_RCS}) + set(MagnumShaders_HEADERS + DistanceFieldVectorShader.h + AbstractVectorShader.h FlatShader.h PhongShader.h Shaders.h + VectorShader.h VertexColorShader.h magnumShadersVisibility.h) add_library(MagnumShaders SHARED ${MagnumShaders_SRCS}) - target_link_libraries(MagnumShaders Magnum) install(TARGETS MagnumShaders DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) diff --git a/src/Shaders/DistanceFieldVectorShader.cpp b/src/Shaders/DistanceFieldVectorShader.cpp new file mode 100644 index 000000000..5d39f356c --- /dev/null +++ b/src/Shaders/DistanceFieldVectorShader.cpp @@ -0,0 +1,94 @@ +/* + 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 "DistanceFieldVectorShader.h" + +#include + +#include "Context.h" +#include "Extensions.h" +#include "Shader.h" + +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 DistanceFieldVectorShader::DistanceFieldVectorShader(): transformationProjectionMatrixUniform(0), colorUniform(1), outlineColorUniform(2), outlineRangeUniform(3), smoothnessUniform(4) { + Corrade::Utility::Resource rs("MagnumShaders"); + + #ifndef MAGNUM_TARGET_GLES + Version v = Context::current()->supportedVersion({Version::GL320, Version::GL210}); + #else + 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(vertexShaderName())); + AbstractShaderProgram::attachShader(vertexShader); + + Shader fragmentShader(v, Shader::Type::Fragment); + fragmentShader.addSource(rs.get("compatibility.glsl")); + fragmentShader.addSource(rs.get("DistanceFieldVectorShader.frag")); + AbstractShaderProgram::attachShader(fragmentShader); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) { + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) { + #endif + AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::Position::Location, "position"); + AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::TextureCoordinates::Location, "textureCoordinates"); + } + + AbstractShaderProgram::link(); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) { + #else + { + #endif + transformationProjectionMatrixUniform = AbstractShaderProgram::uniformLocation("transformationProjectionMatrix"); + colorUniform = AbstractShaderProgram::uniformLocation("color"); + outlineColorUniform = AbstractShaderProgram::uniformLocation("outlineColor"); + outlineRangeUniform = AbstractShaderProgram::uniformLocation("outlineRange"); + smoothnessUniform = AbstractShaderProgram::uniformLocation("smoothness"); + } + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), + AbstractVectorShader::VectorTextureLayer); + #endif +} + +template class DistanceFieldVectorShader<2>; +template class DistanceFieldVectorShader<3>; + +}} diff --git a/src/Shaders/DistanceFieldVectorShader.frag b/src/Shaders/DistanceFieldVectorShader.frag new file mode 100644 index 000000000..1e0ae9f1f --- /dev/null +++ b/src/Shaders/DistanceFieldVectorShader.frag @@ -0,0 +1,73 @@ +/* + 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 GL_ES +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 1) uniform lowp vec4 color; +layout(location = 2) uniform lowp vec4 outlineColor; +layout(location = 3) uniform lowp vec2 outlineRange = vec2(0.5, 0.0); +layout(location = 4) uniform lowp float smoothness = 0.04; +#else +uniform lowp vec4 color; +uniform lowp vec4 outlineColor; +uniform lowp vec2 outlineRange = vec2(0.5, 0.0); +uniform lowp float smoothness = 0.04; +#endif +#else +uniform lowp vec4 color; +uniform lowp vec4 outlineColor; +uniform lowp vec2 outlineRange; +uniform lowp float smoothness; +#endif + +#ifdef EXPLICIT_TEXTURE_LAYER +layout(binding = 16) uniform sampler2D vectorTexture; +#else +uniform lowp sampler2D vectorTexture; +#endif + +in vec2 fragmentTextureCoordinates; + +#ifdef NEW_GLSL +out vec4 fragmentColor; +#endif + +void main() { + lowp float intensity = texture(vectorTexture, fragmentTextureCoordinates).r; + + /* Fill color */ + fragmentColor = smoothstep(outlineRange.x-smoothness, outlineRange.x+smoothness, intensity)*color; + + /* Outline */ + if(outlineRange.x < outlineRange.y) { + lowp float mid = (outlineRange.x + outlineRange.y)/2.0; + lowp float half = (outlineRange.y - outlineRange.x)/2.0; + fragmentColor += smoothstep(half+smoothness, half-smoothness, distance(mid, intensity))*outlineColor; + } +} diff --git a/src/Shaders/DistanceFieldVectorShader.h b/src/Shaders/DistanceFieldVectorShader.h new file mode 100644 index 000000000..e938ee695 --- /dev/null +++ b/src/Shaders/DistanceFieldVectorShader.h @@ -0,0 +1,127 @@ +#ifndef Magnum_Shaders_DistanceFieldVectorShader_h +#define Magnum_Shaders_DistanceFieldVectorShader_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::DistanceFieldVectorShader, typedef Magnum::Shaders::DistanceFieldVectorShader2D, Magnum::Shaders::DistanceFieldVectorShader3D + */ + +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "AbstractVectorShader.h" + +#include "magnumShadersVisibility.h" + +namespace Magnum { namespace Shaders { + +/** +@brief Distance field vector shader + +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 +*/ +template class MAGNUM_SHADERS_EXPORT DistanceFieldVectorShader: public AbstractVectorShader { + public: + DistanceFieldVectorShader(); + + /** @brief Set transformation and projection matrix */ + inline DistanceFieldVectorShader* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { + AbstractShaderProgram::setUniform(transformationProjectionMatrixUniform, matrix); + return this; + } + + /** + * @brief Set fill color + * @return Pointer to self (for method chaining) + * + * @see setOutlineColor() + */ + inline DistanceFieldVectorShader* setColor(const Color4<>& color) { + AbstractShaderProgram::setUniform(colorUniform, color); + return this; + } + + /** + * @brief Set outline color + * @return Pointer to self (for method chaining) + * + * @see setOutlineRange(), setColor() + */ + inline DistanceFieldVectorShader* setOutlineColor(const Color4<>& color) { + AbstractShaderProgram::setUniform(outlineColorUniform, color); + return this; + } + + /** + * @brief Set outline range + * @return Pointer to self (for method chaining) + * + * Parameter @p start describes where fill ends and possible outline + * starts. Initial value is `0.5f`, smaller values will make the vector + * art look thinner, larger will make it look thicker. + * + * Parameter @p end describes where outline ends. If set to value + * smaller than @p start the outline is not drawn. Initial value is + * `0.0f`. + * + * @see setOutlineColor() + */ + inline DistanceFieldVectorShader* setOutlineRange(Float start, Float end) { + AbstractShaderProgram::setUniform(outlineRangeUniform, Vector2(start, end)); + return this; + } + + /** + * @brief Set smoothness radius + * @return Pointer to self (for method chaining) + * + * Larger values will make edges look less aliased (but blurry), smaller + * values will make them look more crisp (but possibly aliased). Initial + * value is `0.04f`. + */ + inline DistanceFieldVectorShader* setSmoothness(Float value) { + AbstractShaderProgram::setUniform(smoothnessUniform, value); + return this; + } + + private: + Int transformationProjectionMatrixUniform, + colorUniform, + outlineColorUniform, + outlineRangeUniform, + smoothnessUniform; +}; + +/** @brief Two-dimensional distance field vector shader */ +typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D; + +/** @brief Three-dimensional distance field vector shader */ +typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D; + +}} + +#endif diff --git a/src/Shaders/FlatShader.cpp b/src/Shaders/FlatShader.cpp index 34859cdfb..c447c2f5c 100644 --- a/src/Shaders/FlatShader.cpp +++ b/src/Shaders/FlatShader.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "FlatShader.h" @@ -23,20 +32,12 @@ namespace Magnum { namespace Shaders { namespace { - template struct ShaderName {}; - - template<> struct ShaderName<2> { - constexpr static const char* vertex() { return "FlatShader2D.vert"; } - constexpr static const char* fragment() { return "FlatShader2D.frag"; } - }; - - template<> struct ShaderName<3> { - constexpr static const char* vertex() { return "FlatShader3D.vert"; } - constexpr static const char* fragment() { return "FlatShader3D.frag"; } - }; + template constexpr const char* vertexShaderName(); + template<> constexpr const char* vertexShaderName<2>() { return "FlatShader2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "FlatShader3D.vert"; } } -template FlatShader::FlatShader() { +template FlatShader::FlatShader(): transformationProjectionMatrixUniform(0), colorUniform(1) { Corrade::Utility::Resource rs("MagnumShaders"); /* Weird bug in GCC 4.5 - cannot use initializer list here, although the @@ -58,16 +59,17 @@ template FlatShader::FlatShader() { Shader vertexShader(v, Shader::Type::Vertex); vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get(ShaderName::vertex())); + vertexShader.addSource(rs.get(vertexShaderName())); attachShader(vertexShader); Shader fragmentShader(v, Shader::Type::Fragment); fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get(ShaderName::fragment())); + fragmentShader.addSource(rs.get("FlatShader.frag")); attachShader(fragmentShader); #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) { + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) { #else if(!Context::current()->isVersionSupported(Version::GLES300)) { #endif @@ -76,8 +78,14 @@ template FlatShader::FlatShader() { link(); - transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); - colorUniform = uniformLocation("color"); + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) { + #else + { + #endif + transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); + colorUniform = uniformLocation("color"); + } } template class FlatShader<2>; diff --git a/src/Shaders/FlatShader.frag b/src/Shaders/FlatShader.frag new file mode 100644 index 000000000..d27192d22 --- /dev/null +++ b/src/Shaders/FlatShader.frag @@ -0,0 +1,41 @@ +/* + 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 fragmentColor gl_FragColor +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 1) uniform vec3 color; +#else +uniform lowp vec3 color; +#endif + +#ifdef NEW_GLSL +out lowp vec4 fragmentColor; +#endif + +void main() { + fragmentColor = vec4(color, 1.0); +} diff --git a/src/Shaders/FlatShader.h b/src/Shaders/FlatShader.h index e8787cdd4..e2ff47e63 100644 --- a/src/Shaders/FlatShader.h +++ b/src/Shaders/FlatShader.h @@ -1,18 +1,27 @@ #ifndef Magnum_Shaders_FlatShader_h #define Magnum_Shaders_FlatShader_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -35,12 +44,12 @@ namespace Magnum { namespace Shaders { Draws whole mesh with one color. @see FlatShader2D, FlatShader3D */ -template class MAGNUM_SHADERS_EXPORT FlatShader: public AbstractShaderProgram { +template class MAGNUM_SHADERS_EXPORT FlatShader: public AbstractShaderProgram { public: /** @brief Vertex position */ - typedef Attribute<0, typename DimensionTraits::PointType> Position; + typedef Attribute<0, typename DimensionTraits::VectorType> Position; - FlatShader(); + explicit FlatShader(); /** * @brief Set transformation and projection matrix @@ -61,7 +70,7 @@ template class MAGNUM_SHADERS_EXPORT FlatShader: public } private: - GLint transformationProjectionMatrixUniform, + Int transformationProjectionMatrixUniform, colorUniform; }; diff --git a/src/Shaders/FlatShader2D.frag b/src/Shaders/FlatShader2D.frag deleted file mode 100644 index 82c2d5a95..000000000 --- a/src/Shaders/FlatShader2D.frag +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef NEW_GLSL -#define fragmentColor gl_FragColor -#endif - -uniform lowp vec3 color; - -#ifdef NEW_GLSL -out lowp vec4 fragmentColor; -#endif - -void main() { - fragmentColor = vec4(color, 1.0); -} diff --git a/src/Shaders/FlatShader2D.vert b/src/Shaders/FlatShader2D.vert index 78d041e8d..9e983a978 100644 --- a/src/Shaders/FlatShader2D.vert +++ b/src/Shaders/FlatShader2D.vert @@ -1,15 +1,43 @@ +/* + 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 attribute #endif +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat3 transformationProjectionMatrix; +#else uniform highp mat3 transformationProjectionMatrix; +#endif #ifdef EXPLICIT_ATTRIB_LOCATION -layout(location = 0) in highp vec3 position; +layout(location = 0) in highp vec2 position; #else -in highp vec3 position; +in highp vec2 position; #endif void main() { - gl_Position.xywz = vec4(transformationProjectionMatrix*position, 0.0); + gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); } diff --git a/src/Shaders/FlatShader3D.vert b/src/Shaders/FlatShader3D.vert new file mode 100644 index 000000000..2f4b875c5 --- /dev/null +++ b/src/Shaders/FlatShader3D.vert @@ -0,0 +1,43 @@ +/* + 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 attribute +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat4 transformationProjectionMatrix; +#else +uniform highp mat4 transformationProjectionMatrix; +#endif + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 0) in highp vec4 position; +#else +in highp vec4 position; +#endif + +void main() { + gl_Position = transformationProjectionMatrix*position; +} diff --git a/src/Shaders/PhongShader.cpp b/src/Shaders/PhongShader.cpp index 8ca78b44d..cbba095c0 100644 --- a/src/Shaders/PhongShader.cpp +++ b/src/Shaders/PhongShader.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "PhongShader.h" @@ -22,7 +31,7 @@ namespace Magnum { namespace Shaders { -PhongShader::PhongShader() { +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"); #ifndef MAGNUM_TARGET_GLES @@ -42,7 +51,8 @@ PhongShader::PhongShader() { attachShader(fragmentShader); #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) { + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) { #else if(!Context::current()->isVersionSupported(Version::GLES300)) { #endif @@ -52,15 +62,21 @@ PhongShader::PhongShader() { link(); - ambientColorUniform = uniformLocation("ambientColor"); - diffuseColorUniform = uniformLocation("diffuseColor"); - specularColorUniform = uniformLocation("specularColor"); - shininessUniform = uniformLocation("shininess"); - transformationMatrixUniform = uniformLocation("transformationMatrix"); - projectionMatrixUniform = uniformLocation("projectionMatrix"); - normalMatrixUniform = uniformLocation("normalMatrix"); - lightUniform = uniformLocation("light"); - lightColorUniform = uniformLocation("lightColor"); + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) { + #else + { + #endif + transformationMatrixUniform = uniformLocation("transformationMatrix"); + projectionMatrixUniform = uniformLocation("projectionMatrix"); + normalMatrixUniform = uniformLocation("normalMatrix"); + lightUniform = uniformLocation("light"); + diffuseColorUniform = uniformLocation("diffuseColor"); + ambientColorUniform = uniformLocation("ambientColor"); + specularColorUniform = uniformLocation("specularColor"); + lightColorUniform = uniformLocation("lightColor"); + shininessUniform = uniformLocation("shininess"); + } /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES diff --git a/src/Shaders/PhongShader.frag b/src/Shaders/PhongShader.frag index 3bb1080ac..c3411f0ea 100644 --- a/src/Shaders/PhongShader.frag +++ b/src/Shaders/PhongShader.frag @@ -1,15 +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. +*/ + #ifndef NEW_GLSL #define in varying #define color gl_FragColor #endif -uniform lowp vec3 diffuseColor; #ifndef GL_ES -uniform lowp vec3 ambientColor = vec3(0.0, 0.0, 0.0); -uniform lowp vec3 specularColor = vec3(1.0, 1.0, 1.0); -uniform lowp vec3 lightColor = vec3(1.0, 1.0, 1.0); -uniform mediump float shininess = 80.0; +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 4) uniform vec3 diffuseColor; +layout(location = 5) uniform vec3 ambientColor = vec3(0.0, 0.0, 0.0); +layout(location = 6) uniform vec3 specularColor = vec3(1.0, 1.0, 1.0); +layout(location = 7) uniform vec3 lightColor = vec3(1.0, 1.0, 1.0); +layout(location = 8) uniform float shininess = 80.0; +#else +uniform vec3 diffuseColor; +uniform vec3 ambientColor = vec3(0.0, 0.0, 0.0); +uniform vec3 specularColor = vec3(1.0, 1.0, 1.0); +uniform vec3 lightColor = vec3(1.0, 1.0, 1.0); +uniform float shininess = 80.0; +#endif #else +uniform lowp vec3 diffuseColor; uniform lowp vec3 ambientColor; uniform lowp vec3 specularColor; uniform lowp vec3 lightColor; diff --git a/src/Shaders/PhongShader.h b/src/Shaders/PhongShader.h index 6be38d84c..98b3312d6 100644 --- a/src/Shaders/PhongShader.h +++ b/src/Shaders/PhongShader.h @@ -1,18 +1,27 @@ #ifndef Magnum_Shaders_PhongShader_h #define Magnum_Shaders_PhongShader_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -35,10 +44,10 @@ otherwise falls back to GLSL 1.20. */ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { public: - typedef Attribute<0, Point3D> Position; /**< @brief Vertex position */ + typedef Attribute<0, Vector3> Position; /**< @brief Vertex position */ typedef Attribute<1, Vector3> Normal; /**< @brief Normal direction */ - PhongShader(); + explicit PhongShader(); /** * @brief Set ambient color @@ -78,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(GLfloat shininess) { + inline PhongShader* setShininess(Float shininess) { setUniform(shininessUniform, shininess); return this; } @@ -123,15 +132,15 @@ class MAGNUM_SHADERS_EXPORT PhongShader: public AbstractShaderProgram { } private: - GLint ambientColorUniform, - diffuseColorUniform, - specularColorUniform, - shininessUniform, - transformationMatrixUniform, + Int transformationMatrixUniform, projectionMatrixUniform, normalMatrixUniform, lightUniform, - lightColorUniform; + diffuseColorUniform, + ambientColorUniform, + specularColorUniform, + lightColorUniform, + shininessUniform; }; }} diff --git a/src/Shaders/PhongShader.vert b/src/Shaders/PhongShader.vert index 066afd94d..c52eb30f9 100644 --- a/src/Shaders/PhongShader.vert +++ b/src/Shaders/PhongShader.vert @@ -1,12 +1,43 @@ +/* + 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 attribute #define out varying #endif +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat4 transformationMatrix; +layout(location = 1) uniform mat4 projectionMatrix; +layout(location = 2) uniform mat3 normalMatrix; +layout(location = 3) uniform vec3 light; +#else uniform highp mat4 transformationMatrix; uniform highp mat4 projectionMatrix; uniform mediump mat3 normalMatrix; uniform highp vec3 light; +#endif #ifdef EXPLICIT_ATTRIB_LOCATION layout(location = 0) in highp vec4 position; diff --git a/src/Shaders/Shaders.h b/src/Shaders/Shaders.h index 5a36b34f8..855c3d0c3 100644 --- a/src/Shaders/Shaders.h +++ b/src/Shaders/Shaders.h @@ -1,37 +1,62 @@ #ifndef Magnum_Shaders_Shader_h #define Magnum_Shaders_Shader_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 Forward declarations for Magnum::Shaders namespace */ -#include +#include "Types.h" namespace Magnum { namespace Shaders { -template class FlatShader; +/** @todoc remove when doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT + +template class DistanceFieldVectorShader; +typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D; +typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D; + +template class AbstractVectorShader; +typedef AbstractVectorShader<2> AbstractVectorShader2D; +typedef AbstractVectorShader<3> AbstractVectorShader3D; + +template class FlatShader; typedef FlatShader<2> FlatShader2D; typedef FlatShader<3> FlatShader3D; class PhongShader; -template class VertexColorShader; +template class VectorShader; +typedef VectorShader<2> VectorShader2D; +typedef VectorShader<3> VectorShader3D; + +template class VertexColorShader; typedef VertexColorShader<2> VertexColorShader2D; typedef VertexColorShader<3> VertexColorShader3D; +#endif }} diff --git a/src/Shaders/VectorShader.cpp b/src/Shaders/VectorShader.cpp new file mode 100644 index 000000000..af1c7ba2f --- /dev/null +++ b/src/Shaders/VectorShader.cpp @@ -0,0 +1,90 @@ +/* + 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 "VectorShader.h" + +#include + +#include "Context.h" +#include "Extensions.h" +#include "Shader.h" + +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 VectorShader::VectorShader(): transformationProjectionMatrixUniform(0), colorUniform(1) { + Corrade::Utility::Resource rs("MagnumShaders"); + + #ifndef MAGNUM_TARGET_GLES + Version v = Context::current()->supportedVersion({Version::GL320, Version::GL210}); + #else + 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(vertexShaderName())); + AbstractShaderProgram::attachShader(vertexShader); + + Shader fragmentShader(v, Shader::Type::Fragment); + fragmentShader.addSource(rs.get("compatibility.glsl")); + fragmentShader.addSource(rs.get("VectorShader.frag")); + AbstractShaderProgram::attachShader(fragmentShader); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) { + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) { + #endif + AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::Position::Location, "position"); + AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::TextureCoordinates::Location, "textureCoordinates"); + } + + AbstractShaderProgram::link(); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) { + #else + { + #endif + transformationProjectionMatrixUniform = AbstractShaderProgram::uniformLocation("transformationProjectionMatrix"); + colorUniform = AbstractShaderProgram::uniformLocation("color"); + } + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVectorShader::VectorTextureLayer); + #endif +} + +template class VectorShader<2>; +template class VectorShader<3>; + +}} diff --git a/src/Shaders/VectorShader.frag b/src/Shaders/VectorShader.frag new file mode 100644 index 000000000..8384499a7 --- /dev/null +++ b/src/Shaders/VectorShader.frag @@ -0,0 +1,51 @@ +/* + 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 + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 1) uniform vec4 color; +#else +uniform lowp vec4 color; +#endif + +#ifdef EXPLICIT_TEXTURE_LAYER +layout(binding = 16) uniform sampler2D vectorTexture; +#else +uniform lowp sampler2D vectorTexture; +#endif + +in vec2 fragmentTextureCoordinates; + +#ifdef NEW_GLSL +out vec4 fragmentColor; +#endif + +void main() { + lowp float intensity = texture(vectorTexture, fragmentTextureCoordinates).r; + fragmentColor = intensity*color; +} diff --git a/src/Shaders/VectorShader.h b/src/Shaders/VectorShader.h new file mode 100644 index 000000000..64ebba832 --- /dev/null +++ b/src/Shaders/VectorShader.h @@ -0,0 +1,81 @@ +#ifndef Magnum_Shaders_VectorShader_h +#define Magnum_Shaders_VectorShader_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::VectorShader, typedef Magnum::Shaders::VectorShader2D, Magnum::Shaders::VectorShader3D + */ + +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "AbstractVectorShader.h" + +#include "magnumShadersVisibility.h" + +namespace Magnum { namespace Shaders { + +/** +@brief Vector shader + +Renders vector art in plain grayscale form. See also DistanceFieldVectorShader +for more advanced effects. +@see VectorShader2D, VectorShader3D +*/ +template class MAGNUM_SHADERS_EXPORT VectorShader: public AbstractVectorShader { + public: + VectorShader(); + + /** + * @brief Set transformation and projection matrix + * @return Pointer to self (for method chaining) + */ + inline VectorShader* setTransformationProjectionMatrix(const typename DimensionTraits::MatrixType& matrix) { + AbstractShaderProgram::setUniform(transformationProjectionMatrixUniform, matrix); + return this; + } + + /** + * @brief Set fill color + * @return Pointer to self (for method chaining) + */ + inline VectorShader* setColor(const Color4<>& color) { + AbstractShaderProgram::setUniform(colorUniform, color); + return this; + } + + private: + Int transformationProjectionMatrixUniform, + colorUniform; +}; + +/** @brief Two-dimensional vector shader */ +typedef VectorShader<2> VectorShader2D; + +/** @brief Three-dimensional vector shader */ +typedef VectorShader<3> VectorShader3D; + +}} + +#endif diff --git a/src/Shaders/VertexColorShader.cpp b/src/Shaders/VertexColorShader.cpp index 714756f1b..f145ab056 100644 --- a/src/Shaders/VertexColorShader.cpp +++ b/src/Shaders/VertexColorShader.cpp @@ -1,16 +1,25 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "VertexColorShader.h" @@ -23,20 +32,12 @@ namespace Magnum { namespace Shaders { namespace { - template struct ShaderName {}; - - template<> struct ShaderName<2> { - constexpr static const char* vertex() { return "VertexColorShader2D.vert"; } - constexpr static const char* fragment() { return "VertexColorShader2D.frag"; } - }; - - template<> struct ShaderName<3> { - constexpr static const char* vertex() { return "VertexColorShader3D.vert"; } - constexpr static const char* fragment() { return "VertexColorShader3D.frag"; } - }; + template constexpr const char* vertexShaderName(); + template<> constexpr const char* vertexShaderName<2>() { return "VertexColorShader2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "VertexColorShader3D.vert"; } } -template VertexColorShader::VertexColorShader() { +template VertexColorShader::VertexColorShader(): transformationProjectionMatrixUniform(0) { Corrade::Utility::Resource rs("MagnumShaders"); /* Weird bug in GCC 4.5 - cannot use initializer list here, although the @@ -58,16 +59,17 @@ template VertexColorShader::VertexColorShad Shader vertexShader(v, Shader::Type::Vertex); vertexShader.addSource(rs.get("compatibility.glsl")); - vertexShader.addSource(rs.get(ShaderName::vertex())); + vertexShader.addSource(rs.get(vertexShaderName())); attachShader(vertexShader); Shader fragmentShader(v, Shader::Type::Fragment); fragmentShader.addSource(rs.get("compatibility.glsl")); - fragmentShader.addSource(rs.get(ShaderName::fragment())); + fragmentShader.addSource(rs.get("VertexColorShader.frag")); attachShader(fragmentShader); #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) { + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) { #else if(!Context::current()->isVersionSupported(Version::GLES300)) { #endif @@ -77,7 +79,13 @@ template VertexColorShader::VertexColorShad link(); - transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) { + #else + { + #endif + transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); + } } template class VertexColorShader<2>; diff --git a/src/Shaders/VertexColorShader.frag b/src/Shaders/VertexColorShader.frag new file mode 100644 index 000000000..caa13dbf4 --- /dev/null +++ b/src/Shaders/VertexColorShader.frag @@ -0,0 +1,38 @@ +/* + 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 + +in lowp vec3 interpolatedColor; + +#ifdef NEW_GLSL +out lowp vec4 fragmentColor; +#endif + +void main() { + fragmentColor = vec4(interpolatedColor, 1.0); +} diff --git a/src/Shaders/VertexColorShader.h b/src/Shaders/VertexColorShader.h index 896fefdc6..87c6a5c88 100644 --- a/src/Shaders/VertexColorShader.h +++ b/src/Shaders/VertexColorShader.h @@ -1,18 +1,27 @@ #ifndef Magnum_Shaders_VertexColorShader_h #define Magnum_Shaders_VertexColorShader_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -35,15 +44,15 @@ namespace Magnum { namespace Shaders { Draws vertex-colored mesh. @see VertexColorShader2D, VertexColorShader3D */ -template class MAGNUM_SHADERS_EXPORT VertexColorShader: public AbstractShaderProgram { +template class MAGNUM_SHADERS_EXPORT VertexColorShader: public AbstractShaderProgram { public: /** @brief Vertex position */ - typedef Attribute<0, typename DimensionTraits::PointType> Position; + typedef Attribute<0, typename DimensionTraits::VectorType> Position; /** @brief Vertex color */ typedef Attribute<1, Color3<>> Color; - VertexColorShader(); + explicit VertexColorShader(); /** * @brief Set transformation and projection matrix @@ -55,7 +64,7 @@ template class MAGNUM_SHADERS_EXPORT VertexColorShader: } private: - GLint transformationProjectionMatrixUniform; + Int transformationProjectionMatrixUniform; }; /** @brief 2D vertex color shader */ diff --git a/src/Shaders/VertexColorShader2D.frag b/src/Shaders/VertexColorShader2D.frag deleted file mode 100644 index 641dd081e..000000000 --- a/src/Shaders/VertexColorShader2D.frag +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef NEW_GLSL -#define in varying -#define fragmentColor gl_FragColor -#endif - -in lowp vec3 interpolatedColor; - -#ifdef NEW_GLSL -out lowp vec4 fragmentColor; -#endif - -void main() { - fragmentColor = vec4(interpolatedColor, 1.0); -} diff --git a/src/Shaders/VertexColorShader2D.vert b/src/Shaders/VertexColorShader2D.vert index 88c8fc9a5..f7d2c879e 100644 --- a/src/Shaders/VertexColorShader2D.vert +++ b/src/Shaders/VertexColorShader2D.vert @@ -1,21 +1,49 @@ +/* + 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 attribute #define out varying #endif +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat3 transformationProjectionMatrix; +#else uniform highp mat3 transformationProjectionMatrix; +#endif #ifdef EXPLICIT_ATTRIB_LOCATION -layout(location = 0) in highp vec3 position; +layout(location = 0) in highp vec2 position; layout(location = 1) in lowp vec3 color; #else -in highp vec3 position; +in highp vec2 position; in lowp vec3 color; #endif out lowp vec3 interpolatedColor; void main() { - gl_Position.xywz = vec4(transformationProjectionMatrix*position, 0.0); + gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); interpolatedColor = color; } diff --git a/src/Shaders/VertexColorShader3D.vert b/src/Shaders/VertexColorShader3D.vert new file mode 100644 index 000000000..9cf727389 --- /dev/null +++ b/src/Shaders/VertexColorShader3D.vert @@ -0,0 +1,49 @@ +/* + 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 attribute +#define out varying +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 0) uniform mat4 transformationProjectionMatrix; +#else +uniform highp mat4 transformationProjectionMatrix; +#endif + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 0) in highp vec4 position; +layout(location = 1) in lowp vec3 color; +#else +in highp vec4 position; +in lowp vec3 color; +#endif + +out lowp vec3 interpolatedColor; + +void main() { + gl_Position = transformationProjectionMatrix*position; + interpolatedColor = color; +} diff --git a/src/Shaders/compatibility.glsl b/src/Shaders/compatibility.glsl index 70f4cd6ba..3534b4187 100644 --- a/src/Shaders/compatibility.glsl +++ b/src/Shaders/compatibility.glsl @@ -1,16 +1,53 @@ +/* + 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. +*/ + #if (!defined(GL_ES) && __VERSION__ >= 130) || (defined(GL_ES) && __VERSION__ >= 300) #define NEW_GLSL #endif /* On NVidia and GLSL 1.20 layout qualifiers result in parsing error, even if the extension is defined as supported */ -#if !defined(GL_ES) && __VERSION__ >= 120 && defined(GL_ARB_explicit_attrib_location) -#extension GL_ARB_explicit_attrib_location: enable -#define EXPLICIT_ATTRIB_LOCATION +#if !defined(GL_ES) && __VERSION__ >= 130 + +#ifdef GL_ARB_explicit_attrib_location + #extension GL_ARB_explicit_attrib_location: enable + #define EXPLICIT_ATTRIB_LOCATION +#endif +#if defined(GL_ARB_shading_language_420pack) + #extension GL_ARB_shading_language_420pack: enable + #define EXPLICIT_TEXTURE_LAYER +#endif +#ifdef GL_ARB_explicit_uniform_location + #extension GL_ARB_explicit_uniform_location: enable + #define EXPLICIT_UNIFORM_LOCATION +#endif + #endif #if defined(GL_ES) && __VERSION__ >= 300 #define EXPLICIT_ATTRIB_LOCATION +/* EXPLICIT_TEXTURE_LAYER & EXPLICIT_UNIFORM_LOCATION is not available in OpenGL ES */ #endif /* Precision qualifiers are not supported in GLSL 1.20 */ diff --git a/src/Shaders/magnumShadersVisibility.h b/src/Shaders/magnumShadersVisibility.h index 047ee9eca..238ddeb04 100644 --- a/src/Shaders/magnumShadersVisibility.h +++ b/src/Shaders/magnumShadersVisibility.h @@ -1,18 +1,27 @@ #ifndef Magnum_Shaders_magnumShadersVisibility_h #define Magnum_Shaders_magnumShadersVisibility_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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. */ #ifdef _WIN32 diff --git a/src/SizeTraits.cpp b/src/SizeTraits.cpp deleted file mode 100644 index 8befa8477..000000000 --- a/src/SizeTraits.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "SizeTraits.h" - -namespace Magnum { - -#ifndef DOXYGEN_GENERATING_OUTPUT -static_assert(Pow<2, 3>::value == 8, "Implementation error in Pow meta class"); -static_assert(Log<2, 9>::value == 3, "Implementation error in Log meta class"); -#endif - -} diff --git a/src/SizeTraits.h b/src/SizeTraits.h deleted file mode 100644 index 6e38537c4..000000000 --- a/src/SizeTraits.h +++ /dev/null @@ -1,225 +0,0 @@ -#ifndef Magnum_SizeTraits_h -#define Magnum_SizeTraits_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file - * @brief Class Magnum::SizeTraits, Magnum::SizeBasedCall, Magnum::Pow, Magnum::Log - */ - -#include - -#include "Math/Math.h" -#include "Magnum.h" - -namespace Magnum { - -/** @todo Remove/internalize things used only in one place (Math::log, Pow, Log)? Simplify SizeTraits? */ - -/** -@brief Traits class providing suitable types for given data sizes -@tparam byte Highest byte needed (counting from zero) - -If you use indexed data, you would probably (for performance reasons) want to -use the smallest type which is able to store all indices in given range. This -class provides type suitable for given **logarithmic** size of data. For -example, if you want to store 289 elements, they occupy two bytes, so -`SizeTraits<1>::%SizeType` is `GLushort`. For convenience you can use Log class -to compute logarithms at compile time, e.g. -`SizeTraits::%value>::%SizeType`. -*/ -#ifdef DOXYGEN_GENERATING_OUTPUT -template struct SizeTraits { - /** - * @brief (Unsigned) type able to index the data - * - * Not implemented for large sizes (@f$ > 2^{32} @f$ elements), because - * OpenGL doesn't have any type which would be able to store the indices. - */ - typedef T SizeType; -}; -#else -template struct SizeTraits: public SizeTraits {}; -#endif - -#ifndef DOXYGEN_GENERATING_OUTPUT -template<> struct SizeTraits<0> { - typedef GLubyte SizeType; -}; -template<> struct SizeTraits<1> { - typedef GLushort SizeType; -}; -template<> struct SizeTraits<2> { - typedef GLuint SizeType; -}; -template<> struct SizeTraits<4> { - /* We don't have size type to store 2^32 values */ -}; -#endif - -/** -@brief Functor for calling templated function with type based on size -@tparam Base Base struct with templated function `run()`. See below for - example. - -If you have templated function which you want to call with type suitable for -indexing data of some size, you will probably use cascade of IFs, like this: -@code -std::size_t dataSize; -template Bar foo(Arg1 arg1, Arg2 arg2, ...); - -Bar bar; -if(dataSize < 256) - bar = foo(arg1, arg2, ...); -else if(dataSize < 65536) - bar = foo(arg1, arg2, ...); -// ... -@endcode -But this approach leads to repetitive and unmaintainable code, especially if -there are many arguments needed to pass to each function. The solution is to -use this class. The only thing you need is to rename your function to `run()` -and wrap it in a `struct`: -@code -struct Foo { - template Bar run(Arg1 arg1, Arg2 arg2, ...); -}; -@endcode -Then you can use this class to call the templated function with the right type -based on data size: -@code -bar = SizeBasedCall(dataSize)(arg1, arg2, ...); -@endcode -*/ -#ifndef CORRADE_GCC44_COMPATIBILITY -template struct SizeBasedCall: public Base { -#else -template struct SizeBasedCall: public Base { -#endif - /** - * @brief Constructor - * @param size Data size - */ - SizeBasedCall(std::size_t size): size(size) {} - - /** - * @brief Functor - * @param arguments Arguments passed to `Base::run()` - * @return Return value of `Base::run()` - * - * Calls `Base::run()` based on data size (given in constructor). If there - * is no suitable type for indexing given data size, prints message to - * error output and returns default-constructed value. - */ - #ifndef CORRADE_GCC45_COMPATIBILITY - template auto operator()(Args&&... arguments) -> decltype(Base::template run(std::forward(arguments)...)) { - #else - #ifdef CORRADE_GCC44_COMPATIBILITY - template Return operator()(Args&& arguments) { - #else - template auto operator()(Args&& arguments) -> decltype(Base::template run(std::forward(arguments))) { - #endif - #endif - switch(Math::log(256, size)) { - case 0: - #ifndef CORRADE_GCC45_COMPATIBILITY - return Base::template run(std::forward(arguments)...); - #else - return Base::template run(std::forward(arguments)); - #endif - case 1: - #ifndef CORRADE_GCC45_COMPATIBILITY - return Base::template run(std::forward(arguments)...); - #else - return Base::template run(std::forward(arguments)); - #endif - case 2: - case 3: - #ifndef CORRADE_GCC45_COMPATIBILITY - return Base::template run(std::forward(arguments)...); - #else - return Base::template run(std::forward(arguments)); - #endif - } - - Error() << "SizeBasedCall: no type able to index" << size << "elements."; - #ifndef CORRADE_GCC45_COMPATIBILITY - return decltype(Base::template run(std::forward(arguments)...))(); - #else - #ifdef CORRADE_GCC44_COMPATIBILITY - return Return(); - #else - return decltype(Base::template run(std::forward(arguments)))(); - #endif - #endif - } - - private: - std::size_t size; -}; - -/** -@brief Class for computing integral powers at compile time -@tparam base Base -@tparam exponent Exponent - -Useful mainly for computing template parameter value, e.g. in conjunction with -SizeTraits class. -*/ -template struct Pow { - /** @brief Value of the power */ - enum: std::uint32_t { - #ifndef DOXYGEN_GENERATING_OUTPUT - value = base*Pow::value - #else - value - #endif - }; -}; - -#ifndef DOXYGEN_GENERATING_OUTPUT -template struct Pow { - enum: std::uint32_t { value = 1 }; -}; -#endif - -/** -@brief Class for computing integral logarithms at compile time -@tparam base Base -@tparam number Number - -Useful mainly for computing template parameter value, e.g. in conjunction with -SizeTraits class. -*/ -template struct Log { - /** @brief Value of the logarithm */ - enum: std::uint32_t { - #ifndef DOXYGEN_GENERATING_OUTPUT - value = 1+Log::value - #else - value - #endif - }; -}; - -#ifndef DOXYGEN_GENERATING_OUTPUT -template struct Log: public Log {}; -template struct Log { - enum: std::uint32_t { value = 0 }; -}; -#endif - -} - -#endif diff --git a/src/Swizzle.h b/src/Swizzle.h index 529d538ec..972cf70cc 100644 --- a/src/Swizzle.h +++ b/src/Swizzle.h @@ -1,55 +1,47 @@ #ifndef Magnum_Swizzle_h #define Magnum_Swizzle_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 Functions Magnum::swizzle(const T&), Magnum::swizzle(const T&, const char(&)[]) +/** @file /Swizzle.h + * @brief Function Magnum::swizzle() */ +#include "Math/Swizzle.h" #include "Color.h" namespace Magnum { #ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - using Math::Implementation::Sequence; - using Math::Implementation::GenerateSequence; - - 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 struct Component {}; - template struct Component: public ComponentAtPosition {}; - template struct Component: public ComponentAtPosition {}; - template struct Component: public ComponentAtPosition {}; - template struct Component: public ComponentAtPosition {}; +namespace Math { namespace Implementation { template struct Component: public ComponentAtPosition {}; template struct Component: public ComponentAtPosition {}; 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 struct Component { - template inline constexpr static T value(const Math::Vector&) { return T(1); } - }; +}} +namespace Implementation { template struct TypeForSize { typedef Math::Vector Type; }; @@ -60,28 +52,6 @@ namespace Implementation { template struct TypeForSize<3, Color4> { typedef Color3 Type; }; template struct TypeForSize<4, Color3> { typedef Color4 Type; }; template struct TypeForSize<4, Color4> { typedef Color4 Type; }; - - template inline constexpr T componentAtPosition(const Math::Vector& vector, std::size_t position) { - return size > position ? vector[position] : throw; - } - - template inline constexpr T component(const Math::Vector& vector, char component) { - return component == 'x' ? componentAtPosition(vector, 0) : - component == 'y' ? componentAtPosition(vector, 1) : - component == 'z' ? componentAtPosition(vector, 2) : - component == 'w' ? componentAtPosition(vector, 3) : - component == 'r' ? componentAtPosition(vector, 0) : - component == 'g' ? componentAtPosition(vector, 1) : - component == 'b' ? componentAtPosition(vector, 2) : - component == 'a' ? componentAtPosition(vector, 3) : - component == '0' ? T(0) : - component == '1' ? T(1) : - throw; - } - - template inline constexpr Math::Vector swizzleFrom(Sequence, const Math::Vector& vector, const char(&components)[sizeof...(sequence)+1]) { - return {component(vector, components[sequence])...}; - } } #endif @@ -90,7 +60,7 @@ namespace Implementation { Creates new vector from given components. Example: @code -Vector4 original(-1, 2, 3, 4); +Vector4i original(-1, 2, 3, 4); auto vec = swizzle<'a', '1', '0', 'r', 'g', 'b'>(original); // vec == { 4, 1, 0, -1, 2, 3 } @@ -98,47 +68,14 @@ auto vec = swizzle<'a', '1', '0', 'r', 'g', 'b'>(original); You can use letters `x`, `y`, `z`, `w` and `r`, `g`, `b`, `a` for addressing components or letters `0` and `1` for zero and one. Count of elements is unlimited, but must be at least one. If the resulting vector is two, three or -four-component, corresponding Vector2, Vector3, Vector4, Color3 or Color4 -specialization is returned. - -@attention This function is less convenient to write than -swizzle(const T&, const char(&)[newSize]), but the evaluation of -the swizzling operation is guaranteed to be always done at compile time -instead of at runtime. +four-component, corresponding Math::Vector2, Math::Vector3, Math::Vector4, +Color3 or Color4 specialization is returned. -@see @ref matrix-vector-component-access, Vector4::xyz(), Color4::rgb(), - Vector4::xy(), Vector3::xy() +@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) { - return {Implementation::Component::value(vector)...}; -} - -/** -@brief Swizzle Vector components - -Creates new vector from given components. Example: -@code -Vector4 original(-1, 2, 3, 4); - -auto vec = swizzle(original, "a10rgb"); -// vec == { 4, 1, 0, -1, 2, 3 } -@endcode -You can use letters `x`, `y`, `z`, `w` and `r`, `g`, `b`, `a` for addressing -components or letters `0` and `1` for zero and one. Count of elements is -unlimited, but must be at least one. If the resulting vector is two, three or -four-component, corresponding Vector2, Vector3 or Vector4 specialization is -returned. - -@attention This function is more convenient to write than -swizzle(const T&), but unless the result is marked with -`constexpr`, the evaluation of the swizzling operation probably won't be -evaluated at compile time, but at runtime. - -@see @ref matrix-vector-component-access, Vector4::xyz(), Color4::rgb(), - Vector4::xy(), Vector3::xy() -*/ -template inline constexpr typename Implementation::TypeForSize::Type swizzle(const T& vector, const char(&components)[newSize]) { - return Implementation::swizzleFrom(typename Implementation::GenerateSequence::Type(), vector, components); + return {Math::Implementation::Component::value(vector)...}; } } diff --git a/src/Test/AbstractImageTest.cpp b/src/Test/AbstractImageTest.cpp new file mode 100644 index 000000000..2f1e475ec --- /dev/null +++ b/src/Test/AbstractImageTest.cpp @@ -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. +*/ + +#include +#include + +#include "AbstractImage.h" + +namespace Magnum { namespace Test { + +class AbstractImageTest: public Corrade::TestSuite::Tester { + public: + explicit AbstractImageTest(); + + void debugFormat(); + void debugType(); +}; + +AbstractImageTest::AbstractImageTest() { + addTests({&AbstractImageTest::debugFormat, + &AbstractImageTest::debugType}); +} + +void AbstractImageTest::debugFormat() { + std::ostringstream o; + Debug(&o) << AbstractImage::Format::RGBA; + CORRADE_COMPARE(o.str(), "AbstractImage::Format::RGBA\n"); +} + +void AbstractImageTest::debugType() { + std::ostringstream o; + Debug(&o) << AbstractImage::Type::UnsignedShort5551; + CORRADE_COMPARE(o.str(), "AbstractImage::Type::UnsignedShort5551\n"); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::AbstractImageTest) diff --git a/src/Test/AbstractShaderProgramTest.cpp b/src/Test/AbstractShaderProgramTest.cpp new file mode 100644 index 000000000..4dc11e31b --- /dev/null +++ b/src/Test/AbstractShaderProgramTest.cpp @@ -0,0 +1,228 @@ +/* + 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 "AbstractShaderProgram.h" + +namespace Magnum { namespace Test { + +class AbstractShaderProgramTest: public Corrade::TestSuite::Tester { + public: + explicit AbstractShaderProgramTest(); + + void attributeScalar(); + void attributeScalarInt(); + void attributeScalarUnsignedInt(); + void attributeScalarDouble(); + + void attributeVector(); + void attributeVectorInt(); + void attributeVectorUnsignedInt(); + void attributeVectorDouble(); + void attributeVector4(); + void attributeVectorBGRA(); + + void attributeMatrix(); + void attributeMatrixDouble(); +}; + +AbstractShaderProgramTest::AbstractShaderProgramTest() { + addTests({&AbstractShaderProgramTest::attributeScalar, + &AbstractShaderProgramTest::attributeScalarInt, + &AbstractShaderProgramTest::attributeScalarUnsignedInt, + &AbstractShaderProgramTest::attributeScalarDouble, + + &AbstractShaderProgramTest::attributeVector, + &AbstractShaderProgramTest::attributeVectorInt, + &AbstractShaderProgramTest::attributeVectorUnsignedInt, + &AbstractShaderProgramTest::attributeVectorDouble, + &AbstractShaderProgramTest::attributeVector4, + &AbstractShaderProgramTest::attributeVectorBGRA, + + &AbstractShaderProgramTest::attributeMatrix, + &AbstractShaderProgramTest::attributeMatrixDouble}); +} + +void AbstractShaderProgramTest::attributeScalar() { + typedef AbstractShaderProgram::Attribute<3, Float> Attribute; + CORRADE_COMPARE(Attribute::Location, 3); + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::One); + CORRADE_VERIFY(!a.dataOptions()); + CORRADE_COMPARE(a.dataSize(), 4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); + + /* Options */ + Attribute b(Attribute::DataType::UnsignedShort, Attribute::DataOption::Normalized); + CORRADE_COMPARE(b.dataSize(), 2); + CORRADE_VERIFY(b.dataOptions() <= Attribute::DataOption::Normalized); +} + +void AbstractShaderProgramTest::attributeScalarInt() { + typedef AbstractShaderProgram::Attribute<3, Int> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.dataSize(), 4); + + /* Options */ + Attribute b(Attribute::DataType::Short); + CORRADE_COMPARE(b.dataSize(), 2); +} + +void AbstractShaderProgramTest::attributeScalarUnsignedInt() { + typedef AbstractShaderProgram::Attribute<3, UnsignedInt> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.dataSize(), 4); + + /* Options */ + Attribute b(Attribute::DataType::UnsignedByte); + CORRADE_COMPARE(b.dataSize(), 1); +} + +void AbstractShaderProgramTest::attributeScalarDouble() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Double> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.dataSize(), 8); + #else + CORRADE_SKIP("Double attributes are not available in OpenGL ES."); + #endif +} + +void AbstractShaderProgramTest::attributeVector() { + typedef AbstractShaderProgram::Attribute<3, Vector3> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Three); + CORRADE_COMPARE(a.dataSize(), 3*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); + + /* Options */ + Attribute b(Attribute::Components::Two, Attribute::DataType::Double); + CORRADE_COMPARE(b.components(), Attribute::Components::Two); + CORRADE_COMPARE(b.dataSize(), 2*8); +} + +void AbstractShaderProgramTest::attributeVectorInt() { + typedef AbstractShaderProgram::Attribute<3, Vector2i> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Two); + CORRADE_COMPARE(a.dataSize(), 2*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Int); + + /* Options */ + Attribute b(Attribute::Components::One, Attribute::DataType::Int); + CORRADE_COMPARE(b.dataSize(), 4); +} + +void AbstractShaderProgramTest::attributeVectorUnsignedInt() { + typedef AbstractShaderProgram::Attribute<3, Vector4ui> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Four); + CORRADE_COMPARE(a.dataSize(), 4*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::UnsignedInt); + + /* Options */ + Attribute b(Attribute::Components::Three, Attribute::DataType::UnsignedShort); + CORRADE_COMPARE(b.dataSize(), 3*2); +} + +void AbstractShaderProgramTest::attributeVectorDouble() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Vector2d> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Two); + CORRADE_COMPARE(a.dataSize(), 2*8); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); + + /* Options */ + Attribute b(Attribute::Components::One); + CORRADE_COMPARE(b.dataSize(), 8); + #else + CORRADE_SKIP("Double attributes are not available in OpenGL ES."); + #endif +} + +void AbstractShaderProgramTest::attributeVector4() { + typedef AbstractShaderProgram::Attribute<3, Vector4> Attribute; + + /* Custom type */ + Attribute a(Attribute::DataType::UnsignedInt2101010Rev); + CORRADE_COMPARE(a.dataSize(), 4); +} + +void AbstractShaderProgramTest::attributeVectorBGRA() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Vector4> Attribute; + + /* BGRA */ + Attribute a(Attribute::Components::BGRA); + CORRADE_COMPARE(a.dataSize(), 4*4); + #else + CORRADE_SKIP("BGRA attribute component ordering is not available in OpenGL ES."); + #endif +} + +void AbstractShaderProgramTest::attributeMatrix() { + typedef AbstractShaderProgram::Attribute<3, Matrix3> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Three); + CORRADE_COMPARE(a.dataSize(), 3*3*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); +} + +void AbstractShaderProgramTest::attributeMatrixDouble() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Matrix4d> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Four); + CORRADE_COMPARE(a.dataSize(), 4*4*8); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); + #else + CORRADE_SKIP("Double attributes are not available in OpenGL ES."); + #endif +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::AbstractShaderProgramTest) diff --git a/src/Test/ArrayTest.cpp b/src/Test/ArrayTest.cpp new file mode 100644 index 000000000..dcf4de7bd --- /dev/null +++ b/src/Test/ArrayTest.cpp @@ -0,0 +1,111 @@ +/* + 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 "Array.h" + +namespace Magnum { namespace Test { + +class ArrayTest: public Corrade::TestSuite::Tester { + public: + ArrayTest(); + + void construct(); + void constexprConstruct(); + void equality(); + void access(); +}; + +typedef Magnum::Array1D Array1D; +typedef Magnum::Array2D Array2D; +typedef Magnum::Array3D Array3D; + +ArrayTest::ArrayTest() { + addTests({&ArrayTest::construct, + &ArrayTest::constexprConstruct, + &ArrayTest::equality, + &ArrayTest::access}); +} + +void ArrayTest::construct() { + CORRADE_COMPARE(Array1D(5), (Array<1, int>(5))); + CORRADE_COMPARE(Array2D(5, 3), (Array<2, int>(5, 3))); + CORRADE_COMPARE(Array3D(5, 3, -2), (Array<3, int>(5, 3, -2))); + + /* Verify proper expansion */ + CORRADE_COMPARE((Array<3, int>(5)), (Array<3, int>(5, 5, 5))); + CORRADE_COMPARE(Array2D(5), (Array<2, int>(5, 5))); + CORRADE_COMPARE(Array3D(5), (Array<3, int>(5, 5, 5))); +} + +void ArrayTest::constexprConstruct() { + /* Verify that all full constructors can be called as constexpr */ + constexpr Array1D a(5); + constexpr Array2D b(5, 3); + constexpr Array2D b2(5); + constexpr Array3D c(5, 6, 7); + constexpr Array3D c2(5); + constexpr Array<3, int> d(5, 6, 7); + + CORRADE_COMPARE(a, Array1D(5)); + CORRADE_COMPARE(b, Array2D(5, 3)); + CORRADE_COMPARE(b2, Array2D(5)); + CORRADE_COMPARE(c, Array3D(5, 6, 7)); + CORRADE_COMPARE(c2, Array3D(5)); + CORRADE_COMPARE(d, (Array<3, int>(5, 6, 7))); +} + +void ArrayTest::equality() { + CORRADE_VERIFY((Array<3, int>(5, 6, 7) == Array<3, int>(5, 6, 7))); + CORRADE_VERIFY((Array<3, int>(5, 6, 7) != Array<3, int>(5, 6, 8))); +} + +void ArrayTest::access() { + Array1D a(50); + const Array1D ac(50); + Array2D b(5, 3); + const Array2D bc(5, 3); + Array3D c(-5, 6, 7); + const Array3D cc(-5, 6, 7); + + CORRADE_COMPARE(a.x(), 50); + CORRADE_COMPARE(ac.x(), 50); + + CORRADE_COMPARE(b.x(), 5); + CORRADE_COMPARE(b.y(), 3); + CORRADE_COMPARE(bc.x(), 5); + CORRADE_COMPARE(bc.y(), 3); + + CORRADE_COMPARE(c.x(), -5); + CORRADE_COMPARE(c.y(), 6); + CORRADE_COMPARE(c.z(), 7); + CORRADE_COMPARE(cc.x(), -5); + CORRADE_COMPARE(cc.y(), 6); + CORRADE_COMPARE(cc.z(), 7); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::ArrayTest) diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 2e6f58e3e..78495259d 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1,7 +1,33 @@ -corrade_add_test2(ColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(MeshTest MeshTest.cpp LIBRARIES Magnum) -corrade_add_test2(ResourceManagerTest ResourceManagerTest.cpp LIBRARIES MagnumTestLib) -corrade_add_test2(SwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test2(TypeTraitsTest TypeTraitsTest.cpp LIBRARIES Magnum) +# +# 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. +# + +corrade_add_test(AbstractImageTest AbstractImageTest.cpp LIBRARIES Magnum) +corrade_add_test(AbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES Magnum) +corrade_add_test(ArrayTest ArrayTest.cpp) +corrade_add_test(ColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MeshTest MeshTest.cpp LIBRARIES Magnum) +corrade_add_test(ResourceManagerTest ResourceManagerTest.cpp LIBRARIES MagnumTestLib) +corrade_add_test(SwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib) set_target_properties(ResourceManagerTest PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) diff --git a/src/Test/ColorTest.cpp b/src/Test/ColorTest.cpp index 176270f2b..773913454 100644 --- a/src/Test/ColorTest.cpp +++ b/src/Test/ColorTest.cpp @@ -1,85 +1,125 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ColorTest.h" - +#include +#include #include #include "Color.h" -using namespace std; +namespace Magnum { namespace Test { -CORRADE_TEST_MAIN(Magnum::Test::ColorTest) +class ColorTest: public Corrade::TestSuite::Tester { + public: + ColorTest(); -using namespace Corrade::Utility; + void access(); -namespace Magnum { namespace Test { + void fromHue(); + void fromSaturation(); + void fromValue(); -typedef Magnum::Color3 Color3; -typedef Magnum::Color4 Color4; -typedef Magnum::Color3 Color3f; -typedef Magnum::Color4 Color4f; + void hue(); + void saturation(); + void value(); -ColorTest::ColorTest() { - addTests(&ColorTest::fromDenormalized, - &ColorTest::fromNormalized, + void hsv(); + void hsvOverflow(); + void hsvAlpha(); - &ColorTest::fromHue, - &ColorTest::fromSaturation, - &ColorTest::fromValue, + void debug(); + void configuration(); +}; - &ColorTest::hue, - &ColorTest::saturation, - &ColorTest::value, +typedef Magnum::Color3 Color3; +typedef Magnum::Color4 Color4; +typedef Magnum::Color3 Color3f; +typedef Magnum::Color4 Color4f; - &ColorTest::hsv, - &ColorTest::hsvOverflow, - &ColorTest::hsvAlpha, +ColorTest::ColorTest() { + addTests({&ColorTest::access, - &ColorTest::debug, - &ColorTest::configuration); -} + &ColorTest::fromHue, + &ColorTest::fromSaturation, + &ColorTest::fromValue, + + &ColorTest::hue, + &ColorTest::saturation, + &ColorTest::value, -void ColorTest::fromDenormalized() { - CORRADE_COMPARE(Color3f::fromDenormalized(Color3(75, 115, 224)), Color3f(0.294118, 0.45098, 0.878431)); + &ColorTest::hsv, + &ColorTest::hsvOverflow, + &ColorTest::hsvAlpha, + + &ColorTest::debug, + &ColorTest::configuration}); } -void ColorTest::fromNormalized() { - CORRADE_COMPARE(Color3::fromNormalized(Color3f(0.294118, 0.45098, 0.878431)), Color3(75, 115, 224)); +void ColorTest::access() { + Color3f c3(15, 255, 10); + const Color3f cc3(15, 255, 10); + + CORRADE_COMPARE(c3.r(), 15); + CORRADE_COMPARE(c3.g(), 255); + CORRADE_COMPARE(c3.b(), 10); + CORRADE_COMPARE(cc3.r(), 15); + CORRADE_COMPARE(cc3.g(), 255); + CORRADE_COMPARE(cc3.b(), 10); + + Color4 c4(125, 98, 51, 22); + const Color4f cc4(125, 98, 51, 22); + + CORRADE_COMPARE(c4.r(), 125); + CORRADE_COMPARE(c4.g(), 98); + CORRADE_COMPARE(c4.b(), 51); + CORRADE_COMPARE(c4.a(), 22); + CORRADE_COMPARE(cc4.r(), 125); + CORRADE_COMPARE(cc4.g(), 98); + CORRADE_COMPARE(cc4.b(), 51); + CORRADE_COMPARE(cc4.a(), 22); } void ColorTest::fromHue() { - CORRADE_COMPARE(Color3::fromHSV(27.0f, 1.0f, 1.0f), Color3(255, 115, 0)); - CORRADE_COMPARE(Color3::fromHSV(86.0f, 1.0f, 1.0f), Color3(145, 255, 0)); - CORRADE_COMPARE(Color3::fromHSV(134.0f, 1.0f, 1.0f), Color3(0, 255, 60)); - CORRADE_COMPARE(Color3::fromHSV(191.0f, 1.0f, 1.0f), Color3(0, 208, 255)); - CORRADE_COMPARE(Color3::fromHSV(269.0f, 1.0f, 1.0f), Color3(123, 0, 255)); - CORRADE_COMPARE(Color3::fromHSV(317.0f, 1.0f, 1.0f), Color3(255, 0, 183)); + CORRADE_COMPARE(Color3::fromHSV(Deg(27.0f), 1.0f, 1.0f), Color3(255, 114, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(86.0f), 1.0f, 1.0f), Color3(144, 255, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(134.0f), 1.0f, 1.0f), Color3(0, 255, 59)); + CORRADE_COMPARE(Color3::fromHSV(Deg(191.0f), 1.0f, 1.0f), Color3(0, 208, 255)); + CORRADE_COMPARE(Color3::fromHSV(Deg(269.0f), 1.0f, 1.0f), Color3(123, 0, 255)); + CORRADE_COMPARE(Color3::fromHSV(Deg(317.0f), 1.0f, 1.0f), Color3(255, 0, 182)); } void ColorTest::hue() { - CORRADE_COMPARE(Color3(255, 115, 0).hue(), 27.058824f); - CORRADE_COMPARE(Color3(145, 255, 0).hue(), 85.882353f); - CORRADE_COMPARE(Color3(0, 255, 60).hue(), 134.11765f); - CORRADE_COMPARE(Color3(0, 208, 255).hue(), 191.05882f); - CORRADE_COMPARE(Color3(123, 0, 255).hue(), 268.94117f); - CORRADE_COMPARE(Color3(255, 0, 183).hue(), 316.94117f); + CORRADE_COMPARE(Color3(255, 115, 0).hue(), Deg(27.058824f)); + CORRADE_COMPARE(Color3(145, 255, 0).hue(), Deg(85.882353f)); + CORRADE_COMPARE(Color3(0, 255, 60).hue(), Deg(134.11765f)); + CORRADE_COMPARE(Color3(0, 208, 255).hue(), Deg(191.05882f)); + CORRADE_COMPARE(Color3(123, 0, 255).hue(), Deg(268.94117f)); + CORRADE_COMPARE(Color3(255, 0, 183).hue(), Deg(316.94117f)); } void ColorTest::fromSaturation() { - CORRADE_COMPARE(Color3::fromHSV(0.0f, 0.702f, 1.0f), Color3(255, 76, 76)); + CORRADE_COMPARE(Color3::fromHSV(Deg(0.0f), 0.702f, 1.0f), Color3(255, 75, 75)); } void ColorTest::saturation() { @@ -88,7 +128,7 @@ void ColorTest::saturation() { } void ColorTest::fromValue() { - CORRADE_COMPARE(Color3::fromHSV(0.0f, 1.0f, 0.522f), Color3(133, 0, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(0.0f), 1.0f, 0.522f), Color3(133, 0, 0)); } void ColorTest::value() { @@ -96,62 +136,65 @@ void ColorTest::value() { } void ColorTest::hsv() { - CORRADE_COMPARE(Color3::fromHSV(230.0f, 0.749f, 0.427f), Color3(27, 41, 109)); + CORRADE_COMPARE(Color3::fromHSV(Deg(230.0f), 0.749f, 0.427f), Color3(27, 40, 108)); - float hue, saturation, value; - tie(hue, saturation, value) = Color3(27, 41, 109).toHSV(); - CORRADE_COMPARE(hue, 229.756106f); + Deg hue; + Float saturation, value; + std::tie(hue, saturation, value) = Color3(27, 41, 109).toHSV(); + CORRADE_COMPARE(hue, Deg(229.756106f)); CORRADE_COMPARE(saturation, 0.752294f); CORRADE_COMPARE(value, 0.427451f); } void ColorTest::hsvOverflow() { - CORRADE_COMPARE(Color3::fromHSV(27.0f-360.0f, 1.0f, 1.0f), Color3(255, 115, 0)); - CORRADE_COMPARE(Color3::fromHSV(86.0f-360.0f, 1.0f, 1.0f), Color3(145, 255, 0)); - CORRADE_COMPARE(Color3::fromHSV(134.0f-360.0f, 1.0f, 1.0f), Color3(0, 255, 60)); - CORRADE_COMPARE(Color3::fromHSV(191.0f-360.0f, 1.0f, 1.0f), Color3(0, 208, 255)); - CORRADE_COMPARE(Color3::fromHSV(269.0f-360.0f, 1.0f, 1.0f), Color3(123, 0, 255)); - CORRADE_COMPARE(Color3::fromHSV(317.0f-360.0f, 1.0f, 1.0f), Color3(255, 0, 183)); - - CORRADE_COMPARE(Color3::fromHSV(360.0f+27.0f, 1.0f, 1.0f), Color3(255, 115, 0)); - CORRADE_COMPARE(Color3::fromHSV(360.0f+86.0f, 1.0f, 1.0f), Color3(145, 255, 0)); - CORRADE_COMPARE(Color3::fromHSV(360.0f+134.0f, 1.0f, 1.0f), Color3(0, 255, 60)); - CORRADE_COMPARE(Color3::fromHSV(360.0f+191.0f, 1.0f, 1.0f), Color3(0, 208, 255)); - CORRADE_COMPARE(Color3::fromHSV(360.0f+269.0f, 1.0f, 1.0f), Color3(123, 0, 255)); - CORRADE_COMPARE(Color3::fromHSV(360.0f+317.0f, 1.0f, 1.0f), Color3(255, 0, 183)); + CORRADE_COMPARE(Color3::fromHSV(Deg(27.0f-360.0f), 1.0f, 1.0f), Color3(255, 114, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(86.0f-360.0f), 1.0f, 1.0f), Color3(144, 255, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(134.0f-360.0f), 1.0f, 1.0f), Color3(0, 255, 59)); + CORRADE_COMPARE(Color3::fromHSV(Deg(191.0f-360.0f), 1.0f, 1.0f), Color3(0, 208, 255)); + CORRADE_COMPARE(Color3::fromHSV(Deg(269.0f-360.0f), 1.0f, 1.0f), Color3(123, 0, 255)); + CORRADE_COMPARE(Color3::fromHSV(Deg(317.0f-360.0f), 1.0f, 1.0f), Color3(255, 0, 182)); + + CORRADE_COMPARE(Color3::fromHSV(Deg(360.0f+27.0f), 1.0f, 1.0f), Color3(255, 114, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(360.0f+86.0f), 1.0f, 1.0f), Color3(144, 255, 0)); + CORRADE_COMPARE(Color3::fromHSV(Deg(360.0f+134.0f), 1.0f, 1.0f), Color3(0, 255, 59)); + CORRADE_COMPARE(Color3::fromHSV(Deg(360.0f+191.0f), 1.0f, 1.0f), Color3(0, 208, 255)); + CORRADE_COMPARE(Color3::fromHSV(Deg(360.0f+269.0f), 1.0f, 1.0f), Color3(123, 0, 255)); + CORRADE_COMPARE(Color3::fromHSV(Deg(360.0f+317.0f), 1.0f, 1.0f), Color3(255, 0, 182)); } void ColorTest::hsvAlpha() { - CORRADE_COMPARE(Color4::fromHSV(make_tuple(230.0f, 0.749f, 0.427f), 23), Color4(27, 41, 109, 23)); - CORRADE_COMPARE(Color4::fromHSV(230.0f, 0.749f, 0.427f, 23), Color4(27, 41, 109, 23)); + CORRADE_COMPARE(Color4::fromHSV(std::make_tuple(Deg(230.0f), 0.749f, 0.427f), 23), Color4(27, 40, 108, 23)); + CORRADE_COMPARE(Color4::fromHSV(Deg(230.0f), 0.749f, 0.427f, 23), Color4(27, 40, 108, 23)); } void ColorTest::debug() { - ostringstream o; + std::ostringstream o; Debug(&o) << Color3f(0.5f, 0.75f, 1.0f); CORRADE_COMPARE(o.str(), "Vector(0.5, 0.75, 1)\n"); - o.str(""); + o.str({}); Debug(&o) << Color4f(0.5f, 0.75f, 0.0f, 1.0f); CORRADE_COMPARE(o.str(), "Vector(0.5, 0.75, 0, 1)\n"); } void ColorTest::configuration() { - Configuration c; + Corrade::Utility::Configuration c; Color3f color3(0.5f, 0.75f, 1.0f); - string value3("0.5 0.75 1"); + std::string value3("0.5 0.75 1"); c.setValue("color3", color3); - CORRADE_COMPARE(c.value("color3"), value3); + CORRADE_COMPARE(c.value("color3"), value3); CORRADE_COMPARE(c.value("color3"), color3); Color4f color4(0.5f, 0.75f, 0.0f, 1.0f); - string value4("0.5 0.75 0 1"); + std::string value4("0.5 0.75 0 1"); c.setValue("color4", color4); - CORRADE_COMPARE(c.value("color4"), value4); + CORRADE_COMPARE(c.value("color4"), value4); CORRADE_COMPARE(c.value("color4"), color4); } }} + +CORRADE_TEST_MAIN(Magnum::Test::ColorTest) diff --git a/src/Test/ColorTest.h b/src/Test/ColorTest.h deleted file mode 100644 index 47b18101d..000000000 --- a/src/Test/ColorTest.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef Magnum_Test_ColorTest_h -#define Magnum_Test_ColorTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Test { - -class ColorTest: public Corrade::TestSuite::Tester { - public: - ColorTest(); - - void fromDenormalized(); - void fromNormalized(); - - void fromHue(); - void fromSaturation(); - void fromValue(); - - void hue(); - void saturation(); - void value(); - - void hsv(); - void hsvOverflow(); - void hsvAlpha(); - - void debug(); - void configuration(); -}; - -}} - -#endif diff --git a/src/Test/MeshTest.cpp b/src/Test/MeshTest.cpp index 0e1a9d949..10c91fcc8 100644 --- a/src/Test/MeshTest.cpp +++ b/src/Test/MeshTest.cpp @@ -1,47 +1,80 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ + 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: -#include "MeshTest.h" + 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 #include "Mesh.h" -CORRADE_TEST_MAIN(Magnum::Test::MeshTest) +namespace Magnum { namespace Test { -using namespace Corrade::Utility; +class MeshTest: public Corrade::TestSuite::Tester { + public: + MeshTest(); -namespace Magnum { namespace Test { + void debugPrimitive(); + void debugIndexType(); + void configurationPrimitive(); + void configurationIndexType(); +}; MeshTest::MeshTest() { - addTests(&MeshTest::debug, - &MeshTest::configuration); + addTests({&MeshTest::debugPrimitive, + &MeshTest::debugIndexType, + &MeshTest::configurationPrimitive, + &MeshTest::configurationIndexType}); } -void MeshTest::debug() { +void MeshTest::debugPrimitive() { std::ostringstream o; Debug(&o) << Mesh::Primitive::TriangleFan; CORRADE_COMPARE(o.str(), "Mesh::Primitive::TriangleFan\n"); } -void MeshTest::configuration() { - Configuration c; +void MeshTest::debugIndexType() { + std::ostringstream o; + Debug(&o) << Mesh::IndexType::UnsignedShort; + CORRADE_COMPARE(o.str(), "Mesh::IndexType::UnsignedShort\n"); +} + +void MeshTest::configurationPrimitive() { + Corrade::Utility::Configuration c; c.setValue("primitive", Mesh::Primitive::LineStrip); CORRADE_COMPARE(c.value("primitive"), "LineStrip"); CORRADE_COMPARE(c.value("primitive"), Mesh::Primitive::LineStrip); } +void MeshTest::configurationIndexType() { + Corrade::Utility::Configuration c; + + c.setValue("type", Mesh::IndexType::UnsignedByte); + CORRADE_COMPARE(c.value("type"), "UnsignedByte"); + CORRADE_COMPARE(c.value("type"), Mesh::IndexType::UnsignedByte); +} + }} + +CORRADE_TEST_MAIN(Magnum::Test::MeshTest) diff --git a/src/Test/MeshTest.h b/src/Test/MeshTest.h deleted file mode 100644 index 051488fbf..000000000 --- a/src/Test/MeshTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Test_MeshTest_h -#define Magnum_Test_MeshTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Test { - -class MeshTest: public Corrade::TestSuite::Tester { - public: - MeshTest(); - - void debug(); - void configuration(); -}; - -}} - -#endif diff --git a/src/Test/ResourceManagerTest.cpp b/src/Test/ResourceManagerTest.cpp index bd73a6b5b..ac3a89747 100644 --- a/src/Test/ResourceManagerTest.cpp +++ b/src/Test/ResourceManagerTest.cpp @@ -1,34 +1,51 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "ResourceManagerTest.h" - #include +#include #include "AbstractResourceLoader.h" #include "ResourceManager.h" #include "corradeCompatibility.h" -using namespace std; -using namespace Corrade::Utility; - -CORRADE_TEST_MAIN(Magnum::Test::ResourceManagerTest) - namespace Magnum { namespace Test { +class ResourceManagerTest: public Corrade::TestSuite::Tester { + public: + ResourceManagerTest(); + + void state(); + void stateFallback(); + void stateDisallowed(); + void basic(); + void residentPolicy(); + void referenceCountedPolicy(); + void manualPolicy(); + void loader(); +}; + class Data { public: static std::size_t count; @@ -37,16 +54,16 @@ class Data { inline ~Data() { --count; } }; -typedef Magnum::ResourceManager ResourceManager; +typedef Magnum::ResourceManager ResourceManager; -class IntResourceLoader: public AbstractResourceLoader { +class IntResourceLoader: public AbstractResourceLoader { public: void load(ResourceKey key) override { AbstractResourceLoader::load(key); } void load() { - set("hello", new std::int32_t(773), ResourceDataState::Final, ResourcePolicy::Resident); + set("hello", new Int(773), ResourceDataState::Final, ResourcePolicy::Resident); setNotFound("world"); } }; @@ -54,14 +71,14 @@ class IntResourceLoader: public AbstractResourceLoader { size_t Data::count = 0; ResourceManagerTest::ResourceManagerTest() { - addTests(&ResourceManagerTest::state, - &ResourceManagerTest::stateFallback, - &ResourceManagerTest::stateDisallowed, - &ResourceManagerTest::basic, - &ResourceManagerTest::residentPolicy, - &ResourceManagerTest::referenceCountedPolicy, - &ResourceManagerTest::manualPolicy, - &ResourceManagerTest::loader); + addTests({&ResourceManagerTest::state, + &ResourceManagerTest::stateFallback, + &ResourceManagerTest::stateDisallowed, + &ResourceManagerTest::basic, + &ResourceManagerTest::residentPolicy, + &ResourceManagerTest::referenceCountedPolicy, + &ResourceManagerTest::manualPolicy, + &ResourceManagerTest::loader}); } void ResourceManagerTest::state() { @@ -117,14 +134,14 @@ void ResourceManagerTest::stateFallback() { void ResourceManagerTest::stateDisallowed() { ResourceManager rm; - stringstream out; + std::ostringstream out; Error::setOutput(&out); Data d; rm.set("data", &d, ResourceDataState::Loading, ResourcePolicy::Resident); CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n"); - out.str(""); + out.str({}); rm.set("data", nullptr, ResourceDataState::Final, ResourcePolicy::Resident); CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n"); } @@ -135,27 +152,27 @@ void ResourceManagerTest::basic() { /* One mutable, one final */ ResourceKey questionKey("the-question"); ResourceKey answerKey("the-answer"); - rm.set(questionKey, new int32_t(10), ResourceDataState::Mutable, ResourcePolicy::Resident); - rm.set(answerKey, new int32_t(42), ResourceDataState::Final, ResourcePolicy::Resident); - Resource theQuestion = rm.get(questionKey); - Resource theAnswer = rm.get(answerKey); + rm.set(questionKey, new Int(10), ResourceDataState::Mutable, ResourcePolicy::Resident); + rm.set(answerKey, new Int(42), ResourceDataState::Final, ResourcePolicy::Resident); + Resource theQuestion = rm.get(questionKey); + Resource theAnswer = rm.get(answerKey); /* Check basic functionality */ CORRADE_COMPARE(theQuestion.state(), ResourceState::Mutable); CORRADE_COMPARE(theAnswer.state(), ResourceState::Final); CORRADE_COMPARE(*theQuestion, 10); CORRADE_COMPARE(*theAnswer, 42); - CORRADE_COMPARE(rm.count(), 2); + CORRADE_COMPARE(rm.count(), 2); /* Cannot change already final resource */ - stringstream out; + std::ostringstream out; Error::setOutput(&out); - rm.set(answerKey, new int32_t(43), ResourceDataState::Mutable, ResourcePolicy::Resident); + rm.set(answerKey, new Int(43), ResourceDataState::Mutable, ResourcePolicy::Resident); CORRADE_COMPARE(*theAnswer, 42); - CORRADE_COMPARE(out.str(), "ResourceManager::set(): cannot change already final resource\n"); + CORRADE_COMPARE(out.str(), "ResourceManager::set(): cannot change already final resource " + answerKey.hexString() + '\n'); /* But non-final can be changed */ - rm.set(questionKey, new int32_t(20), ResourceDataState::Final, ResourcePolicy::Resident); + rm.set(questionKey, new Int(20), ResourceDataState::Final, ResourcePolicy::Resident); CORRADE_COMPARE(theQuestion.state(), ResourceState::Final); CORRADE_COMPARE(*theQuestion, 20); } @@ -227,8 +244,8 @@ void ResourceManagerTest::loader() { rm.setLoader(&loader); Resource data = rm.get("data"); - Resource hello = rm.get("hello"); - Resource world = rm.get("world"); + Resource hello = rm.get("hello"); + Resource world = rm.get("world"); CORRADE_COMPARE(data.state(), ResourceState::NotLoaded); CORRADE_COMPARE(hello.state(), ResourceState::Loading); CORRADE_COMPARE(world.state(), ResourceState::Loading); @@ -240,3 +257,5 @@ void ResourceManagerTest::loader() { } }} + +CORRADE_TEST_MAIN(Magnum::Test::ResourceManagerTest) diff --git a/src/Test/ResourceManagerTest.h b/src/Test/ResourceManagerTest.h deleted file mode 100644 index fa95ec724..000000000 --- a/src/Test/ResourceManagerTest.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef Magnum_Test_ResourceManagerTest_h -#define Magnum_Test_ResourceManagerTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Test { - -class ResourceManagerTest: public Corrade::TestSuite::Tester { - public: - ResourceManagerTest(); - - void state(); - void stateFallback(); - void stateDisallowed(); - void basic(); - void residentPolicy(); - void referenceCountedPolicy(); - void manualPolicy(); - void loader(); -}; - -}} - -#endif diff --git a/src/Test/SwizzleTest.cpp b/src/Test/SwizzleTest.cpp index 3e821c749..75d281c44 100644 --- a/src/Test/SwizzleTest.cpp +++ b/src/Test/SwizzleTest.cpp @@ -1,103 +1,72 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "SwizzleTest.h" +#include #include "Swizzle.h" -using namespace std; - -CORRADE_TEST_MAIN(Magnum::Test::SwizzleTest) - namespace Magnum { namespace Test { -typedef Math::Vector2 Vector2; -typedef Math::Vector3 Vector3; -typedef Math::Vector4 Vector4; +class SwizzleTest: public Corrade::TestSuite::Tester { + public: + SwizzleTest(); -SwizzleTest::SwizzleTest() { - addTests(&SwizzleTest::xyzw, - &SwizzleTest::rgba, - &SwizzleTest::constants, - &SwizzleTest::fromSmall, - &SwizzleTest::type, - &SwizzleTest::defaultType); -} + void rgba(); + void type(); + void defaultType(); +}; -void SwizzleTest::xyzw() { - Vector4 orig(2, 4, 5, 7); - Vector4 swizzled(5, 2, 7, 4); - CORRADE_COMPARE(swizzle(orig, "zxwy"), swizzled); - CORRADE_COMPARE((swizzle<'z', 'x', 'w', 'y'>(orig)), swizzled); +SwizzleTest::SwizzleTest() { + addTests({&SwizzleTest::rgba, + &SwizzleTest::type, + &SwizzleTest::defaultType}); } void SwizzleTest::rgba() { - Vector4 orig(2, 4, 5, 7); - Vector4 swizzled(5, 2, 7, 4); - CORRADE_COMPARE(swizzle(orig, "brag"), swizzled); - CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g'>(orig)), swizzled); -} - -void SwizzleTest::constants() { - Vector4 orig(2, 4, 5, 7); - Vector4 swizzled(1, 7, 0, 4); - CORRADE_COMPARE(swizzle(orig, "1w0g"), swizzled); - CORRADE_COMPARE((swizzle<'1', 'w', '0', 'g'>(orig)), swizzled); -} - -void SwizzleTest::fromSmall() { - #ifndef CORRADE_GCC45_COMPATIBILITY - /* Force compile-time evaluation for both */ - constexpr Vector2 orig(1, 2); - constexpr Vector3 swizzled(swizzle(orig, "gxr")); - CORRADE_VERIFY((integral_constant::value)); - #else - Vector2 orig(1, 2); - #endif - - CORRADE_COMPARE(swizzle(orig, "gxr"), Vector3(2, 1, 1)); - CORRADE_COMPARE((swizzle<'g', 'x', 'r'>(orig)), Vector3(2, 1, 1)); + CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g'>(Vector4i(2, 4, 5, 7))), Vector4i(5, 2, 7, 4)); } void SwizzleTest::type() { - Vector4 orig; - CORRADE_VERIFY((is_same(orig)), Vector2>::value)); - CORRADE_VERIFY((is_same::value)); - CORRADE_VERIFY((is_same(orig)), Vector3>::value)); - CORRADE_VERIFY((is_same::value)); - CORRADE_VERIFY((is_same(orig)), Vector4>::value)); - CORRADE_VERIFY((is_same::value)); - - Color3 origColor3; - Color4 origColor4; - CORRADE_VERIFY((is_same(origColor3)), Color3>::value)); - CORRADE_VERIFY((is_same(origColor4)), Color3>::value)); - CORRADE_VERIFY((is_same>::value)); - CORRADE_VERIFY((is_same>::value)); - CORRADE_VERIFY((is_same(origColor3)), Color4>::value)); - CORRADE_VERIFY((is_same(origColor4)), Color4>::value)); - CORRADE_VERIFY((is_same>::value)); - CORRADE_VERIFY((is_same>::value)); + Vector4i orig; + CORRADE_VERIFY((std::is_same(orig)), Vector2i>::value)); + CORRADE_VERIFY((std::is_same(orig)), Vector3i>::value)); + CORRADE_VERIFY((std::is_same(orig)), Vector4i>::value)); + + Color3 origColor3; + Color4 origColor4; + CORRADE_VERIFY((std::is_same(origColor3)), Color3>::value)); + CORRADE_VERIFY((std::is_same(origColor4)), Color3>::value)); + CORRADE_VERIFY((std::is_same(origColor3)), Color4>::value)); + CORRADE_VERIFY((std::is_same(origColor4)), Color4>::value)); } void SwizzleTest::defaultType() { - Vector4 orig(1, 2, 3, 4); - CORRADE_COMPARE(swizzle<'b'>(orig), (Math::Vector<1, int32_t>(3))); - CORRADE_COMPARE(swizzle(orig, "b"), (Math::Vector<1, int32_t>(3))); - CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g', 'z', 'y', 'x'>(orig)), (Math::Vector<7, int32_t>(3, 1, 4, 2, 3, 2, 1))); - CORRADE_COMPARE(swizzle(orig, "bragzyx"), (Math::Vector<7, int32_t>(3, 1, 4, 2, 3, 2, 1))); + Vector4i orig(1, 2, 3, 4); + CORRADE_COMPARE(swizzle<'b'>(orig), (Math::Vector<1, Int>(3))); + CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g', 'z', 'y', 'x'>(orig)), (Math::Vector<7, Int>(3, 1, 4, 2, 3, 2, 1))); } }} + +CORRADE_TEST_MAIN(Magnum::Test::SwizzleTest) diff --git a/src/Test/SwizzleTest.h b/src/Test/SwizzleTest.h deleted file mode 100644 index 56a705f5d..000000000 --- a/src/Test/SwizzleTest.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef Magnum_Test_SwizzleTest_h -#define Magnum_Test_SwizzleTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Test { - -class SwizzleTest: public Corrade::TestSuite::Tester { - public: - SwizzleTest(); - - void xyzw(); - void rgba(); - void constants(); - void fromSmall(); - void type(); - void defaultType(); -}; - -}} - -#endif diff --git a/src/Test/TypeTraitsTest.cpp b/src/Test/TypeTraitsTest.cpp deleted file mode 100644 index 521e16019..000000000 --- a/src/Test/TypeTraitsTest.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "TypeTraitsTest.h" - -#include - -#include "TypeTraits.h" - -CORRADE_TEST_MAIN(Magnum::Test::TypeTraitsTest) - -using namespace Corrade::Utility; - -namespace Magnum { namespace Test { - -TypeTraitsTest::TypeTraitsTest() { - addTests(&TypeTraitsTest::debug, - &TypeTraitsTest::configuration); -} - -void TypeTraitsTest::debug() { - std::ostringstream o; - Debug(&o) << Type::UnsignedShort; - CORRADE_COMPARE(o.str(), "Type::UnsignedShort\n"); -} - -void TypeTraitsTest::configuration() { - Configuration c; - - c.setValue("type", Type::Byte); - CORRADE_COMPARE(c.value("type"), "Byte"); - CORRADE_COMPARE(c.value("type"), Type::Byte); -} - -}} diff --git a/src/Test/TypeTraitsTest.h b/src/Test/TypeTraitsTest.h deleted file mode 100644 index 2f634f50c..000000000 --- a/src/Test/TypeTraitsTest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef Magnum_Test_TypeTraitsTest_h -#define Magnum_Test_TypeTraitsTest_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include - -namespace Magnum { namespace Test { - -class TypeTraitsTest: public Corrade::TestSuite::Tester { - public: - TypeTraitsTest(); - - void debug(); - void configuration(); -}; - -}} - -#endif diff --git a/src/Text/AbstractFont.cpp b/src/Text/AbstractFont.cpp new file mode 100644 index 000000000..31214e636 --- /dev/null +++ b/src/Text/AbstractFont.cpp @@ -0,0 +1,35 @@ +/* + 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 "Text/AbstractFont.h" + +namespace Magnum { namespace Text { + +AbstractFont::AbstractFont() {} +AbstractFont::~AbstractFont() {} + +AbstractLayouter::AbstractLayouter(): _glyphCount(0) {} +AbstractLayouter::~AbstractLayouter() {} + +}} diff --git a/src/Text/AbstractFont.h b/src/Text/AbstractFont.h new file mode 100644 index 000000000..aa22df3c1 --- /dev/null +++ b/src/Text/AbstractFont.h @@ -0,0 +1,112 @@ +#ifndef Magnum_Text_AbstractFont_h +#define Magnum_Text_AbstractFont_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::Text::AbstractFont, Magnum::Text::AbstractLayouter + */ + +#include +#include + +#include "Magnum.h" +#include "Texture.h" +#include "Text/Text.h" +#include "Text/magnumTextVisibility.h" + +namespace Magnum { namespace Text { + +/** +@brief Base for fonts +*/ +class MAGNUM_TEXT_EXPORT AbstractFont { + AbstractFont(const AbstractFont&) = delete; + AbstractFont(AbstractFont&&) = delete; + AbstractFont& operator=(const AbstractFont&) = delete; + AbstractFont& operator=(const AbstractFont&&) = delete; + + public: + AbstractFont(); + virtual ~AbstractFont() = 0; + + /** @brief %Font texture atlas */ + inline Texture2D& texture() { return _texture; } + + /** + * @brief Layout the text using fon't own layouter + * @param size %Font size + * @param text Text to layout + */ + virtual AbstractLayouter* layout(const Float size, const std::string& text) = 0; + + #ifdef DOXYGEN_GENERATING_OUTPUT + private: + #else + protected: + #endif + Texture2D _texture; +}; + +/** +@brief Base for text layouters + +Returned by AbstractFont::layout(). +*/ +class MAGNUM_TEXT_EXPORT AbstractLayouter { + AbstractLayouter(const AbstractLayouter&) = delete; + AbstractLayouter(AbstractLayouter&&) = delete; + AbstractLayouter& operator=(const AbstractLayouter&) = delete; + AbstractLayouter& operator=(const AbstractLayouter&&) = delete; + + public: + AbstractLayouter(); + virtual ~AbstractLayouter() = 0; + + /** @brief Count of glyphs in laid out text */ + inline UnsignedInt glyphCount() const { + return _glyphCount; + } + + /** + * @brief Render glyph + * @param i Glyph index + * @param cursorPosition Cursor position + * + * Returns quad position, texture coordinates and advance to next + * glyph. + */ + virtual std::tuple renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) = 0; + + #ifdef DOXYGEN_GENERATING_OUTPUT + private: + #else + protected: + #endif + UnsignedInt _glyphCount; +}; + +}} + +#endif diff --git a/src/Text/CMakeLists.txt b/src/Text/CMakeLists.txt new file mode 100644 index 000000000..517ebbea2 --- /dev/null +++ b/src/Text/CMakeLists.txt @@ -0,0 +1,55 @@ +# +# 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. +# + +find_package(Freetype REQUIRED) +include_directories(${FREETYPE_INCLUDE_DIRS}) + +set(MagnumText_SRCS + AbstractFont.cpp + FreeTypeFont.cpp + TextRenderer.cpp) +set(MagnumText_HEADERS + AbstractFont.h + FreeTypeFont.h + Text.h + TextRenderer.h + + magnumTextVisibility.h) + +if(USE_HARFBUZZ) + find_package(HarfBuzz REQUIRED) + include_directories(${HARFBUZZ_INCLUDE_DIRS}) + + set(MagnumText_SRCS ${MagnumText_SRCS} HarfBuzzFont.cpp) + set(MagnumText_HEADERS ${MagnumText_HEADERS} HarfBuzzFont.h) +endif() + +add_library(MagnumText SHARED ${MagnumText_SRCS}) +target_link_libraries(MagnumText Magnum MagnumTextureTools ${FREETYPE_LIBRARIES}) +if(USE_HARFBUZZ) + target_link_libraries(MagnumText ${HARFBUZZ_LIBRARIES}) +endif() + +install(TARGETS MagnumText DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +install(FILES ${MagnumText_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Text) diff --git a/src/Text/FreeTypeFont.cpp b/src/Text/FreeTypeFont.cpp new file mode 100644 index 000000000..4cd54b78c --- /dev/null +++ b/src/Text/FreeTypeFont.cpp @@ -0,0 +1,227 @@ +/* + 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 "FreeTypeFont.h" + +#include +#include +#include FT_FREETYPE_H +#include + +#include "Extensions.h" +#include "Image.h" +#include "TextureTools/Atlas.h" +#include "TextureTools/DistanceField.h" + +namespace Magnum { namespace Text { + +namespace { + +class FreeTypeLayouter: public AbstractLayouter { + public: + FreeTypeLayouter(FreeTypeFont& font, const Float size, const std::string& text); + + std::tuple renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) override; + + private: + FreeTypeFont& font; + std::vector glyphs; + const Float size; +}; + +} + +FreeTypeFontRenderer::FreeTypeFontRenderer() { + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Init_FreeType(&_library) == 0); +} + +FreeTypeFontRenderer::~FreeTypeFontRenderer() { + FT_Done_FreeType(_library); +} + +FreeTypeFont::FreeTypeFont(FreeTypeFontRenderer& renderer, const std::string& fontFile, Float size): _size(size) { + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_New_Face(renderer.library(), fontFile.c_str(), 0, &_ftFont) == 0); + + finishConstruction(); +} + +FreeTypeFont::FreeTypeFont(FreeTypeFontRenderer& renderer, const unsigned char* data, std::size_t dataSize, Float size): _size(size) { + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_New_Memory_Face(renderer.library(), data, dataSize, 0, &_ftFont) == 0); + + finishConstruction(); +} + +void FreeTypeFont::finishConstruction() { + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Set_Char_Size(_ftFont, 0, _size*64, 100, 100) == 0); + + #ifndef MAGNUM_TARGET_GLES + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); + #else + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg); + #endif + + /* Set up the texture */ + _texture.setWrapping(Texture2D::Wrapping::ClampToEdge) + ->setMinificationFilter(Texture2D::Filter::Linear) + ->setMagnificationFilter(Texture2D::Filter::Linear); +} + +void FreeTypeFont::prerenderInternal(const std::string& characters, const Vector2i& atlasSize, const Int radius, Texture2D* output) { + glyphs.clear(); + + /** @bug Crash when atlas is too small */ + + /* Get glyph codes from characters */ + std::vector charIndices; + charIndices.reserve(characters.size()+1); + charIndices.push_back(0); + for(std::size_t i = 0; i != characters.size(); ) { + UnsignedInt codepoint; + std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(characters, i); + charIndices.push_back(FT_Get_Char_Index(_ftFont, codepoint)); + } + + /* Remove duplicates (e.g. uppercase and lowercase mapped to same glyph) */ + std::sort(charIndices.begin(), charIndices.end()); + charIndices.erase(std::unique(charIndices.begin(), charIndices.end()), charIndices.end()); + + /* Sizes of all characters */ + const Vector2i padding = Vector2i(radius); + std::vector charSizes; + charSizes.reserve(charIndices.size()); + for(FT_UInt c: charIndices) { + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, c, FT_LOAD_DEFAULT) == 0); + charSizes.push_back(Vector2i(_ftFont->glyph->metrics.width, _ftFont->glyph->metrics.height)/64); + } + + /* Create texture atlas */ + const std::vector charPositions = TextureTools::atlas(atlasSize, charSizes, padding); + + /* Render all characters to the atlas and create character map */ + glyphs.reserve(charPositions.size()); + unsigned char* pixmap = new unsigned char[atlasSize.product()](); + Image2D image(atlasSize, Image2D::Format::Red, Image2D::Type::UnsignedByte, pixmap); + for(std::size_t i = 0; i != charPositions.size(); ++i) { + /* Load and render glyph */ + /** @todo B&W only if radius != 0 */ + FT_GlyphSlot glyph = _ftFont->glyph; + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0); + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0); + + /* Copy rendered bitmap to texture image */ + const FT_Bitmap& bitmap = glyph->bitmap; + CORRADE_INTERNAL_ASSERT(std::abs(bitmap.width-charPositions[i].width()) <= 2); + CORRADE_INTERNAL_ASSERT(std::abs(bitmap.rows-charPositions[i].height()) <= 2); + for(Int yin = 0, yout = charPositions[i].bottom(), ymax = bitmap.rows; yin != ymax; ++yin, ++yout) + for(Int xin = 0, xout = charPositions[i].left(), xmax = bitmap.width; xin != xmax; ++xin, ++xout) + pixmap[yout*atlasSize.x() + xout] = bitmap.buffer[(bitmap.rows-yin-1)*bitmap.width + xin]; + + /* Save character texture position and texture coordinates for given character index */ + CORRADE_INTERNAL_ASSERT_OUTPUT(glyphs.insert({charIndices[i], std::make_tuple( + Rectangle::fromSize((Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height()) - Vector2(radius))/_size, + Vector2(charPositions[i].size() + 2*padding)/_size), + Rectangle(Vector2(charPositions[i].bottomLeft() - padding)/atlasSize, + Vector2(charPositions[i].topRight() + padding)/atlasSize) + )}).second); + } + + /* Set texture data */ + #ifndef MAGNUM_TARGET_GLES + output->setImage(0, Texture2D::InternalFormat::R8, &image); + #else + output->setImage(0, Texture2D::InternalFormat::Red, &image); + #endif +} + +void FreeTypeFont::prerender(const std::string& characters, const Vector2i& atlasSize) { + prerenderInternal(characters, atlasSize, 0, &_texture); +} + +void FreeTypeFont::prerenderDistanceField(const std::string& characters, const Vector2i& sourceAtlasSize, const Vector2i& atlasSize, Int radius) { + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_storage); + + /* Render input texture */ + Texture2D input; + input.setWrapping(Texture2D::Wrapping::ClampToEdge) + ->setMinificationFilter(Texture2D::Filter::Linear) + ->setMagnificationFilter(Texture2D::Filter::Linear); + prerenderInternal(characters, sourceAtlasSize, radius, &input); + + /* Create distance field from input texture */ + _texture.setStorage(1, Texture2D::InternalFormat::R8, atlasSize); + TextureTools::distanceField(&input, &_texture, Rectanglei::fromSize({}, atlasSize), radius); +} + +FreeTypeFont::~FreeTypeFont() { + FT_Done_Face(_ftFont); +} + +const std::tuple& FreeTypeFont::operator[](char32_t character) const { + auto it = glyphs.find(character); + + if(it == glyphs.end()) + return glyphs.at(0); + return it->second; +} + +AbstractLayouter* FreeTypeFont::layout(const Float size, const std::string& text) { + return new FreeTypeLayouter(*this, size, text); +} + +namespace { + +FreeTypeLayouter::FreeTypeLayouter(FreeTypeFont& font, const Float size, const std::string& text): font(font), size(size) { + /* Get glyph codes from characters */ + glyphs.reserve(text.size()); + _glyphCount = text.size(); + for(std::size_t i = 0; i != text.size(); ) { + UnsignedInt codepoint; + std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(text, i); + glyphs.push_back(FT_Get_Char_Index(font.font(), codepoint)); + } +} + +std::tuple FreeTypeLayouter::renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Rectangle texturePosition, textureCoordinates; + std::tie(texturePosition, textureCoordinates) = font[glyphs[i]]; + + /* Load glyph */ + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(font.font(), glyphs[i], FT_LOAD_DEFAULT) == 0); + const FT_GlyphSlot slot = font.font()->glyph; + Vector2 offset = Vector2(0, 0); /** @todo really? */ + Vector2 advance = Vector2(slot->advance.x, slot->advance.y)/(64*font.size()); + + /* Absolute quad position, composed from cursor position, glyph offset + and texture position, denormalized to requested text size */ + Rectangle quadPosition = Rectangle::fromSize( + (cursorPosition + offset + Vector2(texturePosition.left(), texturePosition.bottom()))*size, + texturePosition.size()*size); + + return std::make_tuple(quadPosition, textureCoordinates, advance); +} + +} + +}} diff --git a/src/Text/FreeTypeFont.h b/src/Text/FreeTypeFont.h new file mode 100644 index 000000000..223698995 --- /dev/null +++ b/src/Text/FreeTypeFont.h @@ -0,0 +1,178 @@ +#ifndef Magnum_Text_FreeTypeFont_h +#define Magnum_Text_FreeTypeFont_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::Text::FreeTypeFontRenderer, Magnum::Text::FreeTypeFont + */ + +#include + +#include "Math/Geometry/Rectangle.h" +#include "Texture.h" +#include "Text/AbstractFont.h" +#include "Text/magnumTextVisibility.h" + +#ifndef DOXYGEN_GENERATING_OUTPUT +struct FT_LibraryRec_; +typedef FT_LibraryRec_* FT_Library; +struct FT_FaceRec_; +typedef FT_FaceRec_* FT_Face; +#endif + +namespace Magnum { namespace Text { + +/** +@brief FreeType font renderer + +Contains global instance of font renderer. See FreeTypeFont class documentation +for more information. +*/ +class MAGNUM_TEXT_EXPORT FreeTypeFontRenderer { + public: + explicit FreeTypeFontRenderer(); + + ~FreeTypeFontRenderer(); + + /** @brief FreeType library handle */ + inline FT_Library library() { return _library; } + + private: + FT_Library _library; +}; + +/** +@brief FreeType font + +Contains font with characters prerendered into texture atlas. + +@section FreeTypeFont-usage Usage + +You need to maintain instance of FreeTypeFontRenderer during the lifetime of all FreeTypeFont +instances. The font can be created either from file or from memory location of +format supported by [FreeType](http://www.freetype.org/) library. Next step is +to prerender all the glyphs which will be used in text rendering later. +@code +Text::FreeTypeFontRenderer fontRenderer; + +Text::FreeTypeFont font(fontRenderer, "MyFreeTypeFont.ttf", 48.0f); +font.prerender("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789 ", Vector2i(512)); +@endcode +See TextRenderer for information about text rendering. + +@section FreeTypeFont-extensions Required OpenGL functionality + +%Font texture uses one-component internal format, which requires +@extension{ARB,texture_rg} (also part of OpenGL ES 3.0 or available as +@es_extension{EXT,texture_rg} in ES 2.0). +*/ +class MAGNUM_TEXT_EXPORT FreeTypeFont: public AbstractFont { + public: + /** + * @brief Create font from file + * @param renderer %Font renderer + * @param fontFile %Font file + * @param size %Font size + */ + explicit FreeTypeFont(FreeTypeFontRenderer& renderer, const std::string& fontFile, Float size); + + /** + * @brief Create font from memory + * @param renderer %Font renderer + * @param data %Font data + * @param dataSize %Font data size + * @param size %Font size + */ + explicit FreeTypeFont(FreeTypeFontRenderer& renderer, const unsigned char* data, std::size_t dataSize, Float size); + + /** + * @brief Prerender given character set + * @param characters UTF-8 characters to render + * @param atlasSize Size of resulting atlas + * + * Creates new atlas with prerendered characters, replacing the + * previous one (if any). + * @attention @p atlasSize must be large enough to contain all + * rendered glyphs. + */ + void prerender(const std::string& characters, const Vector2i& atlasSize); + + /** + * @brief Prerender given character set for use with distance-field rendering + * @param characters UTF-8 characters to render + * @param sourceAtlasSize Size of distance field source atlas + * @param atlasSize Size of resulting atlas + * @param radius Max lookup radius for distance-field creation + * + * Creates new atlas with prerendered characters, replacing the + * previous one (if any). See TextureTools::distanceField() for more + * information. + * @attention @p sourceAtlasSize must be large enough to contain all + * rendered glyphs with padding given by @p radius. + */ + void prerenderDistanceField(const std::string& characters, const Vector2i& sourceAtlasSize, const Vector2i& atlasSize, Int radius); + + ~FreeTypeFont(); + + /** @brief %Font size */ + inline Float size() const { return _size; } + + /** @brief Count of prerendered glyphs in the font */ + inline std::size_t glyphCount() const { return glyphs.size(); } + + /** + * @brief Position of given character in the texture + * @param character Unicode character code (UTF-32) + * + * First returned rectangle is texture position relative to point on + * baseline, second is position of the texture in texture atlas. + */ + const std::tuple& operator[](char32_t character) const; + + /** @brief FreeType font handle */ + inline FT_Face font() { return _ftFont; } + + AbstractLayouter* layout(const Float size, const std::string& text) override; + + #ifdef DOXYGEN_GENERATING_OUTPUT + private: + #else + protected: + #endif + FT_Face _ftFont; + + private: + void MAGNUM_TEXT_LOCAL finishConstruction(); + void MAGNUM_TEXT_LOCAL prerenderInternal(const std::string& characters, const Vector2i& atlasSize, const Int radius, Texture2D* output); + + std::unordered_map> glyphs; + Float _size; +}; + +}} + +#endif diff --git a/src/Text/HarfBuzzFont.cpp b/src/Text/HarfBuzzFont.cpp new file mode 100644 index 000000000..6adf781e7 --- /dev/null +++ b/src/Text/HarfBuzzFont.cpp @@ -0,0 +1,115 @@ +/* + 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 "HarfBuzzFont.h" + +#include + +namespace Magnum { namespace Text { + +namespace { + +class HarfBuzzLayouter: public AbstractLayouter { + public: + HarfBuzzLayouter(HarfBuzzFont& font, const Float size, const std::string& text); + ~HarfBuzzLayouter(); + + std::tuple renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) override; + + private: + const HarfBuzzFont& font; + hb_buffer_t* buffer; + hb_glyph_info_t* glyphInfo; + hb_glyph_position_t* glyphPositions; + const Float size; +}; + +} + +HarfBuzzFont::HarfBuzzFont(FreeTypeFontRenderer& renderer, const std::string& fontFile, Float size): FreeTypeFont(renderer, fontFile, size) { + finishConstruction(); +} + +HarfBuzzFont::HarfBuzzFont(FreeTypeFontRenderer& renderer, const unsigned char* data, std::size_t dataSize, Float size): FreeTypeFont(renderer, data, dataSize, size) { + finishConstruction(); +} + +void HarfBuzzFont::finishConstruction() { + /* Create Harfbuzz font */ + _hbFont = hb_ft_font_create(_ftFont, nullptr); +} + +HarfBuzzFont::~HarfBuzzFont() { + hb_font_destroy(_hbFont); +} + +AbstractLayouter* HarfBuzzFont::layout(const Float size, const std::string& text) { + return new HarfBuzzLayouter(*this, size, text); +} + +namespace { + +HarfBuzzLayouter::HarfBuzzLayouter(HarfBuzzFont& font, const Float size, const std::string& text): font(font), size(size) { + /* Prepare HarfBuzz buffer */ + buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + hb_buffer_set_script(buffer, HB_SCRIPT_LATIN); + hb_buffer_set_language(buffer, hb_language_from_string("en", 2)); + + /* Layout the text */ + hb_buffer_add_utf8(buffer, text.c_str(), -1, 0, -1); + hb_shape(font.font(), buffer, nullptr, 0); + + glyphInfo = hb_buffer_get_glyph_infos(buffer, &_glyphCount); + glyphPositions = hb_buffer_get_glyph_positions(buffer, &_glyphCount); +} + +HarfBuzzLayouter::~HarfBuzzLayouter() { + /* Destroy HarfBuzz buffer */ + hb_buffer_destroy(buffer); +} + +std::tuple HarfBuzzLayouter::renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Rectangle texturePosition, textureCoordinates; + std::tie(texturePosition, textureCoordinates) = font[glyphInfo[i].codepoint]; + + /* Glyph offset and advance to next glyph in normalized coordinates */ + Vector2 offset = Vector2(glyphPositions[i].x_offset, + glyphPositions[i].y_offset)/(64*font.size()); + Vector2 advance = Vector2(glyphPositions[i].x_advance, + glyphPositions[i].y_advance)/(64*font.size()); + + /* Absolute quad position, composed from cursor position, glyph offset + and texture position, denormalized to requested text size */ + Rectangle quadPosition = Rectangle::fromSize( + (cursorPosition + offset + Vector2(texturePosition.left(), texturePosition.bottom()))*size, + texturePosition.size()*size); + + return std::make_tuple(quadPosition, textureCoordinates, advance); +} + +} + +}} diff --git a/src/Text/HarfBuzzFont.h b/src/Text/HarfBuzzFont.h new file mode 100644 index 000000000..b34b8ab77 --- /dev/null +++ b/src/Text/HarfBuzzFont.h @@ -0,0 +1,84 @@ +#ifndef Magnum_Text_HarfBuzzFont_h +#define Magnum_Text_HarfBuzzFont_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::Text::HarfBuzzFont + */ + +#include "Text/FreeTypeFont.h" + +#ifndef DOXYGEN_GENERATING_OUTPUT +struct hb_font_t; +#endif + +#ifndef MAGNUM_USE_HARFBUZZ +#error Magnum is not compiled with HarfBuzz support +#endif + +namespace Magnum { namespace Text { + +/** +@brief HarfBuzz font + +Improves FreeTypeFont with [HarfBuzz](http://www.freedesktop.org/wiki/Software/HarfBuzz) +text layouting capabilities, such as kerning, ligatures etc. See FreeTypeFont +class documentation for more information about usage. +*/ +class MAGNUM_TEXT_EXPORT HarfBuzzFont: public FreeTypeFont { + public: + /** + * @brief Create font from file + * @param renderer %Font renderer + * @param fontFile %Font file + * @param size %Font size + */ + explicit HarfBuzzFont(FreeTypeFontRenderer& renderer, const std::string& fontFile, Float size); + + /** + * @brief Create font from memory + * @param renderer %Font renderer + * @param data %Font data + * @param dataSize %Font data size + * @param size %Font size + */ + explicit HarfBuzzFont(FreeTypeFontRenderer& renderer, const unsigned char* data, std::size_t dataSize, Float size); + + ~HarfBuzzFont(); + + /** @brief HarfBuzz font handle */ + inline hb_font_t* font() { return _hbFont; } + + AbstractLayouter* layout(const Float size, const std::string& text) override; + + private: + void MAGNUM_TEXT_LOCAL finishConstruction(); + + hb_font_t* _hbFont; +}; + +}} + +#endif diff --git a/src/Text/Text.h b/src/Text/Text.h new file mode 100644 index 000000000..7f18557d9 --- /dev/null +++ b/src/Text/Text.h @@ -0,0 +1,53 @@ +#ifndef Magnum_Text_Text_h +#define Magnum_Text_Text_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 Forward declarations for Magnum::Text namespace + */ + +#include "Types.h" + +#include "magnumConfigure.h" + +namespace Magnum { namespace Text { + +class AbstractFont; +class AbstractLayouter; + +class FreeTypeFontRenderer; +class FreeTypeFont; +#ifdef MAGNUM_USE_HARFBUZZ +class HarfBuzzFont; +#endif + +class AbstractTextRenderer; +template class TextRenderer; +typedef TextRenderer<2> TextRenderer2D; +typedef TextRenderer<3> TextRenderer3D; + +}} + +#endif diff --git a/src/Text/TextRenderer.cpp b/src/Text/TextRenderer.cpp new file mode 100644 index 000000000..e471b968d --- /dev/null +++ b/src/Text/TextRenderer.cpp @@ -0,0 +1,288 @@ +/* + 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 "TextRenderer.h" + +#include "Context.h" +#include "Extensions.h" +#include "Mesh.h" +#include "Shaders/AbstractVectorShader.h" +#include "Text/AbstractFont.h" + +namespace Magnum { namespace Text { + +namespace { + +template void createIndices(void* output, const UnsignedInt glyphCount) { + T* const out = reinterpret_cast(output); + for(UnsignedInt i = 0; i != glyphCount; ++i) { + /* 0---2 2 + | / /| + | / / | + |/ / | + 1 1---3 */ + + const T vertex = i*4; + const T pos = i*6; + out[pos] = vertex; + out[pos+1] = vertex+1; + out[pos+2] = vertex+2; + out[pos+3] = vertex+1; + out[pos+4] = vertex+3; + out[pos+5] = vertex+2; + } +} + +struct Vertex { + Vector2 position, texcoords; +}; + +} + +std::tuple, std::vector, std::vector, Rectangle> AbstractTextRenderer::render(AbstractFont& font, Float size, const std::string& text) { + AbstractLayouter* const layouter = font.layout(size, text); + const UnsignedInt vertexCount = layouter->glyphCount()*4; + + /* Output data */ + std::vector positions, texcoords; + positions.reserve(vertexCount); + texcoords.reserve(vertexCount); + + /* Render all glyphs */ + Vector2 cursorPosition; + for(UnsignedInt i = 0; i != layouter->glyphCount(); ++i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Rectangle quadPosition, textureCoordinates; + Vector2 advance; + std::tie(quadPosition, textureCoordinates, advance) = layouter->renderGlyph(cursorPosition, i); + + positions.insert(positions.end(), { + quadPosition.topLeft(), + quadPosition.bottomLeft(), + quadPosition.topRight(), + quadPosition.bottomRight(), + }); + texcoords.insert(texcoords.end(), { + textureCoordinates.topLeft(), + textureCoordinates.bottomLeft(), + textureCoordinates.topRight(), + textureCoordinates.bottomRight() + }); + + /* Advance cursor position to next character */ + cursorPosition += advance; + } + + /* Create indices */ + std::vector indices(layouter->glyphCount()*6); + createIndices(indices.data(), layouter->glyphCount()); + + /* Rendered rectangle */ + Rectangle rectangle; + if(layouter->glyphCount()) rectangle = {positions[1], positions[positions.size()-2]}; + + delete layouter; + return std::make_tuple(std::move(positions), std::move(texcoords), std::move(indices), rectangle); +} + +std::tuple AbstractTextRenderer::render(AbstractFont& font, Float size, const std::string& text, Buffer* vertexBuffer, Buffer* indexBuffer, Buffer::Usage usage) { + AbstractLayouter* const layouter = font.layout(size, text); + + const UnsignedInt vertexCount = layouter->glyphCount()*4; + const UnsignedInt indexCount = layouter->glyphCount()*6; + + /* Vertex buffer */ + std::vector vertices; + vertices.reserve(vertexCount); + + /* Render all glyphs */ + Vector2 cursorPosition; + for(UnsignedInt i = 0; i != layouter->glyphCount(); ++i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Rectangle quadPosition, textureCoordinates; + Vector2 advance; + std::tie(quadPosition, textureCoordinates, advance) = layouter->renderGlyph(cursorPosition, i); + + vertices.insert(vertices.end(), { + {quadPosition.topLeft(), textureCoordinates.topLeft()}, + {quadPosition.bottomLeft(), textureCoordinates.bottomLeft()}, + {quadPosition.topRight(), textureCoordinates.topRight()}, + {quadPosition.bottomRight(), textureCoordinates.bottomRight()} + }); + + /* Advance cursor position to next character */ + cursorPosition += advance; + } + vertexBuffer->setData(vertices, usage); + + /* Fill index buffer */ + Mesh::IndexType indexType; + std::size_t indicesSize; + char* indices; + if(vertexCount < 255) { + indexType = Mesh::IndexType::UnsignedByte; + indicesSize = indexCount*sizeof(UnsignedByte); + indices = new char[indicesSize]; + createIndices(indices, layouter->glyphCount()); + } else if(vertexCount < 65535) { + indexType = Mesh::IndexType::UnsignedShort; + indicesSize = indexCount*sizeof(UnsignedShort); + indices = new char[indicesSize]; + createIndices(indices, layouter->glyphCount()); + } else { + indexType = Mesh::IndexType::UnsignedInt; + indicesSize = indexCount*sizeof(UnsignedInt); + indices = new char[indicesSize]; + createIndices(indices, layouter->glyphCount()); + } + indexBuffer->setData(indicesSize, indices, usage); + delete indices; + + /* Rendered rectangle */ + Rectangle rectangle; + if(layouter->glyphCount()) rectangle = {vertices[1].position, vertices[vertices.size()-2].position}; + + /* Configure mesh except for vertex buffer (depends on dimension count, done + in subclass) */ + Mesh mesh; + mesh.setPrimitive(Mesh::Primitive::Triangles) + ->setIndexCount(indexCount) + ->setIndexBuffer(indexBuffer, 0, indexType, 0, vertexCount); + + delete layouter; + return std::make_tuple(std::move(mesh), rectangle); +} + +template std::tuple TextRenderer::render(AbstractFont& font, Float size, const std::string& text, Buffer* vertexBuffer, Buffer* indexBuffer, Buffer::Usage usage) { + /* Finalize mesh configuration and return the result */ + auto r = AbstractTextRenderer::render(font, size, text, vertexBuffer, indexBuffer, usage); + Mesh& mesh = std::get<0>(r); + mesh.addInterleavedVertexBuffer(vertexBuffer, 0, + typename Shaders::AbstractVectorShader::Position( + Shaders::AbstractVectorShader::Position::Components::Two), + typename Shaders::AbstractVectorShader::TextureCoordinates()); + return std::move(r); +} + +AbstractTextRenderer::AbstractTextRenderer(AbstractFont& font, Float size): vertexBuffer(Buffer::Target::Array), indexBuffer(Buffer::Target::ElementArray), font(font), size(size), _capacity(0) { + #ifndef MAGNUM_TARGET_GLES + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::map_buffer_range); + #else + #ifdef MAGNUM_TARGET_GLES2 + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::map_buffer_range); + #endif + #endif + + /* Vertex buffer configuration depends on dimension count, done in subclass */ + _mesh.setPrimitive(Mesh::Primitive::Triangles); +} + +AbstractTextRenderer::~AbstractTextRenderer() {} + +template TextRenderer::TextRenderer(AbstractFont& font, const Float size): AbstractTextRenderer(font, size) { + /* Finalize mesh configuration */ + _mesh.addInterleavedVertexBuffer(&vertexBuffer, 0, + typename Shaders::AbstractVectorShader::Position(Shaders::AbstractVectorShader::Position::Components::Two), + typename Shaders::AbstractVectorShader::TextureCoordinates()); +} + +void AbstractTextRenderer::reserve(const uint32_t glyphCount, const Buffer::Usage vertexBufferUsage, const Buffer::Usage indexBufferUsage) { + _capacity = glyphCount; + + const UnsignedInt vertexCount = glyphCount*4; + const UnsignedInt indexCount = glyphCount*6; + + /* Allocate vertex buffer, reset vertex count */ + vertexBuffer.setData(vertexCount*sizeof(Vertex), nullptr, vertexBufferUsage); + _mesh.setVertexCount(0); + + /* Allocate index buffer, reset index count and reconfigure buffer binding */ + Mesh::IndexType indexType; + std::size_t indicesSize; + if(vertexCount < 255) { + indexType = Mesh::IndexType::UnsignedByte; + indicesSize = indexCount*sizeof(UnsignedByte); + } else if(vertexCount < 65535) { + indexType = Mesh::IndexType::UnsignedShort; + indicesSize = indexCount*sizeof(UnsignedShort); + } else { + indexType = Mesh::IndexType::UnsignedInt; + indicesSize = indexCount*sizeof(UnsignedInt); + } + indexBuffer.setData(indicesSize, nullptr, indexBufferUsage); + _mesh.setIndexCount(0) + ->setIndexBuffer(&indexBuffer, 0, indexType, 0, vertexCount); + + /* Prefill index buffer */ + void* indices = indexBuffer.map(0, indicesSize, Buffer::MapFlag::InvalidateBuffer|Buffer::MapFlag::Write); + if(vertexCount < 255) + createIndices(indices, glyphCount); + else if(vertexCount < 65535) + createIndices(indices, glyphCount); + else + createIndices(indices, glyphCount); + CORRADE_INTERNAL_ASSERT_OUTPUT(indexBuffer.unmap()); +} + +void AbstractTextRenderer::render(const std::string& text) { + AbstractLayouter* layouter = font.layout(size, text); + + CORRADE_ASSERT(layouter->glyphCount() <= _capacity, "Text::TextRenderer::render(): capacity" << _capacity << "too small to render" << layouter->glyphCount() << "glyphs", ); + + /* Render all glyphs */ + Vertex* const vertices = static_cast(vertexBuffer.map(0, layouter->glyphCount()*4*sizeof(Vertex), + Buffer::MapFlag::InvalidateBuffer|Buffer::MapFlag::Write)); + Vector2 cursorPosition; + for(UnsignedInt i = 0; i != layouter->glyphCount(); ++i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Rectangle quadPosition, textureCoordinates; + Vector2 advance; + std::tie(quadPosition, textureCoordinates, advance) = layouter->renderGlyph(cursorPosition, i); + + if(i == 0) + _rectangle.bottomLeft() = quadPosition.bottomLeft(); + else if(i == layouter->glyphCount()-1) + _rectangle.topRight() = quadPosition.topRight(); + + const std::size_t vertex = i*4; + vertices[vertex] = {quadPosition.topLeft(), textureCoordinates.topLeft()}; + vertices[vertex+1] = {quadPosition.bottomLeft(), textureCoordinates.bottomLeft()}; + vertices[vertex+2] = {quadPosition.topRight(), textureCoordinates.topRight()}; + vertices[vertex+3] = {quadPosition.bottomRight(), textureCoordinates.bottomRight()}; + + /* Advance cursor position to next character */ + cursorPosition += advance; + } + CORRADE_INTERNAL_ASSERT_OUTPUT(vertexBuffer.unmap()); + + /* Update index count */ + _mesh.setIndexCount(layouter->glyphCount()*6); + + delete layouter; +} + +template class TextRenderer<2>; +template class TextRenderer<3>; + +}} diff --git a/src/Text/TextRenderer.h b/src/Text/TextRenderer.h new file mode 100644 index 000000000..998c30bdb --- /dev/null +++ b/src/Text/TextRenderer.h @@ -0,0 +1,228 @@ +#ifndef Magnum_Text_TextRenderer_h +#define Magnum_Text_TextRenderer_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::Text::AbstractTextRenderer, Magnum::Text::TextRenderer, typedef Magnum::Text::TextRenderer2D, Magnum::Text::TextRenderer3D + */ + +#include "Math/Geometry/Rectangle.h" +#include "Buffer.h" +#include "DimensionTraits.h" +#include "Mesh.h" +#include "Text/Text.h" + +#include "magnumTextVisibility.h" + +#include +#include +#include + +namespace Magnum { namespace Text { + +/** +@brief Base for text renderers + +Not meant to be used directly, see TextRenderer for more information. +@see TextRenderer2D, TextRenderer3D +*/ +class MAGNUM_TEXT_EXPORT AbstractTextRenderer { + public: + /** + * @brief Render text + * @param font %Font to use + * @param size %Font size + * @param text %Text to render + * + * Returns tuple with vertex positions, texture coordinates, indices + * and rectangle spanning the rendered text. + */ + static std::tuple, std::vector, std::vector, Rectangle> render(AbstractFont& font, Float size, const std::string& text); + + /** + * @brief Constructor + * @param font %Font to use + * @param size %Font size + */ + AbstractTextRenderer(AbstractFont& font, Float size); + + virtual ~AbstractTextRenderer() = 0; + + /** + * @brief Capacity for rendered glyphs + * + * @see reserve() + */ + inline UnsignedInt capacity() const { return _capacity; } + + /** @brief Rectangle spanning the rendered text */ + inline Rectangle rectangle() const { return _rectangle; } + + /** @brief Text mesh */ + inline Mesh* mesh() { return &_mesh; } + + /** + * @brief Reserve capacity for rendered glyphs + * + * Reallocates memory in buffers to hold @p glyphCount glyphs and + * prefills index buffer. Consider using appropriate @p vertexBufferUsage + * if the text will be changed frequently. Index buffer is changed + * only by calling this function, thus @p indexBufferUsage generally + * doesn't need to be so dynamic if the capacity won't be changed much. + * + * Initially zero capacity is reserved. + * @see capacity() + */ + void reserve(const UnsignedInt glyphCount, const Buffer::Usage vertexBufferUsage, const Buffer::Usage indexBufferUsage); + + /** + * @brief Render text + * + * Renders the text to vertex buffer, reusing index buffer already + * filled with reserve(). Rectangle spanning the rendered text is + * available through rectangle(). + * + * Initially no text is rendered. + * @attention The capacity must be large enough to contain all glyphs, + * see reserve() for more information. + */ + void render(const std::string& text); + + #ifndef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + static std::tuple MAGNUM_LOCAL render(AbstractFont& font, Float size, const std::string& text, Buffer* vertexBuffer, Buffer* indexBuffer, Buffer::Usage usage); + + Mesh _mesh; + Buffer vertexBuffer, indexBuffer; + + private: + AbstractFont& font; + Float size; + UnsignedInt _capacity; + Rectangle _rectangle; +}; + +/** +@brief %Text renderer + +Lays out the text into mesh using given Font. Use of ligatures, kerning etc. +depends on features supported by particular font and its layouter. + +@section TextRenderer-usage Usage + +Immutable text (e.g. menu items, credits) can be simply rendered using static +methods, returning result either as data arrays or as fully configured mesh. +The text can be then drawn by configuring text shader, binding font texture +and drawing the mesh: +@code +Text::Font font; +Shaders::VectorShader2D shader; +Buffer vertexBuffer, indexBuffer; +Mesh mesh; + +// Render the text +Rectangle rectangle; +std::tie(mesh, rectangle) = Text::TextRenderer2D::render(font, 0.15f, + "Hello World!", &vertexBuffer, &indexBuffer, Buffer::Usage::StaticDraw); + +// Draw white text centered on the screen +shader.setTransformationProjectionMatrix(projection*Matrix3::translation(-rectangle.width()/2.0f)) + ->setColor(Color3<>(1.0f)); + ->use(); +font.texture()->bind(Shaders::VectorShader2D::FontTextureLayer); +mesh.draw(); +@endcode +See render(Font&, Float, const std::string&) and +render(Font&, Float, const std::string&, Buffer*, Buffer*, Buffer::Usage) +for more information. + +While this method is sufficient for one-shot rendering of static texts, for +mutable texts (e.g. FPS counters, chat messages) there is another approach +that doesn't recreate everything on each text change: +@code +Text::Font font; +Shaders::VectorShader2D shader; + +// Initialize renderer and reserve memory for enough glyphs +Text::TextRenderer2D renderer(font, 0.15f); +renderer.reserve(32, Buffer::Usage::DynamicDraw, Buffer::Usage::StaticDraw); + +// Update the text occasionally +renderer.render("Hello World Countdown: 10"); + +// Draw the text centered on the screen +shader.setTransformationProjectionMatrix(projection*Matrix3::translation(-renderer.rectangle().width()/2.0f)) + ->setColor(Color3<>(1.0f)); + ->use(); +font.texture()->bind(Shaders::VectorShader2D::FontTextureLayer); +renderer.mesh().draw(); +@endcode + +@section TextRenderer-extensions Required OpenGL functionality + +Mutable text rendering requires @extension{ARB,map_buffer_range} (also part of +OpenGL ES 3.0 or available as @es_extension{EXT,map_buffer_range} in ES 2.0) +for asynchronous buffer updates. + +@see TextRenderer2D, TextRenderer3D, Font, Shaders::AbstractVectorShader +*/ +template class MAGNUM_TEXT_EXPORT TextRenderer: public AbstractTextRenderer { + public: + /** + * @brief Render text + * @param font %Font to use + * @param size %Font size + * @param text %Text to render + * @param vertexBuffer %Buffer where to store vertices + * @param indexBuffer %Buffer where to store indices + * @param usage Usage of vertex and index buffer + * + * Returns mesh prepared for use with Shaders::AbstractVectorShader + * subclasses and rectangle spanning the rendered text. + */ + static std::tuple render(AbstractFont& font, Float size, const std::string& text, Buffer* vertexBuffer, Buffer* indexBuffer, Buffer::Usage usage); + + /** + * @brief Constructor + * @param font %Font to use + * @param size %Font size + */ + TextRenderer(AbstractFont& font, Float size); + + using AbstractTextRenderer::render; +}; + +/** @brief Two-dimensional text renderer */ +typedef TextRenderer<2> TextRenderer2D; + +/** @brief Three-dimensional text renderer */ +typedef TextRenderer<3> TextRenderer3D; + +}} + +#endif diff --git a/src/Text/magnumTextVisibility.h b/src/Text/magnumTextVisibility.h new file mode 100644 index 000000000..a5608044a --- /dev/null +++ b/src/Text/magnumTextVisibility.h @@ -0,0 +1,39 @@ +#ifndef Magnum_Text_magnumTextVisibility_h +#define Magnum_Text_magnumTextVisibility_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. +*/ + +#ifdef _WIN32 + #ifdef MagnumText_EXPORTS + #define MAGNUM_TEXT_EXPORT __declspec(dllexport) + #else + #define MAGNUM_TEXT_EXPORT __declspec(dllimport) + #endif + #define MAGNUM_TEXT_LOCAL +#else + #define MAGNUM_TEXT_EXPORT __attribute__ ((visibility ("default"))) + #define MAGNUM_TEXT_LOCAL __attribute__ ((visibility ("hidden"))) +#endif + +#endif diff --git a/src/Texture.h b/src/Texture.h index 91cca9459..e68ecaf56 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -1,18 +1,27 @@ #ifndef Magnum_Texture_h #define Magnum_Texture_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -27,32 +36,89 @@ namespace Magnum { /** @brief %Texture -Template class for one- to three-dimensional textures. See AbstractTexture -documentation for more information. +Template class for one- to three-dimensional textures. See also +AbstractTexture documentation for more information. + +@section Texture-usage Usage + +Common usage is to fully configure all texture parameters and then set the +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); + +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}) + ->setSubImage(0, {}, &image) + ->generateMipmap(); +@endcode + +@attention Don't forget to fully configure the texture before use. Note that + default configuration (if setMinificationFilter() is not called with + another value) is to use mipmaps, so be sure to either call setMinificationFilter(), + explicitly specify all mip levels with setStorage() and setImage() or call + generateMipmap(). If using rectangle texture, you must also call + setWrapping(), because the initial value is not supported on rectangle + 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. + +@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. + +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() +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) + // ... + ->setStorage(levels, Texture2D::Format::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); + texture->setSubImage(0, Vector3i::zAxis(i), image); +} + +// ... +@endcode -In shader, the texture is used via `sampler1D`, `sampler2D` or `sampler3D` -depending on dimension count. Note that you can have more than one texture bound -to the shader - the only requirement is to have each texture in another layer. +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.). -@section RectangleTextures Rectangle textures +@section Texture-rectangle Rectangle textures -If you want to use rectangle textures, set target in constructor to -`Target::Rectangle` and in shader use `sampler2DRect`. 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. +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` +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. @requires_gl Rectangle textures are not available in OpenGL ES. -@requires_gl31 Extension @extension{ARB,texture_rectangle} (rectangle textures) +@requires_gl31 %Extension @extension{ARB,texture_rectangle} (rectangle + textures) @see Texture1D, Texture2D, Texture3D, CubeMapTexture, CubeMapTextureArray @todo @extension{AMD,sparse_texture} */ -template class Texture: public AbstractTexture { +template class Texture: public AbstractTexture { public: - static const std::uint8_t Dimensions = dimensions; /**< @brief %Texture dimension count */ + static const UnsignedInt Dimensions = dimensions; /**< @brief %Texture dimension count */ #ifdef DOXYGEN_GENERATING_OUTPUT /** @@ -78,7 +144,7 @@ template class Texture: public AbstractTexture { /** * One-dimensional texture array (i.e. two dimensions in total) - * @requires_gl30 Extension @extension{EXT,texture_array} + * @requires_gl30 %Extension @extension{EXT,texture_array} * @requires_gl Only 2D and 3D textures are available in OpenGL * ES. */ @@ -86,7 +152,7 @@ template class Texture: public AbstractTexture { /** * Two-dimensional texture array (i.e. three dimensions in total) - * @requires_gl30 Extension @extension{EXT,texture_array} + * @requires_gl30 %Extension @extension{EXT,texture_array} * @requires_gles30 Array textures are not available in OpenGL ES * 2.0. */ @@ -94,7 +160,7 @@ template class Texture: public AbstractTexture { /** * Rectangle texture (i.e. two dimensions) - * @requires_gl31 Extension @extension{ARB,texture_rectangle} + * @requires_gl31 %Extension @extension{ARB,texture_rectangle} * @requires_gl Rectangle textures are not available in OpenGL ES. */ Rectangle = GL_TEXTURE_RECTANGLE @@ -110,12 +176,30 @@ template class Texture: public AbstractTexture { * `Target::Texture3D` based on dimension count. * * Creates one OpenGL texture. + * @see @fn_gl{GenTextures} */ - inline Texture(Target target = DataHelper::target()): AbstractTexture(static_cast(target)) {} + inline explicit Texture(Target target = DataHelper::target()): AbstractTexture(static_cast(target)) {} /** @brief %Texture target */ inline constexpr Target target() const { return static_cast(_target); } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief %Image size in given mip level + * + * The result is not cached in any way. If + * @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{GetTexLevelParameter} or @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access} + * with @def_gl{TEXTURE_WIDTH}, @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) { + return DataHelper::imageSize(this, _target, level); + } + #endif + /** * @brief Set wrapping * @param wrapping Wrapping type for all texture dimensions @@ -124,7 +208,8 @@ template class Texture: public AbstractTexture { * Sets wrapping type for coordinates out of range (0, 1) for normal * 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. + * the texture is bound to some layer before the operation. Initial + * value is @ref AbstractTexture::Wrapping "Wrapping::Repeat". * @attention For rectangle textures only some modes are supported, * see @ref AbstractTexture::Wrapping "Wrapping" documentation * for more information. @@ -132,47 +217,77 @@ template class Texture: public AbstractTexture { * 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} - * @todo Use something better for this than Vector (mainly something - * that can easily create all values the same) */ - inline Texture* setWrapping(const Math::Vector& wrapping) { + inline Texture* setWrapping(const Array& wrapping) { DataHelper::setWrapping(this, wrapping); return this; } /** - * @brief Set texture data - * @param mipLevel Mip level - * @param internalFormat Internal texture format - * @param image Image, BufferedImage or for example + * @brief Set storage + * @param levels Mip level count + * @param internalFormat Internal format + * @param size Size of largest mip level + * @return Pointer to self (for method chaining) + * + * Specifies entire structure of a texture at once, removing the need + * for additional consistency checks and memory reallocations when + * updating the data later. After calling this function the texture + * is immutable and calling setStorage() or setImage() is not allowed. + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexStorage1D}/@fn_gl{TexStorage2D}/@fn_gl{TexStorage3D} + * or @fn_gl_extension{TextureStorage1D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access} + * @requires_gl42 %Extension @extension{ARB,texture_storage} + * @requires_gles30 %Extension @es_extension{EXT,texture_storage} + */ + inline Texture* setStorage(Int levels, InternalFormat internalFormat, const typename DimensionTraits::VectorType& size) { + DataHelper::setStorage(this, _target, levels, internalFormat, size); + return this; + } + + /** + * @brief Set image data + * @param level Mip level + * @param internalFormat Internal format + * @param image Image, ImageWrapper, BufferImage or * Trade::ImageData of the same dimension count * @return Pointer to self (for method chaining) * - * Sets texture data from given image. The image is not deleted - * afterwards. If @extension{EXT,direct_state_access} is not available, - * the texture is bound to some layer before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexImage1D}/ - * @fn_gl{TexImage2D}/@fn_gl{TexImage3D} or + * The image is not deleted afterwards. + * + * For better performance when generating mipmaps using + * generateMipmap() or calling setImage() more than once use + * setStorage() and setSubImage() instead. + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexImage1D}/@fn_gl{TexImage2D}/@fn_gl{TexImage3D} or * @fn_gl_extension{TextureImage1D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access} */ - template inline Texture* setData(GLint mipLevel, InternalFormat internalFormat, Image* image) { - DataHelper::set(this, _target, mipLevel, internalFormat, image); + template inline Texture* setImage(Int level, InternalFormat internalFormat, Image* image) { + DataHelper::set(this, _target, level, internalFormat, image); return this; } /** - * @brief Set texture subdata - * @param mipLevel Mip level + * @brief Set image subdata + * @param level Mip level * @param offset Offset where to put data in the texture - * @param image Image, BufferedImage or for example - * Trade::ImageData + * @param image Image, ImageWrapper, BufferImage or + * Trade::ImageData of the same or one less dimension count * @return Pointer to self (for method chaining) * - * Sets texture subdata from given image. The image is not deleted - * afterwards. The image can have either the same dimension count or - * have one dimension less, but at least one dimension. + * The image is not deleted afterwards. The image can have either the + * same dimension count or have one dimension less, but at least one + * dimension. * * If the image has one dimension less than the texture, the image is * taken as if it had the last dimension equal to 1. It can be used @@ -181,20 +296,34 @@ template class Texture: public AbstractTexture { * * If @extension{EXT,direct_state_access} is not available, the * texture is bound to some layer before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexSubImage1D}/ - * @fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D} or - * @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}/ + * @see setStorage(), setImage(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} + * and @fn_gl{TexSubImage1D}/@fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D} + * or @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}/ * @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} */ - template inline Texture* setSubData(GLint mipLevel, const typename DimensionTraits::VectorType& offset, Image* image) { - DataHelper::setSub(this, _target, mipLevel, offset, image); + template inline Texture* setSubImage(Int level, const typename DimensionTraits::VectorType& offset, Image* image) { + DataHelper::setSub(this, _target, level, offset, image); return this; } + /** + * @brief Invalidate texture subimage + * @param level Mip level + * @param offset Offset into the texture + * @param size Size of invalidated data + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * 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); + } + /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - inline Texture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel) { + inline Texture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); return this; } @@ -207,7 +336,7 @@ template class Texture: public AbstractTexture { AbstractTexture::setBorderColor(color); return this; } - inline Texture* setMaxAnisotropy(GLfloat anisotropy) { + inline Texture* setMaxAnisotropy(Float anisotropy) { AbstractTexture::setMaxAnisotropy(anisotropy); return this; } diff --git a/src/TextureTools/Atlas.cpp b/src/TextureTools/Atlas.cpp new file mode 100644 index 000000000..08398437c --- /dev/null +++ b/src/TextureTools/Atlas.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 "Atlas.h" + +#include "Math/Functions.h" +#include "Math/Geometry/Rectangle.h" + +namespace Magnum { namespace TextureTools { + +std::vector atlas(const Vector2i& atlasSize, const std::vector& sizes, const Vector2i& padding) { + if(sizes.empty()) return {}; + + /* Size of largest texture */ + Vector2i maxSize; + for(const Vector2i& size: sizes) + maxSize = Math::max(maxSize, size); + + std::vector atlas; + + /* Columns and rows */ + const Vector2i paddedSize = maxSize+2*padding; + const Vector2i gridSize = atlasSize/paddedSize; + if(std::size_t(gridSize.product()) < sizes.size()) { + Error() << "TextureTools::atlas(): requested atlas size" << atlasSize + << "is too small to fit" << sizes.size() << paddedSize + << "textures. Generated atlas will be empty."; + return atlas; + } + + /** @todo actual magic implementation, not this joke */ + + atlas.reserve(sizes.size()); + for(std::size_t i = 0; i != sizes.size(); ++i) + atlas.push_back(Rectanglei::fromSize(Vector2i(i%gridSize.x(), i/gridSize.x())*paddedSize+padding, sizes[i])); + + return atlas; +} + +}} diff --git a/src/TextureTools/Atlas.h b/src/TextureTools/Atlas.h new file mode 100644 index 000000000..548eb9921 --- /dev/null +++ b/src/TextureTools/Atlas.h @@ -0,0 +1,57 @@ +#ifndef Magnum_TextureTools_Atlas_h +#define Magnum_TextureTools_Atlas_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::TextureTools::atlas() + */ + +#include + +#include "Math/Vector2.h" +#include "Magnum.h" + +#include "magnumTextureToolsVisibility.h" + +namespace Magnum { namespace TextureTools { + +/** +@brief Pack textures into texture atlas +@param atlasSize Size of resulting atlas +@param sizes Sizes of all textures in the atlas +@param padding Padding around each texture + +Packs many small textures into one larger. If the textures cannot be packed +into required size, empty vector is returned. + +Padding is added twice to each size and the atlas is laid out so the padding +don't overlap. Returned sizes are the same as original sizes, i.e. without the +padding. +*/ +std::vector MAGNUM_TEXTURETOOLS_EXPORT atlas(const Vector2i& atlasSize, const std::vector& sizes, const Vector2i& padding = Vector2i()); + +}} + +#endif diff --git a/src/TextureTools/CMakeLists.txt b/src/TextureTools/CMakeLists.txt new file mode 100644 index 000000000..701f299e5 --- /dev/null +++ b/src/TextureTools/CMakeLists.txt @@ -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. +# + +corrade_add_resource(MagnumTextureTools_RCS MagnumTextureTools + DistanceFieldShader.vert DistanceFieldShader.frag + ../Shaders/compatibility.glsl ALIAS compatibility.glsl) + +set(MagnumTextureTools_SRCS + Atlas.cpp + DistanceField.cpp + ${MagnumTextureTools_RCS}) + +set(MagnumTextureTools_HEADERS + Atlas.h + DistanceField.h + + magnumTextureToolsVisibility.h) + +add_library(MagnumTextureTools SHARED ${MagnumTextureTools_SRCS}) +target_link_libraries(MagnumTextureTools Magnum) + +install(TARGETS MagnumTextureTools DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +install(FILES ${MagnumTextureTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/TextureTools) + +if(BUILD_TESTS) + add_subdirectory(Test) +endif() diff --git a/src/TextureTools/DistanceField.cpp b/src/TextureTools/DistanceField.cpp new file mode 100644 index 000000000..7b5e0a6f6 --- /dev/null +++ b/src/TextureTools/DistanceField.cpp @@ -0,0 +1,106 @@ +/* + 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 "TextureTools/DistanceField.h" + +#include +#include "Math/Geometry/Rectangle.h" +#include "AbstractShaderProgram.h" +#include "Extensions.h" +#include "Framebuffer.h" +#include "Mesh.h" +#include "Shader.h" +#include "Texture.h" + +namespace Magnum { namespace TextureTools { + +namespace { + +class DistanceFieldShader: public AbstractShaderProgram { + public: + enum: Int { + TextureLayer = 8 + }; + + explicit DistanceFieldShader(); + + inline DistanceFieldShader* setRadius(Int radius) { + setUniform(radiusUniform, radius); + return this; + } + + inline DistanceFieldShader* setScaling(Vector2 scaling) { + setUniform(scalingUniform, scaling); + return this; + } + + private: + static const Int radiusUniform = 0, + scalingUniform = 1; +}; + +DistanceFieldShader::DistanceFieldShader() { + MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_attrib_location); + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_uniform_location); + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::shading_language_420pack); + + /** @todo compatibility! */ + + Corrade::Utility::Resource rs("MagnumTextureTools"); + attachShader(Shader::fromData(Version::GL330, Shader::Type::Vertex, rs.get("DistanceFieldShader.vert"))); + + Shader fragmentShader(Version::GL330, Shader::Type::Fragment); + fragmentShader.addSource(rs.get("compatibility.glsl")); + fragmentShader.addSource(rs.get("DistanceFieldShader.frag")); + attachShader(fragmentShader); + + link(); +} + +} + +void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius) { + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::framebuffer_object); + + /** @todo Disable depth test and then enable it back (if was previously) */ + + Framebuffer framebuffer(rectangle); + framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), output, 0); + framebuffer.bind(Framebuffer::Target::Draw); + + DistanceFieldShader shader; + shader.setRadius(radius) + ->setScaling(Vector2(input->imageSize(0))/rectangle.size()) + ->use(); + + input->bind(DistanceFieldShader::TextureLayer); + + Mesh mesh; + mesh.setPrimitive(Mesh::Primitive::Triangles) + ->setVertexCount(3) + ->draw(); +} + +}} diff --git a/src/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h new file mode 100644 index 000000000..a88ab940e --- /dev/null +++ b/src/TextureTools/DistanceField.h @@ -0,0 +1,74 @@ +#ifndef Magnum_TextureTools_DistanceField_h +#define Magnum_TextureTools_DistanceField_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::TextureTools::distanceField() + */ + +#include "Magnum.h" + +#include "TextureTools/magnumTextureToolsVisibility.h" + +namespace Magnum { namespace TextureTools { + +/** +@brief Create signed distance field +@param input Input texture +@param output Output texture +@param rectangle Rectangle in output texture where to render +@param radius Max lookup radius in input texture + +Converts binary image (stored in red channel of @p input) to signed distance +field (stored in red channel in @p rectangle of @p output). The purpose of this +function is to convert high-resolution binary image (such as vector artwork or +font glyphs) to low-resolution grayscale image. The image will then occupy much +less memory and can be scaled without aliasing issues. Additionally it provides +foundation for features like outlining, glow or drop shadow essentialy for free. + +For each pixel inside @p rectangle the algorithm looks at corresponding pixel in +@p input and tries to find nearest pixel of opposite color in area given by +@p radius. Signed distance between the points is then saved as value of given +pixel in @p output. Value of `0` means that the pixel was originally colored +white and nearest black pixel is farther than @p radius, value of `1` means that +the pixel was originally black and nearest white pixel is farther than +@p radius. Values around `0.5` are around edges. + +The resulting texture can be used with bilinear filtering. It can be converted +back to binary form in shader using e.g. GLSL `smoothstep()` function with step +around `0.5` to create antialiased edges. Or you can exploit the distance field +features to create many other effects. See also Shaders::DistanceFieldVectorShader. + +Based on: *Chris Green - Improved Alpha-Tested Magnification for Vector Textures +and Special Effects, SIGGRAPH 2007, +http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf* + +@attention This is GPU-only implementation, so it expects active context. +*/ +void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius); + +}} + +#endif diff --git a/src/TextureTools/DistanceFieldShader.frag b/src/TextureTools/DistanceFieldShader.frag new file mode 100644 index 000000000..9191f9525 --- /dev/null +++ b/src/TextureTools/DistanceFieldShader.frag @@ -0,0 +1,83 @@ +/* + 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 = 0) uniform int radius; +layout(location = 1) uniform vec2 scaling; +layout(binding = 8) uniform sampler2D texture; + +layout(pixel_center_integer) in vec4 gl_FragCoord; + +out float value; + +ivec2 rotate(const ivec2 vec) { + return ivec2(-vec.y, vec.x); +} + +bool hasValue(const ivec2 position, const ivec2 offset) { + return texelFetch(texture, position+offset, 0).r > 0.5; +} + +void main() { + const ivec2 position = ivec2(gl_FragCoord.xy*scaling); + + /* If pixel at the position is inside (1), we are looking for nearest pixel + outside and the value will be positive (> 0.5). If it is outside (0), we + are looking for nearest pixel inside and the value will be negative + (< 0.5). */ + const bool isInside = hasValue(position, ivec2(0, 0)); + const float sign = isInside ? 1.0 : -1.0; + + /* Minimal found distance is just out of the radius (i.e. infinity) */ + float minDistanceSquared = float((radius+1)*(radius+1)); + + /* Go in circles around the point and find nearest value */ + int radiusLimit = radius; + for(int i = 1; i <= radiusLimit; ++i) { + for(int j = 0, jmax = i*2; j != jmax; ++j) { + const ivec2 offset = {-i+j, i}; + + /* If any of the four values is opposite of what is on the pixel, + we found nearest value */ + if(hasValue(position, offset) == !isInside || + hasValue(position, rotate(offset)) == !isInside || + hasValue(position, rotate(rotate(offset))) == !isInside || + hasValue(position, rotate(rotate(rotate(offset)))) == !isInside) { + const float distanceSquared = dot(vec2(offset), vec2(offset)); + + /* Set smaller distance, if found, or continue with lookup for + smaller */ + if(minDistanceSquared < distanceSquared) continue; + else minDistanceSquared = distanceSquared; + + /* Set radius limit to max radius which can contain smaller + value, e.g. for distance 3.5 we can find smaller value even + in radius 3 */ + radiusLimit = min(radius, int(floor(length(vec2(offset))))); + } + } + } + + /* Final signed distance, normalized from [-radius-1, radius+1] to [0, 1] */ + value = sign*sqrt(minDistanceSquared)/float(radius*2+2)+0.5; +} diff --git a/src/TextureTools/DistanceFieldShader.vert b/src/TextureTools/DistanceFieldShader.vert new file mode 100644 index 000000000..a412a0a20 --- /dev/null +++ b/src/TextureTools/DistanceFieldShader.vert @@ -0,0 +1,28 @@ +/* + 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. +*/ + +void main() { + gl_Position = vec4((gl_VertexID == 2) ? 3.0 : -1.0, + (gl_VertexID == 1) ? -3.0 : 1.0, 0.0, 1.0); +} diff --git a/src/TextureTools/Test/AtlasTest.cpp b/src/TextureTools/Test/AtlasTest.cpp new file mode 100644 index 000000000..aa653ad28 --- /dev/null +++ b/src/TextureTools/Test/AtlasTest.cpp @@ -0,0 +1,98 @@ +/* + 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/Geometry/Rectangle.h" +#include "TextureTools/Atlas.h" + +namespace Magnum { namespace TextureTools { namespace Test { + +class AtlasTest: public Corrade::TestSuite::Tester { + public: + explicit AtlasTest(); + + void create(); + void createPadding(); + void createEmpty(); + void createTooSmall(); +}; + +AtlasTest::AtlasTest() { + addTests({&AtlasTest::create, + &AtlasTest::createPadding, + &AtlasTest::createEmpty, + &AtlasTest::createTooSmall}); +} + +void AtlasTest::create() { + std::vector atlas = TextureTools::atlas({64, 64}, { + {12, 18}, + {32, 15}, + {23, 25} + }); + + CORRADE_COMPARE(atlas.size(), 3); + CORRADE_COMPARE(atlas, (std::vector{ + Rectanglei::fromSize({0, 0}, {12, 18}), + Rectanglei::fromSize({32, 0}, {32, 15}), + Rectanglei::fromSize({0, 25}, {23, 25})})); +} + +void AtlasTest::createPadding() { + std::vector atlas = TextureTools::atlas({64, 64}, { + {8, 16}, + {28, 13}, + {19, 23} + }, {2, 1}); + + CORRADE_COMPARE(atlas.size(), 3); + CORRADE_COMPARE(atlas, (std::vector{ + Rectanglei::fromSize({2, 1}, {8, 16}), + Rectanglei::fromSize({34, 1}, {28, 13}), + Rectanglei::fromSize({2, 26}, {19, 23})})); +} + +void AtlasTest::createEmpty() { + std::vector atlas = TextureTools::atlas({}, {}); + CORRADE_VERIFY(atlas.empty()); +} + +void AtlasTest::createTooSmall() { + std::ostringstream o; + Error::setOutput(&o); + + std::vector atlas = TextureTools::atlas({64, 32}, { + {8, 16}, + {21, 13}, + {19, 29} + }, {2, 1}); + CORRADE_VERIFY(atlas.empty()); + CORRADE_COMPARE(o.str(), "TextureTools::atlas(): requested atlas size Vector(64, 32) is too small to fit 3 Vector(25, 31) textures. Generated atlas will be empty.\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::TextureTools::Test::AtlasTest) diff --git a/src/TextureTools/Test/CMakeLists.txt b/src/TextureTools/Test/CMakeLists.txt new file mode 100644 index 000000000..f1849c53e --- /dev/null +++ b/src/TextureTools/Test/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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. +# + +corrade_add_test(TextureToolsAtlasTest AtlasTest.cpp LIBRARIES MagnumTextureTools) diff --git a/src/TextureTools/magnumTextureToolsVisibility.h b/src/TextureTools/magnumTextureToolsVisibility.h new file mode 100644 index 000000000..ad0dbb333 --- /dev/null +++ b/src/TextureTools/magnumTextureToolsVisibility.h @@ -0,0 +1,37 @@ +#ifndef Magnum_TextureTools_magnumTextureToolsVisibility_h +#define Magnum_TextureTools_magnumTextureToolsVisibility_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. +*/ + +#ifdef _WIN32 + #ifdef MagnumTextureTools_EXPORTS + #define MAGNUM_TEXTURETOOLS_EXPORT __declspec(dllexport) + #else + #define MAGNUM_TEXTURETOOLS_EXPORT __declspec(dllimport) + #endif +#else + #define MAGNUM_TEXTURETOOLS_EXPORT __attribute__ ((visibility ("default"))) +#endif + +#endif diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 7183c899d..2df6f5e74 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -1,19 +1,29 @@ -#include "Timeline.h" /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Timeline.h" + #include #include @@ -23,13 +33,15 @@ namespace Magnum { void Timeline::start() { running = true; - previousFrameTime = high_resolution_clock::now(); + _startTime = high_resolution_clock::now(); + _previousFrameTime = _startTime; _previousFrameDuration = 0; } void Timeline::stop() { running = false; - previousFrameTime = high_resolution_clock::time_point(); + _startTime = high_resolution_clock::time_point(); + _previousFrameTime = _startTime; _previousFrameDuration = 0; } @@ -37,16 +49,20 @@ void Timeline::nextFrame() { if(!running) return; auto now = high_resolution_clock::now(); - std::uint32_t duration = duration_cast(now-previousFrameTime).count(); + UnsignedInt duration = duration_cast(now-_previousFrameTime).count(); _previousFrameDuration = duration/1e6f; if(_previousFrameDuration < _minimalFrameTime) { Corrade::Utility::sleep(_minimalFrameTime*1000 - duration/1000); now = high_resolution_clock::now(); - _previousFrameDuration = duration_cast(now-previousFrameTime).count()/1e6f; + _previousFrameDuration = duration_cast(now-_previousFrameTime).count()/1e6f; } - previousFrameTime = now; + _previousFrameTime = now; +} + +Float Timeline::previousFrameTime() const { + return duration_cast(_previousFrameTime-_startTime).count()/1e6f; } } diff --git a/src/Timeline.h b/src/Timeline.h index 093191677..a74efe154 100644 --- a/src/Timeline.h +++ b/src/Timeline.h @@ -1,23 +1,32 @@ #ifndef Magnum_Timeline_h #define Magnum_Timeline_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "Magnum.h" +#include "Types.h" #include "magnumVisibility.h" @@ -27,39 +36,86 @@ namespace Magnum { -/** @brief %Timeline */ +/** +@brief %Timeline + +Keeps track of time delta between frames and allows FPS limiting. Can be used +as source for animation speed computations. + +@section Timeline-usage Basic usage + +Construct the timeline on initialization so the instance is available for +whole lifetime of the application. Call start() before first draw event is +performed, after everything is properly initialized. + +@note When timeline is started, it immediately starts measuring frame time. + Be prepared that time of first frame will be much longer than time of + following frames. It mainly depends on where you called start() in your + initialization routine, but can be also affected by driver- and + GPU-specific lazy texture binding, shader recompilations etc. + +In your draw event implementation don't forget to call nextFrame() after +buffer swap. You can use previousFrameDuration() to compute animation speed. + +Example usage (in e.g. @ref Platform::GlutApplication "GlutApplication" +subclass): +@code +MyApplication::MyApplication(...): Platform::GlutApplication(...) { + // Initialization ... + + timeline.setMinimalFrameTime(1/120.0f); // 120 FPS at max + timeline.start(); +} + +void MyApplication::drawEvent() { + // Distance of object travelling at speed of 15 units per second + Float distance = 15.0f*timeline.previousFrameDuration(); + + // Move object, draw ... + + swapBuffers(); + redraw(); + timeline.nextFrame(); +} +@endcode +*/ class MAGNUM_EXPORT Timeline { public: /** * @brief Constructor * - * Constructs stopped timeline. + * Creates stopped timeline. * @see start() */ - inline constexpr Timeline(): _minimalFrameTime(0), _previousFrameDuration(0), running(false) {} + inline constexpr explicit Timeline(): _minimalFrameTime(0), _previousFrameDuration(0), running(false) {} /** @brief Minimal frame time (in seconds) */ - GLfloat minimalFrameTime() const { return _minimalFrameTime; } + inline constexpr Float minimalFrameTime() const { + return _minimalFrameTime; + } /** * @brief Set minimal frame time * + * Default value is 0. * @see nextFrame() */ - void setMinimalFrameTime(GLfloat seconds) { + inline void setMinimalFrameTime(Float seconds) { _minimalFrameTime = seconds; } /** * @brief Start timeline * - * Sets previous frame duration to `0`. + * Sets previous frame time and duration to `0`. * @see stop(), previousFrameDuration() */ void start(); /** * @brief Stop timeline + * + * @see start(), nextFrame() */ void stop(); @@ -69,19 +125,32 @@ class MAGNUM_EXPORT Timeline { * If current frame time is smaller than minimal frame time, pauses * the execution for remaining time. * @note This function does nothing if the timeline is stopped. - * @see setMinimalFrameTime() + * @see setMinimalFrameTime(), stop() */ void nextFrame(); - /** @brief Duration of previous frame */ - inline constexpr GLfloat previousFrameDuration() const { + /** + * @brief Time at previous frame (in seconds) + * + * Returns time elapsed since start() was called. If the timeline is + * stopped, the function returns `0.0f`. + */ + Float previousFrameTime() const; + + /** + * @brief Duration of previous frame (in seconds) + * + * If the timeline is stopped, the function returns `0.0f`. + */ + inline constexpr Float previousFrameDuration() const { return _previousFrameDuration; } private: - std::chrono::high_resolution_clock::time_point previousFrameTime; - GLfloat _minimalFrameTime; - GLfloat _previousFrameDuration; + std::chrono::high_resolution_clock::time_point _startTime; + std::chrono::high_resolution_clock::time_point _previousFrameTime; + Float _minimalFrameTime; + Float _previousFrameDuration; bool running; }; diff --git a/src/Trade/AbstractImporter.cpp b/src/Trade/AbstractImporter.cpp index ec68d9c21..79f7a9098 100644 --- a/src/Trade/AbstractImporter.cpp +++ b/src/Trade/AbstractImporter.cpp @@ -1,24 +1,32 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "AbstractImporter.h" #include -using namespace std; -using namespace Corrade::Utility; +#include "Magnum.h" namespace Magnum { namespace Trade { diff --git a/src/Trade/AbstractImporter.h b/src/Trade/AbstractImporter.h index 23cef208c..566a9ae46 100644 --- a/src/Trade/AbstractImporter.h +++ b/src/Trade/AbstractImporter.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_AbstractImporter_h #define Magnum_Trade_AbstractImporter_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -20,27 +29,14 @@ */ #include -#include +#include + +#include "Trade/Trade.h" #include "magnumVisibility.h" namespace Magnum { namespace Trade { -class AbstractMaterialData; -class CameraData; -template class ImageData; -class LightData; -class MeshData2D; -class MeshData3D; -class ObjectData2D; -class ObjectData3D; -class SceneData; -class TextureData; - -typedef ImageData<1> ImageData1D; -typedef ImageData<2> ImageData2D; -typedef ImageData<3> ImageData3D; - /** @brief Base for importer plugins @@ -57,7 +53,7 @@ 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::Plugin { +class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::AbstractPlugin { PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImporter/0.2") public: @@ -74,8 +70,11 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { /** @brief Set of features supported by this importer */ typedef Corrade::Containers::EnumSet Features; - /** @brief Constructor */ - inline AbstractImporter(Corrade::PluginManager::AbstractPluginManager* manager = nullptr, const std::string& plugin = ""): Plugin(manager, plugin) {} + /** @brief Default constructor */ + inline explicit AbstractImporter() = default; + + /** @brief Plugin manager constructor */ + inline explicit AbstractImporter(Corrade::PluginManager::AbstractPluginManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)) {} /** @brief Features supported by this importer */ virtual Features features() const = 0; @@ -118,18 +117,26 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * @note The function is not const, because the value will probably * be lazy-populated. */ - virtual inline std::int32_t defaultScene() { return -1; } + virtual inline Int defaultScene() { return -1; } /** @brief %Scene count */ - virtual inline std::uint32_t sceneCount() const { return 0; } + virtual inline UnsignedInt sceneCount() const { return 0; } /** * @brief %Scene ID for given name * * If no scene for given name exists, returns -1. - * @see SceneData::name() + * @see sceneName() */ - virtual std::int32_t sceneForName(const std::string& name); + virtual Int sceneForName(const std::string& name); + + /** + * @brief %Scene name + * @param id %Scene ID, from range [0, sceneCount()). + * + * @see sceneForName() + */ + virtual std::string sceneName(UnsignedInt id); /** * @brief %Scene @@ -137,18 +144,26 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * * Returns pointer to given scene or nullptr, if no such scene exists. */ - virtual SceneData* scene(std::uint32_t id); + virtual SceneData* scene(UnsignedInt id); /** @brief %Light count */ - virtual inline std::uint32_t lightCount() const { return 0; } + virtual inline UnsignedInt lightCount() const { return 0; } /** * @brief %Light ID for given name * * If no light for given name exists, returns -1. - * @see LightData::name() + * @see lightName() + */ + virtual Int lightForName(const std::string& name); + + /** + * @brief %Light name + * @param id %Light ID, from range [0, lightCount()). + * + * @see lightForName() */ - virtual std::int32_t lightForName(const std::string& name); + virtual std::string lightName(UnsignedInt id); /** * @brief %Light @@ -156,116 +171,164 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * * Returns pointer to given light or nullptr, if no such light exists. */ - virtual LightData* light(std::uint32_t id); + virtual LightData* light(UnsignedInt id); - /** @brief %Camera count */ - virtual inline std::uint32_t cameraCount() const { return 0; } + /** @brief Camera count */ + virtual inline UnsignedInt cameraCount() const { return 0; } /** - * @brief %Camera ID for given name + * @brief Camera ID for given name * * If no camera for given name exists, returns -1. - * @see CameraData::name() + * @see cameraName() */ - virtual std::int32_t cameraForName(const std::string& name); + virtual Int cameraForName(const std::string& name); /** - * @brief %Camera - * @param id %Camera ID, from range [0, cameraCount()). + * @brief Camera name + * @param id Camera ID, from range [0, cameraCount()). + * + * @see cameraForName() + */ + virtual std::string cameraName(UnsignedInt id); + + /** + * @brief Camera + * @param id Camera ID, from range [0, cameraCount()). * * Returns pointer to given camera or nullptr, if no such camera * exists. */ - virtual CameraData* camera(std::uint32_t id); + virtual CameraData* camera(UnsignedInt id); /** @brief Two-dimensional object count */ - virtual inline std::uint32_t object2DCount() const { return 0; } + virtual inline UnsignedInt object2DCount() const { return 0; } /** * @brief Two-dimensional object ID for given name * * If no scene for given name exists, returns -1. - * @see ObjectData2D::name() + * @see object2DName() + */ + virtual Int object2DForName(const std::string& name); + + /** + * @brief Two-dimensional object name + * @param id Object ID, from range [0, object2DCount()). + * + * @see object2DForName() */ - virtual std::int32_t object2DForName(const std::string& name); + virtual std::string object2DName(UnsignedInt id); /** * @brief Two-dimensional object - * @param id %Object ID, from range [0, object2DCount()). + * @param id Object ID, from range [0, object2DCount()). * * Returns pointer to given object or nullptr, if no such object * exists. */ - virtual ObjectData2D* object2D(std::uint32_t id); + virtual ObjectData2D* object2D(UnsignedInt id); /** @brief Three-dimensional object count */ - virtual inline std::uint32_t object3DCount() const { return 0; } + virtual inline UnsignedInt object3DCount() const { return 0; } /** * @brief Three-dimensional object ID for given name * * If no scene for given name exists, returns -1. - * @see ObjectData3D::name() + * @see object3DName() */ - virtual std::int32_t object3DForName(const std::string& name); + virtual Int object3DForName(const std::string& name); + + /** + * @brief Three-dimensional object name + * @param id Object ID, from range [0, object3DCount()). + * + * @see object3DForName() + */ + virtual std::string object3DName(UnsignedInt id); /** * @brief Three-dimensional object - * @param id %Object ID, from range [0, object3DCount()). + * @param id Object ID, from range [0, object3DCount()). * * Returns pointer to given object or nullptr, if no such object * exists. */ - virtual ObjectData3D* object3D(std::uint32_t id); + virtual ObjectData3D* object3D(UnsignedInt id); /** @brief Two-dimensional mesh count */ - virtual inline std::uint32_t mesh2DCount() const { return 0; } + virtual inline UnsignedInt mesh2DCount() const { return 0; } /** * @brief Two-dimensional mesh ID for given name * * If no mesh for given name exists, returns -1. - * @see MeshData2D::name() + * @see mesh2DName() + */ + virtual Int mesh2DForName(const std::string& name); + + /** + * @brief Two-dimensional mesh name + * @param id %Mesh ID, from range [0, mesh2DCount()). + * + * @see mesh2DForName() */ - virtual std::int32_t mesh2DForName(const std::string& name); + virtual std::string mesh2DName(UnsignedInt id); /** * @brief Two-dimensional mesh - * @param id %Mesh ID, from range [0, meshCount()). + * @param id %Mesh ID, from range [0, mesh2DCount()). * * Returns pointer to given mesh or nullptr, if no such mesh exists. */ - virtual MeshData2D* mesh2D(std::uint32_t id); + virtual MeshData2D* mesh2D(UnsignedInt id); /** @brief Three-dimensional mesh count */ - virtual inline std::uint32_t mesh3DCount() const { return 0; } + virtual inline UnsignedInt mesh3DCount() const { return 0; } /** * @brief Three-dimensional mesh ID for given name * * If no mesh for given name exists, returns -1. - * @see MeshData3D::name() + * @see mesh3DName() + */ + virtual Int mesh3DForName(const std::string& name); + + /** + * @brief Three-dimensional mesh name + * @param id %Mesh ID, from range [0, mesh3DCount()). + * + * @see mesh3DForName() */ - virtual std::int32_t mesh3DForName(const std::string& name); + virtual std::string mesh3DName(UnsignedInt id); /** * @brief Three-dimensional mesh - * @param id %Mesh ID, from range [0, meshCount()). + * @param id %Mesh ID, from range [0, mesh3DCount()). * * Returns pointer to given mesh or nullptr, if no such mesh exists. */ - virtual MeshData3D* mesh3D(std::uint32_t id); + virtual MeshData3D* mesh3D(UnsignedInt id); /** @brief Material count */ - virtual inline std::uint32_t materialCount() const { return 0; } + virtual inline UnsignedInt materialCount() const { return 0; } /** * @brief Material ID for given name * * If no material for given name exists, returns -1. - * @see AbstractMaterialData::name() + * @see materialName() */ - virtual std::int32_t materialForName(const std::string& name); + virtual Int materialForName(const std::string& name); + + /** + * @brief Material name + * @param id Material ID, from range [0, materialCount()). + * + * @see materialForName() + */ + virtual std::string materialName(UnsignedInt id); /** * @brief Material @@ -274,18 +337,26 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * Returns pointer to given material or nullptr, if no such material * exists. */ - virtual AbstractMaterialData* material(std::uint32_t id); + virtual AbstractMaterialData* material(UnsignedInt id); /** @brief %Texture count */ - virtual inline std::uint32_t textureCount() const { return 0; } + virtual inline UnsignedInt textureCount() const { return 0; } /** * @brief %Texture ID for given name * * If no texture for given name exists, returns -1. - * @see TextureData::name() + * @see textureName() + */ + virtual Int textureForName(const std::string& name); + + /** + * @brief %Texture name + * @param id %Texture ID, from range [0, textureCount()). + * + * @see textureForName() */ - virtual std::int32_t textureForName(const std::string& name); + virtual std::string textureName(UnsignedInt id); /** * @brief %Texture @@ -294,18 +365,26 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * Returns pointer to given texture or nullptr, if no such texture * exists. */ - virtual TextureData* texture(std::uint32_t id); + virtual TextureData* texture(UnsignedInt id); /** @brief One-dimensional image count */ - virtual inline std::uint32_t image1DCount() const { return 0; } + virtual inline UnsignedInt image1DCount() const { return 0; } /** * @brief One-dimensional image ID for given name * * If no image for given name exists, returns -1. - * @see ImageData1D::name() + * @see image1Dname() */ - virtual std::int32_t image1DForName(const std::string& name); + virtual Int image1DForName(const std::string& name); + + /** + * @brief One-dimensional image name + * @param id %Image ID, from range [0, image1DCount()). + * + * @see image1DForName() + */ + virtual std::string image1DName(UnsignedInt id); /** * @brief One-dimensional image @@ -313,18 +392,26 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * * Returns pointer to given image or nullptr, if no such image exists. */ - virtual ImageData1D* image1D(std::uint32_t id); + virtual ImageData1D* image1D(UnsignedInt id); /** @brief Two-dimensional image count */ - virtual inline std::uint32_t image2DCount() const { return 0; } + virtual inline UnsignedInt image2DCount() const { return 0; } /** * @brief Two-dimensional image ID for given name * * If no image for given name exists, returns -1. - * @see ImageData2D::name() + * @see image2DName() */ - virtual std::int32_t image2DForName(const std::string& name); + virtual Int image2DForName(const std::string& name); + + /** + * @brief Two-dimensional image name + * @param id %Image ID, from range [0, image2DCount()). + * + * @see image2DForName() + */ + virtual std::string image2DName(UnsignedInt id); /** * @brief Two-dimensional image @@ -332,18 +419,26 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * * Returns pointer to given image or nullptr, if no such image exists. */ - virtual ImageData2D* image2D(std::uint32_t id); + virtual ImageData2D* image2D(UnsignedInt id); /** @brief Three-dimensional image count */ - virtual inline std::uint32_t image3DCount() const { return 0; } + virtual inline UnsignedInt image3DCount() const { return 0; } /** * @brief Three-dimensional image ID for given name * * If no image for given name exists, returns -1. - * @see ImageData3D::name() + * @see image3DName() + */ + virtual Int image3DForName(const std::string& name); + + /** + * @brief Three-dimensional image name + * @param id %Image ID, from range [0, image3DCount()). + * + * @see image3DForName() */ - virtual std::int32_t image3DForName(const std::string& name); + virtual std::string image3DName(UnsignedInt id); /** * @brief Three-dimensional image @@ -351,7 +446,7 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { * * Returns pointer to given image or nullptr, if no such image exists. */ - virtual ImageData3D* image3D(std::uint32_t id); + virtual ImageData3D* image3D(UnsignedInt id); /*@}*/ }; @@ -359,30 +454,42 @@ class MAGNUM_EXPORT AbstractImporter: public Corrade::PluginManager::Plugin { CORRADE_ENUMSET_OPERATORS(AbstractImporter::Features) /* Implementations for inline functions with unused parameters */ -inline std::int32_t AbstractImporter::sceneForName(const std::string&) { return -1; } -inline SceneData* AbstractImporter::scene(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::lightForName(const std::string&) { return -1; } -inline LightData* AbstractImporter::light(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::cameraForName(const std::string&) { return -1; } -inline CameraData* AbstractImporter::camera(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::object2DForName(const std::string&) { return -1; } -inline ObjectData2D* AbstractImporter::object2D(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::object3DForName(const std::string&) { return -1; } -inline ObjectData3D* AbstractImporter::object3D(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::mesh2DForName(const std::string&) { return -1; } -inline MeshData2D* AbstractImporter::mesh2D(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::mesh3DForName(const std::string&) { return -1; } -inline MeshData3D* AbstractImporter::mesh3D(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::materialForName(const std::string&) { return -1; } -inline AbstractMaterialData* AbstractImporter::material(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::textureForName(const std::string&) { return -1; } -inline TextureData* AbstractImporter::texture(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::image1DForName(const std::string&) { return -1; } -inline ImageData1D* AbstractImporter::image1D(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::image2DForName(const std::string&) { return -1; } -inline ImageData2D* AbstractImporter::image2D(std::uint32_t) { return nullptr; } -inline std::int32_t AbstractImporter::image3DForName(const std::string&) { return -1; } -inline ImageData3D* AbstractImporter::image3D(std::uint32_t) { return nullptr; } +inline Int AbstractImporter::sceneForName(const std::string&) { return -1; } +inline std::string AbstractImporter::sceneName(UnsignedInt) { return {}; } +inline SceneData* AbstractImporter::scene(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::lightForName(const std::string&) { return -1; } +inline std::string AbstractImporter::lightName(UnsignedInt) { return {}; } +inline LightData* AbstractImporter::light(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::cameraForName(const std::string&) { return -1; } +inline std::string AbstractImporter::cameraName(UnsignedInt) { return {}; } +inline CameraData* AbstractImporter::camera(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::object2DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::object2DName(UnsignedInt) { return {}; } +inline ObjectData2D* AbstractImporter::object2D(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::object3DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::object3DName(UnsignedInt) { return {}; } +inline ObjectData3D* AbstractImporter::object3D(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::mesh2DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::mesh2DName(UnsignedInt) { return {}; } +inline MeshData2D* AbstractImporter::mesh2D(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::mesh3DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::mesh3DName(UnsignedInt) { return {}; } +inline MeshData3D* AbstractImporter::mesh3D(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::materialForName(const std::string&) { return -1; } +inline std::string AbstractImporter::materialName(UnsignedInt) { return {}; } +inline AbstractMaterialData* AbstractImporter::material(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::textureForName(const std::string&) { return -1; } +inline std::string AbstractImporter::textureName(UnsignedInt) { return {}; } +inline TextureData* AbstractImporter::texture(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::image1DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::image1DName(UnsignedInt) { return {}; } +inline ImageData1D* AbstractImporter::image1D(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::image2DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::image2DName(UnsignedInt) { return {}; } +inline ImageData2D* AbstractImporter::image2D(UnsignedInt) { return nullptr; } +inline Int AbstractImporter::image3DForName(const std::string&) { return -1; } +inline std::string AbstractImporter::image3DName(UnsignedInt) { return {}; } +inline ImageData3D* AbstractImporter::image3D(UnsignedInt) { return nullptr; } }} diff --git a/src/Trade/AbstractMaterialData.h b/src/Trade/AbstractMaterialData.h index 0e0b17c69..311644a1e 100644 --- a/src/Trade/AbstractMaterialData.h +++ b/src/Trade/AbstractMaterialData.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_AbstractMaterialData_h #define Magnum_Trade_AbstractMaterialData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -42,22 +51,17 @@ class AbstractMaterialData { /** * @brief Constructor - * @param name Material name * @param type Material type */ - inline AbstractMaterialData(const std::string& name, Type type): _name(name), _type(type) {} + inline AbstractMaterialData(Type type): _type(type) {} /** @brief Destructor */ virtual ~AbstractMaterialData() = 0; - /** @brief Material name */ - inline std::string name() const { return _name; } - /** @brief Material type */ inline Type type() const { return _type; } private: - std::string _name; Type _type; }; diff --git a/src/Trade/CMakeLists.txt b/src/Trade/CMakeLists.txt index 12b1fd60d..3e541fe28 100644 --- a/src/Trade/CMakeLists.txt +++ b/src/Trade/CMakeLists.txt @@ -1,3 +1,27 @@ +# +# 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. +# + set(MagnumTrade_HEADERS AbstractImporter.h AbstractMaterialData.h @@ -12,5 +36,11 @@ set(MagnumTrade_HEADERS ObjectData3D.h PhongMaterialData.h SceneData.h - TextureData.h) + TextureData.h + Trade.h) + install(FILES ${MagnumTrade_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Trade) + +if(BUILD_TESTS) + add_subdirectory(Test) +endif() diff --git a/src/Trade/CameraData.h b/src/Trade/CameraData.h index 914832e4d..a8bfad918 100644 --- a/src/Trade/CameraData.h +++ b/src/Trade/CameraData.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_CameraData_h #define Magnum_Trade_CameraData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -31,19 +40,6 @@ class MAGNUM_EXPORT CameraData { CameraData(CameraData&& other) = delete; CameraData& operator=(const CameraData& other) = delete; CameraData& operator=(CameraData&& other) = delete; - - public: - /** - * @brief Constructor - * @param name %Camera name - */ - inline CameraData(const std::string& name): _name(name) {} - - /** @brief %Camera name */ - inline std::string name() const { return _name; } - - private: - std::string _name; }; }} diff --git a/src/Trade/ImageData.h b/src/Trade/ImageData.h index cb6ca2690..fbe6d8c4c 100644 --- a/src/Trade/ImageData.h +++ b/src/Trade/ImageData.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_ImageData_h #define Magnum_Trade_ImageData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,62 +31,44 @@ #include "Math/Vector3.h" #include "AbstractImage.h" #include "DimensionTraits.h" -#include "TypeTraits.h" namespace Magnum { namespace Trade { /** @brief %Image data -Provides access to image data and additional information about data type and -dimensions. Can be used in the same situations as Image and BufferedImage. +Access to image data provided by AbstractImporter subclasses. Interchangeable +with Image, ImageWrapper or BufferImage. +@see ImageData1D, ImageData2D, ImageData3D */ -template class ImageData: public AbstractImage { +template class ImageData: public AbstractImage { public: - const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */ - - /** - * @brief Constructor - * @param name %Image name - * @param size %Image size - * @param components Color components. Data type is detected - * from passed data array. - * @param data %Image data - * - * Note that the image data are not copied on construction, but they - * are deleted on class destruction. - */ - template inline ImageData(const std::string& name, const typename DimensionTraits::VectorType& size, Components components, T* data): AbstractImage(components, TypeTraits::imageType()), _name(name), _size(size), _data(reinterpret_cast(data)) {} + const static UnsignedInt Dimensions = dimensions; /**< @brief %Image dimension count */ /** * @brief Constructor - * @param name %Image name * @param size %Image size - * @param components Color components - * @param type Data type + * @param format Format of pixel data + * @param type Data type of pixel data * @param data %Image data * * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - inline ImageData(const std::string& name, const typename DimensionTraits::VectorType& size, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _name(name), _size(size), _data(reinterpret_cast(data)) {} + inline ImageData(const typename DimensionTraits::VectorType& size, Format format, Type type, GLvoid* data): AbstractImage(format, type), _size(size), _data(reinterpret_cast(data)) {} /** @brief Destructor */ inline ~ImageData() { delete[] _data; } - /** @brief %Image name */ - inline std::string name() const { return _name; } - /** @brief %Image size */ - inline typename DimensionTraits::VectorType size() const { return _size; } + inline typename DimensionTraits::VectorType size() const { return _size; } /** @brief Pointer to raw data */ inline void* data() { return _data; } inline const void* data() const { return _data; } /**< @overload */ private: - std::string _name; - Math::Vector _size; + Math::Vector _size; char* _data; }; diff --git a/src/Trade/LightData.h b/src/Trade/LightData.h index 824dde363..b06e16773 100644 --- a/src/Trade/LightData.h +++ b/src/Trade/LightData.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_LightData_h #define Magnum_Trade_LightData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -31,19 +40,6 @@ class MAGNUM_EXPORT LightData { LightData(LightData&& other) = delete; LightData& operator=(const LightData& other) = delete; LightData& operator=(LightData&& other) = delete; - - public: - /** - * @brief Constructor - * @param name %Light name - */ - inline LightData(const std::string& name): _name(name) {} - - /** @brief %Light name */ - inline std::string name() const { return _name; } - - private: - std::string _name; }; }} diff --git a/src/Trade/MeshData2D.cpp b/src/Trade/MeshData2D.cpp index 67ff19c51..9d2f218d7 100644 --- a/src/Trade/MeshData2D.cpp +++ b/src/Trade/MeshData2D.cpp @@ -1,20 +1,31 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "MeshData2D.h" +#include "Math/Vector2.h" + namespace Magnum { namespace Trade { MeshData2D::~MeshData2D() { diff --git a/src/Trade/MeshData2D.h b/src/Trade/MeshData2D.h index 4e812f136..4c52fa326 100644 --- a/src/Trade/MeshData2D.h +++ b/src/Trade/MeshData2D.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_MeshData2D_h #define Magnum_Trade_MeshData2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,7 +30,6 @@ #include -#include "Math/Point2D.h" #include "Mesh.h" namespace Magnum { namespace Trade { @@ -35,14 +43,11 @@ type. */ class MAGNUM_EXPORT MeshData2D { MeshData2D(const MeshData2D& other) = delete; - MeshData2D(MeshData2D&& other) = delete; MeshData2D& operator=(const MeshData2D& other) = delete; - MeshData2D& operator=(MeshData2D&& other) = delete; public: /** * @brief Constructor - * @param name %Mesh name * @param primitive Primitive * @param indices Array with indices or 0, if this is not * indexed mesh @@ -51,13 +56,16 @@ class MAGNUM_EXPORT MeshData2D { * @param textureCoords2D Array with two-dimensional texture * coordinate arrays or empty array */ - inline MeshData2D(const std::string& name, Mesh::Primitive primitive, std::vector* indices, std::vector*> positions, std::vector*> textureCoords2D): _name(name), _primitive(primitive), _indices(indices), _positions(positions), _textureCoords2D(textureCoords2D) {} + inline MeshData2D(Mesh::Primitive primitive, std::vector* indices, std::vector*> positions, std::vector*> textureCoords2D): _primitive(primitive), _indices(indices), _positions(positions), _textureCoords2D(textureCoords2D) {} + + /** @brief Move constructor */ + MeshData2D(MeshData2D&&) = default; /** @brief Destructor */ ~MeshData2D(); - /** @brief %Mesh name */ - inline std::string name() const { return _name; } + /** @brief Move assignment */ + MeshData2D& operator=(MeshData2D&&) = default; /** @brief Primitive */ inline Mesh::Primitive primitive() const { return _primitive; } @@ -66,11 +74,11 @@ class MAGNUM_EXPORT MeshData2D { * @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 */ + inline std::vector* indices() { return _indices; } + inline const std::vector* indices() const { return _indices; } /**< @overload */ /** @brief Count of vertex position arrays */ - inline std::uint32_t positionArrayCount() const { return _positions.size(); } + inline UnsignedInt positionArrayCount() const { return _positions.size(); } /** * @brief Positions @@ -78,11 +86,11 @@ class MAGNUM_EXPORT MeshData2D { * @return Positions or nullptr if there is no vertex array with given * ID. */ - inline std::vector* positions(std::uint32_t id) { return _positions[id]; } - inline const std::vector* positions(std::uint32_t id) const { return _positions[id]; } /**< @overload */ + inline std::vector* positions(UnsignedInt id) { return _positions[id]; } + inline const std::vector* positions(UnsignedInt id) const { return _positions[id]; } /**< @overload */ /** @brief Count of 2D texture coordinate arrays */ - inline std::uint32_t textureCoords2DArrayCount() const { return _textureCoords2D.size(); } + inline UnsignedInt textureCoords2DArrayCount() const { return _textureCoords2D.size(); } /** * @brief 2D texture coordinates @@ -90,14 +98,13 @@ class MAGNUM_EXPORT MeshData2D { * @return %Texture coordinates or nullptr if there is no texture * coordinates array with given ID. */ - inline std::vector* textureCoords2D(std::uint32_t id) { return _textureCoords2D[id]; } - inline const std::vector* textureCoords2D(std::uint32_t id) const { return _textureCoords2D[id]; } /**< @overload */ + inline std::vector* textureCoords2D(UnsignedInt id) { return _textureCoords2D[id]; } + inline const std::vector* textureCoords2D(UnsignedInt id) const { return _textureCoords2D[id]; } /**< @overload */ private: - std::string _name; Mesh::Primitive _primitive; - std::vector* _indices; - std::vector*> _positions; + std::vector* _indices; + std::vector*> _positions; std::vector*> _textureCoords2D; }; diff --git a/src/Trade/MeshData3D.cpp b/src/Trade/MeshData3D.cpp index 8dd8ab10c..c78c6a755 100644 --- a/src/Trade/MeshData3D.cpp +++ b/src/Trade/MeshData3D.cpp @@ -1,20 +1,31 @@ /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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: - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 "MeshData3D.h" +#include "Math/Vector3.h" + namespace Magnum { namespace Trade { MeshData3D::~MeshData3D() { diff --git a/src/Trade/MeshData3D.h b/src/Trade/MeshData3D.h index 1de247976..0a41f02d6 100644 --- a/src/Trade/MeshData3D.h +++ b/src/Trade/MeshData3D.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_MeshData3D_h #define Magnum_Trade_MeshData3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -21,7 +30,6 @@ #include -#include "Math/Point3D.h" #include "Mesh.h" namespace Magnum { namespace Trade { @@ -35,14 +43,11 @@ type. */ class MAGNUM_EXPORT MeshData3D { MeshData3D(const MeshData3D& other) = delete; - MeshData3D(MeshData3D&& other) = delete; MeshData3D& operator=(const MeshData3D& other) = delete; - MeshData3D& operator=(MeshData3D&& other) = delete; public: /** * @brief Constructor - * @param name %Mesh name * @param primitive Primitive * @param indices Array with indices or 0, if this is not * indexed mesh @@ -52,13 +57,16 @@ class MAGNUM_EXPORT MeshData3D { * @param textureCoords2D Array with two-dimensional texture * coordinate arrays or empty array */ - inline MeshData3D(const std::string& name, Mesh::Primitive primitive, std::vector* indices, std::vector*> positions, std::vector*> normals, std::vector*> textureCoords2D): _name(name), _primitive(primitive), _indices(indices), _positions(positions), _normals(normals), _textureCoords2D(textureCoords2D) {} + inline MeshData3D(Mesh::Primitive primitive, std::vector* indices, std::vector*> positions, std::vector*> normals, std::vector*> textureCoords2D): _primitive(primitive), _indices(indices), _positions(positions), _normals(normals), _textureCoords2D(textureCoords2D) {} + + /** @brief Move constructor */ + MeshData3D(MeshData3D&&) = default; /** @brief Destructor */ ~MeshData3D(); - /** @brief %Mesh name */ - inline std::string name() const { return _name; } + /** @brief Move assignment */ + MeshData3D& operator=(MeshData3D&&) = default; /** @brief Primitive */ inline Mesh::Primitive primitive() const { return _primitive; } @@ -67,11 +75,11 @@ class MAGNUM_EXPORT MeshData3D { * @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 */ + inline std::vector* indices() { return _indices; } + inline const std::vector* indices() const { return _indices; } /**< @overload */ /** @brief Count of vertex position arrays */ - inline std::uint32_t positionArrayCount() const { return _positions.size(); } + inline UnsignedInt positionArrayCount() const { return _positions.size(); } /** * @brief Positions @@ -79,11 +87,11 @@ class MAGNUM_EXPORT MeshData3D { * @return Positions or nullptr if there is no vertex array with given * ID. */ - inline std::vector* positions(std::uint32_t id) { return _positions[id]; } - inline const std::vector* positions(std::uint32_t id) const { return _positions[id]; } /**< @overload */ + inline std::vector* positions(UnsignedInt id) { return _positions[id]; } + inline const std::vector* positions(UnsignedInt id) const { return _positions[id]; } /**< @overload */ /** @brief Count of normal arrays */ - inline std::uint32_t normalArrayCount() const { return _normals.size(); } + inline UnsignedInt normalArrayCount() const { return _normals.size(); } /** * @brief Normals @@ -91,11 +99,11 @@ class MAGNUM_EXPORT MeshData3D { * @return Normals or nullptr if there is no normal array with given * ID. */ - inline std::vector* normals(std::uint32_t id) { return _normals[id]; } - inline const std::vector* normals(std::uint32_t id) const { return _normals[id]; } /**< @overload */ + inline std::vector* normals(UnsignedInt id) { return _normals[id]; } + inline const std::vector* normals(UnsignedInt id) const { return _normals[id]; } /**< @overload */ /** @brief Count of 2D texture coordinate arrays */ - inline std::uint32_t textureCoords2DArrayCount() const { return _textureCoords2D.size(); } + inline UnsignedInt textureCoords2DArrayCount() const { return _textureCoords2D.size(); } /** * @brief 2D texture coordinates @@ -103,14 +111,13 @@ class MAGNUM_EXPORT MeshData3D { * @return %Texture coordinates or nullptr if there is no texture * coordinates array with given ID. */ - inline std::vector* textureCoords2D(std::uint32_t id) { return _textureCoords2D[id]; } - inline const std::vector* textureCoords2D(std::uint32_t id) const { return _textureCoords2D[id]; } /**< @overload */ + inline std::vector* textureCoords2D(UnsignedInt id) { return _textureCoords2D[id]; } + inline const std::vector* textureCoords2D(UnsignedInt id) const { return _textureCoords2D[id]; } /**< @overload */ private: - std::string _name; Mesh::Primitive _primitive; - std::vector* _indices; - std::vector*> _positions; + std::vector* _indices; + std::vector*> _positions; std::vector*> _normals; std::vector*> _textureCoords2D; }; diff --git a/src/Trade/MeshObjectData2D.h b/src/Trade/MeshObjectData2D.h index dff0770b0..e144880c9 100644 --- a/src/Trade/MeshObjectData2D.h +++ b/src/Trade/MeshObjectData2D.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_MeshObjectData2D_h #define Magnum_Trade_MeshObjectData2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -38,7 +47,6 @@ class MeshObjectData2D: public ObjectData2D { public: /** * @brief Constructor - * @param name %Mesh object name * @param children Child objects * @param transformation Transformation (relative to parent) * @param instance Instance ID @@ -46,13 +54,13 @@ class MeshObjectData2D: public ObjectData2D { * * Creates object with mesh instance type. */ - inline MeshObjectData2D(const std::string& name, const std::vector& children, const Matrix4& transformation, std::uint32_t instance, std::uint32_t material): ObjectData2D(name, children, transformation, InstanceType::Mesh, instance), _material(material) {} + inline MeshObjectData2D(const std::vector& children, const Matrix4& transformation, UnsignedInt instance, UnsignedInt material): ObjectData2D(children, transformation, InstanceType::Mesh, instance), _material(material) {} /** @brief Material ID */ - inline std::uint32_t material() const { return _material; } + inline UnsignedInt material() const { return _material; } private: - std::uint32_t _material; + UnsignedInt _material; }; }} diff --git a/src/Trade/MeshObjectData3D.h b/src/Trade/MeshObjectData3D.h index acec3ed31..348b3f4a4 100644 --- a/src/Trade/MeshObjectData3D.h +++ b/src/Trade/MeshObjectData3D.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_MeshObjectData3D_h #define Magnum_Trade_MeshObjectData3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -38,7 +47,6 @@ class MeshObjectData3D: public ObjectData3D { public: /** * @brief Constructor - * @param name %Mesh object name * @param children Child objects * @param transformation Transformation (relative to parent) * @param instance Instance ID @@ -46,13 +54,13 @@ class MeshObjectData3D: public ObjectData3D { * * Creates object with mesh instance type. */ - inline MeshObjectData3D(const std::string& name, const std::vector& children, const Matrix4& transformation, std::uint32_t instance, std::uint32_t material): ObjectData3D(name, children, transformation, InstanceType::Mesh, instance), _material(material) {} + inline MeshObjectData3D(const std::vector& children, const Matrix4& transformation, UnsignedInt instance, UnsignedInt material): ObjectData3D(children, transformation, InstanceType::Mesh, instance), _material(material) {} /** @brief Material ID */ - inline std::uint32_t material() const { return _material; } + inline UnsignedInt material() const { return _material; } private: - std::uint32_t _material; + UnsignedInt _material; }; }} diff --git a/src/Trade/ObjectData2D.cpp b/src/Trade/ObjectData2D.cpp new file mode 100644 index 000000000..4c44c12f6 --- /dev/null +++ b/src/Trade/ObjectData2D.cpp @@ -0,0 +1,43 @@ +/* + 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 "ObjectData2D.h" + +namespace Magnum { namespace Trade { + +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, ObjectData2D::InstanceType value) { + switch(value) { + #define _c(value) case ObjectData2D::InstanceType::value: return debug << "Trade::ObjectData2D::InstanceType::" #value; + _c(Camera) + _c(Mesh) + _c(Empty) + #undef _c + } + + return debug << "ObjectData2D::InstanceType::(invalid)"; +} +#endif + +}} diff --git a/src/Trade/ObjectData2D.h b/src/Trade/ObjectData2D.h index 8cc1b9226..7e934486b 100644 --- a/src/Trade/ObjectData2D.h +++ b/src/Trade/ObjectData2D.h @@ -1,25 +1,36 @@ #ifndef Magnum_Trade_ObjectData2D_h #define Magnum_Trade_ObjectData2D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Trade::ObjectData2D */ -#include "Math/Matrix4.h" +#include + +#include "Math/Matrix3.h" #include "Magnum.h" namespace Magnum { namespace Trade { @@ -47,30 +58,25 @@ class ObjectData2D { /** * @brief Constructor - * @param name Object name * @param children Child objects * @param transformation Transformation (relative to parent) * @param instanceType Instance type * @param instanceId Instance ID */ - inline ObjectData2D(const std::string& name, const std::vector& children, const Matrix3& transformation, InstanceType instanceType, std::uint32_t instanceId): _name(name), _children(children), _transformation(transformation), _instanceType(instanceType), _instanceId(instanceId) {} + inline ObjectData2D(const std::vector& children, const Matrix3& transformation, InstanceType instanceType, UnsignedInt instanceId): _children(children), _transformation(transformation), _instanceType(instanceType), _instanceId(instanceId) {} /** * @brief Constructor for empty instance - * @param name Object name * @param children Child objects * @param transformation Transformation (relative to parent) */ - inline ObjectData2D(const std::string& name, const std::vector& children, const Matrix3& transformation): _name(name), _children(children), _transformation(transformation), _instanceType(InstanceType::Empty), _instanceId(-1) {} + inline ObjectData2D(const std::vector& children, const Matrix3& transformation): _children(children), _transformation(transformation), _instanceType(InstanceType::Empty), _instanceId(-1) {} /** @brief Destructor */ inline virtual ~ObjectData2D() {} - /** @brief %Object name */ - inline std::string name() const { return _name; } - /** @brief Child objects */ - inline std::vector& children() { return _children; } + inline std::vector& children() { return _children; } /** @brief Transformation (relative to parent) */ inline Matrix3 transformation() const { return _transformation; } @@ -89,16 +95,18 @@ class ObjectData2D { * @return ID of given camera / light / mesh etc., specified by * instanceType() */ - inline std::int32_t instanceId() const { return _instanceId; } + inline Int instanceId() const { return _instanceId; } private: - std::string _name; - std::vector _children; + std::vector _children; Matrix3 _transformation; InstanceType _instanceType; - std::int32_t _instanceId; + Int _instanceId; }; +/** @debugoperator{Magnum::Trade::ObjectData2D} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, ObjectData2D::InstanceType value); + }} #endif diff --git a/src/Trade/ObjectData3D.cpp b/src/Trade/ObjectData3D.cpp new file mode 100644 index 000000000..b021b4305 --- /dev/null +++ b/src/Trade/ObjectData3D.cpp @@ -0,0 +1,44 @@ +/* + 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 "ObjectData3D.h" + +namespace Magnum { namespace Trade { + +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, ObjectData3D::InstanceType value) { + switch(value) { + #define _c(value) case ObjectData3D::InstanceType::value: return debug << "Trade::ObjectData3D::InstanceType::" #value; + _c(Camera) + _c(Light) + _c(Mesh) + _c(Empty) + #undef _c + } + + return debug << "ObjectData3D::InstanceType::(invalid)"; +} +#endif + +}} diff --git a/src/Trade/ObjectData3D.h b/src/Trade/ObjectData3D.h index 0f125b672..c1ff82db4 100644 --- a/src/Trade/ObjectData3D.h +++ b/src/Trade/ObjectData3D.h @@ -1,24 +1,35 @@ #ifndef Magnum_Trade_ObjectData3D_h #define Magnum_Trade_ObjectData3D_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Trade::ObjectData3D */ +#include + #include "Math/Matrix4.h" #include "Magnum.h" @@ -48,30 +59,25 @@ class ObjectData3D { /** * @brief Constructor - * @param name Object name * @param children Child objects * @param transformation Transformation (relative to parent) * @param instanceType Instance type * @param instanceId Instance ID */ - inline ObjectData3D(const std::string& name, const std::vector& children, const Matrix4& transformation, InstanceType instanceType, std::uint32_t instanceId): _name(name), _children(children), _transformation(transformation), _instanceType(instanceType), _instanceId(instanceId) {} + inline ObjectData3D(const std::vector& children, const Matrix4& transformation, InstanceType instanceType, UnsignedInt instanceId): _children(children), _transformation(transformation), _instanceType(instanceType), _instanceId(instanceId) {} /** * @brief Constructor for empty instance - * @param name Object name * @param children Child objects * @param transformation Transformation (relative to parent) */ - inline ObjectData3D(const std::string& name, const std::vector& children, const Matrix4& transformation): _name(name), _children(children), _transformation(transformation), _instanceType(InstanceType::Empty), _instanceId(-1) {} + inline ObjectData3D(const std::vector& children, const Matrix4& transformation): _children(children), _transformation(transformation), _instanceType(InstanceType::Empty), _instanceId(-1) {} /** @brief Destructor */ inline virtual ~ObjectData3D() {} - /** @brief %Object name */ - inline std::string name() const { return _name; } - /** @brief Child objects */ - inline std::vector& children() { return _children; } + inline std::vector& children() { return _children; } /** @brief Transformation (relative to parent) */ inline Matrix4 transformation() const { return _transformation; } @@ -90,16 +96,18 @@ class ObjectData3D { * @return ID of given camera / light / mesh etc., specified by * instanceType() */ - inline std::int32_t instanceId() const { return _instanceId; } + inline Int instanceId() const { return _instanceId; } private: - std::string _name; - std::vector _children; + std::vector _children; Matrix4 _transformation; InstanceType _instanceType; - std::int32_t _instanceId; + Int _instanceId; }; +/** @debugoperator{Magnum::Trade::ObjectData3D} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, ObjectData3D::InstanceType value); + }} #endif diff --git a/src/Trade/PhongMaterialData.h b/src/Trade/PhongMaterialData.h index 21896cba3..fed9fd310 100644 --- a/src/Trade/PhongMaterialData.h +++ b/src/Trade/PhongMaterialData.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_PhongMaterialData_h #define Magnum_Trade_PhongMaterialData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -32,13 +41,12 @@ class PhongMaterialData: public AbstractMaterialData { public: /** * @brief Constructor - * @param name Material name * @param ambientColor Ambient color * @param diffuseColor Diffuse color * @param specularColor Specular color * @param shininess Shininess */ - PhongMaterialData(const std::string& name, const Vector3& ambientColor, const Vector3& diffuseColor, const Vector3& specularColor, GLfloat shininess): AbstractMaterialData(name, Phong), _ambientColor(ambientColor), _diffuseColor(diffuseColor), _specularColor(specularColor), _shininess(shininess) {} + PhongMaterialData(const Vector3& ambientColor, const Vector3& diffuseColor, const Vector3& specularColor, Float shininess): AbstractMaterialData(Phong), _ambientColor(ambientColor), _diffuseColor(diffuseColor), _specularColor(specularColor), _shininess(shininess) {} /** @brief Ambient color */ inline Vector3 ambientColor() const { return _ambientColor; } @@ -50,13 +58,13 @@ class PhongMaterialData: public AbstractMaterialData { inline Vector3 specularColor() const { return _specularColor; } /** @brief Shininess */ - inline GLfloat shininess() const { return _shininess; } + inline Float shininess() const { return _shininess; } private: Vector3 _ambientColor, _diffuseColor, _specularColor; - GLfloat _shininess; + Float _shininess; }; }} diff --git a/src/Trade/SceneData.h b/src/Trade/SceneData.h index 226fa327a..cdf3718b5 100644 --- a/src/Trade/SceneData.h +++ b/src/Trade/SceneData.h @@ -1,18 +1,27 @@ #ifndef Magnum_Trade_SceneData_h #define Magnum_Trade_SceneData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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 @@ -22,6 +31,8 @@ #include #include +#include "Types.h" + namespace Magnum { namespace Trade { /** @@ -36,24 +47,19 @@ class MAGNUM_EXPORT SceneData { public: /** * @brief Constructor - * @param name Scene name * @param children2D Two-dimensional child objects * @param children3D Three-dimensional child objects */ - inline SceneData(const std::string& name, const std::vector& children2D, const std::vector& children3D): _name(name), _children2D(children2D), _children3D(children3D) {} - - /** @brief Scene name */ - inline std::string name() const { return _name; } + inline SceneData(const std::vector& children2D, const std::vector& children3D): _children2D(children2D), _children3D(children3D) {} /** @brief Two-dimensional child objects */ - inline const std::vector& children2D() const { return _children2D; } + inline const std::vector& children2D() const { return _children2D; } /** @brief Three-dimensional child objects */ - inline const std::vector& children3D() const { return _children3D; } + inline const std::vector& children3D() const { return _children3D; } private: - std::string _name; - std::vector _children2D, + std::vector _children2D, _children3D; }; diff --git a/src/Trade/Test/CMakeLists.txt b/src/Trade/Test/CMakeLists.txt new file mode 100644 index 000000000..1581379f4 --- /dev/null +++ b/src/Trade/Test/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# 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. +# + +corrade_add_test(TradeObjectData2DTest ObjectData2DTest.cpp LIBRARIES Magnum) +corrade_add_test(TradeObjectData3DTest ObjectData3DTest.cpp LIBRARIES Magnum) diff --git a/src/Trade/Test/ObjectData2DTest.cpp b/src/Trade/Test/ObjectData2DTest.cpp new file mode 100644 index 000000000..75c377943 --- /dev/null +++ b/src/Trade/Test/ObjectData2DTest.cpp @@ -0,0 +1,51 @@ +/* + 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 "Trade/ObjectData2D.h" + +namespace Magnum { namespace Trade { namespace Test { + +class ObjectData2DTest: public Corrade::TestSuite::Tester { + public: + explicit ObjectData2DTest(); + + void debug(); +}; + +ObjectData2DTest::ObjectData2DTest() { + addTests({&ObjectData2DTest::debug}); +} + +void ObjectData2DTest::debug() { + std::ostringstream o; + Debug(&o) << ObjectData2D::InstanceType::Empty; + CORRADE_COMPARE(o.str(), "Trade::ObjectData2D::InstanceType::Empty\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Trade::Test::ObjectData2DTest) diff --git a/src/Trade/Test/ObjectData3DTest.cpp b/src/Trade/Test/ObjectData3DTest.cpp new file mode 100644 index 000000000..f723262c5 --- /dev/null +++ b/src/Trade/Test/ObjectData3DTest.cpp @@ -0,0 +1,51 @@ +/* + 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 "Trade/ObjectData3D.h" + +namespace Magnum { namespace Trade { namespace Test { + +class ObjectData3DTest: public Corrade::TestSuite::Tester { + public: + explicit ObjectData3DTest(); + + void debug(); +}; + +ObjectData3DTest::ObjectData3DTest() { + addTests({&ObjectData3DTest::debug}); +} + +void ObjectData3DTest::debug() { + std::ostringstream o; + Debug(&o) << ObjectData3D::InstanceType::Light; + CORRADE_COMPARE(o.str(), "Trade::ObjectData3D::InstanceType::Light\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Trade::Test::ObjectData3DTest) diff --git a/src/Trade/TextureData.h b/src/Trade/TextureData.h index d2e9ed825..dd35fc191 100644 --- a/src/Trade/TextureData.h +++ b/src/Trade/TextureData.h @@ -1,26 +1,33 @@ #ifndef Magnum_Trade_TextureData_h #define Magnum_Trade_TextureData_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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::Trade::TextureData */ -#include - namespace Magnum { namespace Trade { /** @@ -31,19 +38,6 @@ class MAGNUM_EXPORT TextureData { TextureData(TextureData&& other) = delete; TextureData& operator=(const TextureData& other) = delete; TextureData& operator=(TextureData&& other) = delete; - - public: - /** - * @brief Constructor - * @param name %Texture name - */ - inline TextureData(const std::string& name): _name(name) {} - - /** @brief %Texture name */ - inline std::string name() const { return _name; } - - private: - std::string _name; }; }} diff --git a/src/Trade/Trade.h b/src/Trade/Trade.h new file mode 100644 index 000000000..37dc2ba1a --- /dev/null +++ b/src/Trade/Trade.h @@ -0,0 +1,60 @@ +#ifndef Magnum_Trade_Trade_h +#define Magnum_Trade_Trade_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 Forward declarations for Magnum::Trade namespace + */ + +#include "Types.h" + +namespace Magnum { namespace Trade { + +/** @todoc Remove `ifndef` when Doxygen is sane again */ +#ifndef DOXYGEN_GENERATING_OUTPUT +class AbstractImporter; +class AbstractMaterialData; +class CameraData; + +template class ImageData; +typedef ImageData<1> ImageData1D; +typedef ImageData<2> ImageData2D; +typedef ImageData<3> ImageData3D; + +class LightData; +class MeshData2D; +class MeshData3D; +class MeshObjectData2D; +class MeshObjectData3D; +class ObjectData2D; +class ObjectData3D; +class PhongMaterialData; +class SceneData; +class TextureData; +#endif + +}} + +#endif diff --git a/src/TypeTraits.cpp b/src/TypeTraits.cpp deleted file mode 100644 index 2d598de4a..000000000 --- a/src/TypeTraits.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -#include "TypeTraits.h" - -#include -#include - -using namespace std; - -namespace Magnum { - -#ifndef DOXYGEN_GENERATING_OUTPUT -static_assert(is_same::value, "GLubyte is not the same as uint8_t"); -static_assert(is_same::value, "GLbyte is not the same as int8_t"); -static_assert(is_same::value, "GLushort is not the same as uint16_t"); -static_assert(is_same::value, "GLshort is not the same as int16_t"); -static_assert(is_same::value, "GLuint is not the same as uint32_t"); -static_assert(is_same::value, "GLint is not the same as int32_t"); -static_assert(is_same::value, "GLfloat is not the same as float"); -#ifndef MAGNUM_TARGET_GLES -static_assert(is_same::value, "GLdouble is not the same as double"); -#endif -#endif - -size_t TypeInfo::sizeOf(Type type) { - switch(type) { - #define val(type) case Type::type: return TypeTraits::Type>::size(); - val(UnsignedByte) - val(Byte) - val(UnsignedShort) - val(Short) - val(UnsignedInt) - val(Int) - #ifndef MAGNUM_TARGET_GLES - val(Double) - #endif - val(Float) - #undef val - - default: return 0; - } -} - -bool TypeInfo::isIntegral(Type type) { - switch(type) { - case Type::UnsignedByte: - case Type::Byte: - case Type::UnsignedShort: - case Type::Short: - case Type::UnsignedInt: - case Type::Int: - return true; - default: - return false; - } -} - -#ifndef DOXYGEN_GENERATING_OUTPUT -Debug operator<<(Debug debug, Type value) { - switch(value) { - #define _c(value) case Type::value: return debug << "Type::" #value; - _c(UnsignedByte) - _c(Byte) - _c(UnsignedShort) - _c(Short) - _c(UnsignedInt) - _c(Int) - _c(Float) - #ifndef MAGNUM_TARGET_GLES - _c(Double) - #endif - #undef _c - } - - return debug << "Type::(invalid)"; -} -#endif - -} - -namespace Corrade { namespace Utility { - -std::string ConfigurationValue::toString(Magnum::Type value, ConfigurationValueFlags) { - switch(value) { - #define _c(value) case Magnum::Type::value: return #value; - _c(UnsignedByte) - _c(Byte) - _c(UnsignedShort) - _c(Short) - _c(UnsignedInt) - _c(Int) - _c(Float) - #ifndef MAGNUM_TARGET_GLES - _c(Double) - #endif - #undef _c - } - - return ""; -} - -Magnum::Type ConfigurationValue::fromString(const std::string& stringValue, ConfigurationValueFlags) { - #define _c(value) if(stringValue == #value) return Magnum::Type::value; - _c(UnsignedByte) - _c(Byte) - _c(UnsignedShort) - _c(Short) - _c(UnsignedInt) - _c(Int) - #ifndef MAGNUM_TARGET_GLES - _c(Double) - #endif - #undef _c - - return Magnum::Type::Float; -} - -}} diff --git a/src/TypeTraits.h b/src/TypeTraits.h deleted file mode 100644 index c6f878e61..000000000 --- a/src/TypeTraits.h +++ /dev/null @@ -1,369 +0,0 @@ -#ifndef Magnum_TypeTraits_h -#define Magnum_TypeTraits_h -/* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - - This file is part of Magnum. - - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. - - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. -*/ - -/** @file /TypeTraits.h - * @brief Enum Magnum::Type, class Magnum::TypeOf, Magnum::TypeInfo, Magnum::TypeTraits - */ - -#include - -#include "Math/MathTypeTraits.h" -#include "AbstractImage.h" - -namespace Magnum { - -namespace Math { - template class RectangularMatrix; - template class Matrix; - template class Vector; -} - -/** -@brief Traits class for plain OpenGL types - -@copydetails Math::MathTypeTraits - -Where it makes sense, this class extends Math::MathTypeTraits with -OpenGL-specific traits. -*/ -#ifdef DOXYGEN_GENERATING_OUTPUT -template struct TypeTraits: Math::MathTypeTraits { - /** - * @brief Corresponding type for vertex attributes - * - * Implemented only in types which can be used for vertex attributes. This - * function is not present for types unusable for vertex attributes, like - * five-component vectors or GLdouble in OpenGL ES. See also - * @ref AbstractShaderProgram-types. - */ - typedef U AttributeType; - - /** - * @brief OpenGL plain type ID - * - * Returns e.g. Type::UnsignedInt for GLuint. - */ - inline constexpr static Type type(); - - /** - * @brief OpenGL type ID for indices - * - * Implemented only in types which can be used for vertex indices (all - * unsigned types). This function is not present for types unusable for - * vertex indices, like GLfloat or GLint. - */ - inline constexpr static Type indexType(); - - /** - * @brief OpenGL type ID for images - * - * Implemented only in types which can be used for image data, like - * GLubyte. This function is not present for types unusable for image data, - * like GLdouble and Matrix3. - */ - inline constexpr static AbstractImage::ComponentType imageType(); - - /** - * @brief Size of plain OpenGL type - * - * Returns sizeof(GLfloat) for GLfloat, but also sizeof(GLfloat) for - * Vector3. See count(). - */ - inline constexpr static std::size_t size(); - - /** - * @brief Count of plain elements in this type - * - * Returns 1 for plain OpenGL types like GLint, but e.g. 3 for Vector3. - */ - inline constexpr static std::size_t count(); -}; -#else -template struct TypeTraits {}; -#endif - -/** @brief OpenGL plain types */ -enum class Type: GLenum { - UnsignedByte = GL_UNSIGNED_BYTE, /**< Unsigned byte (char) */ - Byte = GL_BYTE, /**< Byte (char) */ - UnsignedShort = GL_UNSIGNED_SHORT, /**< Unsigned short */ - Short = GL_SHORT, /**< Short */ - UnsignedInt = GL_UNSIGNED_INT, /**< Unsigned int */ - Int = GL_INT, /**< Int */ - Float = GL_FLOAT /**< Float */ - - #ifndef MAGNUM_TARGET_GLES - , - /** - * Double - * @requires_gl Only floats are available in OpenGL ES. - */ - Double = GL_DOUBLE - #endif -}; - -/** @debugoperator{Magnum::TypeInfo} */ -Debug MAGNUM_EXPORT operator<<(Debug debug, Type value); - -/** -@brief Class for converting Type enum values to types - -When you want to use TypeTraits on type specified only as enum value, you can -use this class to convert it into type, for example these two statements -are equivalent: -@code -type = TypeTraits::Type>::imageType(); -type = TypeTraits::imageType(); -@endcode -*/ -template class TypeOf { - #ifdef DOXYGEN_GENERATING_OUTPUT - typedef U Type; /**< @brief Type */ - #endif -}; - -/** -@brief Functor for runtime information about given type - -TypeTraits alone allows to get information about given type only at compile -time, this class alows to get some information also at runtime with tiny -performance loss. -*/ -struct MAGNUM_EXPORT TypeInfo { - /** - * @brief Size of given type - * - * These two lines provide the same information, one at compile time, - * one at runtime: - * @code - * std::size_t size = TypeTraits::size(); - * std::size_t size = TypeInfo::sizeOf(Type::UnsignedByte); - * @endcode - */ - static std::size_t sizeOf(Type type); - - /** - * @brief Whether the type is integral - * @return true for (un)signed byte, short and integer, false otherwise. - */ - static bool isIntegral(Type type); -}; - -/** @todo Other texture types, referenced in glTexImage2D function manual */ -/** @todo Using Vector3 for textures? */ - -#ifndef DOXYGEN_GENERATING_OUTPUT -template<> struct TypeOf { typedef GLubyte Type; }; -template<> struct TypeOf { typedef GLbyte Type; }; -template<> struct TypeOf { typedef GLushort Type; }; -template<> struct TypeOf { typedef GLshort Type; }; -template<> struct TypeOf { typedef GLuint Type; }; -template<> struct TypeOf { typedef GLint Type; }; -template<> struct TypeOf { typedef GLfloat Type; }; -#ifndef MAGNUM_TARGET_GLES -template<> struct TypeOf { typedef GLdouble Type; }; -#endif - -template<> struct TypeTraits: Math::MathTypeTraits { - /* Can not be used for attributes */ - inline constexpr static Type type() { return Type::UnsignedByte; } - inline constexpr static Type indexType() { return Type::UnsignedByte; } - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::UnsignedByte; } - inline constexpr static std::size_t size() { return sizeof(GLubyte); } - inline constexpr static std::size_t count() { return 1; } -}; - -template<> struct TypeTraits: Math::MathTypeTraits { - /* Can not be used for attributes */ - inline constexpr static Type type() { return Type::Byte; } - /* Can not be used for indices */ - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::Byte; } - inline constexpr static std::size_t size() { return sizeof(GLbyte); } - inline constexpr static std::size_t count() { return 1; } -}; - -template<> struct TypeTraits: Math::MathTypeTraits { - /* Can not be used for attributes */ - inline constexpr static Type type() { return Type::UnsignedShort; } - inline constexpr static Type indexType() { return Type::UnsignedShort; } - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::UnsignedShort; } - inline constexpr static std::size_t size() { return sizeof(GLushort); } - inline constexpr static std::size_t count() { return 1; } -}; - -template<> struct TypeTraits: Math::MathTypeTraits { - /* Can not be used for attributes */ - inline constexpr static Type type() { return Type::Short; } - /* Can not be used for indices */ - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::Short; } - inline constexpr static std::size_t size() { return sizeof(GLshort); } - inline constexpr static std::size_t count() { return 1; } -}; - -template<> struct TypeTraits: Math::MathTypeTraits { - typedef GLuint AttributeType; - inline constexpr static Type type() { return Type::UnsignedInt; } - inline constexpr static Type indexType() { return Type::UnsignedInt; } - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::UnsignedInt; } - inline constexpr static std::size_t size() { return sizeof(GLuint); } - inline constexpr static std::size_t count() { return 1; } -}; - -template<> struct TypeTraits: Math::MathTypeTraits { - typedef GLint AttributeType; - inline constexpr static Type type() { return Type::Int; } - /* Can not be used for indices */ - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::Int; } - inline constexpr static std::size_t size() { return sizeof(GLint); } - inline constexpr static std::size_t count() { return 1; } -}; - -template<> struct TypeTraits: Math::MathTypeTraits { - typedef GLfloat AttributeType; - inline constexpr static Type type() { return Type::Float; } - /* Can not be used for indices */ - inline constexpr static AbstractImage::ComponentType imageType() { return AbstractImage::ComponentType::Float; } - inline constexpr static std::size_t size() { return sizeof(GLfloat); } - inline constexpr static std::size_t count() { return 1; } -}; - -#ifndef MAGNUM_TARGET_GLES -template<> struct TypeTraits: Math::MathTypeTraits { - typedef GLdouble AttributeType; - inline constexpr static Type type() { return Type::Double; } - /* Can not be used for indices */ - /* Can not be used for images */ - inline constexpr static std::size_t size() { return sizeof(GLdouble); } - inline constexpr static std::size_t count() { return 1; } -}; -#endif - -namespace Implementation { - template struct VectorTypeTraits { - /* Might be used for attributes, see below */ - inline constexpr static Type type() { return TypeTraits::type(); } - /* Might be used for attributes, see below */ - /* Can not be used for indices */ - /* Can not be used for images */ - inline constexpr static std::size_t size() { return sizeof(T); } - inline constexpr static std::size_t count() { return vectorSize; } - }; - - template struct VectorAttributeType {}; - - template<> struct VectorAttributeType { - typedef GLuint AttributeType; - }; - - template<> struct VectorAttributeType { - typedef GLint AttributeType; - }; - - template<> struct VectorAttributeType { - typedef GLfloat AttributeType; - }; - - #ifndef MAGNUM_TARGET_GLES - template<> struct VectorAttributeType { - typedef GLdouble AttributeType; - }; - #endif -} - -template struct TypeTraits>: Implementation::VectorTypeTraits {}; - -/* Only some vectors can be used as attributes */ -template struct TypeTraits>: Implementation::VectorTypeTraits<1, T>, Implementation::VectorAttributeType {}; -template struct TypeTraits>: Implementation::VectorTypeTraits<2, T>, Implementation::VectorAttributeType {}; -template struct TypeTraits>: Implementation::VectorTypeTraits<3, T>, Implementation::VectorAttributeType {}; -template struct TypeTraits>: Implementation::VectorTypeTraits<4, T>, Implementation::VectorAttributeType {}; - -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; - -namespace Implementation { - template struct MatrixTypeTraits { - inline constexpr static Type type() { return TypeTraits::type(); } - /* Might be used for attributes, see below */ - /* Can not be used for indices */ - /* Can not be used for images */ - inline constexpr static std::size_t size() { return sizeof(T); } - inline constexpr static std::size_t count() { return rows; } - inline constexpr static std::size_t vectors() { return cols; } - }; - - template struct MatrixAttributeType {}; - - template<> struct MatrixAttributeType { - typedef GLfloat AttributeType; - }; - - #ifndef MAGNUM_TARGET_GLES - template<> struct MatrixAttributeType { - typedef GLdouble AttributeType; - }; - #endif -} - -template struct TypeTraits>: Implementation::MatrixTypeTraits {}; - -/* Only some floating-point matrices can be used as attributes */ -template struct TypeTraits>: Implementation::MatrixTypeTraits<2, 2, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<3, 3, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<4, 4, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<2, 3, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<3, 2, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<2, 4, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<4, 2, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<3, 4, T>, Implementation::MatrixAttributeType {}; -template struct TypeTraits>: Implementation::MatrixTypeTraits<4, 3, T>, Implementation::MatrixAttributeType {}; - -template struct TypeTraits>: TypeTraits> {}; - -template struct TypeTraits>: TypeTraits> {}; -template struct TypeTraits>: TypeTraits> {}; -#endif - -} - -namespace Corrade { namespace Utility { - -/** @configurationvalue{Magnum::TypeInfo} */ -template<> struct MAGNUM_EXPORT ConfigurationValue { - /** - * @brief Writes enum value as string - * - * If the value is invalid, returns empty string. - */ - static std::string toString(Magnum::Type value, ConfigurationValueFlags); - - /** - * @brief Reads enum value as string - * - * If the value is invalid, returns @ref Magnum::Type "Magnum::Type::Float". - */ - static Magnum::Type fromString(const std::string& stringValue, ConfigurationValueFlags); -}; - -}} - -#endif diff --git a/src/Types.h b/src/Types.h new file mode 100644 index 000000000..d8e04bb65 --- /dev/null +++ b/src/Types.h @@ -0,0 +1,54 @@ +#ifndef Magnum_Types_h +#define Magnum_Types_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 Declarations of built-in types + */ + +#include + +#include "magnumConfigure.h" + +namespace Magnum { + +/* Documented in Magnum.h */ +typedef std::uint8_t UnsignedByte; +typedef std::int8_t Byte; +typedef std::uint16_t UnsignedShort; +typedef std::int16_t Short; +typedef std::uint32_t UnsignedInt; +typedef std::int32_t Int; +typedef std::uint64_t UnsignedLong; +typedef std::int64_t Long; +typedef float Float; + +#ifndef MAGNUM_TARGET_GLES +typedef double Double; +#endif + +} + +#endif diff --git a/src/magnumConfigure.h.cmake b/src/magnumConfigure.h.cmake index 5738c3961..303ffee2d 100644 --- a/src/magnumConfigure.h.cmake +++ b/src/magnumConfigure.h.cmake @@ -1,3 +1,29 @@ -#cmakedefine MAGNUM_TARGET_NACL +/* + 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. +*/ + #cmakedefine MAGNUM_TARGET_GLES #cmakedefine MAGNUM_TARGET_GLES2 +#cmakedefine MAGNUM_TARGET_DESKTOP_GLES +#cmakedefine MAGNUM_TARGET_NACL +#cmakedefine MAGNUM_USE_HARFBUZZ diff --git a/src/magnumVisibility.h b/src/magnumVisibility.h index e37af8242..c23a8066b 100644 --- a/src/magnumVisibility.h +++ b/src/magnumVisibility.h @@ -1,18 +1,27 @@ #ifndef Magnum_magnumVisibility_h #define Magnum_magnumVisibility_h /* - Copyright © 2010, 2011, 2012 Vladimír Vondruš - This file is part of Magnum. - Magnum is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 3 - only, as published by the Free Software Foundation. + 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. - Magnum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License version 3 for more details. + 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. */ #ifdef _WIN32