Full Code of patrikhuber/eos-model-viewer for AI

master bf3722a678f9 cached
10 files
83.7 KB
20.6k tokens
142 symbols
1 requests
Download .txt
Repository: patrikhuber/eos-model-viewer
Branch: master
Commit: bf3722a678f9
Files: 10
Total size: 83.7 KB

Directory structure:
gitextract_ir1lx7s3/

├── .clang-format
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── README.md
├── cmake/
│   └── FindLIBIGL.cmake
├── cxxopts.hpp
├── eos-model-viewer.cpp
└── initial_cache.cmake.template

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
---
BasedOnStyle: LLVM
AccessModifierOffset: '-4'
AlwaysBreakTemplateDeclarations: 'true'
BreakBeforeBraces: Custom
BraceWrapping:
  AfterClass:      true
  AfterControlStatement: true
  AfterEnum:       false
  AfterFunction:   true
  AfterNamespace:  false
  AfterObjCDeclaration: false
  AfterStruct:     true
  AfterUnion:      false
  BeforeCatch:     false
  BeforeElse:      false
  IndentBraces:    false
ColumnLimit: '110'
Cpp11BracedListStyle: 'true'
PointerAlignment: Left
IndentWidth: '4'
Language: Cpp
NamespaceIndentation: None
SortIncludes: false
Standard: Cpp11
UseTab: Never
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html

...


================================================
FILE: .gitignore
================================================
# Ignore (optional) configuration files with user-specific paths:
initial_cache.cmake


================================================
FILE: .gitmodules
================================================
[submodule "external/eos"]
	path = external/eos
	url = https://github.com/patrikhuber/eos.git
[submodule "external/libigl"]
	path = external/libigl
	url = https://github.com/libigl/libigl.git


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.1.3)
project(eos-model-viewer)
set(eos-model-viewer_VERSION 0.2.0.alpha)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# This sets the C++ standard to c++14 and required for all the following targets that we define.
# It has no effect on MSVC though - we thus define more specific requirements for each executable target respectively.
# 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.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # This makes CMake use -std=c++11 instead of -std=gnu++11
# This list is likely not complete, but it should be sufficient to error out on old compilers that we cannot build on:
set(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)

# Build a CPack driven installer package:
include(InstallRequiredSystemLibraries) # This module will include any runtime libraries that are needed by the project for the current platform
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION_MAJOR "${eos-model-viewer_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${eos-model-viewer_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${eos-model-viewer_VERSION_PATCH}")
include(CPack)

# Find dependencies:
find_package(OpenCV REQUIRED core)
#check installed version in order to include the correct OpenCV libraries
#version variable is defined from project root's CMakeLists
if("${OpenCV_VERSION_MAJOR}$" EQUAL 2)
  message(STATUS "OpenCV 2.x detected")
  find_package(OpenCV 2.4.3 REQUIRED core)
elseif("${OpenCV_VERSION_MAJOR}$" EQUAL 3)
  message(STATUS "OpenCV 3.x detected - including imgcodecs for compatibility")
  find_package(OpenCV 3 REQUIRED core)
endif()
# This allows us to compile in RelWithDebInfo. It'll use the Release-version of OpenCV:
set_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)

