diff --git a/buildscript/Makefile b/buildscript/Makefile index 487460c..01a600a 100755 --- a/buildscript/Makefile +++ b/buildscript/Makefile @@ -8,16 +8,16 @@ libbzip2_PATH := bzip2-1.0.6 libbzip2_CONFIGURE := /bin/true libbzip2_MAKE := PREFIX="$(COMMON_PREFIX)" -libjpeg_PKG := libjpeg-turbo-1.5.1.tar.gz -libjpeg_PATH := libjpeg-turbo-1.5.1 +libjpeg_PKG := libjpeg-turbo-1.5.2.tar.gz +libjpeg_PATH := libjpeg-turbo-1.5.2 libjpeg_CONFIGURE := $(COMMON_CONFIGURE) -libtiff_PKG := tiff-4.0.7.tar.gz -libtiff_PATH := tiff-4.0.7 +libtiff_PKG := tiff-4.0.8.tar.gz +libtiff_PATH := tiff-4.0.8 libtiff_CONFIGURE := $(COMMON_CONFIGURE) -libpng_PKG := libpng-1.6.28.tar.xz -libpng_PATH := libpng-1.6.28 +libpng_PKG := libpng-1.6.34.tar.xz +libpng_PATH := libpng-1.6.34 libpng_CONFIGURE := $(COMMON_CONFIGURE) zlib_PKG := zlib-1.2.11.tar.xz @@ -25,8 +25,8 @@ zlib_PATH := zlib-1.2.11 zlib_CONFIGURE := ./configure --static --prefix=$(COMMON_PREFIX) ImageMagick_PKG := ImageMagick.tar.gz -ImageMagick_PATH := ImageMagick-7.0.4-9 -ImageMagick_CONFIGURE := $(COMMON_CONFIGURE) --disable-openmp --with-gslib=no --without-freetype --without-lcms --without-openexr --without-webp --without-x +ImageMagick_PATH := ImageMagick-7.0.7-4 +ImageMagick_CONFIGURE := $(COMMON_CONFIGURE) --disable-openmp --with-gslib=no --without-fontconfig --without-freetype --without-lcms --without-openexr --without-pango --without-webp --without-x --without-xml export LD_LIBRARY_PATH := "$(COMMON_PREFIX)/lib" export PKG_CONFIG_PATH := "$(LD_LIBRARY_PATH)/pkgconfig" @@ -39,7 +39,7 @@ all: tex3ds: ImageMagick @cd .. && \ ./autogen.sh && \ - ./configure PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" PKG_CONFIG="pkg-config --static" && \ + ./configure PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" PKG_CONFIG="pkg-config --static" --prefix=$(DEVKITARM) && \ $(MAKE) LDFLAGS="-static -pthread" && \ strip $@ diff --git a/configure.ac b/configure.ac index beb317b..c773cd9 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AX_CHECK_COMPILE_FLAG([-Wall], [CPPFLAGS+=" -Wall"]) AX_CHECK_COMPILE_FLAG([-pthread], [CPPFLAGS+=" -pthread" LDFLAGS+=" -pthread"]) AX_CHECK_COMPILE_FLAG([-flto], [CPPFLAGS+=" -flto" LDFLAGS+=" -flto"]) AX_CHECK_COMPILE_FLAG([-pipe], [CPPFLAGS+=" -pipe"]) -AX_CHECK_COMPILE_FLAG([-std=c++11], [CXXFLAGS+=" -std=c++11"]) +AX_CXX_COMPILE_STDCXX_11(noext, mandatory) AC_LANG_POP() AC_CHECK_PROGS([DOXYGEN], [doxygen]) diff --git a/include/atlas.h b/include/atlas.h index a659d31..f6a2219 100644 --- a/include/atlas.h +++ b/include/atlas.h @@ -31,5 +31,13 @@ struct Atlas Magick::Image img; std::vector subs; + Atlas() + { } + + Atlas(const Atlas &other) = delete; + Atlas(Atlas &&other) = default; + Atlas& operator=(const Atlas &other) = delete; + Atlas& operator=(Atlas &&other) = delete; + static Atlas build(const std::vector &paths); }; diff --git a/include/compat.h b/include/compat.h deleted file mode 100644 index 10e18bb..0000000 --- a/include/compat.h +++ /dev/null @@ -1,46 +0,0 @@ -/*------------------------------------------------------------------------------ - * Copyright (c) 2017 - * Michael Theall (mtheall) - * - * This file is part of tex3ds. - * - * tex3ds is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * tex3ds is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with tex3ds. If not, see . - *----------------------------------------------------------------------------*/ -/** @file compat.h - * @brief C/C++ platform compatibility - */ -#pragma once - -#ifdef __cplusplus -#if __cplusplus >= 201103L -// C++11 -#include -#include - -/** @brief Deleted constructor decoration */ -#define DELETE_CONSTRUCTOR = delete -#else -// C++98 -#include -#include -#define nullptr NULL - -/** @brief Deleted constructor decoration */ -#define DELETE_CONSTRUCTOR -#endif -#else -// C -#include -#include -#endif diff --git a/include/compress.h b/include/compress.h index 47d579f..b09cb21 100644 --- a/include/compress.h +++ b/include/compress.h @@ -25,7 +25,6 @@ /** @brief Compression header size */ #define COMPRESSION_HEADER_SIZE 8 -#include "compat.h" #ifdef __cplusplus #include extern "C" diff --git a/include/encode.h b/include/encode.h index c117718..f28892b 100644 --- a/include/encode.h +++ b/include/encode.h @@ -24,10 +24,10 @@ * for ETC1/ETC1A4 which do not involve swizzling. */ #pragma once -#include "compat.h" #include "magick_compat.h" #include "rg_etc1.h" #include "subimage.h" +#include #include /** @namespace encode @@ -88,7 +88,12 @@ encode(const uint32_t &in, Buffer &out) template<> inline void encode(const float &in, Buffer &out) { - encode(in * 1024, out); + constexpr uint16_t scale = 1024; + + assert(in >= 0); + assert(in <= std::numeric_limits::max() / scale); + + encode(in * scale, out); } /** @brief Encode sub-image @@ -147,6 +152,12 @@ struct WorkUnit process(process) { } + WorkUnit() = delete; + WorkUnit(const WorkUnit &other) = delete; + WorkUnit(WorkUnit &&other) = default; + WorkUnit& operator=(const WorkUnit &other) = delete; + WorkUnit& operator=(WorkUnit &&other) = default; + /** @brief Work unit comparator * @param[in] other Work unit to compare * @returns sequence > other.sequence diff --git a/include/magick_compat.h b/include/magick_compat.h index d21e679..bd2c602 100644 --- a/include/magick_compat.h +++ b/include/magick_compat.h @@ -33,7 +33,6 @@ * - Magick::PixelPacket removed */ #pragma once -#include "compat.h" #include #include @@ -138,7 +137,7 @@ class PixelPacket Magick::Quantum *pixel; ///< Pixel referenced /** @brief Default constructor */ - Reference() DELETE_CONSTRUCTOR; + Reference() = delete; /** @brief Constructor * @param[in] cache Pixel cache @@ -152,7 +151,12 @@ class PixelPacket /** @brief Copy constructor * @param[in] other Reference to copy */ - Reference(const Reference &other); + Reference(const Reference &other) = default; + + /** @brief Copy constructor + * @param[in] other Reference to copy + */ + Reference(Reference &&other) = default; /** @brief Assignment operator * @param[in] other Reference to assign @@ -160,18 +164,11 @@ class PixelPacket */ Reference& operator=(const Reference &other); -#if __cplusplus >= 201103L - /** @brief Copy constructor - * @param[in] other Reference to copy - */ - Reference(Reference &&other) = default; - /** @brief Assignment operator * @param[in] other Reference to assign * @returns reference to self */ Reference& operator=(Reference &&other); -#endif /** @brief Assignment operator * @param[in] c Color to assign @@ -202,7 +199,6 @@ class PixelPacket */ PixelPacket& operator=(const PixelPacket &other); -#if __cplusplus >= 201103L /** @brief Copy constructor * @param[in] other PixelPacket to copy */ @@ -213,7 +209,6 @@ class PixelPacket * @returns reference to self */ PixelPacket& operator=(PixelPacket &&other); -#endif /** @brief Index operator * @param[in] index Pixel index diff --git a/include/tex3ds.h b/include/tex3ds.h deleted file mode 100644 index 2a3db36..0000000 --- a/include/tex3ds.h +++ /dev/null @@ -1,76 +0,0 @@ -/*------------------------------------------------------------------------------ - * Copyright (c) 2017 - * Michael Theall (mtheall) - * - * This file is part of tex3ds. - * - * tex3ds is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * tex3ds is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with tex3ds. If not, see . - *----------------------------------------------------------------------------*/ -/** @file tex3ds.h - * @brief tex3ds import/export support - */ -#pragma once -#include - -/** @brief Sub-Texture - * @note If top > bottom, the sub-texture is rotated 1/4 revolution counter-clockwise - */ -typedef struct Tex3DS_SubTexture -{ - uint16_t width; ///< Sub-texture width (pixels) - uint16_t height; ///< Sub-texture height (pixels) - float left; ///< Left u-coordinate - float top; ///< Top v-coordinate - float right; ///< Right u-coordinate - float bottom; ///< Bottom v-coordinate -} Tex3DS_SubTexture; - -/** @brief Data header - */ -typedef struct Tex3DS_Header -{ - uint16_t width; ///< Texture width - uint16_t height; ///< Texture height - uint8_t format; ///< Texture format - uint8_t mipmapLevels; ///< Number of mipmaps - uint16_t numSubTextures; ///< Number of sub-textures - Tex3DS_SubTexture subTextures[]; ///< Sub-textures -} Tex3DS_Header; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** @brief Import Tex3DS texture - * @param[in] input Input data - * @returns Tex3DS texture - */ -Tex3DS_Header* Tex3DS_Import(const void *input); - -/** @brief Get pointer to texture data - * @param[in] header Tex3DS header - * @returns Pointer to texture data - */ -void* Tex3DS_TextureData(const Tex3DS_Header *header); - -/** @brief Export Tex3DS texture - * @param[in] header Tex3DS header - * @returns Export buffer - */ -void* Tex3DS_Export(const Tex3DS_Header *header); - -#ifdef __cplusplus -} -#endif diff --git a/include/thread.h b/include/thread.h deleted file mode 100644 index 060d049..0000000 --- a/include/thread.h +++ /dev/null @@ -1,255 +0,0 @@ -/*------------------------------------------------------------------------------ - * Copyright (c) 2017 - * Michael Theall (mtheall) - * - * This file is part of tex3ds. - * - * tex3ds is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * tex3ds is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with tex3ds. If not, see . - *----------------------------------------------------------------------------*/ -/** @file thread.h - * @brief C++11 thread emulation - */ -#pragma once -#include "compat.h" - -#if __cplusplus >= 201103L -// C++11 Threads -#include -#include -#include - -/** @brief thread return type */ -#define THREAD_RETURN_T void - -/** @brief thread return statement */ -#define THREAD_EXIT return - -#elif defined(_WIN32) || defined(WIN32) -// C++98/03, Windows Threads -#error "Whoops this isn't ready yet." - -#else -#warning "C++11 threads emulated by pthreads" -// C++98/03, POSIX Threads -#include -#include -#include - -/** @brief thread return type */ -#define THREAD_RETURN_T void* - -/** @brief thread return statement */ -#define THREAD_EXIT return nullptr - -namespace std -{ - -class condition_variable; - -/** @brief Emulated std::mutex */ -class mutex -{ -private: - pthread_mutex_t mtx; ///< pthread mutex - - friend class std::condition_variable; - -public: - /** @brief Destructor */ - ~mutex() - { - int rc = pthread_mutex_destroy(&mtx); - if(rc != 0) - std::terminate(); - } - - /** @brief Constructor */ - mutex() - { - int rc = pthread_mutex_init(&mtx, nullptr); - if(rc != 0) - throw std::runtime_error("Failed to initialize mutex"); - } - - /** @brief Lock mutex */ - void lock() - { - int rc = pthread_mutex_lock(&mtx); - if(rc != 0) - throw std::runtime_error("Failed to lock mutex"); - } - - /** @brief Unlock mutex */ - void unlock() - { - int rc = pthread_mutex_unlock(&mtx); - if(rc != 0) - throw std::runtime_error("Failed to unlock mutex"); - } -}; - -/** @brief Emulated std::unique_lock - * @tparam T Lock type - */ -template -class unique_lock -{ -private: - T &ulock; ///< Unique lock - bool locked; ///< Whether locked - - friend class std::condition_variable; - -public: - /** @brief Destructor */ - ~unique_lock() - { - if(locked) - ulock.unlock(); - } - - /** @brief Constructor - * @param[in] ulock Unique lock - */ - unique_lock(T &ulock) - : ulock(ulock), - locked(true) - { - ulock.lock(); - } - - /** @brief Lock the lock */ - void lock() - { - ulock.lock(); - locked = true; - } - - /** @brief Unlock the lock */ - void unlock() - { - ulock.unlock(); - locked = false; - } -}; - -/** @brief Emulated std::condition_variable */ -class condition_variable -{ -private: - pthread_cond_t cond; ///< pthread condition variable - -public: - /** @brief Destructor */ - ~condition_variable() - { - int rc = pthread_cond_destroy(&cond); - if(rc != 0) - std::terminate(); - } - - /** @brief Constructor */ - condition_variable() - { - int rc = pthread_cond_init(&cond, nullptr); - if(rc != 0) - throw std::runtime_error("Failed to initialize condition variable"); - } - - /** @brief Wait for a condition - * @param[in] ulock Unique lock to yield - */ - void wait(std::unique_lock &ulock) - { - int rc = pthread_cond_wait(&cond, &ulock.ulock.mtx); - if(rc != 0) - throw std::runtime_error("Failed to wait on condition variable"); - } - - /** @brief Signal a condition waiter */ - void notify_one() - { - int rc = pthread_cond_signal(&cond); - if(rc != 0) - throw std::runtime_error("Failed to signal condition variable"); - } - - /** @brief Signal all condition waiters */ - void notify_all() - { - int rc = pthread_cond_broadcast(&cond); - if(rc != 0) - throw std::runtime_error("Failed to broadcast condition variable"); - } -}; - -/** @brief Emulated std::thread - * @note This does not call std::terminate() if an unjoined thread is - * destroyed since we do not have move semantics available. It can only - * wrap pthread entry functions since we don't have perfect forwarding or - * variadic templates. - */ -class thread -{ -private: - pthread_t tid; ///< pthread id - -public: - /** @brief Constructor - * @param[in] entry Entry function - * @param[in] arg Argument to pass to entry function - */ - thread(void* (*entry)(void*), void *arg) - { - int rc = pthread_create(&tid, nullptr, entry, arg); - if(rc != 0) - throw std::runtime_error("Failed to create thread"); - } - - /** @brief Join thread */ - void join() - { - int rc = pthread_join(tid, nullptr); - if(rc != 0) - throw std::runtime_error("Failed to join"); - } - - /** @brief Get hardware concurrency - * @returns hardware concurrency - */ - static unsigned int hardware_concurrency() - { - static unsigned int num_cores = 0; - if(num_cores) - return num_cores; - - /* try to get number of online cores */ - long rc = sysconf(_SC_NPROCESSORS_ONLN); - - /* fallback to number of configured cores */ - if(rc < 1) - rc = sysconf(_SC_NPROCESSORS_CONF); - - /* error */ - if(rc < 1) - throw std::runtime_error("Failed to get number of processors"); - - /* memoize number of cores */ - num_cores = rc; - return rc; - } -}; - -} -#endif diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 0000000..5032bba --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,982 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016 Krzesimir Nowak +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AX_REQUIRE_DEFINED([AC_MSG_WARN]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) + m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])]) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus <= 201402L + +#error "This is not a C++17 compiler" + +#else + +#if defined(__clang__) + #define REALLY_CLANG +#else + #if defined(__GNUC__) + #define REALLY_GCC + #endif +#endif + +#include +#include +#include + +namespace cxx17 +{ + +#if !defined(REALLY_CLANG) + namespace test_constexpr_lambdas + { + + // TODO: test it with clang++ from git + + constexpr int foo = [](){return 42;}(); + + } +#endif // !defined(REALLY_CLANG) + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + +#if !defined(REALLY_CLANG) + namespace test_template_argument_deduction_for_class_templates + { + + // TODO: test it with clang++ from git + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } +#endif // !defined(REALLY_CLANG) + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + +#if !defined(REALLY_CLANG) + namespace test_structured_bindings + { + + // TODO: test it with clang++ from git + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } +#endif // !defined(REALLY_CLANG) + +#if !defined(REALLY_CLANG) + namespace test_exception_spec_type_system + { + + // TODO: test it with clang++ from git + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } +#endif // !defined(REALLY_CLANG) + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus <= 201402L + +]]) diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000..1733fd8 --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,39 @@ +# ============================================================================= +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================= +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXX and CXXCPP to enable +# support. +# +# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX +# macro with the version set to C++11. The two optional arguments are +# forwarded literally as the second and third argument respectively. +# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for +# more information. If you want to use this macro, you also need to +# download the ax_cxx_compile_stdcxx.m4 file. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 18 + +AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) diff --git a/source/atlas.cpp b/source/atlas.cpp index 42cf98c..c482c80 100644 --- a/source/atlas.cpp +++ b/source/atlas.cpp @@ -8,12 +8,12 @@ namespace { -inline size_t calcPOT(size_t x) +inline size_t calcPOT(double x) { if(x < 8) return 8; - return std::pow(2.0, std::ceil(std::log(static_cast(x)) / std::log(2.0))); + return std::pow(2.0, std::ceil(std::log2(x))); } typedef std::pair XY; @@ -25,6 +25,12 @@ struct Block XY xy; size_t x, y, w, h; + Block() = delete; + Block(const Block &other) = default; + Block(Block &&other) = default; + Block& operator=(const Block &other) = delete; + Block& operator=(Block &&other) = delete; + Block(size_t index, const Magick::Image &img, size_t x, size_t y, size_t w, size_t h) : index(index), img(img), x(x), y(y), w(w), h(h) { } @@ -70,21 +76,29 @@ struct Packer size_t width, height; + Packer() = delete; + Packer(const Packer &other) = delete; + Packer(Packer &&other) = default; + Packer& operator=(const Packer &other) = delete; + Packer& operator=(Packer &&other) = default; + Packer(const std::vector &images, size_t width, size_t height); Magick::Image composite() const { Magick::Image img(Magick::Geometry(width, height), transparent()); - for(auto &it: placed) + for(const auto &block: placed) { - if(it.img.columns() == it.w && it.img.rows() == it.h) - img.composite(it.img, Magick::Geometry(0, 0, it.x, it.y), Magick::OverCompositeOp); + if(block.img.columns() == block.w && block.img.rows() == block.h) + img.composite(block.img, Magick::Geometry(0, 0, block.x, block.y), + Magick::OverCompositeOp); else { - Magick::Image copy = it.img; + Magick::Image copy = block.img; copy.rotate(-90); - img.composite(copy, Magick::Geometry(0, 0, it.x, it.y), Magick::OverCompositeOp); + img.composite(copy, Magick::Geometry(0, 0, block.x, block.y), + Magick::OverCompositeOp); } } @@ -102,10 +116,10 @@ struct Packer bool intersects_placed(size_t x, size_t y) const { - for(const auto &it: placed) + for(const auto &block: placed) { - if(x >= it.x && x < it.x + it.w - && y >= it.y && y < it.y + it.h) + if(x >= block.x && x < block.x + block.w + && y >= block.y && y < block.y + block.h) return true; } @@ -130,9 +144,8 @@ struct Packer void fixup() { - std::set::iterator it = free.begin(); - - while(it != free.end()) + auto it = std::begin(free); + while(it != std::end(free)) { if(intersects_placed(*it)) it = free.erase(it); @@ -145,11 +158,8 @@ struct Packer Packer::Packer(const std::vector &images, size_t width, size_t height) : placed(), next(), free(), width(width), height(height) { - for(std::vector::const_iterator it = images.begin(); - it != images.end(); ++it) - { - next.push_back(Block(std::stoul(it->attribute("index")), *it)); - } + for(const auto &img: images) + next.push_back(Block(std::stoul(img.attribute("index")), img)); free.insert(XY(0, 0)); } @@ -161,15 +171,15 @@ bool Packer::solve() Block block = next.back(); next.pop_back(); - std::set::iterator best = free.end(); - size_t best_score = 0; - bool best_flipped = false; - for(std::set::iterator it = free.begin(); it != free.end(); ++it) + XY best; + size_t best_score = 0; + bool best_flipped = false; + for(const auto &it: free) { - block.x = it->first; - block.y = it->second; + block.x = it.first; + block.y = it.second; - size_t score = calc_score(it->first, it->second, block.w, block.h); + size_t score = calc_score(it.first, it.second, block.w, block.h); if(score > best_score) { best = it; @@ -179,7 +189,7 @@ bool Packer::solve() if(block.w != block.h) { - size_t score = calc_score(it->first, it->second, block.h, block.w); + size_t score = calc_score(it.first, it.second, block.h, block.w); if(score > best_score) { best = it; @@ -192,8 +202,8 @@ bool Packer::solve() if(best_score == 0) return false; - block.x = best->first; - block.y = best->second; + block.x = best.first; + block.y = best.second; if(best_flipped) std::swap(block.w, block.h); @@ -250,31 +260,31 @@ size_t Packer::calc_score(size_t x, size_t y, size_t w, size_t h) if(y + h > height) return 0; - for(std::set::iterator it = placed.begin(); it != placed.end(); ++it) + for(const auto &block: placed) { - if(x+w < it->x) + if(x+w < block.x) break; - if(x < it->x + it->w - && x + w > it->x - && y < it->y + it->h - && y + h > it->y) + if(x < block.x + block.w + && x + w > block.x + && y < block.y + block.h + && y + h > block.y) return 0; - if(x == it->x + it->w - || x + w == it->x) + if(x == block.x + block.w + || x + w == block.x) { - size_t start = std::max(y, it->y); - size_t end = std::min(y + h, it->y + it->h); + size_t start = std::max(y, block.y); + size_t end = std::min(y + h, block.y + block.h); if(end > start) score += end - start; } - if(y == it->y + it->h - || y + h == it->y) + if(y == block.y + block.h + || y + h == block.y) { - size_t start = std::max(x, it->x); - size_t end = std::min(x + w, it->x + it->w); + size_t start = std::max(x, block.x); + size_t end = std::min(x + w, block.x + block.w); if(end > start) score += end - start; } @@ -326,18 +336,19 @@ Atlas Atlas::build(const std::vector &paths) { std::vector images; - for(size_t i = 0; i < paths.size(); ++i) + size_t i = 0; + for(const auto &path: paths) { - Magick::Image img(paths[i]); - img.attribute("index", std::to_string(i)); + Magick::Image img(path); + img.attribute("index", std::to_string(i++)); images.push_back(img); } - std::sort(images.begin(), images.end(), AreaSizeComparator()); + std::sort(std::begin(images), std::end(images), AreaSizeComparator()); size_t totalArea = 0; - for(std::vector::iterator it = images.begin(); it != images.end(); ++it) - totalArea += it->rows() * it->columns(); + for(const auto &img: images) + totalArea += img.rows() * img.columns(); std::vector packers; for(size_t h = calcPOT(std::min(images.back().columns(), images.back().rows())); h <= 1024; h *= 2) @@ -349,19 +360,19 @@ Atlas Atlas::build(const std::vector &paths) } } - std::sort(packers.begin(), packers.end(), AreaSizeComparator()); + std::sort(std::begin(packers), std::end(packers), AreaSizeComparator()); - for(size_t i = 0; i < packers.size(); ++i) + for(auto &packer: packers) { - if(packers[i].solve()) + if(packer.solve()) { Atlas atlas; - atlas.img = packers[i].composite(); - for(auto &it: packers[i].placed) - atlas.subs.push_back(it.subImage(atlas.img)); + atlas.img = packer.composite(); + for(auto &block: packer.placed) + atlas.subs.push_back(block.subImage(atlas.img)); - std::sort(atlas.subs.begin(), atlas.subs.end()); + std::sort(std::begin(atlas.subs), std::end(atlas.subs)); return atlas; } } diff --git a/source/magick_compat.cpp b/source/magick_compat.cpp index 0b7e633..b166052 100644 --- a/source/magick_compat.cpp +++ b/source/magick_compat.cpp @@ -32,11 +32,6 @@ PixelPacket::Reference::Reference(const Pixels *cache, Magick::Quantum *pixel) pixel(pixel) { } -PixelPacket::Reference::Reference(const PixelPacket::Reference &other) -: cache(other.cache), - pixel(other.pixel) -{ } - PixelPacket::Reference& PixelPacket::Reference::operator=(const PixelPacket::Reference &other) { if(&other != this) @@ -59,7 +54,6 @@ PixelPacket::Reference& PixelPacket::Reference::operator=(const PixelPacket::Ref return *this; } -#if __cplusplus >= 201103L PixelPacket::Reference& PixelPacket::Reference::operator=(PixelPacket::Reference &&other) { // copy pixel data @@ -78,7 +72,6 @@ PixelPacket::Reference& PixelPacket::Reference::operator=(PixelPacket::Reference return *this; } -#endif PixelPacket::Reference& PixelPacket::Reference::operator=(const Magick::Color &c) { @@ -116,6 +109,11 @@ PixelPacket::PixelPacket(const PixelPacket &other) pixels(other.pixels) { } +PixelPacket::PixelPacket(PixelPacket &&other) +: cache(other.cache), + pixels(other.pixels) +{ } + PixelPacket& PixelPacket::operator=(const PixelPacket &other) { if(&other != this) @@ -127,13 +125,6 @@ PixelPacket& PixelPacket::operator=(const PixelPacket &other) return *this; } -#if __cplusplus >= 201103L -PixelPacket::PixelPacket(PixelPacket &&other) -: cache(other.cache), - pixels(other.pixels) -{ -} - PixelPacket& PixelPacket::operator=(PixelPacket &&other) { cache = other.cache; @@ -141,7 +132,6 @@ PixelPacket& PixelPacket::operator=(PixelPacket &&other) return *this; } -#endif PixelPacket::Reference PixelPacket::operator[](size_t index) const { diff --git a/source/main.cpp b/source/main.cpp index f72a146..6412eba 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -23,32 +23,25 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include "atlas.h" -#include "compat.h" #include "compress.h" #include "encode.h" #include "magick_compat.h" #include "quantum.h" #include "rg_etc1.h" #include "subimage.h" -#include "tex3ds.h" -#include "thread.h" - -/** @brief Get number of elements in an array - * @param[in] x Array to count - * @returns Number of elements in array - */ -#define ARRAY_COUNT(x) (sizeof(x)/sizeof(x[0])) namespace { @@ -62,9 +55,20 @@ inline size_t potCeil(size_t x) if(x < 8) return 8; - return std::pow(2.0, std::ceil(std::log(x)/std::log(2))); + return std::pow(2.0, std::ceil(std::log2(x))); } +/** @brief Case-insensitive string comparator */ +template +struct CaseInsensitiveComparator +{ + bool operator()(const std::pair &lhs, + const char *rhs) const + { + return strcasecmp(lhs.first, rhs) < 0; + } +}; + /** @brief Process format */ enum ProcessFormat { @@ -87,24 +91,11 @@ enum ProcessFormat AUTO_ETC1, ///< ETC1/ETC1A4 encoding }; -/** @brief Process format string map */ -struct ProcessFormatString -{ - const char *str; ///< string - ProcessFormat fmt; ///< format - - /** @brief Comparator - * @param[in] str String to compare - */ - bool operator<(const char *str) const - { - // case-insensitive comparison - return strcasecmp(this->str, str) < 0; - } -}; +typedef std::pair ProcessFormatMap; +typedef CaseInsensitiveComparator ProcessFormatComparator; /** @brief Process format strings */ -ProcessFormatString output_format_strings[] = +const ProcessFormatMap output_format_strings[] = { { "a", A8, }, { "a4", A4, }, @@ -137,10 +128,6 @@ ProcessFormatString output_format_strings[] = { "rgba8888", RGBA8888, }, }; -/** @brief End of output_format_strings */ -ProcessFormatString *output_format_strings_end = - output_format_strings + ARRAY_COUNT(output_format_strings); - /** @brief Compression format */ enum CompressionFormat { @@ -152,24 +139,11 @@ enum CompressionFormat COMPRESSION_AUTO, ///< Choose best compression }; -/** @brief Compression format string map */ -struct CompressionFormatString -{ - const char *str; ///< string - CompressionFormat fmt; ///< format - - /** @brief Comparator - * @param[in] str String to compare - */ - bool operator<(const char *str) const - { - // case-insensitive comparison - return strcasecmp(this->str, str) < 0; - } -}; +typedef std::pair CompressionFormatMap; +typedef CaseInsensitiveComparator CompressionFormatComparator; /** @brief Compression format strings */ -CompressionFormatString compression_format_strings[] = +const CompressionFormatMap compression_format_strings[] = { { "auto", COMPRESSION_AUTO, }, { "huff", COMPRESSION_HUFF, }, @@ -181,28 +155,11 @@ CompressionFormatString compression_format_strings[] = { "rle", COMPRESSION_RLE, }, }; -/** @brief End of compression_format_strings */ -CompressionFormatString *compression_format_strings_end = - compression_format_strings + ARRAY_COUNT(compression_format_strings); - -/** @brief Filter type string format */ -struct FilterTypeString -{ - const char *str; ///< string - FilterType type; ///< filter type - - /** @brief Comparator - * @param[in] str String to compare - */ - bool operator<(const char *str) const - { - // case-insensitive comparison - return strcasecmp(this->str, str) < 0; - } -}; +typedef std::pair FilterTypeMap; +typedef CaseInsensitiveComparator FilterTypeComparator; /** @brief Filter type strings */ -FilterTypeString filter_type_strings[] = +const FilterTypeMap filter_type_strings[] = { { "bartlett", Magick::BartlettFilter, }, { "bessel", Magick::BesselFilter, }, @@ -236,10 +193,6 @@ FilterTypeString filter_type_strings[] = { "welsh", Magick::WelshFilter, }, }; -/** @brief End of filter_type_strings */ -FilterTypeString *filter_type_strings_end = - filter_type_strings + ARRAY_COUNT(filter_type_strings); - /** @brief Processing mode */ enum ProcessingMode { @@ -489,25 +442,25 @@ void swizzle(PixelPacket p, bool reverse) if(!reverse) { // swizzle each foursome - for(size_t i = 0; i < ARRAY_COUNT(table); ++i) + for(const auto &entry: table) { - Magick::Color tmp = p[table[i][0]]; - p[table[i][0]] = p[table[i][1]]; - p[table[i][1]] = p[table[i][2]]; - p[table[i][2]] = p[table[i][3]]; - p[table[i][3]] = tmp; + Magick::Color tmp = p[entry[0]]; + p[entry[0]] = p[entry[1]]; + p[entry[1]] = p[entry[2]]; + p[entry[2]] = p[entry[3]]; + p[entry[3]] = tmp; } } else { // unswizzle each foursome - for(size_t i = 0; i < ARRAY_COUNT(table); ++i) + for(const auto &entry: table) { - Magick::Color tmp = p[table[i][3]]; - p[table[i][3]] = p[table[i][2]]; - p[table[i][2]] = p[table[i][1]]; - p[table[i][1]] = p[table[i][0]]; - p[table[i][0]] = tmp; + Magick::Color tmp = p[entry[3]]; + p[entry[3]] = p[entry[2]]; + p[entry[2]] = p[entry[1]]; + p[entry[1]] = p[entry[0]]; + p[entry[0]] = tmp; } } @@ -587,40 +540,16 @@ std::string add_prefix(std::string path, std::string prefix) */ void finalize_process_format(std::vector &images) { - std::vector::iterator it = images.begin(); - // check each sub-image for transparency - while(it != images.end()) - { - if(process_format == AUTO_L8) - { - if(has_alpha<8>(*it)) - { - process_format = LA88; - break; - } - } - else if(process_format == AUTO_L4) - { - if(has_alpha<4>(*it)) - { - process_format = LA44; - break; - } - } - else if(process_format == AUTO_ETC1) - { - if(has_alpha<4>(*it)) - { - process_format = ETC1A4; - break; - } - } - else - break; - - ++it; - } + if(process_format == AUTO_L8 + && std::any_of(std::begin(images), std::end(images), has_alpha<8>)) + process_format = LA88; + else if(process_format == AUTO_L4 + && std::any_of(std::begin(images), std::end(images), has_alpha<4>)) + process_format = LA44; + else if(process_format == AUTO_ETC1 + && std::any_of(std::begin(images), std::end(images), has_alpha<4>)) + process_format = ETC1A4; // check if no transparency was found if(process_format == AUTO_L8) @@ -655,7 +584,7 @@ bool work_done = false; /** @brief Work thread * @param[in] param Unused */ -THREAD_RETURN_T work_thread(void *param) +void work_thread(void *param) { std::unique_lock mutex(work_mutex); while(true) @@ -666,10 +595,10 @@ THREAD_RETURN_T work_thread(void *param) // if there's no more work, quit if(work_done && work_queue.empty()) - THREAD_EXIT; + return; // get a work unit - encode::WorkUnit work = work_queue.front(); + encode::WorkUnit work = std::move(work_queue.front()); work_queue.pop(); mutex.unlock(); @@ -678,7 +607,7 @@ THREAD_RETURN_T work_thread(void *param) // put result on the result queue result_mutex.lock(); - result_queue.push_back(work); + result_queue.push_back(std::move(work)); std::push_heap(result_queue.begin(), result_queue.end()); result_cond.notify_one(); result_mutex.unlock(); @@ -856,7 +785,7 @@ void process_image(Magick::Image &img) // queue the work unit work_mutex.lock(); - work_queue.push(work); + work_queue.push(std::move(work)); work_cond.notify_one(); work_mutex.unlock(); } @@ -1009,10 +938,9 @@ void write_tex3ds_header(FILE *fp) encode::encode(num_mipmaps, buf); // encode subimage info - for(size_t i = 0; i < subimage_data.size(); ++i) + //for(size_t i = 0; i < subimage_data.size(); ++i) + for(const auto &sub: subimage_data) { - const SubImage &sub = subimage_data[i]; - uint16_t width; uint16_t height; @@ -1042,15 +970,18 @@ void write_tex3ds_header(FILE *fp) */ void* compress_none(const void *src, size_t len, size_t *outlen) { + uint8_t header[COMPRESSION_HEADER_SIZE]; + size_t header_size = compression_header(header, 0x00, len); + // pad to 4 bytes - size_t padded_len = ((len+COMPRESSION_HEADER_SIZE) + 3) & ~3; + size_t padded_len = ((len+header_size) + 3) & ~3; - uint8_t *output = static_cast(std::malloc(padded_len)); + uint8_t *output = static_cast(std::calloc(1, padded_len)); if(!output) return nullptr; - compression_header(output, 0x00, len); - std::memcpy(output+COMPRESSION_HEADER_SIZE, src, len); + std::memcpy(output, header, header_size); + std::memcpy(output+header_size, src, len); *outlen = padded_len; return output; @@ -1067,7 +998,7 @@ void* compress_auto(const void *src, size_t len, size_t *outlen) void *best_output = nullptr; size_t best_outlen = SIZE_MAX; - static void* (* const compress[])(const void*,size_t,size_t*) = + static void* (* const compress_funcs[])(const void*,size_t,size_t*) = { compress_none, lzss_encode, @@ -1076,10 +1007,10 @@ void* compress_auto(const void *src, size_t len, size_t *outlen) rle_encode, }; - for(size_t i = 0; i < ARRAY_COUNT(compress); ++i) + for(const auto &compress: compress_funcs) { size_t outlen; - void *output = compress[i](src, len, &outlen); + void *output = compress(src, len, &outlen); if(output && outlen < best_outlen) { @@ -1189,10 +1120,11 @@ void sanitize_identifier(std::string &id) if(!std::isalnum(id[0]) && id[0] != '_') id.insert(0, 1, '_'); - for(size_t i = 0; i < id.size(); ++i) + //for(size_t i = 0; i < id.size(); ++i) + for(auto &c: id) { - if(!std::isalnum(id[i]) && id[i] != '_') - id[i] = '_'; + if(!std::isalnum(c) && c != '_') + c = '_'; } } @@ -1217,15 +1149,16 @@ void write_header() header_path = ::basename(path.data()); } - std::string::size_type pos = header_path.rfind('.'); + auto pos = header_path.rfind('.'); if(pos != std::string::npos) header_path.resize(pos); sanitize_identifier(header_path); - for(size_t i = 0; i < subimage_data.size(); ++i) + size_t i = 0; + for(const auto &sub: subimage_data) { - std::string label = subimage_data[i].name; + std::string label = sub.name; pos = label.rfind('.'); if(pos != std::string::npos) @@ -1239,7 +1172,7 @@ void write_header() label.insert(0, 1, '_'); std::fprintf(fp, "#define %s%s %zu\n", - header_path.c_str(), label.c_str(), i); + header_path.c_str(), label.c_str(), i++); } // close output header @@ -1346,8 +1279,8 @@ void print_usage(const char *prog) " ETC1 when input has no alpha, otherwise ETC1A4\n\n" " Mipmap Filter Options:\n"); - for(size_t i = 0; i < ARRAY_COUNT(filter_type_strings); ++i) - std::printf(" -m %s\n", filter_type_strings[i].str); + for(const auto &type: filter_type_strings) + std::printf(" -m %s\n", type.first); std::printf("\n" " Compression Options:\n" @@ -1507,14 +1440,14 @@ ParseStatus parseOptions(const std::string &cwd, std::vector &args) case 'f': { // find matching output format - ProcessFormatString *it = - std::lower_bound(output_format_strings, - output_format_strings_end, - optarg); + auto format = std::lower_bound(std::begin(output_format_strings), + std::end(output_format_strings), + optarg, + ProcessFormatComparator()); // set output format option - if(it != output_format_strings_end && strcasecmp(it->str, optarg) == 0) - process_format = it->fmt; + if(format != std::end(output_format_strings)) + process_format = format->second; else { std::fprintf(stderr, "Invalid format option '%s'\n", optarg); @@ -1550,11 +1483,10 @@ ParseStatus parseOptions(const std::string &cwd, std::vector &args) std::vector options = readOptions(optionsFile); std::vector o; - for(std::vector::iterator it = options.begin(); - it != options.end(); ++it) + for(const auto &opt: options) { // getopt only take non-const :( - o.push_back(const_cast(it->c_str())); + o.push_back(const_cast(opt.c_str())); } ParseStatus status = parseOptions(new_cwd, o); @@ -1574,14 +1506,14 @@ ParseStatus parseOptions(const std::string &cwd, std::vector &args) case 'm': { // find matching mipmap filter type - FilterTypeString *it = - std::lower_bound(filter_type_strings, - filter_type_strings_end, - optarg); + auto filter = std::lower_bound(std::begin(filter_type_strings), + std::end(filter_type_strings), + optarg, + FilterTypeComparator()); // set mipmap filter type option - if(it != filter_type_strings_end && strcasecmp(it->str, optarg) == 0) - filter_type = it->type; + if(filter != std::end(filter_type_strings)) + filter_type = filter->second; else { std::fprintf(stderr, "Invalid mipmap filter type '%s'\n", optarg); @@ -1635,17 +1567,14 @@ ParseStatus parseOptions(const std::string &cwd, std::vector &args) case 'z': { // find matching compression format - CompressionFormatString *it = - std::lower_bound(compression_format_strings, - compression_format_strings_end, - optarg); + auto format = std::lower_bound(std::begin(compression_format_strings), + std::end(compression_format_strings), + optarg, + CompressionFormatComparator()); // set compression format option - if(it != compression_format_strings_end - && strcasecmp(it->str, optarg) == 0) - { - compression_format = it->fmt; - } + if(format != std::end(compression_format_strings)) + compression_format = format->second; else { std::fprintf(stderr, "Invalid compression option '%s'\n", optarg); @@ -1728,7 +1657,7 @@ int main(int argc, char *argv[]) std::vector images; if(process_mode == PROCESS_ATLAS) { - Atlas atlas = Atlas::build(input_files); + Atlas atlas(Atlas::build(input_files)); subimage_data.swap(atlas.subs); images = load_image(atlas.img); } diff --git a/source/rg_etc1.cpp b/source/rg_etc1.cpp index bc99e6b..bdc0703 100644 --- a/source/rg_etc1.cpp +++ b/source/rg_etc1.cpp @@ -14,13 +14,8 @@ #include #include #include -#include - -#if __cplusplus >= 201103L #include -#else -#include -#endif +#include #if defined(_WIN32) || defined(WIN32) #pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union