From 70e1ed3dde3f4ffea3bb05da3af6207c662f017a Mon Sep 17 00:00:00 2001 From: Michael Theall Date: Wed, 10 Nov 2021 14:39:54 -0600 Subject: [PATCH] Fix various --border problems --- configure.ac | 3 + include/atlas.h | 4 +- include/subimage.h | 61 +++++++++++++- m4/ax_append_link_flags.m4 | 44 ++++++++++ m4/ax_cxx_compile_stdcxx.m4 | 18 +++- m4/update.sh | 6 ++ source/atlas.cpp | 103 +++++++++++------------ source/tex3ds.cpp | 160 ++++++++++++++++++------------------ source/threadPool.cpp | 49 ++++++----- 9 files changed, 283 insertions(+), 165 deletions(-) create mode 100644 m4/ax_append_link_flags.m4 create mode 100755 m4/update.sh diff --git a/configure.ac b/configure.ac index b1df0ff..ce485a1 100644 --- a/configure.ac +++ b/configure.ac @@ -13,9 +13,12 @@ AC_PROG_CXX AC_LANG_PUSH([C++]) AX_APPEND_COMPILE_FLAGS([-Wall -pthread -flto -pipe]) +AX_APPEND_LINK_FLAGS([-flto]) AX_CXX_COMPILE_STDCXX_11(noext, mandatory) AC_LANG_POP() +AC_DEFINE(NDEBUG) + AC_CHECK_PROGS([DOXYGEN], [doxygen]) AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([Doxyfile])]) diff --git a/include/atlas.h b/include/atlas.h index 8504d9a..5fdbb80 100644 --- a/include/atlas.h +++ b/include/atlas.h @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------------ - * Copyright (c) 2017-2019 + * Copyright (c) 2017-2021 * Michael Theall (mtheall) * * This file is part of tex3ds. @@ -42,5 +42,5 @@ struct Atlas Atlas &operator= (const Atlas &other) = delete; Atlas &operator= (Atlas &&other) = delete; - static Atlas build (const std::vector &paths, bool trim, bool border); + static Atlas build (const std::vector &paths, bool trim, unsigned int border); }; diff --git a/include/subimage.h b/include/subimage.h index 5d07660..b4f20c5 100644 --- a/include/subimage.h +++ b/include/subimage.h @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------------ - * Copyright (c) 2017-2019 + * Copyright (c) 2017-2021 * Michael Theall (mtheall) * * This file is part of tex3ds. @@ -26,6 +26,8 @@ #include +#include +#include #include #include @@ -37,17 +39,30 @@ struct SubImage float top; ///< Top v-coordinate float right; ///< Right u-coordinate float bottom; ///< Bottom v-coordinate + bool rotated; ///< Whether sub-image is rotated SubImage (size_t index, const std::string &name, float left, float top, float right, - float bottom) - : index (index), left (left), top (top), right (right), bottom (bottom) + float bottom, + bool rotated) + : index (index), + name (name), + left (left), + top (top), + right (right), + bottom (bottom), + rotated (rotated) { + assert (rotated == (top < bottom)); + + if (name.empty ()) + return; + std::vector path (name.begin (), name.end ()); - path.push_back (0); + path.emplace_back (0); this->name = ::basename (path.data ()); } @@ -55,4 +70,42 @@ struct SubImage { return index < rhs.index; } + + void print (unsigned int width, unsigned int height) const + { + if (rotated) + std::printf ("%4zu \"%s\"\n" + "\ttl %5.1lf %5.1lf\n" + "\ttr %5.1lf %5.1lf\n" + "\tbl %5.1lf %5.1lf\n" + "\tbr %5.1lf %5.1lf\n" + "\trotated\n", + index, + name.c_str (), + top * width, + left * height, + top * width, + right * height, + bottom * width, + left * height, + bottom * width, + right * height); + + else + std::printf ("%4zu \"%s\"\n" + "\ttl %5.1lf %5.1lf\n" + "\ttr %5.1lf %5.1lf\n" + "\tbl %5.1lf %5.1lf\n" + "\tbr %5.1lf %5.1lf\n", + index, + name.c_str (), + left * width, + top * height, + right * width, + top * height, + left * width, + bottom * height, + right * width, + bottom * height); + } }; diff --git a/m4/ax_append_link_flags.m4 b/m4/ax_append_link_flags.m4 new file mode 100644 index 0000000..99b9fa5 --- /dev/null +++ b/m4/ax_append_link_flags.m4 @@ -0,0 +1,44 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the linker works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is +# used. During the check the flag is always added to the linker's flags. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG. +# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# 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 + +AC_DEFUN([AX_APPEND_LINK_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4]) +done +])dnl AX_APPEND_LINK_FLAGS diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 9e9eaed..9413da6 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -16,7 +16,7 @@ # 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. +# preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is @@ -34,13 +34,15 @@ # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak +# Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill # # 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 10 +#serial 12 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). @@ -61,6 +63,16 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl AC_LANG_PUSH([C++])dnl ac_success=no + m4_if([$2], [], [dnl + 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 @@ -189,11 +201,13 @@ namespace cxx11 struct Base { + virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { + virtual ~Derived() override {} virtual void f() override {} }; diff --git a/m4/update.sh b/m4/update.sh new file mode 100755 index 0000000..c3a0d96 --- /dev/null +++ b/m4/update.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for i in *.m4 +do + wget "http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/$i" -O $i +done diff --git a/source/atlas.cpp b/source/atlas.cpp index 28947a4..ad2af05 100644 --- a/source/atlas.cpp +++ b/source/atlas.cpp @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------------ - * Copyright (c) 2017-2019 + * Copyright (c) 2017-2021 * Michael Theall (mtheall) * * This file is part of tex3ds. @@ -49,7 +49,7 @@ struct Block Magick::Image img; XY xy; size_t x, y, w, h; - bool flipped; + bool rotated; Block () = delete; Block (const Block &other) = default; @@ -57,40 +57,36 @@ struct Block 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, - bool flipped) - : index (index), img (img), x (x), y (y), w (w), h (h), flipped (false) - { - } - - Block (size_t index, const Magick::Image &img) + Block (size_t index, const Magick::Image &img, unsigned int border) : index (index), img (img), x (0), y (0), - w (img.columns ()), - h (img.rows ()), - flipped (false) + w (img.columns () + border), + h (img.rows () + border), + rotated (false) { } - SubImage subImage (const Magick::Image &atlas) const + SubImage subImage (const Magick::Image &atlas, unsigned int border) const { - float left = static_cast (x) / atlas.columns (); - float top = 1.0f - (static_cast (y) / atlas.rows ()); - float right = static_cast (x + w) / atlas.columns (); - float bottom = 1.0f - (static_cast (y + h) / atlas.rows ()); + size_t width = atlas.columns () + border; + size_t height = atlas.rows () + border; - if (img.columns () == w && img.rows () == h) - return SubImage (index, img.fileName (), left, top, right, bottom); + float left = static_cast (x + border) / width; + float top = 1.0f - (static_cast (y + border) / height); + float right = static_cast (x + w) / width; + float bottom = 1.0f - (static_cast (y + h) / height); - // rotated - return SubImage (index, img.fileName (), bottom, left, top, right); + assert (left * width == x + border); + assert ((1.0f - top) * height == y + border); + assert (right * width == x + w); + assert ((1.0f - bottom) * height == y + h); + + if (rotated) + return SubImage (index, img.fileName (), bottom, left, top, right, true); + + return SubImage (index, img.fileName (), left, top, right, bottom, false); } bool operator< (const Block &other) const @@ -115,7 +111,7 @@ struct Packer std::set free; size_t width, height; - bool border; + unsigned int border; Packer () = delete; Packer (const Packer &other) = delete; @@ -123,7 +119,10 @@ struct Packer Packer &operator= (const Packer &other) = delete; Packer &operator= (Packer &&other) = default; - Packer (const std::vector &images, size_t width, size_t height, bool border); + Packer (const std::vector &images, + size_t width, + size_t height, + unsigned int border); Magick::Image composite () const { @@ -131,7 +130,7 @@ struct Packer for (const auto &block : placed) { - if (!block.flipped) + if (!block.rotated) img.composite ( block.img, Magick::Geometry (0, 0, block.x, block.y), Magick::OverCompositeOp); else @@ -195,11 +194,14 @@ struct Packer } }; -Packer::Packer (const std::vector &images, size_t width, size_t height, bool border) +Packer::Packer (const std::vector &images, + size_t width, + size_t height, + unsigned int border) : placed (), next (), free (), width (width), height (height), border (border) { for (const auto &img : images) - next.push_back (Block (std::stoul (img.attribute ("index")), img)); + next.emplace_back (std::stoul (img.attribute ("index")), img, border); free.insert (XY (0, 0)); } @@ -213,7 +215,7 @@ bool Packer::solve () XY best; size_t best_score = 0; - bool best_flipped = false; + bool best_rotated = false; for (const auto &it : free) { block.x = it.first; @@ -224,7 +226,7 @@ bool Packer::solve () { best = it; best_score = score; - best_flipped = false; + best_rotated = false; } if (block.w != block.h) @@ -234,7 +236,7 @@ bool Packer::solve () { best = it; best_score = score; - best_flipped = true; + best_rotated = true; } } } @@ -244,16 +246,10 @@ bool Packer::solve () block.x = best.first; block.y = best.second; - if (best_flipped) + if (best_rotated) { std::swap (block.w, block.h); - block.flipped = true; - } - - if (border) - { - block.w++; - block.h++; + block.rotated = true; } pack (block.x, block.y, block.w, block.h); @@ -375,11 +371,10 @@ struct AreaSizeComparator }; } -Atlas Atlas::build (const std::vector &paths, bool trim, bool border) +Atlas Atlas::build (const std::vector &paths, bool trim, unsigned int border) { std::vector images; - size_t i = 0; for (const auto &path : paths) { Magick::Image img (path); @@ -390,15 +385,15 @@ Atlas Atlas::build (const std::vector &paths, bool trim, bool borde img.page (Magick::Geometry (img.columns (), img.rows ())); } - img.attribute ("index", std::to_string (i++)); - images.push_back (img); + img.attribute ("index", std::to_string (images.size ())); + images.emplace_back (std::move (img)); } std::sort (std::begin (images), std::end (images), AreaSizeComparator ()); size_t totalArea = 0; for (const auto &img : images) - totalArea += img.rows () * img.columns (); + totalArea += (img.rows () + border) * (img.columns () + border); std::vector packers; for (size_t h = calcPOT (std::min (images.back ().columns (), images.back ().rows ())); @@ -409,15 +404,11 @@ Atlas Atlas::build (const std::vector &paths, bool trim, bool borde w <= 1024; w *= 2) { - size_t allowed_height = h; - size_t allowed_width = w; - if (border) - { - allowed_height -= 2; - allowed_width -= 2; - } + const size_t allowed_height = h - border; + const size_t allowed_width = w - border; + if (allowed_width * allowed_height >= totalArea) - packers.push_back (Packer (images, allowed_width, allowed_height, border)); + packers.emplace_back (images, allowed_width, allowed_height, border); } } @@ -431,7 +422,7 @@ Atlas Atlas::build (const std::vector &paths, bool trim, bool borde atlas.img = packer.composite (); for (auto &block : packer.placed) - atlas.subs.push_back (block.subImage (atlas.img)); + atlas.subs.emplace_back (block.subImage (atlas.img, border)); std::sort (std::begin (atlas.subs), std::end (atlas.subs)); return atlas; diff --git a/source/tex3ds.cpp b/source/tex3ds.cpp index 11438d2..b60d82a 100644 --- a/source/tex3ds.cpp +++ b/source/tex3ds.cpp @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------------ - * Copyright (c) 2017-2019 + * Copyright (c) 2017-2021 * Michael Theall (mtheall) * * This file is part of tex3ds. @@ -265,7 +265,7 @@ size_t max_image_height = 1024; size_t max_image_width = 1024; /** @brief Add a border between atlased images */ -bool border = false; +unsigned int border = 0; /** @brief Load image * @param[in] img Input image @@ -358,37 +358,47 @@ std::vector load_image (Magick::Image &img) std::vector result; if (process_mode == PROCESS_NORMAL || process_mode == PROCESS_ATLAS) { - // expand canvas if necessary - // will catch all border cases, as the max width there is never a Po2 - if (img.columns () != potCeil (img.columns ()) || img.rows () != potCeil (img.rows ())) + // apply bottom and right border (top/left already applied for atlas) + output_width = potCeil (img.columns () + border); + output_height = potCeil (img.rows () + border); + + if (process_mode == PROCESS_NORMAL) { - Magick::Image copy = img; + // apply top and left border + output_width += border; + output_height += border; + } - img = Magick::Image ( - Magick::Geometry (potCeil (img.columns ()), potCeil (img.rows ())), transparent ()); + if (img.columns () != output_width || img.rows () != output_height) + { + // expand canvas + Magick::Image copy = img; - const size_t padding = border ? 1 : 0; + img = Magick::Image (Magick::Geometry (output_width, output_height), transparent ()); - img.composite ( - copy, Magick::Geometry (0, 0, padding, padding), Magick::OverCompositeOp); + img.composite (copy, Magick::Geometry (0, 0, border, border), Magick::OverCompositeOp); - subimage_data.push_back (SubImage (0, - "", - static_cast (padding) / img.columns (), - 1.0f - static_cast (padding) / img.columns (), - static_cast (padding + copy.columns ()) / img.columns (), - 1.0f - static_cast (padding + copy.rows ()) / img.rows ())); + if (process_mode == PROCESS_NORMAL) + { + assert (subimage_data.empty ()); + subimage_data.emplace_back (0, + "", + static_cast (border) / img.columns (), + 1.0f - static_cast (border) / img.rows (), + static_cast (border + copy.columns ()) / img.columns (), + 1.0f - static_cast (border + copy.rows ()) / img.rows (), + false); + } } - else if (process_mode != PROCESS_ATLAS) + else if (process_mode == PROCESS_NORMAL) { - subimage_data.push_back (SubImage (0, "", 0.0f, 1.0f, 1.0f, 0.0f)); + // a perfect fit + assert (subimage_data.empty ()); + subimage_data.emplace_back (0, "", 0.0f, 1.0f, 1.0f, 0.0f, false); } - output_width = img.columns (); - output_height = img.rows (); - // push the source image - result.push_back (img); + result.emplace_back (std::move (img)); } else { @@ -405,7 +415,7 @@ std::vector load_image (Magick::Image &img) copy.flop (); // flip horizontal copy.flip (); // flip vertical copy.comment ("px_"); - result.push_back (copy); + result.emplace_back (copy); // -x copy = img; @@ -414,7 +424,7 @@ std::vector load_image (Magick::Image &img) copy.flop (); // flip horizontal copy.flip (); // flip vertical copy.comment ("nx_"); - result.push_back (copy); + result.emplace_back (copy); // +y copy = img; @@ -422,7 +432,7 @@ std::vector load_image (Magick::Image &img) if (process_mode == PROCESS_CUBEMAP) copy.flip (); // flip vertical copy.comment ("py_"); - result.push_back (copy); + result.emplace_back (copy); // -y copy = img; @@ -430,7 +440,7 @@ std::vector load_image (Magick::Image &img) if (process_mode == PROCESS_CUBEMAP) copy.flip (); // flip vertical copy.comment ("ny_"); - result.push_back (copy); + result.emplace_back (copy); // +z copy = img; @@ -443,7 +453,7 @@ std::vector load_image (Magick::Image &img) } copy.flip (); // flip vertical copy.comment ("pz_"); - result.push_back (copy); + result.emplace_back (copy); // -z copy = img; @@ -456,7 +466,7 @@ std::vector load_image (Magick::Image &img) } copy.flip (); // flip vertical copy.comment ("nz_"); - result.push_back (copy); + result.emplace_back (copy); } return result; @@ -555,12 +565,13 @@ bool work_done = false; */ void work_thread (void *param) { - std::unique_lock mutex (work_mutex); while (true) { + std::unique_lock lock (work_mutex); + // wait for work while (!work_done && work_queue.empty ()) - work_cond.wait (mutex); + work_cond.wait (lock); // if there's no more work, quit if (work_done && work_queue.empty ()) @@ -569,19 +580,19 @@ void work_thread (void *param) // get a work unit encode::WorkUnit work = std::move (work_queue.front ()); work_queue.pop (); - mutex.unlock (); + lock.unlock (); // process the work unit work.process (work); - // put result on the result queue - result_mutex.lock (); - result_queue.push_back (std::move (work)); - std::push_heap (result_queue.begin (), result_queue.end ()); - result_cond.notify_one (); - result_mutex.unlock (); + { + // put result on the result queue + std::lock_guard lock (result_mutex); + result_queue.emplace_back (std::move (work)); + std::push_heap (result_queue.begin (), result_queue.end ()); + } - mutex.lock (); + result_cond.notify_one (); } } @@ -707,11 +718,9 @@ void process_image (Magick::Image &img) // create worker threads std::vector workers; - work_mutex.lock (); work_done = false; - work_mutex.unlock (); for (size_t i = 0; i < std::thread::hardware_concurrency (); ++i) - workers.push_back (std::thread (work_thread, nullptr)); + workers.emplace_back (work_thread, nullptr); size_t voff = 0; // vertical offset for mipmap preview size_t hoff = 0; // horizontal offset for mipmap preview @@ -750,21 +759,25 @@ void process_image (Magick::Image &img) !preview_path.empty (), process); - // queue the work unit - work_mutex.lock (); - work_queue.push (std::move (work)); + { + // queue the work unit + std::lock_guard lock (work_mutex); + work_queue.push (std::move (work)); + } + work_cond.notify_one (); - work_mutex.unlock (); } } if (img_queue.empty ()) { - // no more work is coming - work_mutex.lock (); - work_done = true; + { + // no more work is coming + std::lock_guard lock (work_mutex); + work_done = true; + } + work_cond.notify_all (); - work_mutex.unlock (); } // gather results @@ -773,9 +786,7 @@ void process_image (Magick::Image &img) // wait for the next result std::unique_lock mutex (result_mutex); while (result_queue.empty () || result_queue.front ().sequence != num_result) - { result_cond.wait (mutex); - } // get the result's output buffer encode::Buffer result; @@ -786,8 +797,6 @@ void process_image (Magick::Image &img) // append the result's output buffer image_data.insert (image_data.end (), result.begin (), result.end ()); - - mutex.lock (); } // synchronize the pixel cache @@ -902,14 +911,16 @@ 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 (const auto &sub : subimage_data) { uint16_t width; uint16_t height; - // check if subimage is rotated - if (sub.top < sub.bottom) +#ifndef NDEBUG + sub.print (output_width, output_height); +#endif + + if (sub.rotated) { height = (sub.bottom - sub.top) * output_width; width = (sub.right - sub.left) * output_height; @@ -1117,7 +1128,7 @@ void write_header () { std::vector path (header_path.begin (), header_path.end ()); - path.push_back (0); + path.emplace_back (0); header_path = ::basename (path.data ()); } @@ -1130,6 +1141,12 @@ void write_header () size_t i = 0; for (const auto &sub : subimage_data) { + if (sub.name.empty ()) + { + std::fprintf (fp, "#define %s_idx %zu\n", header_path.c_str (), i++); + continue; + } + std::string label = sub.name; pos = label.rfind ('.'); @@ -1400,8 +1417,7 @@ std::vector readOptions (const std::string &path) else if (std::isspace (c)) { if (!opt.empty ()) - options.push_back (opt); - opt.clear (); + options.emplace_back (std::move (opt)); } else opt.push_back (c); @@ -1413,7 +1429,7 @@ std::vector readOptions (const std::string &path) throw std::runtime_error ("Reached end of options file at partially quoted string"); if (!opt.empty ()) - options.push_back (opt); + options.emplace_back (opt); return options; } @@ -1442,8 +1458,8 @@ ParseStatus parseOptions (std::vector &args) case 'b': // border - max_image_height = max_image_width = 1022; - border = true; + max_image_height = max_image_width = 1023; + border = 1; break; case 'c': @@ -1493,7 +1509,7 @@ ParseStatus parseOptions (std::vector &args) std::string new_cwd; { std::vector path (optionsFile.begin (), optionsFile.end ()); - path.push_back (0); + path.emplace_back (0); new_cwd = ::dirname (path.data ()); } @@ -1506,7 +1522,7 @@ ParseStatus parseOptions (std::vector &args) for (const auto &opt : options) { // getopt only take non-const :( - o.push_back (const_cast (opt.c_str ())); + o.emplace_back (const_cast (opt.c_str ())); } include_stack.emplace_back (std::move (new_cwd)); @@ -1682,20 +1698,6 @@ int main (int argc, char *argv[]) Atlas atlas (Atlas::build (input_files, trim, border)); subimage_data.swap (atlas.subs); - if (border) - { - size_t pot_width = potCeil(atlas.img.columns()); - size_t pot_height = potCeil(atlas.img.rows()); - // shift all subimages by 1,1 and use Po2 size for divisor - for (auto &sub : subimage_data) - { - sub.left = (sub.left * atlas.img.columns() + 1) / pot_width; - sub.right = (sub.right * atlas.img.columns() + 1) / pot_width; - sub.bottom = (sub.bottom * atlas.img.rows() + 1) / pot_height; - sub.top = (sub.top * atlas.img.rows() + 1) / pot_height; - } - } - images = load_image (atlas.img); } else if (input_files.size () > 1) diff --git a/source/threadPool.cpp b/source/threadPool.cpp index cb4e361..d6db147 100644 --- a/source/threadPool.cpp +++ b/source/threadPool.cpp @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------------ - * Copyright (c) 2019 + * Copyright (c) 2019-2021 * Michael Theall (mtheall) * * This file is part of tex3ds. @@ -31,7 +31,7 @@ namespace { std::vector threads; -std::queue> jobs; +std::queue> jobs; std::mutex mutex; std::condition_variable newJob; std::condition_variable jobTaken; @@ -39,24 +39,25 @@ bool quit = false; void worker () { - std::unique_lock lock (mutex); - - while (!quit) + while (true) { - while (!quit && jobs.empty ()) - newJob.wait (lock); + std::function job; + + { + std::unique_lock lock (mutex); + while (!quit && jobs.empty ()) + newJob.wait (lock); + + if (quit) + return; - if (quit) - return; + job = std::move (jobs.front ()); + jobs.pop (); + } - auto job = std::move (jobs.front ()); - jobs.pop (); jobTaken.notify_one (); - lock.unlock (); job (); - - lock.lock (); } }; @@ -74,11 +75,12 @@ ThreadPool ThreadPool::pool; ThreadPool::~ThreadPool () { { - std::unique_lock lock (mutex); + std::lock_guard lock (mutex); quit = true; - newJob.notify_all (); } + newJob.notify_all (); + for (auto &thread : threads) thread.join (); } @@ -87,16 +89,19 @@ ThreadPool::ThreadPool () { } -void ThreadPool::pushJob (std::function &&job) +void ThreadPool::pushJob (std::function &&job) { std::call_once (initOnce, init); - std::unique_lock lock (mutex); + { + std::unique_lock lock (mutex); - // block while there's many outstanding jobs - while (jobs.size () > threads.size () * 2) - jobTaken.wait (lock); + // block while there's many outstanding jobs + while (jobs.size () > threads.size () * 2) + jobTaken.wait (lock); + + jobs.emplace (std::move (job)); + } - jobs.emplace (std::move (job)); newJob.notify_one (); }