# Include eos. Todo: We should really rather use an import target approach rather than running add_subdirectory here.
set(eos_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/eos")
set(EOS_BUILD_EXAMPLES OFF)
add_subdirectory(${eos_DIR})

######### The following will find libigl, and build everything that's required for the viewer - e.g. GLFW:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(LIBIGL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/libigl/include")

option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" OFF)
option(LIBIGL_WITH_ANTTWEAKBAR       "Use AntTweakBar"    OFF)
option(LIBIGL_WITH_CGAL              "Use CGAL"           OFF)
option(LIBIGL_WITH_COMISO            "Use CoMiso"         OFF)
option(LIBIGL_WITH_CORK              "Use Cork"           OFF)
option(LIBIGL_WITH_EMBREE            "Use Embree"         OFF)
option(LIBIGL_WITH_LIM               "Use LIM"            OFF)
option(LIBIGL_WITH_MATLAB            "Use Matlab"         OFF)
option(LIBIGL_WITH_MOSEK             "Use MOSEK"          OFF)
option(LIBIGL_WITH_OPENGL            "Use OpenGL"         ON)
option(LIBIGL_WITH_OPENGL_GLFW       "Use GLFW"           ON)
option(LIBIGL_WITH_OPENGL_GLFW_IMGUI "Use ImGui"          ON)
option(LIBIGL_WITH_PNG               "Use PNG"            OFF)
option(LIBIGL_WITH_PYTHON            "Use Python"         OFF)
option(LIBIGL_WITH_TETGEN            "Use Tetgen"         OFF)
option(LIBIGL_WITH_TRIANGLE          "Use Triangle"       OFF)
option(LIBIGL_WITH_VIEWER            "Use OpenGL viewer"  ON)
option(LIBIGL_WITH_XML               "Use XML"            OFF)

find_package(LIBIGL REQUIRED)
######### libigl should be set up by now.

# Set up the eos-model-viewer target:
add_executable(eos-model-viewer eos-model-viewer.cpp cxxopts.hpp)
#target_include_directories(eos-model-viewer PRIVATE ${LIBIGL_INCLUDE_DIRS})
#add_definitions(${LIBIGL_DEFINITIONS})
target_compile_features(eos-model-viewer PRIVATE ${eos-model-viewer_CXX_COMPILE_FEATURES})
target_link_libraries(eos-model-viewer eos ${OpenCV_LIBS} igl::core igl::opengl_glfw igl::opengl_glfw_imgui)
target_link_libraries(eos-model-viewer "$<$<CXX_COMPILER_ID:GNU>:-pthread>$<$<CXX_COMPILER_ID:Clang>:-pthreads>")

# Install the binary:
install(TARGETS eos-model-viewer DESTINATION bin)


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# eos-model-viewer
3D model viewer for the eos Morphable Model library

This is a viewer that displays Morphable Models from the eos Morphable Model library ([github.com/patrikhuber/eos](https://github.com/patrikhuber/eos)).
It allows to play around with the shape and colour PCA models as well as the blendshapes.

![Screenshot of the viewer](https://github.com/patrikhuber/eos-model-viewer/blob/master/doc/viewer_screenshot.png)


## Build & installation

It uses libigl's 3D viewer.

**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).
The CMake scripts are in serious alpha-stage - You are on your own compiling it!

Make sure to clone the repository with `--recursive`, or, if already cloned, run `git submodule update --init --recursive`.

## Running the viewer

The 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.


================================================
FILE: cmake/FindLIBIGL.cmake
================================================
# - Try to find the LIBIGL library
# Once done this will define
#
#  LIBIGL_FOUND - system has LIBIGL
#  LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory
if(LIBIGL_FOUND)
    return()
endif()

find_path(LIBIGL_INCLUDE_DIR igl/readOBJ.h
    HINTS
        ENV LIBIGL
        ENV LIBIGLROOT
        ENV LIBIGL_ROOT
        ENV LIBIGL_DIR
    PATHS
        ${CMAKE_SOURCE_DIR}/../..
        ${CMAKE_SOURCE_DIR}/..
        ${CMAKE_SOURCE_DIR}
        ${CMAKE_SOURCE_DIR}/libigl
        ${CMAKE_SOURCE_DIR}/../libigl
        ${CMAKE_SOURCE_DIR}/../../libigl
        /usr
        /usr/local
        /usr/local/igl/libigl
    PATH_SUFFIXES include
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LIBIGL
    "\nlibigl not found --- You can download it using:\n\tgit clone --recursive https://github.com/libigl/libigl.git ${CMAKE_SOURCE_DIR}/../libigl"
    LIBIGL_INCLUDE_DIR)
mark_as_advanced(LIBIGL_INCLUDE_DIR)

list(APPEND CMAKE_MODULE_PATH "${LIBIGL_INCLUDE_DIR}/../cmake")
include(libigl)


================================================
FILE: cxxopts.hpp
================================================
/*

Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

#ifndef CXXOPTS_HPP_INCLUDED
#define CXXOPTS_HPP_INCLUDED

#include <cstring>
#include <cctype>
#include <exception>
#include <iostream>
#include <map>
#include <memory>
#include <regex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#ifdef __cpp_lib_optional
#include <optional>
#define CXXOPTS_HAS_OPTIONAL
#endif

namespace cxxopts
{
  static constexpr struct {
    uint8_t major, minor, patch;
  } version = {2, 1, 0};
}

//when we ask cxxopts to use Unicode, help strings are processed using ICU,
//which results in the correct lengths being computed for strings when they
//are formatted for the help output
//it is necessary to make sure that <unicode/unistr.h> can be found by the
//compiler, and that icu-uc is linked in to the binary.

#ifdef CXXOPTS_USE_UNICODE
#include <unicode/unistr.h>

namespace cxxopts
{
  typedef icu::UnicodeString String;

  inline
  String
  toLocalString(std::string s)
  {
    return icu::UnicodeString::fromUTF8(std::move(s));
  }

  class UnicodeStringIterator : public
    std::iterator<std::forward_iterator_tag, int32_t>
  {
    public:

    UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
    : s(string)
    , i(pos)
    {
    }

    value_type
    operator*() const
    {
      return s->char32At(i);
    }

    bool
    operator==(const UnicodeStringIterator& rhs) const
    {
      return s == rhs.s && i == rhs.i;
    }

    bool
    operator!=(const UnicodeStringIterator& rhs) const
    {
      return !(*this == rhs);
    }

    UnicodeStringIterator&
    operator++()
    {
      ++i;
      return *this;
    }

    UnicodeStringIterator
    operator+(int32_t v)
    {
      return UnicodeStringIterator(s, i + v);
    }

    private:
    const icu::UnicodeString* s;
    int32_t i;
  };

  inline
  String&
  stringAppend(String&s, String a)
  {
    return s.append(std::move(a));
  }

  inline
  String&
  stringAppend(String& s, int n, UChar32 c)
  {
    for (int i = 0; i != n; ++i)
    {
      s.append(c);
    }

    return s;
  }

  template <typename Iterator>
  String&
  stringAppend(String& s, Iterator begin, Iterator end)
  {
    while (begin != end)
    {
      s.append(*begin);
      ++begin;
    }

    return s;
  }

  inline
  size_t
  stringLength(const String& s)
  {
    return s.length();
  }

  inline
  std::string
  toUTF8String(const String& s)
  {
    std::string result;
    s.toUTF8String(result);

    return result;
  }

  inline
  bool
  empty(const String& s)
  {
    return s.isEmpty();
  }
}

namespace std
{
  inline
  cxxopts::UnicodeStringIterator
  begin(const icu::UnicodeString& s)
  {
    return cxxopts::UnicodeStringIterator(&s, 0);
  }

  inline
  cxxopts::UnicodeStringIterator
  end(const icu::UnicodeString& s)
  {
    return cxxopts::UnicodeStringIterator(&s, s.length());
  }
}

//ifdef CXXOPTS_USE_UNICODE
#else

namespace cxxopts
{
  typedef std::string String;

  template <typename T>
  T
  toLocalString(T&& t)
  {
    return t;
  }

  inline
  size_t
  stringLength(const String& s)
  {
    return s.length();
  }

  inline
  String&
  stringAppend(String&s, String a)
  {
    return s.append(std::move(a));
  }

  inline
  String&
  stringAppend(String& s, size_t n, char c)
  {
    return s.append(n, c);
  }

  template <typename Iterator>
  String&
  stringAppend(String& s, Iterator begin, Iterator end)
  {
    return s.append(begin, end);
  }

  template <typename T>
  std::string
  toUTF8String(T&& t)
  {
    return std::forward<T>(t);
  }

  inline
  bool
  empty(const std::string& s)
  {
    return s.empty();
  }
}

//ifdef CXXOPTS_USE_UNICODE
#endif

namespace cxxopts
{
  namespace
  {
#ifdef _WIN32
    const std::string LQUOTE("\'");
    const std::string RQUOTE("\'");
#else
    const std::string LQUOTE("‘");
    const std::string RQUOTE("’");
#endif
  }

  class Value : public std::enable_shared_from_this<Value>
  {
    public:

    virtual ~Value() = default;

    virtual
    std::shared_ptr<Value>
    clone() const = 0;

    virtual void
    parse(const std::string& text) const = 0;

    virtual void
    parse() const = 0;

    virtual bool
    has_default() const = 0;

    virtual bool
    is_container() const = 0;

    virtual bool
    has_implicit() const = 0;

    virtual std::string
    get_default_value() const = 0;

    virtual std::string
    get_implicit_value() const = 0;

    virtual std::shared_ptr<Value>
    default_value(const std::string& value) = 0;

    virtual std::shared_ptr<Value>
    implicit_value(const std::string& value) = 0;

    virtual bool
    is_boolean() const = 0;
  };

  class OptionException : public std::exception
  {
    public:
    OptionException(const std::string& message)
    : m_message(message)
    {
    }

    virtual const char*
    what() const noexcept
    {
      return m_message.c_str();
    }

    private:
    std::string m_message;
  };

  class OptionSpecException : public OptionException
  {
    public:

    OptionSpecException(const std::string& message)
    : OptionException(message)
    {
    }
  };

  class OptionParseException : public OptionException
  {
    public:
    OptionParseException(const std::string& message)
    : OptionException(message)
    {
    }
  };

  class option_exists_error : public OptionSpecException
  {
    public:
    option_exists_error(const std::string& option)
    : OptionSpecException(u8"Option " + LQUOTE + option + RQUOTE + u8" already exists")
    {
    }
  };

  class invalid_option_format_error : public OptionSpecException
  {
    public:
    invalid_option_format_error(const std::string& format)
    : OptionSpecException(u8"Invalid option format " + LQUOTE + format + RQUOTE)
    {
    }
  };

  class option_not_exists_exception : public OptionParseException
  {
    public:
    option_not_exists_exception(const std::string& option)
    : OptionParseException(u8"Option " + LQUOTE + option + RQUOTE + u8" does not exist")
    {
    }
  };

  class missing_argument_exception : public OptionParseException
  {
    public:
    missing_argument_exception(const std::string& option)
    : OptionParseException(
        u8"Option " + LQUOTE + option + RQUOTE + u8" is missing an argument"
      )
    {
    }
  };

  class option_requires_argument_exception : public OptionParseException
  {
    public:
    option_requires_argument_exception(const std::string& option)
    : OptionParseException(
        u8"Option " + LQUOTE + option + RQUOTE + u8" requires an argument"
      )
    {
    }
  };

  class option_not_has_argument_exception : public OptionParseException
  {
    public:
    option_not_has_argument_exception
    (
      const std::string& option,
      const std::string& arg
    )
    : OptionParseException(
        u8"Option " + LQUOTE + option + RQUOTE +
        u8" does not take an argument, but argument " +
        LQUOTE + arg + RQUOTE + " given"
      )
    {
    }
  };

  class option_not_present_exception : public OptionParseException
  {
    public:
    option_not_present_exception(const std::string& option)
    : OptionParseException(u8"Option " + LQUOTE + option + RQUOTE + u8" not present")
    {
    }
  };

  class argument_incorrect_type : public OptionParseException
  {
    public:
    argument_incorrect_type
    (
      const std::string& arg
    )
    : OptionParseException(
        u8"Argument " + LQUOTE + arg + RQUOTE + u8" failed to parse"
      )
    {
    }
  };

  class option_required_exception : public OptionParseException
  {
    public:
    option_required_exception(const std::string& option)
    : OptionParseException(
        u8"Option " + LQUOTE + option + RQUOTE + u8" is required but not present"
      )
    {
    }
  };

  namespace values
  {
    namespace
    {
      std::basic_regex<char> integer_pattern
        ("(-)?(0x)?([1-9a-zA-Z][0-9a-zA-Z]*)|((0x)?0)");
      std::basic_regex<char> truthy_pattern
        ("(t|T)(rue)?");
      std::basic_regex<char> falsy_pattern
        ("((f|F)(alse)?)?");
    }

    namespace detail
    {
      template <typename T, bool B>
      struct SignedCheck;

      template <typename T>
      struct SignedCheck<T, true>
      {
        template <typename U>
        void
        operator()(bool negative, U u, const std::string& text)
        {
          if (negative)
          {
            if (u > static_cast<U>(-std::numeric_limits<T>::min()))
            {
              throw argument_incorrect_type(text);
            }
          }
          else
          {
            if (u > static_cast<U>(std::numeric_limits<T>::max()))
            {
              throw argument_incorrect_type(text);
            }
          }
        }
      };

      template <typename T>
      struct SignedCheck<T, false>
      {
        template <typename U>
        void
        operator()(bool, U, const std::string&) {}
      };

      template <typename T, typename U>
      void
      check_signed_range(bool negative, U value, const std::string& text)
      {
        SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
      }
    }

    template <typename R, typename T>
    R
    checked_negate(T&& t, const std::string&, std::true_type)
    {
      // if we got to here, then `t` is a positive number that fits into
      // `R`. So to avoid MSVC C4146, we first cast it to `R`.
      // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
      return -static_cast<R>(t);
    }

    template <typename R, typename T>
    T
    checked_negate(T&&, const std::string& text, std::false_type)
    {
      throw argument_incorrect_type(text);
    }

    template <typename T>
    void
    integer_parser(const std::string& text, T& value)
    {
      std::smatch match;
      std::regex_match(text, match, integer_pattern);

      if (match.length() == 0)
      {
        throw argument_incorrect_type(text);
      }

      if (match.length(4) > 0)
      {
        value = 0;
        return;
      }

      using US = typename std::make_unsigned<T>::type;

      constexpr auto umax = std::numeric_limits<US>::max();
      constexpr bool is_signed = std::numeric_limits<T>::is_signed;
      const bool negative = match.length(1) > 0;
      const uint8_t base = match.length(2) > 0 ? 16 : 10;

      auto value_match = match[3];

      US result = 0;

      for (auto iter = value_match.first; iter != value_match.second; ++iter)
      {
        size_t digit = 0;

        if (*iter >= '0' && *iter <= '9')
        {
          digit = *iter - '0';
        }
        else if (base == 16 && *iter >= 'a' && *iter <= 'f')
        {
          digit = *iter - 'a' + 10;
        }
        else if (base == 16 && *iter >= 'A' && *iter <= 'F')
        {
          digit = *iter - 'A' + 10;
        }
        else
        {
          throw argument_incorrect_type(text);
        }

        if (umax - digit < result * base)
        {
          throw argument_incorrect_type(text);
        }

        result = result * base + digit;
      }

      detail::check_signed_range<T>(negative, result, text);

      if (negative)
      {
        value = checked_negate<T>(result,
          text,
          std::integral_constant<bool, is_signed>());
      }
      else
      {
        value = result;
      }
    }

    template <typename T>
    void stringstream_parser(const std::string& text, T& value)
    {
      std::stringstream in(text);
      in >> value;
      if (!in) {
        throw argument_incorrect_type(text);
      }
    }

    inline
    void
    parse_value(const std::string& text, uint8_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, int8_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, uint16_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, int16_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, uint32_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, int32_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, uint64_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, int64_t& value)
    {
      integer_parser(text, value);
    }

    inline
    void
    parse_value(const std::string& text, bool& value)
    {
      std::smatch result;
      std::regex_match(text, result, truthy_pattern);

      if (!result.empty())
      {
        value = true;
        return;
      }

      std::regex_match(text, result, falsy_pattern);
      if (!result.empty())
      {
        value = false;
        return;
      }

      throw argument_incorrect_type(text);
    }

    inline
    void
    parse_value(const std::string& text, std::string& value)
    {
      value = text;
    }

    // The fallback parser. It uses the stringstream parser to parse all types
    // that have not been overloaded explicitly.  It has to be placed in the
    // source code before all other more specialized templates.
    template <typename T>
    void
    parse_value(const std::string& text, T& value) {
      stringstream_parser(text, value);
    }

    template <typename T>
    void
    parse_value(const std::string& text, std::vector<T>& value)
    {
      T v;
      parse_value(text, v);
      value.push_back(v);
    }

#ifdef CXXOPTS_HAS_OPTIONAL
    template <typename T>
    void
    parse_value(const std::string& text, std::optional<T>& value)
    {
      T result;
      parse_value(text, result);
      value = std::move(result);
    }
#endif

    template <typename T>
    struct type_is_container
    {
      static constexpr bool value = false;
    };

    template <typename T>
    struct type_is_container<std::vector<T>>
    {
      static constexpr bool value = true;
    };

    template <typename T>
    class abstract_value : public Value
    {
      using Self = abstract_value<T>;

      public:
      abstract_value()
      : m_result(std::make_shared<T>())
      , m_store(m_result.get())
      {
      }

      abstract_value(T* t)
      : m_store(t)
      {
      }

      virtual ~abstract_value() = default;

      abstract_value(const abstract_value& rhs)
      {
        if (rhs.m_result)
        {
          m_result = std::make_shared<T>();
          m_store = m_result.get();
        }
        else
        {
          m_store = rhs.m_store;
        }

        m_default = rhs.m_default;
        m_implicit = rhs.m_implicit;
        m_default_value = rhs.m_default_value;
        m_implicit_value = rhs.m_implicit_value;
      }

      void
      parse(const std::string& text) const
      {
        parse_value(text, *m_store);
      }

      bool
      is_container() const
      {
        return type_is_container<T>::value;
      }

      void
      parse() const
      {
        parse_value(m_default_value, *m_store);
      }

      bool
      has_default() const
      {
        return m_default;
      }

      bool
      has_implicit() const
      {
        return m_implicit;
      }

      std::shared_ptr<Value>
      default_value(const std::string& value)
      {
        m_default = true;
        m_default_value = value;
        return shared_from_this();
      }

      std::shared_ptr<Value>
      implicit_value(const std::string& value)
      {
        m_implicit = true;
        m_implicit_value = value;
        return shared_from_this();
      }

      std::string
      get_default_value() const
      {
        return m_default_value;
      }

      std::string
      get_implicit_value() const
      {
        return m_implicit_value;
      }

      bool
      is_boolean() const
      {
        return std::is_same<T, bool>::value;
      }

      const T&
      get() const
      {
        if (m_store == nullptr)
        {
          return *m_result;
        }
        else
        {
          return *m_store;
        }
      }

      protected:
      std::shared_ptr<T> m_result;
      T* m_store;

      bool m_default = false;
      bool m_implicit = false;

      std::string m_default_value;
      std::string m_implicit_value;
    };

    template <typename T>
    class standard_value : public abstract_value<T>
    {
      public:
      using abstract_value<T>::abstract_value;

      std::shared_ptr<Value>
      clone() const
      {
        return std::make_shared<standard_value<T>>(*this);
      }
    };

    template <>
    class standard_value<bool> : public abstract_value<bool>
    {
      public:
      ~standard_value() = default;

      standard_value()
      {
        set_default_and_implicit();
      }

      standard_value(bool* b)
      : abstract_value(b)
      {
        set_default_and_implicit();
      }

      std::shared_ptr<Value>
      clone() const
      {
        return std::make_shared<standard_value<bool>>(*this);
      }

      private:

      void
      set_default_and_implicit()
      {
        m_default = true;
        m_default_value = "false";
        m_implicit = true;
        m_implicit_value = "true";
      }
    };
  }

  template <typename T>
  std::shared_ptr<Value>
  value()
  {
    return std::make_shared<values::standard_value<T>>();
  }

  template <typename T>
  std::shared_ptr<Value>
  value(T& t)
  {
    return std::make_shared<values::standard_value<T>>(&t);
  }

  class OptionAdder;

  class OptionDetails
  {
    public:
    OptionDetails
    (
      const std::string& short_,
      const std::string& long_,
      const String& desc,
      std::shared_ptr<const Value> val
    )
    : m_short(short_)
    , m_long(long_)
    , m_desc(desc)
    , m_value(val)
    , m_count(0)
    {
    }

    OptionDetails(const OptionDetails& rhs)
    : m_desc(rhs.m_desc)
    , m_count(rhs.m_count)
    {
      m_value = rhs.m_value->clone();
    }

    OptionDetails(OptionDetails&& rhs) = default;

    const String&
    description() const
    {
      return m_desc;
    }

    const Value& value() const {
        return *m_value;
    }

    std::shared_ptr<Value>
    make_storage() const
    {
      return m_value->clone();
    }

    const std::string&
    short_name() const
    {
      return m_short;
    }

    const std::string&
    long_name() const
    {
      return m_long;
    }

    private:
    std::string m_short;
    std::string m_long;
    String m_desc;
    std::shared_ptr<const Value> m_value;
    int m_count;
  };

  struct HelpOptionDetails
  {
    std::string s;
    std::string l;
    String desc;
    bool has_default;
    std::string default_value;
    bool has_implicit;
    std::string implicit_value;
    std::string arg_help;
    bool is_container;
    bool is_boolean;
  };

  struct HelpGroupDetails
  {
    std::string name;
    std::string description;
    std::vector<HelpOptionDetails> options;
  };

  class OptionValue
  {
    public:
    void
    parse
    (
      std::shared_ptr<const OptionDetails> details,
      const std::string& text
    )
    {
      ensure_value(details);
      ++m_count;
      m_value->parse(text);
    }

    void
    parse_default(std::shared_ptr<const OptionDetails> details)
    {
      ensure_value(details);
      m_value->parse();
    }

    size_t
    count() const
    {
      return m_count;
    }

    template <typename T>
    const T&
    as() const
    {
#ifdef CXXOPTS_NO_RTTI
      return static_cast<const values::standard_value<T>&>(*m_value).get();
#else
      return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
#endif
    }

    private:
    void
    ensure_value(std::shared_ptr<const OptionDetails> details)
    {
      if (m_value == nullptr)
      {
        m_value = details->make_storage();
      }
    }

    std::shared_ptr<Value> m_value;
    size_t m_count = 0;
  };

  class KeyValue
  {
    public:
    KeyValue(std::string key_, std::string value_)
    : m_key(std::move(key_))
    , m_value(std::move(value_))
    {
    }

    const
    std::string&
    key() const
    {
      return m_key;
    }

    const std::string
    value() const
    {
      return m_value;
    }

    template <typename T>
    T
    as() const
    {
      T result;
      values::parse_value(m_value, result);
      return result;
    }

    private:
    std::string m_key;
    std::string m_value;
  };

  class ParseResult
  {
    public:

    ParseResult(
      const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&,
      std::vector<std::string>,
      int&, const char**&);

    size_t
    count(const std::string& o) const
    {
      auto iter = m_options.find(o);
      if (iter == m_options.end())
      {
        return 0;
      }

      auto riter = m_results.find(iter->second);

      return riter->second.count();
    }

    const OptionValue&
    operator[](const std::string& option) const
    {
      auto iter = m_options.find(option);

      if (iter == m_options.end())
      {
        throw option_not_present_exception(option);
      }

      auto riter = m_results.find(iter->second);

      return riter->second;
    }

    const std::vector<KeyValue>&
    arguments() const
    {
      return m_sequential;
    }

    private:

    OptionValue&
    get_option(std::shared_ptr<OptionDetails>);

    void
    parse(int& argc, const char**& argv);

    void
    add_to_option(const std::string& option, const std::string& arg);

    bool
    consume_positional(std::string a);

    void
    parse_option
    (
      std::shared_ptr<OptionDetails> value,
      const std::string& name,
      const std::string& arg = ""
    );

    void
    parse_default(std::shared_ptr<OptionDetails> details);

    void
    checked_parse_arg
    (
      int argc,
      const char* argv[],
      int& current,
      std::shared_ptr<OptionDetails> value,
      const std::string& name
    );

    const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
      &m_options;
    std::vector<std::string> m_positional;
    std::vector<std::string>::iterator m_next_positional;
    std::unordered_set<std::string> m_positional_set;
    std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;

    std::vector<KeyValue> m_sequential;
  };

  class Options
  {
    public:

    Options(std::string program, std::string help_string = "")
    : m_program(std::move(program))
    , m_help_string(toLocalString(std::move(help_string)))
    , m_custom_help("[OPTION...]")
    , m_positional_help("positional parameters")
    , m_show_positional(false)
    , m_next_positional(m_positional.end())
    {
    }

    Options&
    positional_help(std::string help_text)
    {
      m_positional_help = std::move(help_text);
      return *this;
    }

    Options&
    custom_help(std::string help_text)
    {
      m_custom_help = std::move(help_text);
      return *this;
    }

    Options&
    show_positional_help()
    {
      m_show_positional = true;
      return *this;
    }

    ParseResult
    parse(int& argc, const char**& argv);

    OptionAdder
    add_options(std::string group = "");

    void
    add_option
    (
      const std::string& group,
      const std::string& s,
      const std::string& l,
      std::string desc,
      std::shared_ptr<const Value> value,
      std::string arg_help
    );

    //parse positional arguments into the given option
    void
    parse_positional(std::string option);

    void
    parse_positional(std::vector<std::string> options);

    void
    parse_positional(std::initializer_list<std::string> options);

    std::string
    help(const std::vector<std::string>& groups = {""}) const;

    const std::vector<std::string>
    groups() const;

    const HelpGroupDetails&
    group_help(const std::string& group) const;

    private:

    void
    add_one_option
    (
      const std::string& option,
      std::shared_ptr<OptionDetails> details
    );

    String
    help_one_group(const std::string& group) const;

    void
    generate_group_help
    (
      String& result,
      const std::vector<std::string>& groups
    ) const;

    void
    generate_all_groups_help(String& result) const;

    std::string m_program;
    String m_help_string;
    std::string m_custom_help;
    std::string m_positional_help;
    bool m_show_positional;

    std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options;
    std::vector<std::string> m_positional;
    std::vector<std::string>::iterator m_next_positional;
    std::unordered_set<std::string> m_positional_set;

    //mapping from groups to help options
    std::map<std::string, HelpGroupDetails> m_help;
  };

  class OptionAdder
  {
    public:

    OptionAdder(Options& options, std::string group)
    : m_options(options), m_group(std::move(group))
    {
    }

    OptionAdder&
    operator()
    (
      const std::string& opts,
      const std::string& desc,
      std::shared_ptr<const Value> value
        = ::cxxopts::value<bool>(),
      std::string arg_help = ""
    );

    private:
    Options& m_options;
    std::string m_group;
  };

  namespace
  {
    constexpr int OPTION_LONGEST = 30;
    constexpr int OPTION_DESC_GAP = 2;

    std::basic_regex<char> option_matcher
      ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");

    std::basic_regex<char> option_specifier
      ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");

    String
    format_option
    (
      const HelpOptionDetails& o
    )
    {
      auto& s = o.s;
      auto& l = o.l;

      String result = "  ";

      if (s.size() > 0)
      {
        result += "-" + toLocalString(s) + ",";
      }
      else
      {
        result += "   ";
      }

      if (l.size() > 0)
      {
        result += " --" + toLocalString(l);
      }

      auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";

      if (!o.is_boolean)
      {
        if (o.has_implicit)
        {
          result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
        }
        else
        {
          result += " " + arg;
        }
      }

      return result;
    }

    String
    format_description
    (
      const HelpOptionDetails& o,
      size_t start,
      size_t width
    )
    {
      auto desc = o.desc;

      if (o.has_default && (!o.is_boolean || o.default_value != "false"))
      {
        desc += toLocalString(" (default: " + o.default_value + ")");
      }

      String result;

      auto current = std::begin(desc);
      auto startLine = current;
      auto lastSpace = current;

      auto size = size_t{};

      while (current != std::end(desc))
      {
        if (*current == ' ')
        {
          lastSpace = current;
        }

        if (size > width)
        {
          if (lastSpace == startLine)
          {
            stringAppend(result, startLine, current + 1);
            stringAppend(result, "\n");
            stringAppend(result, start, ' ');
            startLine = current + 1;
            lastSpace = startLine;
          }
          else
          {
            stringAppend(result, startLine, lastSpace);
            stringAppend(result, "\n");
            stringAppend(result, start, ' ');
            startLine = lastSpace + 1;
          }
          size = 0;
        }
        else
        {
          ++size;
        }

        ++current;
      }

      //append whatever is left
      stringAppend(result, startLine, current);

      return result;
    }
  }

inline
ParseResult::ParseResult
(
  const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>& options,
  std::vector<std::string> positional,
  int& argc, const char**& argv
)
: m_options(options)
, m_positional(std::move(positional))
, m_next_positional(m_positional.begin())
{
  parse(argc, argv);
}

inline
OptionAdder
Options::add_options(std::string group)
{
  return OptionAdder(*this, std::move(group));
}

inline
OptionAdder&
OptionAdder::operator()
(
  const std::string& opts,
  const std::string& desc,
  std::shared_ptr<const Value> value,
  std::string arg_help
)
{
  std::match_results<const char*> result;
  std::regex_match(opts.c_str(), result, option_specifier);

  if (result.empty())
  {
    throw invalid_option_format_error(opts);
  }

  const auto& short_match = result[2];
  const auto& long_match = result[3];

  if (!short_match.length() && !long_match.length())
  {
    throw invalid_option_format_error(opts);
  } else if (long_match.length() == 1 && short_match.length())
  {
    throw invalid_option_format_error(opts);
  }

  auto option_names = []
  (
    const std::sub_match<const char*>& short_,
    const std::sub_match<const char*>& long_
  )
  {
    if (long_.length() == 1)
    {
      return std::make_tuple(long_.str(), short_.str());
    }
    else
    {
      return std::make_tuple(short_.str(), long_.str());
    }
  }(short_match, long_match);

  m_options.add_option
  (
    m_group,
    std::get<0>(option_names),
    std::get<1>(option_names),
    desc,
    value,
    std::move(arg_help)
  );

  return *this;
}

inline
void
ParseResult::parse_default(std::shared_ptr<OptionDetails> details)
{
  m_results[details].parse_default(details);
}

inline
void
ParseResult::parse_option
(
  std::shared_ptr<OptionDetails> value,
  const std::string& /*name*/,
  const std::string& arg
)
{
  auto& result = m_results[value];
  result.parse(value, arg);

  m_sequential.emplace_back(value->long_name(), arg);
}

inline
void
ParseResult::checked_parse_arg
(
  int argc,
  const char* argv[],
  int& current,
  std::shared_ptr<OptionDetails> value,
  const std::string& name
)
{
  if (current + 1 >= argc)
  {
    if (value->value().has_implicit())
    {
      parse_option(value, name, value->value().get_implicit_value());
    }
    else
    {
      throw missing_argument_exception(name);
    }
  }
  else
  {
    if (value->value().has_implicit())
    {
      parse_option(value, name, value->value().get_implicit_value());
    }
    else
    {
      parse_option(value, name, argv[current + 1]);
      ++current;
    }
  }
}

inline
void
ParseResult::add_to_option(const std::string& option, const std::string& arg)
{
  auto iter = m_options.find(option);

  if (iter == m_options.end())
  {
    throw option_not_exists_exception(option);
  }

  parse_option(iter->second, option, arg);
}

inline
bool
ParseResult::consume_positional(std::string a)
{
  while (m_next_positional != m_positional.end())
  {
    auto iter = m_options.find(*m_next_positional);
    if (iter != m_options.end())
    {
      auto& result = m_results[iter->second];
      if (!iter->second->value().is_container())
      {
        if (result.count() == 0)
        {
          add_to_option(*m_next_positional, a);
          ++m_next_positional;
          return true;
        }
        else
        {
          ++m_next_positional;
          continue;
        }
      }
      else
      {
        add_to_option(*m_next_positional, a);
        return true;
      }
    }
    ++m_next_positional;
  }

  return false;
}

inline
void
Options::parse_positional(std::string option)
{
  parse_positional(std::vector<std::string>{std::move(option)});
}

inline
void
Options::parse_positional(std::vector<std::string> options)
{
  m_positional = std::move(options);
  m_next_positional = m_positional.begin();

  m_positional_set.insert(m_positional.begin(), m_positional.end());
}

inline
void
Options::parse_positional(std::initializer_list<std::string> options)
{
  parse_positional(std::vector<std::string>(std::move(options)));
}

inline
ParseResult
Options::parse(int& argc, const char**& argv)
{
  ParseResult result(m_options, m_positional, argc, argv);
  return result;
}

inline
void
ParseResult::parse(int& argc, const char**& argv)
{
  int current = 1;

  int nextKeep = 1;

  bool consume_remaining = false;

  while (current != argc)
  {
    if (strcmp(argv[current], "--") == 0)
    {
      consume_remaining = true;
      ++current;
      break;
    }

    std::match_results<const char*> result;
    std::regex_match(argv[current], result, option_matcher);

    if (result.empty())
    {
      //not a flag

      //if true is returned here then it was consumed, otherwise it is
      //ignored
      if (consume_positional(argv[current]))
      {
      }
      else
      {
        argv[nextKeep] = argv[current];
        ++nextKeep;
      }
      //if we return from here then it was parsed successfully, so continue
    }
    else
    {
      //short or long option?
      if (result[4].length() != 0)
      {
        const std::string& s = result[4];

        for (std::size_t i = 0; i != s.size(); ++i)
        {
          std::string name(1, s[i]);
          auto iter = m_options.find(name);

          if (iter == m_options.end())
          {
            throw option_not_exists_exception(name);
          }

          auto value = iter->second;

          if (i + 1 == s.size())
          {
            //it must be the last argument
            checked_parse_arg(argc, argv, current, value, name);
          }
          else if (value->value().has_implicit())
          {
            parse_option(value, name, value->value().get_implicit_value());
          }
          else
          {
            //error
            throw option_requires_argument_exception(name);
          }
        }
      }
      else if (result[1].length() != 0)
      {
        const std::string& name = result[1];

        auto iter = m_options.find(name);

        if (iter == m_options.end())
        {
          throw option_not_exists_exception(name);
        }

        auto opt = iter->second;

        //equals provided for long option?
        if (result[2].length() != 0)
        {
          //parse the option given

          parse_option(opt, name, result[3]);
        }
        else
        {
          //parse the next argument
          checked_parse_arg(argc, argv, current, opt, name);
        }
      }

    }

    ++current;
  }

  for (auto& opt : m_options)
  {
    auto& detail = opt.second;
    auto& value = detail->value();

    auto& store = m_results[detail];

    if(!store.count() && value.has_default()){
      parse_default(detail);
    }
  }

  if (consume_remaining)
  {
    while (current < argc)
    {
      if (!consume_positional(argv[current])) {
        break;
      }
      ++current;
    }

    //adjust argv for any that couldn't be swallowed
    while (current != argc) {
      argv[nextKeep] = argv[current];
      ++nextKeep;
      ++current;
    }
  }

  argc = nextKeep;

}

inline
void
Options::add_option
(
  const std::string& group,
  const std::string& s,
  const std::string& l,
  std::string desc,
  std::shared_ptr<const Value> value,
  std::string arg_help
)
{
  auto stringDesc = toLocalString(std::move(desc));
  auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);

  if (s.size() > 0)
  {
    add_one_option(s, option);
  }

  if (l.size() > 0)
  {
    add_one_option(l, option);
  }

  //add the help details
  auto& options = m_help[group];

  options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
      value->has_default(), value->get_default_value(),
      value->has_implicit(), value->get_implicit_value(),
      std::move(arg_help),
      value->is_container(),
      value->is_boolean()});
}

