From b15f3758de470fec7a776144beac02b903865550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 4 Aug 2013 10:48:32 +0200 Subject: [PATCH 01/64] Fixed NaCl compilation. --- src/Mesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index e5b394a3b..c3c0cbc51 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -120,7 +120,7 @@ Mesh& Mesh::operator=(Mesh&& other) { Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) { #ifdef CORRADE_TARGET_NACL CORRADE_ASSERT(buffer.targetHint() == Buffer::Target::ElementArray, - "Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), this); + "Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), *this); #endif indexOffset = offset; From 3f6dcc40e906ee45add9a1f6099eb47cad67321b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 4 Aug 2013 15:17:35 +0200 Subject: [PATCH 02/64] Mention that GL 4.4 is supported. --- README.md | 2 +- doc/mainpage.dox | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 292534235..24f2dfefa 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ DESIGN GOALS SUPPORTED PLATFORMS =================== -* **OpenGL** 2.1 through 4.3, core profile functionality and modern +* **OpenGL** 2.1 through 4.4, core profile functionality and modern extensions * **OpenGL ES** 2.0, 3.0 and extensions to match desktop OpenGL functionality * **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 7ed82d7d5..027bd8526 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -62,7 +62,7 @@ namespace Magnum { @section mainpage-platforms Supported platforms -- **OpenGL** 2.1 through 4.3, core profile functionality and modern +- **OpenGL** 2.1 through 4.4, core profile functionality and modern extensions - **OpenGL ES** 2.0, 3.0 and extensions to match desktop OpenGL functionality - **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through From f8066b9a95d18a6f7453f2c448ad68a502d2dcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 4 Aug 2013 15:18:00 +0200 Subject: [PATCH 03/64] Oh hey, I have Twitter! --- README.md | 3 ++- doc/mainpage.dox | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 24f2dfefa..54dd68635 100644 --- a/README.md +++ b/README.md @@ -137,8 +137,9 @@ CONTACT Want to learn more about the library? Found a bug or want to tell me an awesome idea? Feel free to visit my website or contact me at: - * Website - http://mosra.cz/blog/ + * Website - http://mosra.cz/blog/magnum.php * GitHub - https://github.com/mosra/magnum + * Twitter - https://twitter.com/czmosra * E-mail - mosra@centrum.cz * Jabber - mosra@jabbim.cz diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 027bd8526..38697a952 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -105,8 +105,9 @@ make the library as consistent and maintainable as possible. Feel free to get more information or contact the author at: +- Website - http://mosra.cz/blog/magnum.php - GitHub - https://github.com/mosra/magnum -- Website - http://mosra.cz/blog/ +- Twitter - https://twitter.com/czmosra - E-mail - mosra@centrum.cz - Jabber - mosra@jabbim.cz From 17de6fe51b75922058e10fdbec4033fee2c88cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 6 Aug 2013 21:46:39 +0200 Subject: [PATCH 04/64] Install also test libs on Windows. Resolves DLL hell when running tests. --- src/CMakeLists.txt | 6 ++++++ src/MeshTools/CMakeLists.txt | 6 ++++++ src/SceneGraph/CMakeLists.txt | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bb6c8fb12..ae045b56e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -236,5 +236,11 @@ if(BUILD_TESTS) set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) target_link_libraries(MagnumTestLib ${Magnum_LIBS}) + # On Windows we need to install first and then run the tests to avoid "DLL + # not found" hell, thus we need to install this too + if(WIN32 AND NOT CMAKE_CROSSCOMPILING) + install(TARGETS MagnumMathTestLib MagnumTestLib DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) + endif() + add_subdirectory(Test) endif() diff --git a/src/MeshTools/CMakeLists.txt b/src/MeshTools/CMakeLists.txt index ef0c26d2e..6e9762e58 100644 --- a/src/MeshTools/CMakeLists.txt +++ b/src/MeshTools/CMakeLists.txt @@ -77,5 +77,11 @@ if(BUILD_TESTS) set_target_properties(MagnumMeshToolsTestLib PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumMeshTools_EXPORTS") target_link_libraries(MagnumMeshToolsTestLib Magnum) + # On Windows we need to install first and then run the tests to avoid "DLL + # not found" hell, thus we need to install this too + if(WIN32 AND NOT CMAKE_CROSSCOMPILING) + install(TARGETS MagnumMeshToolsTestLib DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) + endif() + add_subdirectory(Test) endif() diff --git a/src/SceneGraph/CMakeLists.txt b/src/SceneGraph/CMakeLists.txt index e4f7d6145..8238973a5 100644 --- a/src/SceneGraph/CMakeLists.txt +++ b/src/SceneGraph/CMakeLists.txt @@ -92,5 +92,11 @@ if(BUILD_TESTS) set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumSceneGraph_EXPORTS") target_link_libraries(MagnumSceneGraphTestLib MagnumMathTestLib) + # On Windows we need to install first and then run the tests to avoid "DLL + # not found" hell, thus we need to install this too + if(WIN32 AND NOT CMAKE_CROSSCOMPILING) + install(TARGETS MagnumSceneGraphTestLib DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) + endif() + add_subdirectory(Test) endif() From 23945c1d9f0a494f94ab529bb965751b955a1e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 6 Aug 2013 21:47:17 +0200 Subject: [PATCH 05/64] Fix linker errors with Framebuffer::BufferAttachment::* on Windows. --- src/Framebuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 2276426ce..e71265f50 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -153,7 +153,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @see attachRenderbuffer(), attachTexture1D(), attachTexture2D(), * attachCubeMapTexture(), attachTexture3D() */ - class BufferAttachment { + class MAGNUM_EXPORT BufferAttachment { public: /** @brief Depth buffer */ static const BufferAttachment Depth; From d2bdc9d28f14112a0c7ad315585c5d4552308fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 6 Aug 2013 22:05:09 +0200 Subject: [PATCH 06/64] Text: don't use std::u32string on MinGW. MinGW (or Windows at general?!) somehow doesn't expect four-byte characters in a string and this class fails miserably when freeing memory. Replaced with std::vector, it's horrendously ugly solution, but I hope this will be resolved soon with newer MinGW GCC (4.7.2 fails). --- src/Text/AbstractFont.cpp | 7 +++- src/Text/AbstractFont.h | 7 ++++ src/Text/AbstractFontConverter.cpp | 32 ++++++++++++++--- src/Text/AbstractFontConverter.h | 30 +++++++++++++++- src/Text/Test/AbstractFontConverterTest.cpp | 39 ++++++++++++++++++--- 5 files changed, 105 insertions(+), 10 deletions(-) diff --git a/src/Text/AbstractFont.cpp b/src/Text/AbstractFont.cpp index 52c9feaff..aa8e054e1 100644 --- a/src/Text/AbstractFont.cpp +++ b/src/Text/AbstractFont.cpp @@ -124,7 +124,12 @@ void AbstractFont::fillGlyphCache(GlyphCache& cache, const std::string& characte doFillGlyphCache(cache, Utility::Unicode::utf32(characters)); } -void AbstractFont::doFillGlyphCache(GlyphCache&, const std::u32string&) { +#ifndef _WIN32 +void AbstractFont::doFillGlyphCache(GlyphCache&, const std::u32string&) +#else +void AbstractFont::doFillGlyphCache(GlyphCache&, const std::vector&) +#endif +{ CORRADE_ASSERT(false, "Text::AbstractFont::fillGlyphCache(): feature advertised but not implemented", ); } diff --git a/src/Text/AbstractFont.h b/src/Text/AbstractFont.h index bab9763cd..6f20f9197 100644 --- a/src/Text/AbstractFont.h +++ b/src/Text/AbstractFont.h @@ -250,8 +250,15 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { * * The string is converted from UTF-8 to UTF-32, unique characters are * *not* removed. + * @note On Windows uses `std::vector` instead of + * `std::u32string`. See @ref Corrade::Utility::Unicode::utf32() + * for more information. */ + #ifndef _WIN32 virtual void doFillGlyphCache(GlyphCache& cache, const std::u32string& characters); + #else + virtual void doFillGlyphCache(GlyphCache& cache, const std::vector& characters); + #endif /** * @brief Implementation for createGlyphCache() diff --git a/src/Text/AbstractFontConverter.cpp b/src/Text/AbstractFontConverter.cpp index 8487a0f61..845ad48c1 100644 --- a/src/Text/AbstractFontConverter.cpp +++ b/src/Text/AbstractFontConverter.cpp @@ -43,7 +43,12 @@ std::vector>> AbstractFo return doExportFontToData(font, cache, filename, uniqueUnicode(characters)); } -std::vector>> AbstractFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const { +#ifndef _WIN32 +std::vector>> AbstractFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const +#else +std::vector>> AbstractFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::vector& characters) const +#endif +{ CORRADE_ASSERT(!(features() & Feature::MultiFile), "Text::AbstractFontConverter::exportFontToData(): feature advertised but not implemented", {}); @@ -61,7 +66,12 @@ Containers::Array AbstractFontConverter::exportFontToSingleData(A return doExportFontToSingleData(font, cache, uniqueUnicode(characters)); } -Containers::Array AbstractFontConverter::doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string&) const { +#ifndef _WIN32 +Containers::Array AbstractFontConverter::doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string&) const +#else +Containers::Array AbstractFontConverter::doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::vector&) const +#endif +{ CORRADE_ASSERT(false, "Text::AbstractFontConverter::exportFontToSingleData(): feature advertised but not implemented", nullptr); } @@ -73,7 +83,12 @@ bool AbstractFontConverter::exportFontToFile(AbstractFont& font, GlyphCache& cac return doExportFontToFile(font, cache, filename, uniqueUnicode(characters)); } -bool AbstractFontConverter::doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const { +#ifndef _WIN32 +bool AbstractFontConverter::doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const +#else +bool AbstractFontConverter::doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::vector& characters) const +#endif +{ CORRADE_ASSERT(features() & Feature::ConvertData, "Text::AbstractFontConverter::exportFontToFile(): not implemented", false); @@ -214,9 +229,18 @@ GlyphCache* AbstractFontConverter::doImportGlyphCacheFromFile(const std::string& return doImportGlyphCacheFromSingleData(data); } -std::u32string AbstractFontConverter::uniqueUnicode(const std::string& characters) { +#ifndef _WIN32 +std::u32string AbstractFontConverter::uniqueUnicode(const std::string& characters) +#else +std::vector AbstractFontConverter::uniqueUnicode(const std::string& characters) +#endif +{ /* Convert UTF-8 to UTF-32 */ + #ifndef _WIN32 std::u32string result = Utility::Unicode::utf32(characters); + #else + std::vector result = Utility::Unicode::utf32(characters); + #endif /* Remove duplicate glyphs */ std::sort(result.begin(), result.end()); diff --git a/src/Text/AbstractFontConverter.h b/src/Text/AbstractFontConverter.h index 2ea3c0aad..f674fb17f 100644 --- a/src/Text/AbstractFontConverter.h +++ b/src/Text/AbstractFontConverter.h @@ -250,11 +250,28 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl * * If the plugin doesn't have @ref Feature "Feature::MultiFile", * default implementation calls doExportFontToSingleData(). + * @note On Windows uses `std::vector` instead of + * `std::u32string`. See @ref Corrade::Utility::Unicode::utf32() + * for more information. */ + #ifndef _WIN32 virtual std::vector>> doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const; + #else + virtual std::vector>> doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::vector& characters) const; + #endif - /** @brief Implementation for exportFontToSingleData() */ + /** + * @brief Implementation for exportFontToSingleData() + * + * @note On Windows uses `std::vector` instead of + * `std::u32string`. See @ref Corrade::Utility::Unicode::utf32() + * for more information. + */ + #ifndef _WIN32 virtual Containers::Array doExportFontToSingleData(AbstractFont& font, GlyphCache& cache, const std::u32string& characters) const; + #else + virtual Containers::Array doExportFontToSingleData(AbstractFont& font, GlyphCache& cache, const std::vector& characters) const; + #endif /** * @brief Implementation for exportFontToFile() @@ -262,8 +279,15 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl * If @ref Feature "Feature::ConvertData" is supported, default * implementation calls doExportFontToData() and saves the result to * given file(s). + * @note On Windows uses `std::vector` instead of + * `std::u32string`. See @ref Corrade::Utility::Unicode::utf32() + * for more information. */ + #ifndef _WIN32 virtual bool doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const; + #else + virtual bool doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::vector& characters) const; + #endif /** * @brief Implementation for exportGlyphCacheToData() @@ -307,7 +331,11 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl virtual GlyphCache* doImportGlyphCacheFromFile(const std::string& filename) const; private: + #ifndef _WIN32 MAGNUM_TEXT_LOCAL static std::u32string uniqueUnicode(const std::string& characters); + #else + MAGNUM_TEXT_LOCAL static std::vector uniqueUnicode(const std::string& characters); + #endif }; CORRADE_ENUMSET_OPERATORS(AbstractFontConverter::Features) diff --git a/src/Text/Test/AbstractFontConverterTest.cpp b/src/Text/Test/AbstractFontConverterTest.cpp index 643f45242..ee970473e 100644 --- a/src/Text/Test/AbstractFontConverterTest.cpp +++ b/src/Text/Test/AbstractFontConverterTest.cpp @@ -65,24 +65,45 @@ AbstractFontConverterTest::AbstractFontConverterTest() { void AbstractFontConverterTest::convertGlyphs() { class GlyphExporter: public AbstractFontConverter { public: + #ifndef _WIN32 GlyphExporter(std::u32string& characters): characters(characters) {} + #else + GlyphExporter(std::vector& characters): characters(characters) {} + #endif private: Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont; } - Containers::Array doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string& characters) const override { + #ifndef _WIN32 + Containers::Array doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string& characters) const override + #else + Containers::Array doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::vector& characters) const override + #endif + { this->characters = characters; return nullptr; } + #ifndef _WIN32 std::u32string& characters; + #else + std::vector& characters; + #endif }; + #ifndef _WIN32 std::u32string characters; + #else + std::vector characters; + #endif GlyphExporter exporter(characters); exporter.exportFontToSingleData(*static_cast(nullptr), *static_cast(nullptr), "abC01a0 "); - CORRADE_COMPARE(characters, (std::u32string{ + #ifndef _WIN32 + CORRADE_COMPARE(characters, U" 01Cab"); + #else + CORRADE_COMPARE(characters, (std::vector{ U' ', U'0', U'1', U'C', U'a', U'b'})); + #endif } void AbstractFontConverterTest::exportFontToSingleData() { @@ -90,7 +111,12 @@ void AbstractFontConverterTest::exportFontToSingleData() { private: Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont; } - Containers::Array doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string&) const override { + #ifndef _WIN32 + Containers::Array doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string&) const override + #else + Containers::Array doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::vector&) const override + #endif + { Containers::Array data(1); data[0] = 0xee; return std::move(data); @@ -111,7 +137,12 @@ void AbstractFontConverterTest::exportFontToFile() { private: Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont|Feature::MultiFile; } - std::vector>> doExportFontToData(AbstractFont&, GlyphCache&, const std::string& filename, const std::u32string&) const override { + #ifndef _WIN32 + std::vector>> doExportFontToData(AbstractFont&, GlyphCache&, const std::string& filename, const std::u32string&) const override + #else + std::vector>> doExportFontToData(AbstractFont&, GlyphCache&, const std::string& filename, const std::vector&) const override + #endif + { Containers::Array file(1); file[0] = 0xf0; From 50942b034816ceae91044f43c43a9afe15f2d006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 6 Aug 2013 22:24:55 +0200 Subject: [PATCH 07/64] FindMagnum.cmake: allow user to override plugin directories. Useful when deploying on Windows. --- modules/FindMagnum.cmake | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 4cfaa9393..58c5cf901 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -7,6 +7,10 @@ # MAGNUM_LIBRARIES - Magnum library and dependent libraries # MAGNUM_INCLUDE_DIRS - Root include dir and include dirs of # dependencies +# MAGNUM_PLUGINS_DIR - Base directory with plugins. You can modify +# it (e.g. set it to `.` when deploying on Windows with plugins stored +# relatively to the executable), the following MAGNUM_PLUGINS_*_DIR +# variables depend on it. # MAGNUM_PLUGINS_FONT_DIR - Directory with font plugins # MAGNUM_PLUGINS_FONTCONVERTER_DIR - Directory with font converter plugins # MAGNUM_PLUGINS_IMAGECONVERTER_DIR - Directory with image converter plugins @@ -341,15 +345,11 @@ mark_as_advanced(FORCE MAGNUM_INCLUDE_INSTALL_DIR MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR) +set(MAGNUM_PLUGINS_DIR ${MAGNUM_PLUGINS_INSTALL_DIR} + CACHE PATH "Base directory where to look for Magnum plugins") + # Plugin directories -if(NOT WIN32) - set(MAGNUM_PLUGINS_FONT_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fonts) - set(MAGNUM_PLUGINS_FONTCONVERTER_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fontconverters) - set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/imageconverters) - set(MAGNUM_PLUGINS_IMPORTER_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/importers) -else() - set(MAGNUM_PLUGINS_FONT_DIR fonts) - set(MAGNUM_PLUGINS_FONTCONVERTER_DIR fontconverters) - set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR imageconverters) - set(MAGNUM_PLUGINS_IMPORTER_DIR importers) -endif() +set(MAGNUM_PLUGINS_FONT_DIR ${MAGNUM_PLUGINS_DIR}/fonts) +set(MAGNUM_PLUGINS_FONTCONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/fontconverters) +set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/imageconverters) +set(MAGNUM_PLUGINS_IMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/importers) From ff7402200ea3de9c67597efee6b573840d884378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 8 Aug 2013 09:59:41 +0200 Subject: [PATCH 08/64] Renamed Mesh variables. Use leading underscore to hint that they are private variables. --- src/Mesh.cpp | 100 +++++++++++++++++++++++++-------------------------- src/Mesh.h | 16 ++++----- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index c3c0cbc51..4332cb6c6 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -60,9 +60,9 @@ std::size_t Mesh::indexSize(IndexType type) { Mesh::Mesh(Primitive primitive): _primitive(primitive), _vertexCount(0), _indexCount(0) #ifndef MAGNUM_TARGET_GLES2 - , indexStart(0), indexEnd(0) + , _indexStart(0), _indexEnd(0) #endif - , indexOffset(0), indexType(IndexType::UnsignedInt), indexBuffer(nullptr) + , _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr) { (this->*createImplementation)(); } @@ -70,49 +70,49 @@ Mesh::Mesh(Primitive primitive): _primitive(primitive), _vertexCount(0), _indexC Mesh::~Mesh() { /* Remove current vao from the state */ GLuint& current = Context::current()->state().mesh->currentVAO; - if(current == vao) current = 0; + if(current == _id) current = 0; (this->*destroyImplementation)(); } -Mesh::Mesh(Mesh&& other): vao(other.vao), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount) +Mesh::Mesh(Mesh&& other): _id(other._id), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount) #ifndef MAGNUM_TARGET_GLES2 - , indexStart(other.indexStart), indexEnd(other.indexEnd) + , _indexStart(other._indexStart), _indexEnd(other._indexEnd) #endif - , indexOffset(other.indexOffset), indexType(other.indexType), indexBuffer(other.indexBuffer), attributes(std::move(other.attributes)) + , _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes)) #ifndef MAGNUM_TARGET_GLES2 - , integerAttributes(std::move(other.integerAttributes)) + , _integerAttributes(std::move(other._integerAttributes)) #ifndef MAGNUM_TARGET_GLES - , longAttributes(std::move(other.longAttributes)) + , _longAttributes(std::move(other._longAttributes)) #endif #endif { - other.vao = 0; + other._id = 0; } Mesh& Mesh::operator=(Mesh&& other) { (this->*destroyImplementation)(); - vao = other.vao; + _id = other._id; _primitive = other._primitive; _vertexCount = other._vertexCount; _indexCount = other._indexCount; #ifndef MAGNUM_TARGET_GLES2 - indexStart = other.indexStart; - indexEnd = other.indexEnd; + _indexStart = other._indexStart; + _indexEnd = other._indexEnd; #endif - indexOffset = other.indexOffset; - indexType = other.indexType; - indexBuffer = other.indexBuffer; - attributes = std::move(other.attributes); + _indexOffset = other._indexOffset; + _indexType = other._indexType; + _indexBuffer = other._indexBuffer; + _attributes = std::move(other._attributes); #ifndef MAGNUM_TARGET_GLES2 - integerAttributes = std::move(other.integerAttributes); + _integerAttributes = std::move(other._integerAttributes); #ifndef MAGNUM_TARGET_GLES - longAttributes = std::move(other.longAttributes); + _longAttributes = std::move(other._longAttributes); #endif #endif - other.vao = 0; + other._id = 0; return *this; } @@ -123,11 +123,11 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi "Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), *this); #endif - indexOffset = offset; - indexType = type; + _indexOffset = offset; + _indexType = type; #ifndef MAGNUM_TARGET_GLES2 - indexStart = start; - indexEnd = end; + _indexStart = start; + _indexEnd = end; #else static_cast(start); static_cast(end); @@ -148,13 +148,13 @@ void Mesh::draw() { #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)); + else if(_indexEnd) + glDrawRangeElements(static_cast(_primitive), _indexStart, _indexEnd, _indexCount, static_cast(_indexType), reinterpret_cast(_indexOffset)); #endif /* Indexed mesh without specified range */ else - glDrawElements(static_cast(_primitive), _indexCount, static_cast(indexType), reinterpret_cast(indexOffset)); + glDrawElements(static_cast(_primitive), _indexCount, static_cast(_indexType), reinterpret_cast(_indexOffset)); (this->*unbindImplementation)(); } @@ -226,7 +226,7 @@ void Mesh::createImplementationDefault() {} void Mesh::createImplementationVAO() { /** @todo Get some extension wrangler instead to avoid linker errors to glGenVertexArrays() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 - glGenVertexArrays(1, &vao); + glGenVertexArrays(1, &_id); #endif } @@ -235,7 +235,7 @@ void Mesh::destroyImplementationDefault() {} void Mesh::destroyImplementationVAO() { /** @todo Get some extension wrangler instead to avoid linker errors to glDeleteVertexArrays() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 - if(vao) glDeleteVertexArrays(1, &vao); + if(_id) glDeleteVertexArrays(1, &_id); #endif } @@ -245,7 +245,7 @@ void Mesh::attributePointerImplementationDefault(const Attribute& attribute) { "Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::Array << "but got" << attribute.buffer->targetHint(), ); #endif - attributes.push_back(attribute); + _attributes.push_back(attribute); } void Mesh::attributePointerImplementationVAO(const Attribute& attribute) { @@ -254,57 +254,57 @@ void Mesh::attributePointerImplementationVAO(const Attribute& attribute) { "Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::Array << "but got" << attribute.buffer->targetHint(), ); #endif - bindVAO(vao); + bindVAO(_id); vertexAttribPointer(attribute); } #ifndef MAGNUM_TARGET_GLES void Mesh::attributePointerImplementationDSA(const Attribute& attribute) { - glEnableVertexArrayAttribEXT(vao, attribute.location); - glVertexArrayVertexAttribOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset); + glEnableVertexArrayAttribEXT(_id, attribute.location); + glVertexArrayVertexAttribOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset); } #endif #ifndef MAGNUM_TARGET_GLES2 void Mesh::attributePointerImplementationDefault(const IntegerAttribute& attribute) { - integerAttributes.push_back(attribute); + _integerAttributes.push_back(attribute); } void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute) { - bindVAO(vao); + bindVAO(_id); vertexAttribPointer(attribute); } #ifndef MAGNUM_TARGET_GLES void Mesh::attributePointerImplementationDSA(const IntegerAttribute& attribute) { - glEnableVertexArrayAttribEXT(vao, attribute.location); - glVertexArrayVertexAttribIOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); + glEnableVertexArrayAttribEXT(_id, attribute.location); + glVertexArrayVertexAttribIOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); } #endif #ifndef MAGNUM_TARGET_GLES void Mesh::attributePointerImplementationDefault(const LongAttribute& attribute) { - longAttributes.push_back(attribute); + _longAttributes.push_back(attribute); } void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) { - bindVAO(vao); + bindVAO(_id); vertexAttribPointer(attribute); } void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) { - glEnableVertexArrayAttribEXT(vao, attribute.location); - glVertexArrayVertexAttribLOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); + glEnableVertexArrayAttribEXT(_id, attribute.location); + glVertexArrayVertexAttribLOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); } #endif #endif void Mesh::bindIndexBufferImplementationDefault(Buffer& buffer) { - indexBuffer = &buffer; + _indexBuffer = &buffer; } void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) { - bindVAO(vao); + bindVAO(_id); /* Reset ElementArray binding to force explicit glBindBuffer call later */ /** @todo Do this cleaner way */ @@ -315,37 +315,37 @@ void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) { void Mesh::bindImplementationDefault() { /* Specify vertex attributes */ - for(const Attribute& attribute: attributes) + for(const Attribute& attribute: _attributes) vertexAttribPointer(attribute); #ifndef MAGNUM_TARGET_GLES2 - for(const IntegerAttribute& attribute: integerAttributes) + for(const IntegerAttribute& attribute: _integerAttributes) vertexAttribPointer(attribute); #ifndef MAGNUM_TARGET_GLES - for(const LongAttribute& attribute: longAttributes) + for(const LongAttribute& attribute: _longAttributes) vertexAttribPointer(attribute); #endif #endif /* Bind index buffer, if the mesh is indexed */ - if(_indexCount) indexBuffer->bind(Buffer::Target::ElementArray); + if(_indexCount) _indexBuffer->bind(Buffer::Target::ElementArray); } void Mesh::bindImplementationVAO() { - bindVAO(vao); + bindVAO(_id); } void Mesh::unbindImplementationDefault() { - for(const Attribute& attribute: attributes) + for(const Attribute& attribute: _attributes) glDisableVertexAttribArray(attribute.location); #ifndef MAGNUM_TARGET_GLES2 - for(const IntegerAttribute& attribute: integerAttributes) + for(const IntegerAttribute& attribute: _integerAttributes) glDisableVertexAttribArray(attribute.location); #ifndef MAGNUM_TARGET_GLES - for(const LongAttribute& attribute: longAttributes) + for(const LongAttribute& attribute: _longAttributes) glDisableVertexAttribArray(attribute.location); #endif #endif diff --git a/src/Mesh.h b/src/Mesh.h index 5afadf688..2a920e03a 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -759,21 +759,21 @@ class MAGNUM_EXPORT Mesh { void MAGNUM_LOCAL unbindImplementationVAO(); static MAGNUM_LOCAL UnbindImplementation unbindImplementation; - GLuint vao; + GLuint _id; Primitive _primitive; Int _vertexCount, _indexCount; #ifndef MAGNUM_TARGET_GLES2 - UnsignedInt indexStart, indexEnd; + UnsignedInt _indexStart, _indexEnd; #endif - GLintptr indexOffset; - IndexType indexType; - Buffer* indexBuffer; + GLintptr _indexOffset; + IndexType _indexType; + Buffer* _indexBuffer; - std::vector attributes; + std::vector _attributes; #ifndef MAGNUM_TARGET_GLES2 - std::vector integerAttributes; + std::vector _integerAttributes; #ifndef MAGNUM_TARGET_GLES - std::vector longAttributes; + std::vector _longAttributes; #endif #endif }; From 6b4147e25eee6cc10948f0a37f79c6143de2d8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 9 Aug 2013 17:05:06 +0200 Subject: [PATCH 09/64] Doc++ --- src/Renderer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Renderer.h b/src/Renderer.h index cbef32112..7bf87ed64 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -37,9 +37,8 @@ namespace Magnum { /** @nosubgrouping -@brief %Renderer +@brief Global renderer configuration. -Access to global renderer configuration. @todo @extension{ARB,viewport_array} */ class MAGNUM_EXPORT Renderer { From 33653a3469ced82b3177653d11e2d8ec9392734d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 9 Aug 2013 17:18:05 +0200 Subject: [PATCH 10/64] Math: hardened checks for proper size of primitive types. --- src/Math/instantiation.cpp | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/Math/instantiation.cpp b/src/Math/instantiation.cpp index dcaaaa601..1bf7f918b 100644 --- a/src/Math/instantiation.cpp +++ b/src/Math/instantiation.cpp @@ -105,6 +105,46 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quate template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quaternion&); #endif +/* Check proper size of GL types */ +static_assert(sizeof(Vector<2, Float>) == 8, "Improper size of 2-element Float vector"); +static_assert(sizeof(Vector<3, Float>) == 12, "Improper size of 3-element Float vector"); +static_assert(sizeof(Vector<4, Float>) == 16, "Improper size of 4-element Float vector"); +static_assert(sizeof(Vector<2, Int>) == 8, "Improper size of 2-element Int vector"); +static_assert(sizeof(Vector<3, Int>) == 12, "Improper size of 3-element Int vector"); +static_assert(sizeof(Vector<4, Int>) == 16, "Improper size of 4-element Int vector"); +static_assert(sizeof(Vector<2, UnsignedInt>) == 8, "Improper size of 2-element UnsignedInt vector"); +static_assert(sizeof(Vector<3, UnsignedInt>) == 12, "Improper size of 3-element UnsignedInt vector"); +static_assert(sizeof(Vector<4, UnsignedInt>) == 16, "Improper size of 4-element UnsignedInt vector"); +#ifndef MAGNUM_TARGET_GLES +static_assert(sizeof(Vector<2, Double>) == 16, "Improper size of 2-element Double vector"); +static_assert(sizeof(Vector<3, Double>) == 24, "Improper size of 3-element Double vector"); +static_assert(sizeof(Vector<4, Double>) == 32, "Improper size of 4-element Double vector"); +#endif + +static_assert(sizeof(RectangularMatrix<2, 2, Float>) == 16, "Improper size of 2x2 Float matrix"); +static_assert(sizeof(RectangularMatrix<3, 3, Float>) == 36, "Improper size of 3x3 Float matrix"); +static_assert(sizeof(RectangularMatrix<4, 4, Float>) == 64, "Improper size of 4x4 Float matrix"); +#ifndef MAGNUM_TARGET_GLES +static_assert(sizeof(RectangularMatrix<2, 2, Double>) == 32, "Improper size of 2x2 Double matrix"); +static_assert(sizeof(RectangularMatrix<3, 3, Double>) == 72, "Improper size of 3x3 Double matrix"); +static_assert(sizeof(RectangularMatrix<4, 4, Double>) == 128, "Improper size of 4x4 Double matrix"); +#endif + +static_assert(sizeof(RectangularMatrix<2, 3, Float>) == 24, "Improper size of 2x3 Float matrix"); +static_assert(sizeof(RectangularMatrix<3, 2, Float>) == 24, "Improper size of 3x2 Float matrix"); +static_assert(sizeof(RectangularMatrix<2, 4, Float>) == 32, "Improper size of 2x4 Float matrix"); +static_assert(sizeof(RectangularMatrix<4, 2, Float>) == 32, "Improper size of 4x2 Float matrix"); +static_assert(sizeof(RectangularMatrix<3, 4, Float>) == 48, "Improper size of 3x4 Float matrix"); +static_assert(sizeof(RectangularMatrix<4, 3, Float>) == 48, "Improper size of 4x3 Float matrix"); +#ifndef MAGNUM_TARGET_GLES +static_assert(sizeof(RectangularMatrix<2, 3, Double>) == 48, "Improper size of 2x3 Double matrix"); +static_assert(sizeof(RectangularMatrix<3, 2, Double>) == 48, "Improper size of 3x2 Double matrix"); +static_assert(sizeof(RectangularMatrix<2, 4, Double>) == 64, "Improper size of 2x4 Double matrix"); +static_assert(sizeof(RectangularMatrix<4, 2, Double>) == 64, "Improper size of 4x2 Double matrix"); +static_assert(sizeof(RectangularMatrix<3, 4, Double>) == 96, "Improper size of 3x4 Double matrix"); +static_assert(sizeof(RectangularMatrix<4, 3, Double>) == 96, "Improper size of 4x3 Double matrix"); +#endif + template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, Float>&); template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, Float>&); template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, Float>&); From 3b14a1816e71874af95d48db253460f7f0ac56f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 19:12:20 +0200 Subject: [PATCH 11/64] Trade: fixed wrong indentation. --- src/Trade/AbstractImporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Trade/AbstractImporter.cpp b/src/Trade/AbstractImporter.cpp index f6c53eb4a..e5e2eca1a 100644 --- a/src/Trade/AbstractImporter.cpp +++ b/src/Trade/AbstractImporter.cpp @@ -87,8 +87,8 @@ Int AbstractImporter::defaultScene() { Int AbstractImporter::doDefaultScene() { return -1; } UnsignedInt AbstractImporter::sceneCount() const { - CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::sceneCount(): no file opened", 0); - return doSceneCount(); + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::sceneCount(): no file opened", 0); + return doSceneCount(); } UnsignedInt AbstractImporter::doSceneCount() const { return 0; } From e167b971c7738b0c054c942dcc839bad68fa1363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 19:12:33 +0200 Subject: [PATCH 12/64] Trade: don't forget to initialize variable. It's just test, but it might fail when least expected. --- src/Trade/Test/AbstractImporterTest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Trade/Test/AbstractImporterTest.cpp b/src/Trade/Test/AbstractImporterTest.cpp index 0e1143d9e..3dacf06dd 100644 --- a/src/Trade/Test/AbstractImporterTest.cpp +++ b/src/Trade/Test/AbstractImporterTest.cpp @@ -45,6 +45,9 @@ AbstractImporterTest::AbstractImporterTest() { void AbstractImporterTest::openFile() { class DataImporter: public Trade::AbstractImporter { + public: + explicit DataImporter(): opened(false) {} + private: Features doFeatures() const override { return Feature::OpenData; } bool doIsOpened() const override { return opened; } From 6db322062f14cc0133b380e664697157629aee1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 16 Aug 2013 16:07:19 +0200 Subject: [PATCH 13/64] Add performance recommendations for Intel Graphics on Linux. --- doc/best-practices.dox | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/best-practices.dox b/doc/best-practices.dox index 5e5c31ca1..e0f0c9331 100644 --- a/doc/best-practices.dox +++ b/doc/best-practices.dox @@ -65,6 +65,12 @@ to desired target, either in constructor or using Buffer::setTargetHint(). To ease up the development, @ref Mesh checks proper target hint when adding vertex and index buffers. +@section best-practices-hw Hardware-specific + +@subsection best-practices-intel Intel hardware + +- [Performance tuning applications for Intel Graphics for Linux and Chrome OS](http://software.intel.com/sites/default/files/Performance-tuning-applications-for-Intel-GEN-Graphics-for-Linux-and-Google-Chrome-OS.pdf) [PDF] + @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] From 2b32625921c1df25898ae279e3e4cc384739f82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 23 Jul 2013 10:42:46 +0200 Subject: [PATCH 14/64] Bootstrap Audio library. Will require OpenAL for now, although I don't like the state in which AL currently is. At all. Other alternatives (later) might be FMOD or Miles. --- CMakeLists.txt | 1 + doc/building.dox | 1 + doc/cmake.dox | 1 + doc/namespaces.dox | 12 ++++++++++++ modules/FindMagnum.cmake | 14 ++++++++++++++ src/Audio/Audio.h | 35 +++++++++++++++++++++++++++++++++++ src/Audio/CMakeLists.txt | 34 ++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 4 ++++ 8 files changed, 102 insertions(+) create mode 100644 src/Audio/Audio.h create mode 100644 src/Audio/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 328bbb1e8..9b9fc43d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ 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_AUDIO "Build Audio library" ON) option(WITH_DEBUGTOOLS "Build DebugTools library" ON) cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" ON "NOT WITH_DEBUGTOOLS" ON) cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" ON "NOT WITH_DEBUGTOOLS" ON) diff --git a/doc/building.dox b/doc/building.dox index def7912d6..bebcbd912 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -96,6 +96,7 @@ 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_AUDIO` - Audio library. Requires **OpenAL** library. - `WITH_DEBUGTOOLS` - DebugTools library. Enables also building of MeshTools, Primitives, SceneGraph, Shaders and Shapes libraries. - `WITH_MESHTOOLS` - MeshTools library. Enabled automatically if `WITH_DEBUGTOOLS` diff --git a/doc/cmake.dox b/doc/cmake.dox index b23a19c51..eee0944bc 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -51,6 +51,7 @@ components. The base library depends on %Corrade, OpenGL and GLEW libraries (or OpenGL ES libraries). Additional dependencies are specified by the components. The optional components are: +- `%Audio` -- Audio library (depends on OpenAL library) - `%DebugTools` -- DebugTools library (depends on `%MeshTools`, `%Primitives`, `%SceneGraph`, `%Shaders` and `%Shapes` components) - `%MeshTools` -- MeshTools library diff --git a/doc/namespaces.dox b/doc/namespaces.dox index 8a4e1b3b7..f984f03b5 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -88,6 +88,18 @@ This library is built by default and found by default in CMake. See @ref building and @ref cmake for more information. */ +/** @dir Audio + * @brief Namespace Magnum::Audio + */ +/** @namespace Magnum::Audio +@brief %Audio playback + +Audio import, playback and integration with @ref SceneGraph. + +This library is built when `WITH_AUDIO` is enabled and found as `%Audio` +component in CMake. See @ref building and @ref cmake for more information. +*/ + /** @dir DebugTools * @brief Namespace Magnum::DebugTools */ diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 58c5cf901..0be6ab1b0 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -19,6 +19,7 @@ # components. The base library depends on Corrade, OpenGL and GLEW # libraries. Additional dependencies are specified by the components. The # optional components are: +# Audio - Audio library (depends on OpenAL library) # DebugTools - DebugTools library (depends on MeshTools, Primitives, # SceneGraph, Shaders and Shapes components) # MeshTools - MeshTools library @@ -219,6 +220,19 @@ foreach(component ${Magnum_FIND_COMPONENTS}) endif() endif() + # Audio library + if(${component} STREQUAL Audio) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Audio.h) + + find_package(OpenAL) + if(OPENAL_FOUND) + set(_MAGNUM_${_COMPONENT}_LIBRARIES ${OPENAL_LIBRARY}) + set(_MAGNUM_${_COMPONENT}_INCLUDE_DIRS ${OPENAL_INCLUDE_DIR}) + else() + unset(MAGNUM_${_COMPONENT}_LIBRARY) + endif() + endif() + # DebugTools library if(${component} STREQUAL DebugTools) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES DebugTools.h) diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h new file mode 100644 index 000000000..63960eeca --- /dev/null +++ b/src/Audio/Audio.h @@ -0,0 +1,35 @@ +#ifndef Magnum_Audio_Audio_h +#define Magnum_Audio_Audio_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::Audio namespace + */ + +namespace Magnum { namespace Audio { + +}} + +#endif diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt new file mode 100644 index 000000000..e404e1246 --- /dev/null +++ b/src/Audio/CMakeLists.txt @@ -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. +# + +find_package(OpenAL REQUIRED) + +include_directories(${OPENAL_INCLUDE_DIR}) + +set(MagnumAudio_SOURCES + ) +set(MagnumAudio_HEADERS + Audio.h) + +install(FILES ${MagnumAudio_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Audio) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ae045b56e..2e92d2ea5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -191,6 +191,10 @@ add_subdirectory(Math) add_subdirectory(Platform) add_subdirectory(Trade) +if(WITH_AUDIO) + add_subdirectory(Audio) +endif() + if(WITH_DEBUGTOOLS) add_subdirectory(DebugTools) endif() From 60bc510a70a15e0fad96e10be96e82ad6ee0b574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 11:00:21 +0200 Subject: [PATCH 15/64] Added Doxygen aliases for pointing to OpenAL documentation. Not found any online manpages however, so just placeholder. --- Doxyfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doxyfile b/Doxyfile index ec9dbea6a..5efd5080d 100644 --- a/Doxyfile +++ b/Doxyfile @@ -224,7 +224,9 @@ ALIASES = \ "requires_gles20=@xrefitem requires-gles20 \"Requires OpenGL ES 2.0\" \"Functionality requiring OpenGL ES 2.0 (not available in ES 3.0 and desktop OpenGL)\"" \ "requires_es_extension=@xrefitem requires-es-extension \"Requires OpenGL ES extension\" \"Functionality requiring specific OpenGL ES extension\"" \ "es_extension{2}=\1_\2" \ - "es_extension2{3}=\1_\2" + "es_extension2{3}=\1_\2" \ + "fn_al{1}=`al\1()`" \ + "def_al{1}=`AL_\1`" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding From 1e4680f918b8bb5026cfff3e23c1a82fbcbd6ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 10:48:19 +0200 Subject: [PATCH 16/64] Audio: verify OpenAL types. --- src/Audio/Audio.cpp | 49 ++++++++++++++++++++++++++++++++++++++++ src/Audio/CMakeLists.txt | 7 +++++- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/Audio/Audio.cpp diff --git a/src/Audio/Audio.cpp b/src/Audio/Audio.cpp new file mode 100644 index 000000000..25c70e5e4 --- /dev/null +++ b/src/Audio/Audio.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. +*/ + +#include +#include + +#include "Types.h" + +namespace Magnum { namespace Audio { + +/* Verify types */ +static_assert(std::is_same::value, "ALubyte is not the same as UnsignedByte"); +static_assert(std::is_same::value, "ALbyte is not the same as Byte"); +static_assert(std::is_same::value, "ALushort is not the same as UnsignedShort"); +static_assert(std::is_same::value, "ALshort is not the same as Short"); +static_assert(std::is_same::value, "ALuint is not the same as UnsignedInt"); +static_assert(std::is_same::value, "ALint is not the same as Int"); +static_assert(std::is_same::value, "ALsizei is not the same as Int"); +static_assert(std::is_same::value, "ALfloat is not the same as Float"); +#ifndef MAGNUM_TARGET_GLES +static_assert(std::is_same::value, "ALdouble is not the same as Double"); +#endif + +/* Verify boolean values */ +static_assert(AL_FALSE == false, "AL_FALSE is not the same as false"); +static_assert(AL_TRUE == true, "AL_TRUE is not the same as true"); + +}} diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index e404e1246..8bdc6b9f8 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -27,8 +27,13 @@ find_package(OpenAL REQUIRED) include_directories(${OPENAL_INCLUDE_DIR}) set(MagnumAudio_SOURCES - ) + Audio.cpp) + set(MagnumAudio_HEADERS Audio.h) +add_library(MagnumAudio ${SHARED_OR_STATIC} ${MagnumAudio_SOURCES}) +target_link_libraries(MagnumAudio ${OPENAL_LIBRARY}) + +install(TARGETS MagnumAudio DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumAudio_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Audio) From 6efb83f72971592e3a7715f18c54d9d3705d5084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 11:15:18 +0200 Subject: [PATCH 17/64] Audio: added Renderer class. --- src/Audio/Audio.h | 2 + src/Audio/CMakeLists.txt | 12 +- src/Audio/Renderer.cpp | 46 +++++++ src/Audio/Renderer.h | 202 ++++++++++++++++++++++++++++++ src/Audio/Test/CMakeLists.txt | 25 ++++ src/Audio/Test/RendererTest.cpp | 51 ++++++++ src/Audio/magnumAudioVisibility.h | 35 ++++++ src/Renderer.h | 2 +- 8 files changed, 372 insertions(+), 3 deletions(-) create mode 100644 src/Audio/Renderer.cpp create mode 100644 src/Audio/Renderer.h create mode 100644 src/Audio/Test/CMakeLists.txt create mode 100644 src/Audio/Test/RendererTest.cpp create mode 100644 src/Audio/magnumAudioVisibility.h diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h index 63960eeca..d0cabf47e 100644 --- a/src/Audio/Audio.h +++ b/src/Audio/Audio.h @@ -30,6 +30,8 @@ namespace Magnum { namespace Audio { +/* Renderer used only statically */ + }} #endif diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index 8bdc6b9f8..b5ea399a1 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -27,13 +27,21 @@ find_package(OpenAL REQUIRED) include_directories(${OPENAL_INCLUDE_DIR}) set(MagnumAudio_SOURCES - Audio.cpp) + Audio.cpp + Renderer.cpp) set(MagnumAudio_HEADERS - Audio.h) + Audio.h + Renderer.h + + magnumAudioVisibility.h) add_library(MagnumAudio ${SHARED_OR_STATIC} ${MagnumAudio_SOURCES}) target_link_libraries(MagnumAudio ${OPENAL_LIBRARY}) install(TARGETS MagnumAudio DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumAudio_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Audio) + +if(BUILD_TESTS) + add_subdirectory(Test) +endif() diff --git a/src/Audio/Renderer.cpp b/src/Audio/Renderer.cpp new file mode 100644 index 000000000..4dbeae53f --- /dev/null +++ b/src/Audio/Renderer.cpp @@ -0,0 +1,46 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír VondruÅ¡ + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Renderer.h" + +#include + +namespace Magnum { namespace Audio { + +Debug operator<<(Debug debug, const Renderer::Error value) { + switch(value) { + #define _c(value) case Renderer::Error::value: return debug << "Audio::Renderer::Error::" #value; + _c(NoError) + _c(InvalidName) + _c(InvalidEnum) + _c(InvalidValue) + _c(InvalidOperation) + _c(OutOfMemory) + #undef _c + } + + return debug << "Audio::Renderer::Error::(invalid)"; +} + +}} diff --git a/src/Audio/Renderer.h b/src/Audio/Renderer.h new file mode 100644 index 000000000..f8041e28a --- /dev/null +++ b/src/Audio/Renderer.h @@ -0,0 +1,202 @@ +#ifndef Magnum_Audio_Renderer_h +#define Magnum_Audio_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::Audio::Renderer + */ + +#include + +#include "Math/Vector3.h" +#include "Magnum.h" +#include "Audio/magnumAudioVisibility.h" + +namespace Magnum { namespace Audio { + +/** @brief Global renderer configuration */ +class Renderer { + public: + Renderer() = delete; + + /** + * @brief Error status + * + * @see error() + */ + enum class Error: ALenum { + NoError = AL_NO_ERROR, /**< No error occured */ + InvalidName = AL_INVALID_NAME, /**< Invalid name parameter */ + InvalidEnum = AL_INVALID_ENUM, /**< Invalid enum parameter */ + InvalidValue = AL_INVALID_VALUE, /**< Invalid enum value parameter */ + InvalidOperation = AL_INVALID_OPERATION, /**< Illegal call */ + OutOfMemory = AL_OUT_OF_MEMORY /**< Unable to allocate memory */ + }; + + /** @brief Error status */ + static Error error() { return Error(alGetError()); } + + /** @{ @name Listener positioning */ + + /** + * @brief Set listener position + * + * Default is `{0.0f, 0.0f, 0.0f}`. + * @see @fn_al{Listenerfv} with @def_al{POSITION} + */ + static void setListenerPosition(const Vector3& position) { + alListenerfv(AL_POSITION, position.data()); + } + + /** @overload + * @see @fn_al{Listeneriv} with @def_al{POSITION} + */ + static void setListenerPosition(const Vector3i& position) { + alListeneriv(AL_POSITION, position.data()); + } + + /** + * @brief Set listener orientation + * + * The values must be linearly independent and don't need to be + * normalized. Default is -Z and +Y. + * @see @fn_al{Listenerfv} with @def_al{ORIENTATION} + */ + static void setListenerOrientation(const Vector3& forward, const Vector3& up); + + /** @overload + * @see @fn_al{Listeneriv} with @def_al{ORIENTATION} + */ + static void setListenerOrientation(const Vector3i& forward, const Vector3i& up); + + /** + * @brief Set listener velocity + * + * Default is `{0.0f, 0.0f, 0.0f}`. + * @see @fn_al{Listenerfv} with @def_al{VELOCITY} + */ + static void setListenerVelocity(const Vector3& velocity) { + alListenerfv(AL_VELOCITY, velocity.data()); + } + + /** @overload + * @see @fn_al{Listeneriv} with @def_al{VELOCITY} + */ + static void setListenerVelocity(const Vector3i& velocity) { + alListeneriv(AL_VELOCITY, velocity.data()); + } + + /*@}*/ + + /** @{ @name Global behavior */ + + /** + * @brief Distance model + * + * @see setDistanceModel() + */ + enum class DistanceModel: ALenum { + /** No distance attenuation calculation */ + None = AL_NONE, + + /** Inverse distance */ + Inverse = AL_INVERSE_DISTANCE, + + /** Inverse distance, clamped */ + InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, + + /** Linear distance */ + Linear = AL_LINEAR_DISTANCE, + + /** Linear distance, clamped */ + LinearClamped = AL_LINEAR_DISTANCE_CLAMPED, + + /** Exponential distance */ + Exponent = AL_EXPONENT_DISTANCE, + + /** Exponential distance, clamped */ + ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED + }; + + /** + * @brief Set listener gain + * + * Default is `1.0f`, which means that the sound is unattenuated. + * If set to `0.0f`, all sound is muted. + * @see @fn_al{Listenerf} with @def_al{GAIN} + */ + static void setListenerGain(Float gain) { + alListenerf(AL_GAIN, gain); + } + + /** + * @brief Set Doppler factor + * + * Default is `1.0f`. If set to `0.0f`, the effect is disabled. + * @see @ref setSpeedOfSound(), @fn_al{DopplerFactor} + */ + static void setDopplerFactor(Float factor) { + alDopplerFactor(factor); + } + + /** + * @brief Set speed of sound + * + * Default is `343.3f` (meters per second). + * @see @ref setDopplerFactor(), @fn_al{SpeedOfSound} + */ + static void setSpeedOfSound(Float speed) { + alSpeedOfSound(speed); + } + + /** + * @brief Set distance model + * + * Default is @ref DistanceModel "DistanceModel::InverseClamped". + * @see @fn_al{DistanceModel} + */ + static void setDistanceModel(DistanceModel model) { + alDistanceModel(ALenum(model)); + } + + /*@}*/ +}; + +/** @debugoperator{Magnum::Audio::Renderer} */ +Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Renderer::Error value); + +inline void Renderer::setListenerOrientation(const Vector3& forward, const Vector3& up) { + const Vector3 data[] = {forward, up}; + alListenerfv(AL_ORIENTATION, data[0].data()); +} + +inline void Renderer::setListenerOrientation(const Vector3i& forward, const Vector3i& up) { + const Vector3i data[] = {forward, up}; + alListeneriv(AL_ORIENTATION, data[0].data()); +} + +}} + +#endif diff --git a/src/Audio/Test/CMakeLists.txt b/src/Audio/Test/CMakeLists.txt new file mode 100644 index 000000000..3a13c2df8 --- /dev/null +++ b/src/Audio/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(AudioRendererTest RendererTest.cpp LIBRARIES MagnumAudio) diff --git a/src/Audio/Test/RendererTest.cpp b/src/Audio/Test/RendererTest.cpp new file mode 100644 index 000000000..9be69593d --- /dev/null +++ b/src/Audio/Test/RendererTest.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 "Audio/Renderer.h" + +namespace Magnum { namespace Audio { namespace Test { + +class RendererTest: public TestSuite::Tester { + public: + explicit RendererTest(); + + void debugError(); +}; + +RendererTest::RendererTest() { + addTests({&RendererTest::debugError}); +} + +void RendererTest::debugError() { + std::ostringstream out; + Debug(&out) << Renderer::Error::InvalidOperation; + CORRADE_COMPARE(out.str(), "Audio::Renderer::Error::InvalidOperation\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::RendererTest) diff --git a/src/Audio/magnumAudioVisibility.h b/src/Audio/magnumAudioVisibility.h new file mode 100644 index 000000000..e4a7c0f67 --- /dev/null +++ b/src/Audio/magnumAudioVisibility.h @@ -0,0 +1,35 @@ +#ifndef Magnum_Audio_magnumAudioVisibility_h +#define Magnum_Audio_magnumAudioVisibility_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 + +#ifdef MagnumAudio_EXPORTS + #define MAGNUM_AUDIO_EXPORT CORRADE_VISIBILITY_EXPORT +#else + #define MAGNUM_AUDIO_EXPORT CORRADE_VISIBILITY_IMPORT +#endif + +#endif diff --git a/src/Renderer.h b/src/Renderer.h index 7bf87ed64..1e345f3ea 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. */ -/** @file +/** @file /Renderer.h * @brief Class Magnum::Renderer */ From 0382ce70c110d9a88e7da677374254462a857573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 11:16:22 +0200 Subject: [PATCH 18/64] Audio: added Buffer class. --- src/Audio/Audio.h | 1 + src/Audio/Buffer.cpp | 44 +++++++++++++ src/Audio/Buffer.h | 120 ++++++++++++++++++++++++++++++++++ src/Audio/CMakeLists.txt | 2 + src/Audio/Test/BufferTest.cpp | 51 +++++++++++++++ src/Audio/Test/CMakeLists.txt | 1 + src/Buffer.h | 2 +- 7 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 src/Audio/Buffer.cpp create mode 100644 src/Audio/Buffer.h create mode 100644 src/Audio/Test/BufferTest.cpp diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h index d0cabf47e..c02b8d6be 100644 --- a/src/Audio/Audio.h +++ b/src/Audio/Audio.h @@ -30,6 +30,7 @@ namespace Magnum { namespace Audio { +class Buffer; /* Renderer used only statically */ }} diff --git a/src/Audio/Buffer.cpp b/src/Audio/Buffer.cpp new file mode 100644 index 000000000..1a28d95c1 --- /dev/null +++ b/src/Audio/Buffer.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 "Buffer.h" + +#include + +namespace Magnum { namespace Audio { + +Debug operator<<(Debug debug, const Buffer::Format value) { + switch(value) { + #define _c(value) case Buffer::Format::value: return debug << "Audio::Buffer::Format::" #value; + _c(Mono8) + _c(Mono16) + _c(Stereo8) + _c(Stereo16) + #undef _c + } + + return debug << "Audio::Buffer::Format::(invalid)"; +} + +}} diff --git a/src/Audio/Buffer.h b/src/Audio/Buffer.h new file mode 100644 index 000000000..31774c9e5 --- /dev/null +++ b/src/Audio/Buffer.h @@ -0,0 +1,120 @@ +#ifndef Magnum_Audio_Buffer_h +#define Magnum_Audio_Buffer_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::Audio::Buffer + */ + +#include +#include +#include + +#include "Magnum.h" +#include "Audio/magnumAudioVisibility.h" + +namespace Magnum { namespace Audio { + +/** @brief Sample buffer */ +class Buffer { + public: + /** + * @brief Sample format + * + * @note Multi-channel format is played without 3D spatialization + * (useful for background music) + * @see @ref setData() + */ + enum class Format: ALenum { + Mono8 = AL_FORMAT_MONO8, /**< 8-bit unsigned mono */ + Mono16 = AL_FORMAT_MONO16, /**< 16-bit signed mono */ + Stereo8 = AL_FORMAT_STEREO8, /**< 8-bit interleaved unsigned stereo */ + Stereo16 = AL_FORMAT_STEREO16 /**< 16-bit interleaved signed stereo */ + }; + + /** + * @brief Constructor + * + * Creates OpenAL buffer object. + * @see @fn_al{GenBuffers} + */ + explicit Buffer() { alGenBuffers(1, &_id); } + + /** + * @brief Destructor + * + * Deletes OpenAL buffer object. + * @see @fn_al{DeleteBuffers} + */ + ~Buffer() { if(_id) alDeleteBuffers(1, &_id); } + + /** @brief Copying is not allowed */ + Buffer(const Buffer&) = delete; + + /** @brief Move constructor */ + Buffer(Buffer&& other); + + /** @brief Copying is not allowed */ + Buffer& operator=(const Buffer&) = delete; + + /** @brief Move assignment */ + Buffer& operator=(Buffer&& other); + + /** @brief OpenAL buffer ID */ + ALuint id() const { return _id; } + + /** + * @brief Set buffer data + * @param format Sample format + * @param data Data + * @param frequency Frequency + * @return Reference to self (for method chaining) + * + * @see @fn_al{BufferData} + */ + Buffer& setData(Format format, Containers::ArrayReference data, ALsizei frequency) { + alBufferData(_id, ALenum(format), data, data.size(), frequency); + return *this; + } + + private: + ALuint _id; +}; + +/** @debugoperator{Magnum::Audio::Buffer} */ +Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Buffer::Format value); + +inline Buffer::Buffer(Buffer&& other): _id(other._id) { + other._id = 0; +} + +inline Buffer& Buffer::operator=(Buffer&& other) { + std::swap(_id, other._id); + return *this; +} + +}} + +#endif diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index b5ea399a1..0c4691014 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -28,10 +28,12 @@ include_directories(${OPENAL_INCLUDE_DIR}) set(MagnumAudio_SOURCES Audio.cpp + Buffer.cpp Renderer.cpp) set(MagnumAudio_HEADERS Audio.h + Buffer.h Renderer.h magnumAudioVisibility.h) diff --git a/src/Audio/Test/BufferTest.cpp b/src/Audio/Test/BufferTest.cpp new file mode 100644 index 000000000..56c6f2ba9 --- /dev/null +++ b/src/Audio/Test/BufferTest.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 "Audio/Buffer.h" + +namespace Magnum { namespace Audio { namespace Test { + +class BufferTest: public TestSuite::Tester { + public: + explicit BufferTest(); + + void debugFormat(); +}; + +BufferTest::BufferTest() { + addTests({&BufferTest::debugFormat}); +} + +void BufferTest::debugFormat() { + std::ostringstream out; + Debug(&out) << Buffer::Format::Stereo16; + CORRADE_COMPARE(out.str(), "Audio::Buffer::Format::Stereo16\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::BufferTest) diff --git a/src/Audio/Test/CMakeLists.txt b/src/Audio/Test/CMakeLists.txt index 3a13c2df8..869f75ce7 100644 --- a/src/Audio/Test/CMakeLists.txt +++ b/src/Audio/Test/CMakeLists.txt @@ -22,4 +22,5 @@ # DEALINGS IN THE SOFTWARE. # +corrade_add_test(AudioBufferTest BufferTest.cpp LIBRARIES MagnumAudio) corrade_add_test(AudioRendererTest RendererTest.cpp LIBRARIES MagnumAudio) diff --git a/src/Buffer.h b/src/Buffer.h index 73163292e..65dbdf508 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. */ -/** @file +/** @file /Buffer.h * @brief Class Magnum::Buffer */ From fdf878d4586393d1425e34b9f30eb1e9015c6db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 11:17:31 +0200 Subject: [PATCH 19/64] Audio: added Source class. --- src/Audio/Audio.h | 1 + src/Audio/CMakeLists.txt | 4 +- src/Audio/Source.cpp | 123 +++++++ src/Audio/Source.h | 596 ++++++++++++++++++++++++++++++++++ src/Audio/Test/CMakeLists.txt | 1 + src/Audio/Test/SourceTest.cpp | 51 +++ 6 files changed, 775 insertions(+), 1 deletion(-) create mode 100644 src/Audio/Source.cpp create mode 100644 src/Audio/Source.h create mode 100644 src/Audio/Test/SourceTest.cpp diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h index c02b8d6be..5fc044cd0 100644 --- a/src/Audio/Audio.h +++ b/src/Audio/Audio.h @@ -31,6 +31,7 @@ namespace Magnum { namespace Audio { class Buffer; +class Source; /* Renderer used only statically */ }} diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index 0c4691014..eeafc6e22 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -29,12 +29,14 @@ include_directories(${OPENAL_INCLUDE_DIR}) set(MagnumAudio_SOURCES Audio.cpp Buffer.cpp - Renderer.cpp) + Renderer.cpp + Source.cpp) set(MagnumAudio_HEADERS Audio.h Buffer.h Renderer.h + Source.h magnumAudioVisibility.h) diff --git a/src/Audio/Source.cpp b/src/Audio/Source.cpp new file mode 100644 index 000000000..8eba148bc --- /dev/null +++ b/src/Audio/Source.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 "Source.h" + +#include "Audio/Buffer.h" + +namespace Magnum { namespace Audio { + +/** @todo C++14: use VLA to avoid unnecessary allocations */ + +Source& Source::setBuffer(Buffer* buffer) { + alSourcei(_id, AL_BUFFER, buffer ? buffer->id() : 0); + return *this; +} + +namespace { + +const ALuint* sourceIds(const std::initializer_list& sources) { + ALuint* const ids = new ALuint[sources.size()]; + for(auto it = sources.begin(); it != sources.end(); ++it) { + CORRADE_INTERNAL_ASSERT(*it); + ids[it-sources.begin()] = (*it)->id(); + } + return ids; +} + +const ALuint* sourceIds(const std::vector& sources) { + ALuint* const ids = new ALuint[sources.size()]; + for(auto it = sources.begin(); it != sources.end(); ++it) { + CORRADE_INTERNAL_ASSERT(*it); + ids[it-sources.begin()] = (*it)->id(); + } + return ids; +} + +} + +/** @todo Okay, this is too much code copying even for me */ + +void Source::play(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePlayv(sources.size(), ids); + delete[] ids; +} + +void Source::play(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePlayv(sources.size(), ids); + delete[] ids; +} + +void Source::pause(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePausev(sources.size(), ids); + delete[] ids; +} + +void Source::pause(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePausev(sources.size(), ids); + delete[] ids; +} + +void Source::stop(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourceStopv(sources.size(), ids); + delete[] ids; +} + +void Source::stop(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourceStopv(sources.size(), ids); + delete[] ids; +} + +void Source::rewind(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourceRewindv(sources.size(), ids); + delete[] ids; +} + +void Source::rewind(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourceRewindv(sources.size(), ids); + delete[] ids; +} + +Debug operator<<(Debug debug, const Source::State value) { + switch(value) { + #define _c(value) case Source::State::value: return debug << "Audio::Source::State::" #value; + _c(Initial) + _c(Playing) + _c(Paused) + _c(Stopped) + #undef _c + } + + return debug << "Audio::Source::State::(invalid)"; +} + +}} diff --git a/src/Audio/Source.h b/src/Audio/Source.h new file mode 100644 index 000000000..f96de05c1 --- /dev/null +++ b/src/Audio/Source.h @@ -0,0 +1,596 @@ +#ifndef Magnum_Audio_Source_h +#define Magnum_Audio_Source_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::Audio::Source + */ + +#include +#include +#include + +#include "Math/Vector3.h" +#include "Magnum.h" +#include "Audio/Audio.h" +#include "Audio/magnumAudioVisibility.h" + +namespace Magnum { namespace Audio { + +/** +@brief %Source + +Manages positional audio source. +@todo Expose convenient API for buffer queuing +*/ +class MAGNUM_AUDIO_EXPORT Source { + public: + /** + * @brief Constructor + * + * Creates OpenAL source object. + * @see @fn_al{GenSources} + */ + explicit Source() { alGenSources(1, &_id); } + + /** + * @brief Destructor + * + * Deletes OpenAL source object. + * @see @fn_al{DeleteSources} + */ + ~Source() { if(_id) alDeleteSources(1, &_id); } + + /** @brief Copying is not allowed */ + Source(const Source&) = delete; + + /** @brief Move constructor */ + Source(Source&& other); + + /** @brief Copying is not allowed */ + Source& operator=(const Source&) = delete; + + /** @brief Move assignment */ + Source& operator=(Source&& other); + + /** @brief OpenAL source ID */ + ALuint id() const { return _id; } + + /** @{ @name Source positioning */ + + /** + * @brief Set position + * @return Reference to self (for method chaining) + * + * Default is `{0.0f, 0.0f, 0.0f}`. + * @see @ref setRelative(), @fn_al{Sourcefv} with @def_al{POSITION} + */ + Source& setPosition(const Vector3& position) { + alSourcefv(_id, AL_POSITION, position.data()); + return *this; + } + + /** @overload + * @see @fn_al{Sourceiv} with @def_al{POSITION} + */ + Source& setPosition(const Vector3i& position) { + alSourceiv(_id, AL_POSITION, position.data()); + return *this; + } + + /** + * @brief Set velocity + * @return Reference to self (for method chaining) + * + * Default is `{0.0f, 0.0f, 0.0f}`. + * @see @ref setRelative(), @fn_al{Sourcefv} with @def_al{VELOCITY} + */ + Source& setVelocity(const Vector3& velocity) { + alSourcefv(_id, AL_VELOCITY, velocity.data()); + return *this; + } + + /** @overload + * @see @fn_al{Sourceiv} with @def_al{VELOCITY} + */ + Source& setVelocity(const Vector3i& velocity) { + alSourceiv(_id, AL_VELOCITY, velocity.data()); + return *this; + } + + /** + * @brief Interpret source relatively to listener + * + * When enabled, source position, direction and velocity will be + * interpreted relatively to listener. Default is `false`. + * @see @ref setPosition(), @ref setDirection(), @ref setVelocity(), + * @fn_al{Sourcei} with @def_al{SOURCE_RELATIVE} + */ + Source& setRelative(bool relative) { + alSourcei(_id, AL_SOURCE_RELATIVE, relative); + return *this; + } + + /*@}*/ + + /** @{ @name Source behavior */ + + /** + * @brief Set gain + * @return Reference to self (for method chaining) + * + * Default is `1.0f`, which means that the sound is unattenuated. + * If set to `0.0f`, the source is muted. + * @see @ref setMinGain(), @ref setMaxGain(), @fn_al{Sourcef} with + * @def_al{GAIN} + */ + Source& setGain(Float gain) { + alSourcef(_id, AL_GAIN, gain); + return *this; + } + + /** + * @brief Set min gain + * @return Reference to self (for method chaining) + * + * If effective gain is lower than min gain, min gain is used. Note + * that this is done before listener gain is applied. Default is + * `0.0f`. + * @see @ref setMinGain(), @ref setGain(), @fn_al{Sourcef} with + * @def_al{MIN_GAIN} + */ + Source& setMinGain(Float gain) { + alSourcef(_id, AL_MIN_GAIN, gain); + return *this; + } + + /** + * @brief Set max gain + * @return Reference to self (for method chaining) + * + * If effective gain is higher than max gain, max gain is used. Note + * that this is done before listener gain is applied. Default is + * `1.0f`. If set to `0.0f`, the source is muted. + * @see @ref setMinGain(), @ref setGain(), @fn_al{Sourcef} with + * @def_al{MIN_GAIN} + */ + Source& setMaxGain(Float gain) { + alSourcef(_id, AL_MAX_GAIN, gain); + return *this; + } + + /** + * @brief Set reference distance + * @return Reference to self (for method chaining) + * + * Default is `1.0f`. + * @see @ref setRolloffFactor(), @fn_al{Sourcef} with + * @def_al{REFERENCE_DISTANCE} + */ + Source& setReferenceDistance(Float distance) { + alSourcef(_id, AL_REFERENCE_DISTANCE, distance); + return *this; + } + + /** @overload + * @see @fn_al{Sourcei} with @def_al{REFERENCE_DISTANCE} + */ + Source& setReferenceDistance(Int distance) { + alSourcei(_id, AL_REFERENCE_DISTANCE, distance); + return *this; + } + + /** + * @brief Set rolloff factor + * @return Reference to self (for method chaining) + * + * Default is `1.0f`. + * @see @ref setReferenceDistance(), @fn_al{Sourcef} with + * @def_al{ROLLOFF_FACTOR} + */ + Source& setRolloffFactor(Float factor) { + alSourcef(_id, AL_ROLLOFF_FACTOR, factor); + return *this; + } + + /** @overload + * @see @fn_al{Sourcei} with @def_al{ROLLOFF_FACTOR} + */ + Source& setRolloffFactor(Int factor) { + alSourcei(_id, AL_ROLLOFF_FACTOR, factor); + return *this; + } + + /** + * @brief Set max distance + * @return Reference to self (for method chaining) + * + * Default is max representable value. + * @see @fn_al{Sourcef} with @def_al{MAX_DISTANCE} + */ + Source& setMaxDistance(Float distance) { + alSourcef(_id, AL_MAX_DISTANCE, distance); + return *this; + } + + /** @overload + * @see @fn_al{Sourcei} with @def_al{MAX_DISTANCE} + */ + Source& setMaxDistance(Int distance) { + alSourcef(_id, AL_MAX_DISTANCE, distance); + return *this; + } + + /** + * @brief Set direction + * @return Reference to self (for method chaining) + * + * Default is `{0.0f, 0.0f, 0.0f}`, which means that the source is not + * directional. + * @see @ref setInnerConeAngle(), @ref setOuterConeAngle(), + * @ref setRelative(), @fn_al{Sourcefv} with @def_al{DIRECTION} + */ + Source& setDirection(const Vector3& direction) { + alSourcefv(_id, AL_DIRECTION, direction.data()); + return *this; + } + + /** @overload + * @see @fn_al{Sourceiv} with @def_al{DIRECTION} + */ + Source& setDirection(const Vector3i& direction) { + alSourceiv(_id, AL_DIRECTION, direction.data()); + return *this; + } + + /** + * @brief Set inner cone angle + * @return Reference to self (for method chaining) + * + * Has effect only if the source is directional. Default is + * `360.0_degf`. + * @see @ref setOuterConeAngle(), @ref setDirection(), @fn_al{Sourcef} + * with @def_al{CONE_INNER_ANGLE} + */ + Source& setInnerConeAngle(Deg angle) { + alSourcef(_id, AL_CONE_INNER_ANGLE, Float(angle)); + return *this; + } + + /** + * @brief Set outer cone angle + * @return Reference to self (for method chaining) + * + * Has effect only if the source is directional. Default is + * `360.0_degf`. + * @see @ref setInnerConeAngle(), @ref setDirection(), + * @ref setOuterConeGain() @fn_al{Sourcef} with + * @def_al{CONE_OUTER_ANGLE} + */ + Source& setOuterConeAngle(Deg angle) { + alSourcef(_id, AL_CONE_OUTER_ANGLE, Float(angle)); + return *this; + } + + /** + * @brief Set outer cone gain multiplier + * @return Reference to self (for method chaining) + * + * The factor with which the gain is multiplied outside the outer cone. + * Default is `0.0f`. + * @see @ref setGain(), @ref setOuterConeAngle(), @fn_al{Sourcef} with + * @def_al{CONE_OUTER_GAIN} + */ + Source& setOuterConeGain(Float multiplier) { + alSourcef(_id, AL_CONE_OUTER_ANGLE, multiplier); + return *this; + } + + /** + * @brief Set pitch + * @return Reference to self (for method chaining) + * + * Default is `1.0f`. + * @see @fn_al{Sourcef} with @def_al{PITCH} + */ + Source& setPitch(Float pitch) { + alSourcef(_id, AL_PITCH, pitch); + return *this; + } + + /*@}*/ + + /** @{ @name Buffer management */ + + /** + * @brief %Source type + * + * @see @ref type() + */ + enum class Type: ALint { + Undetermined = AL_UNDETERMINED, /**< Undetermined (default) */ + Static = AL_STATIC, /**< Static source */ + Streaming = AL_STREAMING /**< Streaming source */ + }; + + /** + * @brief Source type + * + * @see @ref setBuffer(), @fn_al{GetSourcei} with @def_al{SOURCE_TYPE} + */ + Type type() const; + + /** + * @brief Attach buffer + * @param buffer Buffer to attach or `nullptr` + * @return Reference to self (for method chaining) + * + * If an buffer is attached, changes source type to + * @ref Type "Type::Static", if detached, changes source type to + * @ref Type "Type::Undetermined". The buffer must be already filled + * with data. + * @see @ref type(), @fn_al{Sourcei} with @def_al{BUFFER} + */ + Source& setBuffer(Buffer* buffer); + + /*@}*/ + + /** @{ @name State management */ + + /** + * @brief %Source state + * + * @see @ref state(), @ref play(), @ref pause(), @ref stop(), + * @ref rewind() + */ + enum class State: ALint { + Initial = AL_INITIAL, /**< Initial state (default) */ + Playing = AL_PLAYING, /**< The source is playing */ + Paused = AL_PAUSED, /**< The source is paused */ + Stopped = AL_STOPPED /**< The source is stopped */ + }; + + /** + * @brief Play more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref play(), @ref pause(std::initializer_list), + * @ref stop(std::initializer_list), + * @ref rewind(std::initializer_list), + * @fn_al{SourcePlayv} + */ + static void play(std::initializer_list sources); + static void play(const std::vector& sources); /**< @overload */ + + /** + * @brief Pause more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref pause(), @ref play(std::initializer_list), + * @ref stop(std::initializer_list), + * @ref rewind(std::initializer_list), + * @fn_al{SourcePausev} + */ + static void pause(std::initializer_list sources); + static void pause(const std::vector& sources); /**< @overload */ + + /** + * @brief Stop more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref stop(), @ref play(std::initializer_list), + * @ref pause(std::initializer_list), + * @ref rewind(std::initializer_list), + * @fn_al{SourceStopv} + */ + static void stop(std::initializer_list sources); + static void stop(const std::vector& sources); /**< @overload */ + + /** + * @brief Rewind more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref rewind(), @ref play(std::initializer_list), + * @ref pause(std::initializer_list), + * @ref stop(std::initializer_list), + * @fn_al{SourceRewindv} + */ + static void rewind(std::initializer_list sources); + static void rewind(const std::vector& sources); /**< @overload */ + + /** + * @brief State + * + * @see @ref play(), @ref pause(), @ref stop(), @ref rewind(), + * @fn_al{GetSourcei} with @def_al{SOURCE_STATE} + */ + State state() const; + + /** + * @brief Play + * + * @see @ref play(std::initializer_list), @ref state(), + * @ref pause(), @ref stop(), @ref rewind(), @fn_al{SourcePlay} + */ + void play() { alSourcePlay(_id); } + + /** + * @brief Pause + * + * @see @ref pause(std::initializer_list), @ref state(), + * @ref play(), @ref stop(), @ref rewind(), @fn_al{SourcePause} + */ + void pause() { alSourcePause(_id); } + + /** + * @brief Stop + * + * @see @ref stop(std::initializer_list), @ref state(), + * @ref play(), @ref pause(), @ref rewind(), @fn_al{SourceStop} + */ + void stop() { alSourceStop(_id); } + + /** + * @brief Rewind + * + * @see @ref rewind(std::initializer_list), @ref state(), + * @ref play(), @ref pause(), @ref stop(), @fn_al{SourceRewind} + */ + void rewind() { alSourceRewind(_id); } + + /** + * @brief Whether the source is looping + * + * @see @fn_al{GetSourcei} with @def_al{LOOPING} + */ + bool isLooping() const; + + /** + * @brief Set source looping + * @return Reference to self (for method chaining) + * + * Default is `false`. + * @see @fn_al{Sourcei} with @def_al{LOOPING} + */ + Source& setLooping(bool loop) { + alSourcei(_id, AL_LOOPING, loop); + return *this; + } + + /** + * @brief Offset in seconds + * + * @see @ref offsetInBytes(), @ref offsetInSamples(), + * @fn_al{GetSourcef} with @def_al{SEC_OFFSET} + */ + Float offsetInSeconds() const; + + /** + * @brief Set offset in seconds + * @return Reference to self (for method chaining) + * + * @see @ref setOffsetInBytes(), @ref setOffsetInSamples(), + * @fn_al{Sourcef} with @def_al{SEC_OFFSET} + */ + Source& setOffsetInSeconds(Float offset) { + alSourcef(_id, AL_SEC_OFFSET, offset); + return *this; + } + + /** + * @brief Offset in bytes + * + * @see @ref offsetInSeconds(), @ref offsetInSamples(), + * @fn_al{GetSourcei} with @def_al{BYTE_OFFSET} + */ + Int offsetInBytes() const; + + /** + * @brief Set offset in bytes + * @return Reference to self (for method chaining) + * + * @see @ref setOffsetInSeconds(), @ref setOffsetInSamples(), + * @fn_al{Sourcei} with @def_al{SEC_OFFSET} + */ + Source& setOffsetInBytes(Int offset) { + alSourcei(_id, AL_BYTE_OFFSET, offset); + return *this; + } + + /** + * @brief Offset in samples + * + * @see @ref offsetInSeconds(), @ref offsetInBytes(), + * @fn_al{GetSourcei} with @def_al{SAMPLE_OFFSET} + */ + Int offsetInSamples() const; + + /** + * @brief Set offset in samples + * @return Reference to self (for method chaining) + * + * @see @ref setOffsetInSeconds(), @ref setOffsetInBytes(), + * @fn_al{Sourcei} with @def_al{SEC_OFFSET} + */ + Source& setOffsetInSamples(Int offset) { + alSourcei(_id, AL_SAMPLE_OFFSET, offset); + return *this; + } + + /*@}*/ + + private: + ALuint _id; +}; + +/** @debugoperator{Magnum::Audio::Source} */ +Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Source::State value); + +inline Source::Source(Source&& other): _id(other._id) { + other._id = 0; +} + +inline Source& Source::operator=(Source&& other) { + std::swap(_id, other._id); + return *this; +} + +auto Source::state() const -> State { + ALint state; + alGetSourcei(_id, AL_SOURCE_STATE, &state); + return State(state); +} + +inline bool Source::isLooping() const { + ALint looping; + alGetSourcei(_id, AL_LOOPING, &looping); + return looping; +} + +inline Float Source::offsetInSeconds() const { + Float offset; + alGetSourcef(_id, AL_SEC_OFFSET, &offset); + return offset; +} + +inline Int Source::offsetInBytes() const { + Int offset; + alGetSourcei(_id, AL_BYTE_OFFSET, &offset); + return offset; +} + +inline Int Source::offsetInSamples() const { + Int offset; + alGetSourcei(_id, AL_SAMPLE_OFFSET, &offset); + return offset; +} + +}} + +#endif diff --git a/src/Audio/Test/CMakeLists.txt b/src/Audio/Test/CMakeLists.txt index 869f75ce7..c53624b53 100644 --- a/src/Audio/Test/CMakeLists.txt +++ b/src/Audio/Test/CMakeLists.txt @@ -24,3 +24,4 @@ corrade_add_test(AudioBufferTest BufferTest.cpp LIBRARIES MagnumAudio) corrade_add_test(AudioRendererTest RendererTest.cpp LIBRARIES MagnumAudio) +corrade_add_test(AudioSourceTest SourceTest.cpp LIBRARIES MagnumAudio) diff --git a/src/Audio/Test/SourceTest.cpp b/src/Audio/Test/SourceTest.cpp new file mode 100644 index 000000000..90424ce29 --- /dev/null +++ b/src/Audio/Test/SourceTest.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 "Audio/Source.h" + +namespace Magnum { namespace Audio { namespace Test { + +class SourceTest: public TestSuite::Tester { + public: + explicit SourceTest(); + + void debugState(); +}; + +SourceTest::SourceTest() { + addTests({&SourceTest::debugState}); +} + +void SourceTest::debugState() { + std::ostringstream out; + Debug(&out) << Source::State::Playing; + CORRADE_COMPARE(out.str(), "Audio::Source::State::Playing\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::SourceTest) From 95e1ae2efcfee48513c4c7f819cbf9e471056d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 19:15:58 +0200 Subject: [PATCH 20/64] Audio: added AbstractImporter plugin interface. --- modules/FindMagnum.cmake | 6 + src/Audio/AbstractImporter.cpp | 97 ++++++++++++++ src/Audio/AbstractImporter.h | 163 ++++++++++++++++++++++++ src/Audio/Audio.h | 1 + src/Audio/CMakeLists.txt | 4 +- src/Audio/Test/AbstractImporterTest.cpp | 76 +++++++++++ src/Audio/Test/CMakeLists.txt | 6 + src/Audio/Test/file.bin | 1 + src/Audio/Test/testConfigure.h.cmake | 25 ++++ 9 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 src/Audio/AbstractImporter.cpp create mode 100644 src/Audio/AbstractImporter.h create mode 100644 src/Audio/Test/AbstractImporterTest.cpp create mode 100644 src/Audio/Test/file.bin create mode 100644 src/Audio/Test/testConfigure.h.cmake diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 0be6ab1b0..060f80595 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -15,6 +15,7 @@ # MAGNUM_PLUGINS_FONTCONVERTER_DIR - Directory with font converter plugins # MAGNUM_PLUGINS_IMAGECONVERTER_DIR - Directory with image converter plugins # MAGNUM_PLUGINS_IMPORTER_DIR - Directory with importer plugins +# MAGNUM_PLUGINS_AUDIOIMPORTER_DIR - Directory with audio importer plugins # This command will try to find only the base library, not the optional # components. The base library depends on Corrade, OpenGL and GLEW # libraries. Additional dependencies are specified by the components. The @@ -75,6 +76,8 @@ # installation directory # MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR - Importer plugin installation # directory +# MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR - Audio omporter plugin +# installation directory # MAGNUM_CMAKE_MODULE_INSTALL_DIR - Installation dir for CMake # modules # MAGNUM_INCLUDE_INSTALL_DIR - Header installation directory @@ -343,6 +346,7 @@ set(MAGNUM_PLUGINS_FONT_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fonts) set(MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fontconverters) set(MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/imageconverters) set(MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/importers) +set(MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/audioimporters) set(MAGNUM_CMAKE_MODULE_INSTALL_DIR ${CMAKE_ROOT}/Modules) set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum) set(MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum/Plugins) @@ -355,6 +359,7 @@ mark_as_advanced(FORCE MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR + MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR MAGNUM_CMAKE_MODULE_INSTALL_DIR MAGNUM_INCLUDE_INSTALL_DIR MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR) @@ -367,3 +372,4 @@ set(MAGNUM_PLUGINS_FONT_DIR ${MAGNUM_PLUGINS_DIR}/fonts) set(MAGNUM_PLUGINS_FONTCONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/fontconverters) set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/imageconverters) set(MAGNUM_PLUGINS_IMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/importers) +set(MAGNUM_PLUGINS_AUDIOIMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/audioimporters) diff --git a/src/Audio/AbstractImporter.cpp b/src/Audio/AbstractImporter.cpp new file mode 100644 index 000000000..2e0ced0e3 --- /dev/null +++ b/src/Audio/AbstractImporter.cpp @@ -0,0 +1,97 @@ +/* + 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 "AbstractImporter.h" + +#include +#include +#include + +namespace Magnum { namespace Audio { + +AbstractImporter::AbstractImporter() = default; + +AbstractImporter::AbstractImporter(PluginManager::AbstractManager* manager, std::string plugin): PluginManager::AbstractPlugin(manager, std::move(plugin)) {} + +bool AbstractImporter::openData(Containers::ArrayReference data) { + CORRADE_ASSERT(features() & Feature::OpenData, + "Audio::AbstractImporter::openData(): feature not supported", nullptr); + + close(); + doOpenData(data); + return isOpened(); +} + +void AbstractImporter::doOpenData(Containers::ArrayReference) { + CORRADE_ASSERT(false, "Audio::AbstractImporter::openData(): feature advertised but not implemented", ); +} + +bool AbstractImporter::openFile(const std::string& filename) { + close(); + doOpenFile(filename); + return isOpened(); +} + +void AbstractImporter::doOpenFile(const std::string& filename) { + CORRADE_ASSERT(features() & Feature::OpenData, "Audio::AbstractImporter::openFile(): not implemented", ); + + /* Open file */ + std::ifstream in(filename.data(), std::ios::binary); + if(!in.good()) { + Error() << "Trade::AbstractImporter::openFile(): cannot open file" << filename; + return; + } + + /* Create array to hold file contents */ + in.seekg(0, std::ios::end); + Containers::Array data(in.tellg()); + + /* Read data, close */ + in.seekg(0, std::ios::beg); + in.read(reinterpret_cast(data.begin()), data.size()); + in.close(); + + doOpenData(data); +} + +void AbstractImporter::close() { + if(isOpened()) doClose(); +} + +Buffer::Format AbstractImporter::format() const { + CORRADE_ASSERT(isOpened(), "Audio::AbstractImporter::format(): no file opened", {}); + return doFormat(); +} + +UnsignedInt AbstractImporter::frequency() const { + CORRADE_ASSERT(isOpened(), "Audio::AbstractImporter::frequency(): no file opened", {}); + return doFrequency(); +} + +Containers::Array AbstractImporter::data() { + CORRADE_ASSERT(isOpened(), "Audio::AbstractImporter::data(): no file opened", {}); + return doData(); +} + +}} diff --git a/src/Audio/AbstractImporter.h b/src/Audio/AbstractImporter.h new file mode 100644 index 000000000..9e49fc8bf --- /dev/null +++ b/src/Audio/AbstractImporter.h @@ -0,0 +1,163 @@ +#ifndef Magnum_Audio_AbstractImporter_h +#define Magnum_Audio_AbstractImporter_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 Audio/AbstractImporter.h + * @brief Class Magnum::Audio::AbstractImporter + */ + +#include + +#include "Magnum.h" +#include "Audio/Buffer.h" + +namespace Magnum { namespace Audio { + +/** +@brief Base for audio importer plugins + +@section Audio-AbstractImporter-subclassing Subclassing + +Plugin implements function doFeatures(), doIsOpened(), one of or both +doOpenData() and doOpenFile() functions, function doClose() and data access +functions doFormat(), doFrequency() and doData(). + +You don't need to do most of the redundant sanity checks, these things are +checked by the implementation: + +- Functions doOpenData() and doOpenFile() are called after the previous file + was closed, function doClose() is called only if there is any file opened. +- Function doOpenData() is called only if @ref Feature "Feature::OpenData" + is supported. +- All `do*()` implementations working on opened file are called only if + there is any file opened. +*/ +class MAGNUM_AUDIO_EXPORT AbstractImporter: public PluginManager::AbstractPlugin { + CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Audio.AbstractImporter/0.1") + + public: + /** + * @brief Features supported by this importer + * + * @see Features, features() + */ + enum class Feature: UnsignedByte { + /** Opening files from raw data using openData() */ + OpenData = 1 << 0 + }; + + /** + * @brief Features supported by this importer + * + * @see features() + */ + typedef Containers::EnumSet Features; + + /** @brief Default constructor */ + explicit AbstractImporter(); + + /** @brief Plugin manager constructor */ + explicit AbstractImporter(PluginManager::AbstractManager* manager, std::string plugin); + + /** @brief Features supported by this importer */ + Features features() const { return doFeatures(); } + + /** @brief Whether any file is opened */ + bool isOpened() const { return doIsOpened(); } + + /** + * @brief Open raw data + * + * Closes previous file, if it was opened, and tries to open given + * file. Available only if @ref Feature "Feature::OpenData" is + * supported. Returns `true` on success, `false` otherwise. + * @see features(), openFile() + */ + bool openData(Containers::ArrayReference data); + + /** + * @brief Open file + * + * Closes previous file, if it was opened, and tries to open given + * file. Returns `true` on success, `false` otherwise. + * @see features(), openData() + */ + bool openFile(const std::string& filename); + + /** @brief Close file */ + void close(); + + /** @{ @name Data access */ + + /** @brief Sample format */ + Buffer::Format format() const; + + /** @brief Sample frequency */ + UnsignedInt frequency() const; + + /** @brief Sample data */ + Containers::Array data(); + + /*@}*/ + + #ifndef DOXYGEN_GENERATING_OUTPUT + private: + #else + protected: + #endif + /** @brief Implementation for features() */ + virtual Features doFeatures() const = 0; + + /** @brief Implementation for isOpened() */ + virtual bool doIsOpened() const = 0; + + /** @brief Implementation for openData() */ + virtual void doOpenData(Containers::ArrayReference data); + + /** + * @brief Implementation for openFile() + * + * If @ref Feature "Feature::OpenData" is supported, default + * implementation opens the file and calls doOpenData() with its + * contents. + */ + virtual void doOpenFile(const std::string& filename); + + /** @brief Implementation for close() */ + virtual void doClose() = 0; + + /** @brief Implementation for format() */ + virtual Buffer::Format doFormat() const = 0; + + /** @brief Implementation for frequency() */ + virtual UnsignedInt doFrequency() const = 0; + + /** @brief Implementation for data() */ + virtual Containers::Array doData() = 0; +}; + +}} + +#endif diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h index 5fc044cd0..fb332b3c4 100644 --- a/src/Audio/Audio.h +++ b/src/Audio/Audio.h @@ -30,6 +30,7 @@ namespace Magnum { namespace Audio { +class AbstractImporter; class Buffer; class Source; /* Renderer used only statically */ diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index eeafc6e22..ee770a512 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -27,12 +27,14 @@ find_package(OpenAL REQUIRED) include_directories(${OPENAL_INCLUDE_DIR}) set(MagnumAudio_SOURCES + AbstractImporter.cpp Audio.cpp Buffer.cpp Renderer.cpp Source.cpp) set(MagnumAudio_HEADERS + AbstractImporter.h Audio.h Buffer.h Renderer.h @@ -41,7 +43,7 @@ set(MagnumAudio_HEADERS magnumAudioVisibility.h) add_library(MagnumAudio ${SHARED_OR_STATIC} ${MagnumAudio_SOURCES}) -target_link_libraries(MagnumAudio ${OPENAL_LIBRARY}) +target_link_libraries(MagnumAudio ${CORRADE_PLUGINMANAGER_LIBRARIES} ${OPENAL_LIBRARY}) install(TARGETS MagnumAudio DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(FILES ${MagnumAudio_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Audio) diff --git a/src/Audio/Test/AbstractImporterTest.cpp b/src/Audio/Test/AbstractImporterTest.cpp new file mode 100644 index 000000000..ff479d654 --- /dev/null +++ b/src/Audio/Test/AbstractImporterTest.cpp @@ -0,0 +1,76 @@ +/* + 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 "Audio/AbstractImporter.h" + +#include "testConfigure.h" + +namespace Magnum { namespace Audio { namespace Test { + +class AbstractImporterTest: public TestSuite::Tester { + public: + explicit AbstractImporterTest(); + + void openFile(); +}; + +AbstractImporterTest::AbstractImporterTest() { + addTests({&AbstractImporterTest::openFile}); +} + +void AbstractImporterTest::openFile() { + class DataImporter: public Audio::AbstractImporter { + public: + explicit DataImporter(): opened(false) {} + + private: + Features doFeatures() const override { return Feature::OpenData; } + bool doIsOpened() const override { return opened; } + void doClose() override {} + + void doOpenData(Containers::ArrayReference data) override { + opened = (data.size() == 1 && data[0] == 0xa5); + } + + Buffer::Format doFormat() const override { return {}; } + UnsignedInt doFrequency() const override { return {}; } + Corrade::Containers::Array doData() override { return nullptr; } + + bool opened; + }; + + /* doOpenFile() should call doOpenData() */ + DataImporter importer; + CORRADE_VERIFY(!importer.isOpened()); + importer.openFile(Utility::Directory::join(AUDIO_TEST_DIR, "file.bin")); + CORRADE_VERIFY(importer.isOpened()); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::AbstractImporterTest) diff --git a/src/Audio/Test/CMakeLists.txt b/src/Audio/Test/CMakeLists.txt index c53624b53..3a42d1f27 100644 --- a/src/Audio/Test/CMakeLists.txt +++ b/src/Audio/Test/CMakeLists.txt @@ -22,6 +22,12 @@ # DEALINGS IN THE SOFTWARE. # +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testConfigure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/testConfigure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(AudioAbstractImporterTest AbstractImporterTest.cpp LIBRARIES MagnumAudio) corrade_add_test(AudioBufferTest BufferTest.cpp LIBRARIES MagnumAudio) corrade_add_test(AudioRendererTest RendererTest.cpp LIBRARIES MagnumAudio) corrade_add_test(AudioSourceTest SourceTest.cpp LIBRARIES MagnumAudio) diff --git a/src/Audio/Test/file.bin b/src/Audio/Test/file.bin new file mode 100644 index 000000000..dd6737691 --- /dev/null +++ b/src/Audio/Test/file.bin @@ -0,0 +1 @@ +¥ \ No newline at end of file diff --git a/src/Audio/Test/testConfigure.h.cmake b/src/Audio/Test/testConfigure.h.cmake new file mode 100644 index 000000000..29272db06 --- /dev/null +++ b/src/Audio/Test/testConfigure.h.cmake @@ -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. +*/ + +#define AUDIO_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" From 92b8d7fb0b202400da46edbba9e8c74d322694e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 19:20:37 +0200 Subject: [PATCH 21/64] Audio: added Context class. --- src/Audio/Audio.h | 1 + src/Audio/CMakeLists.txt | 2 + src/Audio/Context.cpp | 65 +++++++++++++++++++++++++++ src/Audio/Context.h | 95 ++++++++++++++++++++++++++++++++++++++++ src/Context.h | 2 +- 5 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/Audio/Context.cpp create mode 100644 src/Audio/Context.h diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h index fb332b3c4..7fd001759 100644 --- a/src/Audio/Audio.h +++ b/src/Audio/Audio.h @@ -32,6 +32,7 @@ namespace Magnum { namespace Audio { class AbstractImporter; class Buffer; +class Context; class Source; /* Renderer used only statically */ diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index ee770a512..ba125c954 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -30,6 +30,7 @@ set(MagnumAudio_SOURCES AbstractImporter.cpp Audio.cpp Buffer.cpp + Context.cpp Renderer.cpp Source.cpp) @@ -37,6 +38,7 @@ set(MagnumAudio_HEADERS AbstractImporter.h Audio.h Buffer.h + Context.h Renderer.h Source.h diff --git a/src/Audio/Context.cpp b/src/Audio/Context.cpp new file mode 100644 index 000000000..86af094de --- /dev/null +++ b/src/Audio/Context.cpp @@ -0,0 +1,65 @@ +/* + 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 "Context.h" + +#include +#include +#include + +#include "Magnum.h" + +namespace Magnum { namespace Audio { + +Context* Context::_current = nullptr; + +Context::Context() { + CORRADE_ASSERT(!_current, "Audio::Context: context already created", ); + + /* Open default device */ + const ALCchar* const defaultDevice = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + _device = alcOpenDevice(defaultDevice); + if(!_device) { + Error() << "Audio::Context: cannot open sound device" << defaultDevice; + std::exit(1); + } + + _context = alcCreateContext(_device, nullptr); + if(!_context) { + Error() << "Audio::Context: cannot create context:" << alcGetError(_device); + std::exit(1); + } + + alcMakeContextCurrent(_context); + _current = this; +} + +Context::~Context() { + CORRADE_INTERNAL_ASSERT(_current == this); + + alcDestroyContext(_context); + alcCloseDevice(_device); +} + +}} diff --git a/src/Audio/Context.h b/src/Audio/Context.h new file mode 100644 index 000000000..b28bba470 --- /dev/null +++ b/src/Audio/Context.h @@ -0,0 +1,95 @@ +#ifndef Magnum_Audio_Context_h +#define Magnum_Audio_Context_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::Audio::Context + */ + +#include +#include + +#include "Audio/magnumAudioVisibility.h" + +#ifndef DOXYGEN_GENERATING_OUTPUT +typedef struct ALCdevice_struct ALCdevice; +typedef struct ALCcontext_struct ALCcontext; +#endif + +namespace Magnum { namespace Audio { + +/** +@brief OpenAL context + */ +class MAGNUM_AUDIO_EXPORT Context { + public: + /** @brief Current context */ + static Context* current() { return _current; } + + /** + * @brief Constructor + * + * Creates OpenAL context. + */ + explicit Context(); + + /** + * @brief Destructor + * + * Destroys OpenAL context. + */ + ~Context(); + + /** + * @brief Vendor string + * + * @see rendererString(), @fn_al{GetString} with @def_al{VENDOR} + */ + std::string vendorString() const { return alGetString(AL_VENDOR); } + + /** + * @brief %Renderer string + * + * @see vendorString(), @fn_al{GetString} with @def_al{RENDERER} + */ + std::string rendererString() const { return alGetString(AL_RENDERER); } + + /** + * @brief Version string + * + * @see @fn_al{GetString} with @def_al{VERSION} + */ + std::string versionString() const { return alGetString(AL_VERSION); } + + private: + static Context* _current; + + ALCdevice* _device; + ALCcontext* _context; +}; + +}} + +#endif diff --git a/src/Context.h b/src/Context.h index 018f8ffcf..b38aa0a88 100644 --- a/src/Context.h +++ b/src/Context.h @@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. */ -/** @file +/** @file /Context.h * @brief Enum Magnum::Version, class Magnum::Context, Magnum::Extension, macro MAGNUM_ASSERT_VERSION_SUPPORTED(), MAGNUM_ASSERT_EXTENSION_SUPPORTED() */ From ba72a563090b53cb60c2dc4206ce46bc7653347c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 8 Aug 2013 11:41:32 +0200 Subject: [PATCH 22/64] Primitives: using half length for Capsule primitive. --- src/Primitives/Capsule.cpp | 20 ++++++++++---------- src/Primitives/Capsule.h | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Primitives/Capsule.cpp b/src/Primitives/Capsule.cpp index 50885b3bd..8699c21a4 100644 --- a/src/Primitives/Capsule.cpp +++ b/src/Primitives/Capsule.cpp @@ -31,14 +31,14 @@ namespace Magnum { namespace Primitives { -Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords) { +Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, TextureCoords textureCoords) { CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 3, "Capsule must have at least one hemisphere ring, one cylinder ring and three segments", Trade::MeshData3D(Mesh::Primitive::Triangles, {}, {}, {}, {})); Implementation::Spheroid capsule(segments, textureCoords == TextureCoords::Generate ? Implementation::Spheroid::TextureCoords::Generate : Implementation::Spheroid::TextureCoords::DontGenerate); - Float height = 2.0f+length; + Float height = 2.0f+2.0f*halfLength; Float hemisphereTextureCoordsVIncrement = 1.0f/(hemisphereRings*height); Rad hemisphereRingAngleIncrement(Constants::pi()/(2*hemisphereRings)); @@ -46,13 +46,13 @@ Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylind capsule.capVertex(-height/2, -1.0f, 0.0f); /* Rings of bottom hemisphere */ - capsule.hemisphereVertexRings(hemisphereRings-1, -length/2, -Rad(Constants::pi())/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); + capsule.hemisphereVertexRings(hemisphereRings-1, -halfLength, -Rad(Constants::pi())/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); /* Rings of cylinder */ - capsule.cylinderVertexRings(cylinderRings+1, -length/2, length/cylinderRings, 1.0f/height, length/(cylinderRings*height)); + capsule.cylinderVertexRings(cylinderRings+1, -halfLength, 2.0f*halfLength/cylinderRings, 1.0f/height, 2.0f*halfLength/(cylinderRings*height)); /* Rings of top hemisphere */ - capsule.hemisphereVertexRings(hemisphereRings-1, length/2, hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, (1.0f + length)/height+hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); + capsule.hemisphereVertexRings(hemisphereRings-1, halfLength, hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, (1.0f + 2.0f*halfLength)/height+hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); /* Top cap vertex */ capsule.capVertex(height/2, 1.0f, 1.0f); @@ -65,23 +65,23 @@ Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylind return capsule.finalize(); } -Trade::MeshData3D Capsule::wireframe(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float length) { +Trade::MeshData3D Capsule::wireframe(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength) { CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 4 && segments%4 == 0, "Primitives::Capsule::wireframe(): improper parameters", Trade::MeshData3D(Mesh::Primitive::Lines, {}, {}, {}, {})); Implementation::WireframeSpheroid capsule(segments/4); /* Bottom hemisphere */ - capsule.bottomHemisphere(-length/2, hemisphereRings); + capsule.bottomHemisphere(-halfLength, hemisphereRings); /* Cylinder */ - capsule.ring(-length/2); + capsule.ring(-halfLength); for(UnsignedInt i = 0; i != cylinderRings; ++i) { capsule.cylinder(); - capsule.ring(-length/2 + (i+1)*(length/cylinderRings)); + capsule.ring(-halfLength + (i+1)*(2.0f*halfLength/cylinderRings)); } /* Top hemisphere */ - capsule.topHemisphere(length/2, hemisphereRings); + capsule.topHemisphere(halfLength, hemisphereRings); return capsule.finalize(); } diff --git a/src/Primitives/Capsule.h b/src/Primitives/Capsule.h index bf9195aed..d5ab50416 100644 --- a/src/Primitives/Capsule.h +++ b/src/Primitives/Capsule.h @@ -54,14 +54,14 @@ class MAGNUM_PRIMITIVES_EXPORT Capsule { * larger or equal to 1. * @param segments Number of (face) segments. Must be larger or * equal to 3. - * @param length Length of the capsule, excluding hemispheres. + * @param halfLength Half the length of cylinder part * @param textureCoords Whether to generate texture coordinates. * * Indexed @ref Mesh::Primitive "Triangles" with normals and optional * 2D texture coordinates. If texture coordinates are generated, * vertices of one segment are duplicated for texture wrapping. */ - static Trade::MeshData3D solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords = TextureCoords::DontGenerate); + static Trade::MeshData3D solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, TextureCoords textureCoords = TextureCoords::DontGenerate); /** * @brief Wireframe capsule @@ -71,11 +71,11 @@ class MAGNUM_PRIMITIVES_EXPORT Capsule { * larger or equal to 1. * @param segments Number of line segments. Must be larger or * equal to 4 and multiple of 4. - * @param length Length of the capsule, excluding hemispheres. + * @param halfLength Half the length of cylinder part * * Indexed @ref Mesh::Primitive "Lines". */ - static Trade::MeshData3D wireframe(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length); + static Trade::MeshData3D wireframe(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength); }; }} From 51e262848687f793927980c51a7c0b3adca79837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 17 Aug 2013 23:18:03 +0200 Subject: [PATCH 23/64] Primitives: test Capsule with more cylinder segments. Testing two face segments is not enough, as _exactly two_ vertex rings are part of both the cylinder and cap hemispheres. --- src/Primitives/Test/CapsuleTest.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Primitives/Test/CapsuleTest.cpp b/src/Primitives/Test/CapsuleTest.cpp index 77e7be8e3..6a8670ab2 100644 --- a/src/Primitives/Test/CapsuleTest.cpp +++ b/src/Primitives/Test/CapsuleTest.cpp @@ -50,7 +50,7 @@ CapsuleTest::CapsuleTest() { } void CapsuleTest::solidWithoutTextureCoords() { - Trade::MeshData3D capsule = Capsule::solid(2, 2, 3, 1.0f); + Trade::MeshData3D capsule = Capsule::solid(2, 4, 3, 1.0f); CORRADE_COMPARE_AS(capsule.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, @@ -63,10 +63,18 @@ void CapsuleTest::solidWithoutTextureCoords() { {0.866025f, -0.5f, -0.5f}, {-0.866025f, -0.5f, -0.5f}, + {0.0f, -0.25f, 1.0f}, + {0.866025f, -0.25f, -0.5f}, + {-0.866025f, -0.25f, -0.5f}, + {0.0f, 0.0f, 1.0f}, {0.866025f, 0.0f, -0.5f}, {-0.866025f, 0.0f, -0.5f}, + {0.0f, 0.25f, 1.0f}, + {0.866025f, 0.25f, -0.5f}, + {-0.866025f, 0.25f, -0.5f}, + {0.0f, 0.5f, 1.0f}, {0.866025f, 0.5f, -0.5f}, {-0.866025f, 0.5f, -0.5f}, @@ -97,6 +105,14 @@ void CapsuleTest::solidWithoutTextureCoords() { {0.866025f, 0.0f, -0.5f}, {-0.866025f, 0.0f, -0.5f}, + {0.0f, 0.0f, 1.0f}, + {0.866025f, 0.0f, -0.5f}, + {-0.866025f, 0.0f, -0.5f}, + + {0.0f, 0.0f, 1.0f}, + {0.866025f, 0.0f, -0.5f}, + {-0.866025f, 0.0f, -0.5f}, + {0.0f, 0.707107f, 0.707107f}, {0.612372f, 0.707107f, -0.353553f}, {-0.612372f, 0.707107f, -0.353553f}, @@ -110,7 +126,9 @@ void CapsuleTest::solidWithoutTextureCoords() { 4, 5, 8, 4, 8, 7, 5, 6, 9, 5, 9, 8, 6, 4, 7, 6, 7, 9, 7, 8, 11, 7, 11, 10, 8, 9, 12, 8, 12, 11, 9, 7, 10, 9, 10, 12, 10, 11, 14, 10, 14, 13, 11, 12, 15, 11, 15, 14, 12, 10, 13, 12, 13, 15, - 13, 14, 16, 14, 15, 16, 15, 13, 16 + 13, 14, 17, 13, 17, 16, 14, 15, 18, 14, 18, 17, 15, 13, 16, 15, 16, 18, + 16, 17, 20, 16, 20, 19, 17, 18, 21, 17, 21, 20, 18, 16, 19, 18, 19, 21, + 19, 20, 22, 20, 21, 22, 21, 19, 22 }), TestSuite::Compare::Container); } From 3c75ba77482beed5b317e40e9db9fc69fc262533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 8 Aug 2013 11:42:11 +0200 Subject: [PATCH 24/64] Primitives: 2D capsule primitive. Will be used for shape debug rendering. --- src/Primitives/Capsule.cpp | 61 +++++++++++++++++++++++- src/Primitives/Capsule.h | 22 ++++++++- src/Primitives/Test/CapsuleTest.cpp | 72 ++++++++++++++++++++++++----- 3 files changed, 140 insertions(+), 15 deletions(-) diff --git a/src/Primitives/Capsule.cpp b/src/Primitives/Capsule.cpp index 8699c21a4..852d23b8c 100644 --- a/src/Primitives/Capsule.cpp +++ b/src/Primitives/Capsule.cpp @@ -25,13 +25,70 @@ #include "Capsule.h" #include "Math/Vector3.h" +#include "Math/Functions.h" #include "Primitives/Implementation/Spheroid.h" #include "Primitives/Implementation/WireframeSpheroid.h" +#include "Trade/MeshData2D.h" #include "Trade/MeshData3D.h" namespace Magnum { namespace Primitives { -Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, TextureCoords textureCoords) { +Trade::MeshData2D Capsule2D::wireframe(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, Float halfLength) { + CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1, "Capsule must have at least one hemisphere ring, one cylinder ring and three segments", Trade::MeshData2D(Mesh::Primitive::Lines, {}, {}, {})); + + std::vector positions; + positions.reserve(hemisphereRings*4+2+(cylinderRings-1)*2); + const Rad angleIncrement(Constants::pi()/(2.0f*hemisphereRings)); + const Float cylinderIncrement = 2.0f*halfLength/cylinderRings; + + /* Bottom cap vertex */ + positions.emplace_back(0.0f, -halfLength-1.0f); + + /* Bottom hemisphere */ + for(UnsignedInt i = 0; i != hemisphereRings; ++i) { + const Rad angle((i+1)*angleIncrement); + const Float x = Math::sin(angle); + const Float y = -Math::cos(angle)-halfLength; + positions.insert(positions.end(), {{-x, y}, {x, y}}); + } + + /* Cylinder (bottom and top vertices are done within caps */ + for(UnsignedInt i = 0; i != cylinderRings-1; ++i) { + const Float y = (i+1)*cylinderIncrement-halfLength; + positions.insert(positions.end(), {{-1.0f, y}, {1.0f, y}}); + } + + /* Top hemisphere */ + for(UnsignedInt i = 0; i != hemisphereRings; ++i) { + const Rad angle(i*angleIncrement); + const Float x = Math::cos(angle); + const Float y = Math::sin(angle)+halfLength; + positions.insert(positions.end(), {{-x, y}, {x, y}}); + } + + /* Top cap vertex */ + positions.emplace_back(0.0f, halfLength+1.0f); + + std::vector indices; + indices.reserve(hemisphereRings*8+cylinderRings*4); + + /* Bottom cap indices */ + indices.insert(indices.end(), {0, 1, 0, 2}); + + /* Side indices */ + for(UnsignedInt i = 0; i != cylinderRings+hemisphereRings*2-2; ++i) + indices.insert(indices.end(), {i*2+1, i*2+3, + i*2+2, i*2+4}); + + /* Top cap indices */ + indices.insert(indices.end(), + {UnsignedInt(positions.size())-3, UnsignedInt(positions.size())-1, + UnsignedInt(positions.size())-2, UnsignedInt(positions.size())-1}); + + return Trade::MeshData2D(Mesh::Primitive::Lines, std::move(indices), {std::move(positions)}, {}); +} + +Trade::MeshData3D Capsule3D::solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, TextureCoords textureCoords) { CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 3, "Capsule must have at least one hemisphere ring, one cylinder ring and three segments", Trade::MeshData3D(Mesh::Primitive::Triangles, {}, {}, {}, {})); Implementation::Spheroid capsule(segments, textureCoords == TextureCoords::Generate ? @@ -65,7 +122,7 @@ Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylind return capsule.finalize(); } -Trade::MeshData3D Capsule::wireframe(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength) { +Trade::MeshData3D Capsule3D::wireframe(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength) { CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 4 && segments%4 == 0, "Primitives::Capsule::wireframe(): improper parameters", Trade::MeshData3D(Mesh::Primitive::Lines, {}, {}, {}, {})); Implementation::WireframeSpheroid capsule(segments/4); diff --git a/src/Primitives/Capsule.h b/src/Primitives/Capsule.h index d5ab50416..64adb1dbd 100644 --- a/src/Primitives/Capsule.h +++ b/src/Primitives/Capsule.h @@ -33,12 +33,32 @@ namespace Magnum { namespace Primitives { +/** +@brief 2D capsule primitive + +%Cylinder of radius `1` along Y axis with hemispheres instead of caps. +*/ +class MAGNUM_PRIMITIVES_EXPORT Capsule2D { + public: + /** + * @brief Wireframe capsule + * @param hemisphereRings Number of (line) rings for each hemisphere. + * Must be larger or equal to 1. + * @param cylinderRings Number of (line) rings for cylinder. Must be + * larger or equal to 1. + * @param halfLength Half the length of cylinder part + * + * Indexed @ref Mesh::Primitive "Lines". + */ + static Trade::MeshData2D wireframe(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, Float halfLength); +}; + /** @brief 3D capsule primitive %Cylinder of radius `1` along Y axis with hemispheres instead of caps. */ -class MAGNUM_PRIMITIVES_EXPORT Capsule { +class MAGNUM_PRIMITIVES_EXPORT Capsule3D { public: /** @brief Whether to generate texture coordinates */ enum class TextureCoords: UnsignedByte { diff --git a/src/Primitives/Test/CapsuleTest.cpp b/src/Primitives/Test/CapsuleTest.cpp index 6a8670ab2..23efaba1e 100644 --- a/src/Primitives/Test/CapsuleTest.cpp +++ b/src/Primitives/Test/CapsuleTest.cpp @@ -29,6 +29,7 @@ #include #include "Math/Vector3.h" +#include "Trade/MeshData2D.h" #include "Trade/MeshData3D.h" #include "Primitives/Capsule.h" @@ -38,19 +39,66 @@ class CapsuleTest: public TestSuite::Tester { public: CapsuleTest(); - void solidWithoutTextureCoords(); - void solidWithTextureCoords(); - void wireframe(); + void wireframe2D(); + + void solid3DWithoutTextureCoords(); + void solid3DWithTextureCoords(); + void wireframe3D(); }; CapsuleTest::CapsuleTest() { - addTests({&CapsuleTest::solidWithoutTextureCoords, - &CapsuleTest::solidWithTextureCoords, - &CapsuleTest::wireframe}); + addTests({&CapsuleTest::wireframe2D, + &CapsuleTest::solid3DWithoutTextureCoords, + &CapsuleTest::solid3DWithTextureCoords, + &CapsuleTest::wireframe3D}); +} + +void CapsuleTest::wireframe2D() { + Trade::MeshData2D capsule = Capsule2D::wireframe(2, 4, 0.5f); + + CORRADE_COMPARE_AS(capsule.positions(0), (std::vector{ + {0.0f, -1.5f}, + + {-0.707107f, -1.20711f}, + {0.707107f, -1.20711f}, + + {-1.0f, -0.5f}, + {1.0f, -0.5f}, + + {-1.0f, -0.25f}, + {1.0f, -0.25f}, + + {-1.0f, 0.0f}, + {1.0f, 0.0f}, + + {-1.0f, 0.25f}, + {1.0f, 0.25f}, + + {-1.0f, 0.5f}, + {1.0f, 0.5f}, + + {-0.707107f, 1.20711f}, + {0.707107f, 1.20711f}, + + {0.0f, 1.5f} + }), TestSuite::Compare::Container); + + CORRADE_COMPARE_AS(capsule.indices(), (std::vector{ + 0, 1, 0, 2, + + 1, 3, 2, 4, + 3, 5, 4, 6, + 5, 7, 6, 8, + 7, 9, 8, 10, + 9, 11, 10, 12, + 11, 13, 12, 14, + + 13, 15, 14, 15 + }), TestSuite::Compare::Container); } -void CapsuleTest::solidWithoutTextureCoords() { - Trade::MeshData3D capsule = Capsule::solid(2, 4, 3, 1.0f); +void CapsuleTest::solid3DWithoutTextureCoords() { + Trade::MeshData3D capsule = Capsule3D::solid(2, 4, 3, 0.5f); CORRADE_COMPARE_AS(capsule.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, @@ -132,8 +180,8 @@ void CapsuleTest::solidWithoutTextureCoords() { }), TestSuite::Compare::Container); } -void CapsuleTest::solidWithTextureCoords() { - Trade::MeshData3D capsule = Capsule::solid(2, 2, 3, 1.0f, Capsule::TextureCoords::Generate); +void CapsuleTest::solid3DWithTextureCoords() { + Trade::MeshData3D capsule = Capsule3D::solid(2, 2, 3, 0.5f, Capsule3D::TextureCoords::Generate); CORRADE_COMPARE_AS(capsule.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, @@ -207,8 +255,8 @@ void CapsuleTest::solidWithTextureCoords() { }), TestSuite::Compare::Container); } -void CapsuleTest::wireframe() { - Trade::MeshData3D capsule = Capsule::wireframe(2, 2, 8, 1.0f); +void CapsuleTest::wireframe3D() { + Trade::MeshData3D capsule = Capsule3D::wireframe(2, 2, 8, 0.5f); CORRADE_COMPARE_AS(capsule.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, From 39033d2480096c487fead1ce8d488378a8e21303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 8 Aug 2013 13:27:41 +0200 Subject: [PATCH 25/64] Added Mesh::drawInternal(). Exposes explicit draw parameters like vertex/index offset etc. --- src/Mesh.cpp | 14 +++++++------- src/Mesh.h | 7 +++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 4332cb6c6..1e613111d 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -136,25 +136,25 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi return *this; } -void Mesh::draw() { +void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount, Int indexStart, Int indexEnd) { /* Nothing to draw */ - if(!_vertexCount && !_indexCount) return; + if(!vertexCount && !indexCount) return; (this->*bindImplementation)(); /* Non-indexed mesh */ - if(!_indexCount) - glDrawArrays(static_cast(_primitive), 0, _vertexCount); + if(!indexCount) + glDrawArrays(static_cast(_primitive), firstVertex, 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)); + else if(indexEnd) + glDrawRangeElements(static_cast(_primitive), indexStart, indexEnd, indexCount, static_cast(_indexType), reinterpret_cast(indexOffset)); #endif /* Indexed mesh without specified range */ else - glDrawElements(static_cast(_primitive), _indexCount, static_cast(_indexType), reinterpret_cast(_indexOffset)); + glDrawElements(static_cast(_primitive), indexCount, static_cast(_indexType), reinterpret_cast(indexOffset)); (this->*unbindImplementation)(); } diff --git a/src/Mesh.h b/src/Mesh.h index 2a920e03a..19369e0a5 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -584,7 +584,9 @@ class MAGNUM_EXPORT Mesh { * or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object} * is available), @fn_gl{DrawArrays} or @fn_gl{DrawElements}/@fn_gl{DrawRangeElements}. */ - void draw(); + void draw() { + drawInternal(0, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + } private: #ifndef DOXYGEN_GENERATING_OUTPUT @@ -708,6 +710,8 @@ class MAGNUM_EXPORT Mesh { #endif #endif + void drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount, Int indexStart, Int indexEnd); + typedef void(Mesh::*CreateImplementation)(); void MAGNUM_LOCAL createImplementationDefault(); void MAGNUM_LOCAL createImplementationVAO(); @@ -792,7 +796,6 @@ template inline Mesh& Mesh::addVertexBuffer(Buffer& buffer, GLintptr return *this; } - } namespace Corrade { namespace Utility { From 0383b345d3f905c2c898807162ec2afb745f3a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 8 Aug 2013 13:29:02 +0200 Subject: [PATCH 26/64] Added convenience parameterless Mesh::indexType(). --- src/Mesh.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Mesh.h b/src/Mesh.h index 19369e0a5..bae5960c7 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -335,7 +335,11 @@ class MAGNUM_EXPORT Mesh { UnsignedInt = GL_UNSIGNED_INT }; - /** @brief Size of given index type */ + /** + * @brief Size of given index type + * + * @see indexSize() const + */ static std::size_t indexSize(IndexType type); /** @@ -362,6 +366,13 @@ class MAGNUM_EXPORT Mesh { /** @brief Move assignment */ Mesh& operator=(Mesh&& other); + /** + * @brief Index size + * + * @see indexSize(IndexType) + */ + std::size_t indexSize() const { return indexSize(_indexType); } + /** @brief Primitive type */ Primitive primitive() const { return _primitive; } From b29a68f25813060932a7f54f5e340ab4a1f5834e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 9 Aug 2013 16:58:02 +0200 Subject: [PATCH 27/64] Added MeshView class. Allows to use one mesh configuration for different views of the data (i.e. rendering object parts with different transformations). --- src/CMakeLists.txt | 2 + src/Magnum.h | 1 + src/Mesh.h | 1 + src/MeshView.cpp | 43 ++++++++++++++ src/MeshView.h | 139 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+) create mode 100644 src/MeshView.cpp create mode 100644 src/MeshView.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e92d2ea5..ed6b75071 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,6 +58,7 @@ set(Magnum_SRCS Image.cpp ImageFormat.cpp Mesh.cpp + MeshView.cpp OpenGL.cpp Query.cpp Renderbuffer.cpp @@ -117,6 +118,7 @@ set(Magnum_HEADERS ImageReference.h Magnum.h Mesh.h + MeshView.h OpenGL.h Query.h Renderbuffer.h diff --git a/src/Magnum.h b/src/Magnum.h index 13eeb2b92..231a93807 100644 --- a/src/Magnum.h +++ b/src/Magnum.h @@ -386,6 +386,7 @@ typedef ImageReference<2> ImageReference2D; typedef ImageReference<3> ImageReference3D; class Mesh; +class MeshView; /* AbstractQuery is not used directly */ class PrimitiveQuery; diff --git a/src/Mesh.h b/src/Mesh.h index bae5960c7..16859d610 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -240,6 +240,7 @@ for more information. */ class MAGNUM_EXPORT Mesh { friend class Context; + friend class MeshView; Mesh(const Mesh&) = delete; Mesh& operator=(const Mesh&) = delete; diff --git a/src/MeshView.cpp b/src/MeshView.cpp new file mode 100644 index 000000000..302f268e7 --- /dev/null +++ b/src/MeshView.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 "MeshView.h" + +#include "Mesh.h" + +namespace Magnum { + +MeshView& MeshView::setIndexRange(Int first, Int count, UnsignedInt start, UnsignedInt end) { + _indexOffset = first*_original->indexSize(); + _indexCount = count; + _indexStart = start; + _indexEnd = end; + return *this; +} + +void MeshView::draw() { + _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); +} + +} diff --git a/src/MeshView.h b/src/MeshView.h new file mode 100644 index 000000000..3fdb0aa0f --- /dev/null +++ b/src/MeshView.h @@ -0,0 +1,139 @@ +#ifndef Magnum_MeshView_h +#define Magnum_MeshView_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::MeshView + */ + +#include "Magnum.h" +#include "magnumVisibility.h" + +#ifndef DOXYGEN_GENERATING_OUTPUT +typedef std::ptrdiff_t GLintptr; +#endif + +namespace Magnum { + +/** +@brief %Mesh view + +Allows different interpretation of given @ref Mesh data via different vertex or +index count and offset. It is then possible to reuse one mesh buffer +configuration for different views. %Mesh primitive, index type, attribute +bindings and attached buffers are reused from original mesh. + +The same rules as in Mesh apply, i.e. if the view 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 view is treated as empty and no draw +commands are issued when calling draw(). + +You must ensure that the original mesh remains available for whole view +lifetime. +@todo Might cause issues when there are more data than just indices in index + buffer (wrongly computed offset) +*/ +class MAGNUM_EXPORT MeshView { + public: + /** + * @brief Constructor + * @param original Original, already configured mesh + */ + explicit MeshView(Mesh& original); + + /** @brief Copy constructor */ + MeshView(const MeshView& other) = default; + + /** @brief Movement is not allowed */ + MeshView(MeshView&& other) = delete; + + /** @brief Copy assignment */ + MeshView& operator=(const MeshView&) = default; + + /** @brief Movement is not allowed */ + MeshView& operator=(MeshView&& other) = delete; + + /** + * @brief Set vertex range + * @param first First vertex + * @param count Vertex count + * @return Reference to self (for method chaining) + * + * Default is zero @p offset and zero @p count. If index range is + * non-zero, vertex range is ignored, see main class documentation for + * more information. + */ + MeshView& setVertexRange(Int first, Int count) { + _firstVertex = first; + _vertexCount = count; + return *this; + } + + /** + * @brief Set index range + * @param first First index + * @param count Index count + * @param start Minimum array index contained in the buffer + * @param end Maximum array index contained in the buffer + * @return Reference to self (for method chaining) + * + * Specifying `0` for both @p start and @p end behaves the same as + * @ref setIndexRange(Int, Int). + */ + MeshView& setIndexRange(Int first, Int count, UnsignedInt start, UnsignedInt end); + + /** + * @brief Set index range + * @param first First index + * @param count Index count + * @return Reference to self (for method chaining) + * + * Prefer to use @ref setIndexRange(Int, Int, UnsignedInt, UnsignedInt) + * for better performance. + */ + MeshView& setIndexRange(Int first, Int count) { + return setIndexRange(first, count, 0, 0); + } + + /** + * @brief Draw the mesh + * + * See @ref Mesh::draw() for more information. + */ + void draw(); + + private: + Mesh* _original; + + Int _firstVertex, _vertexCount, _indexCount; + GLintptr _indexOffset; + UnsignedInt _indexStart, _indexEnd; +}; + +inline MeshView::MeshView(Mesh& original): _original(&original), _firstVertex(0), _vertexCount(0), _indexCount(0), _indexOffset(0), _indexStart(0), _indexEnd(0) {} + +} + +#endif From b50fb5a50eac5363657447dac5aca55f73c38a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 9 Aug 2013 17:02:43 +0200 Subject: [PATCH 28/64] DebugTools: shape renderer for 2D/3D capsule. --- src/DebugTools/CMakeLists.txt | 1 + .../Implementation/CapsuleRenderer.cpp | 116 +++++++++++++++ .../Implementation/CapsuleRenderer.h | 66 +++++++++ .../CapsuleRendererTransformation.h | 93 ++++++++++++ src/DebugTools/ResourceManager.cpp | 3 +- src/DebugTools/ResourceManager.h | 6 +- src/DebugTools/ShapeRenderer.cpp | 7 + src/DebugTools/Test/CMakeLists.txt | 1 + src/DebugTools/Test/CapsuleRendererTest.cpp | 137 ++++++++++++++++++ 9 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 src/DebugTools/Implementation/CapsuleRenderer.cpp create mode 100644 src/DebugTools/Implementation/CapsuleRenderer.h create mode 100644 src/DebugTools/Implementation/CapsuleRendererTransformation.h create mode 100644 src/DebugTools/Test/CapsuleRendererTest.cpp diff --git a/src/DebugTools/CMakeLists.txt b/src/DebugTools/CMakeLists.txt index 66546c172..00d88ecc8 100644 --- a/src/DebugTools/CMakeLists.txt +++ b/src/DebugTools/CMakeLists.txt @@ -33,6 +33,7 @@ set(MagnumDebugTools_SRCS Implementation/AbstractShapeRenderer.cpp Implementation/AxisAlignedBoxRenderer.cpp Implementation/BoxRenderer.cpp + Implementation/CapsuleRenderer.cpp Implementation/LineSegmentRenderer.cpp Implementation/PointRenderer.cpp Implementation/SphereRenderer.cpp) diff --git a/src/DebugTools/Implementation/CapsuleRenderer.cpp b/src/DebugTools/Implementation/CapsuleRenderer.cpp new file mode 100644 index 000000000..d6e48d5b5 --- /dev/null +++ b/src/DebugTools/Implementation/CapsuleRenderer.cpp @@ -0,0 +1,116 @@ +/* + 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 "CapsuleRenderer.h" + +#include "MeshView.h" +#include "DebugTools/ResourceManager.h" +#include "DebugTools/ShapeRenderer.h" +#include "Primitives/Capsule.h" +#include "Shapes/Capsule.h" +#include "Shaders/Flat.h" +#include "Trade/MeshData2D.h" +#include "Trade/MeshData3D.h" + +#include "DebugTools/Implementation/CapsuleRendererTransformation.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +AbstractCapsuleRenderer<2>::AbstractCapsuleRenderer(): AbstractShapeRenderer<2>("capsule2d", "capsule2d-vertices", "capsule2d-indices") { + constexpr UnsignedInt rings = 10; + if(!wireframeMesh) createResources(Primitives::Capsule2D::wireframe(rings, 1, 1.0f)); + + /* Bottom hemisphere */ + if(!(bottom = ResourceManager::instance().get("capsule2d-bottom"))) { + auto view = new MeshView(wireframeMesh); + view->setIndexRange(0, rings*4, 0, rings*2+1); + ResourceManager::instance().set(bottom.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); + } + + /* Cylinder */ + if(!(cylinder = ResourceManager::instance().get("capsule2d-cylinder"))) { + auto view = new MeshView(wireframeMesh); + view->setIndexRange(rings*4, 4, rings*2+1, rings*2+3); + ResourceManager::instance().set(cylinder.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); + } + + /* Top hemisphere */ + if(!(top = ResourceManager::instance().get("capsule2d-top"))) { + auto view = new MeshView(wireframeMesh); + view->setIndexRange(rings*4+4, rings*4, rings*2+3, rings*4+4); + ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); + } +} + +AbstractCapsuleRenderer<3>::AbstractCapsuleRenderer(): AbstractShapeRenderer<3>("capsule3d", "capsule3d-vertices", "capsule3d-indices") { + constexpr UnsignedInt rings = 10; + constexpr UnsignedInt segments = 20; + if(!wireframeMesh) createResources(Primitives::Capsule3D::wireframe(rings, 1, segments, 1.0f)); + + /* Bottom hemisphere */ + if(!(bottom = ResourceManager::instance().get("capsule3d-bottom"))) { + auto view = new MeshView(wireframeMesh); + view->setIndexRange(0, rings*8, 0, rings*4+1); + ResourceManager::instance().set(bottom.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); + } + + /* Cylinder */ + if(!(cylinder = ResourceManager::instance().get("capsule3d-cylinder"))) { + auto view = new MeshView(wireframeMesh); + view->setIndexRange(rings*8, segments*4+8, rings*4+1, rings*4+segments*2+5); + ResourceManager::instance().set(cylinder.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); + } + + /* Top */ + if(!(top = ResourceManager::instance().get("capsule3d-top"))) { + auto view = new MeshView(wireframeMesh); + view->setIndexRange(rings*8+segments*4+8, rings*8, rings*4+segments*2+5, rings*8+segments*2+6); + ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); + } +} + +template CapsuleRenderer::CapsuleRenderer(const Shapes::Implementation::AbstractShape& capsule): capsule(static_cast>&>(capsule).shape) {} + +template void CapsuleRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { + std::array::MatrixType, 3> transformations = Implementation::capsuleRendererTransformation(capsule.a(), capsule.b(), capsule.radius()); + AbstractShapeRenderer::wireframeShader->setColor(options->color()) + .use(); + + /* Bottom */ + AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[0]); + AbstractCapsuleRenderer::bottom->draw(); + + /* Cylinder */ + AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[1]); + AbstractCapsuleRenderer::cylinder->draw(); + + /* Top */ + AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[2]); + AbstractCapsuleRenderer::top->draw(); +} + +template class CapsuleRenderer<2>; +template class CapsuleRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/CapsuleRenderer.h b/src/DebugTools/Implementation/CapsuleRenderer.h new file mode 100644 index 000000000..d00c5e47f --- /dev/null +++ b/src/DebugTools/Implementation/CapsuleRenderer.h @@ -0,0 +1,66 @@ +#ifndef Magnum_DebugTools_Implementation_CapsuleRenderer_h +#define Magnum_DebugTools_Implementation_CapsuleRenderer_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 "Shapes/Shapes.h" + +#include "corradeCompatibility.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template class AbstractCapsuleRenderer; + +template<> class AbstractCapsuleRenderer<2>: public AbstractShapeRenderer<2> { + public: + explicit AbstractCapsuleRenderer(); + + protected: + Resource bottom, cylinder, top; +}; + +template<> class AbstractCapsuleRenderer<3>: public AbstractShapeRenderer<3> { + public: + explicit AbstractCapsuleRenderer(); + + protected: + Resource bottom, cylinder, top; +}; + +template class CapsuleRenderer: public AbstractCapsuleRenderer { + public: + explicit CapsuleRenderer(const Shapes::Implementation::AbstractShape& capsule); + CapsuleRenderer(const Shapes::Implementation::AbstractShape&&) = delete; + + void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; + + private: + const Shapes::Capsule& capsule; +}; + +}}} + +#endif diff --git a/src/DebugTools/Implementation/CapsuleRendererTransformation.h b/src/DebugTools/Implementation/CapsuleRendererTransformation.h new file mode 100644 index 000000000..ec4120491 --- /dev/null +++ b/src/DebugTools/Implementation/CapsuleRendererTransformation.h @@ -0,0 +1,93 @@ +#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 + +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "DimensionTraits.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template std::array::MatrixType, 3> capsuleRendererTransformation(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius); + +template<> inline std::array capsuleRendererTransformation<2>(const Vector2& a, const Vector2& b, const Float radius) { + /* Vector from capsule center to top hemisphere center */ + const Vector2 direction = 0.5f*(b - a); + const Float length = direction.length(); + + /* Capsule rotation and distance to caps after they are scaled to proper + radius (if nonzero cylinder length) */ + Matrix3 rotation; + Vector2 capDistance; + if(length >= Math::TypeTraits::epsilon()) { + rotation.up() = direction/length; + rotation.right() = rotation.up().perpendicular(); + CORRADE_INTERNAL_ASSERT(rotation.right().isNormalized()); + + capDistance = direction*(radius/length); + } + + /* Scaling and translation of all parts */ + const auto rotationScaling = rotation*Matrix3::scaling(Vector2(radius)); + return {{ + Matrix3::translation(a+capDistance)*rotationScaling, + Matrix3::translation(0.5f*(a + b))*rotation*Matrix3::scaling({radius, length}), + Matrix3::translation(b-capDistance)*rotationScaling + }}; +} + +template<> std::array capsuleRendererTransformation<3>(const Vector3& a, const Vector3& b, const Float radius) { + /* Vector from capsule center to top hemisphere center */ + const Vector3 direction = 0.5f*(b - a); + const Float length = direction.length(); + + /* Capsule rotation and distance to caps after they are scaled to proper + radius (if nonzero cylinder length) */ + Matrix4 rotation; + Vector3 capDistance; + if(length >= Math::TypeTraits::epsilon()) { + rotation.up() = direction/length; + rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); + rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); + CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); + + capDistance = direction*(radius/length); + } + + /* Scaling and translation of all parts */ + const auto rotationScaling = rotation*Matrix4::scaling(Vector3(radius)); + return {{ + Matrix4::translation(a+capDistance)*rotationScaling, + Matrix4::translation(0.5f*(a + b))*rotation*Matrix4::scaling({radius, length, radius}), + Matrix4::translation(b-capDistance)*rotationScaling + }}; +} + +}}} + +#endif diff --git a/src/DebugTools/ResourceManager.cpp b/src/DebugTools/ResourceManager.cpp index 204c28357..6b385af7d 100644 --- a/src/DebugTools/ResourceManager.cpp +++ b/src/DebugTools/ResourceManager.cpp @@ -28,13 +28,14 @@ #include "Buffer.h" #include "Mesh.h" +#include "MeshView.h" #include "DebugTools/ForceRenderer.h" #include "DebugTools/ObjectRenderer.h" #include "DebugTools/ShapeRenderer.h" namespace Magnum { -template class ResourceManager; +template class ResourceManager; namespace DebugTools { diff --git a/src/DebugTools/ResourceManager.h b/src/DebugTools/ResourceManager.h index ccf907718..f5205e044 100644 --- a/src/DebugTools/ResourceManager.h +++ b/src/DebugTools/ResourceManager.h @@ -43,7 +43,9 @@ namespace Magnum { -extern template ResourceManager MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager::internalInstance(); +/** @todo Do the listing in one place, not five thousand! */ + +extern template ResourceManager MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager::internalInstance(); namespace DebugTools { @@ -53,7 +55,7 @@ namespace DebugTools { Stores various data used by debug renderers. See @ref debug-tools for more information. */ -class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager { +class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager { public: explicit ResourceManager(); ~ResourceManager(); diff --git a/src/DebugTools/ShapeRenderer.cpp b/src/DebugTools/ShapeRenderer.cpp index f659779eb..62cbc8f37 100644 --- a/src/DebugTools/ShapeRenderer.cpp +++ b/src/DebugTools/ShapeRenderer.cpp @@ -31,6 +31,7 @@ #include "Implementation/AxisAlignedBoxRenderer.h" #include "Implementation/BoxRenderer.h" +#include "Implementation/CapsuleRenderer.h" #include "Implementation/LineSegmentRenderer.h" #include "Implementation/PointRenderer.h" #include "Implementation/SphereRenderer.h" @@ -56,6 +57,9 @@ template<> void createDebugMesh(ShapeRenderer<2>& renderer, const Shapes::Implem case Shapes::AbstractShape2D::Type::Sphere: renderer.renderers.push_back(new Implementation::SphereRenderer<2>(shape)); break; + case Shapes::AbstractShape2D::Type::Capsule: + renderer.renderers.push_back(new Implementation::CapsuleRenderer<2>(shape)); + break; case Shapes::AbstractShape2D::Type::Composition: { const Shapes::Composition2D& composition = static_cast&>(shape).shape; @@ -84,6 +88,9 @@ template<> void createDebugMesh(ShapeRenderer<3>& renderer, const Shapes::Implem case Shapes::AbstractShape3D::Type::Sphere: renderer.renderers.push_back(new Implementation::SphereRenderer<3>(shape)); break; + case Shapes::AbstractShape3D::Type::Capsule: + renderer.renderers.push_back(new Implementation::CapsuleRenderer<3>(shape)); + break; case Shapes::AbstractShape3D::Type::Composition: { const Shapes::Composition3D& composition = static_cast&>(shape).shape; diff --git a/src/DebugTools/Test/CMakeLists.txt b/src/DebugTools/Test/CMakeLists.txt index 1e945d0c0..ba5e678e2 100644 --- a/src/DebugTools/Test/CMakeLists.txt +++ b/src/DebugTools/Test/CMakeLists.txt @@ -22,5 +22,6 @@ # DEALINGS IN THE SOFTWARE. # +corrade_add_test(DebugToolsCapsuleRendererTest CapsuleRendererTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(DebugToolsForceRendererTest ForceRendererTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(DebugToolsLineSegmentRendererTest LineSegmentRendererTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/DebugTools/Test/CapsuleRendererTest.cpp b/src/DebugTools/Test/CapsuleRendererTest.cpp new file mode 100644 index 000000000..9f00b1c9a --- /dev/null +++ b/src/DebugTools/Test/CapsuleRendererTest.cpp @@ -0,0 +1,137 @@ +/* + 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/CapsuleRendererTransformation.h" + +namespace Magnum { namespace DebugTools { namespace Test { + +class CapsuleRendererTest: public TestSuite::Tester { + public: + explicit CapsuleRendererTest(); + + void zeroLength2D(); + void common2D(); + + void zeroLength3D(); + void common3D(); +}; + +CapsuleRendererTest::CapsuleRendererTest() { + addTests({&CapsuleRendererTest::zeroLength2D, + &CapsuleRendererTest::common2D, + + &CapsuleRendererTest::zeroLength3D, + &CapsuleRendererTest::common3D}); +} + +void CapsuleRendererTest::zeroLength2D() { + const Vector2 a(0.5f, 3.0f); + std::array transformation = Implementation::capsuleRendererTransformation<2>(a, a, 3.5f); + + const auto scaling = Math::Matrix<2, Float>::fromDiagonal(Vector2(3.5f)); + CORRADE_COMPARE(transformation[0].rotationScaling(), scaling); + CORRADE_COMPARE(transformation[1].rotationScaling(), (Math::Matrix<2, Float>::fromDiagonal({3.5f, 0.0f}))); + CORRADE_COMPARE(transformation[2].rotationScaling(), scaling); + + CORRADE_COMPARE(transformation[0].translation(), a); + CORRADE_COMPARE(transformation[1].translation(), a); + CORRADE_COMPARE(transformation[2].translation(), a); +} + +void CapsuleRendererTest::common2D() { + const Vector2 a(0.5f, 3.0f); + const Vector2 b(7.5f, -1.0f); + std::array transformation = Implementation::capsuleRendererTransformation<2>(a, b, 3.5f); + + /* Vector from capsule center to top hemisphere center */ + const Vector2 up(3.5f, -2.0f); + CORRADE_COMPARE(transformation[0].up(), up.resized(3.5f)); + CORRADE_COMPARE(transformation[1].up(), up); + CORRADE_COMPARE(transformation[2].up(), up.resized(3.5f)); + + const Vector2 right = Vector2(4.0f, 7.0f).resized(3.5f); + CORRADE_COMPARE(transformation[0].right(), right); + CORRADE_COMPARE(transformation[1].right(), right); + CORRADE_COMPARE(transformation[2].right(), right); + + /* Orthogonality */ + CORRADE_VERIFY(Vector2::dot(transformation[0].up(), transformation[0].right()) < Math::TypeTraits::epsilon()); + + const Vector2 capDistance = up.resized(3.5f); + CORRADE_COMPARE(transformation[0].translation(), a+capDistance); + CORRADE_COMPARE(transformation[1].translation(), 0.5f*(a + b)); + CORRADE_COMPARE(transformation[2].translation(), b-capDistance); +} + +void CapsuleRendererTest::zeroLength3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + std::array transformation = Implementation::capsuleRendererTransformation<3>(a, a, 3.5f); + + const auto scaling = Math::Matrix<3, Float>::fromDiagonal(Vector3(3.5f)); + CORRADE_COMPARE(transformation[0].rotationScaling(), scaling); + CORRADE_COMPARE(transformation[1].rotationScaling(), (Math::Matrix<3, Float>::fromDiagonal({3.5f, 0.0f, 3.5f}))); + CORRADE_COMPARE(transformation[2].rotationScaling(), scaling); + + CORRADE_COMPARE(transformation[0].translation(), a); + CORRADE_COMPARE(transformation[1].translation(), a); + CORRADE_COMPARE(transformation[2].translation(), a); +} + +void CapsuleRendererTest::common3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Vector3 b(7.5f, -1.0f, 1.5f); + std::array transformation = Implementation::capsuleRendererTransformation<3>(a, b, 3.5f); + + /* Vector from capsule center to top hemisphere center */ + const Vector3 up(3.5f, -2.0f, -2.75f); + CORRADE_COMPARE(transformation[0].up(), up.resized(3.5f)); + CORRADE_COMPARE(transformation[1].up(), up); + CORRADE_COMPARE(transformation[2].up(), up.resized(3.5f)); + + const auto right = Vector3(-2.0f, -3.5f, 0.0f).resized(3.5f); + CORRADE_COMPARE(transformation[0].right(), right); + CORRADE_COMPARE(transformation[1].right(), right); + CORRADE_COMPARE(transformation[2].right(), right); + + const auto backward = Vector3(9.625f, -5.5f, 16.25f).resized(3.5f); + CORRADE_COMPARE(transformation[0].backward(), backward); + CORRADE_COMPARE(transformation[1].backward(), backward); + CORRADE_COMPARE(transformation[2].backward(), backward); + + /* Orthogonality */ + CORRADE_VERIFY(Vector3::dot(transformation[0].up(), transformation[0].right()) < Math::TypeTraits::epsilon()); + CORRADE_VERIFY(Vector3::dot(transformation[0].up(), transformation[0].backward()) < Math::TypeTraits::epsilon()); + CORRADE_VERIFY(Vector3::dot(transformation[0].right(), transformation[0].backward()) < Math::TypeTraits::epsilon()); + + const Vector3 capDistance = up.resized(3.5f); + CORRADE_COMPARE(transformation[0].translation(), a+capDistance); + CORRADE_COMPARE(transformation[1].translation(), 0.5f*(a + b)); + CORRADE_COMPARE(transformation[2].translation(), b-capDistance); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::DebugTools::Test::CapsuleRendererTest) From 2c1a859563418a858505b10e4f418e22d4663ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 18 Aug 2013 00:04:31 +0200 Subject: [PATCH 29/64] Shapes: properly test both 2D and 3D where the transform is not trivial. Causes Capsule test to fail. --- src/Shapes/Test/CapsuleTest.cpp | 22 +++++++++++++++++++--- src/Shapes/Test/SphereTest.cpp | 26 +++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/Shapes/Test/CapsuleTest.cpp b/src/Shapes/Test/CapsuleTest.cpp index b4fd8a048..03bd09848 100644 --- a/src/Shapes/Test/CapsuleTest.cpp +++ b/src/Shapes/Test/CapsuleTest.cpp @@ -22,6 +22,7 @@ DEALINGS IN THE SOFTWARE. */ +#include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Magnum.h" #include "Shapes/Capsule.h" @@ -36,19 +37,34 @@ class CapsuleTest: public TestSuite::Tester { public: CapsuleTest(); - void transformed(); + void transformed2D(); + void transformed3D(); void transformedAverageScaling(); void collisionPoint(); void collisionSphere(); }; CapsuleTest::CapsuleTest() { - addTests({&CapsuleTest::transformed, + addTests({&CapsuleTest::transformed2D, + &CapsuleTest::transformed3D, &CapsuleTest::collisionPoint, &CapsuleTest::collisionSphere}); } -void CapsuleTest::transformed() { +void CapsuleTest::transformed2D() { + const Shapes::Capsule2D capsule({1.0f, 2.0f}, {-1.0f, -2.0f}, 7.0f); + + const auto transformed = capsule.transformed(Matrix3::rotation(Deg(90.0f))); + CORRADE_COMPARE(transformed.a(), Vector2(-2.0f, 1.0f)); + CORRADE_COMPARE(transformed.b(), Vector2(2.0f, -1.0f)); + CORRADE_COMPARE(transformed.radius(), 7.0f); + + /* Apply average scaling to radius */ + const auto scaled = capsule.transformed(Matrix3::scaling({-Constants::sqrt2(), 2.0f})); + CORRADE_COMPARE(scaled.radius(), Constants::sqrt3()*7.0f); +} + +void CapsuleTest::transformed3D() { const Shapes::Capsule3D capsule({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}, 7.0f); const auto transformed = capsule.transformed(Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); diff --git a/src/Shapes/Test/SphereTest.cpp b/src/Shapes/Test/SphereTest.cpp index 70f413be5..538a5b282 100644 --- a/src/Shapes/Test/SphereTest.cpp +++ b/src/Shapes/Test/SphereTest.cpp @@ -22,6 +22,7 @@ DEALINGS IN THE SOFTWARE. */ +#include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Magnum.h" #include "Shapes/LineSegment.h" @@ -36,7 +37,8 @@ class SphereTest: public TestSuite::Tester { public: SphereTest(); - void transformed(); + void transformed2D(); + void transformed3D(); void collisionPoint(); void collisionLine(); void collisionLineSegment(); @@ -44,14 +46,32 @@ class SphereTest: public TestSuite::Tester { }; SphereTest::SphereTest() { - addTests({&SphereTest::transformed, + addTests({&SphereTest::transformed2D, + &SphereTest::transformed3D, &SphereTest::collisionPoint, &SphereTest::collisionLine, &SphereTest::collisionLineSegment, &SphereTest::collisionSphere}); } -void SphereTest::transformed() { +void SphereTest::transformed2D() { + const Shapes::Sphere2D sphere({1.0f, 2.0f}, 7.0f); + + const auto transformed = sphere.transformed(Matrix3::rotation(Deg(90.0f))); + CORRADE_COMPARE(transformed.position(), Vector2(-2.0f, 1.0f)); + CORRADE_COMPARE(transformed.radius(), 7.0f); + + /* Symmetric scaling */ + const auto scaled = sphere.transformed(Matrix3::scaling(Vector2(2.0f))); + CORRADE_COMPARE(scaled.position(), Vector2(2.0f, 4.0f)); + CORRADE_COMPARE(scaled.radius(), 14.0f); + + /* Apply average scaling to radius */ + const auto nonEven = sphere.transformed(Matrix3::scaling({-Constants::sqrt2(), 2.0f})); + CORRADE_COMPARE(nonEven.radius(), Constants::sqrt3()*7.0f); +} + +void SphereTest::transformed3D() { const Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 7.0f); const auto transformed = sphere.transformed(Matrix4::rotation(Deg(90.0f), Vector3::yAxis())); From e7dbe606cd47024fc2d87d0e8b801ac6c3a8b29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 18 Aug 2013 00:13:11 +0200 Subject: [PATCH 30/64] Shapes: fixed 2D Capsule transformation. The test now passes again. --- src/Shapes/Capsule.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Shapes/Capsule.cpp b/src/Shapes/Capsule.cpp index 497696d09..7fada2aee 100644 --- a/src/Shapes/Capsule.cpp +++ b/src/Shapes/Capsule.cpp @@ -36,9 +36,21 @@ using namespace Magnum::Math::Geometry; namespace Magnum { namespace Shapes { +namespace { + template static typename DimensionTraits::VectorType unitVector(); + + template<> inline Vector2 unitVector<2>() { + return Vector2(1/Constants::sqrt2()); + } + + template<> inline Vector3 unitVector<3>() { + return Vector3(1/Constants::sqrt3()); + } +} + template Capsule Capsule::transformed(const typename DimensionTraits::MatrixType& matrix) const { return Capsule(matrix.transformPoint(_a), matrix.transformPoint(_b), - (matrix.rotationScaling()*typename DimensionTraits::VectorType(1/Constants::sqrt3())).length()*_radius); + (matrix.rotationScaling()*unitVector()).length()*_radius); } template bool Capsule::operator%(const Point& other) const { From beef4b6113d876fac7218cb7b71631017e7693c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 18 Aug 2013 00:13:54 +0200 Subject: [PATCH 31/64] Shapes: added TODOs. --- src/Shapes/Capsule.h | 2 +- src/Shapes/Plane.h | 1 + src/Shapes/Sphere.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Shapes/Capsule.h b/src/Shapes/Capsule.h index 2d85ddd97..fb0de064c 100644 --- a/src/Shapes/Capsule.h +++ b/src/Shapes/Capsule.h @@ -42,7 +42,7 @@ Unlike other elements the capsule doesn't support asymmetric scaling. When applying transformation, the scale factor is averaged from all axes. See @ref shapes for brief introduction. @see Capsule2D, Capsule3D -@todo Assert for asymmetric scaling +@todo Assert for asymmetric scaling to avoid costly sqrt? */ template class MAGNUM_SHAPES_EXPORT Capsule { public: diff --git a/src/Shapes/Plane.h b/src/Shapes/Plane.h index c3f3471d8..50058fc68 100644 --- a/src/Shapes/Plane.h +++ b/src/Shapes/Plane.h @@ -39,6 +39,7 @@ namespace Magnum { namespace Shapes { @brief Infinite plane, defined by position and normal (3D only) See @ref shapes for brief introduction. +@todo Assert for uniform scaling to avoid costly normalization? */ class MAGNUM_SHAPES_EXPORT Plane { public: diff --git a/src/Shapes/Sphere.h b/src/Shapes/Sphere.h index c100f90b3..dc4c5e2f0 100644 --- a/src/Shapes/Sphere.h +++ b/src/Shapes/Sphere.h @@ -42,7 +42,7 @@ Unlike other elements the sphere doesn't support asymmetric scaling. When applying transformation, the scale factor is averaged from all axes. See @ref shapes for brief introduction. @see Sphere2D, Sphere3D -@todo Assert for asymmetric scaling +@todo Assert for asymmetric scaling to avoid costly sqrt? */ template class MAGNUM_SHAPES_EXPORT Sphere { public: From 7b087425cf48c86ab8525ef8fe24f5cf46095637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:42:34 +0200 Subject: [PATCH 32/64] DebugTools: this shouldn't be inline. --- src/DebugTools/Implementation/CapsuleRendererTransformation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DebugTools/Implementation/CapsuleRendererTransformation.h b/src/DebugTools/Implementation/CapsuleRendererTransformation.h index ec4120491..be649c77f 100644 --- a/src/DebugTools/Implementation/CapsuleRendererTransformation.h +++ b/src/DebugTools/Implementation/CapsuleRendererTransformation.h @@ -35,7 +35,7 @@ namespace Magnum { namespace DebugTools { namespace Implementation { template std::array::MatrixType, 3> capsuleRendererTransformation(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius); -template<> inline std::array capsuleRendererTransformation<2>(const Vector2& a, const Vector2& b, const Float radius) { +template<> std::array capsuleRendererTransformation<2>(const Vector2& a, const Vector2& b, const Float radius) { /* Vector from capsule center to top hemisphere center */ const Vector2 direction = 0.5f*(b - a); const Float length = direction.length(); From 4d6fa4308e1ecf41a4e0b48ae49ba63eb387c854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:43:23 +0200 Subject: [PATCH 33/64] DebugTools: test orthogonality the easy way. Brainfart. --- src/DebugTools/Test/CapsuleRendererTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DebugTools/Test/CapsuleRendererTest.cpp b/src/DebugTools/Test/CapsuleRendererTest.cpp index 9f00b1c9a..96e5013c1 100644 --- a/src/DebugTools/Test/CapsuleRendererTest.cpp +++ b/src/DebugTools/Test/CapsuleRendererTest.cpp @@ -78,7 +78,7 @@ void CapsuleRendererTest::common2D() { CORRADE_COMPARE(transformation[2].right(), right); /* Orthogonality */ - CORRADE_VERIFY(Vector2::dot(transformation[0].up(), transformation[0].right()) < Math::TypeTraits::epsilon()); + CORRADE_COMPARE(Vector2::dot(transformation[0].up(), transformation[0].right()), 0.0f); const Vector2 capDistance = up.resized(3.5f); CORRADE_COMPARE(transformation[0].translation(), a+capDistance); @@ -122,9 +122,9 @@ void CapsuleRendererTest::common3D() { CORRADE_COMPARE(transformation[2].backward(), backward); /* Orthogonality */ - CORRADE_VERIFY(Vector3::dot(transformation[0].up(), transformation[0].right()) < Math::TypeTraits::epsilon()); - CORRADE_VERIFY(Vector3::dot(transformation[0].up(), transformation[0].backward()) < Math::TypeTraits::epsilon()); - CORRADE_VERIFY(Vector3::dot(transformation[0].right(), transformation[0].backward()) < Math::TypeTraits::epsilon()); + CORRADE_COMPARE(Vector3::dot(transformation[0].up(), transformation[0].right()), 0.0f); + CORRADE_COMPARE(Vector3::dot(transformation[0].up(), transformation[0].backward()), 0.0f); + CORRADE_COMPARE(Vector3::dot(transformation[0].right(), transformation[0].backward()), 0.0f); const Vector3 capDistance = up.resized(3.5f); CORRADE_COMPARE(transformation[0].translation(), a+capDistance); From 47fa924f2b89c946d473ecd49266e1af6da65a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:44:01 +0200 Subject: [PATCH 34/64] DebugTools: orthogonal, not parallel. Another brainfart. --- src/DebugTools/Test/ForceRendererTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DebugTools/Test/ForceRendererTest.cpp b/src/DebugTools/Test/ForceRendererTest.cpp index e02d3ce7d..7d1a733ff 100644 --- a/src/DebugTools/Test/ForceRendererTest.cpp +++ b/src/DebugTools/Test/ForceRendererTest.cpp @@ -81,7 +81,7 @@ void ForceRendererTest::arbitrary2D() { /* All vectors have the same length */ CORRADE_COMPARE(m.up().length(), force.length()); - /* All vectors are parallel */ + /* All vectors are orthogonal */ CORRADE_COMPARE(Vector2::dot(m.right(), m.up()), 0.0f); } @@ -112,7 +112,7 @@ void ForceRendererTest::arbitrary3D() { CORRADE_COMPARE(m.up().length(), force.length()); CORRADE_COMPARE(m.backward().length(), force.length()); - /* All vectors are parallel */ + /* All vectors are orthogonal */ 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); From 95bb40ef52fb69dc015b270a9bbb55bde7ba47c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:56:23 +0200 Subject: [PATCH 35/64] Reword features in building documentation a bit. --- doc/building.dox | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/doc/building.dox b/doc/building.dox index bebcbd912..47f17b054 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -74,17 +74,19 @@ optional features. make make install -The libraries are build as shared by default, pass `-DBUILD_STATIC=ON` to build -them as static. If you plan them to use with shared libraries later, enable -also position-independent code with `-DBUILD_STATIC_PIC=ON`. If you want to -build with another compiler (e.g. Clang), pass `-DCMAKE_CXX_COMPILER=clang++` -to CMake. -@subsection building-optional Enabling or disabling features +@subsection building-features Enabling or disabling features + +The libraries are build as shared by default. If you are developing for +platform which doesn't support shared libraries or if you just want to link +them statically, enable `BUILD_STATIC` to build the libraries as static. If you +plan to use them with shared libraries later, enable also position-independent +code with `BUILD_STATIC_PIC`. If you want to build with another compiler (e.g. +Clang), pass `-DCMAKE_CXX_COMPILER=clang++` to CMake. 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. +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 @@ -92,9 +94,14 @@ for desktop OpenGL only, see @ref requires-gl. - `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: +The features used can be conveniently detected in depending projects both in +CMake and C++ sources, see @ref cmake and @ref src/Magnum.h for more +information. See also @ref corrade-cmake and @ref src/Corrade.h for additional +information. + +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_AUDIO` - Audio library. Requires **OpenAL** library. - `WITH_DEBUGTOOLS` - DebugTools library. Enables also building of MeshTools, @@ -135,9 +142,10 @@ platform best: @subsection building-tests Building and running unit tests -If you want to build also unit tests (which are not built by default), pass -`-DBUILD_TESTS=ON` to CMake. Unit tests use Corrade's @ref Corrade::TestSuite -"TestSuite" framework and can be run using +If you want to build also unit tests (which are not built by default), enable +`BUILD_TEST` in CMake. Unit tests use Corrade's @ref Corrade::TestSuite +"TestSuite" framework and can be run either manually (the binaries are located +in `Test/` subdirectories of build directory) or using ctest --output-on-failure From 99ffc440b2f26fdbf4b7bbfd3ba8ff250f91744f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:57:34 +0200 Subject: [PATCH 36/64] Properly document building on Windows. --- README.md | 15 ++++++------ doc/building.dox | 64 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 54dd68635..221f96fcd 100644 --- a/README.md +++ b/README.md @@ -72,13 +72,14 @@ more comprehensive guide for building, packaging and crosscompiling. Minimal dependencies -------------------- - * C++ compiler with good C++11 support. Currently there are two compilers - which are tested to support everything needed: **GCC** >= 4.6 and **Clang** - >= 3.1. - * **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 - https://github.com/mosra/corrade. +* C++ compiler with good C++11 support. Currently there are two compilers + which are tested to support everything needed: **GCC** >= 4.6 and **Clang** + >= 3.1. On Windows you can use **MinGW**, Visual Studio compiler still + lacks some needed features. +* **CMake** >= 2.8.8 +* **GLEW** - OpenGL extension wrangler (only if targeting desktop OpenGL) +* **Corrade** - Plugin management and utility library. You can get it at + https://github.com/mosra/corrade. Compilation, installation ------------------------- diff --git a/doc/building.dox b/doc/building.dox index 47f17b054..1e6b77cea 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -38,8 +38,9 @@ Minimal set of tools and libraries required for building is: - C++ compiler with good C++11 support. Currently there are two compilers which are tested to support everything needed: **GCC** >= 4.6 and **Clang** - >= 3.1. -- **CMake** >= 2.8.8 (needed for `OBJECT` library target) + >= 3.1. On Windows you can use **MinGW**, Visual Studio compiler still lacks + some needed features. +- **CMake** >= 2.8.8 - **GLEW** - OpenGL extension wrangler (only if targeting desktop OpenGL) - **Corrade** - Plugin management and utility library. See @ref building-corrade "Corrade download and installation guide" for more @@ -63,9 +64,10 @@ subdirectory. @section building-compilation Compilation, installation -The library (for example with support for GLUT applications) can be built and -installed using these four commands. See below for more information about -optional features. +@subsection building-linux Via command-line (on Linux/Unix) + +On Unix-based OSs, the library (for example with support for GLUT applications) +can be built and installed using these four commands: mkdir -p build && cd build cmake .. \ @@ -74,6 +76,55 @@ optional features. make make install +The library provides a lot of CMake options (described in sections later). They +can be passed to CMake either as `-Dname=value` parameters on command-line +(like above) or set conveniently using `cmake-gui`: + + cd build + cmake-gui . + +@subsection building-windows Using QtCreator and CMake GUI (on Windows) + +On Windows, if you don't want to touch the command-line, the easiest way is to +install QtCreator (just QtCreator, you don't need the full Qt SDK) and +configure it to use MinGW and CMake. + +For most convenient usage it's best to install (or copy/paste) all library +dependencies into directory where MinGW is installed (e.g. `C:/MinGW/`), +following proper filesystem hierarchy, i.e. headers into `include/` and +binaries into `bin/` or `lib/`. CMake will then have no problem finding them +and you won't need to explicitly specify path to each one. + +Then just open project's root `CMakeLists.txt` file within QtCreator. It then +asks you where to create build directory, allows you to specify initial CMake +parameters and then you can just press Configure and everything should be ready +to be built. You might need to set some CMake parameters before configuring, +they can be set with `-Dname=value`. See below for more information. + +After the initial import you might want to reconfigure some CMake variables +(more information below). Start CMake GUI, point it to the recently created +build dir, modify the variables and press Generate. QtCreator will detect the +changes and reparse the project accordingly. + +For most convenient usage it's best to set `CMAKE_INSTALL_PREFIX` to directory +where MinGW is installed (e.g. `C:/MinGW/`) and add `C:/MinGW/bin` and +`C:/MinGW/lib` to `PATH`. Installation to given prefix can be then done from +within QtCreator by adding new `make install` build rule. + +@subsubsection building-windows-troubleshooting Windows troubleshooting + +If CMake isn't able to find dependencies (e.g. Corrade is not found) and you +have installed them to MinGW directory, point to `CMAKE_FIND_ROOT_PATH` to +MinGW installation prefix, e.g. specify `-DCMAKE_FIND_ROOT_PATH=C:/MinGW/` +CMake parameter. + +If building fails with GLEW linking errors (`undefined reference to glew...`), +you have to set `GLEW_LIBRARY_DLL` and `GLEW_LIBRARY_LIB` CMake variables +manually. One of them should point to `glew32.dll` and the other to +`glew32.lib`. CMake currently isn't able to distinguish between them and in +most cases points both to the same location. + +See also Corrade's @ref building-corrade-windows-troubleshooting "troubleshooting section". @subsection building-features Enabling or disabling features @@ -149,7 +200,8 @@ in `Test/` subdirectories of build directory) or using ctest --output-on-failure -in build directory. Everything should pass ;-) +in build directory. On Windows the tests require the library to be installed +with DLLs accessible through `PATH`. See above for more information. @subsection building-doc Building documentation From b2a5795ff7156cac88fc874fdebcadf48c23bd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:58:56 +0200 Subject: [PATCH 37/64] Minor Markdown reformatting. --- CONTRIBUTING.md | 9 +++++---- README.md | 16 ++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec263025d..673ba7918 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,7 +53,8 @@ Code contribution Contact ------- -- Website - http://mosra.cz/blog/ -- GitHub - https://github.com/mosra/magnum -- E-mail - mosra@centrum.cz -- Jabber - mosra@jabbim.cz +* Website - http://mosra.cz/blog/magnum.php +* GitHub - https://github.com/mosra/magnum +* Twitter - https://twitter.com/czmosra +* E-mail - mosra@centrum.cz +* Jabber - mosra@jabbim.cz diff --git a/README.md b/README.md index 221f96fcd..ad5263a61 100644 --- a/README.md +++ b/README.md @@ -135,14 +135,14 @@ Example repository is at https://github.com/mosra/magnum-examples. CONTACT ======= -Want to learn more about the library? Found a bug or want to tell me an -awesome idea? Feel free to visit my website or contact me at: - - * Website - http://mosra.cz/blog/magnum.php - * GitHub - https://github.com/mosra/magnum - * Twitter - https://twitter.com/czmosra - * E-mail - mosra@centrum.cz - * Jabber - mosra@jabbim.cz +Want to learn more about the library? Found a bug or want to tell me an awesome +idea? Feel free to visit my website or contact me at: + +* Website - http://mosra.cz/blog/magnum.php +* GitHub - https://github.com/mosra/magnum +* Twitter - https://twitter.com/czmosra +* E-mail - mosra@centrum.cz +* Jabber - mosra@jabbim.cz LICENSE ======= From 459f3b3e856942bdb5b98bcec9c99a720b9fa653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 18:59:17 +0200 Subject: [PATCH 38/64] TextureTools: fixed typo. --- src/TextureTools/DistanceField.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h index 811ff6ba3..b788179f9 100644 --- a/src/TextureTools/DistanceField.h +++ b/src/TextureTools/DistanceField.h @@ -51,7 +51,8 @@ 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. +foundation for features like outlining, glow or drop shadow essentially 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 From 5577f98b9e30a0c22f9315111740fe9037114fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 19:12:14 +0200 Subject: [PATCH 39/64] Updated .gitignore. It would accidentaly ignore also doc/building.dox (which is wrong). However it doesn't seem to do that. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d1ef973af..d513341ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -build* +build*/ pkg *.kdev4 *~ From 866ee0594be2c8403ee6bb3cc5ec60f23408c0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 19:13:24 +0200 Subject: [PATCH 40/64] Link with other projects' building and usage documentation. --- Doxyfile | 5 ++++- README.md | 12 ++++++++---- doc/building.dox | 9 +++++++++ doc/cmake.dox | 2 ++ doc/namespaces.dox | 8 +++++++- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Doxyfile b/Doxyfile index 5efd5080d..d9dff7fed 100644 --- a/Doxyfile +++ b/Doxyfile @@ -142,7 +142,8 @@ STRIP_FROM_PATH = ../ # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = ../magnum/src \ - ../magnum-plugins/src + ../magnum-plugins/src \ + ../magnum-integration/src # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system @@ -688,6 +689,8 @@ INPUT = src/ \ doc/ \ ../magnum-plugins/src/ \ ../magnum-plugins/doc/ \ + ../magnum-integration/src/ \ + ../magnum-integration/doc/ \ ../magnum-examples/doc/ # This tag can be used to specify the character encoding of the source files diff --git a/README.md b/README.md index ad5263a61..33299aa2c 100644 --- a/README.md +++ b/README.md @@ -122,10 +122,14 @@ in root directory (i.e. where `Doxyfile` is). Resulting HTML documentation will be in `build/doc/` directory. You might need to create `build/` directory if it doesn't exist yet. -PLUGINS AND EXAMPLES -==================== - -Various importer plugins for image and 3D model formats are maintained in +RELATED PROJECTS +================ + +The engine itself is kept as small as possible with only little dependencies. +Additional functionality, often depending on external libraries, is provided in +separate repositories. Integration with various external math and physics +libraries can be found at https://github.com/mosra/magnum-integration. Various +importer plugins for image, audio and 3D model formats are maintained in 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 diff --git a/doc/building.dox b/doc/building.dox index 1e6b77cea..caaca74dd 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -216,6 +216,15 @@ in root directory (i.e. where `Doxyfile` is). Resulting HTML documentation will be in `build/doc/` directory. You might need to create `build/` directory if it doesn't exist yet. +@section building-related Related projects + +The engine itself is kept as small as possible with only little dependencies. +Additional functionality, often depending on external libraries, is provided in +separate repositories. Various importer plugins for image, audio and 3D model +formats are maintained in @ref building-plugins "Plugins repository", +Integration with various external math and physics libraries is provided by +@ref building-integration "Integration library". + @section building-arch Building ArchLinux packages In `package/archlinux` directory is currently one PKGBUILD for Git development diff --git a/doc/cmake.dox b/doc/cmake.dox index eee0944bc..6ebd791d6 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -106,6 +106,8 @@ are also available as preprocessor variables if including Magnum.h: %Corrade library provides also its own set of CMake macros and variables, see @ref corrade-cmake "its documentation" for more information. +@ref cmake-plugins "Plugins repository" and @ref cmake-integration "Integration library" +have also their own CMake modules. */ } diff --git a/doc/namespaces.dox b/doc/namespaces.dox index f984f03b5..229abad25 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -98,6 +98,8 @@ Audio import, playback and integration with @ref SceneGraph. This library is built when `WITH_AUDIO` is enabled and found as `%Audio` component in CMake. See @ref building and @ref cmake for more information. +Additional plugins are part of plugin repository, see @ref building-plugins and +@ref cmake-plugins for more information. */ /** @dir DebugTools @@ -189,6 +191,8 @@ Font texture creation and text layouting. This library is built when `WITH_TEXT` is enabled and found as `%Text` component in CMake. See @ref building and @ref cmake for more information. +Additional plugins are part of plugin repository, see @ref building-plugins and +@ref cmake-plugins for more information. */ /** @dir TextureTools @@ -214,5 +218,7 @@ Contains plugin interfaces for importing data of various formats and classes for direct access to the data. This library is built by default and found by default in CMake. See -@ref building and @ref cmake for more information. +@ref building and @ref cmake for more information. Additional plugins are part +of plugin repository, see @ref building-plugins and @ref cmake-plugins for more +information. */ From 20148585c205390393885a1b7d9db227de5b0a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 19:51:51 +0200 Subject: [PATCH 41/64] Finally proper Getting Started Guide in documentation. --- Doxyfile | 3 +- README.md | 3 + doc/getting-started-blue.png | Bin 0 -> 8205 bytes doc/getting-started.dox | 202 +++++++++++++++++++++++++++++++++++ doc/getting-started.png | Bin 0 -> 8215 bytes doc/mainpage.dox | 10 +- 6 files changed, 209 insertions(+), 9 deletions(-) create mode 100644 doc/getting-started-blue.png create mode 100644 doc/getting-started.dox create mode 100644 doc/getting-started.png diff --git a/Doxyfile b/Doxyfile index d9dff7fed..9bb7567bd 100644 --- a/Doxyfile +++ b/Doxyfile @@ -775,7 +775,8 @@ EXAMPLE_RECURSIVE = NO # directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = ../magnum-examples/src/ +IMAGE_PATH = doc/ \ + ../magnum-examples/src/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/README.md b/README.md index 33299aa2c..d88d832df 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,9 @@ 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. +Repository with bootstrap projects for many use cases, helping you get up and +running in no time is located at https://github.com/mosra/magnum-bootstrap. + CONTACT ======= diff --git a/doc/getting-started-blue.png b/doc/getting-started-blue.png new file mode 100644 index 0000000000000000000000000000000000000000..554613df2c27ade9ee46917eb3cf90a2e070994c GIT binary patch literal 8205 zcmeHs_g522*KRCFUq#S!EC`6aN>jQZT|lLY7$O})Q|SbVQcXg!oMWLX8fpTH5D1V& zLNkzn9;5^$D3H)3QCcJcLNSR1l3dP@_ulpW0pD6@X3gw1Wv`jF_sp}NJ@fRsi=*s* z#r*&PK-TGsof`nKAO9MX7qR-LvoZ72kLO z;GhKnAjjPyH)dZ80H_>vvb*GQcVcO3JYKEmCVMp~%v0s!%$_|cg-=#5&1~a7LU1d^ z))CbFPQmaa3fKFwbcfV>#M=n#Lg0ow0B(H-pl`&QWA>@V`%`uGc~Dw@}cw(OF))T z(gOfw_2>GU*xPq3`&zW;lTW`NK<@;k)gC`fC8uy^iv#;m;O}7xz0XQ2 zTIedVxEq;QpYQ(-a_g{yf|3H{fbC1by?uA7;Y^r5FNI^I{?wh(+xj3@e^&HZ@3Erk z69H$O=56j)e*#-!=60k@BPZ+J^ZMt=(850e20Pf~gW4H2(!?0(eeSrfXor}D+GrKum*^>{sfBJi5Tyw&e z`km67sP@U(KS$I>_Pf6JApUjv%Y>Ps;Q{xZ0J+&YN_^yeUPY05_M^zLR&t%%(HA48 z&a}P=jwTVahy`Orw?^t=B; z54Z!;0^X_rI}^N_2K{@9h$Bl$}%+$>!#PmB<)MeB|Ng- zvdf+L2)ZuRo_*DM;YWN|Mb(DAP}sDAGNNvNzplw|BK;9z)LjjRR+w6MY*v%_zn+fg zsF-HYlH-}-MT5liwCRy9-}xA7FTGo`T72Wl(DAP4#@#-_F^K7q*N2W~R9=R)x@|9x zvPhc#7$l`~30pm^jy2J>dV?j3a7x)ppRgQ@<{^v}i^PV*l2JDKCJ<3&9o|+YIDKN| zg!DmnLa9xUcg{A8wO~6_ls+Ft|34*NOra=q`Y^+ ztocs;aU=#ay+9&m%IlX(YDWoMUoKzjrx_zdi;|LRGRm(Y`x>*(tubrCIIO?k*_^gg zCL)wZRaAxGh&nIMIk?jPyv9b6g&EOmJipvv2)_}!sh~hT0CS~0r>05-x9d&!hS00| z8azLiiFH+Aps&;=C8)?7RF`07klMc~oo6frv6SJdzgvHalTJ-7&(UCoPYd=wq}aS& zvo@IhEj(>r&{6YHmN0l$<-ik(!z8<@3FpRYIRAy%IJzg<_}i|2@l9iDT)F{*T5=!q zSxE&`tE2x)lbjSb#^*v?Q>7ey8S;KruTTRWE>|II=c8lJP*nc`gn$wJ112m{I_ zO2M&=uw_C}$69yWD9>u^9T?|8N5{1J;lN5g47=wocaDTIT6>$NV6SFVJDA#wYiiV9 z#Bl7kRY>)W3A2pp%OCRl<`#A!Cb*J*jxn*bi-K>m^a2s9rR%6UBBGE3i zO}dxsk)@7T17YPw& zN}SOovIS4(471!+STnbB{>>||PhZ{L_;MsV)D;iYPMpwg(OsTh-qOELvx){^y+pY}+5V6ED2vvTC-& zG(<%eo~+sl-6@X2pL1}^J25tYEYsectq~P3Yz_+abv?y|G_*8Pnn)d#ellh{qSes7 zsHrl}JVWL;$V@eVSMVnZ+lSZ2qbUE#l#K4SNG~K#S;qTnG{rerUalJ-uxxD&@NT;P zSs~d$h4t?Ba8EAQUuT*3W<0uY;>ui{FO7@2Zo;$QE+J~}i)r5!+&_-B4D=r0Z z@LTi2!pA~sByKfNfwYK7J0mKXOXZzVXIYn0cCGaV#EMxw&F4^pX`ms4!*qml;fYsS zX-j$52wpfm!izuQ%nntDvDJb@vKLUPmUZB=rIbzfwF!_yks!$}c=LXmL|_SKMg92L zC7&33ZrA}=-p?|7jms`+<-cE8s~i?Bdh@u<`Q~L-YbE#?_wP)7E|Oh_jJ)tgy16=- zAfk^ZMq!6UH@HCVMhq90T>6zxAmAWLFegYA!-I%9%INO(p{gfZO-$q$C(_@Tj{g!*E_8nAJsI)^u}b%01US>uw#rNzZ+ ze=Y3wGiQiiC6<;Tt8d_J{tB{FGgt8VO9j`GzK3%l==dKI;!xOqMi4_K0^Rpm)*NfJ zHP%69$xL*NEjiqlibP(3go8cHd(k|_ONO}qsETY5Ybbs5zx1y4T2Vo|q-+AbWjhcR zP=*`*xhSKr<=atH!nG_$mw8vTCPleu_lzFVrW^HmHKj@OlWJr=YmJMl&!{f^jr2~0 zW2=*;gEkx^#8v6?hI^|p!adm(%6aGrY26xlG2!2VX|cJIxG+>~4dW@>52pEP&mH8i z_drC;SWo+It|U8%Q|&s^Bet#@Sxn4`R~S^(p1!B>Sn272TMyP^-LwG<(%s;+K3sgz{rA<$Q zSiq+Lv=;w#r`(;p8e39=0R~V+*tB1r=|j}Rnm@Z$I?j2OOh%g^G1x5fN$b0>Ow)g= z0)fB

0aUo)LvWv^7!2l^U%k4$3(y-p0K?tO?VGX6>g7=e%=j-}-(b*rWu3nv;G~ zY&MO?*B;E);D%QN`67G<-KR3nx1ph-HE|u&E?#1}QtE4`z%d1*$;%HjDT$Pu|unt75GYe?f|} zzRT^28apdy*6MS`$>}xxs5&Uh601};Mc+93Mo2)9ERcdlDZ!3|;??*enz5BXE59hR zub5_56)6;DWofNvTI4Ga$9;e2bu6s15femSZ+8iRISH*(K%@H`M6)@=$ncXtHd#{t z%Dh0v4c{4+XYuf@d0%Hp!I0e!mt)-;LK!eZTjZMB-lLB zK0Kq0>nKfejtpo`v1YWXd>tC+kw24iNR;|^V&~5>_+h6Rxl1RHNAF^393Vb~6H?h_ zDzUK6jE8eG_`$Yr)ugq*mRd-EZM(|JW@7=wpD%%O<_ZG6iZ#q*mhq(*(kejK5+5je z^-(OV9S5@6unQkVTfH5af;9A3mSd`_ey)5`#o^E|&jmJtn;OK-h~D3mvvSFM*<_ZA zrXapQDw;X0pDwyjLs{Vl)3-2bD;<(HJo&b359kC>^x6Qvvhv!b?1F2<_=q;4y}Z_& z5S5nXK%WZG)zNE?z3%Y5xus>&)V^{7OC+9m)deY4+KNM%L&I%%Z###Te^W z5`IobrY7d=XU#HY?^A(DWHjOpq`o&6ZXT~^Ewn`$g0v)y_92i|>1 ze1qq{<673{5(5k-?yg*viI0bi`K;m2#|IOmmMWTCOq!Y~Q={{-XNf})0!4%Erc1u< zq!&No6XcD(K(}Z|1sk~`HkCttYub{Re?TSkHVeyBZLN1^9vzcE<{2%NkfGr{zqh1* zx$pg&AF2*HD*xupc0h7;zlqk7=+{0OnR9U$Jh4Z@*lh1I*nE*qYhx1j$oK;_<8t$< zjbG^zu{WL4f3eeR`(Dy}RJJY-SK5W^Nphk`S`UWf=u4By=dG-8GV(O6p(o?%Va)`d zq&18k*3|fJ#A57>Tay=EBu?~&ygXlWwdAQuOLL<;jx$Srp><@xBmDlOprVIqcWw|I z?-cSo!+`Sy-i1$-vA;fjV6>3OA3h9yXrv94az3aolv$0p$5IOFx9Ql&Ys(wL!HQ3m z{L}&}g3vV+o{%zEs26yls_U=N0VKJ+=qL`4uYMNGc>{{=y{6Cg)2Fp{__$sP2Gg!s0KZiFSl-%W@27QHHRvMmmaPwO6)r z4>r9M0F}$|TyK@Bk*DlHhK#&R@7=1QMWR=MR!xl6mrq!Ez9ws9msMNytG(P7{>D_y zfQsKR>9GAaa9@n?apCys2Mqnah{`FmB4k$OCvZi&19hd06zbU;9qw2k@faK9Q5wK# zCfUVqWNV~Y*AqociaIXV{8))X~S zHySVzEz$v|P*k3K4)!>=u&DnPFje_+LqXgq8}2`L&l!~ z-ckAe7U>f5Hdy6uB{-m~RA5F4cXP|r#ow%3A6>5e-ibuZt-QY-%KZ33>?Cis$y8b4 z!Y62m?gXIn&j3)f>CZ7g%+{%Xu@+`s64Bw*s`Q=#T*9x9-XPqDRuiP`)K|iYtSsL7 zznBOd3gObDRy15SOG%h-R9jDhxV;4>@H@*tjRd1%%jyBv9a=n8zPFc}LI6`K3|T-P zT|JCjw|vd`SaUhlS1Pe&O{S-kO+~fwth^M2V0PkMK-xfWExiqVfse{pBb^`q%7IbV zvSy2cx@b}zOIN-zDH80hhg(=hgFJoFjLboFwCs13Wk-5B>mAwjBjRk;4&jh#Sq##Q z1s9VW$rGja6Vh0vHw7BmU)=k(mHvpL3>v_%#N7qR3C7@kJ+j2AFA$|Vv+Y=c(L!Lk zPD0|h!!7*40FH6Zf!9PP8a574TH4RuDVd~*`AVh^Q0Woc`jcJw&BJA*U#BzhTOU|j zrCM6+Uc*RpaaZ~;gu0VEvS_?i<Q%){jW! zD{Rx1j5k-dIfGWxK;KsOIOO8NLLWnm*^1}F+17MnRTb@GYa;UJa}-8f397#~@zUx!Nyy^Gasn@<#%<=n5=lr?D2tqQ2UUtlJxjL%^xyrP#h8$!9DR4e1Nci9v&m! zGx;@gJA_e%#%oSWA_g~l5x47OQejT@*`9hw;LN-6Mn|b0ap|w7G|w_fvDt$(1m;2)xfI;nvd%@oP(?lub%h*hj&`%^!ZO;a{TmIF`-Zv7$R>*9p9f zlScnV>`b~*ZAgeFkfGH?LS0o_`2G;K`DWPDdE}Bj-(~O8REGk&6wQ6+5i&1y0 zz0bTEXL-&a@dt0ATY$8n)91`@hCe#sIR7<7Xaz;Pe#q}gclGWA_zM5?a#VR-$FMcWOeWPysquNOw4v6AxW}Uv)gVJ2L&D4RL-4 zzq{QHM=jTB;W#9L{s#bNOqCp#2-H5N)tHW*kvkTDRg^TE+bD^F7~p(yEQ# zMS`X4-NmH5udIMOZIIz&3y#_z!0x^)+vH~1hOF;x%vhYusPJMGb}k84tllNv+c23y z5sdRh`psMPzZR+uf^JvpZx-(Ww2MsK{iI!90xnn;tHc)Esze$Fy=pk`^d6=#40q7f zXH&@Wdi`z%Y6BrH;FwrwtYl5_hT8(koU9x>*1njz2k?snsc>4GU7guGur%<`tVE}w z1mFBVOHDQf1s)I18r}WeH1<7=3Jax$*T+A1MhkuC1M*vSfJ36?*kDBbu=TrimL;15 zI%$*F^hIs&PQWi*$gF=pBPl5=*Th6|vZN$3HF-2NaylTtnW&LigmRxxLFD)Nj2pVV zZ%Ur0xUo~eSn>kq8*~yQji`BWRji|DjN|iJraZb z9JTU;-90=EOq!byDFmyIkM+UfP{6%a^O-p}Hl-isO#Ik3Vv5B2f-2z})TWMZIg-uj?0;6!jM$O;&*Dz@E_V3KHy->S`v{5I literal 0 HcmV?d00001 diff --git a/doc/getting-started.dox b/doc/getting-started.dox new file mode 100644 index 000000000..d98af28d5 --- /dev/null +++ b/doc/getting-started.dox @@ -0,0 +1,202 @@ +/* + 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 getting-started Getting started +@brief Get started with %Magnum in matter of minutes. + +@tableofcontents + +@section getting-started-download Download, build and install Magnum + +Get latest version from GitHub and install it. Read full guide on +@ref building "how to download, build and install Magnum" on platform of your +choice. For our first project we will use GLUT toolkit, don't forget to enable +it for building using `WITH_GLUTAPPLICATION` CMake parameter. + +@section getting-started-bootstrap Download bootstrap project + +Setting up a new project can be pretty gruesome and nobody likes repeating the +same process every time. %Magnum provides "bootstrap" project structures for +many use cases, helping you get up and running in no time. + +The [bootstrap repository](https://github.com/mosra/magnum-bootstrap) is +located on GitHub. The `master` branch contains just an README file and the +actual bootstrap projects are in various other branches, each covering some +particular use case. For your first project you would need the `base` branch, +which contains only the essential files you need. Download the branch [as an +archive](https://github.com/mosra/magnum-bootstrap/archive/base.zip) and +extract it somewhere. Do it rather than cloning the full repository, as it's +better to init your own repository from scratch to avoid having the history +polluted. + +@section getting-started-review Review project structure + +The base project consists of just seven files in two subfolders. %Magnum uses +CMake build system, see @ref cmake for more information. + + modules/FindCorrade.cmake + modules/FindMagnum.cmake + modules/FindGLEW.cmake + src/MyApplication.cpp + src/CMakeLists.txt + CMakeLists.txt + .gitignore + +In root there is pre-filled `.gitignore` for your Git project and also +project-wide `CMakeLists.txt`. It just sets up project name, specifies module +directory and delegates everything important to `CMakeLists.txt` in `src/` +subdirectory. +@code +cmake_minimum_required(VERSION 2.8.8) +project(MyApplication) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/modules/") + +add_subdirectory(src) +@endcode + +Directory `modules/` contains CMake modules for finding the needed +dependencies. Unlike modules for finding e.g. GLUT and OpenGL, which are part +of standard CMake installation, these aren't part of it and thus must be +distributed with the project. These files are just verbatim copied from %Magnum +repository. + +Directory `src/` contains the actual project. To keep things simple, the +project consists of just one source file with the most minimal code possible: +@code +#include +#include + +using namespace Magnum; + +class MyApplication: public Platform::Application { + public: + explicit MyApplication(const Arguments& arguments); + + protected: + void viewportEvent(const Vector2i& size) override; + void drawEvent() override; +}; + +MyApplication::MyApplication(const Arguments& arguments): Platform::Application(arguments) {} + +void MyApplication::viewportEvent(const Vector2i& size) { + defaultFramebuffer.setViewport({{}, size}); +} + +void MyApplication::drawEvent() { + defaultFramebuffer.clear(FramebufferClear::Color); + swapBuffers(); +} + +MAGNUM_APPLICATION_MAIN(MyApplication) +@endcode + +The application essentially does nothing, just clears properly sized screen +framebuffer to default (black) color and then does buffer swap to actually +display it on the screen. `CMakeLists.txt` finds %Magnum, sets up compiler +flags, creates the executable and links it to all needed libraries: +@code +find_package(Magnum REQUIRED GlutApplication) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CORRADE_CXX_FLAGS}") +include_directories(${MAGNUM_INCLUDE_DIRS} ${MAGNUM_APPLICATION_INCLUDE_DIRS}) + +add_executable(MyApplication MyApplication.cpp) +target_link_libraries(MyApplication + ${MAGNUM_LIBRARIES} + ${MAGNUM_APPLICATION_LIBRARIES}) +@endcode + +In the following tutorials the code will be explained more thoroughly. + +@section getting-started-build Build it and run + +In Linux (and other Unix-based OSs) you can build the example using the +following three commands: create out-of-source build directory, run cmake in it +and then run make. The application binary will then appear in src/ subdirectory +of build dir: + + mkdir -p build && cd build + cmake .. + make + ./src/MyApplication + +On Windows, if you don't want to touch the command-line, the easiest way is to +open root `CMakeLists.txt` in QtCreator, let it import the project and then +just build and run the application. If CMake isn't able to find the +dependencies or the building fails for some reason, you might want to look at +@ref building-windows-troubleshooting. + +@image html getting-started.png +@image latex getting-started.png + +Now you can try to change something in the code. Without going too deep into +the concepts of graphics programming, we can change clear color to something +else and also print basic information about the GPU the engine is running on. +First include the needed headers: +@code +#include +#include +#include +@endcode + +And in the constructor (which is currently empty) change the clear color and +print something to debug output: +@code +Renderer::setClearColor({0.07f, 0.44f, 0.73f}); + +Debug() << "Hello! This application is running on" << Context::current()->version() + << "using" << Context::current()->rendererString(); +@endcode + +After rebuilding and starting the application, the clear color changes to +blueish one and something like this would be printed to the console: +@code +Hello! This application is running on OpenGL 3.3 using Geforce GT 330M +@endcode + +@image html getting-started-blue.png +@image latex getting-started-blue.png + +@section getting-started-tutorials Follow tutorials and learn the principles + +Now that you have your first application up and running, the best way to +continue 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 and start +experimenting on your own! + +@section getting-started-more Additional information + +- @subpage building +- @subpage building-plugins +- @subpage building-integration +- @subpage cmake +- @subpage cmake-plugins +- @subpage cmake-integration + +*/ +} diff --git a/doc/getting-started.png b/doc/getting-started.png new file mode 100644 index 0000000000000000000000000000000000000000..cc0fc6112f11090702347a83ee48b7861983014b GIT binary patch literal 8215 zcmeHs_fr$d|93dgvmJ1AiYTC*qHUEB|v}(1R^1jZ$9(<^n7QYKj4|U-PzsQ_wIXl=iPR9UjN*7yd`~9 z;V1wAkhZbD;Q|0ibx2C^;a?<_zo5fHN%M2~HHT{eKvV89QP4q2{|}J0ivs|VbO``R z{|f;4@09dK03iMf0I+-q05E+H0Lb4hB|2Y~4Ez#ock2c~{NMb7TwNfc9Jy=l4F>>Z zO#uKIu9VE@oAm&I@@bnJ*WB*0R;MT6DmKA0>w#f%GQX4h7x*dEwK#!2&yV@2VN{2O z@;JBDe{Lda{o#4hp&xJ4?yHCv4~q}B2a4tn56b4e2I2g1J!1o1T$2R-7Wme-2~EB~ z%t-O)!!PP|_W(~nIR7DKhz!3Z*eyDDe_%k(O)gz@uH|Ud5y`RscS^@=ZOZw|0s#4Q zn1qAtu3AuG%r5T$;EI|>@PxID!rke&Vfv@y{!#+mQ8MQ+IYY`5*B;aWKQts=r=IHn zJqD0|;BLUi?cqQRn53GCy3>)iu;*o_h4B6ae%+e}uFdz}}&U+x}kNP!xY~ zI-ze%)?dZ|@>}$HOP9sG^+#A`{x@sq6D7vFJvVx+JPLzs0dG!~Zn8tENDS6|SU0q& z*p>kaaZ#bg^mS5y-+eS?Z28RJi~y^=Zen;-Q9e5xrzvNzBp*`oSs^kMx7VC22lx{C z!GuGC!@MCh{n*B$)=cWXKttOLwN3u;xwBJ$N{uH{HJjB6Ra{$RM^7GW|4lyHPlMIr zrSI(5>a5iN{BPP_KziOO8+N#sogN0ODc^P;+jFvj-fF9faNUMn3>YA>y!BnQW9Vn6 zV)|}k`<~I)I_18-%Fdjxxve$n(y1h8d(rpL6S!;@mG@UJ0`3F`uz~0>EgK*2v8dvz z=)OT)7ag0F`Z>~wZGd-5mmnIkq(T=EtI)&X(#NZMOmJ zXP{Bf@;c*gdLlpI$q$|7)QlBE(QZoPsYD}8LP}uCh{-JJtW2wGV2R3o8Bi7^J1lAQ z36hIb%{^NJ5!HlV;FN8e4<;94V^3CVQFWnqR*mKxlaX2HY(Xb(F;9WA+sclq9?Ph? ztsys1fEwdZi9Y0kdiO=L?0Z`n@ixk+Dl@}|N9L_rCn4e!xydt6M*CKt6;Yv>%?Ac$ zC}HV*`9#6%z~e15=ZwNCArIq+*j%HoUdWthM`^r@? zocYz;bM53duljTYaPD=2c-eR8*TAqlB|TpzDWU+mWKTw8^IqUyH?M~y7kOuZ=eYYe z^Pz9oxTsX_9;KJ{OTqxpy|nA;$jn<2D337r`T+OPS{D7MRjq|v4aQO1Ut1F?b%u%f zd0Z1K>Y}fBi)Zm;SG@gDS?rgeoPR+J-0sJMTy_WsMTd}@%ySxidaP3`6DLl|7kO3m z6DJUPfuRU&v+{w>bFDgd~mWX^75c=bPV&v%{(=f&1uja z*%RmC+3Dw^lxRj043riaSTTJoxErV~c)tmE3(3xBuqs4qRJmiAjoXwWi zCBZuI{YUmnfje^82w{{m_@gul5xS?oo)Q{h)-)F1%Xi?3s5qJh1;`hkPi|P+Z|Rz* zb?pZAl%M@|d;iVA?whCbr8`BF;szN*l6iIVl|O`v(U@^&yIsl%-HSGspg6@ym$er> zW*F1<-mYAP{*rSIn*6-6nUsEZ^K(&9FP^frz1PykRzDz{C${+`F?D4}t8ZNW? zKH0M*G7AMCX&j!0BeaL*hKDee*!f{W%v9PBFwWx%q{O|;z1~}~S0X7w?1@k&u`glY z$D`fs2I5coBJ2D-K^4uT%@+>BwZ)$JnDIapHCW(^TKea+y(zli&Nlystg@L$AvP%n z;?lCY=~EvA2@Q4NP|KW8+ypvB)T1IGNj@|h4My!Zsor`liwgC2`mGAAcDf=Xtb-C-mRX7P|xMl6kcJYM= za2I+vZ#rR?A-B>M4MvW%Pu`#bryE=Lmc|DZx>5{2Q)hvk(2&q5PHMPf7TD-K8)!0P zj=h6JB|0`zK29S@j?Z_u6LzOeC!ZuC(w?TT@NlaJ)8oj~dS8A?g6^3$-3P3&vn>yI z?E6>_!hUKLI6AKXDP?{^l5lWB{wTA@c~=@VMCEw#x<<&WT(H>S{vE3C@A3DqH*`}!5yvWHRvST=>7y!Y@=t)=h&G>QLzhlJ<|LGYb28ueO53PTs~ey{ zJKKn>bE#cvpo~UAVuNhhz_wxsgw6cMUy!z9A6%g=cFfgcC(z7ab8RiV-C}F4P`ZAc zT;-UHiwqk%RXq;###53VJ@OMBb*-4sr^&p(+;>~bc%+favS)cq z8mb2Mk-{Ay4>E7#+N(vXY}qXG;L7<6dvwga$=JzAN3>S?7)Lqf#jc{eSx1WRmIiYN z9WYvt#-PFGO!4meNZfLpQ5@{$*!~@^!|ruo5oWvt@!#=V!6S zJG;cY`y>w!&rlqL?uL~pI@B!sZBU$hx#^drgs|O@K^OY#S~toa=@w(|0+M-GiW6ZC z2T7HjH&?5_%AoUI>jiugxpAV?J4N(Fb}N@h!B2FW>}`qnySsPGcxr>XZ9Wng3pFTl z2nE+&0M{`f5pcNcyo*i7^=o-;tj|-)3sU1T4Ub2ZQr9EWPGtkr2(153}Dv00G3upu`8%#Oyzcwu21DmKlUCPvt7& z-5BpQ0YU8Qw2>NKlOgY8tV;h~G{9?g`F)a&SOgrB1N_!jkXtyaL* zmm};n&(X~prppd!Pc(WYMKITVes=52f;QjCLiAD#?HD1&BWBb1cvJ;5Y4&U924j0EQ6*rOa-MN{H!`pn*(nSbhzyTiy3cdZv1siMx^ z;W#Z)8C*#JBL5>gJ`9m07@1gOSPrTq>w@|lIkCA*Q+JVtYlL4DgEdrR$IOBtE||nH}?#!gd$$Bj*h8k zxD;3EZX|WIR}oVADh~Gci?S4f*-d7h53U_;H2JXo@$TENw+}R$#eKT~ozHfDxqV+W z<}7EZCYE zwZ{%wlI#ScAY*FCH_4M_$}pDdkM@$Bgt7!^6(uU%3P=}LUBs`(u5EwaFyp*=ba2M; z_0IIQYapT`aqVnr!g60L@-7?kk#@|dv0-sKamH1>oH2Eys$?9`72-zXxm4n%SDIz! zDUlh3w3JQ*pv|$`(sq_=SvtU{7)t!*jU{96?-6|KdY#Z#-n-?{2SY z`Z0?5K`X*v*0WC6Rnxl#NClgc%~dJ}R!BJ^w_3f7>#&{R%Q&v`%-(-g@uY@bWeT2~ z0ZvI6UmAc%3ikz++u*g5Brw9=qHA8xAd)Ej3KV`QjNid}&T+ZK)V<=E zn5FfK_>}FX>ZHwKqj(PWjQ`$>UYQ9pY{oFLYgh}NSzKEB>HSuGnQ^RN&pigWZF-(? z%TlHjl)PwW%-N$FH(|Wp;IrMS>onPT;n3xj^;rV{p?GU1e*WVz)1;M%@sf8Dt6wdn zuckJ5)MGsZk?!M-{k~2$LDQZ{ur%vHsX!6px2NatNYneh{}~Z~`Et>lH|JNW$I0c+ig)$O zlD2L}n|I)WR;Gw#XQQ>~nk#`WwO(!^S>KktHMKRD*x7-$S`4AE&Jd#casHr$RPPh- z^V})U$Yw6u=9c^={?aYXvTt=JadXgVp6cc{?K8f2NFA1Ny}y7@={m9Fi72BQfhx(0GXGyx4%W5C$EV?Uz zvd7D=wpW%26pFnxY`arrCO>;Qhs=>iSEfjXC(F7!3fdoQ!heeKvb_3PT@mXzqyCoT z*P)Yuk9w9A81_b*I?3(GF-=R{4r)JURUa8yTv9Zu2o)8cHBYW7P|c|qhFCh)F}e)} z|D0DR?+dvwEymOn`FY)H21*V!aC~)jaKca}zHr8^5KBxHH12=X-p^Q@?y4>^fN7)7?B_!;0a>{qf zPgJ!E&-*^D4AZaZ!tBcq4{0tYihpRk7rhqp-z!HnKU?Hy%skCzalSUR5#gN1ORB2z z`yy}mO9Q3}E6>*~yhiy$ttS`cS&E7`>ll$fh}Y*Mv-3Ud!0Mwt1*)tDMx5wJtlZHI zOSAvH&mBq)RQkN;tQ4~Uy8hB8hsPfFjroCkxLQK0KXhpD7kq>MUdtgurFglY8p}1y z+N13O!(al6*mhtFG?Dn6Bq+8>^0|f1S$vn#QjGDX+xM#%`;2XDjfQBREFvIi`OF+Zwu91Z!Ss)V?e3{U>I9gr@&R-armpOLxjbT)E%&QAD{ zC(0?e(5Y@i0fpZJ+*@urF0M4aYV`M|4du-WnS=5MMrIWi;nbyf{RgMJV|`r*tMz?h znQBi=n_FvkijJVF<+ns1_WtdTq*!qFS(~)-WU(=4iKxV!v5`udwo!+%c`z zT^({|T;{j9hej;z&!)NN*C(E;TR%o^p?LnH_#=db5~N_w-#|h7BeO==q;`0??rcK? zBq=QH#c;~^J2#j81fQlLi|ai-*3oO*8Z>(d|CwcE>Rn!3%y>`my=Eee}Ucrc>tz8dcw&T5@J^6ZRSc zkh4HFl*--$RQ&QRE~N^^FmT6Q9ep=eNkaeERD^u+GzsCFd)ADFaFLgnj~9JjpDxJh zS^Uv7YwPomWWP4;!`}m9U%r5Is9+du<5OZdevgkV|Md*JVi9A}k<<9{Hu%Tg`ItlZ z?sVw#-W8NR(Mn>H^}dX6z3#%Fro}J4;3d6Yec8*_otO1qbJOX<=Te_kc1cBH=xeMr z>FuM0$3o!@?*RE0C`1(Fx=0=$n~;yYk#7?3!nUh+ve89P${*alF>bCkV1IRNNj`vy zg%55}!IFn|{wQ`e$OF-jJY&XWQ$UbFFZUXaWlSmu2^`54SfwRw`{wif%n;xH)*{Eu zG1mNtG0E4C<@*(b!*)soQXFBp!jq1HW6;85rm?Y-+p7FiMVF_$cRAfoTL~)rwbYEz zQZdufYW4xCQ!OPJGr~a8#xtq=q}Gn9&dgRZ!|=McgTl+|LQlgB^d#jV-nss-QpTS_ z+{?-aedRat(XYQfjbG8Bz(q2X5-XVPk&ceK3J&aFB%eeVK5Fk2czX24z`M|t*v$p@ zpvA+zt8?kx{SO=iJxZlIWfPsLnmIsXgoIk9ZH(-<)ilyyy+%Rj|}1F+>Km!$cR9?fj?7sr5pOsTA|6bUmwBrOP=WgiVIAN9Wb1 z%_CH6wIOQ4c7?#TY>AF{Q}f>~wm2Vo0cE@C^GW1Les7@<;t_v&G~1qN$s(^@4Nsl1 zeKa&v5qm~AEs=UBNv3csEf1OaZVt6YUuCV8HsAj`TE0P&rd}TAYRUowI_D9+clvbw z1LMwk(WD$3WXNa17%Y(x99|$)V87&kKQQ`9@CK1Bd>Xnj0Do+-ser_ENxgp%Ja>Dg zc2Y6QoX|k=EOIS`CqIs=f<1)xHTC=UQZoWAncG<{4rBQC;b|yBCO79`hax2Iu9H1 z>XmU0%7A9+%X|A1HG;qkXNeKKVNo7vEpTr#jSvreXa6bp03hp~wJ>-Py2oJDbrBHL zQJl=m1g6sK_i^9P`l-H6ejH03KR*8BN=aAy6?csxt44mPvOeIA=ZqCZQQ6Ix(x9p+ zJv)`q(CWHyImvGJ=TfxJ>aDm97<&-NY1W9h8MAGNw0XpXX5|B~l47e312sRkfB!#A z1nR~2&)&*q`Y^JyB}fk3W(?+CH~>`TkV{z;pdl~SWh-f8Z4>;^jz)qOtX6`skOp1Q zSR2-77R1BIaE0~o5Zh$@o+!efX*C;l81Q90KM(HhGc(nI$2S_*D=LCPk%OV&Z~let zEtlepN?jKu_*HOw*6(-APzXF75y+<^(K{M;{w&+(%29g-X9vcg`J`qXF3C*|6{;C1 z!BSU7Owa};*&cf~ZQj%OO7$Ua8eo0NdWmwVlO#F z7guT7`czH)UD{-rm*+&&$Bjo;{no4Nck2k?)O`V46%!=!19k z9bC~>=BR?fQkmGl#}cQLYL}j!(3MAW{nVWy4OtBe`CHUZ4Vz{UvexmNY$ZNX9`FW# ze0F}mMZ=Ev;o@*rq@jX0D}va{fHk6wF=4iTmkbC8Vk!fsPI11>UF1Du=*<*2zh(k1@|saLRV=y6cpP1KEtog4^s=> zBNI}xS%bR%7VUekIc^%gRW&ttqN1YD>GoJPH=(xpYyhAF-ZO}msK5jr@=szd^s;Mx zo^7^$K39~b1e^WY*|G1Y$7o39^%F&2hPrue`SX)ffb{iKCjFu2aC4Mve*B}0Evt8s zVP+j`!s&D27eLrosBGM~2hMZZSIvwiaB9~2K$d6my-vD~rsNeJy>hoeW?Q~{=sTtc zsQ^fKjt=CErlIEgJRP=y5x*5R`WEO(1KxBHEr&Svx%1$6eRET)QviUIiuNa&xS-yk zpYu;Q{R&7A68#)^ C{miNW literal 0 HcmV?d00001 diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 38697a952..d2fac13bf 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -83,16 +83,10 @@ namespace Magnum { - 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! +@ref getting-started "Thorough guide" to download, build, install and start +using Magnum in your project. @section mainpage-hacking Hacking Magnum From ca846fc1f18b77fefc1e6cc32a0e703fff704ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 22:08:01 +0200 Subject: [PATCH 42/64] package: updated magnum-git ArchLinux package. Enabled the least intrusive parts to avoid having many/obscure dependencies. People would need to enable additional modules on their own. --- package/archlinux/magnum-git/PKGBUILD | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/package/archlinux/magnum-git/PKGBUILD b/package/archlinux/magnum-git/PKGBUILD index 5e3128719..12dc8f573 100644 --- a/package/archlinux/magnum-git/PKGBUILD +++ b/package/archlinux/magnum-git/PKGBUILD @@ -1,17 +1,23 @@ # Author: mosra pkgname=magnum-git -pkgver=20120331 +pkgver=20130819 pkgrel=1 -pkgdesc="OpenGL 3 graphics engine (Git version)" +pkgdesc="C++11 and OpenGL 2D/3D graphics engine (Git version)" arch=('i686' 'x86_64') -url="https://github.com/mosra/magnum" +url="http://mosra.cz/blog/magnum.php" license=('MIT') -depends=('corrade-git' 'glew') +depends=('corrade-git' 'glew' 'glut' 'openal') makedepends=('cmake' 'git') +provides=('magnum') +conflicts=('magnum') _gitroot="git://github.com/mosra/magnum.git" _gitname="magnum" +pkgver() { + date +%Y%m%d +} + build() { cd "$srcdir" msg "Connecting to Git server..." @@ -31,15 +37,14 @@ build() { cmake ../$_gitname \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/usr + -DCMAKE_INSTALL_PREFIX=/usr \ + -DWITH_GLUTAPPLICATION=ON \ + -DWITH_GLXAPPLICATION=ON \ + -DWITH_WINDOWLESSGLXAPPLICATION=ON \ + -DWITH_MAGNUMINFO=ON make } -check() { - cd "$startdir/build" - ctest --output-on-failure -E Benchmark -} - package() { cd "$srcdir/build" make DESTDIR="$pkgdir/" install From 81844d1092590638b3fc16b36dda61f39c35cca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 22:09:02 +0200 Subject: [PATCH 43/64] Updated ArchLinux building documentation. --- doc/building.dox | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/doc/building.dox b/doc/building.dox index caaca74dd..97044ac8b 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -230,18 +230,17 @@ Integration with various external math and physics libraries is provided by In `package/archlinux` directory is currently one PKGBUILD for Git development build. The package is also in AUR under the same name. -There is also development PKGBUILD and MinGW development PKGBUILD in root, -which allows you to build and install the package directly from source tree -without downloading anything. The PKGBUILD also contains `check()` function -which will run all unit tests before packaging. Note that the unit tests -require Qt, as said above. +There are also a few development PKGBUILDs in project root, which allow you to +build and install the package directly from source tree without downloading +anything. The native PKGBUILD also contains `check()` function which will run +all unit tests before packaging. If you want to build with another compiler (e.g. Clang), run makepkg this way: CXX=clang++ makepkg -Both development PKGBUILDs can detect when Clang is used and remove -unsupported CXX flags. +Development PKGBUILDs can detect when Clang is used and remove unsupported CXX +flags. @section building-win Crosscompiling for Windows using MinGW From c381572cff50ed1b42aec439a3f488f972025264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 22:27:56 +0200 Subject: [PATCH 44/64] Better links to Getting Started Guide. --- README.md | 6 ++++++ doc/mainpage.dox | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d88d832df..bd95badec 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,12 @@ in root directory (i.e. where `Doxyfile` is). Resulting HTML documentation will be in `build/doc/` directory. You might need to create `build/` directory if it doesn't exist yet. +GETTING STARTED +=============== + +The Doxygen documentation has a thorough [guide how to start using Magnum](http://mosra.cz/blog/magnum-doc/getting-started.html) +in your project. + RELATED PROJECTS ================ diff --git a/doc/mainpage.dox b/doc/mainpage.dox index d2fac13bf..ff86d27a1 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -85,8 +85,8 @@ namespace Magnum { @section mainpage-getting-started Getting started -@ref getting-started "Thorough guide" to download, build, install and start -using Magnum in your project. +Read thorough @ref getting-started "guide to download, build, install and start using Magnum" +in your project. @section mainpage-hacking Hacking Magnum From 75fbe4ac84f54cadefe8e9b1461a5d495883aa97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 23:16:05 +0200 Subject: [PATCH 45/64] Fixed typo in documentation. I'm bored. --- doc/types.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/types.dox b/doc/types.dox index 99d6f8755..3ddb332a6 100644 --- a/doc/types.dox +++ b/doc/types.dox @@ -69,7 +69,7 @@ type, `i` is @ref Int underlying type and `d` is for @ref Double underlying 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 Matrix4 or @ref Matrix4d | `mat4`/`mat4x4` or `dmat4`/`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` | From c4d3446dacca1e62f7ccc2059616ecac22c7b001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 23:16:50 +0200 Subject: [PATCH 46/64] DebugTools: got rid of unnecessary normalization. The tests needed slight ugly adjustment, but I can live with that. --- src/DebugTools/Implementation/ForceRendererTransformation.h | 3 ++- src/DebugTools/Test/ForceRendererTest.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/DebugTools/Implementation/ForceRendererTransformation.h b/src/DebugTools/Implementation/ForceRendererTransformation.h index 83879104c..606c0cf7a 100644 --- a/src/DebugTools/Implementation/ForceRendererTransformation.h +++ b/src/DebugTools/Implementation/ForceRendererTransformation.h @@ -59,7 +59,8 @@ template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, 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(); + const Vector3 binormal = Vector3::cross(normal, force/forceLength); + CORRADE_INTERNAL_ASSERT(binormal.isNormalized()); /* Transformation matrix from scaled base vectors and translation vector */ return Matrix4::from({force, normal*forceLength, binormal*forceLength}, forcePosition); diff --git a/src/DebugTools/Test/ForceRendererTest.cpp b/src/DebugTools/Test/ForceRendererTest.cpp index 7d1a733ff..e7e645221 100644 --- a/src/DebugTools/Test/ForceRendererTest.cpp +++ b/src/DebugTools/Test/ForceRendererTest.cpp @@ -115,7 +115,8 @@ void ForceRendererTest::arbitrary3D() { /* All vectors are orthogonal */ 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); + /** @todo This shouldn't be too different */ + CORRADE_COMPARE(Vector3::dot(m.up(), m.backward()), -Math::TypeTraits::epsilon()); } }}}} From 746424bf677acadf973606064024d004e3880798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 23:48:10 +0200 Subject: [PATCH 47/64] DebugTools: simplified 3D ForceRenderer transformation computation. --- .../Implementation/ForceRendererTransformation.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/DebugTools/Implementation/ForceRendererTransformation.h b/src/DebugTools/Implementation/ForceRendererTransformation.h index 606c0cf7a..fa4cdaf60 100644 --- a/src/DebugTools/Implementation/ForceRendererTransformation.h +++ b/src/DebugTools/Implementation/ForceRendererTransformation.h @@ -24,6 +24,7 @@ DEALINGS IN THE SOFTWARE. */ +#include "Math/Functions.h" #include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Magnum.h" @@ -48,12 +49,8 @@ template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, 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}); + if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) + return translation*Matrix4::scaling({Math::sign(dot)*forceLength, forceLength, forceLength}); /* Normal of plane going through force vector and X axis vector */ const Vector3 normal = Vector3::cross(Vector3::xAxis(), force).normalized(); From f48ed0af13a2fd65ad7c4003e8287007432e26fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 23:49:58 +0200 Subject: [PATCH 48/64] DebugTools: simplified also 2D ForceRenderer transformation computation. Also removed unneeded tests, as they don't reflect the code in any way. --- .../ForceRendererTransformation.h | 2 +- src/DebugTools/Test/ForceRendererTest.cpp | 20 +++---------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/DebugTools/Implementation/ForceRendererTransformation.h b/src/DebugTools/Implementation/ForceRendererTransformation.h index fa4cdaf60..8674cbafa 100644 --- a/src/DebugTools/Implementation/ForceRendererTransformation.h +++ b/src/DebugTools/Implementation/ForceRendererTransformation.h @@ -35,7 +35,7 @@ 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); + return Matrix3::from({force, force.perpendicular()}, forcePosition); } template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, const Vector3& force) { diff --git a/src/DebugTools/Test/ForceRendererTest.cpp b/src/DebugTools/Test/ForceRendererTest.cpp index e7e645221..d560e8e38 100644 --- a/src/DebugTools/Test/ForceRendererTest.cpp +++ b/src/DebugTools/Test/ForceRendererTest.cpp @@ -33,9 +33,7 @@ class ForceRendererTest: public TestSuite::Tester { explicit ForceRendererTest(); void zero2D(); - void parallel2D(); - void antiParallel2D(); - void arbitrary2D(); + void common2D(); void zero3D(); void parallel3D(); @@ -45,9 +43,7 @@ class ForceRendererTest: public TestSuite::Tester { ForceRendererTest::ForceRendererTest() { addTests({&ForceRendererTest::zero2D, - &ForceRendererTest::parallel2D, - &ForceRendererTest::antiParallel2D, - &ForceRendererTest::arbitrary2D, + &ForceRendererTest::common2D, &ForceRendererTest::zero3D, &ForceRendererTest::parallel3D, @@ -60,17 +56,7 @@ void ForceRendererTest::zero2D() { 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() { +void ForceRendererTest::common2D() { Vector2 force(2.7f, -11.5f); Matrix3 m = Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, force); From d329f06b2261b4197ca142eb2f2abe49ff048ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 19 Aug 2013 23:53:11 +0200 Subject: [PATCH 49/64] DebugTools: saved some repetitive multiplication/division. Saves ONE division. Awesome. I'm bored more. --- .../Implementation/CapsuleRendererTransformation.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/DebugTools/Implementation/CapsuleRendererTransformation.h b/src/DebugTools/Implementation/CapsuleRendererTransformation.h index be649c77f..4886d3578 100644 --- a/src/DebugTools/Implementation/CapsuleRendererTransformation.h +++ b/src/DebugTools/Implementation/CapsuleRendererTransformation.h @@ -71,12 +71,13 @@ template<> std::array capsuleRendererTransformation<3>(const Vector3 Matrix4 rotation; Vector3 capDistance; if(length >= Math::TypeTraits::epsilon()) { - rotation.up() = direction/length; + const Vector3 directionNormalized = direction/length; + rotation.up() = directionNormalized; rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); - capDistance = direction*(radius/length); + capDistance = directionNormalized*radius; } /* Scaling and translation of all parts */ From 40797af256ac328ea780e36081cd67d7a986fcb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 00:19:54 +0200 Subject: [PATCH 50/64] DebugTools: auto? auto, auto. --- src/DebugTools/Test/CapsuleRendererTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DebugTools/Test/CapsuleRendererTest.cpp b/src/DebugTools/Test/CapsuleRendererTest.cpp index 96e5013c1..06900d664 100644 --- a/src/DebugTools/Test/CapsuleRendererTest.cpp +++ b/src/DebugTools/Test/CapsuleRendererTest.cpp @@ -72,7 +72,7 @@ void CapsuleRendererTest::common2D() { CORRADE_COMPARE(transformation[1].up(), up); CORRADE_COMPARE(transformation[2].up(), up.resized(3.5f)); - const Vector2 right = Vector2(4.0f, 7.0f).resized(3.5f); + const auto right = Vector2(4.0f, 7.0f).resized(3.5f); CORRADE_COMPARE(transformation[0].right(), right); CORRADE_COMPARE(transformation[1].right(), right); CORRADE_COMPARE(transformation[2].right(), right); From b5a2cb6b1123f5a66c0d2fa96371822fa16ece63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 00:20:32 +0200 Subject: [PATCH 51/64] DebugTools: properly implemented special cases for CapsuleRenderer. --- .../CapsuleRendererTransformation.h | 20 ++++++++-- src/DebugTools/Test/CapsuleRendererTest.cpp | 40 +++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/DebugTools/Implementation/CapsuleRendererTransformation.h b/src/DebugTools/Implementation/CapsuleRendererTransformation.h index 4886d3578..5f9271a67 100644 --- a/src/DebugTools/Implementation/CapsuleRendererTransformation.h +++ b/src/DebugTools/Implementation/CapsuleRendererTransformation.h @@ -26,6 +26,7 @@ #include +#include "Math/Functions.h" #include "Math/Matrix3.h" #include "Math/Matrix4.h" #include "Magnum.h" @@ -72,10 +73,21 @@ template<> std::array capsuleRendererTransformation<3>(const Vector3 Vector3 capDistance; if(length >= Math::TypeTraits::epsilon()) { const Vector3 directionNormalized = direction/length; - rotation.up() = directionNormalized; - rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); - rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); - CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); + const Float dot = Vector3::dot(directionNormalized, Vector3::zAxis()); + + /* Direction is parallel to Z axis, special rotation case */ + if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) { + rotation.up() = dot*Vector3::zAxis(); + rotation.right() = Vector3::xAxis(); + rotation.backward() = -dot*Vector3::yAxis(); + + /* Common case */ + } else { + rotation.up() = directionNormalized; + rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); + rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); + CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); + } capDistance = directionNormalized*radius; } diff --git a/src/DebugTools/Test/CapsuleRendererTest.cpp b/src/DebugTools/Test/CapsuleRendererTest.cpp index 06900d664..4c0f7d762 100644 --- a/src/DebugTools/Test/CapsuleRendererTest.cpp +++ b/src/DebugTools/Test/CapsuleRendererTest.cpp @@ -36,6 +36,8 @@ class CapsuleRendererTest: public TestSuite::Tester { void common2D(); void zeroLength3D(); + void parallel3D(); + void antiParallel3D(); void common3D(); }; @@ -44,6 +46,8 @@ CapsuleRendererTest::CapsuleRendererTest() { &CapsuleRendererTest::common2D, &CapsuleRendererTest::zeroLength3D, + &CapsuleRendererTest::parallel3D, + &CapsuleRendererTest::antiParallel3D, &CapsuleRendererTest::common3D}); } @@ -100,6 +104,42 @@ void CapsuleRendererTest::zeroLength3D() { CORRADE_COMPARE(transformation[2].translation(), a); } +void CapsuleRendererTest::parallel3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Vector3 b(0.5f, 3.0f, 11.0f); + std::array transformation = Implementation::capsuleRendererTransformation<3>(a, b, 3.5f); + + const auto rotation = Matrix4::rotationX(Deg(90.0f)); + const auto scaling = (rotation*Matrix4::scaling(Vector3(3.5f))).rotationScaling(); + CORRADE_COMPARE(transformation[0].rotationScaling(), scaling); + CORRADE_COMPARE(transformation[1].rotationScaling(), + (rotation*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling()); + CORRADE_COMPARE(transformation[2].rotationScaling(), scaling); + + const auto capDistance = Vector3::zAxis(3.5f); + CORRADE_COMPARE(transformation[0].translation(), a+capDistance); + CORRADE_COMPARE(transformation[1].translation(), a+Vector3::zAxis(2.0f)); + CORRADE_COMPARE(transformation[2].translation(), b-capDistance); +} + +void CapsuleRendererTest::antiParallel3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Vector3 b(0.5f, 3.0f, 3.0f); + std::array transformation = Implementation::capsuleRendererTransformation<3>(a, b, 3.5f); + + const auto rotation = Matrix4::rotationX(-Deg(90.0f)); + const auto rotationScaling = (rotation*Matrix4::scaling(Vector3(3.5f))).rotationScaling(); + CORRADE_COMPARE(transformation[0].rotationScaling(), rotationScaling); + CORRADE_COMPARE(transformation[1].rotationScaling(), + (rotation*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling()); + CORRADE_COMPARE(transformation[2].rotationScaling(), rotationScaling); + + const auto capDistance = Vector3::zAxis(-3.5f); + CORRADE_COMPARE(transformation[0].translation(), a+capDistance); + CORRADE_COMPARE(transformation[1].translation(), a+Vector3::zAxis(-2.0f)); + CORRADE_COMPARE(transformation[2].translation(), b-capDistance); +} + void CapsuleRendererTest::common3D() { const Vector3 a(0.5f, 3.0f, 7.0f); const Vector3 b(7.5f, -1.0f, 1.5f); From 59be5e26f74b2ed28494a6b762eaa5eb94cec28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 21:02:12 +0200 Subject: [PATCH 52/64] Math: added uniform scaling extraction to Matrix[34]. --- src/Math/Matrix3.h | 25 ++++++++++++++++++++----- src/Math/Matrix4.h | 29 ++++++++++++++++++++++++----- src/Math/Test/Matrix3Test.cpp | 16 ++++++++++++++++ src/Math/Test/Matrix4Test.cpp | 16 ++++++++++++++++ 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index d977a79c1..ab88b85c4 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -164,7 +164,7 @@ template class Matrix3: public Matrix<3, T> { * * Upper-left 2x2 part of the matrix. * @see from(const Matrix<2, T>&, const Vector2&), rotation() const - * rotationNormalized(), rotation(T), + * rotationNormalized(), @ref uniformScaling(), rotation(T), * Matrix4::rotationScaling() const */ constexpr Matrix<2, T> rotationScaling() const { @@ -177,7 +177,8 @@ template class Matrix3: public Matrix<3, T> { * * Similar to @ref rotationScaling(), but additionally checks that the * base vectors are normalized. - * @see rotation() const, @ref Matrix4::rotationNormalized() + * @see rotation() const, @ref uniformScaling(), + * @ref Matrix4::rotationNormalized() * @todo assert also orthogonality or this is good enough? */ Matrix<2, T> rotationNormalized() const { @@ -191,8 +192,8 @@ template class Matrix3: public Matrix<3, T> { * @brief 2D rotation part of the matrix * * Normalized upper-left 2x2 part of the matrix. - * @see rotationNormalized(), rotationScaling() const, rotation(T), - * Matrix4::rotation() const + * @see rotationNormalized(), rotationScaling(), @ref uniformScaling(), + * rotation(T), Matrix4::rotation() const * @todo assert uniform scaling (otherwise this would be garbage) */ Matrix<2, T> rotation() const { @@ -200,7 +201,21 @@ template class Matrix3: public Matrix<3, T> { (*this)[1].xy().normalized()}; } - /** @todo uniform scaling extraction */ + /** + * @brief Uniform scaling part of the matrix + * + * Length of vectors in upper-left 2x2 part of the matrix. Expects that + * the scaling is the same in all axes. + * @see @ref rotationScaling(), @ref rotation(), + * @ref rotationNormalized(), @ref scaling(const Vector2&), + * @ref Matrix4::uniformScaling() + */ + T uniformScaling() const { + const T scalingSquared = (*this)[0].xy().dot(); + CORRADE_ASSERT(TypeTraits::equals((*this)[1].xy().dot(), scalingSquared), + "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling", {}); + return std::sqrt(scalingSquared); + } /** * @brief Right-pointing 2D vector diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index dec15dbfc..a082f3bbd 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -227,8 +227,8 @@ template class Matrix4: public Matrix<4, T> { * * Upper-left 3x3 part of the matrix. * @see from(const Matrix<3, T>&, const Vector3&), rotation() const, - * rotationNormalized(), rotation(T, const Vector3&), - * Matrix3::rotationScaling() const + * rotationNormalized(), @ref uniformScaling(), + * rotation(T, const Vector3&), Matrix3::rotationScaling() const */ /* Not Matrix3, because it is for affine 2D transformations */ constexpr Matrix<3, T> rotationScaling() const { @@ -242,7 +242,8 @@ template class Matrix4: public Matrix<4, T> { * * Similar to @ref rotationScaling(), but additionally checks that the * base vectors are normalized. - * @see rotation() const, @ref Matrix3::rotationNormalized() + * @see rotation() const, @ref uniformScaling(), + * @ref Matrix3::rotationNormalized() * @todo assert also orthogonality or this is good enough? */ /* Not Matrix3, because it is for affine 2D transformations */ @@ -259,13 +260,23 @@ template class Matrix4: public Matrix<4, T> { * * Normalized upper-left 3x3 part of the matrix. * @see rotationNormalized(), rotationScaling() const, - * rotation(T, const Vector3&), Matrix3::rotation() const + * @ref uniformScaling(), rotation(T, const Vector3&), + * Matrix3::rotation() const * @todo assert uniform scaling (otherwise this would be garbage) */ /* Not Matrix3, because it is for affine 2D transformations */ Matrix<3, T> rotation() const; - /** @todo uniform scaling extraction */ + /** + * @brief Uniform scaling part of the matrix + * + * Length of vectors in upper-left 3x3 part of the matrix. Expects that + * the scaling is the same in all axes. + * @see @ref rotationScaling(), @ref rotation(), + * @ref rotationNormalized(), @ref scaling(const Vector3&), + * @ref Matrix3::uniformScaling() + */ + T uniformScaling() const; /** * @brief Right-pointing 3D vector @@ -446,6 +457,14 @@ template inline Matrix<3, T> Matrix4::rotation() const { (*this)[2].xyz().normalized()}; } +template T Matrix4::uniformScaling() const { + const T scalingSquared = (*this)[0].xyz().dot(); + CORRADE_ASSERT(TypeTraits::equals((*this)[1].xyz().dot(), scalingSquared) && + TypeTraits::equals((*this)[2].xyz().dot(), scalingSquared), + "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling", {}); + return std::sqrt(scalingSquared); +} + template Matrix4 Matrix4::invertedRigid() const { CORRADE_ASSERT(isRigidTransformation(), "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {}); diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index efadb60af..c55425112 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -78,6 +78,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester { void rotationScalingPart(); void rotationNormalizedPart(); void rotationPart(); + void uniformScalingPart(); void vectorParts(); void invertedRigid(); void transform(); @@ -113,6 +114,7 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::rotationScalingPart, &Matrix3Test::rotationNormalizedPart, &Matrix3Test::rotationPart, + &Matrix3Test::uniformScalingPart, &Matrix3Test::vectorParts, &Matrix3Test::invertedRigid, &Matrix3Test::transform, @@ -334,6 +336,20 @@ void Matrix3Test::rotationPart() { } } +void Matrix3Test::uniformScalingPart() { + const Matrix3 rotation = Matrix3::rotation(Deg(-74.0f)); + + /* Test uniform scaling */ + CORRADE_COMPARE((rotation*Matrix3::scaling(Vector2(3.0f))).uniformScaling(), 3.0f); + + /* Fails on non-uniform scaling */ + std::ostringstream o; + Error::setOutput(&o); + const Float nonUniformScaling = (rotation*Matrix3::scaling(Vector2::yScale(3.0f))).uniformScaling(); + CORRADE_COMPARE(o.str(), "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(nonUniformScaling, 0.0f); +} + void Matrix3Test::vectorParts() { constexpr Matrix3 a({15.0f, 0.0f, 0.0f}, { 0.0f, -3.0f, 0.0f}, diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index 31659580a..fb84fc54e 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -85,6 +85,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester { void rotationScalingPart(); void rotationNormalizedPart(); void rotationPart(); + void uniformScalingPart(); void vectorParts(); void invertedRigid(); void transform(); @@ -125,6 +126,7 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::rotationScalingPart, &Matrix4Test::rotationNormalizedPart, &Matrix4Test::rotationPart, + &Matrix4Test::uniformScalingPart, &Matrix4Test::vectorParts, &Matrix4Test::invertedRigid, &Matrix4Test::transform, @@ -420,6 +422,20 @@ void Matrix4Test::rotationPart() { } } +void Matrix4Test::uniformScalingPart() { + const Matrix4 rotation = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()); + + /* Test uniform scaling */ + CORRADE_COMPARE((rotation*Matrix4::scaling(Vector3(3.0f))).uniformScaling(), 3.0f); + + /* Fails on non-uniform scaling */ + std::ostringstream o; + Error::setOutput(&o); + const Float nonUniformScaling = (rotation*Matrix4::scaling(Vector3::yScale(3.0f))).uniformScaling(); + CORRADE_COMPARE(o.str(), "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(nonUniformScaling, 0.0f); +} + void Matrix4Test::vectorParts() { constexpr Matrix4 a({-1.0f, 0.0f, 0.0f, 0.0f}, { 0.0f, 12.0f, 0.0f, 0.0f}, From f2840e5880ae5314ec4ca3089aac7fdaa679864e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 21:03:08 +0200 Subject: [PATCH 53/64] Math: assert uniform scaling in Matrix[34]::rotation(). Needed to adjust the test cases slightly, because they were firing the assert even if they shouldn't and the "expect fail" case wasn't working at all. I now badly need proper floating-point equality comparison. --- src/Math/Matrix3.h | 6 ++++-- src/Math/Matrix4.h | 7 +++++-- src/Math/Test/Matrix3Test.cpp | 15 ++++++--------- src/Math/Test/Matrix4Test.cpp | 15 ++++++--------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index ab88b85c4..6b7398102 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -191,12 +191,14 @@ template class Matrix3: public Matrix<3, T> { /** * @brief 2D rotation part of the matrix * - * Normalized upper-left 2x2 part of the matrix. + * Normalized upper-left 2x2 part of the matrix. Expects uniform + * scaling. * @see rotationNormalized(), rotationScaling(), @ref uniformScaling(), * rotation(T), Matrix4::rotation() const - * @todo assert uniform scaling (otherwise this would be garbage) */ Matrix<2, T> rotation() const { + CORRADE_ASSERT(TypeTraits::equals((*this)[0].xy().dot(), (*this)[1].xy().dot()), + "Math::Matrix3::rotation(): the matrix doesn't have uniform scaling", {}); return {(*this)[0].xy().normalized(), (*this)[1].xy().normalized()}; } diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index a082f3bbd..48f5c84db 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -258,11 +258,11 @@ template class Matrix4: public Matrix<4, T> { /** * @brief 3D rotation part of the matrix * - * Normalized upper-left 3x3 part of the matrix. + * Normalized upper-left 3x3 part of the matrix. Expects uniform + * scaling. * @see rotationNormalized(), rotationScaling() const, * @ref uniformScaling(), rotation(T, const Vector3&), * Matrix3::rotation() const - * @todo assert uniform scaling (otherwise this would be garbage) */ /* Not Matrix3, because it is for affine 2D transformations */ Matrix<3, T> rotation() const; @@ -452,6 +452,9 @@ template Matrix4 Matrix4::perspectiveProjection(const Vector2& } template inline Matrix<3, T> Matrix4::rotation() const { + CORRADE_ASSERT(TypeTraits::equals((*this)[0].xyz().dot(), (*this)[1].xyz().dot()) && + TypeTraits::equals((*this)[1].xyz().dot(), (*this)[2].xyz().dot()), + "Math::Matrix4::rotation(): the matrix doesn't have uniform scaling", {}); return {(*this)[0].xyz().normalized(), (*this)[1].xyz().normalized(), (*this)[2].xyz().normalized()}; diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index c55425112..2cf0d8b2a 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -319,21 +319,18 @@ void Matrix3Test::rotationPart() { CORRADE_COMPARE(rotationTranslationPart, expectedRotationPart); /* Test uniform scaling */ - Matrix3 rotationScaling = rotation*Matrix3::scaling(Vector2(9.0f)); + Matrix3 rotationScaling = rotation*Matrix3::scaling(Vector2(3.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)); - } + std::ostringstream o; + Error::setOutput(&o); + Matrix2 rotationScaling2 = (rotation*Matrix3::scaling(Vector2::yScale(3.5f))).rotation(); + CORRADE_COMPARE(o.str(), "Math::Matrix3::rotation(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(rotationScaling2, Matrix2()); } void Matrix3Test::uniformScalingPart() { diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index fb84fc54e..066a4715d 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -405,21 +405,18 @@ void Matrix4Test::rotationPart() { CORRADE_COMPARE(rotationTranslationPart, expectedRotationPart); /* Test uniform scaling */ - Matrix4 rotationScaling = rotation*Matrix4::scaling(Vector3(9.0f)); + Matrix4 rotationScaling = rotation*Matrix4::scaling(Vector3(3.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)); - } + std::ostringstream o; + Error::setOutput(&o); + Matrix3 rotationScaling2 = (rotation*Matrix4::scaling(Vector3::yScale(3.5f))).rotation(); + CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(rotationScaling2, Matrix3()); } void Matrix4Test::uniformScalingPart() { From 0f1142e5ed1b5216c05560e60e42e1c76e013499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 22:10:30 +0200 Subject: [PATCH 54/64] Math: added also Matrix[34]::uniformScalingSquared(). Usable to avoid square root and then squaring the value again in spheroid collision detection algorithms. --- src/Math/Matrix3.h | 24 +++++++++++++++++++----- src/Math/Matrix4.h | 22 ++++++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 6b7398102..d9d9b94b0 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -204,21 +204,35 @@ template class Matrix3: public Matrix<3, T> { } /** - * @brief Uniform scaling part of the matrix + * @brief Uniform scaling part of the matrix, squared * - * Length of vectors in upper-left 2x2 part of the matrix. Expects that - * the scaling is the same in all axes. + * Squared length of vectors in upper-left 2x2 part of the matrix. + * Expects that the scaling is the same in all axes. Faster alternative + * to @ref uniformScaling(), because it doesn't compute the square + * root. * @see @ref rotationScaling(), @ref rotation(), * @ref rotationNormalized(), @ref scaling(const Vector2&), * @ref Matrix4::uniformScaling() */ - T uniformScaling() const { + T uniformScalingSquared() const { const T scalingSquared = (*this)[0].xy().dot(); CORRADE_ASSERT(TypeTraits::equals((*this)[1].xy().dot(), scalingSquared), "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling", {}); - return std::sqrt(scalingSquared); + return scalingSquared; } + /** + * @brief Uniform scaling part of the matrix + * + * Length of vectors in upper-left 2x2 part of the matrix. Expects that + * the scaling is the same in all axes. Use faster alternative + * @ref uniformScalingSquared() where possible. + * @see @ref rotationScaling(), @ref rotation(), + * @ref rotationNormalized(), @ref scaling(const Vector2&), + * @ref Matrix4::uniformScaling() + */ + T uniformScaling() const { return std::sqrt(uniformScalingSquared()); } + /** * @brief Right-pointing 2D vector * diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 48f5c84db..be00c05f3 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -267,16 +267,30 @@ template class Matrix4: public Matrix<4, T> { /* Not Matrix3, because it is for affine 2D transformations */ Matrix<3, T> rotation() const; + /** + * @brief Uniform scaling part of the matrix, squared + * + * Squared length of vectors in upper-left 3x3 part of the matrix. + * Expects that the scaling is the same in all axes. Faster alternative + * to @ref uniformScaling(), because it doesn't compute the square + * root. + * @see @ref rotationScaling(), @ref rotation(), + * @ref rotationNormalized(), @ref scaling(const Vector3&), + * @ref Matrix3::uniformScaling() + */ + T uniformScalingSquared() const; + /** * @brief Uniform scaling part of the matrix * * Length of vectors in upper-left 3x3 part of the matrix. Expects that - * the scaling is the same in all axes. + * the scaling is the same in all axes. Use faster alternative + * @ref uniformScalingSquared() where possible. * @see @ref rotationScaling(), @ref rotation(), * @ref rotationNormalized(), @ref scaling(const Vector3&), * @ref Matrix3::uniformScaling() */ - T uniformScaling() const; + T uniformScaling() const { return std::sqrt(uniformScalingSquared()); } /** * @brief Right-pointing 3D vector @@ -460,12 +474,12 @@ template inline Matrix<3, T> Matrix4::rotation() const { (*this)[2].xyz().normalized()}; } -template T Matrix4::uniformScaling() const { +template T Matrix4::uniformScalingSquared() const { const T scalingSquared = (*this)[0].xyz().dot(); CORRADE_ASSERT(TypeTraits::equals((*this)[1].xyz().dot(), scalingSquared) && TypeTraits::equals((*this)[2].xyz().dot(), scalingSquared), "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling", {}); - return std::sqrt(scalingSquared); + return scalingSquared; } template Matrix4 Matrix4::invertedRigid() const { From 55afd472fe112df95e1e7ea951e15f9162b5e69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 22:25:03 +0200 Subject: [PATCH 55/64] Shapes: expect only uniform scaling for some primitives. Capsule, Sphere and Plane would behave weirdly if non-uniform scale would be applied to them. This restriction allows to use more performant code (i.e. less normalization and matrix multiplication). Updated the tests to verify that uniform scaling is handled well, for Capsule and Sphere there is now also no need to test both 2D and 3D transformation. --- src/Shapes/Capsule.cpp | 15 +------------ src/Shapes/Capsule.h | 6 ++--- src/Shapes/Plane.cpp | 5 ++++- src/Shapes/Plane.h | 4 ++-- src/Shapes/Sphere.cpp | 15 +------------ src/Shapes/Sphere.h | 6 ++--- src/Shapes/Test/CapsuleTest.cpp | 33 ++++++--------------------- src/Shapes/Test/PlaneTest.cpp | 10 +++------ src/Shapes/Test/SphereTest.cpp | 40 +++++---------------------------- 9 files changed, 28 insertions(+), 106 deletions(-) diff --git a/src/Shapes/Capsule.cpp b/src/Shapes/Capsule.cpp index 7fada2aee..d0df89afa 100644 --- a/src/Shapes/Capsule.cpp +++ b/src/Shapes/Capsule.cpp @@ -36,21 +36,8 @@ using namespace Magnum::Math::Geometry; namespace Magnum { namespace Shapes { -namespace { - template static typename DimensionTraits::VectorType unitVector(); - - template<> inline Vector2 unitVector<2>() { - return Vector2(1/Constants::sqrt2()); - } - - template<> inline Vector3 unitVector<3>() { - return Vector3(1/Constants::sqrt3()); - } -} - template Capsule Capsule::transformed(const typename DimensionTraits::MatrixType& matrix) const { - return Capsule(matrix.transformPoint(_a), matrix.transformPoint(_b), - (matrix.rotationScaling()*unitVector()).length()*_radius); + return Capsule(matrix.transformPoint(_a), matrix.transformPoint(_b), matrix.uniformScaling()*_radius); } template bool Capsule::operator%(const Point& other) const { diff --git a/src/Shapes/Capsule.h b/src/Shapes/Capsule.h index fb0de064c..f0a654cbc 100644 --- a/src/Shapes/Capsule.h +++ b/src/Shapes/Capsule.h @@ -38,11 +38,9 @@ namespace Magnum { namespace Shapes { /** @brief %Capsule defined by cylinder start and end point and radius -Unlike other elements the capsule doesn't support asymmetric scaling. When -applying transformation, the scale factor is averaged from all axes. See -@ref shapes for brief introduction. +Unlike other elements the capsule expects uniform scaling. See @ref shapes for +brief introduction. @see Capsule2D, Capsule3D -@todo Assert for asymmetric scaling to avoid costly sqrt? */ template class MAGNUM_SHAPES_EXPORT Capsule { public: diff --git a/src/Shapes/Plane.cpp b/src/Shapes/Plane.cpp index e62d5a15f..7c2ef4fc0 100644 --- a/src/Shapes/Plane.cpp +++ b/src/Shapes/Plane.cpp @@ -35,8 +35,11 @@ using namespace Magnum::Math::Geometry; namespace Magnum { namespace Shapes { Plane Plane::transformed(const Matrix4& matrix) const { + /* Using matrix.rotation() would result in two more normalizations (slow), + using .normalized() instead of matrix.uniformScaling() would not check + uniform scaling */ return Plane(matrix.transformPoint(_position), - matrix.rotation()*_normal); + matrix.rotationScaling()*_normal/matrix.uniformScaling()); } bool Plane::operator%(const Line3D& other) const { diff --git a/src/Shapes/Plane.h b/src/Shapes/Plane.h index 50058fc68..81f1608e5 100644 --- a/src/Shapes/Plane.h +++ b/src/Shapes/Plane.h @@ -38,8 +38,8 @@ namespace Magnum { namespace Shapes { /** @brief Infinite plane, defined by position and normal (3D only) -See @ref shapes for brief introduction. -@todo Assert for uniform scaling to avoid costly normalization? +Unlike other elements the plane expects uniform scaling. See @ref shapes for +brief introduction. */ class MAGNUM_SHAPES_EXPORT Plane { public: diff --git a/src/Shapes/Sphere.cpp b/src/Shapes/Sphere.cpp index f1af70317..295a9ab0a 100644 --- a/src/Shapes/Sphere.cpp +++ b/src/Shapes/Sphere.cpp @@ -36,21 +36,8 @@ using namespace Magnum::Math::Geometry; namespace Magnum { namespace Shapes { -namespace { - template static typename DimensionTraits::VectorType unitVector(); - - template<> inline Vector2 unitVector<2>() { - return Vector2(1/Constants::sqrt2()); - } - - template<> inline Vector3 unitVector<3>() { - return Vector3(1/Constants::sqrt3()); - } -} - template Sphere Sphere::transformed(const typename DimensionTraits::MatrixType& matrix) const { - return Sphere(matrix.transformPoint(_position), - (matrix.rotationScaling()*unitVector()).length()*_radius); + return Sphere(matrix.transformPoint(_position), matrix.uniformScaling()*_radius); } template bool Sphere::operator%(const Point& other) const { diff --git a/src/Shapes/Sphere.h b/src/Shapes/Sphere.h index dc4c5e2f0..44f7faa03 100644 --- a/src/Shapes/Sphere.h +++ b/src/Shapes/Sphere.h @@ -38,11 +38,9 @@ namespace Magnum { namespace Shapes { /** @brief %Sphere defined by position and radius -Unlike other elements the sphere doesn't support asymmetric scaling. When -applying transformation, the scale factor is averaged from all axes. See -@ref shapes for brief introduction. +Unlike other elements the sphere expects uniform scaling. See @ref shapes for +brief introduction. @see Sphere2D, Sphere3D -@todo Assert for asymmetric scaling to avoid costly sqrt? */ template class MAGNUM_SHAPES_EXPORT Sphere { public: diff --git a/src/Shapes/Test/CapsuleTest.cpp b/src/Shapes/Test/CapsuleTest.cpp index 03bd09848..ebbb78241 100644 --- a/src/Shapes/Test/CapsuleTest.cpp +++ b/src/Shapes/Test/CapsuleTest.cpp @@ -37,44 +37,25 @@ class CapsuleTest: public TestSuite::Tester { public: CapsuleTest(); - void transformed2D(); - void transformed3D(); + void transformed(); void transformedAverageScaling(); void collisionPoint(); void collisionSphere(); }; CapsuleTest::CapsuleTest() { - addTests({&CapsuleTest::transformed2D, - &CapsuleTest::transformed3D, + addTests({&CapsuleTest::transformed, &CapsuleTest::collisionPoint, &CapsuleTest::collisionSphere}); } -void CapsuleTest::transformed2D() { - const Shapes::Capsule2D capsule({1.0f, 2.0f}, {-1.0f, -2.0f}, 7.0f); - - const auto transformed = capsule.transformed(Matrix3::rotation(Deg(90.0f))); - CORRADE_COMPARE(transformed.a(), Vector2(-2.0f, 1.0f)); - CORRADE_COMPARE(transformed.b(), Vector2(2.0f, -1.0f)); - CORRADE_COMPARE(transformed.radius(), 7.0f); - - /* Apply average scaling to radius */ - const auto scaled = capsule.transformed(Matrix3::scaling({-Constants::sqrt2(), 2.0f})); - CORRADE_COMPARE(scaled.radius(), Constants::sqrt3()*7.0f); -} - -void CapsuleTest::transformed3D() { +void CapsuleTest::transformed() { const Shapes::Capsule3D capsule({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}, 7.0f); - const auto transformed = capsule.transformed(Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); - CORRADE_COMPARE(transformed.a(), Vector3(-2.0f, 1.0f, 3.0f)); - CORRADE_COMPARE(transformed.b(), Vector3(2.0f, -1.0f, -3.0f)); - CORRADE_COMPARE(transformed.radius(), 7.0f); - - /* Apply average scaling to radius */ - const auto scaled = capsule.transformed(Matrix4::scaling({Constants::sqrt3(), -Constants::sqrt2(), 2.0f})); - CORRADE_COMPARE(scaled.radius(), Constants::sqrt3()*7.0f); + const auto transformed = capsule.transformed(Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); + CORRADE_COMPARE(transformed.a(), Vector3(-4.0f, 2.0f, 6.0f)); + CORRADE_COMPARE(transformed.b(), Vector3(4.0f, -2.0f, -6.0f)); + CORRADE_COMPARE(transformed.radius(), 14.0f); } void CapsuleTest::collisionPoint() { diff --git a/src/Shapes/Test/PlaneTest.cpp b/src/Shapes/Test/PlaneTest.cpp index c86a6386b..5041aeb85 100644 --- a/src/Shapes/Test/PlaneTest.cpp +++ b/src/Shapes/Test/PlaneTest.cpp @@ -49,14 +49,10 @@ PlaneTest::PlaneTest() { void PlaneTest::transformed() { const Shapes::Plane plane({1.0f, 2.0f, 3.0f}, {Constants::sqrt2(), -Constants::sqrt2(), 0}); - const auto transformed = plane.transformed(Matrix4::rotation(Deg(90.0f), Vector3::xAxis())); - CORRADE_COMPARE(transformed.position(), Vector3(1.0f, -3.0f, 2.0f)); + /* The normal should stay normalized after scaling */ + const auto transformed = plane.transformed(Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(Deg(90.0f), Vector3::xAxis())); + CORRADE_COMPARE(transformed.position(), Vector3(2.0f, -6.0f, 4.0f)); CORRADE_COMPARE(transformed.normal(), Vector3(Constants::sqrt2(), 0, -Constants::sqrt2())); - - /* The normal should stay normalized */ - const auto scaled = plane.transformed(Matrix4::scaling({1.5f, 2.0f, 3.0f})); - CORRADE_COMPARE(scaled.position(), Vector3(1.5f, 4.0f, 9.0f)); - CORRADE_COMPARE(scaled.normal(), Vector3(Constants::sqrt2(), -Constants::sqrt2(), 0)); } void PlaneTest::collisionLine() { diff --git a/src/Shapes/Test/SphereTest.cpp b/src/Shapes/Test/SphereTest.cpp index 538a5b282..b66e86e50 100644 --- a/src/Shapes/Test/SphereTest.cpp +++ b/src/Shapes/Test/SphereTest.cpp @@ -37,8 +37,7 @@ class SphereTest: public TestSuite::Tester { public: SphereTest(); - void transformed2D(); - void transformed3D(); + void transformed(); void collisionPoint(); void collisionLine(); void collisionLineSegment(); @@ -46,46 +45,19 @@ class SphereTest: public TestSuite::Tester { }; SphereTest::SphereTest() { - addTests({&SphereTest::transformed2D, - &SphereTest::transformed3D, + addTests({&SphereTest::transformed, &SphereTest::collisionPoint, &SphereTest::collisionLine, &SphereTest::collisionLineSegment, &SphereTest::collisionSphere}); } -void SphereTest::transformed2D() { - const Shapes::Sphere2D sphere({1.0f, 2.0f}, 7.0f); - - const auto transformed = sphere.transformed(Matrix3::rotation(Deg(90.0f))); - CORRADE_COMPARE(transformed.position(), Vector2(-2.0f, 1.0f)); - CORRADE_COMPARE(transformed.radius(), 7.0f); - - /* Symmetric scaling */ - const auto scaled = sphere.transformed(Matrix3::scaling(Vector2(2.0f))); - CORRADE_COMPARE(scaled.position(), Vector2(2.0f, 4.0f)); - CORRADE_COMPARE(scaled.radius(), 14.0f); - - /* Apply average scaling to radius */ - const auto nonEven = sphere.transformed(Matrix3::scaling({-Constants::sqrt2(), 2.0f})); - CORRADE_COMPARE(nonEven.radius(), Constants::sqrt3()*7.0f); -} - -void SphereTest::transformed3D() { +void SphereTest::transformed() { const Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 7.0f); - const auto transformed = sphere.transformed(Matrix4::rotation(Deg(90.0f), Vector3::yAxis())); - CORRADE_COMPARE(transformed.position(), Vector3(3.0f, 2.0f, -1.0f)); - CORRADE_COMPARE(transformed.radius(), 7.0f); - - /* Symmetric scaling */ - const auto scaled = sphere.transformed(Matrix4::scaling(Vector3(2.0f))); - CORRADE_COMPARE(scaled.position(), Vector3(2.0f, 4.0f, 6.0f)); - CORRADE_COMPARE(scaled.radius(), 14.0f); - - /* Apply average scaling to radius */ - const auto nonEven = sphere.transformed(Matrix4::scaling({Constants::sqrt3(), -Constants::sqrt2(), 2.0f})); - CORRADE_COMPARE(nonEven.radius(), Constants::sqrt3()*7.0f); + const auto transformed = sphere.transformed(Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(Deg(90.0f), Vector3::yAxis())); + CORRADE_COMPARE(transformed.position(), Vector3(6.0f, 4.0f, -2.0f)); + CORRADE_COMPARE(transformed.radius(), 14.0f); } void SphereTest::collisionPoint() { From d09ee623769b8a179a5b2487f20cd146c1a73a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 20 Aug 2013 23:12:18 +0200 Subject: [PATCH 56/64] Shapes: added TODO. --- src/Shapes/Capsule.h | 2 ++ src/Shapes/Sphere.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Shapes/Capsule.h b/src/Shapes/Capsule.h index f0a654cbc..bceb0876c 100644 --- a/src/Shapes/Capsule.h +++ b/src/Shapes/Capsule.h @@ -41,6 +41,8 @@ namespace Magnum { namespace Shapes { Unlike other elements the capsule expects uniform scaling. See @ref shapes for brief introduction. @see Capsule2D, Capsule3D +@todo Store the radius as squared value to avoid sqrt/pow? Will complicate + collision detection with sphere. */ template class MAGNUM_SHAPES_EXPORT Capsule { public: diff --git a/src/Shapes/Sphere.h b/src/Shapes/Sphere.h index 44f7faa03..17d27bdd0 100644 --- a/src/Shapes/Sphere.h +++ b/src/Shapes/Sphere.h @@ -41,6 +41,8 @@ namespace Magnum { namespace Shapes { Unlike other elements the sphere expects uniform scaling. See @ref shapes for brief introduction. @see Sphere2D, Sphere3D +@todo Store the radius as squared value to avoid sqrt/pow? Will complicate + collision detection with another sphere. */ template class MAGNUM_SHAPES_EXPORT Sphere { public: From d8a5695a280285651e8cc6fab17815720c57ad52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Aug 2013 00:31:05 +0200 Subject: [PATCH 57/64] Shapes: added infinite cylinder shape. Seems like an essential part of the toolbox -- we have Point, LineSegment and Line and now we have also all "swept sphere" alternatives to them -- Sphere (swept "along" the point), Capsule (swept along line segment) and Cylinder (swept along infinite line). "Implemented" collision detection with point and sphere, which is just simplified version of collision detection implemented for Capsule (i.e. no need to check for cap cases). --- doc/shapes.dox | 1 + src/Shapes/CMakeLists.txt | 2 + src/Shapes/Capsule.h | 2 +- src/Shapes/Composition.h | 1 + src/Shapes/Cylinder.cpp | 58 +++++++++ src/Shapes/Cylinder.h | 117 ++++++++++++++++++ .../Implementation/CollisionDispatch.cpp | 7 ++ src/Shapes/Shapes.h | 4 + src/Shapes/Test/CMakeLists.txt | 1 + src/Shapes/Test/CylinderTest.cpp | 85 +++++++++++++ src/Shapes/shapeImplementation.cpp | 2 + src/Shapes/shapeImplementation.h | 25 ++-- 12 files changed, 295 insertions(+), 10 deletions(-) create mode 100644 src/Shapes/Cylinder.cpp create mode 100644 src/Shapes/Cylinder.h create mode 100644 src/Shapes/Test/CylinderTest.cpp diff --git a/doc/shapes.dox b/doc/shapes.dox index cb99d5454..1e5772d56 100644 --- a/doc/shapes.dox +++ b/doc/shapes.dox @@ -51,6 +51,7 @@ line and point. Collision of two lines can be detected only in 2D. @subsection shapes-3D Three-dimensional shapes - @ref Shapes::Sphere "Shapes::Sphere*D" -- @copybrief Shapes::Sphere +- @ref Shapes::Cylinder "Shapes::Cylinder*D" -- @copybrief Shapes::Cylinder - @ref Shapes::Capsule "Shapes::Capsule*D" -- @copybrief Shapes::Capsule - @ref Shapes::AxisAlignedBox "Shapes::AxisAlignedBox*D" -- @copybrief Shapes::AxisAlignedBox - @ref Shapes::Box "Shapes::Box*D" -- @copybrief Shapes::Box diff --git a/src/Shapes/CMakeLists.txt b/src/Shapes/CMakeLists.txt index 2f23c8abb..de98a9474 100644 --- a/src/Shapes/CMakeLists.txt +++ b/src/Shapes/CMakeLists.txt @@ -27,6 +27,7 @@ set(MagnumShapes_SRCS AxisAlignedBox.cpp Box.cpp Capsule.cpp + Cylinder.cpp Composition.cpp Line.cpp Plane.cpp @@ -44,6 +45,7 @@ set(MagnumShapes_HEADERS AxisAlignedBox.h Box.h Capsule.h + Cylinder.h Composition.h Line.h LineSegment.h diff --git a/src/Shapes/Capsule.h b/src/Shapes/Capsule.h index bceb0876c..c0f0d4bbc 100644 --- a/src/Shapes/Capsule.h +++ b/src/Shapes/Capsule.h @@ -40,7 +40,7 @@ namespace Magnum { namespace Shapes { Unlike other elements the capsule expects uniform scaling. See @ref shapes for brief introduction. -@see Capsule2D, Capsule3D +@see Capsule2D, Capsule3D, Cylinder @todo Store the radius as squared value to avoid sqrt/pow? Will complicate collision detection with sphere. */ diff --git a/src/Shapes/Composition.h b/src/Shapes/Composition.h index 5552352cc..1783ee593 100644 --- a/src/Shapes/Composition.h +++ b/src/Shapes/Composition.h @@ -79,6 +79,7 @@ template class MAGNUM_SHAPES_EXPORT Composition { Line, /**< Line */ LineSegment, /**< @ref LineSegment "Line segment" */ Sphere, /**< Sphere */ + Cylinder, /**< @ref Cylinder */ Capsule, /**< Capsule */ AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ Box, /**< Box */ diff --git a/src/Shapes/Cylinder.cpp b/src/Shapes/Cylinder.cpp new file mode 100644 index 000000000..b24cc43f0 --- /dev/null +++ b/src/Shapes/Cylinder.cpp @@ -0,0 +1,58 @@ +/* + 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 "Cylinder.h" + +#include "Math/Functions.h" +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Math/Geometry/Distance.h" +#include "Magnum.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" + +using namespace Magnum::Math::Geometry; + +namespace Magnum { namespace Shapes { + +template Cylinder Cylinder::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Cylinder(matrix.transformPoint(_a), matrix.transformPoint(_b), matrix.uniformScaling()*_radius); +} + +template bool Cylinder::operator%(const Point& other) const { + return Distance::linePointSquared(_a, _b, other.position()) < + Math::pow<2>(_radius); +} + +template bool Cylinder::operator%(const Sphere& other) const { + return Distance::linePointSquared(_a, _b, other.position()) < + Math::pow<2>(_radius+other.radius()); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SHAPES_EXPORT Cylinder<2>; +template class MAGNUM_SHAPES_EXPORT Cylinder<3>; +#endif + +}} diff --git a/src/Shapes/Cylinder.h b/src/Shapes/Cylinder.h new file mode 100644 index 000000000..e9a04d33b --- /dev/null +++ b/src/Shapes/Cylinder.h @@ -0,0 +1,117 @@ +#ifndef Magnum_Shapes_Cylinder_h +#define Magnum_Shapes_Cylinder_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Shapes::Cylinder, typedef Magnum::Shapes::Cylinder2D, Magnum::Shapes::Cylinder3D + */ + +#include "Math/Vector3.h" +#include "DimensionTraits.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" + +namespace Magnum { namespace Shapes { + +/** +@brief Infinite cylinder defined by line and radius + +Unlike other elements the cylinder expects uniform scaling. See @ref shapes for +brief introduction. +@see @ref Cylinder2D, @ref Cylinder3D, @ref Capsule +@todo Store the radius as squared value to avoid sqrt/pow? Will complicate + collision detection with sphere. +*/ +template class MAGNUM_SHAPES_EXPORT Cylinder { + public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + + /** + * @brief Constructor + * + * Creates zero-sized cylinder at origin. + */ + constexpr /*implicit*/ Cylinder(): _radius(0.0f) {} + + /** @brief Constructor */ + constexpr /*implicit*/ Cylinder(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius): _a(a), _b(b), _radius(radius) {} + + /** @brief Transformed shape */ + Cylinder transformed(const typename DimensionTraits::MatrixType& matrix) const; + + /** @brief First point */ + constexpr typename DimensionTraits::VectorType a() const { + return _a; + } + + /** @brief Set first point */ + void setA(const typename DimensionTraits::VectorType& a) { + _a = a; + } + + /** @brief Second point */ + constexpr typename DimensionTraits::VectorType b() const { + return _b; + } + + /** @brief Set second point */ + void setB(const typename DimensionTraits::VectorType& b) { + _b = b; + } + + /** @brief Radius */ + constexpr Float radius() const { return _radius; } + + /** @brief Set radius */ + void setRadius(Float radius) { _radius = radius; } + + /** @brief Collision with point */ + bool operator%(const Point& other) const; + + /** @brief Collision with sphere */ + bool operator%(const Sphere& other) const; + + private: + typename DimensionTraits::VectorType _a, _b; + Float _radius; +}; + +/** @brief Infinite two-dimensional cylinder */ +typedef Cylinder<2> Cylinder2D; + +/** @brief Infinite three-dimensional cylinder */ +typedef Cylinder<3> Cylinder3D; + +/** @collisionoperator{Point,Cylinder} */ +template inline bool operator%(const Point& a, const Cylinder& b) { return b % a; } + +/** @collisionoperator{Sphere,Cylinder} */ +template inline bool operator%(const Sphere& a, const Cylinder& b) { return b % a; } + +}} + +#endif diff --git a/src/Shapes/Implementation/CollisionDispatch.cpp b/src/Shapes/Implementation/CollisionDispatch.cpp index d4c0e8602..d5943d612 100644 --- a/src/Shapes/Implementation/CollisionDispatch.cpp +++ b/src/Shapes/Implementation/CollisionDispatch.cpp @@ -27,6 +27,7 @@ #include "Shapes/AxisAlignedBox.h" #include "Shapes/Box.h" #include "Shapes/Capsule.h" +#include "Shapes/Cylinder.h" #include "Shapes/LineSegment.h" #include "Shapes/Plane.h" #include "Shapes/Point.h" @@ -47,6 +48,9 @@ template<> bool collides(const AbstractShape<2>& a, const AbstractShape<2>& b) { _c(Sphere, Sphere2D, LineSegment, LineSegment2D) _c(Sphere, Sphere2D, Sphere, Sphere2D) + _c(Cylinder, Cylinder2D, Point, Point2D) + _c(Cylinder, Cylinder2D, Sphere, Sphere2D) + _c(Capsule, Capsule2D, Point, Point2D) _c(Capsule, Capsule2D, Sphere, Sphere2D) @@ -69,6 +73,9 @@ template<> bool collides(const AbstractShape<3>& a, const AbstractShape<3>& b) { _c(Sphere, Sphere3D, LineSegment, LineSegment3D) _c(Sphere, Sphere3D, Sphere, Sphere3D) + _c(Cylinder, Cylinder3D, Point, Point3D) + _c(Cylinder, Cylinder3D, Sphere, Sphere3D) + _c(Capsule, Capsule3D, Point, Point3D) _c(Capsule, Capsule3D, Sphere, Sphere3D) diff --git a/src/Shapes/Shapes.h b/src/Shapes/Shapes.h index dfc0d0fd7..057cb7e90 100644 --- a/src/Shapes/Shapes.h +++ b/src/Shapes/Shapes.h @@ -54,6 +54,10 @@ template class Composition; typedef Composition<2> Composition2D; typedef Composition<3> Composition3D; +template class Cylinder; +typedef Cylinder<2> Cylinder2D; +typedef Cylinder<3> Cylinder3D; + template class Line; typedef Line<2> Line2D; typedef Line<3> Line3D; diff --git a/src/Shapes/Test/CMakeLists.txt b/src/Shapes/Test/CMakeLists.txt index 2615b6d99..b08d2ec0a 100644 --- a/src/Shapes/Test/CMakeLists.txt +++ b/src/Shapes/Test/CMakeLists.txt @@ -26,6 +26,7 @@ corrade_add_test(ShapesShapeImplementationTest ShapeImplementationTest.cpp LIBRA corrade_add_test(ShapesAxisAlignedBoxTest AxisAlignedBoxTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesBoxTest BoxTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesCylinderTest CylinderTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesLineTest LineTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesPlaneTest PlaneTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesPointTest PointTest.cpp LIBRARIES MagnumShapes) diff --git a/src/Shapes/Test/CylinderTest.cpp b/src/Shapes/Test/CylinderTest.cpp new file mode 100644 index 000000000..013f16da9 --- /dev/null +++ b/src/Shapes/Test/CylinderTest.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 "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "Shapes/Cylinder.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" + +#include "ShapeTestBase.h" + +namespace Magnum { namespace Shapes { namespace Test { + +class CylinderTest: public TestSuite::Tester { + public: + CylinderTest(); + + void transformed(); + void transformedAverageScaling(); + void collisionPoint(); + void collisionSphere(); +}; + +CylinderTest::CylinderTest() { + addTests({&CylinderTest::transformed, + &CylinderTest::collisionPoint, + &CylinderTest::collisionSphere}); +} + +void CylinderTest::transformed() { + const Shapes::Cylinder3D cylinder({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}, 7.0f); + + const auto transformed = cylinder.transformed(Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); + CORRADE_COMPARE(transformed.a(), Vector3(-4.0f, 2.0f, 6.0f)); + CORRADE_COMPARE(transformed.b(), Vector3(4.0f, -2.0f, -6.0f)); + CORRADE_COMPARE(transformed.radius(), 14.0f); +} + +void CylinderTest::collisionPoint() { + Shapes::Cylinder3D cylinder({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); + Shapes::Point3D point({2.0f, 0.0f, 0.0f}); + Shapes::Point3D point1({1.0f, 3.1f, 0.0f}); + Shapes::Point3D point2({2.9f, -1.0f, 0.0f}); + + VERIFY_COLLIDES(cylinder, point); + VERIFY_COLLIDES(cylinder, point1); + VERIFY_NOT_COLLIDES(cylinder, point2); +} + +void CylinderTest::collisionSphere() { + Shapes::Cylinder3D cylinder({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); + Shapes::Sphere3D sphere({3.0f, 0.0f, 0.0f}, 0.9f); + Shapes::Sphere3D sphere1({1.0f, 4.1f, 0.0f}, 1.0f); + Shapes::Sphere3D sphere2({3.5f, -1.0f, 0.0f}, 0.6f); + + VERIFY_COLLIDES(cylinder, sphere); + VERIFY_COLLIDES(cylinder, sphere1); + VERIFY_NOT_COLLIDES(cylinder, sphere2); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Shapes::Test::CylinderTest) diff --git a/src/Shapes/shapeImplementation.cpp b/src/Shapes/shapeImplementation.cpp index 1b3b57973..9a9ab4a4f 100644 --- a/src/Shapes/shapeImplementation.cpp +++ b/src/Shapes/shapeImplementation.cpp @@ -36,6 +36,7 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<2>::Type value) { _val(LineSegment) _val(Sphere) _val(Capsule) + _val(Cylinder) _val(AxisAlignedBox) _val(Box) _val(Composition) @@ -53,6 +54,7 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<3>::Type value) { _val(LineSegment) _val(Sphere) _val(Capsule) + _val(Cylinder) _val(AxisAlignedBox) _val(Box) _val(Plane) diff --git a/src/Shapes/shapeImplementation.h b/src/Shapes/shapeImplementation.h index ecf028570..8b2a16597 100644 --- a/src/Shapes/shapeImplementation.h +++ b/src/Shapes/shapeImplementation.h @@ -44,10 +44,11 @@ template<> struct ShapeDimensionTraits<2> { Line = 2, LineSegment = 3, Sphere = 5, - Capsule = 7, - AxisAlignedBox = 11, - Box = 13, - Composition = 17 + Cylinder = 7, + Capsule = 11, + AxisAlignedBox = 13, + Box = 17, + Composition = 19 }; }; @@ -57,11 +58,12 @@ template<> struct ShapeDimensionTraits<3> { Line = 2, LineSegment = 3, Sphere = 5, - Capsule = 7, - AxisAlignedBox = 11, - Box = 13, - Plane = 17, - Composition = 19 + Cylinder = 7, + Capsule = 11, + AxisAlignedBox = 13, + Box = 17, + Plane = 19, + Composition = 23 }; }; @@ -92,6 +94,11 @@ template struct TypeOf> { return ShapeDimensionTraits::Type::Sphere; } }; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Cylinder; + } +}; template struct TypeOf> { constexpr static typename ShapeDimensionTraits::Type type() { return ShapeDimensionTraits::Type::Capsule; From 8929f4c1ae8ce30d39389851f6448d1a6b1b56d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Aug 2013 00:36:13 +0200 Subject: [PATCH 58/64] Shapes: documentation for adding new shapes. It's a lot of steps to rediscover. --- src/Shapes/shapeImplementation.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Shapes/shapeImplementation.h b/src/Shapes/shapeImplementation.h index 8b2a16597..898f50bd3 100644 --- a/src/Shapes/shapeImplementation.h +++ b/src/Shapes/shapeImplementation.h @@ -34,6 +34,23 @@ namespace Magnum { namespace Shapes { namespace Implementation { +/* + Adding new collision type: + + 1. Add the type into the 2D/3D enums below, pick new prime number and + preserve complexity ordering + 2. Update debug output operators for changed enums + 3. Add TypeOf struct specialization (either for both 2D/3D or for only one + of them) + 4. Add the enum value to (documentation-only) enum in Composition + 5. Update doc/shapes.dox with new type + + Adding new collision detection implementation: + + 1. Update Implementation/CollisionDispatch.cpp with newly implemented + 2D/3D pair +*/ + /* Shape type for given dimension count */ template struct ShapeDimensionTraits; From 9c34c00bb6f921e338e296d861fc74827d0b0d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Aug 2013 00:47:27 +0200 Subject: [PATCH 59/64] Primitives: use half length also in Cylinder primitive. Everything is now consistent. --- src/Primitives/Cylinder.cpp | 24 +++++++++++++----------- src/Primitives/Cylinder.h | 8 ++++---- src/Primitives/Test/CylinderTest.cpp | 6 +++--- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/Primitives/Cylinder.cpp b/src/Primitives/Cylinder.cpp index b1af5e6a8..da6b28b81 100644 --- a/src/Primitives/Cylinder.cpp +++ b/src/Primitives/Cylinder.cpp @@ -31,27 +31,27 @@ namespace Magnum { namespace Primitives { -Trade::MeshData3D Cylinder::solid(UnsignedInt rings, UnsignedInt segments, Float length, Cylinder::Flags flags) { +Trade::MeshData3D Cylinder::solid(const UnsignedInt rings, const UnsignedInt segments, const Float halfLength, const Flags flags) { CORRADE_ASSERT(rings >= 1 && segments >= 3, "Primitives::Cylinder::solid(): cylinder must have at least one ring and three segments", Trade::MeshData3D(Mesh::Primitive::Triangles, {}, {}, {}, {})); Implementation::Spheroid cylinder(segments, flags & Flag::GenerateTextureCoords ? Implementation::Spheroid::TextureCoords::Generate : Implementation::Spheroid::TextureCoords::DontGenerate); - Float y = length*0.5f; - Float textureCoordsV = flags & Flag::CapEnds ? 1.0f/(length+2.0f) : 0.0f; + const Float length = 2.0f*halfLength; + const Float textureCoordsV = flags & Flag::CapEnds ? 1.0f/(length+2.0f) : 0.0f; /* Bottom cap */ if(flags & Flag::CapEnds) { - cylinder.capVertex(-y, -1.0f, 0.0f); - cylinder.capVertexRing(-y, textureCoordsV, Vector3::yAxis(-1.0f)); + cylinder.capVertex(-halfLength, -1.0f, 0.0f); + cylinder.capVertexRing(-halfLength, textureCoordsV, Vector3::yAxis(-1.0f)); } /* Vertex rings */ - cylinder.cylinderVertexRings(rings+1, -y, length/rings, textureCoordsV, length/(rings*(flags & Flag::CapEnds ? length + 2.0f : length))); + cylinder.cylinderVertexRings(rings+1, -halfLength, length/rings, textureCoordsV, length/(rings*(flags & Flag::CapEnds ? length + 2.0f : length))); /* Top cap */ if(flags & Flag::CapEnds) { - cylinder.capVertexRing(y, 1.0f - textureCoordsV, Vector3::yAxis(1.0f)); - cylinder.capVertex(y, 1.0f, 1.0f); + cylinder.capVertexRing(halfLength, 1.0f - textureCoordsV, Vector3::yAxis(1.0f)); + cylinder.capVertex(halfLength, 1.0f, 1.0f); } /* Faces */ @@ -62,16 +62,18 @@ Trade::MeshData3D Cylinder::solid(UnsignedInt rings, UnsignedInt segments, Float return cylinder.finalize(); } -Trade::MeshData3D Cylinder::wireframe(const UnsignedInt rings, const UnsignedInt segments, const Float length) { +Trade::MeshData3D Cylinder::wireframe(const UnsignedInt rings, const UnsignedInt segments, const Float halfLength) { CORRADE_ASSERT(rings >= 1 && segments >= 4 && segments%4 == 0, "Primitives::Cylinder::wireframe(): improper parameters", Trade::MeshData3D(Mesh::Primitive::Lines, {}, {}, {}, {})); Implementation::WireframeSpheroid cylinder(segments/4); + const Float increment = 2*halfLength/rings; + /* Rings */ - cylinder.ring(-length/2); + cylinder.ring(-halfLength); for(UnsignedInt i = 0; i != rings; ++i) { cylinder.cylinder(); - cylinder.ring(-length/2 + (i+1)*(length/rings)); + cylinder.ring(-halfLength + (i+1)*increment); } return cylinder.finalize(); diff --git a/src/Primitives/Cylinder.h b/src/Primitives/Cylinder.h index 8b8d92bfb..e00946d63 100644 --- a/src/Primitives/Cylinder.h +++ b/src/Primitives/Cylinder.h @@ -62,7 +62,7 @@ class MAGNUM_PRIMITIVES_EXPORT Cylinder { * equal to 1. * @param segments Number of (face) segments. Must be larger or * equal to 3. - * @param length Cylinder length + * @param halfLength Half the cylinder length * @param flags Flags * * Indexed @ref Mesh::Primitive "Triangles" with normals, optional 2D @@ -70,7 +70,7 @@ class MAGNUM_PRIMITIVES_EXPORT Cylinder { * are generated, vertices of one segment are duplicated for texture * wrapping. */ - static Trade::MeshData3D solid(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags = Flags()); + static Trade::MeshData3D solid(UnsignedInt rings, UnsignedInt segments, Float halfLength, Flags flags = Flags()); /** * @brief Wireframe cylinder @@ -78,11 +78,11 @@ class MAGNUM_PRIMITIVES_EXPORT Cylinder { * to 1. * @param segments Number of (line) segments. Must be larger or * equal to 4 and multiple of 4. - * @param length Cylinder length + * @param halfLength Half the cylinder length * * Indexed @ref Mesh::Primitive "Lines". */ - static Trade::MeshData3D wireframe(UnsignedInt rings, UnsignedInt segments, Float length); + static Trade::MeshData3D wireframe(UnsignedInt rings, UnsignedInt segments, Float halfLength); }; CORRADE_ENUMSET_OPERATORS(Cylinder::Flags) diff --git a/src/Primitives/Test/CylinderTest.cpp b/src/Primitives/Test/CylinderTest.cpp index 7aa532bf6..10bc34add 100644 --- a/src/Primitives/Test/CylinderTest.cpp +++ b/src/Primitives/Test/CylinderTest.cpp @@ -47,7 +47,7 @@ CylinderTest::CylinderTest() { } void CylinderTest::solidWithoutAnything() { - Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 3.0f); + Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 1.5f); CORRADE_COMPARE_AS(cylinder.positions(0), (std::vector{ {0.0f, -1.5f, 1.0f}, @@ -84,7 +84,7 @@ void CylinderTest::solidWithoutAnything() { } void CylinderTest::solidWithTextureCoordsAndCaps() { - Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 3.0f, Cylinder::Flag::GenerateTextureCoords|Cylinder::Flag::CapEnds); + Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 1.5f, Cylinder::Flag::GenerateTextureCoords|Cylinder::Flag::CapEnds); CORRADE_COMPARE_AS(cylinder.positions(0), (std::vector{ {0.0f, -1.5f, 0.0f}, @@ -188,7 +188,7 @@ void CylinderTest::solidWithTextureCoordsAndCaps() { } void CylinderTest::wireframe() { - Trade::MeshData3D cylinder = Cylinder::wireframe(2, 8, 1.0f); + Trade::MeshData3D cylinder = Cylinder::wireframe(2, 8, 0.5f); CORRADE_COMPARE_AS(cylinder.positions(0), (std::vector{ {0.0f, -0.5f, 1.0f}, From 9c935e80c2faed4690c02d17c4c01705cdd64b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Aug 2013 01:03:55 +0200 Subject: [PATCH 60/64] DebugTools: support for Cylinder shape in ShapeRenderer. The code is mostly copied and simplified from Capsule renderer. However, it is such simplification that any attempt to reduce duplicate code would result in much less maintainable thing. --- src/DebugTools/CMakeLists.txt | 1 + .../Implementation/CylinderRenderer.cpp | 61 +++++++++ .../Implementation/CylinderRenderer.h | 60 +++++++++ .../CylinderRendererTransformation.h | 88 ++++++++++++ src/DebugTools/ShapeRenderer.cpp | 7 + src/DebugTools/Test/CMakeLists.txt | 1 + src/DebugTools/Test/CylinderRendererTest.cpp | 125 ++++++++++++++++++ 7 files changed, 343 insertions(+) create mode 100644 src/DebugTools/Implementation/CylinderRenderer.cpp create mode 100644 src/DebugTools/Implementation/CylinderRenderer.h create mode 100644 src/DebugTools/Implementation/CylinderRendererTransformation.h create mode 100644 src/DebugTools/Test/CylinderRendererTest.cpp diff --git a/src/DebugTools/CMakeLists.txt b/src/DebugTools/CMakeLists.txt index 00d88ecc8..d348e3b8b 100644 --- a/src/DebugTools/CMakeLists.txt +++ b/src/DebugTools/CMakeLists.txt @@ -34,6 +34,7 @@ set(MagnumDebugTools_SRCS Implementation/AxisAlignedBoxRenderer.cpp Implementation/BoxRenderer.cpp Implementation/CapsuleRenderer.cpp + Implementation/CylinderRenderer.cpp Implementation/LineSegmentRenderer.cpp Implementation/PointRenderer.cpp Implementation/SphereRenderer.cpp) diff --git a/src/DebugTools/Implementation/CylinderRenderer.cpp b/src/DebugTools/Implementation/CylinderRenderer.cpp new file mode 100644 index 000000000..f7cfbd1e2 --- /dev/null +++ b/src/DebugTools/Implementation/CylinderRenderer.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 "CylinderRenderer.h" + +#include "Mesh.h" +#include "DebugTools/ShapeRenderer.h" +#include "Shapes/Cylinder.h" +#include "Primitives/Cylinder.h" +#include "Primitives/Square.h" +#include "Shaders/Flat.h" +#include "Trade/MeshData2D.h" +#include "Trade/MeshData3D.h" + +#include "DebugTools/Implementation/CylinderRendererTransformation.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +AbstractCylinderRenderer<2>::AbstractCylinderRenderer(): AbstractShapeRenderer<2>("cylinder2d", "cylinder2d-vertices", {}) { + if(!wireframeMesh) createResources(Primitives::Square::wireframe()); +} + +AbstractCylinderRenderer<3>::AbstractCylinderRenderer(): AbstractShapeRenderer<3>("cylinder3d", "cylinder3d-vertices", "cylinder3d-indices") { + if(!wireframeMesh) createResources(Primitives::Cylinder::wireframe(1, 40, 1.0f)); +} + +template CylinderRenderer::CylinderRenderer(const Shapes::Implementation::AbstractShape& cylinder): cylinder(static_cast>&>(cylinder).shape) {} + +template void CylinderRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { + AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix* + Implementation::cylinderRendererTransformation(cylinder.a(), cylinder.b(), cylinder.radius())) + .setColor(options->color()) + .use(); + AbstractShapeRenderer::wireframeMesh->draw(); +} + +template class CylinderRenderer<2>; +template class CylinderRenderer<3>; + +}}} diff --git a/src/DebugTools/Implementation/CylinderRenderer.h b/src/DebugTools/Implementation/CylinderRenderer.h new file mode 100644 index 000000000..d5a511254 --- /dev/null +++ b/src/DebugTools/Implementation/CylinderRenderer.h @@ -0,0 +1,60 @@ +#ifndef Magnum_DebugTools_Implementation_CylinderRenderer_h +#define Magnum_DebugTools_Implementation_CylinderRenderer_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 "Shapes/Shapes.h" + +#include "corradeCompatibility.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template class AbstractCylinderRenderer; + +template<> class AbstractCylinderRenderer<2>: public AbstractShapeRenderer<2> { + public: + explicit AbstractCylinderRenderer(); +}; + +template<> class AbstractCylinderRenderer<3>: public AbstractShapeRenderer<3> { + public: + explicit AbstractCylinderRenderer(); +}; + +template class CylinderRenderer: public AbstractCylinderRenderer { + public: + explicit CylinderRenderer(const Shapes::Implementation::AbstractShape& cylinder); + CylinderRenderer(const Shapes::Implementation::AbstractShape&&) = delete; + + void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override; + + private: + const Shapes::Cylinder& cylinder; +}; + +}}} + +#endif diff --git a/src/DebugTools/Implementation/CylinderRendererTransformation.h b/src/DebugTools/Implementation/CylinderRendererTransformation.h new file mode 100644 index 000000000..4caf8c5d6 --- /dev/null +++ b/src/DebugTools/Implementation/CylinderRendererTransformation.h @@ -0,0 +1,88 @@ +#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/Functions.h" +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "DimensionTraits.h" + +namespace Magnum { namespace DebugTools { namespace Implementation { + +template typename DimensionTraits::MatrixType cylinderRendererTransformation(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius); + +template<> Matrix3 cylinderRendererTransformation<2>(const Vector2& a, const Vector2& b, const Float radius) { + /* Vector from cylinder center to top hemisphere center */ + const Vector2 direction = 0.5f*(b - a); + const Float length = direction.length(); + + /* Capsule rotation and distance to caps after they are scaled to proper + radius (if nonzero cylinder length) */ + Matrix3 rotation; + if(length >= Math::TypeTraits::epsilon()) { + rotation.up() = direction/length; + rotation.right() = rotation.up().perpendicular(); + CORRADE_INTERNAL_ASSERT(rotation.right().isNormalized()); + } + + /* Scaling and translation */ + return Matrix3::translation(0.5f*(a + b))*rotation*Matrix3::scaling({radius, length}); +} + +template<> Matrix4 cylinderRendererTransformation<3>(const Vector3& a, const Vector3& b, const Float radius) { + /* Vector from cylinder center to top hemisphere center */ + const Vector3 direction = 0.5f*(b - a); + const Float length = direction.length(); + + /* Capsule rotation and distance to caps after they are scaled to proper + radius (if nonzero cylinder length) */ + Matrix4 rotation; + if(length >= Math::TypeTraits::epsilon()) { + const Vector3 directionNormalized = direction/length; + const Float dot = Vector3::dot(directionNormalized, Vector3::zAxis()); + + /* Direction is parallel to Z axis, special rotation case */ + if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) { + rotation.up() = dot*Vector3::zAxis(); + rotation.right() = Vector3::xAxis(); + rotation.backward() = -dot*Vector3::yAxis(); + + /* Common case */ + } else { + rotation.up() = directionNormalized; + rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized(); + rotation.backward() = Vector3::cross(rotation.right(), rotation.up()); + CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized()); + } + } + + /* Scaling and translation */ + return Matrix4::translation(0.5f*(a + b))*rotation*Matrix4::scaling({radius, length, radius}); +} + +}}} + +#endif diff --git a/src/DebugTools/ShapeRenderer.cpp b/src/DebugTools/ShapeRenderer.cpp index 62cbc8f37..28118071c 100644 --- a/src/DebugTools/ShapeRenderer.cpp +++ b/src/DebugTools/ShapeRenderer.cpp @@ -32,6 +32,7 @@ #include "Implementation/AxisAlignedBoxRenderer.h" #include "Implementation/BoxRenderer.h" #include "Implementation/CapsuleRenderer.h" +#include "Implementation/CylinderRenderer.h" #include "Implementation/LineSegmentRenderer.h" #include "Implementation/PointRenderer.h" #include "Implementation/SphereRenderer.h" @@ -60,6 +61,9 @@ template<> void createDebugMesh(ShapeRenderer<2>& renderer, const Shapes::Implem case Shapes::AbstractShape2D::Type::Capsule: renderer.renderers.push_back(new Implementation::CapsuleRenderer<2>(shape)); break; + case Shapes::AbstractShape2D::Type::Cylinder: + renderer.renderers.push_back(new Implementation::CylinderRenderer<2>(shape)); + break; case Shapes::AbstractShape2D::Type::Composition: { const Shapes::Composition2D& composition = static_cast&>(shape).shape; @@ -91,6 +95,9 @@ template<> void createDebugMesh(ShapeRenderer<3>& renderer, const Shapes::Implem case Shapes::AbstractShape3D::Type::Capsule: renderer.renderers.push_back(new Implementation::CapsuleRenderer<3>(shape)); break; + case Shapes::AbstractShape3D::Type::Cylinder: + renderer.renderers.push_back(new Implementation::CylinderRenderer<3>(shape)); + break; case Shapes::AbstractShape3D::Type::Composition: { const Shapes::Composition3D& composition = static_cast&>(shape).shape; diff --git a/src/DebugTools/Test/CMakeLists.txt b/src/DebugTools/Test/CMakeLists.txt index ba5e678e2..35fca1640 100644 --- a/src/DebugTools/Test/CMakeLists.txt +++ b/src/DebugTools/Test/CMakeLists.txt @@ -23,5 +23,6 @@ # corrade_add_test(DebugToolsCapsuleRendererTest CapsuleRendererTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(DebugToolsCylinderRendererTest CylinderRendererTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(DebugToolsForceRendererTest ForceRendererTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(DebugToolsLineSegmentRendererTest LineSegmentRendererTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/DebugTools/Test/CylinderRendererTest.cpp b/src/DebugTools/Test/CylinderRendererTest.cpp new file mode 100644 index 000000000..958003f96 --- /dev/null +++ b/src/DebugTools/Test/CylinderRendererTest.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 "DebugTools/Implementation/CylinderRendererTransformation.h" + +namespace Magnum { namespace DebugTools { namespace Test { + +class CylinderRendererTest: public TestSuite::Tester { + public: + explicit CylinderRendererTest(); + + void zeroLength2D(); + void common2D(); + + void zeroLength3D(); + void parallel3D(); + void antiParallel3D(); + void common3D(); +}; + +CylinderRendererTest::CylinderRendererTest() { + addTests({&CylinderRendererTest::zeroLength2D, + &CylinderRendererTest::common2D, + + &CylinderRendererTest::zeroLength3D, + &CylinderRendererTest::parallel3D, + &CylinderRendererTest::antiParallel3D, + &CylinderRendererTest::common3D}); +} + +void CylinderRendererTest::zeroLength2D() { + const Vector2 a(0.5f, 3.0f); + const Matrix3 transformation = Implementation::cylinderRendererTransformation<2>(a, a, 3.5f); + + CORRADE_COMPARE(transformation.rotationScaling(), (Math::Matrix<2, Float>::fromDiagonal({3.5f, 0.0f}))); + CORRADE_COMPARE(transformation.translation(), a); +} + +void CylinderRendererTest::common2D() { + const Vector2 a(0.5f, 3.0f); + const Vector2 b(7.5f, -1.0f); + const Matrix3 transformation = Implementation::cylinderRendererTransformation<2>(a, b, 3.5f); + + /* Rotation + scaling, test orthogonality */ + CORRADE_COMPARE(transformation.up(), Vector2(3.5f, -2.0f)); + CORRADE_COMPARE(transformation.right(), Vector2(4.0f, 7.0f).resized(3.5f)); + CORRADE_COMPARE(Vector2::dot(transformation.up(), transformation.right()), 0.0f); + + CORRADE_COMPARE(transformation.translation(), 0.5f*(a + b)); +} + +void CylinderRendererTest::zeroLength3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, a, 3.5f); + + CORRADE_COMPARE(transformation.rotationScaling(), (Math::Matrix<3, Float>::fromDiagonal({3.5f, 0.0f, 3.5f}))); + CORRADE_COMPARE(transformation.translation(), a); +} + +void CylinderRendererTest::parallel3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Vector3 b(0.5f, 3.0f, 11.0f); + const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, b, 3.5f); + + CORRADE_COMPARE(transformation.rotationScaling(), + (Matrix4::rotationX(Deg(90.0f))*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling()); + + CORRADE_COMPARE(transformation.translation(), a+Vector3::zAxis(2.0f)); +} + +void CylinderRendererTest::antiParallel3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Vector3 b(0.5f, 3.0f, 3.0f); + const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, b, 3.5f); + + CORRADE_COMPARE(transformation.rotationScaling(), + (Matrix4::rotationX(-Deg(90.0f))*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling()); + + CORRADE_COMPARE(transformation.translation(), a+Vector3::zAxis(-2.0f)); +} + +void CylinderRendererTest::common3D() { + const Vector3 a(0.5f, 3.0f, 7.0f); + const Vector3 b(7.5f, -1.0f, 1.5f); + const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, b, 3.5f); + + /* Rotation + scaling */ + CORRADE_COMPARE(transformation.up(), Vector3(3.5f, -2.0f, -2.75f)); + CORRADE_COMPARE(transformation.right(), Vector3(-2.0f, -3.5f, 0.0f).resized(3.5f)); + CORRADE_COMPARE(transformation.backward(), Vector3(9.625f, -5.5f, 16.25f).resized(3.5f)); + + /* Orthogonality */ + CORRADE_COMPARE(Vector3::dot(transformation.up(), transformation.right()), 0.0f); + CORRADE_COMPARE(Vector3::dot(transformation.up(), transformation.backward()), 0.0f); + CORRADE_COMPARE(Vector3::dot(transformation.right(), transformation.backward()), 0.0f); + + CORRADE_COMPARE(transformation.translation(), 0.5f*(a + b)); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::DebugTools::Test::CylinderRendererTest) From d0ac31141634bd5cc631ec700151aeea665e8f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Aug 2013 22:51:58 +0200 Subject: [PATCH 61/64] DebugTools: use common segment/ring count for all spheroids. Every circle should consist of 40 lines, i.e. sphere should have 40 segments and 20 rings, capsule should have 40 segments and 10 rings per hemisphere (=20 rings total). --- src/DebugTools/Implementation/CapsuleRenderer.cpp | 2 +- src/DebugTools/Implementation/SphereRenderer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DebugTools/Implementation/CapsuleRenderer.cpp b/src/DebugTools/Implementation/CapsuleRenderer.cpp index d6e48d5b5..1cd1922bd 100644 --- a/src/DebugTools/Implementation/CapsuleRenderer.cpp +++ b/src/DebugTools/Implementation/CapsuleRenderer.cpp @@ -65,7 +65,7 @@ AbstractCapsuleRenderer<2>::AbstractCapsuleRenderer(): AbstractShapeRenderer<2>( AbstractCapsuleRenderer<3>::AbstractCapsuleRenderer(): AbstractShapeRenderer<3>("capsule3d", "capsule3d-vertices", "capsule3d-indices") { constexpr UnsignedInt rings = 10; - constexpr UnsignedInt segments = 20; + constexpr UnsignedInt segments = 40; if(!wireframeMesh) createResources(Primitives::Capsule3D::wireframe(rings, 1, segments, 1.0f)); /* Bottom hemisphere */ diff --git a/src/DebugTools/Implementation/SphereRenderer.cpp b/src/DebugTools/Implementation/SphereRenderer.cpp index 9a6815738..59362b226 100644 --- a/src/DebugTools/Implementation/SphereRenderer.cpp +++ b/src/DebugTools/Implementation/SphereRenderer.cpp @@ -40,7 +40,7 @@ AbstractSphereRenderer<2>::AbstractSphereRenderer(): AbstractShapeRenderer<2>("s } AbstractSphereRenderer<3>::AbstractSphereRenderer(): AbstractShapeRenderer<3>("sphere3d", "sphere3d-vertices", "sphere3d-indices") { - if(!wireframeMesh) createResources(Primitives::UVSphere::wireframe(40, 20)); + if(!wireframeMesh) createResources(Primitives::UVSphere::wireframe(20, 40)); } template SphereRenderer::SphereRenderer(const Shapes::Implementation::AbstractShape& sphere): sphere(static_cast>&>(sphere).shape) {} From 68638969f3bbcd2f7f8a9a17619c1b1680146229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Aug 2013 22:54:06 +0200 Subject: [PATCH 62/64] Don't forbid setting resources by copy/move. It adds much more convenience. Only some resources can't be moved around (i.e. those with someone pointing at them), which isn't excuse for forbidding copy/move altogether. Finally it is possible to do convenient things like this again: DebugTools::ResourceManager::instance()->set("red", DebugTools::ShapeRendererOptions().setColor({1.0f, 0.0f, 0.0f})); --- src/AbstractResourceLoader.h | 10 ++++++++++ src/ResourceManager.h | 17 ++++++++++++++++- src/Test/ResourceManagerTest.cpp | 15 +++++++-------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/AbstractResourceLoader.h b/src/AbstractResourceLoader.h index 3c7e4e697..830297489 100644 --- a/src/AbstractResourceLoader.h +++ b/src/AbstractResourceLoader.h @@ -161,6 +161,11 @@ template class AbstractResourceLoader { */ void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy); + /** @overload */ + template void set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) { + set(key, new typename std::remove_cv::type>::type(std::forward(data)), state, policy); + } + /** * @brief Set loaded resource to resource manager * @@ -171,6 +176,11 @@ template class AbstractResourceLoader { set(key, data, ResourceDataState::Final, ResourcePolicy::Resident); } + /** @overload */ + template void set(ResourceKey key, U&& data) { + set(key, new typename std::remove_cv::type>::type(std::forward(data))); + } + /** * @brief Mark resource as not found * diff --git a/src/ResourceManager.h b/src/ResourceManager.h index a1d4df745..b18393c49 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -313,17 +313,27 @@ template class ResourceManager: private Implementation::Resource return *this; } + /** @overload */ + template ResourceManager& set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) { + return set(key, new typename std::remove_cv::type>::type(std::forward(data)), state, policy); + } + /** * @brief Set resource data * @return Reference to self (for method chaining) * - * Same as above function with state set to @ref ResourceDataState "ResourceDataState::Final" + * Same as above with state set to @ref ResourceDataState "ResourceDataState::Final" * and policy to @ref ResourcePolicy "ResourcePolicy::Resident". */ template ResourceManager& set(ResourceKey key, T* data) { return set(key, data, ResourceDataState::Final, ResourcePolicy::Resident); } + /** @overload */ + template ResourceManager& set(ResourceKey key, U&& data) { + return set(key, new typename std::remove_cv::type>::type(std::forward(data))); + } + /** @brief Fallback for not found resources */ template T* fallback() { return this->Implementation::ResourceManagerData::fallback(); @@ -343,6 +353,11 @@ template class ResourceManager: private Implementation::Resource return *this; } + /** @overload */ + template ResourceManager& setFallback(U&& data) { + return setFallback(new typename std::remove_cv::type>::type(std::forward(data))); + } + /** * @brief Free all resources of given type which are not referenced * @return Reference to self (for method chaining) diff --git a/src/Test/ResourceManagerTest.cpp b/src/Test/ResourceManagerTest.cpp index c6d38cf02..92c325343 100644 --- a/src/Test/ResourceManagerTest.cpp +++ b/src/Test/ResourceManagerTest.cpp @@ -129,8 +129,7 @@ void ResourceManagerTest::stateDisallowed() { std::ostringstream out; Error::setOutput(&out); - Data d; - rm.set("data", &d, ResourceDataState::Loading, ResourcePolicy::Resident); + rm.set("data", Data(), 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({}); @@ -144,8 +143,8 @@ void ResourceManagerTest::basic() { /* One mutable, one final */ ResourceKey questionKey("the-question"); ResourceKey answerKey("the-answer"); - rm.set(questionKey, new Int(10), ResourceDataState::Mutable, ResourcePolicy::Resident); - rm.set(answerKey, new Int(42), ResourceDataState::Final, ResourcePolicy::Resident); + rm.set(questionKey, 10, ResourceDataState::Mutable, ResourcePolicy::Resident); + rm.set(answerKey, 42, ResourceDataState::Final, ResourcePolicy::Resident); Resource theQuestion = rm.get(questionKey); Resource theAnswer = rm.get(answerKey); @@ -159,12 +158,12 @@ void ResourceManagerTest::basic() { /* Cannot change already final resource */ std::ostringstream out; Error::setOutput(&out); - rm.set(answerKey, new Int(43), ResourceDataState::Mutable, ResourcePolicy::Resident); + rm.set(answerKey, 43, ResourceDataState::Mutable, ResourcePolicy::Resident); CORRADE_COMPARE(*theAnswer, 42); CORRADE_COMPARE(out.str(), "ResourceManager::set(): cannot change already final resource " + answerKey.hexString() + '\n'); /* But non-final can be changed */ - rm.set(questionKey, new Int(20), ResourceDataState::Final, ResourcePolicy::Resident); + rm.set(questionKey, 20, ResourceDataState::Final, ResourcePolicy::Resident); CORRADE_COMPARE(theQuestion.state(), ResourceState::Final); CORRADE_COMPARE(*theQuestion, 20); } @@ -250,7 +249,7 @@ void ResourceManagerTest::clearWhileReferenced() { Error::setOutput(&out); ResourceManager rm; - rm.set("blah", new Int); + rm.set("blah", Int()); /** @todo this will leak, is there any better solution without hitting assertion in decrementReferenceCount()? */ new Resource(rm.get("blah")); @@ -265,7 +264,7 @@ void ResourceManagerTest::loader() { IntResourceLoader(): resource(ResourceManager::instance().get("data")) {} void load() { - set("hello", new Int(773), ResourceDataState::Final, ResourcePolicy::Resident); + set("hello", 773, ResourceDataState::Final, ResourcePolicy::Resident); setNotFound("world"); } From 3285b23ad91fb27dfc12197c55914e4cb2c930e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 22 Aug 2013 12:03:57 +0200 Subject: [PATCH 63/64] Minor cleanup in tests. --- src/Test/ResourceManagerTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Test/ResourceManagerTest.cpp b/src/Test/ResourceManagerTest.cpp index 92c325343..7718c1906 100644 --- a/src/Test/ResourceManagerTest.cpp +++ b/src/Test/ResourceManagerTest.cpp @@ -98,7 +98,7 @@ void ResourceManagerTest::state() { void ResourceManagerTest::stateFallback() { { ResourceManager rm; - rm.setFallback(new Data); + rm.setFallback(new Data); Resource data = rm.get("data"); CORRADE_VERIFY(data); @@ -188,7 +188,7 @@ void ResourceManagerTest::referenceCountedPolicy() { /* Reference counted resources must be requested first */ { - rm.set(dataRefCountKey, new Data(), ResourceDataState::Final, ResourcePolicy::ReferenceCounted); + rm.set(dataRefCountKey, new Data, ResourceDataState::Final, ResourcePolicy::ReferenceCounted); CORRADE_COMPARE(rm.count(), 0); Resource data = rm.get(dataRefCountKey); CORRADE_COMPARE(data.state(), ResourceState::NotLoaded); @@ -197,7 +197,7 @@ void ResourceManagerTest::referenceCountedPolicy() { Resource data = rm.get(dataRefCountKey); CORRADE_COMPARE(rm.count(), 1); CORRADE_COMPARE(data.state(), ResourceState::NotLoaded); - rm.set(dataRefCountKey, new Data(), ResourceDataState::Final, ResourcePolicy::ReferenceCounted); + rm.set(dataRefCountKey, new Data, ResourceDataState::Final, ResourcePolicy::ReferenceCounted); CORRADE_COMPARE(data.state(), ResourceState::Final); CORRADE_COMPARE(Data::count, 1); } From f4a410eddf2e5d21909236165fc7fcb0a61debf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 22 Aug 2013 14:32:35 +0200 Subject: [PATCH 64/64] GCC 4.6 compatibility: no `override` keyword. --- src/Shapes/shapeImplementation.h | 1 + src/Test/AbstractOpenGLTester.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Shapes/shapeImplementation.h b/src/Shapes/shapeImplementation.h index 898f50bd3..a91457775 100644 --- a/src/Shapes/shapeImplementation.h +++ b/src/Shapes/shapeImplementation.h @@ -26,6 +26,7 @@ #include #include +#include #include "DimensionTraits.h" #include "Magnum.h" diff --git a/src/Test/AbstractOpenGLTester.h b/src/Test/AbstractOpenGLTester.h index fe23735a2..f23a83e67 100644 --- a/src/Test/AbstractOpenGLTester.h +++ b/src/Test/AbstractOpenGLTester.h @@ -25,6 +25,7 @@ */ #include +#include #include "Renderer.h"