diff --git a/src/Plugins/MagnumFont/CMakeLists.txt b/src/Plugins/MagnumFont/CMakeLists.txt new file mode 100644 index 000000000..11d09f8e5 --- /dev/null +++ b/src/Plugins/MagnumFont/CMakeLists.txt @@ -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. +# + +find_package(Magnum REQUIRED Text) + +set(MagnumFont_SOURCES + MagnumFont.cpp) + +set(MagnumFont_HEADERS + MagnumFont.h) + +add_library(MagnumFontObjects OBJECT ${MagnumFont_SOURCES}) +set_target_properties(MagnumFontObjects PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") + +add_plugin(MagnumFont ${MAGNUM_PLUGINS_FONT_INSTALL_DIR} + MagnumFont.conf + $ + pluginRegistrationMagnumFont.cpp) +target_link_libraries(MagnumFont + ${MAGNUM_LIBRARIES} + ${MAGNUM_TEXT_LIBRARIES}) + +if(WIN32) + target_link_libraries(MagnumFont TgaImporter) +endif() + +install(FILES ${MagnumFont_HEADERS} DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/MagnumFont) + +if(BUILD_GL_TESTS) + add_library(MagnumFontTestLib STATIC $) + target_link_libraries(MagnumFontTestLib + ${MAGNUM_LIBRARIES} + ${MAGNUM_TEXT_LIBRARIES} + TgaImporterTestLib) + + add_subdirectory(Test) +endif() diff --git a/src/Plugins/MagnumFont/MagnumFont.conf b/src/Plugins/MagnumFont/MagnumFont.conf new file mode 100644 index 000000000..6aae56c10 --- /dev/null +++ b/src/Plugins/MagnumFont/MagnumFont.conf @@ -0,0 +1 @@ +depends=TgaImporter diff --git a/src/Plugins/MagnumFont/MagnumFont.cpp b/src/Plugins/MagnumFont/MagnumFont.cpp new file mode 100644 index 000000000..8fdbeedf9 --- /dev/null +++ b/src/Plugins/MagnumFont/MagnumFont.cpp @@ -0,0 +1,238 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION 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 "MagnumFont.h" + +#include +#include +#include +#include +#include +#include + +#include "TgaImporter/TgaImporter.h" + +namespace Magnum { namespace Text { + +struct MagnumFont::Data { + Utility::Configuration conf; + Trade::ImageData2D image; + std::unordered_map glyphId; + std::vector glyphAdvance; +}; + +namespace { + class MagnumFontLayouter: public AbstractLayouter { + public: + explicit MagnumFontLayouter(const std::unordered_map& glyphId, const std::vector& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, const std::string& text); + + std::tuple renderGlyph(UnsignedInt i) override; + + private: + const std::vector& glyphAdvance; + const GlyphCache& cache; + const Float fontSize, textSize; + std::vector glyphs; + }; +} + +MagnumFont::MagnumFont(): _opened(nullptr) {} + +MagnumFont::MagnumFont(PluginManager::AbstractManager* const manager, std::string plugin): AbstractFont(manager, std::move(plugin)), _opened(nullptr) {} + +MagnumFont::~MagnumFont() { close(); } + +auto MagnumFont::doFeatures() const -> Features { return Feature::OpenData|Feature::MultiFile|Feature::PreparedGlyphCache; } + +bool MagnumFont::doIsOpened() const { return _opened; } + +void MagnumFont::doOpenData(const std::vector>>& data, const Float) { + /* We need just the configuration file and image file */ + if(data.size() != 2) { + Error() << "Text::MagnumFont::openData(): wanted two files, got" << data.size(); + return; + } + + /* Open the configuration file */ + std::istringstream in({reinterpret_cast(data[0].second.begin()), data[0].second.size()}); + Utility::Configuration conf(in, Utility::Configuration::Flag::SkipComments); + if(!conf.isValid() || conf.isEmpty()) { + Error() << "Text::MagnumFont::openData(): cannot open file" << data[0].first << conf.isValid(); + return; + } + + /* Check version */ + if(conf.value("version") != 1) { + Error() << "Text::MagnumFont::openData(): unsupported file version, expected 1 but got" + << conf.value("version"); + return; + } + + /* Check that we have also the image file */ + if(conf.value("image") != data[1].first) { + Error() << "Text::MagnumFont::openData(): expected file" + << conf.value("image") << "but got" << data[1].first; + return; + } + + /* Open and load image file */ + Trade::TgaImporter importer; + if(!importer.openData(data[1].second)) { + Error() << "Text::MagnumFont::openData(): cannot open image file"; + return; + } + std::optional image = importer.image2D(0); + if(!image) { + Error() << "Text::MagnumFont::openData(): cannot load image file"; + return; + } + + openInternal(std::move(conf), std::move(*image)); +} + +void MagnumFont::doOpenFile(const std::string& filename, Float) { + /* Open the configuration file */ + Utility::Configuration conf(filename, Utility::Configuration::Flag::ReadOnly|Utility::Configuration::Flag::SkipComments); + if(!conf.isValid() || conf.isEmpty()) { + Error() << "Text::MagnumFont::openFile(): cannot open file" << filename << conf.isValid(); + return; + } + + /* Check version */ + if(conf.value("version") != 1) { + Error() << "Text::MagnumFont::openFile(): unsupported file version, expected 1 but got" + << conf.value("version"); + return; + } + + /* Open and load image file */ + const std::string imageFilename = Utility::Directory::join(Utility::Directory::path(filename), conf.value("image")); + Trade::TgaImporter importer; + if(!importer.openFile(imageFilename)) { + Error() << "Text::MagnumFont::openFile(): cannot open image file" << imageFilename; + return; + } + std::optional image = importer.image2D(0); + if(!image) { + Error() << "Text::MagnumFont::openFile(): cannot load image file"; + return; + } + + openInternal(std::move(conf), std::move(*image)); +} + +void MagnumFont::openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image) { + /* Everything okay, save the data internally */ + _opened = new Data{std::move(conf), std::move(image), {}, {}}; + _size = _opened->conf.value("fontSize"); + + /* Glyph advances */ + const std::vector glyphs = _opened->conf.groups("glyph"); + _opened->glyphAdvance.reserve(glyphs.size()); + for(const Utility::ConfigurationGroup* const g: glyphs) + _opened->glyphAdvance.push_back(g->value("advance")); + + /* Fill character->glyph map */ + const std::vector chars = _opened->conf.groups("char"); + for(const Utility::ConfigurationGroup* const c: chars) { + const UnsignedInt glyphId = c->value("glyph"); + CORRADE_INTERNAL_ASSERT(glyphId < _opened->glyphAdvance.size()); + _opened->glyphId.emplace(c->value("unicode"), glyphId); + } +} + +void MagnumFont::doClose() { + delete _opened; + _opened = nullptr; +} + +UnsignedInt MagnumFont::doGlyphId(const char32_t character) { + auto it = _opened->glyphId.find(character); + return it != _opened->glyphId.end() ? it->second : 0; +} + +Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) { + return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2(); +} + +GlyphCache* MagnumFont::doCreateGlyphCache() { + /* Set cache image */ + auto cache = new Text::GlyphCache( + _opened->conf.value("originalImageSize"), + _opened->image.size(), + _opened->conf.value("padding")); + cache->setImage({}, _opened->image); + + /* Fill glyph map */ + const std::vector glyphs = _opened->conf.groups("glyph"); + for(std::size_t i = 0; i != glyphs.size(); ++i) + cache->insert(i, glyphs[i]->value("position"), glyphs[i]->value("rectangle")); + + return cache; +} + +AbstractLayouter* MagnumFont::doLayout(const GlyphCache& cache, Float size, const std::string& text) { + return new MagnumFontLayouter(_opened->glyphId, _opened->glyphAdvance, cache, this->size(), size, text); +} + +namespace { + +MagnumFontLayouter::MagnumFontLayouter(const std::unordered_map& glyphId, const std::vector& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, const std::string& text): glyphAdvance(glyphAdvance), cache(cache), fontSize(fontSize), textSize(textSize) { + /* Get glyph codes from characters */ + glyphs.reserve(text.size()); + for(std::size_t i = 0; i != text.size(); ) { + UnsignedInt codepoint; + std::tie(codepoint, i) = Utility::Unicode::nextChar(text, i); + const auto it = glyphId.find(codepoint); + glyphs.push_back(it == glyphId.end() ? 0 : it->second); + } + _glyphCount = glyphs.size(); +} + +std::tuple MagnumFontLayouter::renderGlyph(UnsignedInt i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Vector2i position; + Rectanglei rectangle; + std::tie(position, rectangle) = cache[glyphs[i]]; + + const Rectangle texturePosition = Rectangle::fromSize(Vector2(position)/fontSize, + Vector2(rectangle.size())/fontSize); + const Rectangle textureCoordinates(Vector2(rectangle.bottomLeft())/Vector2(cache.textureSize()), + Vector2(rectangle.topRight())/Vector2(cache.textureSize())); + + /* Absolute quad position, composed from cursor position, glyph offset + and texture position, denormalized to requested text size */ + Rectangle quadPosition = Rectangle::fromSize( + Vector2(texturePosition.left(), texturePosition.bottom())*textSize, + texturePosition.size()*textSize); + + /* Advance for given glyph, denormalized to requested text size */ + const Vector2 advance = glyphAdvance[glyphs[i]]*textSize/fontSize; + + return std::make_tuple(quadPosition, textureCoordinates, advance); +} + +} + +}} diff --git a/src/Plugins/MagnumFont/MagnumFont.h b/src/Plugins/MagnumFont/MagnumFont.h new file mode 100644 index 000000000..18690b750 --- /dev/null +++ b/src/Plugins/MagnumFont/MagnumFont.h @@ -0,0 +1,140 @@ +#ifndef Magnum_Text_MagnumFont_h +#define Magnum_Text_MagnumFont_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Text::MagnumFont + */ + +#include +#include + +namespace Magnum { namespace Text { + +/** +@brief Simple bitmap font plugin + +This plugin depends on @ref Trade::TgaImporter "TgaImporter" plugin and is +built if `WITH_MAGNUMFONT` is enabled in CMake. To use dynamic plugin, you need +to load `%MagnumFont` plugin from `fonts/` subdirectory of your plugin dir. To +use static plugin or use this as a dependency of another plugin, you need to +request `%MagnumFont` component in CMake and link to +`${MAGNUMPLUGINS_MAGNUMFONT_LIBRARIES}`. See @ref building-plugins and +@ref cmake-plugins for more information. + +The font consists of two files, one text file containing character and glyph +info and one TGA file containing the glyphs in distance field format. The font +can be conveniently created from any other format using MagnumFontConverter. +The file syntax is as in following: + + # Font image filename + image=font.tga + + # Size of unscaled font image + originalImageSize=1536 1536 + + # Glyph padding + padding=9 + + # Font size + fontSize=128 + + # Character + [char] + + # UTF-32 codepoint ('a') + unicode=0061 + + # Glyph ID + glyph=1 + + # Advance to next character in pixels (i.e. on unscaled font image) + advance=45 0 + + # Another character + [char] + unicode=0062 + glyph=2 + advance=42 0 + + # ... + + # Glyph 0, a.k.a. "Not Found" glyph + [glyph] + + # Glyph texture position relative to baseline, in pixels + position=5 -1 + + # Glyph rectangle in font image, in pixels (left, bottom, right, top) + rectangle=0 0 42 25 + + # Glyph 1 + [glyph] + position=0 0 + rectangle=45 0 44 25 + + # ... + +@see Trade::TgaImporter +*/ +class MagnumFont: public AbstractFont { + public: + /** @brief Default constructor */ + explicit MagnumFont(); + + /** @brief Plugin manager constructor */ + explicit MagnumFont(PluginManager::AbstractManager* manager, std::string plugin); + + ~MagnumFont(); + + private: + struct Data; + + Features doFeatures() const override; + + bool doIsOpened() const override; + + void doOpenData(const std::vector>>& data, Float) override; + + void doOpenFile(const std::string& filename, Float) override; + + void doClose() override; + + UnsignedInt doGlyphId(char32_t character) override; + + Vector2 doGlyphAdvance(UnsignedInt glyph) override; + + GlyphCache* doCreateGlyphCache() override; + + AbstractLayouter* doLayout(const GlyphCache& cache, Float size, const std::string& text) override; + + Data* _opened; + + void openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image); +}; + +}} + +#endif diff --git a/src/Plugins/MagnumFont/Test/CMakeLists.txt b/src/Plugins/MagnumFont/Test/CMakeLists.txt new file mode 100644 index 000000000..0cc473499 --- /dev/null +++ b/src/Plugins/MagnumFont/Test/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magnumFontTestConfigure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/magnumFontTestConfigure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(MagnumFontTest MagnumFontTest.cpp LIBRARIES MagnumFontTestLib ${GL_TEST_LIBRARIES}) diff --git a/src/Plugins/MagnumFont/Test/MagnumFontTest.cpp b/src/Plugins/MagnumFont/Test/MagnumFontTest.cpp new file mode 100644 index 000000000..35b130f8e --- /dev/null +++ b/src/Plugins/MagnumFont/Test/MagnumFontTest.cpp @@ -0,0 +1,105 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION 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 "MagnumFont/MagnumFont.h" + +#include "magnumFontTestConfigure.h" + +namespace Magnum { namespace Text { namespace Test { + +class MagnumFontTest: public Magnum::Test::AbstractOpenGLTester { + public: + explicit MagnumFontTest(); + + void properties(); + void layout(); + void createGlyphCache(); +}; + +MagnumFontTest::MagnumFontTest() { + addTests({&MagnumFontTest::properties, + &MagnumFontTest::layout, + &MagnumFontTest::createGlyphCache}); +} + +void MagnumFontTest::properties() { + MagnumFont font; + CORRADE_VERIFY(font.openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f)); + CORRADE_COMPARE(font.size(), 16.0f); + CORRADE_COMPARE(font.glyphAdvance(font.glyphId(U'W')), Vector2(23.0f, 0.0f)); +} + +void MagnumFontTest::layout() { + MagnumFont font; + CORRADE_VERIFY(font.openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f)); + + /* Fill the cache with some fake glyphs */ + GlyphCache cache(Vector2i(256)); + cache.insert(font.glyphId(U'W'), {25, 34}, {{0, 8}, {16, 128}}); + cache.insert(font.glyphId(U'e'), {25, 12}, {{16, 4}, {64, 32}}); + + AbstractLayouter* layouter = font.layout(cache, 0.5f, "Wave"); + CORRADE_VERIFY(layouter); + CORRADE_COMPARE(layouter->glyphCount(), 4); + + Rectangle position; + Rectangle textureCoordinates; + Vector2 advance; + + /* 'W' */ + std::tie(position, textureCoordinates, advance) = layouter->renderGlyph(0); + CORRADE_COMPARE(position, Rectangle({0.78125f, 1.0625f}, {1.28125f, 4.8125f})); + CORRADE_COMPARE(textureCoordinates, Rectangle({0, 0.03125f}, {0.0625f, 0.5f})); + CORRADE_COMPARE(advance, Vector2(0.71875f, 0.0f)); + + /* 'a' (not found) */ + std::tie(position, textureCoordinates, advance) = layouter->renderGlyph(1); + CORRADE_COMPARE(position, Rectangle()); + CORRADE_COMPARE(textureCoordinates, Rectangle()); + CORRADE_COMPARE(advance, Vector2(0.25f, 0.0f)); + + /* 'v' (not found) */ + std::tie(position, textureCoordinates, advance) = layouter->renderGlyph(2); + CORRADE_COMPARE(position, Rectangle()); + CORRADE_COMPARE(textureCoordinates, Rectangle()); + CORRADE_COMPARE(advance, Vector2(0.25f, 0.0f)); + + /* 'e' */ + std::tie(position, textureCoordinates, advance) = layouter->renderGlyph(3); + CORRADE_COMPARE(position, Rectangle({0.78125f, 0.375f}, {2.28125f, 1.25f})); + CORRADE_COMPARE(textureCoordinates, Rectangle({0.0625f, 0.015625f}, {0.25f, 0.125f})); + CORRADE_COMPARE(advance, Vector2(0.375f, 0.0f)); +} + +void MagnumFontTest::createGlyphCache() { + /** @todo */ +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Text::Test::MagnumFontTest) diff --git a/src/Plugins/MagnumFont/Test/font.conf b/src/Plugins/MagnumFont/Test/font.conf new file mode 100644 index 000000000..4c2a3baea --- /dev/null +++ b/src/Plugins/MagnumFont/Test/font.conf @@ -0,0 +1,29 @@ +version=1 +image=font.tga +originalImageSize=1536 1536 +padding=24 24 +fontSize=16 +[char] +unicode=57 +glyph=2 +[char] +unicode=61 +glyph=0 +[char] +unicode=65 +glyph=1 +[char] +unicode=76 +glyph=0 +[glyph] +advance=8 0 +position=24 24 +rectangle=24 24 -24 -24 +[glyph] +advance=12 0 +position=25 12 +rectangle=16 4 64 32 +[glyph] +advance=23 0 +position=25 34 +rectangle=0 8 16 128 diff --git a/src/Plugins/MagnumFont/Test/font.tga b/src/Plugins/MagnumFont/Test/font.tga new file mode 100644 index 000000000..8389c0da6 Binary files /dev/null and b/src/Plugins/MagnumFont/Test/font.tga differ diff --git a/src/Plugins/MagnumFont/Test/magnumFontTestConfigure.h.cmake b/src/Plugins/MagnumFont/Test/magnumFontTestConfigure.h.cmake new file mode 100644 index 000000000..250b209d4 --- /dev/null +++ b/src/Plugins/MagnumFont/Test/magnumFontTestConfigure.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 MAGNUMFONT_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" diff --git a/src/Plugins/MagnumFont/pluginRegistrationMagnumFont.cpp b/src/Plugins/MagnumFont/pluginRegistrationMagnumFont.cpp new file mode 100644 index 000000000..3250c4f96 --- /dev/null +++ b/src/Plugins/MagnumFont/pluginRegistrationMagnumFont.cpp @@ -0,0 +1,28 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "MagnumFont/MagnumFont.h" + +CORRADE_PLUGIN_REGISTER(MagnumFont, Magnum::Text::MagnumFont, + "cz.mosra.magnum.Text.AbstractFont/0.2") diff --git a/src/Plugins/MagnumFontConverter/CMakeLists.txt b/src/Plugins/MagnumFontConverter/CMakeLists.txt new file mode 100644 index 000000000..71efa0c47 --- /dev/null +++ b/src/Plugins/MagnumFontConverter/CMakeLists.txt @@ -0,0 +1,57 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION 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(Magnum REQUIRED Text) + +set(MagnumFontConverter_SOURCES + MagnumFontConverter.cpp) + +set(MagnumFontConverter_HEADERS + MagnumFontConverter.h) + +add_library(MagnumFontConverterObjects OBJECT ${MagnumFontConverter_SOURCES}) +set_target_properties(MagnumFontConverterObjects PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") + +add_plugin(MagnumFontConverter ${MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR} + MagnumFontConverter.conf + $ + pluginRegistrationMagnumFontConverter.cpp) +target_link_libraries(MagnumFontConverter + ${MAGNUM_LIBRARIES} + ${MAGNUM_TEXT_LIBRARIES}) + +if(WIN32) + target_link_libraries(MagnumFontConverter TgaImageConverter) +endif() + +install(FILES ${MagnumFontConverter_HEADERS} DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/MagnumFontConverter) + +if(BUILD_GL_TESTS) + add_library(MagnumFontConverterTestLib STATIC $) + target_link_libraries(MagnumFontConverterTestLib + ${MAGNUM_LIBRARIES} + ${MAGNUM_TEXT_LIBRARIES} + TgaImageConverterTestLib) + add_subdirectory(Test) +endif() diff --git a/src/Plugins/MagnumFontConverter/MagnumFontConverter.conf b/src/Plugins/MagnumFontConverter/MagnumFontConverter.conf new file mode 100644 index 000000000..977dc2119 --- /dev/null +++ b/src/Plugins/MagnumFontConverter/MagnumFontConverter.conf @@ -0,0 +1 @@ +depends=TgaImageConverter diff --git a/src/Plugins/MagnumFontConverter/MagnumFontConverter.cpp b/src/Plugins/MagnumFontConverter/MagnumFontConverter.cpp new file mode 100644 index 000000000..0e841fca3 --- /dev/null +++ b/src/Plugins/MagnumFontConverter/MagnumFontConverter.cpp @@ -0,0 +1,115 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "MagnumFontConverter.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Magnum { namespace Text { + +MagnumFontConverter::MagnumFontConverter() = default; + +MagnumFontConverter::MagnumFontConverter(PluginManager::AbstractManager* manager, std::string plugin): AbstractFontConverter(manager, std::move(plugin)) {} + +auto MagnumFontConverter::doFeatures() const -> Features { + return Feature::ExportFont|Feature::ConvertData|Feature::MultiFile; +} + +#ifndef _WIN32 +std::vector>> MagnumFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const +#else +std::vector>> MagnumFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::vector& characters) const +#endif +{ + Utility::Configuration configuration; + + configuration.setValue("version", 1); + configuration.setValue("image", Utility::Directory::filename(filename) + ".tga"); + configuration.setValue("originalImageSize", cache.textureSize()); + configuration.setValue("padding", cache.padding()); + configuration.setValue("fontSize", font.size()); + + /* Compress glyph IDs so the glyphs are in consecutive array, glyph 0 + should stay at position 0 */ + std::unordered_map glyphIdMap; + glyphIdMap.reserve(cache.glyphCount()); + glyphIdMap.emplace(0, 0); + for(const std::pair>& glyph: cache) + glyphIdMap.emplace(glyph.first, glyphIdMap.size()); + + /** @todo Save only glyphs contained in @p characters */ + + /* Inverse map from new glyph IDs to old ones */ + std::vector inverseGlyphIdMap(glyphIdMap.size()); + for(const std::pair& map: glyphIdMap) + inverseGlyphIdMap[map.second] = map.first; + + /* Character->glyph map, map glyph IDs to new ones */ + for(const char32_t c: characters) { + Utility::ConfigurationGroup* group = configuration.addGroup("char"); + const UnsignedInt glyphId = font.glyphId(c); + group->setValue("unicode", c); + + /* Map old glyph ID to new, if not found, map to glyph 0 */ + auto found = glyphIdMap.find(glyphId); + group->setValue("glyph", found == glyphIdMap.end() ? 0 : glyphIdMap.at(glyphId)); + } + + /* Save glyph properties in order which preserves their IDs, remove padding + from the values so they aren't added twice when using the font later */ + /** @todo Some better way to handle this padding stuff */ + for(UnsignedInt oldGlyphId: inverseGlyphIdMap) { + std::pair glyph = cache[oldGlyphId]; + Utility::ConfigurationGroup* group = configuration.addGroup("glyph"); + group->setValue("advance", font.glyphAdvance(oldGlyphId)); + group->setValue("position", glyph.first+cache.padding()); + group->setValue("rectangle", Rectanglei(glyph.second.bottomLeft()+cache.padding(), + glyph.second.topRight()-cache.padding())); + } + + std::ostringstream confOut; + configuration.save(confOut); + std::string confStr = confOut.str(); + Containers::Array confData{confStr.size()}; + std::copy(confStr.begin(), confStr.end(), confData.begin()); + + /* Save cache image */ + Image2D image(ColorFormat::Red, ColorType::UnsignedByte); + cache.texture().image(0, image); + auto tgaData = Trade::TgaImageConverter().exportToData(image); + + std::vector>> out; + out.emplace_back(filename + ".conf", std::move(confData)); + out.emplace_back(filename + ".tga", std::move(tgaData)); + return std::move(out); +} + +}} diff --git a/src/Plugins/MagnumFontConverter/MagnumFontConverter.h b/src/Plugins/MagnumFontConverter/MagnumFontConverter.h new file mode 100644 index 000000000..8c363f84b --- /dev/null +++ b/src/Plugins/MagnumFontConverter/MagnumFontConverter.h @@ -0,0 +1,70 @@ +#ifndef Magnum_Text_MagnumFontConverter_h +#define Magnum_Text_MagnumFontConverter_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Text::MagnumFontConverter + */ + +#include + +namespace Magnum { namespace Text { + +/** +@brief MagnumFont converter plugin + +Expects filename prefix, creates two files, `prefix.conf` and `prefix.tga`. See +@ref MagnumFont for more information about the font. + +This plugin is available only on desktop OpenGL, as it uses @ref Texture::image() +to read back the generated data. It depends on +@ref Trade::TgaImageConverter "TgaImageConverter" plugin and is built if +`WITH_MAGNUMFONTCONVERTER` is enabled in CMake. To use dynamic plugin, you need +to load `%MagnumFontConverter` plugin from `fontconverters/` subdirectory of +your plugin dir. To use static plugin or use this as a dependency of another +plugin, you need to request `%MagnumFontConverter` component in CMake and link +to `${MAGNUMPLUGINS_MAGNUMFONTCONVERTER_LIBRARIES}`. See @ref building-plugins +and @ref cmake-plugins for more information. +*/ +class MagnumFontConverter: public Text::AbstractFontConverter { + public: + /** @brief Default constructor */ + explicit MagnumFontConverter(); + + /** @brief Plugin manager constructor */ + explicit MagnumFontConverter(PluginManager::AbstractManager* manager, std::string plugin); + + private: + Features doFeatures() const override; + #ifndef _WIN32 + std::vector>> doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const override; + #else + std::vector>> doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::vector& characters) const override; + #endif +}; + +}} + +#endif diff --git a/src/Plugins/MagnumFontConverter/Test/CMakeLists.txt b/src/Plugins/MagnumFontConverter/Test/CMakeLists.txt new file mode 100644 index 000000000..a6b28e93e --- /dev/null +++ b/src/Plugins/MagnumFontConverter/Test/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magnumFontConverterTestConfigure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/magnumFontConverterTestConfigure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../FreeTypeFont/Test/ + ${CMAKE_CURRENT_BINARY_DIR}/../../MagnumFont/Test/ + ${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(MagnumFontConverterTest MagnumFontConverterTest.cpp LIBRARIES + MagnumFontConverterTestLib + FreeTypeFontTestLib + TgaImporterTestLib + ${GL_TEST_LIBRARIES}) diff --git a/src/Plugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp b/src/Plugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp new file mode 100644 index 000000000..9e00c415c --- /dev/null +++ b/src/Plugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp @@ -0,0 +1,100 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FreeTypeFont/FreeTypeFont.h" +#include "MagnumFontConverter/MagnumFontConverter.h" +#include "TgaImporter/TgaImporter.h" + +#include "freeTypeFontTestConfigure.h" +#include "magnumFontTestConfigure.h" +#include "magnumFontConverterTestConfigure.h" + +namespace Magnum { namespace Text { namespace Test { + +class MagnumFontConverterTest: public Magnum::Test::AbstractOpenGLTester { + public: + explicit MagnumFontConverterTest(); + + ~MagnumFontConverterTest(); + + void exportFont(); +}; + +MagnumFontConverterTest::MagnumFontConverterTest() { + addTests({&MagnumFontConverterTest::exportFont}); + + FreeTypeFont::initialize(); +} + +MagnumFontConverterTest::~MagnumFontConverterTest() { + FreeTypeFont::finalize(); +} + +void MagnumFontConverterTest::exportFont() { + /* Remove previously created files */ + Utility::Directory::rm(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.conf")); + Utility::Directory::rm(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.tga")); + + /* Open font */ + FreeTypeFont font; + CORRADE_VERIFY(font.openFile(Utility::Directory::join(FREETYPEFONT_TEST_DIR, "Oxygen.ttf"), 16.0f)); + + /* Create fake cache */ + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); + GlyphCache cache(TextureFormat::R8, Vector2i(1536), Vector2i(256), Vector2i(24)); + cache.insert(font.glyphId(U'W'), {25, 34}, {{0, 8}, {16, 128}}); + cache.insert(font.glyphId(U'e'), {25, 12}, {{16, 4}, {64, 32}}); + + /* Convert the file */ + MagnumFontConverter converter; + converter.exportFontToFile(font, cache, Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font"), "Wave"); + + /* Verify font parameters */ + /** @todo This might behave differently elsewhere due to unspecified order of glyphs in cache */ + CORRADE_COMPARE_AS(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.conf"), + Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), + TestSuite::Compare::File); + + /* Verify font image, no need to test image contents, as the image is garbage anyway */ + Trade::TgaImporter importer; + CORRADE_VERIFY(importer.openFile(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.tga"))); + std::optional image = importer.image2D(0); + CORRADE_VERIFY(image); + CORRADE_COMPARE(image->size(), Vector2i(256)); + CORRADE_COMPARE(image->format(), ColorFormat::Red); + CORRADE_COMPARE(image->type(), ColorType::UnsignedByte); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Text::Test::MagnumFontConverterTest) diff --git a/src/Plugins/MagnumFontConverter/Test/magnumFontConverterTestConfigure.h.cmake b/src/Plugins/MagnumFontConverter/Test/magnumFontConverterTestConfigure.h.cmake new file mode 100644 index 000000000..befd1c45b --- /dev/null +++ b/src/Plugins/MagnumFontConverter/Test/magnumFontConverterTestConfigure.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 MAGNUMFONTCONVERTER_TEST_WRITE_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/src/Plugins/MagnumFontConverter/pluginRegistrationMagnumFontConverter.cpp b/src/Plugins/MagnumFontConverter/pluginRegistrationMagnumFontConverter.cpp new file mode 100644 index 000000000..a0bbc18ce --- /dev/null +++ b/src/Plugins/MagnumFontConverter/pluginRegistrationMagnumFontConverter.cpp @@ -0,0 +1,28 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "MagnumFontConverter/MagnumFontConverter.h" + +CORRADE_PLUGIN_REGISTER(MagnumFontConverter, Magnum::Text::MagnumFontConverter, + "cz.mosra.magnum.Text.AbstractFontConverter/0.1") diff --git a/src/Plugins/TgaImageConverter/CMakeLists.txt b/src/Plugins/TgaImageConverter/CMakeLists.txt new file mode 100644 index 000000000..f72e90679 --- /dev/null +++ b/src/Plugins/TgaImageConverter/CMakeLists.txt @@ -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. +# + +set(TgaImageConverter_SRCS + TgaImageConverter.cpp) + +set(TgaImageConverter_HEADERS + TgaImageConverter.h) + +add_library(TgaImageConverterObjects OBJECT ${TgaImageConverter_SRCS}) +set_target_properties(TgaImageConverterObjects PROPERTIES COMPILE_FLAGS "-DTgaImageConverterObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") + +add_plugin(TgaImageConverter ${MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR} + TgaImageConverter.conf + $ + pluginRegistrationTgaImageConverter.cpp) +target_link_libraries(TgaImageConverter ${MAGNUM_LIBRARIES}) + +install(FILES ${TgaImageConverter_HEADERS} DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/TgaImageConverter) + +if(BUILD_TESTS) + add_library(TgaImageConverterTestLib SHARED $) + target_link_libraries(TgaImageConverterTestLib ${MAGNUM_LIBRARIES}) + add_subdirectory(Test) +endif() diff --git a/src/Plugins/TgaImageConverter/Test/CMakeLists.txt b/src/Plugins/TgaImageConverter/Test/CMakeLists.txt new file mode 100644 index 000000000..f1c56f698 --- /dev/null +++ b/src/Plugins/TgaImageConverter/Test/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/configure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(TgaImageConverterTest TgaImageConverterTest.cpp LIBRARIES TgaImageConverterTestLib TgaImporterTestLib) diff --git a/src/Plugins/TgaImageConverter/Test/TgaImageConverterTest.cpp b/src/Plugins/TgaImageConverter/Test/TgaImageConverterTest.cpp new file mode 100644 index 000000000..20e1a5c77 --- /dev/null +++ b/src/Plugins/TgaImageConverter/Test/TgaImageConverterTest.cpp @@ -0,0 +1,113 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "configure.h" + +namespace Magnum { namespace Trade { namespace Test { + +class TgaImageConverterTest: public TestSuite::Tester { + public: + explicit TgaImageConverterTest(); + + void wrongFormat(); + void wrongType(); + + void data(); +}; + +namespace { + #ifndef MAGNUM_TARGET_GLES + const Image2D original(ColorFormat::BGR, ColorType::UnsignedByte, {2, 3}, new char[18] + #else + const Image2D original(ColorFormat::RGB, ColorType::UnsignedByte, {2, 3}, new char[18] + #endif + { + 1, 2, 3, 2, 3, 4, + 3, 4, 5, 4, 5, 6, + 5, 6, 7, 6, 7, 8 + }); +} + +TgaImageConverterTest::TgaImageConverterTest() { + addTests({&TgaImageConverterTest::wrongFormat, + &TgaImageConverterTest::wrongType, + + &TgaImageConverterTest::data}); +} + +void TgaImageConverterTest::wrongFormat() { + ImageReference2D image(ColorFormat::RG, ColorType::UnsignedByte, {}, nullptr); + + std::ostringstream out; + Error::setOutput(&out); + + const auto data = TgaImageConverter().exportToData(image); + CORRADE_VERIFY(!data); + CORRADE_COMPARE(out.str(), "Trade::TgaImageConverter::convertToData(): unsupported image format ColorFormat::RG\n"); +} + +void TgaImageConverterTest::wrongType() { + ImageReference2D image(ColorFormat::Red, ColorType::Float, {}, nullptr); + + std::ostringstream out; + Error::setOutput(&out); + + const auto data = TgaImageConverter().exportToData(image); + CORRADE_VERIFY(!data); + CORRADE_COMPARE(out.str(), "Trade::TgaImageConverter::convertToData(): unsupported image type ColorType::Float\n"); +} + +void TgaImageConverterTest::data() { + const auto data = TgaImageConverter().exportToData(original); + + TgaImporter importer; + CORRADE_VERIFY(importer.openData(data)); + std::optional converted = importer.image2D(0); + CORRADE_VERIFY(converted); + + CORRADE_COMPARE(converted->size(), Vector2i(2, 3)); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(converted->format(), ColorFormat::BGR); + #else + CORRADE_COMPARE(converted->format(), ColorFormat::RGB); + #endif + CORRADE_COMPARE(converted->type(), ColorType::UnsignedByte); + CORRADE_COMPARE(std::string(reinterpret_cast(converted->data()), 2*3*3), + std::string(reinterpret_cast(original.data()), 2*3*3)); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Trade::Test::TgaImageConverterTest) diff --git a/src/Plugins/TgaImageConverter/Test/configure.h.cmake b/src/Plugins/TgaImageConverter/Test/configure.h.cmake new file mode 100644 index 000000000..98c60f430 --- /dev/null +++ b/src/Plugins/TgaImageConverter/Test/configure.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 TGAIMAGECONVERTER_TEST_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/src/Plugins/TgaImageConverter/TgaImageConverter.conf b/src/Plugins/TgaImageConverter/TgaImageConverter.conf new file mode 100644 index 000000000..e69de29bb diff --git a/src/Plugins/TgaImageConverter/TgaImageConverter.cpp b/src/Plugins/TgaImageConverter/TgaImageConverter.cpp new file mode 100644 index 000000000..e273226ae --- /dev/null +++ b/src/Plugins/TgaImageConverter/TgaImageConverter.cpp @@ -0,0 +1,98 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "TgaImageConverter.h" + +#include +#include +#include +#include +#include +#include + +#ifdef MAGNUM_TARGET_GLES +#include +#include +#endif + +#include "TgaImporter/TgaHeader.h" + +namespace Magnum { namespace Trade { + +TgaImageConverter::TgaImageConverter() = default; + +TgaImageConverter::TgaImageConverter(PluginManager::AbstractManager* manager, std::string plugin): AbstractImageConverter(manager, std::move(plugin)) {} + +auto TgaImageConverter::doFeatures() const -> Features { return Feature::ConvertData; } + +Containers::Array TgaImageConverter::doExportToData(const ImageReference2D& image) const { + #ifndef MAGNUM_TARGET_GLES + if(image.format() != ColorFormat::BGR && + image.format() != ColorFormat::BGRA && + image.format() != ColorFormat::Red) + #else + if(image.format() != ColorFormat::RGB && + image.format() != ColorFormat::RGBA && + image.format() != ColorFormat::Red) + #endif + { + Error() << "Trade::TgaImageConverter::convertToData(): unsupported image format" << image.format(); + return nullptr; + } + + if(image.type() != ColorType::UnsignedByte) { + Error() << "Trade::TgaImageConverter::convertToData(): unsupported image type" << image.type(); + return nullptr; + } + + /* Initialize data buffer */ + const UnsignedByte pixelSize = image.pixelSize(); + auto data = Containers::Array::zeroInitialized(sizeof(TgaHeader) + pixelSize*image.size().product()); + + /* Fill header */ + auto header = reinterpret_cast(data.begin()); + header->imageType = image.format() == ColorFormat::Red ? 3 : 2; + header->bpp = pixelSize*8; + header->width = Utility::Endianness::littleEndian(image.size().x()); + header->height = Utility::Endianness::littleEndian(image.size().y()); + + /* Fill data */ + std::copy(image.data(), image.data()+pixelSize*image.size().product(), data.begin()+sizeof(TgaHeader)); + + #ifdef MAGNUM_TARGET_GLES + if(image->format() == ColorFormat::RGB) { + auto pixels = reinterpret_cast*>(data.begin()+sizeof(TgaHeader)); + std::transform(pixels, pixels + image.size().product(), pixels, + [](Math::Vector3 pixel) { return swizzle<'b', 'g', 'r'>(pixel); }); + } else if(image.format() == ColorFormat::RGBA) { + auto pixels = reinterpret_cast*>(data.begin()+sizeof(TgaHeader)); + std::transform(pixels, pixels + image.size().product(), pixels, + [](Math::Vector4 pixel) { return swizzle<'b', 'g', 'r', 'a'>(pixel); }); + } + #endif + + return std::move(data); +} + +}} diff --git a/src/Plugins/TgaImageConverter/TgaImageConverter.h b/src/Plugins/TgaImageConverter/TgaImageConverter.h new file mode 100644 index 000000000..face4c643 --- /dev/null +++ b/src/Plugins/TgaImageConverter/TgaImageConverter.h @@ -0,0 +1,72 @@ +#ifndef Magnum_Trade_TgaImageConverter_h +#define Magnum_Trade_TgaImageConverter_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::Trade::TgaImageConverter + */ + +#include + +#ifndef DOXYGEN_GENERATING_OUTPUT +#if defined(TgaImageConverter_EXPORTS) || defined(TgaImageConverterObjects_EXPORTS) + #define MAGNUM_TRADE_TGAIMAGECONVERTER_EXPORT CORRADE_VISIBILITY_EXPORT +#else + #define MAGNUM_TRADE_TGAIMAGECONVERTER_EXPORT CORRADE_VISIBILITY_IMPORT +#endif +#define MAGNUM_TRADE_TGAIMAGECONVERTER_LOCAL CORRADE_VISIBILITY_LOCAL +#endif + +namespace Magnum { namespace Trade { + +/** +@brief TGA image converter plugin + +Supports images with format @ref ColorFormat::BGR, @ref ColorFormat::BGRA or +@ref ColorFormat::Red and type @ref ColorType::UnsignedByte. + +This plugin is built if `WITH_TGAIMAGECONVERTER` is enabled in CMake. To use +dynamic plugin, you need to load `%TgaImageConverter` plugin from +`imageconverters/` subdirectory of your plugin dir. To use static plugin or use +this as a dependency of another plugin, you need to request `%TgaImageConverter` +component in CMake and link to `${MAGNUMPLUGINS_TGAIMAGECONVERTER_LIBRARIES}`. +See @ref building-plugins and @ref cmake-plugins for more information. +*/ +class MAGNUM_TRADE_TGAIMAGECONVERTER_EXPORT TgaImageConverter: public AbstractImageConverter { + public: + /** @brief Default constructor */ + explicit TgaImageConverter(); + + /** @brief Plugin manager constructor */ + explicit TgaImageConverter(PluginManager::AbstractManager* manager, std::string plugin); + + private: + Features MAGNUM_TRADE_TGAIMAGECONVERTER_LOCAL doFeatures() const override; + Containers::Array MAGNUM_TRADE_TGAIMAGECONVERTER_LOCAL doExportToData(const ImageReference2D& image) const override; +}; + +}} + +#endif diff --git a/src/Plugins/TgaImageConverter/pluginRegistrationTgaImageConverter.cpp b/src/Plugins/TgaImageConverter/pluginRegistrationTgaImageConverter.cpp new file mode 100644 index 000000000..fe5767e82 --- /dev/null +++ b/src/Plugins/TgaImageConverter/pluginRegistrationTgaImageConverter.cpp @@ -0,0 +1,28 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "TgaImageConverter/TgaImageConverter.h" + +CORRADE_PLUGIN_REGISTER(TgaImageConverter, Magnum::Trade::TgaImageConverter, + "cz.mosra.magnum.Trade.AbstractImageConverter/0.2.1") diff --git a/src/Plugins/TgaImporter/CMakeLists.txt b/src/Plugins/TgaImporter/CMakeLists.txt new file mode 100644 index 000000000..90b63a1ea --- /dev/null +++ b/src/Plugins/TgaImporter/CMakeLists.txt @@ -0,0 +1,47 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +set(TgaImporter_SRCS + TgaImporter.cpp) + +set(TgaImporter_HEADERS + TgaHeader.h + TgaImporter.h) + +add_library(TgaImporterObjects OBJECT ${TgaImporter_SRCS}) +set_target_properties(TgaImporterObjects PROPERTIES COMPILE_FLAGS "-DTgaImporterObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") + +add_plugin(TgaImporter ${MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR} + TgaImporter.conf + $ + pluginRegistrationTgaImporter.cpp) +target_link_libraries(TgaImporter ${MAGNUM_LIBRARIES}) + +install(FILES ${TgaImporter_HEADERS} DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/TgaImporter) + +if(BUILD_TESTS) + add_library(TgaImporterTestLib SHARED $) + target_link_libraries(TgaImporterTestLib ${MAGNUM_LIBRARIES}) + add_subdirectory(Test) +endif() diff --git a/src/Plugins/TgaImporter/Test/CMakeLists.txt b/src/Plugins/TgaImporter/Test/CMakeLists.txt new file mode 100644 index 000000000..3e825ad47 --- /dev/null +++ b/src/Plugins/TgaImporter/Test/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/configure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(TgaImporterTest TgaImporterTest.cpp LIBRARIES TgaImporterTestLib) diff --git a/src/Plugins/TgaImporter/Test/TgaImporterTest.cpp b/src/Plugins/TgaImporter/Test/TgaImporterTest.cpp new file mode 100644 index 000000000..7f08d8c62 --- /dev/null +++ b/src/Plugins/TgaImporter/Test/TgaImporterTest.cpp @@ -0,0 +1,239 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "TgaImporter/TgaImporter.h" + +#include "configure.h" + +namespace Magnum { namespace Trade { namespace Test { + +class TgaImporterTest: public TestSuite::Tester { + public: + TgaImporterTest(); + + void openInexistent(); + void openShort(); + void paletted(); + void compressed(); + + void colorBits16(); + void colorBits24(); + void colorBits32(); + + void grayscaleBits8(); + void grayscaleBits16(); + + void file(); +}; + +TgaImporterTest::TgaImporterTest() { + addTests({&TgaImporterTest::openInexistent, + &TgaImporterTest::openShort, + &TgaImporterTest::paletted, + &TgaImporterTest::compressed, + + &TgaImporterTest::colorBits16, + &TgaImporterTest::colorBits24, + &TgaImporterTest::colorBits32, + + &TgaImporterTest::grayscaleBits8, + &TgaImporterTest::grayscaleBits16, + + &TgaImporterTest::file}); +} + +void TgaImporterTest::openInexistent() { + std::ostringstream debug; + Error::setOutput(&debug); + + TgaImporter importer; + CORRADE_VERIFY(!importer.openFile("inexistent.file")); + CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::openFile(): cannot open file inexistent.file\n"); +} + +void TgaImporterTest::openShort() { + TgaImporter importer; + const unsigned char data[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + CORRADE_VERIFY(importer.openData(data)); + + std::ostringstream debug; + Error::setOutput(&debug); + CORRADE_VERIFY(!importer.image2D(0)); + CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): the file is too short: 17 bytes\n"); +} + +void TgaImporterTest::paletted() { + TgaImporter importer; + const unsigned char data[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + CORRADE_VERIFY(importer.openData(data)); + + std::ostringstream debug; + Error::setOutput(&debug); + CORRADE_VERIFY(!importer.image2D(0)); + CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): paletted files are not supported\n"); +} + +void TgaImporterTest::compressed() { + TgaImporter importer; + const unsigned char data[] = { 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + CORRADE_VERIFY(importer.openData(data)); + + std::ostringstream debug; + Error::setOutput(&debug); + CORRADE_VERIFY(!importer.image2D(0)); + CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported (compressed?) image type: 9\n"); +} + +void TgaImporterTest::colorBits16() { + TgaImporter importer; + const unsigned char data[] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 }; + CORRADE_VERIFY(importer.openData(data)); + + std::ostringstream debug; + Error::setOutput(&debug); + CORRADE_VERIFY(!importer.image2D(0)); + CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported color bits-per-pixel: 16\n"); +} + +void TgaImporterTest::colorBits24() { + TgaImporter importer; + const unsigned char data[] = { + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 24, 0, + 1, 2, 3, 2, 3, 4, + 3, 4, 5, 4, 5, 6, + 5, 6, 7, 6, 7, 8 + }; + #ifndef MAGNUM_TARGET_GLES + const char* pixels = reinterpret_cast(data) + 18; + #else + const char pixels[] = { + 3, 2, 1, 4, 3, 2, + 5, 4, 3, 6, 5, 4, + 7, 6, 5, 8, 7, 6 + }; + #endif + CORRADE_VERIFY(importer.openData(data)); + + std::optional image = importer.image2D(0); + CORRADE_VERIFY(image); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(image->format(), ColorFormat::BGR); + #else + CORRADE_COMPARE(image->format(), ColorFormat::RGB); + #endif + CORRADE_COMPARE(image->size(), Vector2i(2, 3)); + CORRADE_COMPARE(image->type(), ColorType::UnsignedByte); + CORRADE_COMPARE(std::string(reinterpret_cast(image->data()), 2*3*3), std::string(pixels, 2*3*3)); +} + +void TgaImporterTest::colorBits32() { + TgaImporter importer; + const unsigned char data[] = { + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 32, 0, + 1, 2, 3, 1, 2, 3, 4, 1, + 3, 4, 5, 1, 4, 5, 6, 1, + 5, 6, 7, 1, 6, 7, 8, 1 + }; + #ifndef MAGNUM_TARGET_GLES + const char* pixels = reinterpret_cast(data) + 18; + #else + const char pixels[] = { + 3, 2, 1, 1, 4, 3, 2, 1, + 5, 4, 3, 1, 6, 5, 4, 1, + 7, 6, 5, 1, 8, 7, 6, 1 + }; + #endif + CORRADE_VERIFY(importer.openData(data)); + + std::optional image = importer.image2D(0); + CORRADE_VERIFY(image); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(image->format(), ColorFormat::BGRA); + #else + CORRADE_COMPARE(image->format(), ColorFormat::RGBA); + #endif + CORRADE_COMPARE(image->size(), Vector2i(2, 3)); + CORRADE_COMPARE(image->type(), ColorType::UnsignedByte); + CORRADE_COMPARE(std::string(reinterpret_cast(image->data()), 2*3*3), std::string(pixels, 2*3*3)); +} + +void TgaImporterTest::grayscaleBits8() { + TgaImporter importer; + const unsigned char data[] = { + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0, + 1, 2, + 3, 4, + 5, 6 + }; + CORRADE_VERIFY(importer.openData(data)); + + std::optional image = importer.image2D(0); + CORRADE_VERIFY(image); + CORRADE_COMPARE(image->format(), ColorFormat::Red); + CORRADE_COMPARE(image->size(), Vector2i(2, 3)); + CORRADE_COMPARE(image->type(), ColorType::UnsignedByte); + CORRADE_COMPARE(std::string(reinterpret_cast(image->data()), 2*3), + std::string(reinterpret_cast(data) + 18, 2*3)); +} + +void TgaImporterTest::grayscaleBits16() { + TgaImporter importer; + const unsigned char data[] = { 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 }; + CORRADE_VERIFY(importer.openData(data)); + + std::ostringstream debug; + Error::setOutput(&debug); + CORRADE_VERIFY(!importer.image2D(0)); + CORRADE_COMPARE(debug.str(), "Trade::TgaImporter::image2D(): unsupported grayscale bits-per-pixel: 16\n"); +} + +void TgaImporterTest::file() { + TgaImporter importer; + const unsigned char data[] = { + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0, + 1, 2, + 3, 4, + 5, 6 + }; + CORRADE_VERIFY(importer.openFile(Utility::Directory::join(TGAIMPORTER_TEST_DIR, "file.tga"))); + + std::optional image = importer.image2D(0); + CORRADE_VERIFY(image); + CORRADE_COMPARE(image->format(), ColorFormat::Red); + CORRADE_COMPARE(image->size(), Vector2i(2, 3)); + CORRADE_COMPARE(image->type(), ColorType::UnsignedByte); + CORRADE_COMPARE(std::string(reinterpret_cast(image->data()), 2*3), + std::string(reinterpret_cast(data) + 18, 2*3)); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Trade::Test::TgaImporterTest) diff --git a/src/Plugins/TgaImporter/Test/configure.h.cmake b/src/Plugins/TgaImporter/Test/configure.h.cmake new file mode 100644 index 000000000..e507e8ed7 --- /dev/null +++ b/src/Plugins/TgaImporter/Test/configure.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 TGAIMPORTER_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" diff --git a/src/Plugins/TgaImporter/Test/file.tga b/src/Plugins/TgaImporter/Test/file.tga new file mode 100644 index 000000000..711486718 Binary files /dev/null and b/src/Plugins/TgaImporter/Test/file.tga differ diff --git a/src/Plugins/TgaImporter/TgaHeader.h b/src/Plugins/TgaImporter/TgaHeader.h new file mode 100644 index 000000000..def766d8e --- /dev/null +++ b/src/Plugins/TgaImporter/TgaHeader.h @@ -0,0 +1,58 @@ +#ifndef Magnum_Trade_TgaHeader_h +#define Magnum_Trade_TgaHeader_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 Struct Magnum::Trade::TgaHeader + */ + +#include + +namespace Magnum { namespace Trade { + +#pragma pack(1) +/** @brief TGA file header */ +/** @todoc Enable @c INLINE_SIMPLE_STRUCTS again when unclosed <component> in tagfile is fixed*/ +struct TgaHeader { + UnsignedByte identsize; /**< @brief Size of ID field that follows header (0) */ + UnsignedByte colorMapType; /**< @brief 0 = None, 1 = paletted */ + UnsignedByte imageType; /**< @brief 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle */ + UnsignedShort colorMapStart; /**< @brief First color map entry */ + UnsignedShort colorMapLength; /**< @brief Number of colors */ + UnsignedByte colorMapBpp; /**< @brief Bits per palette entry */ + UnsignedShort beginX; /**< @brief %Image x origin */ + UnsignedShort beginY; /**< @brief %Image y origin */ + UnsignedShort width; /**< @brief %Image width */ + UnsignedShort height; /**< @brief %Image height */ + UnsignedByte bpp; /**< @brief Bits per pixel (8, 16, 24, 32) */ + UnsignedByte descriptor; /**< @brief %Image descriptor */ +}; +#pragma pack() + +static_assert(sizeof(TgaHeader) == 18, "TgaHeader size is not 18 bytes"); + +}} + +#endif diff --git a/src/Plugins/TgaImporter/TgaImporter.conf b/src/Plugins/TgaImporter/TgaImporter.conf new file mode 100644 index 000000000..02be1f4ce --- /dev/null +++ b/src/Plugins/TgaImporter/TgaImporter.conf @@ -0,0 +1,4 @@ +author=Vladimír Vondruš + +[metadata] +name=TGA image importer diff --git a/src/Plugins/TgaImporter/TgaImporter.cpp b/src/Plugins/TgaImporter/TgaImporter.cpp new file mode 100644 index 000000000..5e6867c4e --- /dev/null +++ b/src/Plugins/TgaImporter/TgaImporter.cpp @@ -0,0 +1,160 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION 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 "TgaImporter.h" + +#include +#include +#include +#include +#include +#include + +#ifdef MAGNUM_TARGET_GLES +#include +#include +#include +#include +#endif + +#include "TgaHeader.h" + +namespace Magnum { namespace Trade { + +TgaImporter::TgaImporter(): in(nullptr) {} + +TgaImporter::TgaImporter(PluginManager::AbstractManager* manager, std::string plugin): AbstractImporter(manager, std::move(plugin)), in(nullptr) {} + +TgaImporter::~TgaImporter() { close(); } + +auto TgaImporter::doFeatures() const -> Features { return Feature::OpenData; } + +bool TgaImporter::doIsOpened() const { return in; } + +void TgaImporter::doOpenData(const Containers::ArrayReference data) { + in = new std::istringstream(std::string(reinterpret_cast(data.begin()), data.size())); +} + +void TgaImporter::doOpenFile(const std::string& filename) { + in = new std::ifstream(filename.c_str()); + if(in->good()) return; + + Error() << "Trade::TgaImporter::openFile(): cannot open file" << filename; + close(); +} + +void TgaImporter::doClose() { + delete in; + in = nullptr; +} + +UnsignedInt TgaImporter::doImage2DCount() const { return 1; } + +std::optional TgaImporter::doImage2D(UnsignedInt) { + /* Check if the file is long enough */ + in->seekg(0, std::istream::end); + std::streampos filesize = in->tellg(); + in->seekg(0, std::istream::beg); + if(filesize < std::streampos(sizeof(TgaHeader))) { + Error() << "Trade::TgaImporter::image2D(): the file is too short:" << filesize << "bytes"; + return std::nullopt; + } + + TgaHeader header; + in->read(reinterpret_cast(&header), sizeof(TgaHeader)); + + /* Convert to machine endian */ + header.width = Utility::Endianness::littleEndian(header.width); + header.height = Utility::Endianness::littleEndian(header.height); + + /* Image format */ + ColorFormat format; + if(header.colorMapType != 0) { + Error() << "Trade::TgaImporter::image2D(): paletted files are not supported"; + return std::nullopt; + } + + /* Color */ + if(header.imageType == 2) { + switch(header.bpp) { + case 24: + #ifndef MAGNUM_TARGET_GLES + format = ColorFormat::BGR; + #else + format = ColorFormat::RGB; + #endif + break; + case 32: + #ifndef MAGNUM_TARGET_GLES + format = ColorFormat::BGRA; + #else + format = ColorFormat::RGBA; + #endif + break; + default: + Error() << "Trade::TgaImporter::image2D(): unsupported color bits-per-pixel:" << header.bpp; + return std::nullopt; + } + + /* Grayscale */ + } else if(header.imageType == 3) { + #ifdef MAGNUM_TARGET_GLES + format = Context::current() && Context::current()->isExtensionSupported() ? + ColorFormat::Red : ColorFormat::Luminance; + #else + format = ColorFormat::Red; + #endif + if(header.bpp != 8) { + Error() << "Trade::TgaImporter::image2D(): unsupported grayscale bits-per-pixel:" << header.bpp; + return std::nullopt; + } + + /* Compressed files */ + } else { + Error() << "Trade::TgaImporter::image2D(): unsupported (compressed?) image type:" << header.imageType; + return std::nullopt; + } + + const std::size_t dataSize = header.width*header.height*header.bpp/8; + char* const data = new char[dataSize]; + in->read(data, dataSize); + + Vector2i size(header.width, header.height); + + #ifdef MAGNUM_TARGET_GLES + if(format == ColorFormat::RGB) { + auto pixels = reinterpret_cast*>(data); + std::transform(pixels, pixels + size.product(), pixels, + [](Math::Vector3 pixel) { return swizzle<'b', 'g', 'r'>(pixel); }); + } else if(format == ColorFormat::RGBA) { + auto pixels = reinterpret_cast*>(data); + std::transform(pixels, pixels + size.product(), pixels, + [](Math::Vector4 pixel) { return swizzle<'b', 'g', 'r', 'a'>(pixel); }); + } + #endif + + return ImageData2D(format, ColorType::UnsignedByte, size, data); +} + +}} diff --git a/src/Plugins/TgaImporter/TgaImporter.h b/src/Plugins/TgaImporter/TgaImporter.h new file mode 100644 index 000000000..95deeeebb --- /dev/null +++ b/src/Plugins/TgaImporter/TgaImporter.h @@ -0,0 +1,90 @@ +#ifndef Magnum_Trade_TgaImporter_h +#define Magnum_Trade_TgaImporter_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::Trade::TgaImporter + */ + +#include +#include + +#ifndef DOXYGEN_GENERATING_OUTPUT +#if defined(TgaImporter_EXPORTS) || defined(TgaImporterObjects_EXPORTS) + #define MAGNUM_TRADE_TGAIMPORTER_EXPORT CORRADE_VISIBILITY_EXPORT +#else + #define MAGNUM_TRADE_TGAIMPORTER_EXPORT CORRADE_VISIBILITY_IMPORT +#endif +#define MAGNUM_TRADE_TGAIMPORTER_LOCAL CORRADE_VISIBILITY_LOCAL +#endif + +namespace Magnum { namespace Trade { + +/** +@brief TGA importer plugin + +Supports uncompressed BGR, BGRA or grayscale images with 8 bits per channel. + +This plugin is built if `WITH_TGAIMPORTER` is enabled in CMake. To use dynamic +plugin, you need to load `%TgaImporter` plugin from `importers/` subdirectory +of your plugin dir. To use static plugin or use this as a dependency of another +plugin, you need to request `%TgaImporter` component in CMake and link to +`${MAGNUMPLUGINS_TGAIMPORTER_LIBRARIES}`. See @ref building-plugins and +@ref cmake-plugins for more information. + +The images are imported with @ref ColorType::UnsignedByte and @ref ColorFormat::BGR, +@ref ColorFormat::BGRA or @ref ColorFormat::Red, respectively. Grayscale images +require extension @extension{ARB,texture_rg}. + +In OpenGL ES BGR and BGRA images are converted to @ref ColorFormat::RGB +and @ref ColorFormat::RGBA. In OpenGL ES 2.0, if @es_extension{EXT,texture_rg} +is not supported, grayscale images use @ref ColorFormat::Luminance instead of +@ref ColorFormat::Red. +*/ +class MAGNUM_TRADE_TGAIMPORTER_EXPORT TgaImporter: public AbstractImporter { + public: + /** @brief Default constructor */ + explicit TgaImporter(); + + /** @brief Plugin manager constructor */ + explicit TgaImporter(PluginManager::AbstractManager* manager, std::string plugin); + + ~TgaImporter(); + + private: + Features MAGNUM_TRADE_TGAIMPORTER_LOCAL doFeatures() const override; + bool MAGNUM_TRADE_TGAIMPORTER_LOCAL doIsOpened() const override; + void MAGNUM_TRADE_TGAIMPORTER_LOCAL doOpenData(Containers::ArrayReference data) override; + void MAGNUM_TRADE_TGAIMPORTER_LOCAL doOpenFile(const std::string& filename) override; + void MAGNUM_TRADE_TGAIMPORTER_LOCAL doClose() override; + UnsignedInt MAGNUM_TRADE_TGAIMPORTER_LOCAL doImage2DCount() const override; + std::optional MAGNUM_TRADE_TGAIMPORTER_LOCAL doImage2D(UnsignedInt id) override; + + std::istream* in; +}; + +}} + +#endif diff --git a/src/Plugins/TgaImporter/pluginRegistrationTgaImporter.cpp b/src/Plugins/TgaImporter/pluginRegistrationTgaImporter.cpp new file mode 100644 index 000000000..25a34e435 --- /dev/null +++ b/src/Plugins/TgaImporter/pluginRegistrationTgaImporter.cpp @@ -0,0 +1,28 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "TgaImporter.h" + +CORRADE_PLUGIN_REGISTER(TgaImporter, Magnum::Trade::TgaImporter, + "cz.mosra.magnum.Trade.AbstractImporter/0.3") diff --git a/src/Plugins/WavAudioImporter/CMakeLists.txt b/src/Plugins/WavAudioImporter/CMakeLists.txt new file mode 100644 index 000000000..71bce608f --- /dev/null +++ b/src/Plugins/WavAudioImporter/CMakeLists.txt @@ -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. +# + +find_package(Magnum REQUIRED Audio) + +include_directories(${MAGNUM_AUDIO_INCLUDE_DIRS}) + +set(WavAudioImporter_SRCS + WavImporter.cpp) + +set(WavAudioImporter_HEADERS + WavHeader.h + WavImporter.h) + +add_library(WavAudioImporterObjects OBJECT ${WavAudioImporter_SRCS}) +set_target_properties(WavAudioImporterObjects PROPERTIES COMPILE_FLAGS "-DWavAudioImporterObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") + +add_plugin(WavAudioImporter ${MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR} + WavAudioImporter.conf + $ + pluginRegistrationWavAudioImporter.cpp) +target_link_libraries(WavAudioImporter ${MAGNUM_LIBRARIES} ${MAGNUM_AUDIO_LIBRARIES}) + +install(FILES ${WavAudioImporter_HEADERS} DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/WavAudioImporter) + +if(BUILD_TESTS) + add_library(WavAudioImporterTestLib STATIC $) + target_link_libraries(WavAudioImporterTestLib ${MAGNUM_LIBRARIES} ${MAGNUM_AUDIO_LIBRARIES}) + add_subdirectory(Test) +endif() diff --git a/src/Plugins/WavAudioImporter/Test/CMakeLists.txt b/src/Plugins/WavAudioImporter/Test/CMakeLists.txt new file mode 100644 index 000000000..fda7c7e61 --- /dev/null +++ b/src/Plugins/WavAudioImporter/Test/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/configure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(WavAudioImporterTest WavImporterTest.cpp LIBRARIES WavAudioImporterTestLib) diff --git a/src/Plugins/WavAudioImporter/Test/WavImporterTest.cpp b/src/Plugins/WavAudioImporter/Test/WavImporterTest.cpp new file mode 100644 index 000000000..1a9593379 --- /dev/null +++ b/src/Plugins/WavAudioImporter/Test/WavImporterTest.cpp @@ -0,0 +1,123 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include "WavAudioImporter/WavImporter.h" + +#include "configure.h" + +namespace Magnum { namespace Audio { namespace Test { + +class WavImporterTest: public TestSuite::Tester { + public: + explicit WavImporterTest(); + + void wrongSize(); + void wrongSignature(); + void unsupportedFormat(); + void unsupportedChannelCount(); + void mono16(); + void stereo8(); +}; + +WavImporterTest::WavImporterTest() { + addTests({&WavImporterTest::wrongSize, + &WavImporterTest::wrongSignature, + &WavImporterTest::unsupportedFormat, + &WavImporterTest::unsupportedChannelCount, + &WavImporterTest::mono16, + &WavImporterTest::stereo8}); +} + +void WavImporterTest::wrongSize() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openData(Containers::Array(43))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): the file is too short: 43 bytes\n"); +} + +void WavImporterTest::wrongSignature() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "wrongSignature.wav"))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): the file signature is invalid\n"); +} + +void WavImporterTest::unsupportedFormat() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "unsupportedFormat.wav"))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): unsupported audio format 2\n"); +} + +void WavImporterTest::unsupportedChannelCount() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "unsupportedChannelCount.wav"))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): unsupported channel count 6 with 8 bits per sample\n"); +} + +void WavImporterTest::mono16() { + WavImporter importer; + CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono16.wav"))); + + CORRADE_COMPARE(importer.format(), Buffer::Format::Mono16); + CORRADE_COMPARE(importer.frequency(), 44000); + Containers::Array data = importer.data(); + CORRADE_COMPARE(data.size(), 4); + CORRADE_COMPARE(data[0], 0x1d); + CORRADE_COMPARE(data[1], 0x10); + CORRADE_COMPARE(data[2], 0x71); + CORRADE_COMPARE(data[3], 0xC5); +} + +void WavImporterTest::stereo8() { + WavImporter importer; + CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo8.wav"))); + + CORRADE_COMPARE(importer.format(), Buffer::Format::Stereo8); + CORRADE_COMPARE(importer.frequency(), 96000); + Containers::Array data = importer.data(); + CORRADE_COMPARE(data.size(), 4); + CORRADE_COMPARE(data[0], 0xde); + CORRADE_COMPARE(data[1], 0xfe); + CORRADE_COMPARE(data[2], 0xca); + CORRADE_COMPARE(data[3], 0x7e); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::WavImporterTest) diff --git a/src/Plugins/WavAudioImporter/Test/configure.h.cmake b/src/Plugins/WavAudioImporter/Test/configure.h.cmake new file mode 100644 index 000000000..d5a41dac3 --- /dev/null +++ b/src/Plugins/WavAudioImporter/Test/configure.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 WAVAUDIOIMPORTER_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" diff --git a/src/Plugins/WavAudioImporter/Test/mono16.wav b/src/Plugins/WavAudioImporter/Test/mono16.wav new file mode 100644 index 000000000..30d898274 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/mono16.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/stereo8.wav b/src/Plugins/WavAudioImporter/Test/stereo8.wav new file mode 100644 index 000000000..02298ef3b Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/stereo8.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/unsupportedChannelCount.wav b/src/Plugins/WavAudioImporter/Test/unsupportedChannelCount.wav new file mode 100644 index 000000000..2f0b89221 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/unsupportedChannelCount.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/unsupportedFormat.wav b/src/Plugins/WavAudioImporter/Test/unsupportedFormat.wav new file mode 100644 index 000000000..443eefa82 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/unsupportedFormat.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/wrongSignature.wav b/src/Plugins/WavAudioImporter/Test/wrongSignature.wav new file mode 100644 index 000000000..e50f1cd12 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/wrongSignature.wav differ diff --git a/src/Plugins/WavAudioImporter/WavAudioImporter.conf b/src/Plugins/WavAudioImporter/WavAudioImporter.conf new file mode 100644 index 000000000..e69de29bb diff --git a/src/Plugins/WavAudioImporter/WavHeader.h b/src/Plugins/WavAudioImporter/WavHeader.h new file mode 100644 index 000000000..e472b8f5f --- /dev/null +++ b/src/Plugins/WavAudioImporter/WavHeader.h @@ -0,0 +1,60 @@ +#ifndef Magnum_Audio_WavHeader_h +#define Magnum_Audio_WavHeader_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 Struct Magnum::Audio::WavHeader + */ + +#include + +namespace Magnum { namespace Audio { + +#pragma pack(1) +/** @brief WAV file header */ +struct WavHeader { + char chunkId[4]; /**< @brief `RIFF` characters */ + UnsignedInt chunkSize; /**< @brief Size of the rest of the file */ + char format[4]; /**< @brief `WAVE` characters */ + + char subChunk1Id[4]; /**< @brief `fmt ` characters */ + UnsignedInt subChunk1Size; /**< @brief 16 for PCM */ + UnsignedShort audioFormat; /**< @brief 1 = PCM */ + UnsignedShort numChannels; /**< @brief 1 = Mono, 2 = Stereo */ + UnsignedInt sampleRate; /**< @brief Sample rate in Hz */ + UnsignedInt byteRate; /**< @brief Bytes per second */ + UnsignedShort blockAlign; /**< @brief Bytes per sample (all channels) */ + UnsignedShort bitsPerSample; /**< @brief Bits per sample (one channel) */ + + char subChunk2Id[4]; /**< @brief `data` characters */ + UnsignedInt subChunk2Size; /**< @brief Size of the following data */ +}; +#pragma pack() + +static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes"); + +}} + +#endif diff --git a/src/Plugins/WavAudioImporter/WavImporter.cpp b/src/Plugins/WavAudioImporter/WavImporter.cpp new file mode 100644 index 000000000..db93e0885 --- /dev/null +++ b/src/Plugins/WavAudioImporter/WavImporter.cpp @@ -0,0 +1,130 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "WavImporter.h" + +#include +#include +#include + +#include "WavHeader.h" + +namespace Magnum { namespace Audio { + +WavImporter::WavImporter() = default; + +WavImporter::WavImporter(PluginManager::AbstractManager* manager, std::string plugin): AbstractImporter(manager, std::move(plugin)) {} + +WavImporter::~WavImporter() { close(); } + +auto WavImporter::doFeatures() const -> Features { return Feature::OpenData; } + +bool WavImporter::doIsOpened() const { return _data; } + +void WavImporter::doOpenData(Containers::ArrayReference data) { + /* Check file size */ + if(data.size() < sizeof(WavHeader)) { + Error() << "Audio::WavImporter::openData(): the file is too short:" << data.size() << "bytes"; + return; + } + + /* Get header contents and fix endianness */ + WavHeader header(*reinterpret_cast(data.begin())); + Utility::Endianness::littleEndianInPlace(header.chunkSize, + header.subChunk1Size, header.audioFormat, header.numChannels, + header.sampleRate, header.byteRate, header.blockAlign, + header.bitsPerSample, header.subChunk2Size); + + /* Check file signature */ + if(std::strncmp(header.chunkId, "RIFF", 4) != 0 || + std::strncmp(header.format, "WAVE", 4) != 0 || + std::strncmp(header.subChunk1Id, "fmt ", 4) != 0 || + std::strncmp(header.subChunk2Id, "data", 4) != 0) { + Error() << "Audio::WavImporter::openData(): the file signature is invalid"; + return; + } + + /* Check file size */ + if(header.chunkSize + 8 != data.size()) { + Error() << "Audio::WavImporter::openData(): the file has improper size, expected" + << header.chunkSize + 8 << "but got" << data.size(); + return; + } + + /* Check PCM format */ + if(header.audioFormat != 1) { + Error() << "Audio::WavImporter::openData(): unsupported audio format" << header.audioFormat; + return; + } + + /* Verify more things */ + if(header.subChunk1Size != 16 || + header.subChunk2Size + 44 != data.size() || + header.blockAlign != header.numChannels*header.bitsPerSample/8 || + header.byteRate != header.sampleRate*header.blockAlign) { + Error() << "Audio::WavImporter::openData(): the file is corrupted"; + return; + } + + /* Decide about format */ + if(header.numChannels == 1 && header.bitsPerSample == 8) + _format = Buffer::Format::Mono8; + else if(header.numChannels == 1 && header.bitsPerSample == 16) + _format = Buffer::Format::Mono16; + else if(header.numChannels == 2 && header.bitsPerSample == 8) + _format = Buffer::Format::Stereo8; + else if(header.numChannels == 2 && header.bitsPerSample == 16) + _format = Buffer::Format::Stereo16; + else { + Error() << "Audio::WavImporter::openData(): unsupported channel count" + << header.numChannels << "with" << header.bitsPerSample + << "bits per sample"; + return; + } + + /* Save frequency */ + _frequency = header.sampleRate; + + /** @todo Convert the data from little endian too */ + CORRADE_INTERNAL_ASSERT(!Utility::Endianness::isBigEndian()); + + /* Copy the data */ + _data = Containers::Array(header.subChunk2Size); + std::copy(data.begin()+sizeof(WavHeader), data.end(), _data.begin()); + return; +} + +void WavImporter::doClose() { _data = nullptr; } + +Buffer::Format WavImporter::doFormat() const { return _format; } + +UnsignedInt WavImporter::doFrequency() const { return _frequency; } + +Containers::Array WavImporter::doData() { + Containers::Array copy(_data.size()); + std::copy(_data.begin(), _data.end(), copy.begin()); + return copy; +} + +}} diff --git a/src/Plugins/WavAudioImporter/WavImporter.h b/src/Plugins/WavAudioImporter/WavImporter.h new file mode 100644 index 000000000..fe7f8010e --- /dev/null +++ b/src/Plugins/WavAudioImporter/WavImporter.h @@ -0,0 +1,78 @@ +#ifndef Magnum_Audio_WavImporter_h +#define Magnum_Audio_WavImporter_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::WavImporter + */ + +#include +#include +#include