inline
void
Options::add_one_option
(
  const std::string& option,
  std::shared_ptr<OptionDetails> details
)
{
  auto in = m_options.emplace(option, details);

  if (!in.second)
  {
    throw option_exists_error(option);
  }
}

inline
String
Options::help_one_group(const std::string& g) const
{
  typedef std::vector<std::pair<String, String>> OptionHelp;

  auto group = m_help.find(g);
  if (group == m_help.end())
  {
    return "";
  }

  OptionHelp format;

  size_t longest = 0;

  String result;

  if (!g.empty())
  {
    result += toLocalString(" " + g + " options:\n");
  }

  for (const auto& o : group->second.options)
  {
    if (o.is_container &&
        m_positional_set.find(o.l) != m_positional_set.end() &&
        !m_show_positional)
    {
      continue;
    }

    auto s = format_option(o);
    longest = std::max(longest, stringLength(s));
    format.push_back(std::make_pair(s, String()));
  }

  longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));

  //widest allowed description
  auto allowed = size_t{76} - longest - OPTION_DESC_GAP;

  auto fiter = format.begin();
  for (const auto& o : group->second.options)
  {
    if (o.is_container &&
        m_positional_set.find(o.l) != m_positional_set.end() &&
        !m_show_positional)
    {
      continue;
    }

    auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);

    result += fiter->first;
    if (stringLength(fiter->first) > longest)
    {
      result += '\n';
      result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
    }
    else
    {
      result += toLocalString(std::string(longest + OPTION_DESC_GAP -
        stringLength(fiter->first),
        ' '));
    }
    result += d;
    result += '\n';

    ++fiter;
  }

  return result;
}

