[
  {
    "path": ".clang-format",
    "content": "---\nBasedOnStyle: LLVM\nAccessModifierOffset: '-4'\nAlwaysBreakTemplateDeclarations: 'true'\nBreakBeforeBraces: Custom\nBraceWrapping:\n  AfterClass:      true\n  AfterControlStatement: true\n  AfterEnum:       false\n  AfterFunction:   true\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     true\n  AfterUnion:      false\n  BeforeCatch:     false\n  BeforeElse:      false\n  IndentBraces:    false\nColumnLimit: '110'\nCpp11BracedListStyle: 'true'\nPointerAlignment: Left\nIndentWidth: '4'\nLanguage: Cpp\nNamespaceIndentation: None\nSortIncludes: false\nStandard: Cpp11\nUseTab: Never\n# http://clang.llvm.org/docs/ClangFormatStyleOptions.html\n\n...\n"
  },
  {
    "path": ".gitignore",
    "content": "# Ignore (optional) configuration files with user-specific paths:\ninitial_cache.cmake\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"external/eos\"]\n\tpath = external/eos\n\turl = https://github.com/patrikhuber/eos.git\n[submodule \"external/libigl\"]\n\tpath = external/libigl\n\turl = https://github.com/libigl/libigl.git\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.1.3)\nproject(eos-model-viewer)\nset(eos-model-viewer_VERSION 0.2.0.alpha)\n\nset_property(GLOBAL PROPERTY USE_FOLDERS ON)\n\n# This sets the C++ standard to c++14 and required for all the following targets that we define.\n# It has no effect on MSVC though - we thus define more specific requirements for each executable target respectively.\n# Also it will not apply to the eos library target, since it is an INTERFACE_LIBRARY, and these properties do not apply to interface libraries.\nset(CMAKE_CXX_STANDARD 14)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF) # This makes CMake use -std=c++11 instead of -std=gnu++11\n# This list is likely not complete, but it should be sufficient to error out on old compilers that we cannot build on:\nset(eos-model-viewer_CXX_COMPILE_FEATURES cxx_defaulted_functions cxx_generalized_initializers cxx_generic_lambdas cxx_lambdas cxx_nonstatic_member_init cxx_range_for cxx_right_angle_brackets cxx_strong_enums)\n\n# Build a CPack driven installer package:\ninclude(InstallRequiredSystemLibraries) # This module will include any runtime libraries that are needed by the project for the current platform\nset(CPACK_RESOURCE_FILE_LICENSE \"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE\")\nset(CPACK_PACKAGE_VERSION_MAJOR \"${eos-model-viewer_VERSION_MAJOR}\")\nset(CPACK_PACKAGE_VERSION_MINOR \"${eos-model-viewer_VERSION_MINOR}\")\nset(CPACK_PACKAGE_VERSION_PATCH \"${eos-model-viewer_VERSION_PATCH}\")\ninclude(CPack)\n\n# Find dependencies:\nfind_package(OpenCV REQUIRED core)\n#check installed version in order to include the correct OpenCV libraries\n#version variable is defined from project root's CMakeLists\nif(\"${OpenCV_VERSION_MAJOR}$\" EQUAL 2)\n  message(STATUS \"OpenCV 2.x detected\")\n  find_package(OpenCV 2.4.3 REQUIRED core)\nelseif(\"${OpenCV_VERSION_MAJOR}$\" EQUAL 3)\n  message(STATUS \"OpenCV 3.x detected - including imgcodecs for compatibility\")\n  find_package(OpenCV 3 REQUIRED core)\nendif()\n# This allows us to compile in RelWithDebInfo. It'll use the Release-version of OpenCV:\nset_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)\n\n# Include eos. Todo: We should really rather use an import target approach rather than running add_subdirectory here.\nset(eos_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/external/eos\")\nset(EOS_BUILD_EXAMPLES OFF)\nadd_subdirectory(${eos_DIR})\n\n######### The following will find libigl, and build everything that's required for the viewer - e.g. GLFW:\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)\nset(LIBIGL_INCLUDE_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/external/libigl/include\")\n\noption(LIBIGL_USE_STATIC_LIBRARY \"Use libigl as static library\" OFF)\noption(LIBIGL_WITH_ANTTWEAKBAR       \"Use AntTweakBar\"    OFF)\noption(LIBIGL_WITH_CGAL              \"Use CGAL\"           OFF)\noption(LIBIGL_WITH_COMISO            \"Use CoMiso\"         OFF)\noption(LIBIGL_WITH_CORK              \"Use Cork\"           OFF)\noption(LIBIGL_WITH_EMBREE            \"Use Embree\"         OFF)\noption(LIBIGL_WITH_LIM               \"Use LIM\"            OFF)\noption(LIBIGL_WITH_MATLAB            \"Use Matlab\"         OFF)\noption(LIBIGL_WITH_MOSEK             \"Use MOSEK\"          OFF)\noption(LIBIGL_WITH_OPENGL            \"Use OpenGL\"         ON)\noption(LIBIGL_WITH_OPENGL_GLFW       \"Use GLFW\"           ON)\noption(LIBIGL_WITH_OPENGL_GLFW_IMGUI \"Use ImGui\"          ON)\noption(LIBIGL_WITH_PNG               \"Use PNG\"            OFF)\noption(LIBIGL_WITH_PYTHON            \"Use Python\"         OFF)\noption(LIBIGL_WITH_TETGEN            \"Use Tetgen\"         OFF)\noption(LIBIGL_WITH_TRIANGLE          \"Use Triangle\"       OFF)\noption(LIBIGL_WITH_VIEWER            \"Use OpenGL viewer\"  ON)\noption(LIBIGL_WITH_XML               \"Use XML\"            OFF)\n\nfind_package(LIBIGL REQUIRED)\n######### libigl should be set up by now.\n\n# Set up the eos-model-viewer target:\nadd_executable(eos-model-viewer eos-model-viewer.cpp cxxopts.hpp)\n#target_include_directories(eos-model-viewer PRIVATE ${LIBIGL_INCLUDE_DIRS})\n#add_definitions(${LIBIGL_DEFINITIONS})\ntarget_compile_features(eos-model-viewer PRIVATE ${eos-model-viewer_CXX_COMPILE_FEATURES})\ntarget_link_libraries(eos-model-viewer eos ${OpenCV_LIBS} igl::core igl::opengl_glfw igl::opengl_glfw_imgui)\ntarget_link_libraries(eos-model-viewer \"$<$<CXX_COMPILER_ID:GNU>:-pthread>$<$<CXX_COMPILER_ID:Clang>:-pthreads>\")\n\n# Install the binary:\ninstall(TARGETS eos-model-viewer DESTINATION bin)\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# eos-model-viewer\n3D model viewer for the eos Morphable Model library\n\nThis is a viewer that displays Morphable Models from the eos Morphable Model library ([github.com/patrikhuber/eos](https://github.com/patrikhuber/eos)).\nIt allows to play around with the shape and colour PCA models as well as the blendshapes.\n\n![Screenshot of the viewer](https://github.com/patrikhuber/eos-model-viewer/blob/master/doc/viewer_screenshot.png)\n\n\n## Build & installation\n\nIt uses libigl's 3D viewer.\n\n**Note:** The viewer works well, but the code is not very polished and will crash if you do unexpected things (e.g. cancel the loading dialogues).\nThe CMake scripts are in serious alpha-stage - You are on your own compiling it!\n\nMake sure to clone the repository with `--recursive`, or, if already cloned, run `git submodule update --init --recursive`.\n\n## Running the viewer\n\nThe viewer can be given a `-m` and `-b` options to open a specific model and blendshapes. If you don't specify these options, a GUI file dialog will pop up, asking you to first select the model, and then the blendshapes file.\n"
  },
  {
    "path": "cmake/FindLIBIGL.cmake",
    "content": "# - Try to find the LIBIGL library\n# Once done this will define\n#\n#  LIBIGL_FOUND - system has LIBIGL\n#  LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory\nif(LIBIGL_FOUND)\n    return()\nendif()\n\nfind_path(LIBIGL_INCLUDE_DIR igl/readOBJ.h\n    HINTS\n        ENV LIBIGL\n        ENV LIBIGLROOT\n        ENV LIBIGL_ROOT\n        ENV LIBIGL_DIR\n    PATHS\n        ${CMAKE_SOURCE_DIR}/../..\n        ${CMAKE_SOURCE_DIR}/..\n        ${CMAKE_SOURCE_DIR}\n        ${CMAKE_SOURCE_DIR}/libigl\n        ${CMAKE_SOURCE_DIR}/../libigl\n        ${CMAKE_SOURCE_DIR}/../../libigl\n        /usr\n        /usr/local\n        /usr/local/igl/libigl\n    PATH_SUFFIXES include\n)\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(LIBIGL\n    \"\\nlibigl not found --- You can download it using:\\n\\tgit clone --recursive https://github.com/libigl/libigl.git ${CMAKE_SOURCE_DIR}/../libigl\"\n    LIBIGL_INCLUDE_DIR)\nmark_as_advanced(LIBIGL_INCLUDE_DIR)\n\nlist(APPEND CMAKE_MODULE_PATH \"${LIBIGL_INCLUDE_DIR}/../cmake\")\ninclude(libigl)\n"
  },
  {
    "path": "cxxopts.hpp",
    "content": "/*\n\nCopyright (c) 2014, 2015, 2016, 2017 Jarryd Beck\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n*/\n\n#ifndef CXXOPTS_HPP_INCLUDED\n#define CXXOPTS_HPP_INCLUDED\n\n#include <cstring>\n#include <cctype>\n#include <exception>\n#include <iostream>\n#include <map>\n#include <memory>\n#include <regex>\n#include <sstream>\n#include <string>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n\n#ifdef __cpp_lib_optional\n#include <optional>\n#define CXXOPTS_HAS_OPTIONAL\n#endif\n\nnamespace cxxopts\n{\n  static constexpr struct {\n    uint8_t major, minor, patch;\n  } version = {2, 1, 0};\n}\n\n//when we ask cxxopts to use Unicode, help strings are processed using ICU,\n//which results in the correct lengths being computed for strings when they\n//are formatted for the help output\n//it is necessary to make sure that <unicode/unistr.h> can be found by the\n//compiler, and that icu-uc is linked in to the binary.\n\n#ifdef CXXOPTS_USE_UNICODE\n#include <unicode/unistr.h>\n\nnamespace cxxopts\n{\n  typedef icu::UnicodeString String;\n\n  inline\n  String\n  toLocalString(std::string s)\n  {\n    return icu::UnicodeString::fromUTF8(std::move(s));\n  }\n\n  class UnicodeStringIterator : public\n    std::iterator<std::forward_iterator_tag, int32_t>\n  {\n    public:\n\n    UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)\n    : s(string)\n    , i(pos)\n    {\n    }\n\n    value_type\n    operator*() const\n    {\n      return s->char32At(i);\n    }\n\n    bool\n    operator==(const UnicodeStringIterator& rhs) const\n    {\n      return s == rhs.s && i == rhs.i;\n    }\n\n    bool\n    operator!=(const UnicodeStringIterator& rhs) const\n    {\n      return !(*this == rhs);\n    }\n\n    UnicodeStringIterator&\n    operator++()\n    {\n      ++i;\n      return *this;\n    }\n\n    UnicodeStringIterator\n    operator+(int32_t v)\n    {\n      return UnicodeStringIterator(s, i + v);\n    }\n\n    private:\n    const icu::UnicodeString* s;\n    int32_t i;\n  };\n\n  inline\n  String&\n  stringAppend(String&s, String a)\n  {\n    return s.append(std::move(a));\n  }\n\n  inline\n  String&\n  stringAppend(String& s, int n, UChar32 c)\n  {\n    for (int i = 0; i != n; ++i)\n    {\n      s.append(c);\n    }\n\n    return s;\n  }\n\n  template <typename Iterator>\n  String&\n  stringAppend(String& s, Iterator begin, Iterator end)\n  {\n    while (begin != end)\n    {\n      s.append(*begin);\n      ++begin;\n    }\n\n    return s;\n  }\n\n  inline\n  size_t\n  stringLength(const String& s)\n  {\n    return s.length();\n  }\n\n  inline\n  std::string\n  toUTF8String(const String& s)\n  {\n    std::string result;\n    s.toUTF8String(result);\n\n    return result;\n  }\n\n  inline\n  bool\n  empty(const String& s)\n  {\n    return s.isEmpty();\n  }\n}\n\nnamespace std\n{\n  inline\n  cxxopts::UnicodeStringIterator\n  begin(const icu::UnicodeString& s)\n  {\n    return cxxopts::UnicodeStringIterator(&s, 0);\n  }\n\n  inline\n  cxxopts::UnicodeStringIterator\n  end(const icu::UnicodeString& s)\n  {\n    return cxxopts::UnicodeStringIterator(&s, s.length());\n  }\n}\n\n//ifdef CXXOPTS_USE_UNICODE\n#else\n\nnamespace cxxopts\n{\n  typedef std::string String;\n\n  template <typename T>\n  T\n  toLocalString(T&& t)\n  {\n    return t;\n  }\n\n  inline\n  size_t\n  stringLength(const String& s)\n  {\n    return s.length();\n  }\n\n  inline\n  String&\n  stringAppend(String&s, String a)\n  {\n    return s.append(std::move(a));\n  }\n\n  inline\n  String&\n  stringAppend(String& s, size_t n, char c)\n  {\n    return s.append(n, c);\n  }\n\n  template <typename Iterator>\n  String&\n  stringAppend(String& s, Iterator begin, Iterator end)\n  {\n    return s.append(begin, end);\n  }\n\n  template <typename T>\n  std::string\n  toUTF8String(T&& t)\n  {\n    return std::forward<T>(t);\n  }\n\n  inline\n  bool\n  empty(const std::string& s)\n  {\n    return s.empty();\n  }\n}\n\n//ifdef CXXOPTS_USE_UNICODE\n#endif\n\nnamespace cxxopts\n{\n  namespace\n  {\n#ifdef _WIN32\n    const std::string LQUOTE(\"\\'\");\n    const std::string RQUOTE(\"\\'\");\n#else\n    const std::string LQUOTE(\"‘\");\n    const std::string RQUOTE(\"’\");\n#endif\n  }\n\n  class Value : public std::enable_shared_from_this<Value>\n  {\n    public:\n\n    virtual ~Value() = default;\n\n    virtual\n    std::shared_ptr<Value>\n    clone() const = 0;\n\n    virtual void\n    parse(const std::string& text) const = 0;\n\n    virtual void\n    parse() const = 0;\n\n    virtual bool\n    has_default() const = 0;\n\n    virtual bool\n    is_container() const = 0;\n\n    virtual bool\n    has_implicit() const = 0;\n\n    virtual std::string\n    get_default_value() const = 0;\n\n    virtual std::string\n    get_implicit_value() const = 0;\n\n    virtual std::shared_ptr<Value>\n    default_value(const std::string& value) = 0;\n\n    virtual std::shared_ptr<Value>\n    implicit_value(const std::string& value) = 0;\n\n    virtual bool\n    is_boolean() const = 0;\n  };\n\n  class OptionException : public std::exception\n  {\n    public:\n    OptionException(const std::string& message)\n    : m_message(message)\n    {\n    }\n\n    virtual const char*\n    what() const noexcept\n    {\n      return m_message.c_str();\n    }\n\n    private:\n    std::string m_message;\n  };\n\n  class OptionSpecException : public OptionException\n  {\n    public:\n\n    OptionSpecException(const std::string& message)\n    : OptionException(message)\n    {\n    }\n  };\n\n  class OptionParseException : public OptionException\n  {\n    public:\n    OptionParseException(const std::string& message)\n    : OptionException(message)\n    {\n    }\n  };\n\n  class option_exists_error : public OptionSpecException\n  {\n    public:\n    option_exists_error(const std::string& option)\n    : OptionSpecException(u8\"Option \" + LQUOTE + option + RQUOTE + u8\" already exists\")\n    {\n    }\n  };\n\n  class invalid_option_format_error : public OptionSpecException\n  {\n    public:\n    invalid_option_format_error(const std::string& format)\n    : OptionSpecException(u8\"Invalid option format \" + LQUOTE + format + RQUOTE)\n    {\n    }\n  };\n\n  class option_not_exists_exception : public OptionParseException\n  {\n    public:\n    option_not_exists_exception(const std::string& option)\n    : OptionParseException(u8\"Option \" + LQUOTE + option + RQUOTE + u8\" does not exist\")\n    {\n    }\n  };\n\n  class missing_argument_exception : public OptionParseException\n  {\n    public:\n    missing_argument_exception(const std::string& option)\n    : OptionParseException(\n        u8\"Option \" + LQUOTE + option + RQUOTE + u8\" is missing an argument\"\n      )\n    {\n    }\n  };\n\n  class option_requires_argument_exception : public OptionParseException\n  {\n    public:\n    option_requires_argument_exception(const std::string& option)\n    : OptionParseException(\n        u8\"Option \" + LQUOTE + option + RQUOTE + u8\" requires an argument\"\n      )\n    {\n    }\n  };\n\n  class option_not_has_argument_exception : public OptionParseException\n  {\n    public:\n    option_not_has_argument_exception\n    (\n      const std::string& option,\n      const std::string& arg\n    )\n    : OptionParseException(\n        u8\"Option \" + LQUOTE + option + RQUOTE +\n        u8\" does not take an argument, but argument \" +\n        LQUOTE + arg + RQUOTE + \" given\"\n      )\n    {\n    }\n  };\n\n  class option_not_present_exception : public OptionParseException\n  {\n    public:\n    option_not_present_exception(const std::string& option)\n    : OptionParseException(u8\"Option \" + LQUOTE + option + RQUOTE + u8\" not present\")\n    {\n    }\n  };\n\n  class argument_incorrect_type : public OptionParseException\n  {\n    public:\n    argument_incorrect_type\n    (\n      const std::string& arg\n    )\n    : OptionParseException(\n        u8\"Argument \" + LQUOTE + arg + RQUOTE + u8\" failed to parse\"\n      )\n    {\n    }\n  };\n\n  class option_required_exception : public OptionParseException\n  {\n    public:\n    option_required_exception(const std::string& option)\n    : OptionParseException(\n        u8\"Option \" + LQUOTE + option + RQUOTE + u8\" is required but not present\"\n      )\n    {\n    }\n  };\n\n  namespace values\n  {\n    namespace\n    {\n      std::basic_regex<char> integer_pattern\n        (\"(-)?(0x)?([1-9a-zA-Z][0-9a-zA-Z]*)|((0x)?0)\");\n      std::basic_regex<char> truthy_pattern\n        (\"(t|T)(rue)?\");\n      std::basic_regex<char> falsy_pattern\n        (\"((f|F)(alse)?)?\");\n    }\n\n    namespace detail\n    {\n      template <typename T, bool B>\n      struct SignedCheck;\n\n      template <typename T>\n      struct SignedCheck<T, true>\n      {\n        template <typename U>\n        void\n        operator()(bool negative, U u, const std::string& text)\n        {\n          if (negative)\n          {\n            if (u > static_cast<U>(-std::numeric_limits<T>::min()))\n            {\n              throw argument_incorrect_type(text);\n            }\n          }\n          else\n          {\n            if (u > static_cast<U>(std::numeric_limits<T>::max()))\n            {\n              throw argument_incorrect_type(text);\n            }\n          }\n        }\n      };\n\n      template <typename T>\n      struct SignedCheck<T, false>\n      {\n        template <typename U>\n        void\n        operator()(bool, U, const std::string&) {}\n      };\n\n      template <typename T, typename U>\n      void\n      check_signed_range(bool negative, U value, const std::string& text)\n      {\n        SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);\n      }\n    }\n\n    template <typename R, typename T>\n    R\n    checked_negate(T&& t, const std::string&, std::true_type)\n    {\n      // if we got to here, then `t` is a positive number that fits into\n      // `R`. So to avoid MSVC C4146, we first cast it to `R`.\n      // See https://github.com/jarro2783/cxxopts/issues/62 for more details.\n      return -static_cast<R>(t);\n    }\n\n    template <typename R, typename T>\n    T\n    checked_negate(T&&, const std::string& text, std::false_type)\n    {\n      throw argument_incorrect_type(text);\n    }\n\n    template <typename T>\n    void\n    integer_parser(const std::string& text, T& value)\n    {\n      std::smatch match;\n      std::regex_match(text, match, integer_pattern);\n\n      if (match.length() == 0)\n      {\n        throw argument_incorrect_type(text);\n      }\n\n      if (match.length(4) > 0)\n      {\n        value = 0;\n        return;\n      }\n\n      using US = typename std::make_unsigned<T>::type;\n\n      constexpr auto umax = std::numeric_limits<US>::max();\n      constexpr bool is_signed = std::numeric_limits<T>::is_signed;\n      const bool negative = match.length(1) > 0;\n      const uint8_t base = match.length(2) > 0 ? 16 : 10;\n\n      auto value_match = match[3];\n\n      US result = 0;\n\n      for (auto iter = value_match.first; iter != value_match.second; ++iter)\n      {\n        size_t digit = 0;\n\n        if (*iter >= '0' && *iter <= '9')\n        {\n          digit = *iter - '0';\n        }\n        else if (base == 16 && *iter >= 'a' && *iter <= 'f')\n        {\n          digit = *iter - 'a' + 10;\n        }\n        else if (base == 16 && *iter >= 'A' && *iter <= 'F')\n        {\n          digit = *iter - 'A' + 10;\n        }\n        else\n        {\n          throw argument_incorrect_type(text);\n        }\n\n        if (umax - digit < result * base)\n        {\n          throw argument_incorrect_type(text);\n        }\n\n        result = result * base + digit;\n      }\n\n      detail::check_signed_range<T>(negative, result, text);\n\n      if (negative)\n      {\n        value = checked_negate<T>(result,\n          text,\n          std::integral_constant<bool, is_signed>());\n      }\n      else\n      {\n        value = result;\n      }\n    }\n\n    template <typename T>\n    void stringstream_parser(const std::string& text, T& value)\n    {\n      std::stringstream in(text);\n      in >> value;\n      if (!in) {\n        throw argument_incorrect_type(text);\n      }\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, uint8_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, int8_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, uint16_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, int16_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, uint32_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, int32_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, uint64_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, int64_t& value)\n    {\n      integer_parser(text, value);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, bool& value)\n    {\n      std::smatch result;\n      std::regex_match(text, result, truthy_pattern);\n\n      if (!result.empty())\n      {\n        value = true;\n        return;\n      }\n\n      std::regex_match(text, result, falsy_pattern);\n      if (!result.empty())\n      {\n        value = false;\n        return;\n      }\n\n      throw argument_incorrect_type(text);\n    }\n\n    inline\n    void\n    parse_value(const std::string& text, std::string& value)\n    {\n      value = text;\n    }\n\n    // The fallback parser. It uses the stringstream parser to parse all types\n    // that have not been overloaded explicitly.  It has to be placed in the\n    // source code before all other more specialized templates.\n    template <typename T>\n    void\n    parse_value(const std::string& text, T& value) {\n      stringstream_parser(text, value);\n    }\n\n    template <typename T>\n    void\n    parse_value(const std::string& text, std::vector<T>& value)\n    {\n      T v;\n      parse_value(text, v);\n      value.push_back(v);\n    }\n\n#ifdef CXXOPTS_HAS_OPTIONAL\n    template <typename T>\n    void\n    parse_value(const std::string& text, std::optional<T>& value)\n    {\n      T result;\n      parse_value(text, result);\n      value = std::move(result);\n    }\n#endif\n\n    template <typename T>\n    struct type_is_container\n    {\n      static constexpr bool value = false;\n    };\n\n    template <typename T>\n    struct type_is_container<std::vector<T>>\n    {\n      static constexpr bool value = true;\n    };\n\n    template <typename T>\n    class abstract_value : public Value\n    {\n      using Self = abstract_value<T>;\n\n      public:\n      abstract_value()\n      : m_result(std::make_shared<T>())\n      , m_store(m_result.get())\n      {\n      }\n\n      abstract_value(T* t)\n      : m_store(t)\n      {\n      }\n\n      virtual ~abstract_value() = default;\n\n      abstract_value(const abstract_value& rhs)\n      {\n        if (rhs.m_result)\n        {\n          m_result = std::make_shared<T>();\n          m_store = m_result.get();\n        }\n        else\n        {\n          m_store = rhs.m_store;\n        }\n\n        m_default = rhs.m_default;\n        m_implicit = rhs.m_implicit;\n        m_default_value = rhs.m_default_value;\n        m_implicit_value = rhs.m_implicit_value;\n      }\n\n      void\n      parse(const std::string& text) const\n      {\n        parse_value(text, *m_store);\n      }\n\n      bool\n      is_container() const\n      {\n        return type_is_container<T>::value;\n      }\n\n      void\n      parse() const\n      {\n        parse_value(m_default_value, *m_store);\n      }\n\n      bool\n      has_default() const\n      {\n        return m_default;\n      }\n\n      bool\n      has_implicit() const\n      {\n        return m_implicit;\n      }\n\n      std::shared_ptr<Value>\n      default_value(const std::string& value)\n      {\n        m_default = true;\n        m_default_value = value;\n        return shared_from_this();\n      }\n\n      std::shared_ptr<Value>\n      implicit_value(const std::string& value)\n      {\n        m_implicit = true;\n        m_implicit_value = value;\n        return shared_from_this();\n      }\n\n      std::string\n      get_default_value() const\n      {\n        return m_default_value;\n      }\n\n      std::string\n      get_implicit_value() const\n      {\n        return m_implicit_value;\n      }\n\n      bool\n      is_boolean() const\n      {\n        return std::is_same<T, bool>::value;\n      }\n\n      const T&\n      get() const\n      {\n        if (m_store == nullptr)\n        {\n          return *m_result;\n        }\n        else\n        {\n          return *m_store;\n        }\n      }\n\n      protected:\n      std::shared_ptr<T> m_result;\n      T* m_store;\n\n      bool m_default = false;\n      bool m_implicit = false;\n\n      std::string m_default_value;\n      std::string m_implicit_value;\n    };\n\n    template <typename T>\n    class standard_value : public abstract_value<T>\n    {\n      public:\n      using abstract_value<T>::abstract_value;\n\n      std::shared_ptr<Value>\n      clone() const\n      {\n        return std::make_shared<standard_value<T>>(*this);\n      }\n    };\n\n    template <>\n    class standard_value<bool> : public abstract_value<bool>\n    {\n      public:\n      ~standard_value() = default;\n\n      standard_value()\n      {\n        set_default_and_implicit();\n      }\n\n      standard_value(bool* b)\n      : abstract_value(b)\n      {\n        set_default_and_implicit();\n      }\n\n      std::shared_ptr<Value>\n      clone() const\n      {\n        return std::make_shared<standard_value<bool>>(*this);\n      }\n\n      private:\n\n      void\n      set_default_and_implicit()\n      {\n        m_default = true;\n        m_default_value = \"false\";\n        m_implicit = true;\n        m_implicit_value = \"true\";\n      }\n    };\n  }\n\n  template <typename T>\n  std::shared_ptr<Value>\n  value()\n  {\n    return std::make_shared<values::standard_value<T>>();\n  }\n\n  template <typename T>\n  std::shared_ptr<Value>\n  value(T& t)\n  {\n    return std::make_shared<values::standard_value<T>>(&t);\n  }\n\n  class OptionAdder;\n\n  class OptionDetails\n  {\n    public:\n    OptionDetails\n    (\n      const std::string& short_,\n      const std::string& long_,\n      const String& desc,\n      std::shared_ptr<const Value> val\n    )\n    : m_short(short_)\n    , m_long(long_)\n    , m_desc(desc)\n    , m_value(val)\n    , m_count(0)\n    {\n    }\n\n    OptionDetails(const OptionDetails& rhs)\n    : m_desc(rhs.m_desc)\n    , m_count(rhs.m_count)\n    {\n      m_value = rhs.m_value->clone();\n    }\n\n    OptionDetails(OptionDetails&& rhs) = default;\n\n    const String&\n    description() const\n    {\n      return m_desc;\n    }\n\n    const Value& value() const {\n        return *m_value;\n    }\n\n    std::shared_ptr<Value>\n    make_storage() const\n    {\n      return m_value->clone();\n    }\n\n    const std::string&\n    short_name() const\n    {\n      return m_short;\n    }\n\n    const std::string&\n    long_name() const\n    {\n      return m_long;\n    }\n\n    private:\n    std::string m_short;\n    std::string m_long;\n    String m_desc;\n    std::shared_ptr<const Value> m_value;\n    int m_count;\n  };\n\n  struct HelpOptionDetails\n  {\n    std::string s;\n    std::string l;\n    String desc;\n    bool has_default;\n    std::string default_value;\n    bool has_implicit;\n    std::string implicit_value;\n    std::string arg_help;\n    bool is_container;\n    bool is_boolean;\n  };\n\n  struct HelpGroupDetails\n  {\n    std::string name;\n    std::string description;\n    std::vector<HelpOptionDetails> options;\n  };\n\n  class OptionValue\n  {\n    public:\n    void\n    parse\n    (\n      std::shared_ptr<const OptionDetails> details,\n      const std::string& text\n    )\n    {\n      ensure_value(details);\n      ++m_count;\n      m_value->parse(text);\n    }\n\n    void\n    parse_default(std::shared_ptr<const OptionDetails> details)\n    {\n      ensure_value(details);\n      m_value->parse();\n    }\n\n    size_t\n    count() const\n    {\n      return m_count;\n    }\n\n    template <typename T>\n    const T&\n    as() const\n    {\n#ifdef CXXOPTS_NO_RTTI\n      return static_cast<const values::standard_value<T>&>(*m_value).get();\n#else\n      return dynamic_cast<const values::standard_value<T>&>(*m_value).get();\n#endif\n    }\n\n    private:\n    void\n    ensure_value(std::shared_ptr<const OptionDetails> details)\n    {\n      if (m_value == nullptr)\n      {\n        m_value = details->make_storage();\n      }\n    }\n\n    std::shared_ptr<Value> m_value;\n    size_t m_count = 0;\n  };\n\n  class KeyValue\n  {\n    public:\n    KeyValue(std::string key_, std::string value_)\n    : m_key(std::move(key_))\n    , m_value(std::move(value_))\n    {\n    }\n\n    const\n    std::string&\n    key() const\n    {\n      return m_key;\n    }\n\n    const std::string\n    value() const\n    {\n      return m_value;\n    }\n\n    template <typename T>\n    T\n    as() const\n    {\n      T result;\n      values::parse_value(m_value, result);\n      return result;\n    }\n\n    private:\n    std::string m_key;\n    std::string m_value;\n  };\n\n  class ParseResult\n  {\n    public:\n\n    ParseResult(\n      const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&,\n      std::vector<std::string>,\n      int&, const char**&);\n\n    size_t\n    count(const std::string& o) const\n    {\n      auto iter = m_options.find(o);\n      if (iter == m_options.end())\n      {\n        return 0;\n      }\n\n      auto riter = m_results.find(iter->second);\n\n      return riter->second.count();\n    }\n\n    const OptionValue&\n    operator[](const std::string& option) const\n    {\n      auto iter = m_options.find(option);\n\n      if (iter == m_options.end())\n      {\n        throw option_not_present_exception(option);\n      }\n\n      auto riter = m_results.find(iter->second);\n\n      return riter->second;\n    }\n\n    const std::vector<KeyValue>&\n    arguments() const\n    {\n      return m_sequential;\n    }\n\n    private:\n\n    OptionValue&\n    get_option(std::shared_ptr<OptionDetails>);\n\n    void\n    parse(int& argc, const char**& argv);\n\n    void\n    add_to_option(const std::string& option, const std::string& arg);\n\n    bool\n    consume_positional(std::string a);\n\n    void\n    parse_option\n    (\n      std::shared_ptr<OptionDetails> value,\n      const std::string& name,\n      const std::string& arg = \"\"\n    );\n\n    void\n    parse_default(std::shared_ptr<OptionDetails> details);\n\n    void\n    checked_parse_arg\n    (\n      int argc,\n      const char* argv[],\n      int& current,\n      std::shared_ptr<OptionDetails> value,\n      const std::string& name\n    );\n\n    const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>\n      &m_options;\n    std::vector<std::string> m_positional;\n    std::vector<std::string>::iterator m_next_positional;\n    std::unordered_set<std::string> m_positional_set;\n    std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;\n\n    std::vector<KeyValue> m_sequential;\n  };\n\n  class Options\n  {\n    public:\n\n    Options(std::string program, std::string help_string = \"\")\n    : m_program(std::move(program))\n    , m_help_string(toLocalString(std::move(help_string)))\n    , m_custom_help(\"[OPTION...]\")\n    , m_positional_help(\"positional parameters\")\n    , m_show_positional(false)\n    , m_next_positional(m_positional.end())\n    {\n    }\n\n    Options&\n    positional_help(std::string help_text)\n    {\n      m_positional_help = std::move(help_text);\n      return *this;\n    }\n\n    Options&\n    custom_help(std::string help_text)\n    {\n      m_custom_help = std::move(help_text);\n      return *this;\n    }\n\n    Options&\n    show_positional_help()\n    {\n      m_show_positional = true;\n      return *this;\n    }\n\n    ParseResult\n    parse(int& argc, const char**& argv);\n\n    OptionAdder\n    add_options(std::string group = \"\");\n\n    void\n    add_option\n    (\n      const std::string& group,\n      const std::string& s,\n      const std::string& l,\n      std::string desc,\n      std::shared_ptr<const Value> value,\n      std::string arg_help\n    );\n\n    //parse positional arguments into the given option\n    void\n    parse_positional(std::string option);\n\n    void\n    parse_positional(std::vector<std::string> options);\n\n    void\n    parse_positional(std::initializer_list<std::string> options);\n\n    std::string\n    help(const std::vector<std::string>& groups = {\"\"}) const;\n\n    const std::vector<std::string>\n    groups() const;\n\n    const HelpGroupDetails&\n    group_help(const std::string& group) const;\n\n    private:\n\n    void\n    add_one_option\n    (\n      const std::string& option,\n      std::shared_ptr<OptionDetails> details\n    );\n\n    String\n    help_one_group(const std::string& group) const;\n\n    void\n    generate_group_help\n    (\n      String& result,\n      const std::vector<std::string>& groups\n    ) const;\n\n    void\n    generate_all_groups_help(String& result) const;\n\n    std::string m_program;\n    String m_help_string;\n    std::string m_custom_help;\n    std::string m_positional_help;\n    bool m_show_positional;\n\n    std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options;\n    std::vector<std::string> m_positional;\n    std::vector<std::string>::iterator m_next_positional;\n    std::unordered_set<std::string> m_positional_set;\n\n    //mapping from groups to help options\n    std::map<std::string, HelpGroupDetails> m_help;\n  };\n\n  class OptionAdder\n  {\n    public:\n\n    OptionAdder(Options& options, std::string group)\n    : m_options(options), m_group(std::move(group))\n    {\n    }\n\n    OptionAdder&\n    operator()\n    (\n      const std::string& opts,\n      const std::string& desc,\n      std::shared_ptr<const Value> value\n        = ::cxxopts::value<bool>(),\n      std::string arg_help = \"\"\n    );\n\n    private:\n    Options& m_options;\n    std::string m_group;\n  };\n\n  namespace\n  {\n    constexpr int OPTION_LONGEST = 30;\n    constexpr int OPTION_DESC_GAP = 2;\n\n    std::basic_regex<char> option_matcher\n      (\"--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)\");\n\n    std::basic_regex<char> option_specifier\n      (\"(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?\");\n\n    String\n    format_option\n    (\n      const HelpOptionDetails& o\n    )\n    {\n      auto& s = o.s;\n      auto& l = o.l;\n\n      String result = \"  \";\n\n      if (s.size() > 0)\n      {\n        result += \"-\" + toLocalString(s) + \",\";\n      }\n      else\n      {\n        result += \"   \";\n      }\n\n      if (l.size() > 0)\n      {\n        result += \" --\" + toLocalString(l);\n      }\n\n      auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : \"arg\";\n\n      if (!o.is_boolean)\n      {\n        if (o.has_implicit)\n        {\n          result += \" [=\" + arg + \"(=\" + toLocalString(o.implicit_value) + \")]\";\n        }\n        else\n        {\n          result += \" \" + arg;\n        }\n      }\n\n      return result;\n    }\n\n    String\n    format_description\n    (\n      const HelpOptionDetails& o,\n      size_t start,\n      size_t width\n    )\n    {\n      auto desc = o.desc;\n\n      if (o.has_default && (!o.is_boolean || o.default_value != \"false\"))\n      {\n        desc += toLocalString(\" (default: \" + o.default_value + \")\");\n      }\n\n      String result;\n\n      auto current = std::begin(desc);\n      auto startLine = current;\n      auto lastSpace = current;\n\n      auto size = size_t{};\n\n      while (current != std::end(desc))\n      {\n        if (*current == ' ')\n        {\n          lastSpace = current;\n        }\n\n        if (size > width)\n        {\n          if (lastSpace == startLine)\n          {\n            stringAppend(result, startLine, current + 1);\n            stringAppend(result, \"\\n\");\n            stringAppend(result, start, ' ');\n            startLine = current + 1;\n            lastSpace = startLine;\n          }\n          else\n          {\n            stringAppend(result, startLine, lastSpace);\n            stringAppend(result, \"\\n\");\n            stringAppend(result, start, ' ');\n            startLine = lastSpace + 1;\n          }\n          size = 0;\n        }\n        else\n        {\n          ++size;\n        }\n\n        ++current;\n      }\n\n      //append whatever is left\n      stringAppend(result, startLine, current);\n\n      return result;\n    }\n  }\n\ninline\nParseResult::ParseResult\n(\n  const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>& options,\n  std::vector<std::string> positional,\n  int& argc, const char**& argv\n)\n: m_options(options)\n, m_positional(std::move(positional))\n, m_next_positional(m_positional.begin())\n{\n  parse(argc, argv);\n}\n\ninline\nOptionAdder\nOptions::add_options(std::string group)\n{\n  return OptionAdder(*this, std::move(group));\n}\n\ninline\nOptionAdder&\nOptionAdder::operator()\n(\n  const std::string& opts,\n  const std::string& desc,\n  std::shared_ptr<const Value> value,\n  std::string arg_help\n)\n{\n  std::match_results<const char*> result;\n  std::regex_match(opts.c_str(), result, option_specifier);\n\n  if (result.empty())\n  {\n    throw invalid_option_format_error(opts);\n  }\n\n  const auto& short_match = result[2];\n  const auto& long_match = result[3];\n\n  if (!short_match.length() && !long_match.length())\n  {\n    throw invalid_option_format_error(opts);\n  } else if (long_match.length() == 1 && short_match.length())\n  {\n    throw invalid_option_format_error(opts);\n  }\n\n  auto option_names = []\n  (\n    const std::sub_match<const char*>& short_,\n    const std::sub_match<const char*>& long_\n  )\n  {\n    if (long_.length() == 1)\n    {\n      return std::make_tuple(long_.str(), short_.str());\n    }\n    else\n    {\n      return std::make_tuple(short_.str(), long_.str());\n    }\n  }(short_match, long_match);\n\n  m_options.add_option\n  (\n    m_group,\n    std::get<0>(option_names),\n    std::get<1>(option_names),\n    desc,\n    value,\n    std::move(arg_help)\n  );\n\n  return *this;\n}\n\ninline\nvoid\nParseResult::parse_default(std::shared_ptr<OptionDetails> details)\n{\n  m_results[details].parse_default(details);\n}\n\ninline\nvoid\nParseResult::parse_option\n(\n  std::shared_ptr<OptionDetails> value,\n  const std::string& /*name*/,\n  const std::string& arg\n)\n{\n  auto& result = m_results[value];\n  result.parse(value, arg);\n\n  m_sequential.emplace_back(value->long_name(), arg);\n}\n\ninline\nvoid\nParseResult::checked_parse_arg\n(\n  int argc,\n  const char* argv[],\n  int& current,\n  std::shared_ptr<OptionDetails> value,\n  const std::string& name\n)\n{\n  if (current + 1 >= argc)\n  {\n    if (value->value().has_implicit())\n    {\n      parse_option(value, name, value->value().get_implicit_value());\n    }\n    else\n    {\n      throw missing_argument_exception(name);\n    }\n  }\n  else\n  {\n    if (value->value().has_implicit())\n    {\n      parse_option(value, name, value->value().get_implicit_value());\n    }\n    else\n    {\n      parse_option(value, name, argv[current + 1]);\n      ++current;\n    }\n  }\n}\n\ninline\nvoid\nParseResult::add_to_option(const std::string& option, const std::string& arg)\n{\n  auto iter = m_options.find(option);\n\n  if (iter == m_options.end())\n  {\n    throw option_not_exists_exception(option);\n  }\n\n  parse_option(iter->second, option, arg);\n}\n\ninline\nbool\nParseResult::consume_positional(std::string a)\n{\n  while (m_next_positional != m_positional.end())\n  {\n    auto iter = m_options.find(*m_next_positional);\n    if (iter != m_options.end())\n    {\n      auto& result = m_results[iter->second];\n      if (!iter->second->value().is_container())\n      {\n        if (result.count() == 0)\n        {\n          add_to_option(*m_next_positional, a);\n          ++m_next_positional;\n          return true;\n        }\n        else\n        {\n          ++m_next_positional;\n          continue;\n        }\n      }\n      else\n      {\n        add_to_option(*m_next_positional, a);\n        return true;\n      }\n    }\n    ++m_next_positional;\n  }\n\n  return false;\n}\n\ninline\nvoid\nOptions::parse_positional(std::string option)\n{\n  parse_positional(std::vector<std::string>{std::move(option)});\n}\n\ninline\nvoid\nOptions::parse_positional(std::vector<std::string> options)\n{\n  m_positional = std::move(options);\n  m_next_positional = m_positional.begin();\n\n  m_positional_set.insert(m_positional.begin(), m_positional.end());\n}\n\ninline\nvoid\nOptions::parse_positional(std::initializer_list<std::string> options)\n{\n  parse_positional(std::vector<std::string>(std::move(options)));\n}\n\ninline\nParseResult\nOptions::parse(int& argc, const char**& argv)\n{\n  ParseResult result(m_options, m_positional, argc, argv);\n  return result;\n}\n\ninline\nvoid\nParseResult::parse(int& argc, const char**& argv)\n{\n  int current = 1;\n\n  int nextKeep = 1;\n\n  bool consume_remaining = false;\n\n  while (current != argc)\n  {\n    if (strcmp(argv[current], \"--\") == 0)\n    {\n      consume_remaining = true;\n      ++current;\n      break;\n    }\n\n    std::match_results<const char*> result;\n    std::regex_match(argv[current], result, option_matcher);\n\n    if (result.empty())\n    {\n      //not a flag\n\n      //if true is returned here then it was consumed, otherwise it is\n      //ignored\n      if (consume_positional(argv[current]))\n      {\n      }\n      else\n      {\n        argv[nextKeep] = argv[current];\n        ++nextKeep;\n      }\n      //if we return from here then it was parsed successfully, so continue\n    }\n    else\n    {\n      //short or long option?\n      if (result[4].length() != 0)\n      {\n        const std::string& s = result[4];\n\n        for (std::size_t i = 0; i != s.size(); ++i)\n        {\n          std::string name(1, s[i]);\n          auto iter = m_options.find(name);\n\n          if (iter == m_options.end())\n          {\n            throw option_not_exists_exception(name);\n          }\n\n          auto value = iter->second;\n\n          if (i + 1 == s.size())\n          {\n            //it must be the last argument\n            checked_parse_arg(argc, argv, current, value, name);\n          }\n          else if (value->value().has_implicit())\n          {\n            parse_option(value, name, value->value().get_implicit_value());\n          }\n          else\n          {\n            //error\n            throw option_requires_argument_exception(name);\n          }\n        }\n      }\n      else if (result[1].length() != 0)\n      {\n        const std::string& name = result[1];\n\n        auto iter = m_options.find(name);\n\n        if (iter == m_options.end())\n        {\n          throw option_not_exists_exception(name);\n        }\n\n        auto opt = iter->second;\n\n        //equals provided for long option?\n        if (result[2].length() != 0)\n        {\n          //parse the option given\n\n          parse_option(opt, name, result[3]);\n        }\n        else\n        {\n          //parse the next argument\n          checked_parse_arg(argc, argv, current, opt, name);\n        }\n      }\n\n    }\n\n    ++current;\n  }\n\n  for (auto& opt : m_options)\n  {\n    auto& detail = opt.second;\n    auto& value = detail->value();\n\n    auto& store = m_results[detail];\n\n    if(!store.count() && value.has_default()){\n      parse_default(detail);\n    }\n  }\n\n  if (consume_remaining)\n  {\n    while (current < argc)\n    {\n      if (!consume_positional(argv[current])) {\n        break;\n      }\n      ++current;\n    }\n\n    //adjust argv for any that couldn't be swallowed\n    while (current != argc) {\n      argv[nextKeep] = argv[current];\n      ++nextKeep;\n      ++current;\n    }\n  }\n\n  argc = nextKeep;\n\n}\n\ninline\nvoid\nOptions::add_option\n(\n  const std::string& group,\n  const std::string& s,\n  const std::string& l,\n  std::string desc,\n  std::shared_ptr<const Value> value,\n  std::string arg_help\n)\n{\n  auto stringDesc = toLocalString(std::move(desc));\n  auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);\n\n  if (s.size() > 0)\n  {\n    add_one_option(s, option);\n  }\n\n  if (l.size() > 0)\n  {\n    add_one_option(l, option);\n  }\n\n  //add the help details\n  auto& options = m_help[group];\n\n  options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,\n      value->has_default(), value->get_default_value(),\n      value->has_implicit(), value->get_implicit_value(),\n      std::move(arg_help),\n      value->is_container(),\n      value->is_boolean()});\n}\n\ninline\nvoid\nOptions::add_one_option\n(\n  const std::string& option,\n  std::shared_ptr<OptionDetails> details\n)\n{\n  auto in = m_options.emplace(option, details);\n\n  if (!in.second)\n  {\n    throw option_exists_error(option);\n  }\n}\n\ninline\nString\nOptions::help_one_group(const std::string& g) const\n{\n  typedef std::vector<std::pair<String, String>> OptionHelp;\n\n  auto group = m_help.find(g);\n  if (group == m_help.end())\n  {\n    return \"\";\n  }\n\n  OptionHelp format;\n\n  size_t longest = 0;\n\n  String result;\n\n  if (!g.empty())\n  {\n    result += toLocalString(\" \" + g + \" options:\\n\");\n  }\n\n  for (const auto& o : group->second.options)\n  {\n    if (o.is_container &&\n        m_positional_set.find(o.l) != m_positional_set.end() &&\n        !m_show_positional)\n    {\n      continue;\n    }\n\n    auto s = format_option(o);\n    longest = std::max(longest, stringLength(s));\n    format.push_back(std::make_pair(s, String()));\n  }\n\n  longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));\n\n  //widest allowed description\n  auto allowed = size_t{76} - longest - OPTION_DESC_GAP;\n\n  auto fiter = format.begin();\n  for (const auto& o : group->second.options)\n  {\n    if (o.is_container &&\n        m_positional_set.find(o.l) != m_positional_set.end() &&\n        !m_show_positional)\n    {\n      continue;\n    }\n\n    auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);\n\n    result += fiter->first;\n    if (stringLength(fiter->first) > longest)\n    {\n      result += '\\n';\n      result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));\n    }\n    else\n    {\n      result += toLocalString(std::string(longest + OPTION_DESC_GAP -\n        stringLength(fiter->first),\n        ' '));\n    }\n    result += d;\n    result += '\\n';\n\n    ++fiter;\n  }\n\n  return result;\n}\n\ninline\nvoid\nOptions::generate_group_help\n(\n  String& result,\n  const std::vector<std::string>& print_groups\n) const\n{\n  for (size_t i = 0; i != print_groups.size(); ++i)\n  {\n    const String& group_help_text = help_one_group(print_groups[i]);\n    if (empty(group_help_text))\n    {\n      continue;\n    }\n    result += group_help_text;\n    if (i < print_groups.size() - 1)\n    {\n      result += '\\n';\n    }\n  }\n}\n\ninline\nvoid\nOptions::generate_all_groups_help(String& result) const\n{\n  std::vector<std::string> all_groups;\n  all_groups.reserve(m_help.size());\n\n  for (auto& group : m_help)\n  {\n    all_groups.push_back(group.first);\n  }\n\n  generate_group_help(result, all_groups);\n}\n\ninline\nstd::string\nOptions::help(const std::vector<std::string>& help_groups) const\n{\n  String result = m_help_string + \"\\nUsage:\\n  \" +\n    toLocalString(m_program) + \" \" + toLocalString(m_custom_help);\n\n  if (m_positional.size() > 0 && m_positional_help.size() > 0) {\n    result += \" \" + toLocalString(m_positional_help);\n  }\n\n  result += \"\\n\\n\";\n\n  if (help_groups.size() == 0)\n  {\n    generate_all_groups_help(result);\n  }\n  else\n  {\n    generate_group_help(result, help_groups);\n  }\n\n  return toUTF8String(result);\n}\n\ninline\nconst std::vector<std::string>\nOptions::groups() const\n{\n  std::vector<std::string> g;\n\n  std::transform(\n    m_help.begin(),\n    m_help.end(),\n    std::back_inserter(g),\n    [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)\n    {\n      return pair.first;\n    }\n  );\n\n  return g;\n}\n\ninline\nconst HelpGroupDetails&\nOptions::group_help(const std::string& group) const\n{\n  return m_help.at(group);\n}\n\n}\n\n#endif //CXXOPTS_HPP_INCLUDED\n"
  },
  {
    "path": "eos-model-viewer.cpp",
    "content": "/*\n * eos - A 3D Morphable Model fitting library written in modern C++11/14.\n *\n * File: eos-model-viewer.cpp\n *\n * Copyright 2017, 2018 Patrik Huber\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#include \"cxxopts.hpp\"\n\n#include \"eos/core/Mesh.hpp\"\n#include \"eos/morphablemodel/MorphableModel.hpp\"\n#include \"eos/morphablemodel/io/cvssp.hpp\"\n#include \"eos/morphablemodel/Blendshape.hpp\"\n#include \"eos/cpp17/variant.hpp\"\n\n#include \"igl/opengl/glfw/Viewer.h\"\n#include \"igl/opengl/glfw/imgui/ImGuiMenu.h\"\n#include \"igl/opengl/glfw/imgui/ImGuiHelpers.h\"\n#include \"imgui/imgui.h\"\n\n#include <iostream>\n#include <sstream>\n#include <iomanip>\n#include <random>\n#include <algorithm>\n\ntemplate <typename T>\nstd::string to_string(const T a_value, const int n = 6)\n{\n    std::ostringstream out;\n    out << std::setprecision(n) << a_value;\n    return out.str();\n};\n\n// From: https://stackoverflow.com/a/1493195/1345959\ntemplate <class ContainerType>\nvoid tokenize(const std::string& str, ContainerType& tokens, const std::string& delimiters = \" \",\n              bool trim_empty = false)\n{\n    std::string::size_type pos, last_pos = 0;\n    const auto length = str.length();\n\n    using value_type = typename ContainerType::value_type;\n    using size_type = typename ContainerType::size_type;\n\n    while (last_pos < length + 1)\n    {\n        pos = str.find_first_of(delimiters, last_pos);\n        if (pos == std::string::npos)\n        {\n            pos = length;\n        }\n\n        if (pos != last_pos || !trim_empty)\n            tokens.push_back(value_type(str.data() + last_pos, (size_type)pos - last_pos));\n\n        last_pos = pos + 1;\n    }\n};\n\neos::morphablemodel::MorphableModel load_bin_or_scm_model(std::string model_file)\n{\n    using namespace eos;\n    using eos::morphablemodel::MorphableModel;\n\n    MorphableModel morphable_model;\n\n    std::vector<std::string> tokens;\n    tokenize(model_file, tokens, \".\");\n    const auto model_file_extension = tokens.back();\n\n    // Todo: Add try-catch to all these?\n    if (model_file_extension == \"scm\")\n    {\n        morphable_model = morphablemodel::load_scm_model(model_file);\n    } else if (model_file_extension == \"bin\")\n    {\n        morphable_model = morphablemodel::load_model(model_file);\n    } else\n    {\n        throw std::runtime_error(\"Error: Please load a model with .bin or .scm extension.\");\n    }\n    return morphable_model;\n}\n\n/**\n *\n */\neos::morphablemodel::MorphableModel load_model(std::string model_file, std::string blendshapes_file)\n{\n    using namespace eos;\n    using eos::morphablemodel::MorphableModel;\n\n    MorphableModel morphable_model;\n\n    // Todo: Add try-catch to all these?\n    morphable_model = load_bin_or_scm_model(model_file);\n    // If separate blendshapes are given, load them, and construct a model with expressions:\n    if (!blendshapes_file.empty())\n    {\n        const auto blendshapes = morphablemodel::load_blendshapes(blendshapes_file);\n        morphable_model = MorphableModel(\n            morphable_model.get_shape_model(), blendshapes, morphable_model.get_color_model(),\n            morphable_model.get_landmark_definitions(), morphable_model.get_texture_coordinates());\n    }\n    return morphable_model;\n};\n\n/**\n * Model viewer for 3D Morphable Models.\n */\nint main(int argc, const char* argv[])\n{\n    using namespace eos;\n    using Eigen::VectorXf;\n    using std::begin;\n    using std::cout;\n    using std::end;\n    using std::endl;\n    using std::for_each;\n    using std::string;\n    using std::vector;\n\n    string model_file, blendshapes_file;\n    try\n    {\n        cxxopts::Options options(\"eos-model-viewer\", \"OpenGL viewer for eos's 3D morphable models.\");\n        // clang-format off\n        options.add_options()\n            (\"h,help\", \"display the help message\")\n            (\"m,model\", \"an eos 3D Morphable Model stored as cereal BinaryArchive (.bin)\",\n                cxxopts::value(model_file))\n            (\"b,blendshapes\", \"an eos file with blendshapes (.bin)\",\n                cxxopts::value(blendshapes_file));\n        // clang-format on\n        const auto result = options.parse(argc, argv);\n        if (result.count(\"help\"))\n        {\n            cout << options.help() << endl;\n            return EXIT_SUCCESS;\n        }\n    } catch (const cxxopts::OptionException& e)\n    {\n        cout << \"Error parsing options: \" << e.what() << endl;\n        return EXIT_FAILURE;\n    }\n\n    // Note: Take the vertices here directly, so we can maybe avoid ever generating a Mesh instance\n    auto get_V = [](const core::Mesh& mesh) {\n        Eigen::MatrixXd V(mesh.vertices.size(), 3);\n        for (int i = 0; i < mesh.vertices.size(); ++i)\n        {\n            V(i, 0) = mesh.vertices[i](0);\n            V(i, 1) = mesh.vertices[i](1);\n            V(i, 2) = mesh.vertices[i](2);\n        }\n        return V;\n    };\n    auto get_F = [](const core::Mesh& mesh) {\n        Eigen::MatrixXi F(mesh.tvi.size(), 3);\n        for (int i = 0; i < mesh.tvi.size(); ++i)\n        {\n            F(i, 0) = mesh.tvi[i][0];\n            F(i, 1) = mesh.tvi[i][1];\n            F(i, 2) = mesh.tvi[i][2];\n        }\n        return F;\n    };\n    auto get_C = [](const core::Mesh& mesh) {\n        Eigen::MatrixXd C(mesh.colors.size(), 3);\n        for (int i = 0; i < mesh.colors.size(); ++i)\n        {\n            C(i, 0) = mesh.colors[i](0);\n            C(i, 1) = mesh.colors[i](1);\n            C(i, 2) = mesh.colors[i](2);\n        }\n        return C;\n    };\n\n    // Init the viewer:\n    igl::opengl::glfw::Viewer viewer;\n\n    // Attach a menu plugin:\n    igl::opengl::glfw::imgui::ImGuiMenu menu;\n    viewer.plugins.push_back(&menu);\n\n    morphablemodel::MorphableModel morphable_model;\n    // Load the model right away on start up, if it was given via command-line parameters:\n    if (!model_file.empty())\n    {\n        try\n        {\n            // Loads a .bin or .scm model, with or without blendshapes:\n            morphable_model = load_model(model_file, blendshapes_file);\n            const auto& mean = morphable_model.get_mean();\n            viewer.data().set_mesh(get_V(mean), get_F(mean));\n            viewer.core.align_camera_center(viewer.data().V, viewer.data().F);\n            if (!mean.colors.empty())\n            {\n                viewer.data().set_colors(get_C(mean));\n            }\n\n        } catch (const std::runtime_error& e)\n        {\n            cout << \"Error loading the given model: \" << e.what() << endl;\n            return EXIT_FAILURE;\n        }\n    }\n\n    // These are the coefficients of the currently active mesh instance:\n    vector<float> shape_coefficients;\n    vector<float> color_coefficients;\n    vector<float> expression_coefficients;\n    bool display_identity_model_only = true;\n\n    std::default_random_engine rng;\n    std::array<float, 3> random_sample_sdev = {1.0f, 1.0f, 1.0f}; // shp, exp, col\n\n    // Draw our viewers windows:\n    menu.callback_draw_custom_window = [&]() {\n        // Load model & draw sample options:\n        ImGui::SetNextWindowPos(ImVec2(0.f * menu.menu_scaling(), 585), ImGuiSetCond_FirstUseEver);\n        ImGui::SetNextWindowSize(ImVec2(240, 280), ImGuiSetCond_FirstUseEver);\n        ImGui::Begin(\"Morphable Model\", nullptr, ImGuiWindowFlags_NoSavedSettings);\n        if (ImGui::Button(\"Load Morphable Model\", ImVec2(-1, 0)))\n        {\n            const string mm_fn = igl::file_dialog_open();\n            cout << \"Loading Morphable Model \" << mm_fn << \"...\" << endl;\n            try\n            {\n                morphable_model = load_bin_or_scm_model(mm_fn);\n                const auto& mean = morphable_model.get_mean();\n                viewer.data().clear();\n                viewer.data().set_mesh(get_V(mean), get_F(mean));\n                viewer.core.align_camera_center(viewer.data().V, viewer.data().F);\n                if (!mean.colors.empty())\n                {\n                    viewer.data().set_colors(get_C(mean));\n                }\n            } catch (const std::runtime_error&\n                         e) // Todo: I think we have to catch more errors here, like cereal exceptions\n            {\n                cout << \"Error loading the given model: \" << e.what() << endl;\n            }\n            if (morphable_model.has_separate_expression_model())\n            {\n                // Just a sensible default - if the loaded model has expressions, use them by default:\n                display_identity_model_only = false;\n            }\n        }\n        if (ImGui::Button(\"Load Blendshapes\", ImVec2(-1, 0)))\n        {\n            const string bs_fn = igl::file_dialog_open();\n            cout << \"Loading Blendshapes \" << bs_fn << \"...\" << endl;\n            morphablemodel::Blendshapes blendshapes;\n            try\n            {\n                blendshapes = morphablemodel::load_blendshapes(bs_fn);\n                cout << \"Blendshapes loaded. Constructing a new model consisting of the loaded identity and \"\n                        \"colour PCA models, and the loaded blendshapes...\"\n                     << endl;\n                morphable_model = morphablemodel::MorphableModel(\n                    morphable_model.get_shape_model(), blendshapes, morphable_model.get_color_model(),\n                    morphable_model.get_landmark_definitions(), morphable_model.get_texture_coordinates());\n                const auto& mean = morphable_model.get_mean();\n                viewer.data().clear();\n                viewer.data().set_mesh(get_V(mean), get_F(mean));\n                viewer.core.align_camera_center(viewer.data().V, viewer.data().F);\n                if (!mean.colors.empty())\n                {\n                    viewer.data().set_colors(get_C(mean));\n                }\n\n            } catch (const std::runtime_error&\n                         e) // Todo: I think we have to catch more errors here, like cereal exceptions\n            {\n                cout << \"Error loading the given blendshapes: \" << e.what() << endl;\n            }\n            display_identity_model_only = false;\n        }\n        ImGui::Separator();\n        if (ImGui::Button(\"Mean (id)\", ImVec2(-1, 0)))\n        {\n            Eigen::VectorXf mean = morphable_model.get_shape_model().get_mean();\n            // Take 3 at a piece, then transpose:\n            const auto num_vertices = mean.rows() / 3;\n            Eigen::Map<Eigen::MatrixXf> mean_reshaped(mean.data(), 3, num_vertices);\n            viewer.data().set_vertices(mean_reshaped.transpose().cast<double>());\n\n            if (morphable_model.get_color_model().get_mean().size() > 0)\n            {\n                Eigen::VectorXf color_mean = morphable_model.get_color_model().get_mean();\n                Eigen::Map<Eigen::MatrixXf> color_mean_reshaped(\n                    color_mean.data(), 3,\n                    color_mean.rows() / 3); // Todo: This will fail for gray-level models\n                viewer.data().set_colors(color_mean_reshaped.transpose().cast<double>());\n            }\n\n            for_each(begin(shape_coefficients), end(shape_coefficients), [](auto& coeff) { coeff = 0.0f; });\n            for_each(begin(color_coefficients), end(color_coefficients), [](auto& coeff) { coeff = 0.0f; });\n            for_each(begin(expression_coefficients), end(expression_coefficients),\n                     [](auto& coeff) { coeff = 0.0f; });\n            display_identity_model_only = true;\n        }\n        if (ImGui::Button(\"Mean (id+exp)\", ImVec2(-1, 0)))\n        {\n            const auto mean = morphable_model.get_mean();\n            viewer.data().set_vertices(get_V(mean));\n            if (!mean.colors.empty())\n            {\n                viewer.data().set_colors(get_C(mean));\n            }\n            for_each(begin(shape_coefficients), end(shape_coefficients), [](auto& coeff) { coeff = 0.0f; });\n            for_each(begin(color_coefficients), end(color_coefficients), [](auto& coeff) { coeff = 0.0f; });\n            for_each(begin(expression_coefficients), end(expression_coefficients),\n                     [](auto& coeff) { coeff = 0.0f; });\n            display_identity_model_only = false;\n        }\n        ImGui::Separator();\n        if (ImGui::Button(\"Random face sample\", ImVec2(-1, 0)))\n        {\n            // Shape sample:\n            std::normal_distribution<float> shape_coeffs_dist(0.0f,\n                                                              random_sample_sdev[0]); // c'tor takes stddev\n            shape_coefficients =\n                vector<float>(morphable_model.get_shape_model().get_num_principal_components());\n            for_each(begin(shape_coefficients), end(shape_coefficients),\n                     [&rng, &shape_coeffs_dist](auto& coeff) { coeff = shape_coeffs_dist(rng); });\n            // Expression sample:\n            if (morphable_model.has_separate_expression_model())\n            {\n\n                if (eos::cpp17::holds_alternative<morphablemodel::Blendshapes>(\n                        morphable_model.get_expression_model().value()))\n                {\n                    std::uniform_real_distribution<float> expression_coeffs_dist(\n                        0.0f,\n                        random_sample_sdev[1]); // using the interval [0, sdev] (so it's not really an sdev\n                                                // here!)\n                    const auto expression_model_num_coeffs =\n                        eos::cpp17::get<morphablemodel::Blendshapes>(\n                            morphable_model.get_expression_model().value())\n                            .size();\n                    expression_coefficients = vector<float>(expression_model_num_coeffs);\n                    for_each(begin(expression_coefficients), end(expression_coefficients),\n                             [&rng, &expression_coeffs_dist](auto& coeff) {\n                                 coeff = expression_coeffs_dist(rng);\n                             });\n\n                } else if (eos::cpp17::holds_alternative<morphablemodel::PcaModel>(\n                               morphable_model.get_expression_model().value()))\n                {\n                    std::normal_distribution<float> expression_coeffs_dist(0.0f, random_sample_sdev[1]);\n                    const auto expression_model_num_coeffs =\n                        eos::cpp17::get<morphablemodel::PcaModel>(\n                            morphable_model.get_expression_model().value())\n                            .get_num_principal_components();\n                    expression_coefficients = vector<float>(expression_model_num_coeffs);\n                    for_each(begin(expression_coefficients), end(expression_coefficients),\n                             [&rng, &expression_coeffs_dist](auto& coeff) {\n                                 coeff = expression_coeffs_dist(rng);\n                             });\n                }\n            }\n            // Colour sample:\n            std::normal_distribution<float> color_coeffs_dist(0.0f, random_sample_sdev[2]);\n            color_coefficients =\n                vector<float>(morphable_model.get_color_model().get_num_principal_components());\n            for_each(begin(color_coefficients), end(color_coefficients),\n                     [&rng, &color_coeffs_dist](auto& coeff) { coeff = color_coeffs_dist(rng); });\n\n            // Now generate the sample:\n            core::Mesh sample;\n            // Note: Can it happen that we pass in colour-coeffs, but it's a model without colour?\n            if (morphable_model.has_separate_expression_model())\n            {\n                sample = morphable_model.draw_sample(shape_coefficients, expression_coefficients,\n                                                     color_coefficients);\n            } else\n            {\n                sample = morphable_model.draw_sample(shape_coefficients, color_coefficients);\n            }\n            viewer.data().set_vertices(get_V(sample));\n            if (!sample.colors.empty())\n            {\n                viewer.data().set_colors(get_C(sample));\n            }\n        }\n        /* // Not yet implemented:\n        if (ImGui::Button(\"Random identity sample\", ImVec2(-1, 0)))\n        {\n        }\n        if (ImGui::Button(\"Random expression sample\", ImVec2(-1, 0)))\n        {\n        }\n        if (ImGui::Button(\"Random color sample\", ImVec2(-1, 0)))\n        {\n        }\n        */\n        ImGui::InputFloat3(\"sdev [shp, exp, col]\", &random_sample_sdev[0], 2);\n        ImGui::Checkbox(\"Identity model only\", &display_identity_model_only);\n        ImGui::End(); // end \"Morphable Model\" window\n\n        // PCA shape coefficients:\n        ImGui::SetNextWindowPos(ImVec2(180.f * menu.menu_scaling(), 0), ImGuiSetCond_FirstUseEver);\n        ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);\n        ImGui::Begin(\"Shape PCA\", nullptr, ImGuiWindowFlags_NoSavedSettings);\n\n        ImGui::Text(\"Coefficients\");\n        if (morphable_model.get_shape_model().get_num_principal_components() > 0) // a model was loaded\n        {\n            int num_shape_coeffs_to_display =\n                std::min(morphable_model.get_shape_model().get_num_principal_components(), 30);\n\n            if (shape_coefficients.empty() || shape_coefficients.size() != num_shape_coeffs_to_display)\n            {\n                // no coeffs yet, or number of coeffs has changed for some reason:\n                shape_coefficients.resize(num_shape_coeffs_to_display);\n            }\n            // shape_coefficients are always initialised now.\n\n            ImGui::BeginGroup();\n            for (int i = 0; i < num_shape_coeffs_to_display; ++i)\n            {\n                const string label = std::to_string(i);\n                ImGui::SliderFloat(label.c_str(), &shape_coefficients[i], -3.0, 3.0);\n            }\n            ImGui::EndGroup();\n            string coeffs_displayed =\n                \"Displaying \" + std::to_string(num_shape_coeffs_to_display) + \"/\" +\n                std::to_string(morphable_model.get_shape_model().get_num_principal_components()) +\n                \" coefficients.\";\n            ImGui::Text(coeffs_displayed.c_str());\n\n            // We've got a shape model. So update the mesh that's been drawn with the value of the\n            // coefficients. Note that we are currently doing this every draw call, not only when the\n            // slider changes. See eos-model-viewer/issues/5.\n            VectorXf shape_instance = morphable_model.get_shape_model().draw_sample(shape_coefficients);\n            const auto num_vertices = morphable_model.get_shape_model().get_data_dimension() / 3;\n            // If expression coeffs are set, add the expression part:\n            if (!expression_coefficients.empty() && morphable_model.has_separate_expression_model() &&\n                !display_identity_model_only)\n            {\n                if (eos::cpp17::holds_alternative<morphablemodel::PcaModel>(\n                        morphable_model.get_expression_model().value()))\n                {\n                    const auto& expression_model = eos::cpp17::get<morphablemodel::PcaModel>(\n                        morphable_model.get_expression_model().value());\n                    const VectorXf expression_instance =\n                        expression_model.draw_sample(expression_coefficients);\n                    shape_instance += expression_instance;\n                } else if (eos::cpp17::holds_alternative<morphablemodel::Blendshapes>(\n                               morphable_model.get_expression_model().value()))\n                {\n                    const auto& blendshapes = eos::cpp17::get<morphablemodel::Blendshapes>(\n                        morphable_model.get_expression_model().value());\n                    for (int i = 0; i < blendshapes.size(); ++i)\n                    {\n                        shape_instance += blendshapes[i].deformation * expression_coefficients[i];\n                    }\n                }\n            }\n            Eigen::Map<Eigen::MatrixXf> shape_instance_reshaped(\n                shape_instance.data(), 3, num_vertices); // Take 3 at a piece, then transpose below\n            viewer.data().set_vertices(shape_instance_reshaped.transpose().cast<double>());\n        }\n\n        ImGui::End(); // end \"Shape PCA\" window\n\n        // PCA colour coefficients:\n        ImGui::SetNextWindowPos(ImVec2(380.f * menu.menu_scaling(), 0), ImGuiSetCond_FirstUseEver);\n        ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);\n        ImGui::Begin(\"Colour PCA\", nullptr, ImGuiWindowFlags_NoSavedSettings);\n\n        ImGui::Text(\"Coefficients\");\n        if (morphable_model.get_color_model().get_num_principal_components() > 0) // a model was loaded\n        {\n            int num_color_coeffs_to_display =\n                std::min(morphable_model.get_color_model().get_num_principal_components(), 30);\n\n            if (color_coefficients.empty() || color_coefficients.size() != num_color_coeffs_to_display)\n            {\n                color_coefficients.resize(num_color_coeffs_to_display);\n            }\n            // color_coefficients are always initialised now.\n\n            ImGui::BeginGroup();\n            for (int i = 0; i < num_color_coeffs_to_display; ++i)\n            {\n                const string label = std::to_string(i);\n                ImGui::SliderFloat(label.c_str(), &color_coefficients[i], -3.0, 3.0);\n            }\n            ImGui::EndGroup();\n            string coeffs_displayed =\n                \"Displaying \" + std::to_string(num_color_coeffs_to_display) + \"/\" +\n                std::to_string(morphable_model.get_color_model().get_num_principal_components()) +\n                \" coefficients.\";\n            ImGui::Text(coeffs_displayed.c_str());\n\n            // We've got a colour model. So update the mesh that's been drawn with the value of the\n            // coefficients. Note that we are currently doing this every draw call, not only when the\n            // slider changes. See eos-model-viewer/issues/5.\n            VectorXf color_instance = morphable_model.get_color_model().draw_sample(color_coefficients);\n            const auto num_vertices = morphable_model.get_color_model().get_data_dimension() /\n                                      3; // will break for gray-level models!\n            Eigen::Map<Eigen::MatrixXf> color_instance_reshaped(\n                color_instance.data(), 3, num_vertices); // Take 3 at a piece, then transpose below\n            viewer.data().set_colors(color_instance_reshaped.transpose().cast<double>());\n        }\n\n        ImGui::End(); // end \"Colour PCA\" window\n\n        // PCA expression coefficients:\n        ImGui::SetNextWindowPos(ImVec2(580.f * menu.menu_scaling(), 0), ImGuiSetCond_FirstUseEver);\n        ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);\n        ImGui::Begin(\"Expression PCA\", nullptr, ImGuiWindowFlags_NoSavedSettings);\n\n        ImGui::Text(\"Coefficients\");\n        if (morphable_model.has_separate_expression_model()) // a model was loaded\n        {\n            int expression_model_num_coeffs = 0;\n            float slider_min_range = -3.0f;\n            float slider_max_range = +3.0f;\n            if (eos::cpp17::holds_alternative<morphablemodel::Blendshapes>(\n                    morphable_model.get_expression_model().value()))\n            {\n                expression_model_num_coeffs = eos::cpp17::get<morphablemodel::Blendshapes>(\n                                                  morphable_model.get_expression_model().value())\n                                                  .size();\n                slider_min_range = -1.0f;\n            } else if (eos::cpp17::holds_alternative<morphablemodel::PcaModel>(\n                           morphable_model.get_expression_model().value()))\n            {\n                expression_model_num_coeffs =\n                    eos::cpp17::get<morphablemodel::PcaModel>(morphable_model.get_expression_model().value())\n                        .get_num_principal_components();\n            }\n\n            int num_expression_coeffs_to_display = std::min(expression_model_num_coeffs, 30);\n\n            if (expression_coefficients.empty() ||\n                expression_coefficients.size() != num_expression_coeffs_to_display)\n            {\n                expression_coefficients.resize(num_expression_coeffs_to_display);\n            }\n            // expression_coefficients are always initialised now.\n\n            ImGui::BeginGroup();\n            for (int i = 0; i < num_expression_coeffs_to_display; ++i)\n            {\n                const string label = std::to_string(i);\n                ImGui::SliderFloat(label.c_str(), &expression_coefficients[i], slider_min_range,\n                                   slider_max_range);\n            }\n            ImGui::EndGroup();\n            string coeffs_displayed = \"Displaying \" + std::to_string(num_expression_coeffs_to_display) + \"/\" +\n                                      std::to_string(expression_model_num_coeffs) + \" coefficients.\";\n            ImGui::Text(coeffs_displayed.c_str());\n\n            // We're not updating the mesh here. The identity-update above already updates it, since we update\n            // in each frame, and not just when a slider has moved. As long as we always have an identity\n            // model, this is fine.\n        }\n\n        ImGui::End(); // end \"Expression PCA\" window\n    };\n\n    viewer.launch();\n\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "initial_cache.cmake.template",
    "content": "# Mechanism via FindLIB.cmake\n# ==============================\n# Boost:\n# -------\n# Windows: Download the pre-built binaries from http://sourceforge.net/projects/boost/files/boost-binaries/ for VS2015 (msvc-14 64bit).\n# Either set the windows PATH variable to \"<YOUR_BOOST_DIRECTORY>\\lib64-msvc-14.0\" and CMake will find it, or, set:\n#set(BOOST_ROOT \"C:/boost\" CACHE PATH \"Boost search location\" FORCE)\n# Linux: Boost can usually be installed via a package manager (e.g. apt-get install boost-all-dev) and this variable can be left uncommented.\n#set(BOOST_ROOT \"/home/user/boost/install\" CACHE PATH \"Boost search location\" FORCE)\n\n\n# Mechanism via ConfigLIB.cmake in 3rd party library directory\n# ==============================\n# OpenCV:\n# -------\n# Windows: Download the package from opencv.org, use 2.4.7.2 or never. It includes binaries for VS2013. Set this path accordingly.\n#set(OpenCV_DIR \"C:/opencv/install\" CACHE PATH \"Location of OpenCVConfig.cmake\" FORCE)\n# Linux: Usually can be left blank but it can be used if OpenCV is not found.\n#set(OpenCV_DIR \"/home/user/opencv/install/share/OpenCV\" CACHE PATH \"Location of OpenCVConfig.cmake\" FORCE)\n"
  }
]