├── .clang-format
├── .github
└── workflows
│ ├── apt-ci.yaml
│ └── conda-forge-ci.yml
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── README.md
├── cmake
├── AddInstallRPATHSupport.cmake
├── AddUninstallTarget.cmake
├── FetchuWebSockets.cmake
├── FinduSockets.cmake
├── FinduWebSockets.cmake
├── InstallBasicPackageFiles.cmake
└── MeshcatCppDeps.cmake
├── examples
├── CMakeLists.txt
├── meshcat_example.cpp
└── misc
│ ├── Dragonite.stl
│ └── LICENSE_DRAGONITE_STL
├── include
└── MeshcatCpp
│ ├── Material.h
│ ├── MatrixView.h
│ ├── Meshcat.h
│ ├── Property.h
│ ├── Shape.h
│ └── impl
│ ├── FindResource.h
│ ├── MsgpackTypes.h
│ ├── TreeNode.h
│ └── UUIDGenerator.h
├── misc
├── LICENSE_MESHCAT
├── favicon.ico
├── index.html
├── main.min.js
└── main.min.js.THIRD_PARTY_LICENSES.json
└── src
├── Material.cpp
├── Meshcat.cpp
├── MsgpackTypes.cpp
├── Shape.cpp
└── UUIDGenerator.cpp
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | # BasedOnStyle: WebKit
4 | AccessModifierOffset: -4
5 | AlignAfterOpenBracket: Align
6 | AlignConsecutiveAssignments: false
7 | AlignConsecutiveDeclarations: false
8 | AlignEscapedNewlines: Left
9 | AlignOperands: true
10 | AlignTrailingComments: false
11 | AllowAllParametersOfDeclarationOnNextLine: true
12 | AllowShortBlocksOnASingleLine: false
13 | AllowShortCaseLabelsOnASingleLine: false
14 | AllowShortFunctionsOnASingleLine: None
15 | AllowShortIfStatementsOnASingleLine: false
16 | AllowShortLoopsOnASingleLine: false
17 | AlwaysBreakAfterDefinitionReturnType: None
18 | AlwaysBreakAfterReturnType: None
19 | AlwaysBreakBeforeMultilineStrings: false
20 | AlwaysBreakTemplateDeclarations: false
21 | BinPackArguments: false
22 | BinPackParameters: false
23 | BraceWrapping:
24 | AfterClass: true
25 | AfterControlStatement: true
26 | AfterEnum: true
27 | AfterFunction: true
28 | AfterNamespace: true
29 | AfterObjCDeclaration: false
30 | AfterStruct: true
31 | AfterUnion: true
32 | BeforeCatch: false
33 | BeforeElse: false
34 | IndentBraces: false
35 | SplitEmptyFunction: true
36 | SplitEmptyRecord: true
37 | SplitEmptyNamespace: true
38 | BreakBeforeBinaryOperators: All
39 | BreakBeforeBraces: Custom
40 | BreakBeforeInheritanceComma: false
41 | BreakBeforeTernaryOperators: true
42 | BreakConstructorInitializersBeforeComma: true
43 | BreakConstructorInitializers: BeforeComma
44 | BreakAfterJavaFieldAnnotations: false
45 | BreakStringLiterals: true
46 | ColumnLimit: 100
47 | CommentPragmas: '^ IWYU pragma:'
48 | CompactNamespaces: false
49 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
50 | ConstructorInitializerIndentWidth: 4
51 | ContinuationIndentWidth: 4
52 | Cpp11BracedListStyle: true
53 | DerivePointerAlignment: false
54 | DisableFormat: false
55 | ExperimentalAutoDetectBinPacking: false
56 | FixNamespaceComments: true
57 | ForEachMacros:
58 | - foreach
59 | - Q_FOREACH
60 | - BOOST_FOREACH
61 | IncludeCategories:
62 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
63 | Priority: 2
64 | - Regex: '^(<|"(gtest|gmock|isl|json)/)'
65 | Priority: 3
66 | - Regex: '.*'
67 | Priority: 1
68 | IncludeIsMainRegex: '(Test)?$'
69 | IndentCaseLabels: false
70 | IndentWidth: 4
71 | IndentWrappedFunctionNames: false
72 | JavaScriptQuotes: Leave
73 | JavaScriptWrapImports: true
74 | KeepEmptyLinesAtTheStartOfBlocks: true
75 | MacroBlockBegin: ''
76 | MacroBlockEnd: ''
77 | MaxEmptyLinesToKeep: 1
78 | NamespaceIndentation: None
79 | ObjCBlockIndentWidth: 4
80 | ObjCSpaceAfterProperty: true
81 | ObjCSpaceBeforeProtocolList: true
82 | PenaltyBreakAssignment: 10
83 | PenaltyBreakBeforeFirstCallParameter: 1000
84 | PenaltyBreakComment: 10
85 | PenaltyBreakString: 10
86 | PenaltyExcessCharacter: 100
87 | PenaltyReturnTypeOnItsOwnLine: 5
88 | PointerAlignment: Left
89 | ReflowComments: true
90 | SortIncludes: true
91 | SortUsingDeclarations: true
92 | SpaceAfterCStyleCast: false
93 | SpaceAfterTemplateKeyword: true
94 | SpaceBeforeAssignmentOperators: true
95 | SpaceBeforeParens: ControlStatements
96 | SpaceInEmptyParentheses: false
97 | SpacesBeforeTrailingComments: 1
98 | SpacesInAngles: false
99 | SpacesInContainerLiterals: true
100 | SpacesInCStyleCastParentheses: false
101 | SpacesInParentheses: false
102 | SpacesInSquareBrackets: false
103 | Standard: Cpp11
104 | TabWidth: 4
105 | UseTab: Never
106 |
--------------------------------------------------------------------------------
/.github/workflows/apt-ci.yaml:
--------------------------------------------------------------------------------
1 | name: C++ CI Workflow with apt dependencies
2 |
3 | on:
4 | push:
5 | pull_request:
6 | schedule:
7 | # * is a special character in YAML so you have to quote this string
8 | # Execute a "nightly" build at 2 AM UTC
9 | - cron: '0 2 * * *'
10 |
11 | jobs:
12 | build:
13 | name: '[${{ matrix.docker_image }}@${{ matrix.build_type }}@apt]'
14 | runs-on: ${{ matrix.os }}
15 | strategy:
16 | matrix:
17 | build_type: [Release]
18 | os:
19 | - ubuntu-latest
20 | docker_image:
21 | - "ubuntu:20.04"
22 | - "ubuntu:22.04"
23 | - "debian:sid"
24 | container:
25 | image: ${{ matrix.docker_image }}
26 |
27 | steps:
28 | - uses: actions/checkout@v3
29 |
30 |
31 | - name: Dependencies
32 | run: |
33 | # See https://stackoverflow.com/questions/44331836/apt-get-install-tzdata-noninteractive,
34 | # only required by Ubuntu 20.04
35 | export DEBIAN_FRONTEND=noninteractive
36 | apt-get update
37 | apt-get -y upgrade
38 | apt-get -y install cmake pkg-config build-essential ninja-build git libssl-dev libuv1-dev libz-dev libboost-dev
39 |
40 | - name: Configure
41 | run: |
42 | mkdir -p build
43 | cd build
44 | cmake -GNinja -DBUILD_TESTING:BOOL=ON -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} ..
45 |
46 | - name: Build
47 | shell: bash -l {0}
48 | run: |
49 | cd build
50 | cmake --build . --config ${{ matrix.build_type }}
51 |
52 | - name: Test
53 | shell: bash -l {0}
54 | run: |
55 | cd build
56 | ctest --output-on-failure -C ${{ matrix.build_type }}
57 |
58 |
--------------------------------------------------------------------------------
/.github/workflows/conda-forge-ci.yml:
--------------------------------------------------------------------------------
1 | name: C++ CI Workflow with conda-forge dependencies
2 |
3 | on:
4 | push:
5 | pull_request:
6 | schedule:
7 | # * is a special character in YAML so you have to quote this string
8 | # Execute a "nightly" build at 2 AM UTC
9 | - cron: '0 2 * * *'
10 |
11 | jobs:
12 | build:
13 | name: '[${{ matrix.os }}@${{ matrix.build_type }}@conda]'
14 | runs-on: ${{ matrix.os }}
15 | strategy:
16 | matrix:
17 | build_type: [Release]
18 | os: [ubuntu-latest, windows-2019, macOS-latest]
19 | fail-fast: false
20 |
21 | steps:
22 | - uses: actions/checkout@v3
23 |
24 | - uses: conda-incubator/setup-miniconda@v2
25 | with:
26 | miniforge-variant: Mambaforge
27 | miniforge-version: latest
28 |
29 | - name: Dependencies
30 | shell: bash -l {0}
31 | run: |
32 | mamba install cmake pkg-config make ninja compilers boost-cpp libuwebsockets zlib openssl libuv msgpack-cxx
33 |
34 | # Workaround for https://github.com/conda-forge/boost-cpp-feedstock/issues/134
35 | - name: Dependencies
36 | if: contains(matrix.os, 'macos')
37 | shell: bash -l {0}
38 | run: |
39 | mamba install "libcxx<16"
40 |
41 |
42 | - name: Configure [Linux&macOS]
43 | if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
44 | shell: bash -l {0}
45 | run: |
46 | mkdir -p build
47 | cd build
48 | cmake -GNinja -DBUILD_TESTING:BOOL=ON -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} ..
49 |
50 | - name: Configure [Windows]
51 | if: contains(matrix.os, 'windows')
52 | shell: bash -l {0}
53 | run: |
54 | mkdir -p build
55 | cd build
56 | cmake -G"Visual Studio 16 2019" -DBUILD_TESTING:BOOL=ON -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} ..
57 |
58 | - name: Build
59 | shell: bash -l {0}
60 | run: |
61 | cd build
62 | cmake --build . --config ${{ matrix.build_type }}
63 |
64 | - name: Test
65 | shell: bash -l {0}
66 | run: |
67 | cd build
68 | ctest --output-on-failure -C ${{ matrix.build_type }}
69 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build folders
2 | build*
3 |
4 | # emacs
5 | *~
6 | \#*\#
7 |
8 | # Qtcreator
9 | *.user*
10 | *.autosave
11 |
12 | # IDEs
13 | .idea*
14 |
15 | # ======
16 | # Python (https://github.com/github/gitignore/blob/master/Python.gitignore)
17 | # ======
18 |
19 | # Byte-compiled / optimized / DLL files
20 | __pycache__/
21 | *.py[cod]
22 | *$py.class
23 |
24 | # C extensions
25 | *.so
26 |
27 | # Distribution / packaging
28 | .Python
29 | build/
30 | develop-eggs/
31 | dist/
32 | downloads/
33 | eggs/
34 | .eggs/
35 | lib/
36 | lib64/
37 | parts/
38 | sdist/
39 | var/
40 | wheels/
41 | share/python-wheels/
42 | *.egg-info/
43 | .installed.cfg
44 | *.egg
45 | MANIFEST
46 |
47 | # PyInstaller
48 | # Usually these files are written by a python script from a template
49 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
50 | *.manifest
51 | *.spec
52 |
53 | # Installer logs
54 | pip-log.txt
55 | pip-delete-this-directory.txt
56 |
57 | # Unit test / coverage reports
58 | htmlcov/
59 | .tox/
60 | .nox/
61 | .coverage
62 | .coverage.*
63 | .cache
64 | nosetests.xml
65 | coverage.xml
66 | *.cover
67 | *.py,cover
68 | .hypothesis/
69 | .pytest_cache/
70 | cover/
71 |
72 | # Translations
73 | *.mo
74 | *.pot
75 |
76 | # Django stuff:
77 | *.log
78 | local_settings.py
79 | db.sqlite3
80 | db.sqlite3-journal
81 |
82 | # Flask stuff:
83 | instance/
84 | .webassets-cache
85 |
86 | # Scrapy stuff:
87 | .scrapy
88 |
89 | # Sphinx documentation
90 | docs/_build/
91 |
92 | # PyBuilder
93 | .pybuilder/
94 | target/
95 |
96 | # Jupyter Notebook
97 | .ipynb_checkpoints
98 |
99 | # IPython
100 | profile_default/
101 | ipython_config.py
102 |
103 | # pyenv
104 | # For a library or package, you might want to ignore these files since the code is
105 | # intended to run in multiple environments; otherwise, check them in:
106 | # .python-version
107 |
108 | # pipenv
109 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
110 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
111 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
112 | # install all needed dependencies.
113 | #Pipfile.lock
114 |
115 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
116 | __pypackages__/
117 |
118 | # Celery stuff
119 | celerybeat-schedule
120 | celerybeat.pid
121 |
122 | # SageMath parsed files
123 | *.sage.py
124 |
125 | # Environments
126 | .env
127 | .venv
128 | env/
129 | venv/
130 | ENV/
131 | env.bak/
132 | venv.bak/
133 |
134 | # Spyder project settings
135 | .spyderproject
136 | .spyproject
137 |
138 | # Rope project settings
139 | .ropeproject
140 |
141 | # mkdocs documentation
142 | /site
143 |
144 | # mypy
145 | .mypy_cache/
146 | .dmypy.json
147 | dmypy.json
148 |
149 | # Pyre type checker
150 | .pyre/
151 |
152 | # pytype static type analyzer
153 | .pytype/
154 |
155 | # Cython debug symbols
156 | cython_debug/
157 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ami-iit/meshcat-cpp/a84be7add7f344d61e615bee7f26e6a7d5444f2a/.gitmodules
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Authors: Giulio Romualdi
2 |
3 | # Set cmake mimimun version
4 | cmake_minimum_required(VERSION 3.12)
5 |
6 | project(MeshcatCpp
7 | VERSION 0.1.0)
8 |
9 | # Avoid warnings with CMake 3.26
10 | if(POLICY CMP0135)
11 | cmake_policy(SET CMP0135 NEW)
12 | endif()
13 |
14 | # ouptut paths
15 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}")
16 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
17 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
18 |
19 | # Build shared libs
20 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
21 |
22 | if(MSVC)
23 | set(CMAKE_DEBUG_POSTFIX "d")
24 | endif()
25 |
26 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
27 |
28 | option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON)
29 |
30 | # Disable C and C++ compiler extensions.
31 | # C/CXX_EXTENSIONS are ON by default to allow the compilers to use extended
32 | # variants of the C/CXX language.
33 | # However, this could expose cross-platform bugs in user code or in the headers
34 | # of third-party dependencies and thus it is strongly suggested to turn
35 | # extensions off.
36 | set(CMAKE_C_EXTENSIONS OFF)
37 | set(CMAKE_CXX_EXTENSIONS OFF)
38 |
39 | # add GNU dirs
40 | include(GNUInstallDirs)
41 |
42 | include(CMakePackageConfigHelpers)
43 |
44 | option(ENABLE_RPATH "Enable RPATH for this library" ON)
45 | mark_as_advanced(ENABLE_RPATH)
46 | include(AddInstallRPATHSupport)
47 | add_install_rpath_support(BIN_DIRS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
48 | LIB_DIRS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
49 | DEPENDS ENABLE_RPATH
50 | USE_LINK_PATH)
51 |
52 | # Encourage user to specify a build type (e.g. Release, Debug, etc.), otherwise set it to Release.
53 | if(NOT CMAKE_CONFIGURATION_TYPES)
54 | if(NOT CMAKE_BUILD_TYPE)
55 | message(STATUS "Setting build type to 'Release' as none was specified.")
56 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE "Release")
57 | endif()
58 | endif()
59 |
60 |
61 |
62 | find_package(Threads REQUIRED)
63 | find_package(ZLIB REQUIRED)
64 | include(MeshcatCppDeps)
65 |
66 |
67 | set(${PROJECT_NAME}_SRC
68 | src/Meshcat.cpp
69 | src/Material.cpp
70 | src/MsgpackTypes.cpp
71 | src/UUIDGenerator.cpp
72 | src/Shape.cpp)
73 |
74 | set(${PROJECT_NAME}_HDR
75 | include/MeshcatCpp/Meshcat.h
76 | include/MeshcatCpp/Material.h
77 | include/MeshcatCpp/MatrixView.h
78 | include/MeshcatCpp/Shape.h)
79 |
80 | cmrc_add_resource_library(${PROJECT_NAME}_resources
81 | ALIAS ${PROJECT_NAME}::resources
82 | NAMESPACE ${PROJECT_NAME}
83 | misc/index.html
84 | misc/main.min.js
85 | misc/favicon.ico)
86 |
87 | set_property(TARGET ${PROJECT_NAME}_resources PROPERTY POSITION_INDEPENDENT_CODE ON)
88 |
89 |
90 | add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRC} ${${PROJECT_NAME}_HDR})
91 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
92 |
93 | target_include_directories(${PROJECT_NAME} PRIVATE
94 | "$"
95 | "$")
96 |
97 | target_include_directories(${PROJECT_NAME} PUBLIC
98 | "$"
99 | "$")
100 |
101 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
102 |
103 | if(MSVC)
104 | target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
105 | else()
106 | target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
107 | endif()
108 |
109 | target_link_libraries(${PROJECT_NAME} PRIVATE
110 | stduuid
111 | Threads::Threads
112 | ZLIB::ZLIB
113 | msgpack-cxx
114 | uWebSockets::uWebSockets
115 | ${PROJECT_NAME}::resources)
116 |
117 |
118 | set_target_properties(${PROJECT_NAME} PROPERTIES
119 | VERSION ${PROJECT_VERSION}
120 | PUBLIC_HEADER "${${PROJECT_NAME}_HDR}"
121 | )
122 |
123 | install(TARGETS ${PROJECT_NAME}
124 | EXPORT ${PROJECT_NAME}
125 | COMPONENT runtime
126 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib
127 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib
128 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin
129 | PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}")
130 |
131 | include(InstallBasicPackageFiles)
132 | install_basic_package_files(${PROJECT_NAME}
133 | NAMESPACE MeshcatCpp::
134 | VERSION ${${PROJECT_NAME}_VERSION}
135 | COMPATIBILITY SameMajorVersion
136 | VARS_PREFIX ${PROJECT_NAME}
137 | NO_CHECK_REQUIRED_COMPONENTS_MACRO)
138 |
139 | include(AddUninstallTarget)
140 |
141 | # Build examples
142 | option(MESHCAT_CPP_BUILT_EXAMPLES "Build the examples" OFF)
143 | if(${MESHCAT_CPP_BUILT_EXAMPLES})
144 | add_subdirectory(examples)
145 | endif()
146 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, Giulio Romualdi
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
meshcat-cpp
3 |
4 |
5 |
6 |
7 |
8 |
9 | Self-contained C++ interface for the [MeshCat visualizer](https://github.com/rdeits/meshcat).
10 |
11 | **meshcat-cpp** took (heavy) inspiration for C++ (drake) MeshCat interface extensively discussed [here](https://github.com/RobotLocomotion/drake/issues/13038). The main purpose of this package is to have an independent (self-contained) C++ library that exposes the MeshCat interface in C++.
12 |
13 | ---
14 |
15 |
16 | 🚧 REPOSITORY UNDER DEVELOPMENT 🚧
17 |
The library implemented in this repository is still experimental and we cannot guarantee stable API
18 |
19 |
20 | ---
21 |
22 | ## 🏗️ Dependencies
23 |
24 | **meshcat-cpp** is a self-contained library. Most dependencies can be cloned at compile time and they are statically linked to the library. The only dependencies you need is a sufficiently recent C++ compiler (full support to C++20), `cmake`, `openssl`, `zlib`, `libuv`, `boost` and `pkg-config`.
25 |
26 | ### Install dependencies on Debian/Ubuntu
27 |
28 | ~~~
29 | sudo apt install cmake pkg-config build-essential ninja-build git libssl-dev libuv1-dev libz-dev libboost-dev
30 | ~~~
31 |
32 | ### Install dependencies with conda-forge
33 |
34 | ~~~
35 | mamba create -n meshcatcppdev boost-cpp libuwebsockets cmake pkg-config compilers zlib openssl libuv msgpack-cxx
36 | ~~~
37 |
38 | Then, execute all the other commands after activating the environment:
39 | ~~~
40 | mamba activate meshcatcppdev
41 | ~~~
42 |
43 | ## ⚒️ Build the library
44 |
45 | You can build the library coping and paste the following snippet into a terminal
46 | ```console
47 | git clone https://github.com/GiulioRomualdi/meshcat-cpp.git
48 | cd meshcat-cpp
49 | mkdir build && cd build
50 | cmake ..
51 | cmake --build .
52 | [sudo] make install
53 | ```
54 | ## 🏃 Example
55 |
56 | **meshcat-cpp** provides native `CMake` support which allows the library to be easily used in `CMake` projects. Please add in your `CMakeLists.txt`
57 | ```cmake
58 | project(foo)
59 | find_package(MeshcatCpp REQUIRED)
60 | add_executable(${PROJECT_NAME} src/foo.cpp)
61 | target_link_libraries(${PROJECT_NAME} MeshcatCpp::MeshcatCpp)
62 | ```
63 |
64 | Differently for the [python](https://github.com/rdeits/meshcat-python),
65 | [julia](https://github.com/rdeits/MeshCat.jl), and [C++
66 | (drake)](https://drake.mit.edu/doxygen_cxx/classdrake_1_1geometry_1_1_meshcat_visualizer.html)
67 | interfaces this interface currently supports only a subset of functionalities (🚧 New
68 | functionalities will be soon implemented). The following example shows you how to display some primary shapes.
69 | ```cpp
70 | #include
71 | #include
72 | #include
73 |
74 | MeshcatCpp::MatrixView array_to_matrix_view(std::array& array)
75 | {
76 | constexpr MeshcatCpp::MatrixView::index_type rows = 4;
77 | constexpr MeshcatCpp::MatrixView::index_type cols = 4;
78 | constexpr auto order = MeshcatCpp::MatrixStorageOrdering::ColumnMajor;
79 | return MeshcatCpp::make_matrix_view(array.data(), rows, cols, order);
80 | }
81 |
82 | int main()
83 | {
84 | MeshcatCpp::Meshcat meshcat;
85 | MeshcatCpp::Material m;
86 |
87 | std::array transform = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
88 | auto matrix_view = array_to_matrix_view(transform);
89 |
90 | m.set_color(66, 133, 244);
91 | meshcat.set_object("box", MeshcatCpp::Box(0.5, 0.5, 0.5), m);
92 | matrix_view(3, 1) = 1.75;
93 | meshcat.set_transform("box", matrix_view);
94 |
95 | m.set_color(234, 67, 53);
96 | meshcat.set_object("sphere", MeshcatCpp::Sphere(0.5), m);
97 | matrix_view(3, 1) = 0.75;
98 | meshcat.set_transform("sphere", matrix_view);
99 |
100 | m.set_color(251, 188, 5);
101 | meshcat.set_object("ellipsoid", MeshcatCpp::Ellipsoid(0.5, 0.25, 0.75), m);
102 | matrix_view(3, 1) = -0.75;
103 | meshcat.set_transform("ellipsoid", matrix_view);
104 |
105 | m.set_color(52, 168, 83);
106 | meshcat.set_object("cylinder", MeshcatCpp::Cylinder(0.25, 0.5), m);
107 | matrix_view(3, 1) = -1.75;
108 | meshcat.set_transform("cylinder", matrix_view);
109 |
110 | meshcat.join();
111 |
112 | return 0;
113 | }
114 | ```
115 |
116 | Once you have run the [example](./examples/meshcat_example.cpp), the `MeshcatCpp::Meshcat` class will print the `URL` at which the MeshCat server runs. Please open the link in your browser and you should be able to see the following screen
117 |
118 | 
119 |
120 |
121 | ## 🐛 Bug reports and support
122 |
123 | All types of [issues](https://github.com/GiulioRomualdi/meshcat-cpp/issues/new) are welcome.
124 |
125 | ## 📝 License
126 | Materials in this repository are distributed under the following license:
127 |
128 | > All software is licensed under the BSD 3-Clause "New" or "Revised" License. See [LICENSE](https://github.com/GiulioRomualdi/meshcat-cpp/blob/master/LICENSE) file for details.
129 |
--------------------------------------------------------------------------------
/cmake/AddInstallRPATHSupport.cmake:
--------------------------------------------------------------------------------
1 | #.rst:
2 | # AddInstallRPATHSupport
3 | # ----------------------
4 | #
5 | # Add support to RPATH during installation to your project::
6 | #
7 | # add_install_rpath_support([BIN_DIRS dir [dir]]
8 | # [LIB_DIRS dir [dir]]
9 | # [INSTALL_NAME_DIR [dir]]
10 | # [DEPENDS condition [condition]]
11 | # [USE_LINK_PATH])
12 | #
13 | # Normally (depending on the platform) when you install a shared
14 | # library you can either specify its absolute path as the install name,
15 | # or leave just the library name itself. In the former case the library
16 | # will be correctly linked during run time by all executables and other
17 | # shared libraries, but it must not change its install location. This
18 | # is often the case for libraries installed in the system default
19 | # library directory (e.g. ``/usr/lib``).
20 | # In the latter case, instead, the library can be moved anywhere in the
21 | # file system but at run time the dynamic linker must be able to find
22 | # it. This is often accomplished by setting environmental variables
23 | # (i.e. ``LD_LIBRARY_PATH`` on Linux).
24 | # This procedure is usually not desirable for two main reasons:
25 | #
26 | # - by setting the variable you are changing the default behaviour
27 | # of the dynamic linker thus potentially breaking executables (not as
28 | # destructive as ``LD_PRELOAD``)
29 | # - the variable will be used only by applications spawned by the shell
30 | # and not by other processes.
31 | #
32 | # RPATH is aimed to solve the issues introduced by the second
33 | # installation method. Using run-path dependent libraries you can
34 | # create a directory structure containing executables and dependent
35 | # libraries that users can relocate without breaking it.
36 | # A run-path dependent library is a dependent library whose complete
37 | # install name is not known when the library is created.
38 | # Instead, the library specifies that the dynamic loader must resolve
39 | # the library’s install name when it loads the executable that depends
40 | # on the library. The executable or the other shared library will
41 | # hardcode in the binary itself the additional search directories
42 | # to be passed to the dynamic linker. This works great in conjunction
43 | # with relative paths.
44 | # This command will enable support to RPATH to your project.
45 | # It will enable the following things:
46 | #
47 | # - If the project builds shared libraries it will generate a run-path
48 | # enabled shared library, i.e. its install name will be resolved
49 | # only at run time.
50 | # - In all cases (building executables and/or shared libraries)
51 | # dependent shared libraries with RPATH support will be properly
52 | #
53 | # The command has the following parameters:
54 | #
55 | # Options:
56 | # - ``USE_LINK_PATH``: if passed the command will automatically adds to
57 | # the RPATH the path to all the dependent libraries.
58 | #
59 | # Arguments:
60 | # - ``BIN_DIRS`` list of directories when the targets (executable and
61 | # plugins) will be installed.
62 | # - ``LIB_DIRS`` list of directories to be added to the RPATH. These
63 | # directories will be added "relative" w.r.t. the ``BIN_DIRS`` and
64 | # ``LIB_DIRS``.
65 | # - ``INSTALL_NAME_DIR`` directory where the libraries will be installed.
66 | # This variable will be used only if ``CMAKE_SKIP_RPATH`` or
67 | # ``CMAKE_SKIP_INSTALL_RPATH`` is set to ``TRUE`` as it will set the
68 | # ``INSTALL_NAME_DIR`` on all targets
69 | # - ``DEPENDS`` list of conditions that should be ``TRUE`` to enable
70 | # RPATH, for example ``FOO; NOT BAR``.
71 | #
72 | # Note: see https://gitlab.kitware.com/cmake/cmake/issues/16589 for further
73 | # details.
74 |
75 | #=======================================================================
76 | # Copyright 2014 Istituto Italiano di Tecnologia (IIT)
77 | # @author Francesco Romano
78 | #
79 | # Distributed under the OSI-approved BSD License (the "License");
80 | # see accompanying file Copyright.txt for details.
81 | #
82 | # This software is distributed WITHOUT ANY WARRANTY; without even the
83 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
84 | # See the License for more information.
85 | #=======================================================================
86 | # (To distribute this file outside of CMake, substitute the full
87 | # License text for the above reference.)
88 |
89 |
90 | include(CMakeParseArguments)
91 |
92 |
93 | function(ADD_INSTALL_RPATH_SUPPORT)
94 |
95 | set(_options USE_LINK_PATH)
96 | set(_oneValueArgs INSTALL_NAME_DIR)
97 | set(_multiValueArgs BIN_DIRS
98 | LIB_DIRS
99 | DEPENDS)
100 |
101 | cmake_parse_arguments(_ARS "${_options}"
102 | "${_oneValueArgs}"
103 | "${_multiValueArgs}"
104 | "${ARGN}")
105 |
106 | # if either RPATH or INSTALL_RPATH is disabled
107 | # and the INSTALL_NAME_DIR variable is set, then hardcode the install name
108 | if(CMAKE_SKIP_RPATH OR CMAKE_SKIP_INSTALL_RPATH)
109 | if(DEFINED _ARS_INSTALL_NAME_DIR)
110 | set(CMAKE_INSTALL_NAME_DIR ${_ARS_INSTALL_NAME_DIR} PARENT_SCOPE)
111 | endif()
112 | endif()
113 |
114 | if (CMAKE_SKIP_RPATH OR (CMAKE_SKIP_INSTALL_RPATH AND CMAKE_SKIP_BUILD_RPATH))
115 | return()
116 | endif()
117 |
118 |
119 | set(_rpath_available 1)
120 | if(DEFINED _ARS_DEPENDS)
121 | foreach(_dep ${_ARS_DEPENDS})
122 | string(REGEX REPLACE " +" ";" _dep "${_dep}")
123 | if(NOT (${_dep}))
124 | set(_rpath_available 0)
125 | endif()
126 | endforeach()
127 | endif()
128 |
129 | if(_rpath_available)
130 |
131 | # Enable RPATH on OSX.
132 | set(CMAKE_MACOSX_RPATH TRUE PARENT_SCOPE)
133 |
134 | # Find system implicit lib directories
135 | set(_system_lib_dirs ${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES})
136 | if(EXISTS "/etc/debian_version") # is this a debian system ?
137 | if(CMAKE_LIBRARY_ARCHITECTURE)
138 | list(APPEND _system_lib_dirs "/lib/${CMAKE_LIBRARY_ARCHITECTURE}"
139 | "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
140 | endif()
141 | endif()
142 | # This is relative RPATH for libraries built in the same project
143 | foreach(lib_dir ${_ARS_LIB_DIRS})
144 | list(FIND _system_lib_dirs "${lib_dir}" isSystemDir)
145 | if("${isSystemDir}" STREQUAL "-1")
146 | foreach(bin_dir ${_ARS_LIB_DIRS} ${_ARS_BIN_DIRS})
147 | file(RELATIVE_PATH _rel_path ${bin_dir} ${lib_dir})
148 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
149 | list(APPEND CMAKE_INSTALL_RPATH "@loader_path/${_rel_path}")
150 | else()
151 | list(APPEND CMAKE_INSTALL_RPATH "\$ORIGIN/${_rel_path}")
152 | endif()
153 | endforeach()
154 | endif()
155 | endforeach()
156 | if(NOT "${CMAKE_INSTALL_RPATH}" STREQUAL "")
157 | list(REMOVE_DUPLICATES CMAKE_INSTALL_RPATH)
158 | endif()
159 | set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} PARENT_SCOPE)
160 |
161 | # add the automatically determined parts of the RPATH
162 | # which point to directories outside the build tree to the install RPATH
163 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ${_ARS_USE_LINK_PATH} PARENT_SCOPE)
164 |
165 | endif()
166 |
167 | endfunction()
168 |
--------------------------------------------------------------------------------
/cmake/AddUninstallTarget.cmake:
--------------------------------------------------------------------------------
1 | #.rst:
2 | # AddUninstallTarget
3 | # ------------------
4 | #
5 | # Add the "uninstall" target for your project::
6 | #
7 | # include(AddUninstallTarget)
8 | #
9 | #
10 | # will create a file cmake_uninstall.cmake in the build directory and add a
11 | # custom target uninstall that will remove the files installed by your package
12 | # (using install_manifest.txt)
13 |
14 | #=============================================================================
15 | # Copyright 2008-2013 Kitware, Inc.
16 | # Copyright 2013 iCub Facility, Istituto Italiano di Tecnologia
17 | # Authors: Daniele E. Domenichelli
18 | #
19 | # Distributed under the OSI-approved BSD License (the "License");
20 | # see accompanying file Copyright.txt for details.
21 | #
22 | # This software is distributed WITHOUT ANY WARRANTY; without even the
23 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 | # See the License for more information.
25 | #=============================================================================
26 | # (To distribute this file outside of CMake, substitute the full
27 | # License text for the above reference.)
28 |
29 |
30 | if(DEFINED __ADD_UNINSTALL_TARGET_INCLUDED)
31 | return()
32 | endif()
33 | set(__ADD_UNINSTALL_TARGET_INCLUDED TRUE)
34 |
35 |
36 | set(_filename ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
37 |
38 | file(WRITE ${_filename}
39 | "if(NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\")
40 | message(WARNING \"Cannot find install manifest: \\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\"\")
41 | return()
42 | endif()
43 |
44 | file(READ \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\" files)
45 | string(STRIP \"\${files}\" files)
46 | string(REGEX REPLACE \"\\n\" \";\" files \"\${files}\")
47 | list(REVERSE files)
48 | foreach(file \${files})
49 | message(STATUS \"Uninstalling: \$ENV{DESTDIR}\${file}\")
50 | if(EXISTS \"\$ENV{DESTDIR}\${file}\")
51 | execute_process(
52 | COMMAND \${CMAKE_COMMAND} -E remove \"\$ENV{DESTDIR}\${file}\"
53 | OUTPUT_VARIABLE rm_out
54 | RESULT_VARIABLE rm_retval)
55 | if(NOT \"\${rm_retval}\" EQUAL 0)
56 | message(FATAL_ERROR \"Problem when removing \\\"\$ENV{DESTDIR}\${file}\\\"\")
57 | endif()
58 | else()
59 | message(STATUS \"File \\\"\$ENV{DESTDIR}\${file}\\\" does not exist.\")
60 | endif()
61 | endforeach(file)
62 | ")
63 |
64 | if("${CMAKE_GENERATOR}" MATCHES "^(Visual Studio|Xcode)")
65 | set(_uninstall "UNINSTALL")
66 | else()
67 | set(_uninstall "uninstall")
68 | endif()
69 | add_custom_target(${_uninstall} COMMAND "${CMAKE_COMMAND}" -P "${_filename}")
70 | set_property(TARGET ${_uninstall} PROPERTY FOLDER "CMakePredefinedTargets")
71 |
--------------------------------------------------------------------------------
/cmake/FetchuWebSockets.cmake:
--------------------------------------------------------------------------------
1 | # Download uSockets and uWebSockets
2 | include(FetchContent)
3 |
4 | FetchContent_Declare(usockets
5 | URL https://github.com/uNetworking/uSockets/archive/refs/tags/v0.8.5.zip)
6 | FetchContent_GetProperties(usockets)
7 |
8 | FetchContent_Declare(uwebsockets
9 | URL https://github.com/uNetworking/uWebSockets/archive/refs/tags/v20.37.0.zip)
10 | FetchContent_GetProperties(uwebsockets)
11 |
12 | if(NOT usockets_POPULATED AND NOT uwebsockets_POPULATED)
13 | FetchContent_Populate(usockets)
14 | FetchContent_Populate(uwebsockets)
15 |
16 | # Build uSockets
17 | find_package(OpenSSL REQUIRED)
18 | find_package(PkgConfig REQUIRED)
19 | pkg_check_modules(UV REQUIRED IMPORTED_TARGET libuv)
20 |
21 | # See https://github.com/uNetworking/uSockets/blob/v0.8.5/Makefile#L66
22 | # and https://github.com/uNetworking/uSockets/blob/v0.8.5/Makefile#L74
23 | file(GLOB US_SRCS ${usockets_SOURCE_DIR}/src/*.c ${usockets_SOURCE_DIR}/src/eventing/*.c
24 | ${usockets_SOURCE_DIR}/src/crypto/*.c ${usockets_SOURCE_DIR}/src/crypto/*.cpp)
25 |
26 | # Hardcode static library as we do not install the library and we do compile as shared
27 | add_library(uSockets STATIC ${US_SRCS})
28 | add_library(uSockets::uSockets ALIAS uSockets)
29 | # Necessary to link a static library to a shared library
30 | set_property(TARGET uSockets PROPERTY POSITION_INDEPENDENT_CODE ON)
31 |
32 | target_include_directories(uSockets PUBLIC
33 | $
34 | )
35 |
36 | target_link_libraries(uSockets PRIVATE OpenSSL::SSL OpenSSL::Crypto PkgConfig::UV)
37 |
38 | # See https://github.com/uNetworking/uSockets/blob/v0.8.5/Makefile#L32
39 | # and https://github.com/uNetworking/uSockets/blob/v0.8.5/Makefile#L15
40 | target_compile_definitions(uSockets PRIVATE -DLIBUS_USE_LIBUV -DLIBUS_USE_OPENSSL)
41 | target_compile_features(uSockets PRIVATE cxx_std_17)
42 |
43 | # Define target for uWebSockets
44 | add_library(uWebSockets INTERFACE)
45 | add_library(uWebSockets::uWebSockets ALIAS uWebSockets)
46 |
47 | target_include_directories(uWebSockets INTERFACE
48 | $
49 | )
50 |
51 | target_link_libraries(uWebSockets INTERFACE uSockets::uSockets ZLIB::ZLIB)
52 | target_compile_features(uWebSockets INTERFACE cxx_std_17)
53 | endif()
54 |
55 |
--------------------------------------------------------------------------------
/cmake/FinduSockets.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
2 | # SPDX-License-Identifier: BSD-3-Clause
3 |
4 | #[=======================================================================[.rst:
5 | FinduSockets
6 | -----------
7 |
8 | The following imported targets are created:
9 |
10 | uSockets::uSockets
11 |
12 | #]=======================================================================]
13 |
14 | include(FindPackageHandleStandardArgs)
15 |
16 | find_path(uSockets_INCLUDE_DIR libusockets.h)
17 | mark_as_advanced(uSockets_INCLUDE_DIR)
18 | find_library(uSockets_LIBRARY uSockets libuSockets)
19 | mark_as_advanced(uSockets_LIBRARY)
20 |
21 | find_package_handle_standard_args(uSockets DEFAULT_MSG uSockets_INCLUDE_DIR uSockets_LIBRARY)
22 |
23 | if(uSockets_FOUND)
24 | if(NOT TARGET uSockets::uSockets)
25 | add_library(uSockets::uSockets UNKNOWN IMPORTED)
26 | set_target_properties(uSockets::uSockets PROPERTIES
27 | INTERFACE_INCLUDE_DIRECTORIES "${uSockets_INCLUDE_DIR}")
28 | set_property(TARGET uSockets::uSockets PROPERTY
29 | IMPORTED_LOCATION "${uSockets_LIBRARY}")
30 | endif()
31 | endif()
32 |
--------------------------------------------------------------------------------
/cmake/FinduWebSockets.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
2 | # SPDX-License-Identifier: BSD-3-Clause
3 |
4 | #[=======================================================================[.rst:
5 | FinduWebSockets
6 | -----------
7 |
8 | Find the uWebSockets library.
9 |
10 | The following imported targets are created:
11 |
12 | uWebSockets::uWebSockets
13 |
14 | #]=======================================================================]
15 |
16 | include(FindPackageHandleStandardArgs)
17 | include(CMakeFindDependencyMacro)
18 |
19 | find_dependency(uSockets REQUIRED)
20 | find_dependency(ZLIB REQUIRED)
21 |
22 | # We do not use WebSocket.h as it has the same name of a
23 | # Windows system header, found for example in
24 | # C:/Program Files (x86)/Windows Kits/10/Include/10.0.19041.0/um
25 | find_path(uWebSockets_INCLUDE_DIR WebSocketProtocol.h PATH_SUFFIXES uWebSockets uwebsockets)
26 |
27 | mark_as_advanced(uWebSockets_INCLUDE_DIR)
28 |
29 | find_package_handle_standard_args(uWebSockets DEFAULT_MSG uWebSockets_INCLUDE_DIR)
30 |
31 | if(uWebSockets_FOUND)
32 | if(NOT TARGET uWebSockets::uWebSockets)
33 | add_library(uWebSockets::uWebSockets INTERFACE IMPORTED)
34 | set_target_properties(uWebSockets::uWebSockets PROPERTIES
35 | INTERFACE_INCLUDE_DIRECTORIES "${uWebSockets_INCLUDE_DIR}")
36 | set_target_properties(uWebSockets::uWebSockets PROPERTIES
37 | INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
38 | set_property(TARGET uWebSockets::uWebSockets APPEND PROPERTY
39 | INTERFACE_LINK_LIBRARIES uSockets::uSockets)
40 | endif()
41 | endif()
42 |
--------------------------------------------------------------------------------
/cmake/InstallBasicPackageFiles.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT)
2 | # SPDX-License-Identifier: BSD-3-Clause
3 |
4 | #[=======================================================================[.rst:
5 | InstallBasicPackageFiles
6 | ------------------------
7 |
8 | A helper module to make your package easier to be found by other
9 | projects.
10 |
11 |
12 | .. command:: install_basic_package_files
13 |
14 | Create and install a basic version of cmake config files for your
15 | project::
16 |
17 | install_basic_package_files(
18 | COMPATIBILITY
19 | [VERSION ]
20 | [ARCH_INDEPENDENT]
21 | [NO_EXPORT | EXPORT ] # (default = "EXPORT ")
22 | [NO_SET_AND_CHECK_MACRO]
23 | [NO_CHECK_REQUIRED_COMPONENTS_MACRO]
24 | [VARS_PREFIX ] # (default = "")
25 | [EXPORT_DESTINATION ]
26 | [INSTALL_DESTINATION ]
27 | [NAMESPACE ] # (default = "::")
28 | [EXTRA_PATH_VARS_SUFFIX path1 [path2 ...]]
29 | [CONFIG_TEMPLATE ]
30 | [UPPERCASE_FILENAMES | LOWERCASE_FILENAMES]
31 | [DEPENDENCIES " [...]" ...]
32 | [PRIVATE_DEPENDENCIES " [...]" ...]
33 | [INCLUDE_FILE | INCLUDE_CONTENT ]
34 | [COMPONENT ] # (default = "")
35 | )
36 |
37 | Depending on ``UPPERCASE_FILENAMES`` and ``LOWERCASE_FILENAMES``, this
38 | function generates 3 files:
39 |
40 | - ``ConfigVersion.cmake`` or ``-config-version.cmake``
41 | - ``Config.cmake`` or ``-config.cmake``
42 | - ``Targets.cmake`` or ``-targets.cmake``
43 |
44 | If neither ``UPPERCASE_FILENAMES`` nor ``LOWERCASE_FILENAMES`` is
45 | set, a file ``Config.cmake.in`` or
46 | ``-config.cmake.in`` is searched, and the convention
47 | is chosed according to the file found. If no file was found, the
48 | uppercase convention is used.
49 |
50 | The ``DEPENDENCIES`` argument can be used to set a list of dependencies
51 | that will be searched using the :cmake:command:`find_dependency` command
52 | from the :module:`CMakeFindDependencyMacro` module.
53 | Dependencies can be followed by any of the possible
54 | :cmake:command:`find_dependency` argument.
55 | In this case, all the arguments must be specified within double quotes (e.g.
56 | ``" 1.0.0 EXACT"``, or ``" CONFIG"``).
57 | The ``PRIVATE_DEPENDENCIES`` argument is similar to ``DEPENDENCIES``, but
58 | these dependencies are included only when :variable:`BUILD_SHARED_LIBS` is
59 | ``OFF``.
60 | If a libraries is declared ``STATIC``, ``OBJECT`` or ``INTERFACE``, and they
61 | link to some dependency, these should be added using the ``DEPENDENCIES``
62 | argument, since the ``PRIVATE_DEPENDENCIES`` argument would work only when
63 | :variable:`BUILD_SHARED_LIBS` is disabled.
64 |
65 | When using a custom template file, the ``@PACKAGE_DEPENDENCIES@``
66 | string is replaced with the code checking for the dependencies
67 | specified by these two argument.
68 |
69 | If the ``ARCH_INDEPENDENT`` option is enabled, the installed package version
70 | will be considered compatible even if it was built for a different
71 | architecture than the requested architecture.
72 |
73 | Each file is generated twice, one for the build directory and one for
74 | the installation directory. The ``INSTALL_DESTINATION`` argument can be
75 | passed to install the files in a location different from the default
76 | one (``${CMAKE_INSTALL_DATADIR}/cmake/${Name}`` if the ``ARCH_INDEPENDENT``
77 | option is enabled, ``${CMAKE_INSTALL_LIBDIR}/cmake/${Name}`` otherwise).
78 | The ``EXPORT_DESTINATION`` argument can be passed to
79 | generate the files in the build tree in a location different from the default
80 | one (``CMAKE_BINARY_DIR``). If this is a relative path, it is
81 | considered relative to the ``CMAKE_CURRENT_BINARY_DIR`` directory.
82 |
83 | The build directory is exported to the CMake user package registry if the
84 | build option ``CMAKE_EXPORT_PACKAGE_REGISTRY`` is set.
85 |
86 | The ``ConfigVersion.cmake`` file is generated using
87 | :cmake:command:`write_basic_package_version_file`. The ``VERSION``,
88 | ``COMPATIBILITY``, and ``ARCH_INDEPENDENT``arguments are passed to this
89 | function.
90 |
91 | ``VERSION`` shall be in the form ``[.[.[.]]]]``.
92 | If no ``VERSION`` is given, the ``PROJECT_VERSION`` variable is used.
93 | If this hasn’t been set, it errors out. The ``VERSION`` argument is also used
94 | to replace the ``@PACKAGE_VERSION@`` string in the configuration file.
95 |
96 | ``COMPATIBILITY`` shall be any of the options accepted by the
97 | :cmake:command:`write_basic_package_version_file` command
98 | (``AnyNewerVersion``, ``SameMajorVersion``, ``SameMinorVersion`` [CMake 3.11],
99 | or ``ExactVersion``).
100 | These options are explained in :cmake:command:`write_basic_package_version_file`
101 | command documentation.
102 | If your project has more elaborate version matching rules, you will need to
103 | write your own custom ConfigVersion.cmake file instead of using this macro.
104 |
105 | The ``Config.cmake`` file is generated using
106 | :cmake:command:`configure_package_config_file`. The
107 | ``NO_SET_AND_CHECK_MACRO``, ``NO_CHECK_REQUIRED_COMPONENTS_MACRO``, and
108 | arguments are passed to this function.
109 |
110 | By default :command:`install_basic_package_files` also generates the two helper
111 | macros ``set_and_check()`` and ``check_required_components()`` into the
112 | ``Config.cmake`` file. ``set_and_check()`` should be used instead of the
113 | normal :cmake:command:`set()` command for setting directories and file locations.
114 | Additionally to setting the variable it also checks that the referenced file
115 | or directory actually exists and fails with a ``FATAL_ERROR`` otherwise.
116 | This makes sure that the created ``Config.cmake`` file does not contain
117 | wrong references.
118 | When using the ``NO_SET_AND_CHECK_MACRO, this macro is not generated into the
119 | ``Config.cmake`` file.
120 |
121 | By default, :command:`install_basic_package_files` append a call to
122 | ``check_required_components()`` in ``Config.cmake`` file if the
123 | package supports components. This macro checks whether all requested,
124 | non-optional components have been found, and if this is not the case, sets the
125 | ``_FOUND`` variable to ``FALSE``, so that the package is considered to
126 | be not found. It does that by testing the ``__FOUND``
127 | variables for all requested required components. When using the
128 | ``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated
129 | into the ``Config.cmake`` file.
130 |
131 | Finally, the files in the build and install directory are exactly the same.
132 |
133 | See the documentation of :module:`CMakePackageConfigHelpers` module for
134 | further information and references therein.
135 |
136 | If the ``CONFIG_TEMPLATE`` argument is passed, the specified file
137 | is used as template for generating the configuration file, otherwise
138 | this module expects to find a ``Config.cmake.in`` or
139 | ``-config.cmake.in`` file either in current source directory.
140 | If the file does not exist, a very basic file is created.
141 |
142 | A set of variables are checked and passed to
143 | :cmake:command:`configure_package_config_file` as ``PATH_VARS``. For each of the
144 | ``SUFFIX`` considered, if one of the variables::
145 |
146 | _(BUILD|INSTALL)_
147 | (BUILD|INSTALL)__
148 |
149 | is defined, the ``_`` variable will be defined
150 | before configuring the package. In order to use that variable in the
151 | config file, you have to add a line::
152 |
153 | set_and_check(_ \"@PACKAGE__@\")
154 |
155 | if the path must exist or just::
156 |
157 | set(_ \"@PACKAGE__@\")
158 |
159 | if the path could be missing.
160 |
161 | These variable will have different values whether you are using the
162 | package from the build tree or from the install directory. Also these
163 | files will contain only relative paths, meaning that you can move the
164 | whole installation and the CMake files will still work.
165 |
166 | Default ``PATH_VARS`` suffixes are::
167 |
168 | BINDIR BIN_DIR
169 | SBINDIR SBIN_DIR
170 | LIBEXECDIR LIBEXEC_DIR
171 | SYSCONFDIR SYSCONF_DIR
172 | SHAREDSTATEDIR SHAREDSTATE_DIR
173 | LOCALSTATEDIR LOCALSTATE_DIR
174 | LIBDIR LIB_DIR
175 | INCLUDEDIR INCLUDE_DIR
176 | OLDINCLUDEDIR OLDINCLUDE_DIR
177 | DATAROOTDIR DATAROOT_DIR
178 | DATADIR DATA_DIR
179 | INFODIR INFO_DIR
180 | LOCALEDIR LOCALE_DIR
181 | MANDIR MAN_DIR
182 | DOCDIR DOC_DIR
183 |
184 | more suffixes can be added using the ``EXTRA_PATH_VARS_SUFFIX``
185 | argument.
186 |
187 |
188 | The ``Targets.cmake`` is generated using :cmake:command:`export(EXPORT)`
189 | in the build tree and :cmake:command:`install(EXPORT)` in the installation
190 | directory. The targets are exported using the value for the ``NAMESPACE``
191 | argument as namespace.
192 | The export can be passed using the ``EXPORT`` argument. If no export is
193 | used (e.g. for a CMake script library), pass ``NO_EXPORT``.
194 |
195 | If the ``INCLUDE_FILE`` argument is passed, the content of the specified file
196 | (which might contain ``@variables@``) is appended to the generated
197 | ``Config.cmake`` file.
198 | If the ``INCLUDE_CONTENT`` argument is passed, the specified content
199 | (which might contain ``@variables@``) is appended to the generated
200 | ``Config.cmake`` file.
201 | When a ``CONFIG_TEMPLATE`` is passed, or a ``ConfigVersion.cmake.in`` or
202 | a ``-config-version.cmake.in file is available, these 2 arguments are
203 | used to replace the ``@INCLUDED_CONTENT@`` string in this file.
204 | This allows one to inject custom code to this file, useful e.g. to set
205 | additional variables which are loaded by downstream projects.
206 |
207 | Note that content specified with ``INCLUDE_FILE`` or ``INCLUDE_CONTENT``
208 | cannot reference any of the ``PATH_VARS`` because this content is not
209 | expanded by :cmake:command:`configure_package_config_file`.
210 |
211 | If the ``COMPONENT`` argument is passed, it is forwarded to the
212 | :cmake:command:`install` commands, otherwise ```` is used.
213 | #]=======================================================================]
214 |
215 |
216 | if(COMMAND install_basic_package_files)
217 | return()
218 | endif()
219 |
220 |
221 | include(GNUInstallDirs)
222 | include(CMakePackageConfigHelpers)
223 | include(CMakeParseArguments)
224 |
225 |
226 | function(INSTALL_BASIC_PACKAGE_FILES _Name)
227 |
228 | set(_options ARCH_INDEPENDENT
229 | NO_EXPORT
230 | NO_SET_AND_CHECK_MACRO
231 | NO_CHECK_REQUIRED_COMPONENTS_MACRO
232 | UPPERCASE_FILENAMES
233 | LOWERCASE_FILENAMES
234 | NO_COMPATIBILITY_VARS # Deprecated
235 | ENABLE_COMPATIBILITY_VARS) # Deprecated
236 | set(_oneValueArgs VERSION
237 | COMPATIBILITY
238 | EXPORT
239 | FIRST_TARGET # Deprecated
240 | TARGETS_PROPERTY # Deprecated
241 | VARS_PREFIX
242 | EXPORT_DESTINATION
243 | INSTALL_DESTINATION
244 | DESTINATION # Deprecated
245 | NAMESPACE
246 | CONFIG_TEMPLATE
247 | INCLUDE_FILE
248 | INCLUDE_CONTENT
249 | COMPONENT)
250 | set(_multiValueArgs EXTRA_PATH_VARS_SUFFIX
251 | TARGETS # Deprecated
252 | TARGETS_PROPERTIES # Deprecated
253 | DEPENDENCIES
254 | PRIVATE_DEPENDENCIES)
255 | cmake_parse_arguments(_IBPF "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" "${ARGN}")
256 |
257 | if(NOT DEFINED _IBPF_VARS_PREFIX)
258 | set(_IBPF_VARS_PREFIX ${_Name})
259 | endif()
260 |
261 | if(NOT DEFINED _IBPF_VERSION)
262 | if(NOT DEFINED PROJECT_VERSION)
263 | message(FATAL_ERROR "VERSION argument is required (PROJECT_VERSION is not defined)")
264 | endif()
265 | set(_IBPF_VERSION ${PROJECT_VERSION})
266 | endif()
267 |
268 | if(NOT DEFINED _IBPF_COMPATIBILITY)
269 | message(FATAL_ERROR "COMPATIBILITY argument is required")
270 | endif()
271 |
272 | unset(_arch_independent)
273 | if(_IBPF_ARCH_INDEPENDENT)
274 | set(_arch_independent ARCH_INDEPENDENT)
275 | endif()
276 |
277 | if(_IBPF_UPPERCASE_FILENAMES AND _IBPF_LOWERCASE_FILENAMES)
278 | message(FATAL_ERROR "UPPERCASE_FILENAMES and LOWERCASE_FILENAMES arguments cannot be used together")
279 | endif()
280 |
281 | if(DEFINED _IBPF_INCLUDE_FILE AND DEFINED _IBPF_INCLUDE_CONTENT)
282 | message(FATAL_ERROR "INCLUDE_FILE and INCLUDE_CONTENT arguments cannot be used together")
283 | endif()
284 |
285 | # Prepare install and export commands
286 | unset(_targets)
287 | set(_install_cmd EXPORT ${_Name})
288 | set(_export_cmd EXPORT ${_Name})
289 |
290 | if(DEFINED _IBPF_EXPORT)
291 | if(_IBPF_NO_EXPORT OR DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES)
292 | message(FATAL_ERROR "EXPORT cannot be used with NO_EXPORT, TARGETS, TARGETS_PROPERTY, or TARGETS_PROPERTIES")
293 | endif()
294 |
295 | set(_export_cmd EXPORT ${_IBPF_EXPORT})
296 | set(_install_cmd EXPORT ${_IBPF_EXPORT})
297 |
298 | elseif(_IBPF_NO_EXPORT)
299 | if(DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES)
300 | message(FATAL_ERROR "NO_EXPORT cannot be used with TARGETS, TARGETS_PROPERTY, or TARGETS_PROPERTIES")
301 | endif()
302 |
303 | elseif(DEFINED _IBPF_TARGETS)
304 | message(DEPRECATION "TARGETS is deprecated. Use EXPORT instead")
305 |
306 | if(DEFINED _IBPF_TARGETS_PROPERTY OR DEFINED _IBPF_TARGETS_PROPERTIES)
307 | message(FATAL_ERROR "TARGETS cannot be used with TARGETS_PROPERTY or TARGETS_PROPERTIES")
308 | endif()
309 |
310 | set(_targets ${_IBPF_TARGETS})
311 | set(_export_cmd TARGETS ${_IBPF_TARGETS})
312 |
313 | elseif(DEFINED _IBPF_TARGETS_PROPERTY)
314 | message(DEPRECATION "TARGETS_PROPERTY is deprecated. Use EXPORT instead")
315 |
316 | if(DEFINED _IBPF_TARGETS_PROPERTIES)
317 | message(FATAL_ERROR "TARGETS_PROPERTIES cannot be used with TARGETS_PROPERTIES")
318 | endif()
319 |
320 | get_property(_targets GLOBAL PROPERTY ${_IBPF_TARGETS_PROPERTY})
321 | set(_export_cmd TARGETS ${_targets})
322 |
323 | elseif(DEFINED _IBPF_TARGETS_PROPERTIES)
324 | message(DEPRECATION "TARGETS_PROPERTIES is deprecated. Use EXPORT instead")
325 |
326 | set(_targets "") # Defined but empty
327 | foreach(_prop ${_IBPF_TARGETS_PROPERTIES})
328 | get_property(_prop_val GLOBAL PROPERTY ${_prop})
329 | list(APPEND _targets ${_prop_val})
330 | endforeach()
331 | set(_export_cmd TARGETS ${_targets})
332 |
333 | endif()
334 |
335 | # Path for installed cmake files
336 | if(DEFINED _IBPF_DESTINATION)
337 | message(DEPRECATION "DESTINATION is deprecated. Use INSTALL_DESTINATION instead")
338 | if(NOT DEFINED _IBPF_INSTALL_DESTINATION)
339 | set(_IBPF_INSTALL_DESTINATION ${_IBPF_DESTINATION})
340 | endif()
341 | endif()
342 |
343 | # If not set by the user, choose an adequate destination
344 | if(NOT DEFINED _IBPF_INSTALL_DESTINATION)
345 | if(_IBPF_ARCH_INDEPENDENT)
346 | set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/${_Name})
347 | else()
348 | set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_Name})
349 | endif()
350 | endif()
351 |
352 | # FIRST_TARGET is no longer used
353 | if(DEFINED _IBPF_FIRST_TARGET)
354 | message(DEPRECATION "FIRST_TARGET is deprecated.")
355 | endif()
356 |
357 | # NO_COMPATIBILITY_VARS and ENABLE_COMPATIBILITY_VARS cannot be used together
358 | if(_IBPF_NO_COMPATIBILITY_VARS AND _ENABLE_COMPATIBILITY_VARS)
359 | message(FATAL_ERROR "NO_COMPATIBILITY_VARS and ENABLE_COMPATIBILITY_VARS cannot be used together")
360 | endif()
361 | # NO_COMPATIBILITY_VARS is deprecated
362 | if(_IBPF_NO_COMPATIBILITY_VARS)
363 | message(DEPRECATION "NO_COMPATIBILITY_VARS is deprecated.")
364 | endif()
365 | # ENABLE_COMPATIBILITY_VARS is deprecated
366 | if(_IBPF_ENABLE_COMPATIBILITY_VARS)
367 | message(DEPRECATION "ENABLE_COMPATIBILITY_VARS is deprecated.")
368 | endif()
369 | # ENABLE_COMPATIBILITY_VARS does not work with EXPORT
370 | if(NOT DEFINED _targets AND _IBPF_ENABLE_COMPATIBILITY_VARS)
371 | message(FATAL_ERROR "ENABLE_COMPATIBILITY_VARS does not work with EXPORT")
372 | endif()
373 | # ENABLE_COMPATIBILITY_VARS can be enabled for projects still using targets
374 | if(DEFINED _targets AND NOT _IBPF_NO_COMPATIBILITY_VARS AND NOT _IBPF_ENABLE_COMPATIBILITY_VARS)
375 | message(DEPRECATION "Compatibility variables are no longer generated. Use ENABLE_COMPATIBILITY_VARS to re-enable them (deprecated) or define them using either INCLUDE_FILE or INCLUDE_CONTENT (recommended).")
376 | endif()
377 |
378 | if(NOT DEFINED _IBPF_EXPORT_DESTINATION)
379 | set(_IBPF_EXPORT_DESTINATION "${CMAKE_BINARY_DIR}")
380 | elseif(NOT IS_ABSOLUTE "${_IBPF_EXPORT_DESTINATION}")
381 | set(_IBPF_EXPORT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${_IBPF_EXPORT_DESTINATION}")
382 | endif()
383 |
384 | if(NOT DEFINED _IBPF_NAMESPACE)
385 | set(_IBPF_NAMESPACE "${_Name}::")
386 | endif()
387 |
388 | if(NOT DEFINED _IBPF_COMPONENT)
389 | set(_IBPF_COMPONENT "${_Name}")
390 | endif()
391 |
392 | if(_IBPF_NO_SET_AND_CHECK_MACRO)
393 | list(APPEND configure_package_config_file_extra_args NO_SET_AND_CHECK_MACRO)
394 | endif()
395 |
396 | if(_IBPF_NO_CHECK_REQUIRED_COMPONENTS_MACRO)
397 | list(APPEND configure_package_config_file_extra_args NO_CHECK_REQUIRED_COMPONENTS_MACRO)
398 | endif()
399 |
400 |
401 |
402 | # Set input file for config, and ensure that _IBPF_UPPERCASE_FILENAMES
403 | # and _IBPF_LOWERCASE_FILENAMES are set correctly
404 | unset(_config_cmake_in)
405 | set(_generate_file 0)
406 | if(DEFINED _IBPF_CONFIG_TEMPLATE)
407 | if(NOT EXISTS "${_IBPF_CONFIG_TEMPLATE}")
408 | message(FATAL_ERROR "Config template file \"${_IBPF_CONFIG_TEMPLATE}\" not found")
409 | endif()
410 | set(_config_cmake_in "${_IBPF_CONFIG_TEMPLATE}")
411 | if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES)
412 | if("${_IBPF_CONFIG_TEMPLATE}" MATCHES "${_Name}Config.cmake.in")
413 | set(_IBPF_UPPERCASE_FILENAMES 1)
414 | elseif("${_IBPF_CONFIG_TEMPLATE}" MATCHES "${_name}-config.cmake.in")
415 | set(_IBPF_LOWERCASE_FILENAMES 1)
416 | else()
417 | set(_IBPF_UPPERCASE_FILENAMES 1)
418 | endif()
419 | endif()
420 | else()
421 | string(TOLOWER "${_Name}" _name)
422 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in")
423 | set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in")
424 | if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES)
425 | set(_IBPF_UPPERCASE_FILENAMES 1)
426 | endif()
427 | elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_name}-config.cmake.in")
428 | set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_name}-config.cmake.in")
429 | if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES)
430 | set(_IBPF_LOWERCASE_FILENAMES 1)
431 | endif()
432 | else()
433 | set(_generate_file 1)
434 | if(_IBPF_LOWERCASE_FILENAMES)
435 | set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_name}-config.cmake.in")
436 | else()
437 | set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_Name}Config.cmake.in")
438 | set(_IBPF_UPPERCASE_FILENAMES 1)
439 | endif()
440 | endif()
441 | endif()
442 |
443 | # Set input file containing user variables
444 | if(DEFINED _IBPF_INCLUDE_FILE)
445 | if(NOT IS_ABSOLUTE "${_IBPF_INCLUDE_FILE}")
446 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}")
447 | set(_IBPF_INCLUDE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}")
448 | endif()
449 | endif()
450 | if(NOT EXISTS "${_IBPF_INCLUDE_FILE}")
451 | message(FATAL_ERROR "File \"${_IBPF_INCLUDE_FILE}\" not found")
452 | endif()
453 | file(READ ${_IBPF_INCLUDE_FILE} _IBPF_INCLUDE_CONTENT)
454 | endif()
455 |
456 | if(DEFINED _IBPF_INCLUDE_CONTENT)
457 | string(CONFIGURE ${_IBPF_INCLUDE_CONTENT}
458 | _IBPF_INCLUDE_CONTENT
459 | @ONLY)
460 | set(INCLUDED_CONTENT
461 | "#### Expanded from INCLUDE_FILE/INCLUDE_CONTENT by install_basic_package_files() ####
462 |
463 | ${_IBPF_INCLUDE_CONTENT}
464 |
465 | #####################################################################################
466 | ")
467 | endif()
468 |
469 | # Backwards compatibility
470 | if(NOT _generate_file AND DEFINED _IBPF_INCLUDE_FILE)
471 | file(READ ${_config_cmake_in} _config_cmake_in_content)
472 | if("${_config_cmake_in_content}" MATCHES "@INCLUDED_FILE_CONTENT@")
473 | message(DEPRECATION "The @INCLUDED_FILE_CONTENT@ variable is deprecated in favour of @INCLUDED_CONTENT@")
474 | set(INCLUDED_FILE_CONTENT "${INCLUDED_CONTENT}")
475 | endif()
476 | endif()
477 |
478 | # Select output file names
479 | if(_IBPF_UPPERCASE_FILENAMES)
480 | set(_config_filename ${_Name}Config.cmake)
481 | set(_version_filename ${_Name}ConfigVersion.cmake)
482 | set(_targets_filename ${_Name}Targets.cmake)
483 | elseif(_IBPF_LOWERCASE_FILENAMES)
484 | set(_config_filename ${_name}-config.cmake)
485 | set(_version_filename ${_name}-config-version.cmake)
486 | set(_targets_filename ${_name}-targets.cmake)
487 | endif()
488 |
489 |
490 | # If the template config file does not exist, write a basic one
491 | if(_generate_file)
492 | # Generate the compatibility code
493 | unset(_compatibility_vars)
494 | if(_IBPF_ENABLE_COMPATIBILITY_VARS)
495 | unset(_get_include_dir_code)
496 | unset(_set_include_dir_code)
497 | unset(_target_list)
498 | foreach(_target ${_targets})
499 | list(APPEND _target_list ${_IBPF_NAMESPACE}${_target})
500 | endforeach()
501 | if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDEDIR OR
502 | DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDEDIR OR
503 | DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDEDIR OR
504 | DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDEDIR)
505 | list(APPEND _include_dir_list "\"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDEDIR\@\"")
506 | elseif(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDE_DIR OR
507 | DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDE_DIR OR
508 | DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDE_DIR OR
509 | DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDE_DIR)
510 | list(APPEND _include_dir_list "\"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDE_DIR\@\"")
511 | else()
512 | unset(_include_dir_list)
513 | foreach(_target ${_targets})
514 | list(APPEND _include_dir_list "\$")
515 | endforeach()
516 | string(REPLACE ";" " " _include_dir_list "${_include_dir_list}")
517 | string(REPLACE ";" " " _target_list "${_target_list}")
518 | set(_set_include_dir "")
519 | endif()
520 | set(_compatibility_vars
521 | "# Compatibility\nset(${_Name}_LIBRARIES ${_target_list})
522 | set(${_Name}_INCLUDE_DIRS ${_include_dir_list})
523 | if(NOT \"\${${_Name}_INCLUDE_DIRS}\" STREQUAL \"\")
524 | list(REMOVE_DUPLICATES ${_Name}_INCLUDE_DIRS)
525 | endif()
526 | ")
527 | endif()
528 |
529 | if(_IBPF_NO_EXPORT)
530 | set(_include_targets_cmd "")
531 | else()
532 | set(_include_targets_cmd "include(\"\${CMAKE_CURRENT_LIST_DIR}/${_targets_filename}\")")
533 | endif()
534 |
535 | # Write the file
536 | file(WRITE "${_config_cmake_in}"
537 | "set(${_IBPF_VARS_PREFIX}_VERSION \@PACKAGE_VERSION\@)
538 |
539 | \@PACKAGE_INIT\@
540 |
541 | \@PACKAGE_DEPENDENCIES\@
542 |
543 | ${_include_targets_cmd}
544 |
545 | ${_compatibility_vars}
546 |
547 | \@INCLUDED_CONTENT\@
548 | ")
549 | endif()
550 |
551 | # Make relative paths absolute (needed later on) and append the
552 | # defined variables to _(build|install)_path_vars_suffix
553 | foreach(p BINDIR BIN_DIR
554 | SBINDIR SBIN_DIR
555 | LIBEXECDIR LIBEXEC_DIR
556 | SYSCONFDIR SYSCONF_DIR
557 | SHAREDSTATEDIR SHAREDSTATE_DIR
558 | LOCALSTATEDIR LOCALSTATE_DIR
559 | LIBDIR LIB_DIR
560 | INCLUDEDIR INCLUDE_DIR
561 | OLDINCLUDEDIR OLDINCLUDE_DIR
562 | DATAROOTDIR DATAROOT_DIR
563 | DATADIR DATA_DIR
564 | INFODIR INFO_DIR
565 | LOCALEDIR LOCALE_DIR
566 | MANDIR MAN_DIR
567 | DOCDIR DOC_DIR
568 | ${_IBPF_EXTRA_PATH_VARS_SUFFIX})
569 | if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p})
570 | list(APPEND _build_path_vars_suffix ${p})
571 | list(APPEND _build_path_vars "${_IBPF_VARS_PREFIX}_${p}")
572 | endif()
573 | if(DEFINED BUILD_${_IBPF_VARS_PREFIX}_${p})
574 | list(APPEND _build_path_vars_suffix ${p})
575 | list(APPEND _build_path_vars "${_IBPF_VARS_PREFIX}_${p}")
576 | endif()
577 | if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p})
578 | list(APPEND _install_path_vars_suffix ${p})
579 | list(APPEND _install_path_vars "${_IBPF_VARS_PREFIX}_${p}")
580 | endif()
581 | if(DEFINED INSTALL_${_IBPF_VARS_PREFIX}_${p})
582 | list(APPEND _install_path_vars_suffix ${p})
583 | list(APPEND _install_path_vars "${_IBPF_VARS_PREFIX}_${p}")
584 | endif()
585 | endforeach()
586 |
587 |
588 | # ConfigVersion.cmake file (same for build tree and intall)
589 | write_basic_package_version_file("${_IBPF_EXPORT_DESTINATION}/${_version_filename}"
590 | VERSION ${_IBPF_VERSION}
591 | COMPATIBILITY ${_IBPF_COMPATIBILITY}
592 | ${_arch_independent})
593 | install(FILES "${_IBPF_EXPORT_DESTINATION}/${_version_filename}"
594 | DESTINATION ${_IBPF_INSTALL_DESTINATION}
595 | COMPONENT ${_IBPF_COMPONENT})
596 |
597 |
598 | # Prepare PACKAGE_DEPENDENCIES variable
599 | set(_need_private_deps 0)
600 | if(NOT BUILD_SHARED_LIBS)
601 | set(_need_private_deps 1)
602 | endif()
603 |
604 | unset(PACKAGE_DEPENDENCIES)
605 | if(DEFINED _IBPF_DEPENDENCIES OR (DEFINED _IBPF_PRIVATE_DEPENDENCIES AND _need_private_deps))
606 | set(PACKAGE_DEPENDENCIES "#### Expanded from @PACKAGE_DEPENDENCIES@ by install_basic_package_files() ####\n\ninclude(CMakeFindDependencyMacro)\n")
607 |
608 | foreach(_dep ${_IBPF_DEPENDENCIES})
609 | string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n")
610 | endforeach()
611 |
612 | if(_need_private_deps)
613 | foreach(_dep ${_IBPF_PRIVATE_DEPENDENCIES})
614 | string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n")
615 | endforeach()
616 | endif()
617 |
618 | string(APPEND PACKAGE_DEPENDENCIES "\n###############################################################################\n")
619 | endif()
620 |
621 | # Prepare PACKAGE_VERSION variable
622 | set(PACKAGE_VERSION ${_IBPF_VERSION})
623 |
624 | # Config.cmake (build tree)
625 | foreach(p ${_build_path_vars_suffix})
626 | if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p})
627 | set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_BUILD_${p}}")
628 | elseif(DEFINED BUILD_${_IBPF_VARS_PREFIX}_${p})
629 | set(${_IBPF_VARS_PREFIX}_${p} "${BUILD_${_IBPF_VARS_PREFIX}_${p}}")
630 | endif()
631 | endforeach()
632 | configure_package_config_file("${_config_cmake_in}"
633 | "${_IBPF_EXPORT_DESTINATION}/${_config_filename}"
634 | INSTALL_DESTINATION ${_IBPF_EXPORT_DESTINATION}
635 | PATH_VARS ${_build_path_vars}
636 | ${configure_package_config_file_extra_args}
637 | INSTALL_PREFIX ${CMAKE_BINARY_DIR})
638 |
639 | # Config.cmake (installed)
640 | foreach(p ${_install_path_vars_suffix})
641 | if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p})
642 | set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_INSTALL_${p}}")
643 | elseif(DEFINED INSTALL_${_IBPF_VARS_PREFIX}_${p})
644 | set(${_IBPF_VARS_PREFIX}_${p} "${INSTALL_${_IBPF_VARS_PREFIX}_${p}}")
645 | endif()
646 | endforeach()
647 | configure_package_config_file("${_config_cmake_in}"
648 | "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_config_filename}.install"
649 | INSTALL_DESTINATION ${_IBPF_INSTALL_DESTINATION}
650 | PATH_VARS ${_install_path_vars}
651 | ${configure_package_config_file_extra_args})
652 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_config_filename}.install"
653 | DESTINATION ${_IBPF_INSTALL_DESTINATION}
654 | RENAME ${_config_filename}
655 | COMPONENT ${_IBPF_COMPONENT})
656 |
657 |
658 | # Targets.cmake (build tree)
659 | if(NOT _IBPF_NO_EXPORT)
660 | export(${_export_cmd}
661 | NAMESPACE ${_IBPF_NAMESPACE}
662 | FILE "${_IBPF_EXPORT_DESTINATION}/${_targets_filename}")
663 | endif()
664 |
665 | # Export build directory if CMAKE_EXPORT_PACKAGE_REGISTRY is set.
666 | # CMake >= 3.15 already checks for CMAKE_EXPORT_PACKAGE_REGISTRY in `export(PACKAGE)` (cf.
667 | # cf. https://cmake.org/cmake/help/latest/policy/CMP0090.html), and we effectively back-port
668 | # this behavior to earlier versions.
669 | # Note that even never CMake versions may apply old policy behaviors if the consuming project
670 | # requires a lower version of CMake (e.g. `cmake_minimum_required(VERSION 3.14)`), so the
671 | # check for `CMAKE_EXPORT_PACKAGE_REGISTRY` is necessary for CMake >= 3.15 as well.
672 | if(CMAKE_EXPORT_PACKAGE_REGISTRY)
673 | export(PACKAGE ${_Name})
674 | endif()
675 |
676 | # Targets.cmake (installed)
677 | if(NOT _IBPF_NO_EXPORT)
678 | install(${_install_cmd}
679 | NAMESPACE ${_IBPF_NAMESPACE}
680 | DESTINATION ${_IBPF_INSTALL_DESTINATION}
681 | FILE "${_targets_filename}"
682 | COMPONENT ${_IBPF_COMPONENT})
683 | endif()
684 | endfunction()
685 |
--------------------------------------------------------------------------------
/cmake/MeshcatCppDeps.cmake:
--------------------------------------------------------------------------------
1 | # Some dependencies are available in conda-forge but not in Debian/Ubuntu
2 | # If we are in a conda environment, let's assume that the dependency are available
3 | # and use them by default. Advanced user can always cahnge the MESHCAT_CPP_USE_SYSTEM_*
4 | # variables to match the desired behaviour
5 | if(DEFINED ENV{CONDA_PREFIX})
6 | set(MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS_DEFAULT ON)
7 | set(MESHCAT_CPP_USE_SYSTEM_MSGPACKCXX_DEFAULT ON)
8 | else()
9 | set(MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS_DEFAULT OFF)
10 | set(MESHCAT_CPP_USE_SYSTEM_MSGPACKCXX_DEFAULT OFF)
11 | endif()
12 |
13 | option(MESHCAT_CPP_USE_SYSTEM_STDUUID "Use system stduuid" OFF)
14 | mark_as_advanced(MESHCAT_CPP_USE_SYSTEM_STDUUID)
15 | if(MESHCAT_CPP_USE_SYSTEM_STDUUID)
16 | find_package(stduuid REQUIRED)
17 | else()
18 | include(FetchContent)
19 | FetchContent_Declare(
20 | stduuid
21 | GIT_REPOSITORY https://github.com/mariusbancila/stduuid.git
22 | GIT_TAG v1.2.3
23 | )
24 | FetchContent_GetProperties(stduuid)
25 | if(NOT stduuid_POPULATED)
26 | FetchContent_Populate(stduuid)
27 | #set(UUID_USING_CXX20_SPAN ON CACHE BOOL "" FORCE)
28 | add_subdirectory(${stduuid_SOURCE_DIR} ${stduuid_BINARY_DIR} EXCLUDE_FROM_ALL)
29 | endif()
30 | endif()
31 |
32 |
33 | option(MESHCAT_CPP_USE_SYSTEM_MSGPACKCXX "Use system msgpack-cxx" ${MESHCAT_CPP_USE_SYSTEM_MSGPACKCXX_DEFAULT})
34 | mark_as_advanced(MESHCAT_CPP_USE_SYSTEM_MSGPACKCXX)
35 | if(MESHCAT_CPP_USE_SYSTEM_MSGPACKCXX)
36 | find_package(msgpack-cxx REQUIRED)
37 | else()
38 | include(FetchContent)
39 | FetchContent_Declare(
40 | msgpack-cxx
41 | URL https://github.com/msgpack/msgpack-c/archive/refs/tags/cpp-6.0.0.zip
42 | )
43 | FetchContent_GetProperties(msgpack-cxx)
44 | if(NOT msgpack-cxx_POPULATED)
45 | FetchContent_Populate(msgpack-cxx)
46 | add_subdirectory(${msgpack-cxx_SOURCE_DIR} ${msgpack-cxx_BINARY_DIR} EXCLUDE_FROM_ALL)
47 | endif()
48 | endif()
49 |
50 | option(MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS "Use system uwebsockets" ${MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS_DEFAULT})
51 | if(NOT MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS AND NOT BUILD_SHARED_LIBS)
52 | message(FATAL_ERROR "MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS and BUILD_SHARED_LIBS can't be OFF at the same time")
53 | endif()
54 | mark_as_advanced(MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS)
55 | if(MESHCAT_CPP_USE_SYSTEM_UWEBSOCKETS)
56 | find_package(uWebSockets REQUIRED)
57 | else()
58 | include(FetchuWebSockets)
59 | endif()
60 |
61 | # Handle relocatability via cmrc
62 | option(MESHCAT_CPP_USE_SYSTEM_CMRC "Use system cmrc" OFF)
63 | mark_as_advanced(MESHCAT_CPP_USE_SYSTEM_CMRC)
64 | if(MESHCAT_CPP_USE_SYSTEM_CMRC)
65 | find_package(CMakeRC REQUIRED)
66 | else()
67 | include(FetchContent)
68 | FetchContent_Declare(
69 | cmrc
70 | GIT_REPOSITORY https://github.com/vector-of-bool/cmrc.git
71 | GIT_TAG 2.0.1
72 | )
73 | FetchContent_GetProperties(cmrc)
74 | if(NOT cmrc_POPULATED)
75 | FetchContent_Populate(cmrc)
76 | add_subdirectory(${cmrc_SOURCE_DIR} ${cmrc_BINARY_DIR} EXCLUDE_FROM_ALL)
77 | endif()
78 | endif()
79 |
--------------------------------------------------------------------------------
/examples/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(example meshcat_example.cpp)
2 | target_link_libraries(example ${PROJECT_NAME}::${PROJECT_NAME})
3 |
--------------------------------------------------------------------------------
/examples/meshcat_example.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file meshcat_example.cpp
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 |
14 | MeshcatCpp::MatrixView array_to_matrix_view(std::array& array)
15 | {
16 | constexpr MeshcatCpp::MatrixView::index_type rows = 4;
17 | constexpr MeshcatCpp::MatrixView::index_type cols = 4;
18 | constexpr auto order = MeshcatCpp::MatrixStorageOrdering::ColumnMajor;
19 | return MeshcatCpp::make_matrix_view(array.data(), rows, cols, order);
20 | }
21 |
22 | int main()
23 | {
24 | MeshcatCpp::Meshcat meshcat;
25 | MeshcatCpp::Material m = MeshcatCpp::Material::get_default_material();
26 |
27 | std::array transform = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
28 | auto matrix_view = array_to_matrix_view(transform);
29 |
30 | m.set_color(66, 133, 244, 0.5);
31 | meshcat.set_object("box", MeshcatCpp::Box(0.5, 0.5, 0.5), m);
32 | matrix_view(1, 3) = 1.75;
33 |
34 | meshcat.set_transform("box", matrix_view);
35 |
36 | m.set_color(234, 67, 53);
37 | meshcat.set_object("sphere", MeshcatCpp::Sphere(0.5), m);
38 | matrix_view(1, 3) = 0.75;
39 | meshcat.set_transform("sphere", matrix_view);
40 |
41 | m.set_color(251, 188, 5, 0.5);
42 | meshcat.set_object("ellipsoid", MeshcatCpp::Ellipsoid(0.5, 0.25, 0.75), m);
43 | matrix_view(1, 3) = -0.75;
44 | meshcat.set_transform("ellipsoid", matrix_view);
45 |
46 | m.set_color(52, 168, 83);
47 | meshcat.set_object("cylinder", MeshcatCpp::Cylinder(0.25, 0.5), m);
48 | matrix_view(1, 3) = -1.75;
49 | meshcat.set_transform("cylinder", matrix_view);
50 |
51 | const auto stl_path = std::filesystem::path(__FILE__).parent_path() / "misc" / "Dragonite.stl";
52 | auto transparent_default = MeshcatCpp::Material::get_default_material();
53 | transparent_default.transparent = true;
54 | transparent_default.opacity = 0.5;
55 | meshcat.set_object("obj", MeshcatCpp::Mesh(stl_path.string(), 0.01), transparent_default);
56 | matrix_view(0, 3) = -1;
57 | matrix_view(1, 3) = 0;
58 | matrix_view(0, 0) = 0;
59 | matrix_view(1, 1) = 0;
60 | matrix_view(0, 1) = -1;
61 | matrix_view(1, 0) = 1;
62 | meshcat.set_transform("obj", matrix_view);
63 |
64 | meshcat.join();
65 |
66 | return EXIT_SUCCESS;
67 | }
68 |
--------------------------------------------------------------------------------
/examples/misc/Dragonite.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ami-iit/meshcat-cpp/a84be7add7f344d61e615bee7f26e6a7d5444f2a/examples/misc/Dragonite.stl
--------------------------------------------------------------------------------
/examples/misc/LICENSE_DRAGONITE_STL:
--------------------------------------------------------------------------------
1 | Dragonite(Pokemon) by Patrickartis licensed under the [Creative Commons - Attribution - Non-Commercial - Share Alike](https://creativecommons.org/licenses/by-nc-sa/4.0/) license.
--------------------------------------------------------------------------------
/include/MeshcatCpp/Material.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Material.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #ifndef MESHCAT_CPP_MATERIAL_H
9 | #define MESHCAT_CPP_MATERIAL_H
10 |
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | namespace MeshcatCpp
19 | {
20 |
21 | struct Material
22 | {
23 | public:
24 | enum class Type
25 | {
26 | MeshBasicMaterial,
27 | MeshPhongMaterial,
28 | MeshLambertMaterial,
29 | MeshToonMaterial,
30 | LineBasicMaterial
31 | };
32 |
33 | int color{(229 << 16) + (229 << 8) + 229};
34 | std::optional reflectivity;
35 | std::optional side;
36 | std::optional transparent;
37 | std::optional opacity;
38 | std::optional linewidth;
39 | std::optional wireframe;
40 | std::optional wireframeLineWidth;
41 | bool vertexColors{false};
42 | Type type{Type::MeshPhongMaterial};
43 |
44 | const std::unordered_map type_map{{Type::MeshBasicMaterial, "MeshBasicMaterial"},
45 | {Type::MeshPhongMaterial, "MeshPhongMaterial"},
46 | {Type::MeshLambertMaterial, "MeshLambertMaterial"},
47 | {Type::MeshToonMaterial, "MeshToonMaterial"},
48 | {Type::LineBasicMaterial, "LineBasicMaterial"}};
49 |
50 |
51 | void set_color(uint8_t r, uint8_t g, uint8_t b, double a = 1.0);
52 |
53 | static Material get_default_material();
54 | };
55 |
56 | } // namespace MeshcatCpp
57 |
58 | #endif // MESHCAT_CPP_MATERIAL_H
59 |
--------------------------------------------------------------------------------
/include/MeshcatCpp/MatrixView.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file MatrixView.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #ifndef MESHCAT_CPP_MATRIX_VIEW_H
9 | #define MESHCAT_CPP_MATRIX_VIEW_H
10 |
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | namespace MeshcatCpp
17 | {
18 |
19 | namespace MatrixViewInternal
20 | {
21 | /**
22 | * has_IsRowMajor is used to build a type-dependent expression that check if an
23 | * element has IsRowMajor argument. This specific implementation is used when
24 | * the the object has not IsRowMajor.
25 | */
26 | template struct has_IsRowMajor : std::false_type
27 | {
28 | };
29 |
30 | /**
31 | * has_IsRowMajor is used to build a type-dependent expression that check if an
32 | * element has IsRowMajor argument. This specific implementation is used when
33 | * the the object has not IsRowMajor, indeed void_t<\endcode> is used to
34 | * detect ill-formed types in SFINAE context.
35 | */
36 | template
37 | struct has_IsRowMajor> : std::true_type
38 | {
39 | };
40 | } // namespace MatrixViewInternal
41 |
42 | namespace details
43 | {
44 | template
45 | struct is_allowed_element_type_conversion
46 | : public std::integral_constant::value>
47 | {
48 | };
49 |
50 | } // namespace details
51 |
52 | /**
53 | * Enum describing the possible matrix storage ordering
54 | */
55 | enum class MatrixStorageOrdering
56 | {
57 | RowMajor, /*!< Row Major ordering, i.e. matrix is serialized row by row */
58 | ColumnMajor /*!< Column Major ordering, i.e. matrix is serialized row by column */
59 | };
60 |
61 | /**
62 | * MatrixView implements a view interface of Matrices. Both RowMajor and ColumnMajor matrices are
63 | * supported.
64 | * @note The user should define the storage ordering when the MatrixView is created (the default
65 | order is RowMajor). However if the MatrixView is generated:
66 | * - from an object having a public member called IsRowMajor
, the correct storage
67 | order is chosen.
68 | * - from another MatrixView, the correct storage order is chosen.
69 | * @note the original implementation can be found in
70 | https://github.com/robotology/idyntree/blob/a7fdef001d38e47aabcdc541607a255101212dd9/src/core/include/iDynTree/Core/MatrixView.h
71 | */
72 | template class MatrixView
73 | {
74 | public:
75 | using element_type = ElementType;
76 | using value_type = std::remove_cv_t;
77 | using index_type = std::ptrdiff_t;
78 | using pointer = element_type*;
79 | using reference = element_type&;
80 |
81 | private:
82 | pointer m_storage;
83 | index_type m_rows;
84 | index_type m_cols;
85 |
86 | MatrixStorageOrdering m_storageOrder;
87 |
88 | index_type m_innerStride;
89 | index_type m_outerStride;
90 |
91 | index_type rawIndex(index_type row, index_type col) const
92 | {
93 | if (m_storageOrder == MatrixStorageOrdering::RowMajor)
94 | {
95 | return (col + this->m_outerStride * row);
96 | } else
97 | {
98 | return (this->m_outerStride * col + row);
99 | }
100 | }
101 |
102 | public:
103 | MatrixView()
104 | : MatrixView(nullptr, 0, 0, MatrixStorageOrdering::RowMajor)
105 | {
106 | }
107 | MatrixView(const MatrixView& other)
108 | : MatrixView(other.m_storage, other.m_rows, other.m_cols, other.m_storageOrder)
109 | {
110 | }
111 |
112 | template ::value_type,
115 | value_type>::value>>
116 | constexpr MatrixView(const MatrixView& other)
117 | : MatrixView(other.data(), other.rows(), other.cols(), other.storageOrder())
118 | {
119 | }
120 |
121 | template ::value
123 | && std::is_convertible().data()),
124 | pointer>::value
125 | && MatrixViewInternal::has_IsRowMajor::value
126 | && !std::is_same::value,
127 | int> = 0>
128 | MatrixView(const Container& matrix)
129 | : MatrixView(matrix.data(),
130 | matrix.rows(),
131 | matrix.cols(),
132 | Container::IsRowMajor ? MatrixStorageOrdering::RowMajor
133 | : MatrixStorageOrdering::ColumnMajor)
134 | {
135 | }
136 |
137 | template ::value
139 | && std::is_convertible().data()),
140 | pointer>::value
141 | && !MatrixViewInternal::has_IsRowMajor::value
142 | && !std::is_same::value,
143 | int> = 0>
144 | MatrixView(const Container& matrix,
145 | const MatrixStorageOrdering& order = MatrixStorageOrdering::RowMajor)
146 | : MatrixView(matrix.data(), matrix.rows(), matrix.cols(), order)
147 | {
148 | }
149 |
150 | template ().data()), pointer>::value
153 | && MatrixViewInternal::has_IsRowMajor::value
154 | && !std::is_same::value,
155 | int> = 0>
156 | MatrixView(Container& matrix)
157 | : MatrixView(matrix.data(),
158 | matrix.rows(),
159 | matrix.cols(),
160 | Container::IsRowMajor ? MatrixStorageOrdering::RowMajor
161 | : MatrixStorageOrdering::ColumnMajor)
162 | {
163 | }
164 |
165 | template ().data()), pointer>::value
168 | && !MatrixViewInternal::has_IsRowMajor::value
169 | && !std::is_same::value
170 | && !std::is_same().data())>>>::value,
173 | int> = 0>
174 | MatrixView(Container& matrix,
175 | const MatrixStorageOrdering& order = MatrixStorageOrdering::RowMajor)
176 | : MatrixView(matrix.data(), matrix.rows(), matrix.cols(), order)
177 | {
178 | }
179 |
180 | MatrixView(pointer in_data,
181 | index_type in_rows,
182 | index_type in_cols,
183 | const MatrixStorageOrdering& order = MatrixStorageOrdering::RowMajor)
184 | : m_storage(in_data)
185 | , m_rows(in_rows)
186 | , m_cols(in_cols)
187 | , m_storageOrder(order)
188 | , m_innerStride(1)
189 | , m_outerStride(order == MatrixStorageOrdering::RowMajor ? in_cols : in_rows)
190 | {
191 | }
192 |
193 | const MatrixStorageOrdering& storageOrder() const noexcept
194 | {
195 | return m_storageOrder;
196 | }
197 |
198 | pointer data() const noexcept
199 | {
200 | return m_storage;
201 | }
202 |
203 | template ::value_type, value_type>>>
206 | MatrixView& operator=(MatrixView other)
207 | {
208 | assert(other.rows() == this->rows());
209 | assert(other.cols() == this->cols());
210 |
211 | if (other.storageOrder() == this->storageOrder())
212 | {
213 | std::memcpy(this->m_storage,
214 | other.data(),
215 | this->rows() * this->cols() * sizeof(element_type));
216 |
217 | return *this;
218 | }
219 |
220 | for (index_type i = 0; i < this->rows(); i++)
221 | {
222 | for (index_type j = 0; j < this->cols(); j++)
223 | {
224 | this->operator()(i, j) = other(i, j);
225 | }
226 | }
227 |
228 | return *this;
229 | }
230 |
231 | /**
232 | * @name Matrix interface methods.
233 | * Methods exposing a matrix-like interface to MatrixView.
234 | *
235 | */
236 | ///@{
237 | reference operator()(index_type row, const index_type col) const
238 | {
239 | assert(row < this->rows());
240 | assert(col < this->cols());
241 | return this->m_storage[rawIndex(row, col)];
242 | }
243 |
244 | index_type rows() const noexcept
245 | {
246 | return this->m_rows;
247 | }
248 |
249 | index_type cols() const noexcept
250 | {
251 | return this->m_cols;
252 | }
253 | ///@}
254 |
255 | MatrixView
256 | block(index_type startingRow, index_type startingColumn, index_type rows, index_type cols) const
257 | {
258 | assert(rows <= this->rows());
259 | assert(cols <= this->cols());
260 |
261 | const index_type offset = rawIndex(startingRow, startingColumn);
262 | assert(offset < this->rows() * this->cols());
263 |
264 | MatrixView block;
265 | block = *this;
266 | block.m_rows = rows;
267 | block.m_cols = cols;
268 | block.m_storage = this->m_storage + offset;
269 |
270 | return block;
271 | }
272 | };
273 |
274 | template
275 | constexpr MatrixView
276 | make_matrix_view(ElementType* ptr,
277 | typename MatrixView::index_type rows,
278 | typename MatrixView::index_type cols,
279 | MatrixStorageOrdering order = MatrixStorageOrdering::RowMajor)
280 | {
281 | return MatrixView(ptr, rows, cols, order);
282 | }
283 |
284 | template ::value
287 | || std::is_same, Container>::value,
288 | int> = 0>
289 | constexpr MatrixView make_matrix_view(Container& cont)
290 | {
291 | return MatrixView(cont);
292 | }
293 |
294 | template ::value
296 | || std::is_same,
297 | Container>::value,
298 | int> = 0>
299 | constexpr MatrixView make_matrix_view(const Container& cont)
300 | {
301 | return MatrixView(cont);
302 | }
303 |
304 | template ::value
307 | && !std::is_same, Container>::value,
308 | int> = 0>
309 | constexpr MatrixView
310 | make_matrix_view(Container& cont,
311 | typename MatrixView::MatrixStorageOrdering order
312 | = MatrixView::MatrixStorageOrdering::RowMajor)
313 | {
314 | return MatrixView(cont, order);
315 | }
316 |
317 | template ::value
320 | && !std::is_same, Container>::value,
321 | int> = 0>
322 | constexpr MatrixView make_matrix_view(
323 | const Container& cont,
324 | typename MatrixView::MatrixStorageOrdering order
325 | = MatrixView::MatrixStorageOrdering::RowMajor)
326 | {
327 | return MatrixView(cont, order);
328 | }
329 |
330 | } // namespace MeshcatCpp
331 |
332 | #endif /* IDYNTREE_MATRIX_MATRIX_VIEW_H */
333 |
--------------------------------------------------------------------------------
/include/MeshcatCpp/Meshcat.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Meshcat.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | // Part of the content of this file has been taken from drake. Drake lincense follows
9 | //
10 | // All components of Drake are licensed under the BSD 3-Clause License
11 | // shown below. Where noted in the source code, some portions may
12 | // be subject to other permissive, non-viral licenses.
13 | //
14 | // Copyright 2012-2022 Robot Locomotion Group @ CSAIL
15 | // All rights reserved.
16 | //
17 | // Redistribution and use in source and binary forms, with or without
18 | // modification, are permitted provided that the following conditions are
19 | // met:
20 | //
21 | // Redistributions of source code must retain the above copyright notice,
22 | // this list of conditions and the following disclaimer. Redistributions
23 | // in binary form must reproduce the above copyright notice, this list of
24 | // conditions and the following disclaimer in the documentation and/or
25 | // other materials provided with the distribution. Neither the name of
26 | // the Massachusetts Institute of Technology nor the names of its
27 | // contributors may be used to endorse or promote products derived from
28 | // this software without specific prior written permission.
29 | //
30 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 |
42 | #ifndef MESHCAT_CPP_MESHCAT_H
43 | #define MESHCAT_CPP_MESHCAT_H
44 |
45 | #include
46 |
47 | #include
48 | #include
49 | #include
50 |
51 | namespace MeshcatCpp
52 | {
53 | /**
54 | * The Meshcat class provides an interface to [meshcat](https://github.com/rdeits/meshcat).
55 | * This class's instances start a thread that runs a http/websocket server. Users may view the
56 | * Meshcat scene by navigating their browser to the hosted URL.
57 | * Users can exploit this class to load primary shapes (e.g. spheres, cylinders ellipsoids and
58 | * boxes). For example,
59 | * @verbatim
60 | * Meshcat viz;
61 | * viz.set_object("box", MeshcatCpp::Box(0.1, 0.1, 0.1));
62 | * @endverbatim
63 | * will start an interface between meshcat and load a box.
64 | * @note the Design of this class took inspiration form drake Meshcat C++ implementation.
65 | * Please refer to https://github.com/RobotLocomotion/drake/issues/13038 if you are interested in
66 | * the original project.
67 | */
68 | class Meshcat
69 | {
70 | public:
71 | Meshcat& operator=(const Meshcat&) = delete;
72 | Meshcat(const Meshcat&) = delete;
73 |
74 | /**
75 | * Constructs the Meshcat instance. It will listen on the first available port starting at 7001
76 | * (up to 7099).
77 | */
78 | Meshcat();
79 |
80 | ~Meshcat();
81 |
82 | /**
83 | * Utility function to make the meshcat interface run forever (until the user stop the
84 | * application)
85 | */
86 | void join();
87 |
88 | void set_property(std::string_view path, const std::string& property, bool value);
89 |
90 | void set_object(std::string_view path,
91 | const Sphere& sphere,
92 | const Material& material = Material::get_default_material());
93 |
94 | void set_object(std::string_view path,
95 | const Cylinder& cylinder,
96 | const Material& material = Material::get_default_material());
97 |
98 | void set_object(std::string_view path,
99 | const Box& box,
100 | const Material& material = Material::get_default_material());
101 |
102 | void set_object(std::string_view path,
103 | const Ellipsoid& ellipsoid,
104 | const Material& material = Material::get_default_material());
105 |
106 | void set_object(std::string_view path,
107 | const Mesh& mesh,
108 | const Material& material = Material::get_default_material());
109 |
110 | void set_transform(std::string_view path, const MatrixView& matrix);
111 |
112 | private:
113 | class Impl;
114 | std::unique_ptr pimpl_;
115 | };
116 |
117 | } // namespace MeshcatCpp
118 |
119 | #endif // MESHCAT_CPP_MESHCAT_H
120 |
--------------------------------------------------------------------------------
/include/MeshcatCpp/Property.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Property.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #ifndef MESHCAT_CPP_PROPERTY_H
9 | #define MESHCAT_CPP_PROPERTY_H
10 |
11 | #include
12 |
13 | namespace MeshcatCpp
14 | {
15 |
16 | template struct Property
17 | {
18 | std::string path;
19 | std::string property;
20 | T value;
21 | };
22 |
23 | } // namespace MeshcatCpp
24 |
25 | #endif // MESHCAT_CPP_MATERIAL_H
26 |
--------------------------------------------------------------------------------
/include/MeshcatCpp/Shape.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Shape.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #ifndef MESHCAT_CPP_SHAPE_H
9 | #define MESHCAT_CPP_SHAPE_H
10 |
11 | #include
12 |
13 | #define MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(type, attribute) \
14 | private: \
15 | type attribute##_; \
16 | \
17 | public: \
18 | const type& attribute() const \
19 | { \
20 | return this->attribute##_; \
21 | }
22 |
23 | namespace MeshcatCpp
24 | {
25 |
26 | struct Shape
27 | {
28 | const std::string type;
29 | };
30 |
31 | class Sphere : public Shape
32 | {
33 | public:
34 | Sphere(double radius);
35 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, radius);
36 | };
37 |
38 | class Ellipsoid : public Shape
39 | {
40 | public:
41 | Ellipsoid(double a, double b, double c);
42 |
43 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, a);
44 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, b);
45 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, c);
46 | };
47 |
48 | class Cylinder : public Shape
49 | {
50 | public:
51 | Cylinder(double radius, double height);
52 |
53 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, radius);
54 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, height);
55 | };
56 |
57 | class Box : public Shape
58 | {
59 | public:
60 | Box(double width, double depth, double height);
61 |
62 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, width);
63 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, depth);
64 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, height);
65 | };
66 |
67 | class Mesh : public Shape
68 | {
69 | public:
70 | Mesh(std::string_view file_path, double scale = 1);
71 |
72 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(std::string, file_path);
73 | MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE(double, scale);
74 | };
75 |
76 |
77 | } // namespace MeshcatCpp
78 |
79 | #undef MESHCAT_CPP_ADD_SHAPE_ATTRIBUTE
80 |
81 | #endif // MESHCAT_CPP_SHAPE_H
82 |
--------------------------------------------------------------------------------
/include/MeshcatCpp/impl/FindResource.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file FindResource.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #ifndef MESHCAT_CPP_FIND_ASSET_H
9 | #define MESHCAT_CPP_FIND_ASSET_H
10 |
11 | #include
12 | #include
13 |
14 | namespace MeshcatCpp::details
15 | {
16 |
17 | std::filesystem::path get_resource_path(const std::string& resource);
18 |
19 | } // namespace MeshcatCpp::details
20 |
21 | #endif // MESHCAT_CPP_FIND_ASSET_H
22 |
--------------------------------------------------------------------------------
/include/MeshcatCpp/impl/MsgpackTypes.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file MsgpackTypes.h
3 | * @authors Giulio Romualdi
4 | * @copyright This software may be modified and distributed under the terms of the BSD-3-Clause
5 | * license.
6 | */
7 |
8 | #ifndef MESHCAT_CPP_MSGPACK_TYPES_H
9 | #define MESHCAT_CPP_MSGPACK_TYPES_H
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 |
17 | #include
18 |
19 | #define PACK_MAP_VAR(packer, var) \
20 | packer.pack(#var); \
21 | packer.pack(var);
22 |
23 | #define PACK_MAP_VAR_WITH_NAME(packer, name, var) \
24 | packer.pack(#name); \
25 | packer.pack(var);
26 |
27 | #define PACK_MAP_VAR_FROM_INNER_CLASS(packer, inner_class, var) \
28 | PACK_MAP_VAR_WITH_NAME(packer, var, inner_class.var);
29 |
30 | #define PACK_MAP_OPTIONAL_VAR_WITH_NAME(packer, name, var) \
31 | if (var) \
32 | { \
33 | PACK_MAP_VAR_WITH_NAME(packer, name, var.value()); \
34 | }
35 |
36 | #define PACK_MAP_OPTIONAL_VAR_FROM_INNER_CLASS(packer, inner_class, var) \
37 | PACK_MAP_OPTIONAL_VAR_WITH_NAME(packer, var, inner_class.var);
38 |
39 | #define SHAPE_TRAMPOLINE(shape) \
40 | struct shape##Trampoline; \
41 | template <> struct traits<::MeshcatCpp::shape> \
42 | { \
43 | using trampoline = shape##Trampoline; \
44 | };
45 |
46 | namespace MeshcatCpp::details
47 | {
48 |
49 | template struct traits;
50 |
51 | /// @note the following is from the Eigen library
52 | /// here we say once and for all that traits == traits
53 | ///
54 | /// When constness must affect traits, it has to be constness on
55 | /// template parameters on which T itself depends.
56 | /// For example, traits