inline
void
Options::generate_group_help
(
  String& result,
  const std::vector<std::string>& print_groups
) const
{
  for (size_t i = 0; i != print_groups.size(); ++i)
  {
    const String& group_help_text = help_one_group(print_groups[i]);
    if (empty(group_help_text))
    {
      continue;
    }
    result += group_help_text;
    if (i < print_groups.size() - 1)
    {
      result += '\n';
    }
  }
}

inline
void
Options::generate_all_groups_help(String& result) const
{
  std::vector<std::string> all_groups;
  all_groups.reserve(m_help.size());

  for (auto& group : m_help)
  {
    all_groups.push_back(group.first);
  }

  generate_group_help(result, all_groups);
}

inline
std::string
Options::help(const std::vector<std::string>& help_groups) const
{
  String result = m_help_string + "\nUsage:\n  " +
    toLocalString(m_program) + " " + toLocalString(m_custom_help);

  if (m_positional.size() > 0 && m_positional_help.size() > 0) {
    result += " " + toLocalString(m_positional_help);
  }

  result += "\n\n";

  if (help_groups.size() == 0)
  {
    generate_all_groups_help(result);
  }
  else
  {
    generate_group_help(result, help_groups);
  }

  return toUTF8String(result);
}

inline
const std::vector<std::string>
Options::groups() const
{
  std::vector<std::string> g;

  std::transform(
    m_help.begin(),
    m_help.end(),
    std::back_inserter(g),
    [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
    {
      return pair.first;
    }
  );

  return g;
}

inline
const HelpGroupDetails&
Options::group_help(const std::string& group) const
{
  return m_help.at(group);
}

}

#endif //CXXOPTS_HPP_INCLUDED


================================================
FILE: eos-model-viewer.cpp
================================================
/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: eos-model-viewer.cpp
 *
 * Copyright 2017, 2018 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "cxxopts.hpp"

#include "eos/core/Mesh.hpp"
#include "eos/morphablemodel/MorphableModel.hpp"
#include "eos/morphablemodel/io/cvssp.hpp"
#include "eos/morphablemodel/Blendshape.hpp"
#include "eos/cpp17/variant.hpp"

#include "igl/opengl/glfw/Viewer.h"
#include "igl/opengl/glfw/imgui/ImGuiMenu.h"
#include "igl/opengl/glfw/imgui/ImGuiHelpers.h"
#include "imgui/imgui.h"

#include <iostream>
#include <sstream>
#include <iomanip>
#include <random>
#include <algorithm>

template <typename T>
std::string to_string(const T a_value, const int n = 6)
{
    std::ostringstream out;
    out << std::setprecision(n) << a_value;
    return out.str();
};

// From: https://stackoverflow.com/a/1493195/1345959
template <class ContainerType>
void tokenize(const std::string& str, ContainerType& tokens, const std::string& delimiters = " ",
              bool trim_empty = false)
{
    std::string::size_type pos, last_pos = 0;
    const auto length = str.length();

    using value_type = typename ContainerType::value_type;
    using size_type = typename ContainerType::size_type;

    while (last_pos < length + 1)
    {
        pos = str.find_first_of(delimiters, last_pos);
        if (pos == std::string::npos)
        {
            pos = length;
        }

        if (pos != last_pos || !trim_empty)
            tokens.push_back(value_type(str.data() + last_pos, (size_type)pos - last_pos));

        last_pos = pos + 1;
    }
};

eos::morphablemodel::MorphableModel load_bin_or_scm_model(std::string model_file)
{
    using namespace eos;
    using eos::morphablemodel::MorphableModel;

    MorphableModel morphable_model;

    std::vector<std::string> tokens;
    tokenize(model_file, tokens, ".");
    const auto model_file_extension = tokens.back();

    // Todo: Add try-catch to all these?
    if (model_file_extension == "scm")
    {
        morphable_model = morphablemodel::load_scm_model(model_file);
    } else if (model_file_extension == "bin")
    {
        morphable_model = morphablemodel::load_model(model_file);
    } else
    {
        throw std::runtime_error("Error: Please load a model with .bin or .scm extension.");
    }
    return morphable_model;
}

/**
 *
 */
eos::morphablemodel::MorphableModel load_model(std::string model_file, std::string blendshapes_file)
{
    using namespace eos;
    using eos::morphablemodel::MorphableModel;

    MorphableModel morphable_model;

    // Todo: Add try-catch to all these?
    morphable_model = load_bin_or_scm_model(model_file);
    // If separate blendshapes are given, load them, and construct a model with expressions:
    if (!blendshapes_file.empty())
    {
        const auto blendshapes = morphablemodel::load_blendshapes(blendshapes_file);
        morphable_model = MorphableModel(
            morphable_model.get_shape_model(), blendshapes, morphable_model.get_color_model(),
            morphable_model.get_landmark_definitions(), morphable_model.get_texture_coordinates());
    }
    return morphable_model;
};

/**
 * Model viewer for 3D Morphable Models.
 */
int main(int argc, const char* argv[])
{
    using namespace eos;
    using Eigen::VectorXf;
    using std::begin;
    using std::cout;
    using std::end;
    using std::endl;
    using std::for_each;
    using std::string;
    using std::vector;

    string model_file, blendshapes_file;
    try
    {
        cxxopts::Options options("eos-model-viewer", "OpenGL viewer for eos's 3D morphable models.");
        // clang-format off
        options.add_options()
            ("h,help", "display the help message")
            ("m,model", "an eos 3D Morphable Model stored as cereal BinaryArchive (.bin)",
                cxxopts::value(model_file))
            ("b,blendshapes", "an eos file with blendshapes (.bin)",
                cxxopts::value(blendshapes_file));
        // clang-format on
        const auto result = options.parse(argc, argv);
        if (result.count("help"))
        {
            cout << options.help() << endl;
            return EXIT_SUCCESS;
        }
    } catch (const cxxopts::OptionException& e)
    {
        cout << "Error parsing options: " << e.what() << endl;
        return EXIT_FAILURE;
    }

    // Note: Take the vertices here directly, so we can maybe avoid ever generating a Mesh instance
    auto get_V = [](const core::Mesh& mesh) {
        Eigen::MatrixXd V(mesh.vertices.size(), 3);
        for (int i = 0; i < mesh.vertices.size(); ++i)
        {
            V(i, 0) = mesh.vertices[i](0);
            V(i, 1) = mesh.vertices[i](1);
            V(i, 2) = mesh.vertices[i](2);
        }
        return V;
    };
    auto get_F = [](const core::Mesh& mesh) {
        Eigen::MatrixXi F(mesh.tvi.size(), 3);
        for (int i = 0; i < mesh.tvi.size(); ++i)
        {
            F(i, 0) = mesh.tvi[i][0];
            F(i, 1) = mesh.tvi[i][1];
            F(i, 2) = mesh.tvi[i][2];
        }
        return F;
    };
    auto get_C = [](const core::Mesh& mesh) {
        Eigen::MatrixXd C(mesh.colors.size(), 3);
        for (int i = 0; i < mesh.colors.size(); ++i)
        {
            C(i, 0) = mesh.colors[i](0);
            C(i, 1) = mesh.colors[i](1);
            C(i, 2) = mesh.colors[i](2);
        }
        return C;
    };

    // Init the viewer:
    igl::opengl::glfw::Viewer viewer;

    // Attach a menu plugin:
    igl::opengl::glfw::imgui::ImGuiMenu menu;
    viewer.plugins.push_back(&menu);

    morphablemodel::MorphableModel morphable_model;
    // Load the model right away on start up, if it was given via command-line parameters:
    if (!model_file.empty())
    {
        try
        {
            // Loads a .bin or .scm model, with or without blendshapes:
            morphable_model = load_model(model_file, blendshapes_file);
            const auto& mean = morphable_model.get_mean();
            viewer.data().set_mesh(get_V(mean), get_F(mean));
            viewer.core.align_camera_center(viewer.data().V, viewer.data().F);
            if (!mean.colors.empty())
            {
                viewer.data().set_colors(get_C(mean));
            }

        } catch (const std::runtime_error& e)
        {
            cout << "Error loading the given model: " << e.what() << endl;
            return EXIT_FAILURE;
        }
    }

    // These are the coefficients of the currently active mesh instance:
    vector<float> shape_coefficients;
    vector<float> color_coefficients;
    vector<float> expression_coefficients;
    bool display_identity_model_only = true;

    std::default_random_engine rng;
    std::array<float, 3> random_sample_sdev = {1.0f, 1.0f, 1.0f}; // shp, exp, col

    // Draw our viewers windows:
    menu.callback_draw_custom_window = [&]() {
        // Load model & draw sample options:
        ImGui::SetNextWindowPos(ImVec2(0.f * menu.menu_scaling(), 585), ImGuiSetCond_FirstUseEver);
        ImGui::SetNextWindowSize(ImVec2(240, 280), ImGuiSetCond_FirstUseEver);
        ImGui::Begin("Morphable Model", nullptr, ImGuiWindowFlags_NoSavedSettings);
        if (ImGui::Button("Load Morphable Model", ImVec2(-1, 0)))
        {
            const string mm_fn = igl::file_dialog_open();
            cout << "Loading Morphable Model " << mm_fn << "..." << endl;
            try
            {
                morphable_model = load_bin_or_scm_model(mm_fn);
                const auto& mean = morphable_model.get_mean();
                viewer.data().clear();
                viewer.data().set_mesh(get_V(mean), get_F(mean));
                viewer.core.align_camera_center(viewer.data().V, viewer.data().F);
                if (!mean.colors.empty())
                {
                    viewer.data().set_colors(get_C(mean));
                }
            } catch (const std::runtime_error&
                         e) // Todo: I think we have to catch more errors here, like cereal exceptions
            {
                cout << "Error loading the given model: " << e.what() << endl;
            }
            if (morphable_model.has_separate_expression_model())
            {
                // Just a sensible default - if the loaded model has expressions, use them by default:
                display_identity_model_only = false;
            }
        }
        if (ImGui::Button("Load Blendshapes", ImVec2(-1, 0)))
        {
            const string bs_fn = igl::file_dialog_open();
            cout << "Loading Blendshapes " << bs_fn << "..." << endl;
            morphablemodel::Blendshapes blendshapes;
            try
            {
                blendshapes = morphablemodel::load_blendshapes(bs_fn);
                cout << "Blendshapes loaded. Constructing a new model consisting of the loaded identity and "
                        "colour PCA models, and the loaded blendshapes..."
                     << endl;
                morphable_model = morphablemodel::MorphableModel(
                    morphable_model.get_shape_model(), blendshapes, morphable_model.get_color_model(),
                    morphable_model.get_landmark_definitions(), morphable_model.get_texture_coordinates());
                const auto& mean = morphable_model.get_mean();
                viewer.data().clear();
                viewer.data().set_mesh(get_V(mean), get_F(mean));
                viewer.core.align_camera_center(viewer.data().V, viewer.data().F);
                if (!mean.colors.empty())
                {
                    viewer.data().set_colors(get_C(mean));
                }

            } catch (const std::runtime_error&
                         e) // Todo: I think we have to catch more errors here, like cereal exceptions
            {
                cout << "Error loading the given blendshapes: " << e.what() << endl;
            }
            display_identity_model_only = false;
        }
        ImGui::Separator();
        if (ImGui::Button("Mean (id)", ImVec2(-1, 0)))
        {
            Eigen::VectorXf mean = morphable_model.get_shape_model().get_mean();
            // Take 3 at a piece, then transpose:
            const auto num_vertices = mean.rows() / 3;
            Eigen::Map<Eigen::MatrixXf> mean_reshaped(mean.data(), 3, num_vertices);
            viewer.data().set_vertices(mean_reshaped.transpose().cast<double>());

            if (morphable_model.get_color_model().get_mean().size() > 0)
            {
                Eigen::VectorXf color_mean = morphable_model.get_color_model().get_mean();
                Eigen::Map<Eigen::MatrixXf> color_mean_reshaped(
                    color_mean.data(), 3,
                    color_mean.rows() / 3); // Todo: This will fail for gray-level models
                viewer.data().set_colors(color_mean_reshaped.transpose().cast<double>());
            }

            for_each(begin(shape_coefficients), end(shape_coefficients), [](auto& coeff) { coeff = 0.0f; });
            for_each(begin(color_coefficients), end(color_coefficients), [](auto& coeff) { coeff = 0.0f; });
            for_each(begin(expression_coefficients), end(expression_coefficients),
                     [](auto& coeff) { coeff = 0.0f; });
            display_identity_model_only = true;
        }
        if (ImGui::Button("Mean (id+exp)", ImVec2(-1, 0)))
        {
            const auto mean = morphable_model.get_mean();
            viewer.data().set_vertices(get_V(mean));
            if (!mean.colors.empty())
            {
                viewer.data().set_colors(get_C(mean));
            }
            for_each(begin(shape_coefficients), end(shape_coefficients), [](auto& coeff) { coeff = 0.0f; });
            for_each(begin(color_coefficients), end(color_coefficients), [](auto& coeff) { coeff = 0.0f; });
            for_each(begin(expression_coefficients), end(expression_coefficients),
                     [](auto& coeff) { coeff = 0.0f; });
            display_identity_model_only = false;
        }
        ImGui::Separator();
        if (ImGui::Button("Random face sample", ImVec2(-1, 0)))
        {
            // Shape sample:
            std::normal_distribution<float> shape_coeffs_dist(0.0f,
                                                              random_sample_sdev[0]); // c'tor takes stddev
            shape_coefficients =
                vector<float>(morphable_model.get_shape_model().get_num_principal_components());
            for_each(begin(shape_coefficients), end(shape_coefficients),
                     [&rng, &shape_coeffs_dist](auto& coeff) { coeff = shape_coeffs_dist(rng); });
            // Expression sample:
            if (morphable_model.has_separate_expression_model())
            {

                if (eos::cpp17::holds_alternative<morphablemodel::Blendshapes>(
                        morphable_model.get_expression_model().value()))
                {
                    std::uniform_real_distribution<float> expression_coeffs_dist(
                        0.0f,
                        random_sample_sdev[1]); // using the interval [0, sdev] (so it's not really an sdev
                                                // here!)
                    const auto expression_model_num_coeffs =
                        eos::cpp17::get<morphablemodel::Blendshapes>(
                            morphable_model.get_expression_model().value())
                            .size();
                    expression_coefficients = vector<float>(expression_model_num_coeffs);
                    for_each(begin(expression_coefficients), end(expression_coefficients),
                             [&rng, &expression_coeffs_dist](auto& coeff) {
                                 coeff = expression_coeffs_dist(rng);
                             });

                } else if (eos::cpp17::holds_alternative<morphablemodel::PcaModel>(
                               morphable_model.get_expression_model().value()))
                {
                    std::normal_distribution<float> expression_coeffs_dist(0.0f, random_sample_sdev[1]);
                    const auto expression_model_num_coeffs =
                        eos::cpp17::get<morphablemodel::PcaModel>(
                            morphable_model.get_expression_model().value())
                            .get_num_principal_components();
                    expression_coefficients = vector<float>(expression_model_num_coeffs);
                    for_each(begin(expression_coefficients), end(expression_coefficients),
                             [&rng, &expression_coeffs_dist](auto& coeff) {
                                 coeff = expression_coeffs_dist(rng);
                             });
                }
            }
            // Colour sample:
            std::normal_distribution<float> color_coeffs_dist(0.0f, random_sample_sdev[2]);
            color_coefficients =
                vector<float>(morphable_model.get_color_model().get_num_principal_components());
            for_each(begin(color_coefficients), end(color_coefficients),
                     [&rng, &color_coeffs_dist](auto& coeff) { coeff = color_coeffs_dist(rng); });

            // Now generate the sample:
            core::Mesh sample;
            // Note: Can it happen that we pass in colour-coeffs, but it's a model without colour?
            if (morphable_model.has_separate_expression_model())
            {
                sample = morphable_model.draw_sample(shape_coefficients, expression_coefficients,
                                                     color_coefficients);
            } else
            {
                sample = morphable_model.draw_sample(shape_coefficients, color_coefficients);
            }
            viewer.data().set_vertices(get_V(sample));
            if (!sample.colors.empty())
            {
                viewer.data().set_colors(get_C(sample));
            }
        }
        /* // Not yet implemented:
        if (ImGui::Button("Random identity sample", ImVec2(-1, 0)))
        {
        }
        if (ImGui::Button("Random expression sample", ImVec2(-1, 0)))
        {
        }
        if (ImGui::Button("Random color sample", ImVec2(-1, 0)))
        {
        }
        */
        ImGui::InputFloat3("sdev [shp, exp, col]", &random_sample_sdev[0], 2);
        ImGui::Checkbox("Identity model only", &display_identity_model_only);
        ImGui::End(); // end "Morphable Model" window

        // PCA shape coefficients:
        ImGui::SetNextWindowPos(ImVec2(180.f * menu.menu_scaling(), 0), ImGuiSetCond_FirstUseEver);
        ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);
        ImGui::Begin("Shape PCA", nullptr, ImGuiWindowFlags_NoSavedSettings);

        ImGui::Text("Coefficients");
        if (morphable_model.get_shape_model().get_num_principal_components() > 0) // a model was loaded
        {
            int num_shape_coeffs_to_display =
                std::min(morphable_model.get_shape_model().get_num_principal_components(), 30);

            if (shape_coefficients.empty() || shape_coefficients.size() != num_shape_coeffs_to_display)
            {
                // no coeffs yet, or number of coeffs has changed for some reason:
                shape_coefficients.resize(num_shape_coeffs_to_display);
            }
            // shape_coefficients are always initialised now.

            ImGui::BeginGroup();
            for (int i = 0; i < num_shape_coeffs_to_display; ++i)
            {
                const string label = std::to_string(i);
                ImGui::SliderFloat(label.c_str(), &shape_coefficients[i], -3.0, 3.0);
            }
            ImGui::EndGroup();
            string coeffs_displayed =
                "Displaying " + std::to_string(num_shape_coeffs_to_display) + "/" +
                std::to_string(morphable_model.get_shape_model().get_num_principal_components()) +
                " coefficients.";
            ImGui::Text(coeffs_displayed.c_str());

            // We've got a shape model. So update the mesh that's been drawn with the value of the
            // coefficients. Note that we are currently doing this every draw call, not only when the
            // slider changes. See eos-model-viewer/issues/5.
            VectorXf shape_instance = morphable_model.get_shape_model().draw_sample(shape_coefficients);
            const auto num_vertices = morphable_model.get_shape_model().get_data_dimension() / 3;
            // If expression coeffs are set, add the expression part:
            if (!expression_coefficients.empty() && morphable_model.has_separate_expression_model() &&
                !display_identity_model_only)
            {
                if (eos::cpp17::holds_alternative<morphablemodel::PcaModel>(
                        morphable_model.get_expression_model().value()))
                {
                    const auto& expression_model = eos::cpp17::get<morphablemodel::PcaModel>(
                        morphable_model.get_expression_model().value());
                    const VectorXf expression_instance =
                        expression_model.draw_sample(expression_coefficients);
                    shape_instance += expression_instance;
                } else if (eos::cpp17::holds_alternative<morphablemodel::Blendshapes>(
                               morphable_model.get_expression_model().value()))
                {
                    const auto& blendshapes = eos::cpp17::get<morphablemodel::Blendshapes>(
                        morphable_model.get_expression_model().value());
                    for (int i = 0; i < blendshapes.size(); ++i)
                    {
                        shape_instance += blendshapes[i].deformation * expression_coefficients[i];
                    }
                }
            }
            Eigen::Map<Eigen::MatrixXf> shape_instance_reshaped(
                shape_instance.data(), 3, num_vertices); // Take 3 at a piece, then transpose below
            viewer.data().set_vertices(shape_instance_reshaped.transpose().cast<double>());
        }

        ImGui::End(); // end "Shape PCA" window

        // PCA colour coefficients:
        ImGui::SetNextWindowPos(ImVec2(380.f * menu.menu_scaling(), 0), ImGuiSetCond_FirstUseEver);
        ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);
        ImGui::Begin("Colour PCA", nullptr, ImGuiWindowFlags_NoSavedSettings);

        ImGui::Text("Coefficients");
        if (morphable_model.get_color_model().get_num_principal_components() > 0) // a model was loaded
        {
            int num_color_coeffs_to_display =
                std::min(morphable_model.get_color_model().get_num_principal_components(), 30);

            if (color_coefficients.empty() || color_coefficients.size() != num_color_coeffs_to_display)
            {
                color_coefficients.resize(num_color_coeffs_to_display);
            }
            // color_coefficients are always initialised now.

            ImGui::BeginGroup();
            for (int i = 0; i < num_color_coeffs_to_display; ++i)
            {
                const string label = std::to_string(i);
                ImGui::SliderFloat(label.c_str(), &color_coefficients[i], -3.0, 3.0);
            }
            ImGui::EndGroup();
            string coeffs_displayed =
                "Displaying " + std::to_string(num_color_coeffs_to_display) + "/" +
                std::to_string(morphable_model.get_color_model().get_num_principal_components()) +
                " coefficients.";
            ImGui::Text(coeffs_displayed.c_str());

            // We've got a colour model. So update the mesh that's been drawn with the value of the
            // coefficients. Note that we are currently doing this every draw call, not only when the
            // slider changes. See eos-model-viewer/issues/5.
            VectorXf color_instance = morphable_model.get_color_model().draw_sample(color_coefficients);
            const auto num_vertices = morphable_model.get_color_model().get_data_dimension() /
                                      3; // will break for gray-level models!
            Eigen::Map<Eigen::MatrixXf> color_instance_reshaped(
                color_instance.data(), 3, num_vertices); // Take 3 at a piece, then transpose below
            viewer.data().set_colors(color_instance_reshaped.transpose().cast<double>());
        }

        ImGui::End(); // end "Colour PCA" window

        // PCA expression coefficients:
        ImGui::SetNextWindowPos(ImVec2(580.f * menu.menu_scaling(), 0), ImGuiSetCond_FirstUseEver);
        ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);
        ImGui::Begin("Expression PCA", nullptr, ImGuiWindowFlags_NoSavedSettings);

        ImGui::Text("Coefficients");
        if (morphable_model.has_separate_expression_model()) // a model was loaded
        {
            int expression_model_num_coeffs = 0;
            float slider_min_range = -3.0f;
            float slider_max_range = +3.0f;
            if (eos::cpp17::holds_alternative<morphablemodel::Blendshapes>(
                    morphable_model.get_expression_model().value()))
            {
                expression_model_num_coeffs = eos::cpp17::get<morphablemodel::Blendshapes>(
                                                  morphable_model.get_expression_model().value())
                                                  .size();
                slider_min_range = -1.0f;
            } else if (eos::cpp17::holds_alternative<morphablemodel::PcaModel>(
                           morphable_model.get_expression_model().value()))
            {
                expression_model_num_coeffs =
                    eos::cpp17::get<morphablemodel::PcaModel>(morphable_model.get_expression_model().value())
                        .get_num_principal_components();
            }

            int num_expression_coeffs_to_display = std::min(expression_model_num_coeffs, 30);

            if (expression_coefficients.empty() ||
                expression_coefficients.size() != num_expression_coeffs_to_display)
            {
                expression_coefficients.resize(num_expression_coeffs_to_display);
            }
            // expression_coefficients are always initialised now.

            ImGui::BeginGroup();
            for (int i = 0; i < num_expression_coeffs_to_display; ++i)
            {
                const string label = std::to_string(i);
                ImGui::SliderFloat(label.c_str(), &expression_coefficients[i], slider_min_range,
                                   slider_max_range);
            }
            ImGui::EndGroup();
            string coeffs_displayed = "Displaying " + std::to_string(num_expression_coeffs_to_display) + "/" +
                                      std::to_string(expression_model_num_coeffs) + " coefficients.";
            ImGui::Text(coeffs_displayed.c_str());

            // We're not updating the mesh here. The identity-update above already updates it, since we update
            // in each frame, and not just when a slider has moved. As long as we always have an identity
            // model, this is fine.
        }

        ImGui::End(); // end "Expression PCA" window
    };

    viewer.launch();

    return EXIT_SUCCESS;
}


================================================
FILE: initial_cache.cmake.template
================================================
# Mechanism via FindLIB.cmake
# ==============================
# Boost:
# -------
# Windows: Download the pre-built binaries from http://sourceforge.net/projects/boost/files/boost-binaries/ for VS2015 (msvc-14 64bit).
# Either set the windows PATH variable to "<YOUR_BOOST_DIRECTORY>\lib64-msvc-14.0" and CMake will find it, or, set:
#set(BOOST_ROOT "C:/boost" CACHE PATH "Boost search location" FORCE)
# 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.
#set(BOOST_ROOT "/home/user/boost/install" CACHE PATH "Boost search location" FORCE)


# Mechanism via ConfigLIB.cmake in 3rd party library directory
# ==============================
# OpenCV:
# -------
# Windows: Download the package from opencv.org, use 2.4.7.2 or never. It includes binaries for VS2013. Set this path accordingly.
#set(OpenCV_DIR "C:/opencv/install" CACHE PATH "Location of OpenCVConfig.cmake" FORCE)
# Linux: Usually can be left blank but it can be used if OpenCV is not found.
#set(OpenCV_DIR "/home/user/opencv/install/share/OpenCV" CACHE PATH "Location of OpenCVConfig.cmake" FORCE)
Download .txt
gitextract_ir1lx7s3/

├── .clang-format
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── README.md
├── cmake/
│   └── FindLIBIGL.cmake
├── cxxopts.hpp
├── eos-model-viewer.cpp
└── initial_cache.cmake.template
Download .txt
SYMBOL INDEX (142 symbols across 2 files)

FILE: cxxopts.hpp
  type cxxopts (line 46) | namespace cxxopts
    function String (line 66) | inline
    class UnicodeStringIterator (line 73) | class UnicodeStringIterator : public
      method UnicodeStringIterator (line 78) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
      method value_type (line 84) | value_type
      method UnicodeStringIterator (line 102) | UnicodeStringIterator&
      method UnicodeStringIterator (line 109) | UnicodeStringIterator
    function String (line 120) | inline
    function String (line 127) | inline
    function String (line 140) | String&
    function stringLength (line 152) | inline
    function toUTF8String (line 159) | inline
    function empty (line 169) | inline
    function T (line 202) | T
    function stringLength (line 208) | inline
    function String (line 215) | inline
    function String (line 222) | inline
    function String (line 230) | String&
    function toUTF8String (line 237) | std::string
    function empty (line 243) | inline
    class Value (line 267) | class Value : public std::enable_shared_from_this<Value>
    class OptionException (line 308) | class OptionException : public std::exception
      method OptionException (line 311) | OptionException(const std::string& message)
    class OptionSpecException (line 326) | class OptionSpecException : public OptionException
      method OptionSpecException (line 330) | OptionSpecException(const std::string& message)
    class OptionParseException (line 336) | class OptionParseException : public OptionException
      method OptionParseException (line 339) | OptionParseException(const std::string& message)
    class option_exists_error (line 345) | class option_exists_error : public OptionSpecException
      method option_exists_error (line 348) | option_exists_error(const std::string& option)
    class invalid_option_format_error (line 354) | class invalid_option_format_error : public OptionSpecException
      method invalid_option_format_error (line 357) | invalid_option_format_error(const std::string& format)
    class option_not_exists_exception (line 363) | class option_not_exists_exception : public OptionParseException
      method option_not_exists_exception (line 366) | option_not_exists_exception(const std::string& option)
    class missing_argument_exception (line 372) | class missing_argument_exception : public OptionParseException
      method missing_argument_exception (line 375) | missing_argument_exception(const std::string& option)
    class option_requires_argument_exception (line 383) | class option_requires_argument_exception : public OptionParseException
      method option_requires_argument_exception (line 386) | option_requires_argument_exception(const std::string& option)
    class option_not_has_argument_exception (line 394) | class option_not_has_argument_exception : public OptionParseException
      method option_not_has_argument_exception (line 397) | option_not_has_argument_exception
    class option_not_present_exception (line 411) | class option_not_present_exception : public OptionParseException
      method option_not_present_exception (line 414) | option_not_present_exception(const std::string& option)
    class argument_incorrect_type (line 420) | class argument_incorrect_type : public OptionParseException
      method argument_incorrect_type (line 423) | argument_incorrect_type
    class option_required_exception (line 434) | class option_required_exception : public OptionParseException
      method option_required_exception (line 437) | option_required_exception(const std::string& option)
    type values (line 445) | namespace values
      type detail (line 457) | namespace detail
        type SignedCheck (line 460) | struct SignedCheck
        type SignedCheck<T, true> (line 463) | struct SignedCheck<T, true>
        type SignedCheck<T, false> (line 487) | struct SignedCheck<T, false>
        function check_signed_range (line 495) | void
      function R (line 503) | R
      function T (line 513) | T
      function integer_parser (line 520) | void
      function stringstream_parser (line 592) | void stringstream_parser(const std::string& text, T& value)
      function parse_value (line 601) | inline
      function parse_value (line 608) | inline
      function parse_value (line 615) | inline
      function parse_value (line 622) | inline
      function parse_value (line 629) | inline
      function parse_value (line 636) | inline
      function parse_value (line 643) | inline
      function parse_value (line 650) | inline
      function parse_value (line 657) | inline
      function parse_value (line 680) | inline
      function parse_value (line 691) | void
      function parse_value (line 697) | void
      function parse_value (line 707) | void
      type type_is_container (line 717) | struct type_is_container
      type type_is_container<std::vector<T>> (line 723) | struct type_is_container<std::vector<T>>
      class abstract_value (line 729) | class abstract_value : public Value
        method abstract_value (line 734) | abstract_value()
        method abstract_value (line 740) | abstract_value(T* t)
        method abstract_value (line 747) | abstract_value(const abstract_value& rhs)
        method parse (line 765) | void
        method is_container (line 771) | bool
        method parse (line 777) | void
        method has_default (line 783) | bool
        method has_implicit (line 789) | bool
        method default_value (line 795) | std::shared_ptr<Value>
        method implicit_value (line 803) | std::shared_ptr<Value>
        method get_default_value (line 811) | std::string
        method get_implicit_value (line 817) | std::string
        method is_boolean (line 823) | bool
        method T (line 829) | const T&
      class standard_value (line 854) | class standard_value : public abstract_value<T>
        method clone (line 859) | std::shared_ptr<Value>
      class standard_value<bool> (line 867) | class standard_value<bool> : public abstract_value<bool>
        method standard_value (line 872) | standard_value()
        method standard_value (line 877) | standard_value(bool* b)
        method clone (line 883) | std::shared_ptr<Value>
        method set_default_and_implicit (line 891) | void
    function value (line 903) | std::shared_ptr<Value>
    function value (line 910) | std::shared_ptr<Value>
    class OptionAdder (line 916) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    class OptionDetails (line 918) | class OptionDetails
      method OptionDetails (line 921) | OptionDetails
      method OptionDetails (line 936) | OptionDetails(const OptionDetails& rhs)
      method OptionDetails (line 943) | OptionDetails(OptionDetails&& rhs) = default;
      method String (line 945) | const String&
      method Value (line 951) | const Value& value() const {
      method make_storage (line 955) | std::shared_ptr<Value>
    type HelpOptionDetails (line 981) | struct HelpOptionDetails
    type HelpGroupDetails (line 995) | struct HelpGroupDetails
    class OptionValue (line 1002) | class OptionValue
      method parse (line 1005) | void
      method parse_default (line 1017) | void
      method count (line 1024) | size_t
      method T (line 1031) | const T&
      method ensure_value (line 1042) | void
    class KeyValue (line 1055) | class KeyValue
      method KeyValue (line 1058) | KeyValue(std::string key_, std::string value_)
      method value (line 1071) | const std::string
      method T (line 1078) | T
    class ParseResult (line 1091) | class ParseResult
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    class Options (line 1180) | class Options
      method Options (line 1184) | Options(std::string program, std::string help_string = "")
      method Options (line 1194) | Options&
      method Options (line 1201) | Options&
      method Options (line 1208) | Options&
    class OptionAdder (line 1288) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function String (line 1323) | String
    function String (line 1365) | String
    function OptionAdder (line 1443) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function OptionAdder (line 1450) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function ParseResult (line 1640) | inline
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    function String (line 1839) | inline
    function HelpGroupDetails (line 1996) | inline
  type cxxopts (line 62) | namespace cxxopts
    function String (line 66) | inline
    class UnicodeStringIterator (line 73) | class UnicodeStringIterator : public
      method UnicodeStringIterator (line 78) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
      method value_type (line 84) | value_type
      method UnicodeStringIterator (line 102) | UnicodeStringIterator&
      method UnicodeStringIterator (line 109) | UnicodeStringIterator
    function String (line 120) | inline
    function String (line 127) | inline
    function String (line 140) | String&
    function stringLength (line 152) | inline
    function toUTF8String (line 159) | inline
    function empty (line 169) | inline
    function T (line 202) | T
    function stringLength (line 208) | inline
    function String (line 215) | inline
    function String (line 222) | inline
    function String (line 230) | String&
    function toUTF8String (line 237) | std::string
    function empty (line 243) | inline
    class Value (line 267) | class Value : public std::enable_shared_from_this<Value>
    class OptionException (line 308) | class OptionException : public std::exception
      method OptionException (line 311) | OptionException(const std::string& message)
    class OptionSpecException (line 326) | class OptionSpecException : public OptionException
      method OptionSpecException (line 330) | OptionSpecException(const std::string& message)
    class OptionParseException (line 336) | class OptionParseException : public OptionException
      method OptionParseException (line 339) | OptionParseException(const std::string& message)
    class option_exists_error (line 345) | class option_exists_error : public OptionSpecException
      method option_exists_error (line 348) | option_exists_error(const std::string& option)
    class invalid_option_format_error (line 354) | class invalid_option_format_error : public OptionSpecException
      method invalid_option_format_error (line 357) | invalid_option_format_error(const std::string& format)
    class option_not_exists_exception (line 363) | class option_not_exists_exception : public OptionParseException
      method option_not_exists_exception (line 366) | option_not_exists_exception(const std::string& option)
    class missing_argument_exception (line 372) | class missing_argument_exception : public OptionParseException
      method missing_argument_exception (line 375) | missing_argument_exception(const std::string& option)
    class option_requires_argument_exception (line 383) | class option_requires_argument_exception : public OptionParseException
      method option_requires_argument_exception (line 386) | option_requires_argument_exception(const std::string& option)
    class option_not_has_argument_exception (line 394) | class option_not_has_argument_exception : public OptionParseException
      method option_not_has_argument_exception (line 397) | option_not_has_argument_exception
    class option_not_present_exception (line 411) | class option_not_present_exception : public OptionParseException
      method option_not_present_exception (line 414) | option_not_present_exception(const std::string& option)
    class argument_incorrect_type (line 420) | class argument_incorrect_type : public OptionParseException
      method argument_incorrect_type (line 423) | argument_incorrect_type
    class option_required_exception (line 434) | class option_required_exception : public OptionParseException
      method option_required_exception (line 437) | option_required_exception(const std::string& option)
    type values (line 445) | namespace values
      type detail (line 457) | namespace detail
        type SignedCheck (line 460) | struct SignedCheck
        type SignedCheck<T, true> (line 463) | struct SignedCheck<T, true>
        type SignedCheck<T, false> (line 487) | struct SignedCheck<T, false>
        function check_signed_range (line 495) | void
      function R (line 503) | R
      function T (line 513) | T
      function integer_parser (line 520) | void
      function stringstream_parser (line 592) | void stringstream_parser(const std::string& text, T& value)
      function parse_value (line 601) | inline
      function parse_value (line 608) | inline
      function parse_value (line 615) | inline
      function parse_value (line 622) | inline
      function parse_value (line 629) | inline
      function parse_value (line 636) | inline
      function parse_value (line 643) | inline
      function parse_value (line 650) | inline
      function parse_value (line 657) | inline
      function parse_value (line 680) | inline
      function parse_value (line 691) | void
      function parse_value (line 697) | void
      function parse_value (line 707) | void
      type type_is_container (line 717) | struct type_is_container
      type type_is_container<std::vector<T>> (line 723) | struct type_is_container<std::vector<T>>
      class abstract_value (line 729) | class abstract_value : public Value
        method abstract_value (line 734) | abstract_value()
        method abstract_value (line 740) | abstract_value(T* t)
        method abstract_value (line 747) | abstract_value(const abstract_value& rhs)
        method parse (line 765) | void
        method is_container (line 771) | bool
        method parse (line 777) | void
        method has_default (line 783) | bool
        method has_implicit (line 789) | bool
        method default_value (line 795) | std::shared_ptr<Value>
        method implicit_value (line 803) | std::shared_ptr<Value>
        method get_default_value (line 811) | std::string
        method get_implicit_value (line 817) | std::string
        method is_boolean (line 823) | bool
        method T (line 829) | const T&
      class standard_value (line 854) | class standard_value : public abstract_value<T>
        method clone (line 859) | std::shared_ptr<Value>
      class standard_value<bool> (line 867) | class standard_value<bool> : public abstract_value<bool>
        method standard_value (line 872) | standard_value()
        method standard_value (line 877) | standard_value(bool* b)
        method clone (line 883) | std::shared_ptr<Value>
        method set_default_and_implicit (line 891) | void
    function value (line 903) | std::shared_ptr<Value>
    function value (line 910) | std::shared_ptr<Value>
    class OptionAdder (line 916) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    class OptionDetails (line 918) | class OptionDetails
      method OptionDetails (line 921) | OptionDetails
      method OptionDetails (line 936) | OptionDetails(const OptionDetails& rhs)
      method OptionDetails (line 943) | OptionDetails(OptionDetails&& rhs) = default;
      method String (line 945) | const String&
      method Value (line 951) | const Value& value() const {
      method make_storage (line 955) | std::shared_ptr<Value>
    type HelpOptionDetails (line 981) | struct HelpOptionDetails
    type HelpGroupDetails (line 995) | struct HelpGroupDetails
    class OptionValue (line 1002) | class OptionValue
      method parse (line 1005) | void
      method parse_default (line 1017) | void
      method count (line 1024) | size_t
      method T (line 1031) | const T&
      method ensure_value (line 1042) | void
    class KeyValue (line 1055) | class KeyValue
      method KeyValue (line 1058) | KeyValue(std::string key_, std::string value_)
      method value (line 1071) | const std::string
      method T (line 1078) | T
    class ParseResult (line 1091) | class ParseResult
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    class Options (line 1180) | class Options
      method Options (line 1184) | Options(std::string program, std::string help_string = "")
      method Options (line 1194) | Options&
      method Options (line 1201) | Options&
      method Options (line 1208) | Options&
    class OptionAdder (line 1288) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function String (line 1323) | String
    function String (line 1365) | String
    function OptionAdder (line 1443) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function OptionAdder (line 1450) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function ParseResult (line 1640) | inline
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    function String (line 1839) | inline
    function HelpGroupDetails (line 1996) | inline
  type std (line 177) | namespace std
    function begin (line 179) | inline
    function end (line 186) | inline
  type cxxopts (line 197) | namespace cxxopts
    function String (line 66) | inline
    class UnicodeStringIterator (line 73) | class UnicodeStringIterator : public
      method UnicodeStringIterator (line 78) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
      method value_type (line 84) | value_type
      method UnicodeStringIterator (line 102) | UnicodeStringIterator&
      method UnicodeStringIterator (line 109) | UnicodeStringIterator
    function String (line 120) | inline
    function String (line 127) | inline
    function String (line 140) | String&
    function stringLength (line 152) | inline
    function toUTF8String (line 159) | inline
    function empty (line 169) | inline
    function T (line 202) | T
    function stringLength (line 208) | inline
    function String (line 215) | inline
    function String (line 222) | inline
    function String (line 230) | String&
    function toUTF8String (line 237) | std::string
    function empty (line 243) | inline
    class Value (line 267) | class Value : public std::enable_shared_from_this<Value>
    class OptionException (line 308) | class OptionException : public std::exception
      method OptionException (line 311) | OptionException(const std::string& message)
    class OptionSpecException (line 326) | class OptionSpecException : public OptionException
      method OptionSpecException (line 330) | OptionSpecException(const std::string& message)
    class OptionParseException (line 336) | class OptionParseException : public OptionException
      method OptionParseException (line 339) | OptionParseException(const std::string& message)
    class option_exists_error (line 345) | class option_exists_error : public OptionSpecException
      method option_exists_error (line 348) | option_exists_error(const std::string& option)
    class invalid_option_format_error (line 354) | class invalid_option_format_error : public OptionSpecException
      method invalid_option_format_error (line 357) | invalid_option_format_error(const std::string& format)
    class option_not_exists_exception (line 363) | class option_not_exists_exception : public OptionParseException
      method option_not_exists_exception (line 366) | option_not_exists_exception(const std::string& option)
    class missing_argument_exception (line 372) | class missing_argument_exception : public OptionParseException
      method missing_argument_exception (line 375) | missing_argument_exception(const std::string& option)
    class option_requires_argument_exception (line 383) | class option_requires_argument_exception : public OptionParseException
      method option_requires_argument_exception (line 386) | option_requires_argument_exception(const std::string& option)
    class option_not_has_argument_exception (line 394) | class option_not_has_argument_exception : public OptionParseException
      method option_not_has_argument_exception (line 397) | option_not_has_argument_exception
    class option_not_present_exception (line 411) | class option_not_present_exception : public OptionParseException
      method option_not_present_exception (line 414) | option_not_present_exception(const std::string& option)
    class argument_incorrect_type (line 420) | class argument_incorrect_type : public OptionParseException
      method argument_incorrect_type (line 423) | argument_incorrect_type
    class option_required_exception (line 434) | class option_required_exception : public OptionParseException
      method option_required_exception (line 437) | option_required_exception(const std::string& option)
    type values (line 445) | namespace values
      type detail (line 457) | namespace detail
        type SignedCheck (line 460) | struct SignedCheck
        type SignedCheck<T, true> (line 463) | struct SignedCheck<T, true>
        type SignedCheck<T, false> (line 487) | struct SignedCheck<T, false>
        function check_signed_range (line 495) | void
      function R (line 503) | R
      function T (line 513) | T
      function integer_parser (line 520) | void
      function stringstream_parser (line 592) | void stringstream_parser(const std::string& text, T& value)
      function parse_value (line 601) | inline
      function parse_value (line 608) | inline
      function parse_value (line 615) | inline
      function parse_value (line 622) | inline
      function parse_value (line 629) | inline
      function parse_value (line 636) | inline
      function parse_value (line 643) | inline
      function parse_value (line 650) | inline
      function parse_value (line 657) | inline
      function parse_value (line 680) | inline
      function parse_value (line 691) | void
      function parse_value (line 697) | void
      function parse_value (line 707) | void
      type type_is_container (line 717) | struct type_is_container
      type type_is_container<std::vector<T>> (line 723) | struct type_is_container<std::vector<T>>
      class abstract_value (line 729) | class abstract_value : public Value
        method abstract_value (line 734) | abstract_value()
        method abstract_value (line 740) | abstract_value(T* t)
        method abstract_value (line 747) | abstract_value(const abstract_value& rhs)
        method parse (line 765) | void
        method is_container (line 771) | bool
        method parse (line 777) | void
        method has_default (line 783) | bool
        method has_implicit (line 789) | bool
        method default_value (line 795) | std::shared_ptr<Value>
        method implicit_value (line 803) | std::shared_ptr<Value>
        method get_default_value (line 811) | std::string
        method get_implicit_value (line 817) | std::string
        method is_boolean (line 823) | bool
        method T (line 829) | const T&
      class standard_value (line 854) | class standard_value : public abstract_value<T>
        method clone (line 859) | std::shared_ptr<Value>
      class standard_value<bool> (line 867) | class standard_value<bool> : public abstract_value<bool>
        method standard_value (line 872) | standard_value()
        method standard_value (line 877) | standard_value(bool* b)
        method clone (line 883) | std::shared_ptr<Value>
        method set_default_and_implicit (line 891) | void
    function value (line 903) | std::shared_ptr<Value>
    function value (line 910) | std::shared_ptr<Value>
    class OptionAdder (line 916) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    class OptionDetails (line 918) | class OptionDetails
      method OptionDetails (line 921) | OptionDetails
      method OptionDetails (line 936) | OptionDetails(const OptionDetails& rhs)
      method OptionDetails (line 943) | OptionDetails(OptionDetails&& rhs) = default;
      method String (line 945) | const String&
      method Value (line 951) | const Value& value() const {
      method make_storage (line 955) | std::shared_ptr<Value>
    type HelpOptionDetails (line 981) | struct HelpOptionDetails
    type HelpGroupDetails (line 995) | struct HelpGroupDetails
    class OptionValue (line 1002) | class OptionValue
      method parse (line 1005) | void
      method parse_default (line 1017) | void
      method count (line 1024) | size_t
      method T (line 1031) | const T&
      method ensure_value (line 1042) | void
    class KeyValue (line 1055) | class KeyValue
      method KeyValue (line 1058) | KeyValue(std::string key_, std::string value_)
      method value (line 1071) | const std::string
      method T (line 1078) | T
    class ParseResult (line 1091) | class ParseResult
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    class Options (line 1180) | class Options
      method Options (line 1184) | Options(std::string program, std::string help_string = "")
      method Options (line 1194) | Options&
      method Options (line 1201) | Options&
      method Options (line 1208) | Options&
    class OptionAdder (line 1288) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function String (line 1323) | String
    function String (line 1365) | String
    function OptionAdder (line 1443) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function OptionAdder (line 1450) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function ParseResult (line 1640) | inline
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    function String (line 1839) | inline
    function HelpGroupDetails (line 1996) | inline
  type cxxopts (line 254) | namespace cxxopts
    function String (line 66) | inline
    class UnicodeStringIterator (line 73) | class UnicodeStringIterator : public
      method UnicodeStringIterator (line 78) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
      method value_type (line 84) | value_type
      method UnicodeStringIterator (line 102) | UnicodeStringIterator&
      method UnicodeStringIterator (line 109) | UnicodeStringIterator
    function String (line 120) | inline
    function String (line 127) | inline
    function String (line 140) | String&
    function stringLength (line 152) | inline
    function toUTF8String (line 159) | inline
    function empty (line 169) | inline
    function T (line 202) | T
    function stringLength (line 208) | inline
    function String (line 215) | inline
    function String (line 222) | inline
    function String (line 230) | String&
    function toUTF8String (line 237) | std::string
    function empty (line 243) | inline
    class Value (line 267) | class Value : public std::enable_shared_from_this<Value>
    class OptionException (line 308) | class OptionException : public std::exception
      method OptionException (line 311) | OptionException(const std::string& message)
    class OptionSpecException (line 326) | class OptionSpecException : public OptionException
      method OptionSpecException (line 330) | OptionSpecException(const std::string& message)
    class OptionParseException (line 336) | class OptionParseException : public OptionException
      method OptionParseException (line 339) | OptionParseException(const std::string& message)
    class option_exists_error (line 345) | class option_exists_error : public OptionSpecException
      method option_exists_error (line 348) | option_exists_error(const std::string& option)
    class invalid_option_format_error (line 354) | class invalid_option_format_error : public OptionSpecException
      method invalid_option_format_error (line 357) | invalid_option_format_error(const std::string& format)
    class option_not_exists_exception (line 363) | class option_not_exists_exception : public OptionParseException
      method option_not_exists_exception (line 366) | option_not_exists_exception(const std::string& option)
    class missing_argument_exception (line 372) | class missing_argument_exception : public OptionParseException
      method missing_argument_exception (line 375) | missing_argument_exception(const std::string& option)
    class option_requires_argument_exception (line 383) | class option_requires_argument_exception : public OptionParseException
      method option_requires_argument_exception (line 386) | option_requires_argument_exception(const std::string& option)
    class option_not_has_argument_exception (line 394) | class option_not_has_argument_exception : public OptionParseException
      method option_not_has_argument_exception (line 397) | option_not_has_argument_exception
    class option_not_present_exception (line 411) | class option_not_present_exception : public OptionParseException
      method option_not_present_exception (line 414) | option_not_present_exception(const std::string& option)
    class argument_incorrect_type (line 420) | class argument_incorrect_type : public OptionParseException
      method argument_incorrect_type (line 423) | argument_incorrect_type
    class option_required_exception (line 434) | class option_required_exception : public OptionParseException
      method option_required_exception (line 437) | option_required_exception(const std::string& option)
    type values (line 445) | namespace values
      type detail (line 457) | namespace detail
        type SignedCheck (line 460) | struct SignedCheck
        type SignedCheck<T, true> (line 463) | struct SignedCheck<T, true>
        type SignedCheck<T, false> (line 487) | struct SignedCheck<T, false>
        function check_signed_range (line 495) | void
      function R (line 503) | R
      function T (line 513) | T
      function integer_parser (line 520) | void
      function stringstream_parser (line 592) | void stringstream_parser(const std::string& text, T& value)
      function parse_value (line 601) | inline
      function parse_value (line 608) | inline
      function parse_value (line 615) | inline
      function parse_value (line 622) | inline
      function parse_value (line 629) | inline
      function parse_value (line 636) | inline
      function parse_value (line 643) | inline
      function parse_value (line 650) | inline
      function parse_value (line 657) | inline
      function parse_value (line 680) | inline
      function parse_value (line 691) | void
      function parse_value (line 697) | void
      function parse_value (line 707) | void
      type type_is_container (line 717) | struct type_is_container
      type type_is_container<std::vector<T>> (line 723) | struct type_is_container<std::vector<T>>
      class abstract_value (line 729) | class abstract_value : public Value
        method abstract_value (line 734) | abstract_value()
        method abstract_value (line 740) | abstract_value(T* t)
        method abstract_value (line 747) | abstract_value(const abstract_value& rhs)
        method parse (line 765) | void
        method is_container (line 771) | bool
        method parse (line 777) | void
        method has_default (line 783) | bool
        method has_implicit (line 789) | bool
        method default_value (line 795) | std::shared_ptr<Value>
        method implicit_value (line 803) | std::shared_ptr<Value>
        method get_default_value (line 811) | std::string
        method get_implicit_value (line 817) | std::string
        method is_boolean (line 823) | bool
        method T (line 829) | const T&
      class standard_value (line 854) | class standard_value : public abstract_value<T>
        method clone (line 859) | std::shared_ptr<Value>
      class standard_value<bool> (line 867) | class standard_value<bool> : public abstract_value<bool>
        method standard_value (line 872) | standard_value()
        method standard_value (line 877) | standard_value(bool* b)
        method clone (line 883) | std::shared_ptr<Value>
        method set_default_and_implicit (line 891) | void
    function value (line 903) | std::shared_ptr<Value>
    function value (line 910) | std::shared_ptr<Value>
    class OptionAdder (line 916) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    class OptionDetails (line 918) | class OptionDetails
      method OptionDetails (line 921) | OptionDetails
      method OptionDetails (line 936) | OptionDetails(const OptionDetails& rhs)
      method OptionDetails (line 943) | OptionDetails(OptionDetails&& rhs) = default;
      method String (line 945) | const String&
      method Value (line 951) | const Value& value() const {
      method make_storage (line 955) | std::shared_ptr<Value>
    type HelpOptionDetails (line 981) | struct HelpOptionDetails
    type HelpGroupDetails (line 995) | struct HelpGroupDetails
    class OptionValue (line 1002) | class OptionValue
      method parse (line 1005) | void
      method parse_default (line 1017) | void
      method count (line 1024) | size_t
      method T (line 1031) | const T&
      method ensure_value (line 1042) | void
    class KeyValue (line 1055) | class KeyValue
      method KeyValue (line 1058) | KeyValue(std::string key_, std::string value_)
      method value (line 1071) | const std::string
      method T (line 1078) | T
    class ParseResult (line 1091) | class ParseResult
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    class Options (line 1180) | class Options
      method Options (line 1184) | Options(std::string program, std::string help_string = "")
      method Options (line 1194) | Options&
      method Options (line 1201) | Options&
      method Options (line 1208) | Options&
    class OptionAdder (line 1288) | class OptionAdder
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function String (line 1323) | String
    function String (line 1365) | String
    function OptionAdder (line 1443) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function OptionAdder (line 1450) | inline
      method OptionAdder (line 1292) | OptionAdder(Options& options, std::string group)
    function ParseResult (line 1640) | inline
      method count (line 1100) | size_t
      method OptionValue (line 1114) | const OptionValue&
    function String (line 1839) | inline
    function HelpGroupDetails (line 1996) | inline

FILE: eos-model-viewer.cpp
  function to_string (line 40) | std::string to_string(const T a_value, const int n = 6)
  function tokenize (line 49) | void tokenize(const std::string& str, ContainerType& tokens, const std::...
  function load_bin_or_scm_model (line 73) | eos::morphablemodel::MorphableModel load_bin_or_scm_model(std::string mo...
  function load_model (line 101) | eos::morphablemodel::MorphableModel load_model(std::string model_file, s...
  function main (line 124) | int main(int argc, const char* argv[])
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (90K chars).
[
  {
    "path": ".clang-format",
    "chars": 655,
    "preview": "---\nBasedOnStyle: LLVM\nAccessModifierOffset: '-4'\nAlwaysBreakTemplateDeclarations: 'true'\nBreakBeforeBraces: Custom\nBrac"
  },
  {
    "path": ".gitignore",
    "chars": 86,
    "preview": "# Ignore (optional) configuration files with user-specific paths:\ninitial_cache.cmake\n"
  },
  {
    "path": ".gitmodules",
    "chars": 192,
    "preview": "[submodule \"external/eos\"]\n\tpath = external/eos\n\turl = https://github.com/patrikhuber/eos.git\n[submodule \"external/libig"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 4452,
    "preview": "cmake_minimum_required(VERSION 3.1.3)\nproject(eos-model-viewer)\nset(eos-model-viewer_VERSION 0.2.0.alpha)\n\nset_property("
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 1090,
    "preview": "# eos-model-viewer\n3D model viewer for the eos Morphable Model library\n\nThis is a viewer that displays Morphable Models "
  },
  {
    "path": "cmake/FindLIBIGL.cmake",
    "chars": 1018,
    "preview": "# - Try to find the LIBIGL library\n# Once done this will define\n#\n#  LIBIGL_FOUND - system has LIBIGL\n#  LIBIGL_INCLUDE_"
  },
  {
    "path": "cxxopts.hpp",
    "chars": 39945,
    "preview": "/*\n\nCopyright (c) 2014, 2015, 2016, 2017 Jarryd Beck\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "eos-model-viewer.cpp",
    "chars": 25784,
    "preview": "/*\n * eos - A 3D Morphable Model fitting library written in modern C++11/14.\n *\n * File: eos-model-viewer.cpp\n *\n * Copy"
  },
  {
    "path": "initial_cache.cmake.template",
    "chars": 1152,
    "preview": "# Mechanism via FindLIB.cmake\n# ==============================\n# Boost:\n# -------\n# Windows: Download the pre-built bina"
  }
]

About this extraction

This page contains the full source code of the patrikhuber/eos-model-viewer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (83.7 KB), approximately 20.6k tokens, and a symbol index with 142 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!