upgrade draco to 1.5.6
Signed-off-by: Jackie9527 <80555200+Jackie9527@users.noreply.github.com>pull/4978/head
parent
90333340d6
commit
39efe4c832
|
@ -1,102 +1,137 @@
|
||||||
# Generated with cmake-format 0.5.1
|
with section('parse'):
|
||||||
# How wide to allow formatted cmake files
|
# Specify structure for custom cmake functions
|
||||||
line_width = 80
|
additional_commands = {
|
||||||
|
'draco_add_emscripten_executable': {
|
||||||
# How many spaces to tab for indent
|
'kwargs': {
|
||||||
tab_size = 2
|
'NAME': '*',
|
||||||
|
'SOURCES': '*',
|
||||||
# If arglists are longer than this, break them always
|
'OUTPUT_NAME': '*',
|
||||||
max_subargs_per_line = 10
|
'DEFINES': '*',
|
||||||
|
'INCLUDES': '*',
|
||||||
# If true, separate flow control names from their parentheses with a space
|
'COMPILE_FLAGS': '*',
|
||||||
separate_ctrl_name_with_space = False
|
'LINK_FLAGS': '*',
|
||||||
|
'OBJLIB_DEPS': '*',
|
||||||
# If true, separate function names from parentheses with a space
|
'LIB_DEPS': '*',
|
||||||
separate_fn_name_with_space = False
|
'GLUE_PATH': '*',
|
||||||
|
'PRE_LINK_JS_SOURCES': '*',
|
||||||
# If a statement is wrapped to more than one line, than dangle the closing
|
'POST_LINK_JS_SOURCES': '*',
|
||||||
# parenthesis on its own line
|
'FEATURES': '*',
|
||||||
dangle_parens = False
|
},
|
||||||
|
'pargs': 0,
|
||||||
# What character to use for bulleted lists
|
},
|
||||||
bullet_char = '*'
|
'draco_add_executable': {
|
||||||
|
'kwargs': {
|
||||||
# What character to use as punctuation after numerals in an enumerated list
|
'NAME': '*',
|
||||||
enum_char = '.'
|
'SOURCES': '*',
|
||||||
|
'OUTPUT_NAME': '*',
|
||||||
# What style line endings to use in the output.
|
'TEST': 0,
|
||||||
line_ending = u'unix'
|
'DEFINES': '*',
|
||||||
|
'INCLUDES': '*',
|
||||||
# Format command names consistently as 'lower' or 'upper' case
|
'COMPILE_FLAGS': '*',
|
||||||
command_case = u'lower'
|
'LINK_FLAGS': '*',
|
||||||
|
'OBJLIB_DEPS': '*',
|
||||||
# Format keywords consistently as 'lower' or 'upper' case
|
'LIB_DEPS': '*',
|
||||||
keyword_case = u'unchanged'
|
},
|
||||||
|
'pargs': 0,
|
||||||
# Specify structure for custom cmake functions
|
},
|
||||||
additional_commands = {
|
'draco_add_library': {
|
||||||
"foo": {
|
'kwargs': {
|
||||||
"flags": [
|
'NAME': '*',
|
||||||
"BAR",
|
'TYPE': '*',
|
||||||
"BAZ"
|
'SOURCES': '*',
|
||||||
],
|
'TEST': 0,
|
||||||
"kwargs": {
|
'OUTPUT_NAME': '*',
|
||||||
"HEADERS": "*",
|
'DEFINES': '*',
|
||||||
"DEPENDS": "*",
|
'INCLUDES': '*',
|
||||||
"SOURCES": "*"
|
'COMPILE_FLAGS': '*',
|
||||||
}
|
'LINK_FLAGS': '*',
|
||||||
|
'OBJLIB_DEPS': '*',
|
||||||
|
'LIB_DEPS': '*',
|
||||||
|
'PUBLIC_INCLUDES': '*',
|
||||||
|
},
|
||||||
|
'pargs': 0,
|
||||||
|
},
|
||||||
|
'draco_generate_emscripten_glue': {
|
||||||
|
'kwargs': {
|
||||||
|
'INPUT_IDL': '*',
|
||||||
|
'OUTPUT_PATH': '*',
|
||||||
|
},
|
||||||
|
'pargs': 0,
|
||||||
|
},
|
||||||
|
'draco_get_required_emscripten_flags': {
|
||||||
|
'kwargs': {
|
||||||
|
'FLAG_LIST_VAR_COMPILER': '*',
|
||||||
|
'FLAG_LIST_VAR_LINKER': '*',
|
||||||
|
},
|
||||||
|
'pargs': 0,
|
||||||
|
},
|
||||||
|
'draco_option': {
|
||||||
|
'kwargs': {
|
||||||
|
'NAME': '*',
|
||||||
|
'HELPSTRING': '*',
|
||||||
|
'VALUE': '*',
|
||||||
|
},
|
||||||
|
'pargs': 0,
|
||||||
|
},
|
||||||
|
# Rules for built in CMake commands and those from dependencies.
|
||||||
|
'list': {
|
||||||
|
'kwargs': {
|
||||||
|
'APPEND': '*',
|
||||||
|
'FILTER': '*',
|
||||||
|
'FIND': '*',
|
||||||
|
'GET': '*',
|
||||||
|
'INSERT': '*',
|
||||||
|
'JOIN': '*',
|
||||||
|
'LENGTH': '*',
|
||||||
|
'POP_BACK': '*',
|
||||||
|
'POP_FRONT': '*',
|
||||||
|
'PREPEND': '*',
|
||||||
|
'REMOVE_DUPLICATES': '*',
|
||||||
|
'REMOVE_ITEM': '*',
|
||||||
|
'REVERSE': '*',
|
||||||
|
'SORT': '*',
|
||||||
|
'SUBLIST': '*',
|
||||||
|
'TRANSFORM': '*',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'protobuf_generate': {
|
||||||
|
'kwargs': {
|
||||||
|
'IMPORT_DIRS': '*',
|
||||||
|
'LANGUAGE': '*',
|
||||||
|
'OUT_VAR': '*',
|
||||||
|
'PROTOC_OUT_DIR': '*',
|
||||||
|
'PROTOS': '*',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
# A list of command names which should always be wrapped
|
with section('format'):
|
||||||
always_wrap = []
|
# Formatting options.
|
||||||
|
|
||||||
# Specify the order of wrapping algorithms during successive reflow attempts
|
# How wide to allow formatted cmake files
|
||||||
algorithm_order = [0, 1, 2, 3, 4]
|
line_width = 80
|
||||||
|
|
||||||
# If true, the argument lists which are known to be sortable will be sorted
|
# How many spaces to tab for indent
|
||||||
# lexicographicall
|
tab_size = 2
|
||||||
autosort = False
|
|
||||||
|
|
||||||
# enable comment markup parsing and reflow
|
# If true, separate flow control names from their parentheses with a space
|
||||||
enable_markup = True
|
separate_ctrl_name_with_space = False
|
||||||
|
|
||||||
# If comment markup is enabled, don't reflow the first comment block in
|
# If true, separate function names from parentheses with a space
|
||||||
# eachlistfile. Use this to preserve formatting of your
|
separate_fn_name_with_space = False
|
||||||
# copyright/licensestatements.
|
|
||||||
first_comment_is_literal = False
|
|
||||||
|
|
||||||
# If comment markup is enabled, don't reflow any comment block which matchesthis
|
# If a statement is wrapped to more than one line, than dangle the closing
|
||||||
# (regex) pattern. Default is `None` (disabled).
|
# parenthesis on its own line.
|
||||||
literal_comment_pattern = None
|
dangle_parens = False
|
||||||
|
|
||||||
# Regular expression to match preformat fences in comments
|
# Do not sort argument lists.
|
||||||
# default=r'^\s*([`~]{3}[`~]*)(.*)$'
|
enable_sort = False
|
||||||
fence_pattern = u'^\\s*([`~]{3}[`~]*)(.*)$'
|
|
||||||
|
|
||||||
# Regular expression to match rulers in comments
|
# What style line endings to use in the output.
|
||||||
# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
|
line_ending = 'unix'
|
||||||
ruler_pattern = u'^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
|
|
||||||
|
|
||||||
# If true, emit the unicode byte-order mark (BOM) at the start of the file
|
# Format command names consistently as 'lower' or 'upper' case
|
||||||
emit_byteorder_mark = False
|
command_case = 'canonical'
|
||||||
|
|
||||||
# If a comment line starts with at least this many consecutive hash characters,
|
# Format keywords consistently as 'lower' or 'upper' case
|
||||||
# then don't lstrip() them off. This allows for lazy hash rulers where the first
|
keyword_case = 'upper'
|
||||||
# hash char is not separated by space
|
|
||||||
hashruler_min_length = 10
|
|
||||||
|
|
||||||
# If true, then insert a space between the first hash char and remaining hash
|
|
||||||
# chars in a hash ruler, and normalize its length to fill the column
|
|
||||||
canonicalize_hashrulers = True
|
|
||||||
|
|
||||||
# Specify the encoding of the input file. Defaults to utf-8.
|
|
||||||
input_encoding = u'utf-8'
|
|
||||||
|
|
||||||
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
|
|
||||||
# only claims to support utf-8 so be careful when using anything else
|
|
||||||
output_encoding = u'utf-8'
|
|
||||||
|
|
||||||
# A dictionary containing any per-command configuration overrides. Currently
|
|
||||||
# only `command_case` is supported.
|
|
||||||
per_command = {}
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
*.obj eol=lf
|
|
@ -0,0 +1,12 @@
|
||||||
|
[submodule "third_party/googletest"]
|
||||||
|
path = third_party/googletest
|
||||||
|
url = https://github.com/google/googletest.git
|
||||||
|
[submodule "third_party/eigen"]
|
||||||
|
path = third_party/eigen
|
||||||
|
url = https://gitlab.com/libeigen/eigen.git
|
||||||
|
[submodule "third_party/tinygltf"]
|
||||||
|
path = third_party/tinygltf
|
||||||
|
url = https://github.com/syoyo/tinygltf.git
|
||||||
|
[submodule "third_party/filesystem"]
|
||||||
|
path = third_party/filesystem
|
||||||
|
url = https://github.com/gulrak/filesystem
|
|
@ -4,8 +4,10 @@ _**Contents**_
|
||||||
* [Mac OS X](#mac-os-x)
|
* [Mac OS X](#mac-os-x)
|
||||||
* [Windows](#windows)
|
* [Windows](#windows)
|
||||||
* [CMake Build Configuration](#cmake-build-configuration)
|
* [CMake Build Configuration](#cmake-build-configuration)
|
||||||
|
* [Transcoder](#transcoder)
|
||||||
* [Debugging and Optimization](#debugging-and-optimization)
|
* [Debugging and Optimization](#debugging-and-optimization)
|
||||||
* [Googletest Integration](#googletest-integration)
|
* [Googletest Integration](#googletest-integration)
|
||||||
|
* [Third Party Libraries](#third-party-libraries)
|
||||||
* [Javascript Encoder/Decoder](#javascript-encoderdecoder)
|
* [Javascript Encoder/Decoder](#javascript-encoderdecoder)
|
||||||
* [WebAssembly Decoder](#webassembly-decoder)
|
* [WebAssembly Decoder](#webassembly-decoder)
|
||||||
* [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
|
* [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
|
||||||
|
@ -72,6 +74,43 @@ C:\Users\nobody> cmake ../ -G "Visual Studio 16 2019" -A x64
|
||||||
CMake Build Configuration
|
CMake Build Configuration
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
Transcoder
|
||||||
|
----------
|
||||||
|
|
||||||
|
Before attempting to build Draco with transcoding support you must run an
|
||||||
|
additional Git command to obtain the submodules:
|
||||||
|
|
||||||
|
~~~~~ bash
|
||||||
|
# Run this command from within your Draco clone.
|
||||||
|
$ git submodule update --init
|
||||||
|
# See below if you prefer to use existing versions of Draco dependencies.
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
In order to build the `draco_transcoder` target, the transcoding support needs
|
||||||
|
to be explicitly enabled when you run `cmake`, for example:
|
||||||
|
|
||||||
|
~~~~~ bash
|
||||||
|
$ cmake ../ -DDRACO_TRANSCODER_SUPPORTED=ON
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
The above option is currently not compatible with our Javascript or WebAssembly
|
||||||
|
builds but all other use cases are supported. Note that binaries and libraries
|
||||||
|
built with the transcoder support may result in increased binary sizes of the
|
||||||
|
produced libraries and executables compared to the default CMake settings.
|
||||||
|
|
||||||
|
The following CMake variables can be used to configure Draco to use local
|
||||||
|
copies of third party dependencies instead of git submodules.
|
||||||
|
|
||||||
|
- `DRACO_EIGEN_PATH`: this path must contain an Eigen directory that includes
|
||||||
|
the Eigen sources.
|
||||||
|
- `DRACO_FILESYSTEM_PATH`: this path must contain the ghc directory where the
|
||||||
|
filesystem includes are located.
|
||||||
|
- `DRACO_TINYGLTF_PATH`: this path must contain tiny_gltf.h and its
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
When not specified the Draco build requires the presence of the submodules that
|
||||||
|
are stored within `draco/third_party`.
|
||||||
|
|
||||||
Debugging and Optimization
|
Debugging and Optimization
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
@ -114,17 +153,52 @@ $ cmake ../ -DDRACO_SANITIZE=address
|
||||||
Googletest Integration
|
Googletest Integration
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Draco includes testing support built using Googletest. To enable Googletest unit
|
Draco includes testing support built using Googletest. The Googletest repository
|
||||||
test support the DRACO_TESTS cmake variable must be turned on at cmake
|
is included as a submodule of the Draco git repository. Run the following
|
||||||
generation time:
|
command to clone the Googletest repository:
|
||||||
|
|
||||||
|
~~~~~ bash
|
||||||
|
$ git submodule update --init
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
To enable Googletest unit test support the DRACO_TESTS cmake variable must be
|
||||||
|
turned on at cmake generation time:
|
||||||
|
|
||||||
~~~~~ bash
|
~~~~~ bash
|
||||||
$ cmake ../ -DDRACO_TESTS=ON
|
$ cmake ../ -DDRACO_TESTS=ON
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
When cmake is used as shown in the above example the googletest directory must
|
To run the tests execute `draco_tests` from your build output directory:
|
||||||
be a sibling of the Draco repository root directory. To run the tests execute
|
|
||||||
`draco_tests` from your build output directory.
|
~~~~~ bash
|
||||||
|
$ ./draco_tests
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Draco can be configured to use a local Googletest installation. The
|
||||||
|
`DRACO_GOOGLETEST_PATH` variable overrides the behavior described above and
|
||||||
|
configures Draco to use the Googletest at the specified path.
|
||||||
|
|
||||||
|
Third Party Libraries
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
When Draco is built with transcoding and/or testing support enabled the project
|
||||||
|
has dependencies on third party libraries:
|
||||||
|
|
||||||
|
- [Eigen](https://eigen.tuxfamily.org/)
|
||||||
|
- Provides various math utilites.
|
||||||
|
- [Googletest](https://github.com/google/googletest)
|
||||||
|
- Provides testing support.
|
||||||
|
- [Gulrak/filesystem](https://github.com/gulrak/filesystem)
|
||||||
|
- Provides C++17 std::filesystem emulation for pre-C++17 environments.
|
||||||
|
- [TinyGLTF](https://github.com/syoyo/tinygltf)
|
||||||
|
- Provides GLTF I/O support.
|
||||||
|
|
||||||
|
These dependencies are managed as Git submodules. To obtain the dependencies
|
||||||
|
run the following command in your Draco repository:
|
||||||
|
|
||||||
|
~~~~~ bash
|
||||||
|
$ git submodule update --init
|
||||||
|
~~~~~
|
||||||
|
|
||||||
WebAssembly Decoder
|
WebAssembly Decoder
|
||||||
-------------------
|
-------------------
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,10 +2,93 @@
|
||||||
<img width="350px" src="docs/artwork/draco3d-vert.svg" />
|
<img width="350px" src="docs/artwork/draco3d-vert.svg" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[![Build Status](https://github.com/google/draco/workflows/Build/badge.svg)](https://github.com/google/draco/actions?query=workflow%3ABuild)
|
[![draco-ci](https://github.com/google/draco/workflows/draco-ci/badge.svg?branch=master)](https://github.com/google/draco/actions/workflows/ci.yml)
|
||||||
|
|
||||||
News
|
News
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
Attention GStatic users: the Draco team strongly recommends using the versioned
|
||||||
|
URLs for accessing Draco GStatic content. If you are using the URLs that include
|
||||||
|
the `v1/decoders` substring within the URL, edge caching and GStatic propagation
|
||||||
|
delays can result in transient errors that can be difficult to diagnose when
|
||||||
|
new Draco releases are launched. To avoid the issue pin your sites to a
|
||||||
|
versioned release.
|
||||||
|
|
||||||
|
### Version 1.5.6 release:
|
||||||
|
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
|
||||||
|
to be recommended. To use v1.5.6, use this URL:
|
||||||
|
* https://www.gstatic.com/draco/versioned/decoders/1.5.6/*
|
||||||
|
* The CMake flag DRACO_DEBUG_MSVC_WARNINGS has been replaced with
|
||||||
|
DRACO_DEBUG_COMPILER_WARNINGS, and the behavior has changed. It is now a
|
||||||
|
boolean flag defined in draco_options.cmake.
|
||||||
|
* Bug fixes.
|
||||||
|
* Security fixes.
|
||||||
|
|
||||||
|
### Version 1.5.5 release:
|
||||||
|
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
|
||||||
|
to be recommended. To use v1.5.5, use this URL:
|
||||||
|
* https://www.gstatic.com/draco/versioned/decoders/1.5.5/*
|
||||||
|
* Bug fix: https://github.com/google/draco/issues/935
|
||||||
|
|
||||||
|
### Version 1.5.4 release:
|
||||||
|
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
|
||||||
|
to be recommended. To use v1.5.4, use this URL:
|
||||||
|
* https://www.gstatic.com/draco/versioned/decoders/1.5.4/*
|
||||||
|
* Added partial support for glTF extensions EXT_mesh_features and
|
||||||
|
EXT_structural_metadata.
|
||||||
|
* Bug fixes.
|
||||||
|
* Security fixes.
|
||||||
|
|
||||||
|
### Version 1.5.3 release:
|
||||||
|
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
|
||||||
|
to be recommended. To use v1.5.3, use this URL:
|
||||||
|
* https://www.gstatic.com/draco/versioned/decoders/1.5.3/*
|
||||||
|
* Bug fixes.
|
||||||
|
|
||||||
|
### Version 1.5.2 release
|
||||||
|
* This is the same as v1.5.1 with the following two bug fixes:
|
||||||
|
* Fixes DRACO_TRANSCODER_SUPPORTED enabled builds.
|
||||||
|
* ABI version updated.
|
||||||
|
|
||||||
|
### Version 1.5.1 release
|
||||||
|
* Adds assertion enabled Emscripten builds to the release, and a subset of the
|
||||||
|
assertion enabled builds to GStatic. See the file listing below.
|
||||||
|
* Custom paths to third party dependencies are now supported. See BUILDING.md
|
||||||
|
for more information.
|
||||||
|
* The CMake configuration file draco-config.cmake is now tested and known to
|
||||||
|
work for using Draco in Linux, MacOS, and Windows CMake projects. See the
|
||||||
|
`install_test` subdirectory of `src/draco/tools` for more information.
|
||||||
|
* Bug fixes.
|
||||||
|
|
||||||
|
### Version 1.5.0 release
|
||||||
|
* Adds the draco_transcoder tool. See the section below on the glTF transcoding
|
||||||
|
tool, and BUILDING.md for build and dependency information.
|
||||||
|
* Some changes to configuration variables have been made for this release:
|
||||||
|
- The DRACO_GLTF flag has been renamed to DRACO_GLTF_BITSTREAM to help
|
||||||
|
increase understanding of its purpose, which is to limit Draco features to
|
||||||
|
those included in the Draco glTF specification.
|
||||||
|
- Variables exported in CMake via draco-config.cmake and find-draco.cmake
|
||||||
|
(formerly FindDraco.cmake) have been renamed. It's unlikely that this
|
||||||
|
impacts any existing projects as the aforementioned files were not formed
|
||||||
|
correctly. See [PR775](https://github.com/google/draco/pull/775) for full
|
||||||
|
details of the changes.
|
||||||
|
* A CMake version file has been added.
|
||||||
|
* The CMake install target now uses absolute paths direct from CMake instead
|
||||||
|
of building them using CMAKE_INSTALL_PREFIX. This was done to make Draco
|
||||||
|
easier to use for downstream packagers and should have little to no impact on
|
||||||
|
users picking up Draco from source.
|
||||||
|
* Certain MSVC warnings have had their levels changed via compiler flag to
|
||||||
|
reduce the amount of noise output by the MSVC compilers. Set MSVC warning
|
||||||
|
level to 4, or define DRACO_DEBUG_MSVC_WARNINGS at CMake configuration time
|
||||||
|
to restore previous behavior.
|
||||||
|
* Bug fixes.
|
||||||
|
|
||||||
|
### Version 1.4.3 release
|
||||||
|
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
|
||||||
|
to be recommended. To use v1.4.3, use this URL:
|
||||||
|
* https://www.gstatic.com/draco/versioned/decoders/1.4.3/*
|
||||||
|
* Bug fixes
|
||||||
|
|
||||||
### Version 1.4.1 release
|
### Version 1.4.1 release
|
||||||
* Using the versioned www.gstatic.com WASM and Javascript decoders is now
|
* Using the versioned www.gstatic.com WASM and Javascript decoders is now
|
||||||
recommended. To use v1.4.1, use this URL:
|
recommended. To use v1.4.1, use this URL:
|
||||||
|
@ -129,6 +212,7 @@ _**Contents**_
|
||||||
* [Encoding Tool](#encoding-tool)
|
* [Encoding Tool](#encoding-tool)
|
||||||
* [Encoding Point Clouds](#encoding-point-clouds)
|
* [Encoding Point Clouds](#encoding-point-clouds)
|
||||||
* [Decoding Tool](#decoding-tool)
|
* [Decoding Tool](#decoding-tool)
|
||||||
|
* [glTF Transcoding Tool](#gltf-transcoding-tool)
|
||||||
* [C++ Decoder API](#c-decoder-api)
|
* [C++ Decoder API](#c-decoder-api)
|
||||||
* [Javascript Encoder API](#javascript-encoder-api)
|
* [Javascript Encoder API](#javascript-encoder-api)
|
||||||
* [Javascript Decoder API](#javascript-decoder-api)
|
* [Javascript Decoder API](#javascript-decoder-api)
|
||||||
|
@ -136,6 +220,7 @@ _**Contents**_
|
||||||
* [Metadata API](#metadata-api)
|
* [Metadata API](#metadata-api)
|
||||||
* [NPM Package](#npm-package)
|
* [NPM Package](#npm-package)
|
||||||
* [three.js Renderer Example](#threejs-renderer-example)
|
* [three.js Renderer Example](#threejs-renderer-example)
|
||||||
|
* [GStatic Javascript Builds](#gstatic-javascript-builds)
|
||||||
* [Support](#support)
|
* [Support](#support)
|
||||||
* [License](#license)
|
* [License](#license)
|
||||||
* [References](#references)
|
* [References](#references)
|
||||||
|
@ -170,16 +255,18 @@ Command Line Applications
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
The default target created from the build files will be the `draco_encoder`
|
The default target created from the build files will be the `draco_encoder`
|
||||||
and `draco_decoder` command line applications. For both applications, if you
|
and `draco_decoder` command line applications. Additionally, `draco_transcoder`
|
||||||
run them without any arguments or `-h`, the applications will output usage and
|
is generated when CMake is run with the DRACO_TRANSCODER_SUPPORTED variable set
|
||||||
options.
|
to ON (see [BUILDING](BUILDING.md#transcoder) for more details). For all
|
||||||
|
applications, if you run them without any arguments or `-h`, the applications
|
||||||
|
will output usage and options.
|
||||||
|
|
||||||
Encoding Tool
|
Encoding Tool
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
`draco_encoder` will read OBJ or PLY files as input, and output Draco-encoded
|
`draco_encoder` will read OBJ, STL or PLY files as input, and output
|
||||||
files. We have included Stanford's [Bunny] mesh for testing. The basic command
|
Draco-encoded files. We have included Stanford's [Bunny] mesh for testing. The
|
||||||
line looks like this:
|
basic command line looks like this:
|
||||||
|
|
||||||
~~~~~ bash
|
~~~~~ bash
|
||||||
./draco_encoder -i testdata/bun_zipper.ply -o out.drc
|
./draco_encoder -i testdata/bun_zipper.ply -o out.drc
|
||||||
|
@ -232,15 +319,34 @@ and denser point clouds.
|
||||||
Decoding Tool
|
Decoding Tool
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
`draco_decoder` will read Draco files as input, and output OBJ or PLY files.
|
`draco_decoder` will read Draco files as input, and output OBJ, STL or PLY
|
||||||
The basic command line looks like this:
|
files. The basic command line looks like this:
|
||||||
|
|
||||||
~~~~~ bash
|
~~~~~ bash
|
||||||
./draco_decoder -i in.drc -o out.obj
|
./draco_decoder -i in.drc -o out.obj
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
glTF Transcoding Tool
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
`draco_transcoder` can be used to add Draco compression to glTF assets. The
|
||||||
|
basic command line looks like this:
|
||||||
|
|
||||||
|
~~~~~ bash
|
||||||
|
./draco_transcoder -i in.glb -o out.glb
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
This command line will add geometry compression to all meshes in the `in.glb`
|
||||||
|
file. Quantization values for different glTF attributes can be specified
|
||||||
|
similarly to the `draco_encoder` tool. For example `-qp` can be used to define
|
||||||
|
quantization of the position attribute:
|
||||||
|
|
||||||
|
~~~~~ bash
|
||||||
|
./draco_transcoder -i in.glb -o out.glb -qp 12
|
||||||
|
~~~~~
|
||||||
|
|
||||||
C++ Decoder API
|
C++ Decoder API
|
||||||
-------------
|
---------------
|
||||||
|
|
||||||
If you'd like to add decoding to your applications you will need to include
|
If you'd like to add decoding to your applications you will need to include
|
||||||
the `draco_dec` library. In order to use the Draco decoder you need to
|
the `draco_dec` library. In order to use the Draco decoder you need to
|
||||||
|
@ -442,6 +548,30 @@ Javascript decoder using the `three.js` renderer.
|
||||||
|
|
||||||
Please see the [javascript/example/README.md](javascript/example/README.md) file for more information.
|
Please see the [javascript/example/README.md](javascript/example/README.md) file for more information.
|
||||||
|
|
||||||
|
GStatic Javascript Builds
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Prebuilt versions of the Emscripten-built Draco javascript decoders are hosted
|
||||||
|
on www.gstatic.com in version labeled directories:
|
||||||
|
|
||||||
|
https://www.gstatic.com/draco/versioned/decoders/VERSION/*
|
||||||
|
|
||||||
|
As of the v1.4.3 release the files available are:
|
||||||
|
|
||||||
|
- [draco_decoder.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder.js)
|
||||||
|
- [draco_decoder.wasm](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder.wasm)
|
||||||
|
- [draco_decoder_gltf.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder_gltf.js)
|
||||||
|
- [draco_decoder_gltf.wasm](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder_gltf.wasm)
|
||||||
|
- [draco_wasm_wrapper.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_wasm_wrapper.js)
|
||||||
|
- [draco_wasm_wrapper_gltf.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_wasm_wrapper_gltf.js)
|
||||||
|
|
||||||
|
Beginning with the v1.5.1 release assertion enabled builds of the following
|
||||||
|
files are available:
|
||||||
|
|
||||||
|
- [draco_decoder.js](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_decoder.js)
|
||||||
|
- [draco_decoder.wasm](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_decoder.wasm)
|
||||||
|
- [draco_wasm_wrapper.js](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_wasm_wrapper.js)
|
||||||
|
|
||||||
Support
|
Support
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
@PACKAGE_INIT@
|
|
||||||
set_and_check(draco_INCLUDE_DIR "@PACKAGE_draco_include_install_dir@")
|
|
||||||
set_and_check(draco_LIBRARY_DIR "@PACKAGE_draco_lib_install_dir@")
|
|
|
@ -1,56 +0,0 @@
|
||||||
# Finddraco
|
|
||||||
#
|
|
||||||
# Locates draco and sets the following variables:
|
|
||||||
#
|
|
||||||
# draco_FOUND draco_INCLUDE_DIRS draco_LIBARY_DIRS draco_LIBRARIES
|
|
||||||
# draco_VERSION_STRING
|
|
||||||
#
|
|
||||||
# draco_FOUND is set to YES only when all other variables are successfully
|
|
||||||
# configured.
|
|
||||||
|
|
||||||
unset(draco_FOUND)
|
|
||||||
unset(draco_INCLUDE_DIRS)
|
|
||||||
unset(draco_LIBRARY_DIRS)
|
|
||||||
unset(draco_LIBRARIES)
|
|
||||||
unset(draco_VERSION_STRING)
|
|
||||||
|
|
||||||
mark_as_advanced(draco_FOUND)
|
|
||||||
mark_as_advanced(draco_INCLUDE_DIRS)
|
|
||||||
mark_as_advanced(draco_LIBRARY_DIRS)
|
|
||||||
mark_as_advanced(draco_LIBRARIES)
|
|
||||||
mark_as_advanced(draco_VERSION_STRING)
|
|
||||||
|
|
||||||
set(draco_version_file_no_prefix "draco/src/draco/core/draco_version.h")
|
|
||||||
|
|
||||||
# Set draco_INCLUDE_DIRS
|
|
||||||
find_path(draco_INCLUDE_DIRS NAMES "${draco_version_file_no_prefix}")
|
|
||||||
|
|
||||||
# Extract the version string from draco_version.h.
|
|
||||||
if(draco_INCLUDE_DIRS)
|
|
||||||
set(draco_version_file
|
|
||||||
"${draco_INCLUDE_DIRS}/draco/src/draco/core/draco_version.h")
|
|
||||||
file(STRINGS "${draco_version_file}" draco_version REGEX "kdracoVersion")
|
|
||||||
list(GET draco_version 0 draco_version)
|
|
||||||
string(REPLACE "static const char kdracoVersion[] = " "" draco_version
|
|
||||||
"${draco_version}")
|
|
||||||
string(REPLACE ";" "" draco_version "${draco_version}")
|
|
||||||
string(REPLACE "\"" "" draco_version "${draco_version}")
|
|
||||||
set(draco_VERSION_STRING ${draco_version})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Find the library.
|
|
||||||
if(BUILD_SHARED_LIBS)
|
|
||||||
find_library(draco_LIBRARIES NAMES draco.dll libdraco.dylib libdraco.so)
|
|
||||||
else()
|
|
||||||
find_library(draco_LIBRARIES NAMES draco.lib libdraco.a)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Store path to library.
|
|
||||||
get_filename_component(draco_LIBRARY_DIRS ${draco_LIBRARIES} DIRECTORY)
|
|
||||||
|
|
||||||
if(draco_INCLUDE_DIRS
|
|
||||||
AND draco_LIBRARY_DIRS
|
|
||||||
AND draco_LIBRARIES
|
|
||||||
AND draco_VERSION_STRING)
|
|
||||||
set(draco_FOUND YES)
|
|
||||||
endif()
|
|
|
@ -1,220 +0,0 @@
|
||||||
if(DRACO_CMAKE_COMPILER_FLAGS_CMAKE_)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(DRACO_CMAKE_COMPILER_FLAGS_CMAKE_ 1)
|
|
||||||
|
|
||||||
include(CheckCCompilerFlag)
|
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
include("${draco_root}/cmake/compiler_tests.cmake")
|
|
||||||
|
|
||||||
# Strings used to cache failed C/CXX flags.
|
|
||||||
set(DRACO_FAILED_C_FLAGS)
|
|
||||||
set(DRACO_FAILED_CXX_FLAGS)
|
|
||||||
|
|
||||||
# Checks C compiler for support of $c_flag. Adds $c_flag to $CMAKE_C_FLAGS when
|
|
||||||
# the compile test passes. Caches $c_flag in $DRACO_FAILED_C_FLAGS when the test
|
|
||||||
# fails.
|
|
||||||
macro(add_c_flag_if_supported c_flag)
|
|
||||||
unset(C_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_C_FLAGS}" "${c_flag}" C_FLAG_FOUND)
|
|
||||||
unset(C_FLAG_FAILED CACHE)
|
|
||||||
string(FIND "${DRACO_FAILED_C_FLAGS}" "${c_flag}" C_FLAG_FAILED)
|
|
||||||
|
|
||||||
if(${C_FLAG_FOUND} EQUAL -1 AND ${C_FLAG_FAILED} EQUAL -1)
|
|
||||||
unset(C_FLAG_SUPPORTED CACHE)
|
|
||||||
message("Checking C compiler flag support for: " ${c_flag})
|
|
||||||
check_c_compiler_flag("${c_flag}" C_FLAG_SUPPORTED)
|
|
||||||
if(${C_FLAG_SUPPORTED})
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${c_flag}" CACHE STRING "")
|
|
||||||
else()
|
|
||||||
set(DRACO_FAILED_C_FLAGS
|
|
||||||
"${DRACO_FAILED_C_FLAGS} ${c_flag}"
|
|
||||||
CACHE STRING "" FORCE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks C++ compiler for support of $cxx_flag. Adds $cxx_flag to
|
|
||||||
# $CMAKE_CXX_FLAGS when the compile test passes. Caches $c_flag in
|
|
||||||
# $DRACO_FAILED_CXX_FLAGS when the test fails.
|
|
||||||
macro(add_cxx_flag_if_supported cxx_flag)
|
|
||||||
unset(CXX_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FOUND)
|
|
||||||
unset(CXX_FLAG_FAILED CACHE)
|
|
||||||
string(FIND "${DRACO_FAILED_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FAILED)
|
|
||||||
|
|
||||||
if(${CXX_FLAG_FOUND} EQUAL -1 AND ${CXX_FLAG_FAILED} EQUAL -1)
|
|
||||||
unset(CXX_FLAG_SUPPORTED CACHE)
|
|
||||||
message("Checking CXX compiler flag support for: " ${cxx_flag})
|
|
||||||
check_cxx_compiler_flag("${cxx_flag}" CXX_FLAG_SUPPORTED)
|
|
||||||
if(${CXX_FLAG_SUPPORTED})
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_flag}" CACHE STRING "")
|
|
||||||
else()
|
|
||||||
set(DRACO_FAILED_CXX_FLAGS
|
|
||||||
"${DRACO_FAILED_CXX_FLAGS} ${cxx_flag}"
|
|
||||||
CACHE STRING "" FORCE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Convenience method for adding a flag to both the C and C++ compiler command
|
|
||||||
# lines.
|
|
||||||
macro(add_compiler_flag_if_supported flag)
|
|
||||||
add_c_flag_if_supported(${flag})
|
|
||||||
add_cxx_flag_if_supported(${flag})
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks C compiler for support of $c_flag and terminates generation when
|
|
||||||
# support is not present.
|
|
||||||
macro(require_c_flag c_flag update_c_flags)
|
|
||||||
unset(C_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_C_FLAGS}" "${c_flag}" C_FLAG_FOUND)
|
|
||||||
|
|
||||||
if(${C_FLAG_FOUND} EQUAL -1)
|
|
||||||
unset(HAVE_C_FLAG CACHE)
|
|
||||||
message("Checking C compiler flag support for: " ${c_flag})
|
|
||||||
check_c_compiler_flag("${c_flag}" HAVE_C_FLAG)
|
|
||||||
if(NOT ${HAVE_C_FLAG})
|
|
||||||
message(
|
|
||||||
FATAL_ERROR "${PROJECT_NAME} requires support for C flag: ${c_flag}.")
|
|
||||||
endif()
|
|
||||||
if(${update_c_flags})
|
|
||||||
set(CMAKE_C_FLAGS "${c_flag} ${CMAKE_C_FLAGS}" CACHE STRING "" FORCE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks CXX compiler for support of $cxx_flag and terminates generation when
|
|
||||||
# support is not present.
|
|
||||||
macro(require_cxx_flag cxx_flag update_cxx_flags)
|
|
||||||
unset(CXX_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FOUND)
|
|
||||||
|
|
||||||
if(${CXX_FLAG_FOUND} EQUAL -1)
|
|
||||||
unset(HAVE_CXX_FLAG CACHE)
|
|
||||||
message("Checking CXX compiler flag support for: " ${cxx_flag})
|
|
||||||
check_cxx_compiler_flag("${cxx_flag}" HAVE_CXX_FLAG)
|
|
||||||
if(NOT ${HAVE_CXX_FLAG})
|
|
||||||
message(
|
|
||||||
FATAL_ERROR
|
|
||||||
"${PROJECT_NAME} requires support for CXX flag: ${cxx_flag}.")
|
|
||||||
endif()
|
|
||||||
if(${update_cxx_flags})
|
|
||||||
set(CMAKE_CXX_FLAGS
|
|
||||||
"${cxx_flag} ${CMAKE_CXX_FLAGS}"
|
|
||||||
CACHE STRING "" FORCE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks for support of $flag by both the C and CXX compilers. Terminates
|
|
||||||
# generation when support is not present in both compilers.
|
|
||||||
macro(require_compiler_flag flag update_cmake_flags)
|
|
||||||
require_c_flag(${flag} ${update_cmake_flags})
|
|
||||||
require_cxx_flag(${flag} ${update_cmake_flags})
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks only non-MSVC targets for support of $c_flag and terminates generation
|
|
||||||
# when support is not present.
|
|
||||||
macro(require_c_flag_nomsvc c_flag update_c_flags)
|
|
||||||
if(NOT MSVC)
|
|
||||||
require_c_flag(${c_flag} ${update_c_flags})
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks only non-MSVC targets for support of $cxx_flag and terminates
|
|
||||||
# generation when support is not present.
|
|
||||||
macro(require_cxx_flag_nomsvc cxx_flag update_cxx_flags)
|
|
||||||
if(NOT MSVC)
|
|
||||||
require_cxx_flag(${cxx_flag} ${update_cxx_flags})
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Checks only non-MSVC targets for support of $flag by both the C and CXX
|
|
||||||
# compilers. Terminates generation when support is not present in both
|
|
||||||
# compilers.
|
|
||||||
macro(require_compiler_flag_nomsvc flag update_cmake_flags)
|
|
||||||
require_c_flag_nomsvc(${flag} ${update_cmake_flags})
|
|
||||||
require_cxx_flag_nomsvc(${flag} ${update_cmake_flags})
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Adds $flag to assembler command line.
|
|
||||||
macro(append_as_flag flag)
|
|
||||||
unset(AS_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${DRACO_AS_FLAGS}" "${flag}" AS_FLAG_FOUND)
|
|
||||||
|
|
||||||
if(${AS_FLAG_FOUND} EQUAL -1)
|
|
||||||
set(DRACO_AS_FLAGS "${DRACO_AS_FLAGS} ${flag}")
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Adds $flag to the C compiler command line.
|
|
||||||
macro(append_c_flag flag)
|
|
||||||
unset(C_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_C_FLAGS}" "${flag}" C_FLAG_FOUND)
|
|
||||||
|
|
||||||
if(${C_FLAG_FOUND} EQUAL -1)
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Adds $flag to the CXX compiler command line.
|
|
||||||
macro(append_cxx_flag flag)
|
|
||||||
unset(CXX_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" CXX_FLAG_FOUND)
|
|
||||||
|
|
||||||
if(${CXX_FLAG_FOUND} EQUAL -1)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Adds $flag to the C and CXX compiler command lines.
|
|
||||||
macro(append_compiler_flag flag)
|
|
||||||
append_c_flag(${flag})
|
|
||||||
append_cxx_flag(${flag})
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Adds $flag to the executable linker command line.
|
|
||||||
macro(append_exe_linker_flag flag)
|
|
||||||
unset(LINKER_FLAG_FOUND CACHE)
|
|
||||||
string(FIND "${CMAKE_EXE_LINKER_FLAGS}" "${flag}" LINKER_FLAG_FOUND)
|
|
||||||
|
|
||||||
if(${LINKER_FLAG_FOUND} EQUAL -1)
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}")
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Adds $flag to the link flags for $target.
|
|
||||||
function(append_link_flag_to_target target flags)
|
|
||||||
unset(target_link_flags)
|
|
||||||
get_target_property(target_link_flags ${target} LINK_FLAGS)
|
|
||||||
|
|
||||||
if(target_link_flags)
|
|
||||||
unset(link_flag_found)
|
|
||||||
string(FIND "${target_link_flags}" "${flags}" link_flag_found)
|
|
||||||
|
|
||||||
if(NOT ${link_flag_found} EQUAL -1)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(target_link_flags "${target_link_flags} ${flags}")
|
|
||||||
else()
|
|
||||||
set(target_link_flags "${flags}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(${target} PROPERTIES LINK_FLAGS ${target_link_flags})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Adds $flag to executable linker flags, and makes sure C/CXX builds still work.
|
|
||||||
macro(require_linker_flag flag)
|
|
||||||
append_exe_linker_flag(${flag})
|
|
||||||
|
|
||||||
unset(c_passed)
|
|
||||||
draco_check_c_compiles("LINKER_FLAG_C_TEST(${flag})" "" c_passed)
|
|
||||||
unset(cxx_passed)
|
|
||||||
draco_check_cxx_compiles("LINKER_FLAG_CXX_TEST(${flag})" "" cxx_passed)
|
|
||||||
|
|
||||||
if(NOT c_passed OR NOT cxx_passed)
|
|
||||||
message(FATAL_ERROR "Linker flag test for ${flag} failed.")
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
|
@ -1,103 +0,0 @@
|
||||||
if(DRACO_CMAKE_COMPILER_TESTS_CMAKE_)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(DRACO_CMAKE_COMPILER_TESTS_CMAKE_ 1)
|
|
||||||
|
|
||||||
include(CheckCSourceCompiles)
|
|
||||||
include(CheckCXXSourceCompiles)
|
|
||||||
|
|
||||||
# The basic main() macro used in all compile tests.
|
|
||||||
set(DRACO_C_MAIN "\nint main(void) { return 0; }")
|
|
||||||
set(DRACO_CXX_MAIN "\nint main() { return 0; }")
|
|
||||||
|
|
||||||
# Strings containing the names of passed and failed tests.
|
|
||||||
set(DRACO_C_PASSED_TESTS)
|
|
||||||
set(DRACO_C_FAILED_TESTS)
|
|
||||||
set(DRACO_CXX_PASSED_TESTS)
|
|
||||||
set(DRACO_CXX_FAILED_TESTS)
|
|
||||||
|
|
||||||
macro(draco_push_var var new_value)
|
|
||||||
set(SAVED_${var} ${var})
|
|
||||||
set(${var} ${new_value})
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
macro(draco_pop_var var)
|
|
||||||
set(var ${SAVED_${var}})
|
|
||||||
unset(SAVED_${var})
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Confirms $test_source compiles and stores $test_name in one of
|
|
||||||
# $DRACO_C_PASSED_TESTS or $DRACO_C_FAILED_TESTS depending on out come. When the
|
|
||||||
# test passes $result_var is set to 1. When it fails $result_var is unset. The
|
|
||||||
# test is not run if the test name is found in either of the passed or failed
|
|
||||||
# test variables.
|
|
||||||
macro(draco_check_c_compiles test_name test_source result_var)
|
|
||||||
unset(C_TEST_PASSED CACHE)
|
|
||||||
unset(C_TEST_FAILED CACHE)
|
|
||||||
string(FIND "${DRACO_C_PASSED_TESTS}" "${test_name}" C_TEST_PASSED)
|
|
||||||
string(FIND "${DRACO_C_FAILED_TESTS}" "${test_name}" C_TEST_FAILED)
|
|
||||||
if(${C_TEST_PASSED} EQUAL -1 AND ${C_TEST_FAILED} EQUAL -1)
|
|
||||||
unset(C_TEST_COMPILED CACHE)
|
|
||||||
message("Running C compiler test: ${test_name}")
|
|
||||||
check_c_source_compiles("${test_source} ${DRACO_C_MAIN}" C_TEST_COMPILED)
|
|
||||||
set(${result_var} ${C_TEST_COMPILED})
|
|
||||||
|
|
||||||
if(${C_TEST_COMPILED})
|
|
||||||
set(DRACO_C_PASSED_TESTS "${DRACO_C_PASSED_TESTS} ${test_name}")
|
|
||||||
else()
|
|
||||||
set(DRACO_C_FAILED_TESTS "${DRACO_C_FAILED_TESTS} ${test_name}")
|
|
||||||
message("C Compiler test ${test_name} failed.")
|
|
||||||
endif()
|
|
||||||
elseif(NOT ${C_TEST_PASSED} EQUAL -1)
|
|
||||||
set(${result_var} 1)
|
|
||||||
else() # ${C_TEST_FAILED} NOT EQUAL -1
|
|
||||||
unset(${result_var})
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Confirms $test_source compiles and stores $test_name in one of
|
|
||||||
# $DRACO_CXX_PASSED_TESTS or $DRACO_CXX_FAILED_TESTS depending on out come. When
|
|
||||||
# the test passes $result_var is set to 1. When it fails $result_var is unset.
|
|
||||||
# The test is not run if the test name is found in either of the passed or
|
|
||||||
# failed test variables.
|
|
||||||
macro(draco_check_cxx_compiles test_name test_source result_var)
|
|
||||||
unset(CXX_TEST_PASSED CACHE)
|
|
||||||
unset(CXX_TEST_FAILED CACHE)
|
|
||||||
string(FIND "${DRACO_CXX_PASSED_TESTS}" "${test_name}" CXX_TEST_PASSED)
|
|
||||||
string(FIND "${DRACO_CXX_FAILED_TESTS}" "${test_name}" CXX_TEST_FAILED)
|
|
||||||
if(${CXX_TEST_PASSED} EQUAL -1 AND ${CXX_TEST_FAILED} EQUAL -1)
|
|
||||||
unset(CXX_TEST_COMPILED CACHE)
|
|
||||||
message("Running CXX compiler test: ${test_name}")
|
|
||||||
check_cxx_source_compiles("${test_source} ${DRACO_CXX_MAIN}"
|
|
||||||
CXX_TEST_COMPILED)
|
|
||||||
set(${result_var} ${CXX_TEST_COMPILED})
|
|
||||||
|
|
||||||
if(${CXX_TEST_COMPILED})
|
|
||||||
set(DRACO_CXX_PASSED_TESTS "${DRACO_CXX_PASSED_TESTS} ${test_name}")
|
|
||||||
else()
|
|
||||||
set(DRACO_CXX_FAILED_TESTS "${DRACO_CXX_FAILED_TESTS} ${test_name}")
|
|
||||||
message("CXX Compiler test ${test_name} failed.")
|
|
||||||
endif()
|
|
||||||
elseif(NOT ${CXX_TEST_PASSED} EQUAL -1)
|
|
||||||
set(${result_var} 1)
|
|
||||||
else() # ${CXX_TEST_FAILED} NOT EQUAL -1
|
|
||||||
unset(${result_var})
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Convenience macro that confirms $test_source compiles as C and C++.
|
|
||||||
# $result_var is set to 1 when both tests are successful, and 0 when one or both
|
|
||||||
# tests fail. Note: This macro is intended to be used to write to result
|
|
||||||
# variables that are expanded via configure_file(). $result_var is set to 1 or 0
|
|
||||||
# to allow direct usage of the value in generated source files.
|
|
||||||
macro(draco_check_source_compiles test_name test_source result_var)
|
|
||||||
unset(C_PASSED)
|
|
||||||
unset(CXX_PASSED)
|
|
||||||
draco_check_c_compiles(${test_name} ${test_source} C_PASSED)
|
|
||||||
draco_check_cxx_compiles(${test_name} ${test_source} CXX_PASSED)
|
|
||||||
if(${C_PASSED} AND ${CXX_PASSED})
|
|
||||||
set(${result_var} 1)
|
|
||||||
else()
|
|
||||||
set(${result_var} 0)
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
|
@ -1,2 +1,3 @@
|
||||||
set(DRACO_INCLUDE_DIRS "@DRACO_INCLUDE_DIRS@")
|
@PACKAGE_INIT@
|
||||||
set(DRACO_LIBRARIES "draco")
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/draco-targets.cmake")
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
libdir=@libdir@
|
|
||||||
includedir=@includedir@
|
|
||||||
|
|
||||||
Name: @PROJECT_NAME@
|
Name: @PROJECT_NAME@
|
||||||
Description: Draco geometry de(com)pression library.
|
Description: Draco geometry de(com)pression library.
|
||||||
Version: @DRACO_VERSION@
|
Version: @DRACO_VERSION@
|
||||||
Cflags: -I${includedir}
|
Cflags: -I@includes_path@
|
||||||
Libs: -L${libdir} -ldraco
|
Libs: -L@libs_path@ -ldraco
|
||||||
Libs.private: @CMAKE_THREAD_LIBS_INIT@
|
Libs.private: @CMAKE_THREAD_LIBS_INIT@
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_)
|
if(DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_
|
||||||
|
@ -17,10 +31,6 @@ macro(set_draco_target)
|
||||||
endif()
|
endif()
|
||||||
set(draco_plugin_dependency draco_static)
|
set(draco_plugin_dependency draco_static)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_SHARED_LIBS)
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
||||||
endif()
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# Configures flags and sets build system globals.
|
# Configures flags and sets build system globals.
|
||||||
|
@ -36,23 +46,37 @@ macro(draco_set_build_definitions)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
draco_load_version_info()
|
draco_load_version_info()
|
||||||
set(DRACO_SOVERSION 1)
|
|
||||||
|
# Library version info. See the libtool docs for updating the values:
|
||||||
|
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
|
||||||
|
#
|
||||||
|
# c=<current>, r=<revision>, a=<age>
|
||||||
|
#
|
||||||
|
# libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
|
||||||
|
# passed to libtool.
|
||||||
|
#
|
||||||
|
# We set DRACO_SOVERSION = [c-a].a.r
|
||||||
|
set(LT_CURRENT 8)
|
||||||
|
set(LT_REVISION 0)
|
||||||
|
set(LT_AGE 0)
|
||||||
|
math(EXPR DRACO_SOVERSION_MAJOR "${LT_CURRENT} - ${LT_AGE}")
|
||||||
|
set(DRACO_SOVERSION "${DRACO_SOVERSION_MAJOR}.${LT_AGE}.${LT_REVISION}")
|
||||||
|
unset(LT_CURRENT)
|
||||||
|
unset(LT_REVISION)
|
||||||
|
unset(LT_AGE)
|
||||||
|
|
||||||
list(APPEND draco_include_paths "${draco_root}" "${draco_root}/src"
|
list(APPEND draco_include_paths "${draco_root}" "${draco_root}/src"
|
||||||
"${draco_build}")
|
"${draco_build}")
|
||||||
|
|
||||||
if(DRACO_ABSL)
|
if(DRACO_TRANSCODER_SUPPORTED)
|
||||||
list(APPEND draco_include_path "${draco_root}/third_party/abseil-cpp")
|
draco_setup_eigen()
|
||||||
|
draco_setup_filesystem()
|
||||||
|
draco_setup_tinygltf()
|
||||||
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
list(APPEND draco_gtest_include_paths
|
|
||||||
"${draco_root}/../googletest/googlemock/include"
|
|
||||||
"${draco_root}/../googletest/googlemock"
|
|
||||||
"${draco_root}/../googletest/googletest/include"
|
|
||||||
"${draco_root}/../googletest/googletest")
|
|
||||||
list(APPEND draco_test_include_paths ${draco_include_paths}
|
|
||||||
${draco_gtest_include_paths})
|
|
||||||
list(APPEND draco_defines "DRACO_CMAKE=1"
|
list(APPEND draco_defines "DRACO_CMAKE=1"
|
||||||
"DRACO_FLAGS_SRCDIR=\"${draco_root}\""
|
"DRACO_FLAGS_SRCDIR=\"${draco_root}\""
|
||||||
"DRACO_FLAGS_TMPDIR=\"/tmp\"")
|
"DRACO_FLAGS_TMPDIR=\"/tmp\"")
|
||||||
|
@ -63,11 +87,22 @@ macro(draco_set_build_definitions)
|
||||||
if(BUILD_SHARED_LIBS)
|
if(BUILD_SHARED_LIBS)
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||||
endif()
|
endif()
|
||||||
else()
|
endif()
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||||
# Ensure 64-bit platforms can support large files.
|
# Ensure 64-bit platforms can support large files.
|
||||||
list(APPEND draco_defines "_LARGEFILE_SOURCE" "_FILE_OFFSET_BITS=64")
|
list(APPEND draco_defines "_LARGEFILE_SOURCE" "_FILE_OFFSET_BITS=64")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
list(APPEND draco_clang_cxx_flags
|
||||||
|
"-Wno-implicit-const-int-float-conversion")
|
||||||
|
else()
|
||||||
|
list(APPEND draco_base_cxx_flags "-Wno-deprecated-declarations")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
|
@ -102,13 +137,9 @@ macro(draco_set_build_definitions)
|
||||||
set(draco_neon_source_file_suffix "neon.cc")
|
set(draco_neon_source_file_suffix "neon.cc")
|
||||||
set(draco_sse4_source_file_suffix "sse4.cc")
|
set(draco_sse4_source_file_suffix "sse4.cc")
|
||||||
|
|
||||||
if((${CMAKE_CXX_COMPILER_ID}
|
if((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
|
||||||
STREQUAL
|
VERSION_LESS 5)
|
||||||
"GNU"
|
OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"
|
||||||
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 5)
|
|
||||||
OR (${CMAKE_CXX_COMPILER_ID}
|
|
||||||
STREQUAL
|
|
||||||
"Clang"
|
|
||||||
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4))
|
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4))
|
||||||
message(
|
message(
|
||||||
WARNING "GNU/GCC < v5 or Clang/LLVM < v4, ENABLING COMPATIBILITY MODE.")
|
WARNING "GNU/GCC < v5 or Clang/LLVM < v4, ENABLING COMPATIBILITY MODE.")
|
||||||
|
@ -117,7 +148,9 @@ macro(draco_set_build_definitions)
|
||||||
|
|
||||||
if(EMSCRIPTEN)
|
if(EMSCRIPTEN)
|
||||||
draco_check_emscripten_environment()
|
draco_check_emscripten_environment()
|
||||||
draco_get_required_emscripten_flags(FLAG_LIST_VAR draco_base_cxx_flags)
|
draco_get_required_emscripten_flags(
|
||||||
|
FLAG_LIST_VAR_COMPILER draco_base_cxx_flags
|
||||||
|
FLAG_LIST_VAR_LINKER draco_base_exe_linker_flags)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
draco_configure_sanitizer()
|
draco_configure_sanitizer()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_)
|
if(DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Copyright 2022 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
|
if(DRACO_CMAKE_DRACO_DEPENDENCIES_CMAKE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(DRACO_CMAKE_DRACO_DEPENDENCIES_CMAKE 1)
|
||||||
|
|
||||||
|
include("${draco_root}/cmake/draco_variables.cmake")
|
||||||
|
|
||||||
|
# Each variable holds a user specified custom path to a local copy of the
|
||||||
|
# sources that belong to each project that Draco depends on. When paths are
|
||||||
|
# empty the build will be generated pointing to the Draco git submodules.
|
||||||
|
# Otherwise the paths specified by the user will be used in the build
|
||||||
|
# configuration.
|
||||||
|
|
||||||
|
# Path to the Eigen. The path must contain the Eigen directory.
|
||||||
|
set(DRACO_EIGEN_PATH)
|
||||||
|
draco_track_configuration_variable(DRACO_EIGEN_PATH)
|
||||||
|
|
||||||
|
# Path to the gulrak/filesystem installation. The path specified must contain
|
||||||
|
# the ghc subdirectory that houses the filesystem includes.
|
||||||
|
set(DRACO_FILESYSTEM_PATH)
|
||||||
|
draco_track_configuration_variable(DRACO_FILESYSTEM_PATH)
|
||||||
|
|
||||||
|
# Path to the googletest installation. The path must be to the root of the
|
||||||
|
# Googletest project directory.
|
||||||
|
set(DRACO_GOOGLETEST_PATH)
|
||||||
|
draco_track_configuration_variable(DRACO_GOOGLETEST_PATH)
|
||||||
|
|
||||||
|
# Path to the syoyo/tinygltf installation. The path must be to the root of the
|
||||||
|
# project directory.
|
||||||
|
set(DRACO_TINYGLTF_PATH)
|
||||||
|
draco_track_configuration_variable(DRACO_TINYGLTF_PATH)
|
||||||
|
|
||||||
|
# Utility macro for killing the build due to a missing submodule directory.
|
||||||
|
macro(draco_die_missing_submodule dir)
|
||||||
|
message(FATAL_ERROR "${dir} missing, run git submodule update --init")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Determines the Eigen location and updates the build configuration accordingly.
|
||||||
|
macro(draco_setup_eigen)
|
||||||
|
if(DRACO_EIGEN_PATH)
|
||||||
|
set(eigen_path "${DRACO_EIGEN_PATH}")
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY "${eigen_path}")
|
||||||
|
message(FATAL_ERROR "DRACO_EIGEN_PATH does not exist.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(eigen_path "${draco_root}/third_party/eigen")
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY "${eigen_path}")
|
||||||
|
draco_die_missing_submodule("${eigen_path}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(eigen_include_path "${eigen_path}/Eigen")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${eigen_path}/Eigen")
|
||||||
|
message(FATAL_ERROR "The eigen path does not contain an Eigen directory.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND draco_include_paths "${eigen_path}")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Determines the gulrak/filesystem location and updates the build configuration
|
||||||
|
# accordingly.
|
||||||
|
macro(draco_setup_filesystem)
|
||||||
|
if(DRACO_FILESYSTEM_PATH)
|
||||||
|
set(fs_path "${DRACO_FILESYSTEM_PATH}")
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY "${fs_path}")
|
||||||
|
message(FATAL_ERROR "DRACO_FILESYSTEM_PATH does not exist.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(fs_path "${draco_root}/third_party/filesystem/include")
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY "${fs_path}")
|
||||||
|
draco_die_missing_submodule("${fs_path}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND draco_include_paths "${fs_path}")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Determines the Googletest location and sets up include and source list vars
|
||||||
|
# for the draco_tests build.
|
||||||
|
macro(draco_setup_googletest)
|
||||||
|
if(DRACO_GOOGLETEST_PATH)
|
||||||
|
set(gtest_path "${DRACO_GOOGLETEST_PATH}")
|
||||||
|
if(NOT IS_DIRECTORY "${gtest_path}")
|
||||||
|
message(FATAL_ERROR "DRACO_GOOGLETEST_PATH does not exist.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(gtest_path "${draco_root}/third_party/googletest")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND draco_test_include_paths ${draco_include_paths}
|
||||||
|
"${gtest_path}/include" "${gtest_path}/googlemock"
|
||||||
|
"${gtest_path}/googletest/include" "${gtest_path}/googletest")
|
||||||
|
|
||||||
|
list(APPEND draco_gtest_all "${gtest_path}/googletest/src/gtest-all.cc")
|
||||||
|
list(APPEND draco_gtest_main "${gtest_path}/googletest/src/gtest_main.cc")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
|
||||||
|
# Determines the location of TinyGLTF and updates the build configuration
|
||||||
|
# accordingly.
|
||||||
|
macro(draco_setup_tinygltf)
|
||||||
|
if(DRACO_TINYGLTF_PATH)
|
||||||
|
set(tinygltf_path "${DRACO_TINYGLTF_PATH}")
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY "${tinygltf_path}")
|
||||||
|
message(FATAL_ERROR "DRACO_TINYGLTF_PATH does not exist.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(tinygltf_path "${draco_root}/third_party/tinygltf")
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY "${tinygltf_path}")
|
||||||
|
draco_die_missing_submodule("${tinygltf_path}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND draco_include_paths "${tinygltf_path}")
|
||||||
|
endmacro()
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_)
|
if(DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_
|
||||||
|
@ -18,39 +32,64 @@ endmacro()
|
||||||
|
|
||||||
# Obtains the required Emscripten flags for Draco targets.
|
# Obtains the required Emscripten flags for Draco targets.
|
||||||
macro(draco_get_required_emscripten_flags)
|
macro(draco_get_required_emscripten_flags)
|
||||||
set(em_FLAG_LIST_VAR)
|
set(em_FLAG_LIST_VAR_COMPILER)
|
||||||
|
set(em_FLAG_LIST_VAR_LINKER)
|
||||||
set(em_flags)
|
set(em_flags)
|
||||||
set(em_single_arg_opts FLAG_LIST_VAR)
|
set(em_single_arg_opts FLAG_LIST_VAR_COMPILER FLAG_LIST_VAR_LINKER)
|
||||||
set(em_multi_arg_opts)
|
set(em_multi_arg_opts)
|
||||||
cmake_parse_arguments(em "${em_flags}" "${em_single_arg_opts}"
|
cmake_parse_arguments(em "${em_flags}" "${em_single_arg_opts}"
|
||||||
"${em_multi_arg_opts}" ${ARGN})
|
"${em_multi_arg_opts}" ${ARGN})
|
||||||
if(NOT em_FLAG_LIST_VAR)
|
if(NOT em_FLAG_LIST_VAR_COMPILER)
|
||||||
message(FATAL "draco_get_required_emscripten_flags: FLAG_LIST_VAR required")
|
message(
|
||||||
|
FATAL
|
||||||
|
"draco_get_required_emscripten_flags: FLAG_LIST_VAR_COMPILER required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT em_FLAG_LIST_VAR_LINKER)
|
||||||
|
message(
|
||||||
|
FATAL
|
||||||
|
"draco_get_required_emscripten_flags: FLAG_LIST_VAR_LINKER required")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(DRACO_JS_GLUE)
|
if(DRACO_JS_GLUE)
|
||||||
unset(required_flags)
|
unset(required_flags)
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sALLOW_MEMORY_GROWTH=1")
|
# TODO(tomfinegan): Revisit splitting of compile/link flags for Emscripten,
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-Wno-almost-asm")
|
# and drop -Wno-unused-command-line-argument. Emscripten complains about
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "--memory-init-file" "0")
|
# what are supposedly link-only flags sent with compile commands, but then
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-fno-omit-frame-pointer")
|
# proceeds to produce broken code if the warnings are heeded.
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sMODULARIZE=1")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sNO_FILESYSTEM=1")
|
"-Wno-unused-command-line-argument")
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sEXPORTED_RUNTIME_METHODS=[]")
|
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sPRECISE_F32=1")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-Wno-almost-asm")
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_EXIT=0")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--memory-init-file" "0")
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_REJECTION=0")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-fno-omit-frame-pointer")
|
||||||
|
|
||||||
|
# According to Emscripten the following flags are linker only, but sending
|
||||||
|
# these flags (en masse) to only the linker results in a broken Emscripten
|
||||||
|
# build with an empty DracoDecoderModule.
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sALLOW_MEMORY_GROWTH=1")
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sMODULARIZE=1")
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sFILESYSTEM=0")
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
|
||||||
|
"-sEXPORTED_FUNCTIONS=[\"_free\",\"_malloc\"]")
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sPRECISE_F32=1")
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sNODEJS_CATCH_EXIT=0")
|
||||||
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sNODEJS_CATCH_REJECTION=0")
|
||||||
|
|
||||||
if(DRACO_FAST)
|
if(DRACO_FAST)
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "--llvm-lto" "1")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--llvm-lto" "1")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# The WASM flag is reported as linker only.
|
||||||
if(DRACO_WASM)
|
if(DRACO_WASM)
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=1")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=1")
|
||||||
else()
|
else()
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=0")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=0")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# The LEGACY_VM_SUPPORT flag is reported as linker only.
|
||||||
if(DRACO_IE_COMPATIBLE)
|
if(DRACO_IE_COMPATIBLE)
|
||||||
list(APPEND ${em_FLAG_LIST_VAR} "-sLEGACY_VM_SUPPORT=1")
|
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sLEGACY_VM_SUPPORT=1")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
@ -66,10 +105,11 @@ macro(draco_generate_emscripten_glue)
|
||||||
"${glue_multi_arg_opts}" ${ARGN})
|
"${glue_multi_arg_opts}" ${ARGN})
|
||||||
|
|
||||||
if(DRACO_VERBOSE GREATER 1)
|
if(DRACO_VERBOSE GREATER 1)
|
||||||
message("--------- draco_generate_emscripten_glue -----------\n"
|
message(
|
||||||
"glue_INPUT_IDL=${glue_INPUT_IDL}\n"
|
"--------- draco_generate_emscripten_glue -----------\n"
|
||||||
"glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n" ]
|
"glue_INPUT_IDL=${glue_INPUT_IDL}\n"
|
||||||
"----------------------------------------------------\n")
|
"glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n"
|
||||||
|
"----------------------------------------------------\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT glue_INPUT_IDL OR NOT glue_OUTPUT_PATH)
|
if(NOT glue_INPUT_IDL OR NOT glue_OUTPUT_PATH)
|
||||||
|
@ -79,22 +119,22 @@ macro(draco_generate_emscripten_glue)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Generate the glue source.
|
# Generate the glue source.
|
||||||
execute_process(COMMAND ${PYTHON_EXECUTABLE}
|
execute_process(
|
||||||
$ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
||||||
${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
|
${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
|
||||||
if(NOT EXISTS "${glue_OUTPUT_PATH}.cpp")
|
if(NOT EXISTS "${glue_OUTPUT_PATH}.cpp")
|
||||||
message(FATAL_ERROR "JS glue generation failed for ${glue_INPUT_IDL}.")
|
message(FATAL_ERROR "JS glue generation failed for ${glue_INPUT_IDL}.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create a dependency so that it regenerated on edits.
|
# Create a dependency so that it regenerated on edits.
|
||||||
add_custom_command(OUTPUT "${glue_OUTPUT_PATH}.cpp"
|
add_custom_command(
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
OUTPUT "${glue_OUTPUT_PATH}.cpp"
|
||||||
$ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
||||||
${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
|
${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
|
||||||
DEPENDS ${draco_js_dec_idl}
|
DEPENDS ${draco_js_dec_idl}
|
||||||
COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
|
COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
|
||||||
WORKING_DIRECTORY ${draco_build}
|
WORKING_DIRECTORY ${draco_build}
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# Wrapper for draco_add_executable() that handles the extra work necessary for
|
# Wrapper for draco_add_executable() that handles the extra work necessary for
|
||||||
|
@ -120,8 +160,14 @@ macro(draco_add_emscripten_executable)
|
||||||
unset(emexe_LINK_FLAGS)
|
unset(emexe_LINK_FLAGS)
|
||||||
set(optional_args)
|
set(optional_args)
|
||||||
set(single_value_args NAME GLUE_PATH)
|
set(single_value_args NAME GLUE_PATH)
|
||||||
set(multi_value_args SOURCES DEFINES FEATURES INCLUDES LINK_FLAGS
|
set(multi_value_args
|
||||||
PRE_LINK_JS_SOURCES POST_LINK_JS_SOURCES)
|
SOURCES
|
||||||
|
DEFINES
|
||||||
|
FEATURES
|
||||||
|
INCLUDES
|
||||||
|
LINK_FLAGS
|
||||||
|
PRE_LINK_JS_SOURCES
|
||||||
|
POST_LINK_JS_SOURCES)
|
||||||
|
|
||||||
cmake_parse_arguments(emexe "${optional_args}" "${single_value_args}"
|
cmake_parse_arguments(emexe "${optional_args}" "${single_value_args}"
|
||||||
"${multi_value_args}" ${ARGN})
|
"${multi_value_args}" ${ARGN})
|
||||||
|
@ -136,49 +182,50 @@ macro(draco_add_emscripten_executable)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(DRACO_VERBOSE GREATER 1)
|
if(DRACO_VERBOSE GREATER 1)
|
||||||
message("--------- draco_add_emscripten_executable ---------\n"
|
message(
|
||||||
"emexe_NAME=${emexe_NAME}\n"
|
"--------- draco_add_emscripten_executable ---------\n"
|
||||||
"emexe_SOURCES=${emexe_SOURCES}\n"
|
"emexe_NAME=${emexe_NAME}\n"
|
||||||
"emexe_DEFINES=${emexe_DEFINES}\n"
|
"emexe_SOURCES=${emexe_SOURCES}\n"
|
||||||
"emexe_INCLUDES=${emexe_INCLUDES}\n"
|
"emexe_DEFINES=${emexe_DEFINES}\n"
|
||||||
"emexe_LINK_FLAGS=${emexe_LINK_FLAGS}\n"
|
"emexe_INCLUDES=${emexe_INCLUDES}\n"
|
||||||
"emexe_GLUE_PATH=${emexe_GLUE_PATH}\n"
|
"emexe_LINK_FLAGS=${emexe_LINK_FLAGS}\n"
|
||||||
"emexe_FEATURES=${emexe_FEATURES}\n"
|
"emexe_GLUE_PATH=${emexe_GLUE_PATH}\n"
|
||||||
"emexe_PRE_LINK_JS_SOURCES=${emexe_PRE_LINK_JS_SOURCES}\n"
|
"emexe_FEATURES=${emexe_FEATURES}\n"
|
||||||
"emexe_POST_LINK_JS_SOURCES=${emexe_POST_LINK_JS_SOURCES}\n"
|
"emexe_PRE_LINK_JS_SOURCES=${emexe_PRE_LINK_JS_SOURCES}\n"
|
||||||
"----------------------------------------------------\n")
|
"emexe_POST_LINK_JS_SOURCES=${emexe_POST_LINK_JS_SOURCES}\n"
|
||||||
|
"----------------------------------------------------\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The Emscripten linker needs the C++ flags in addition to whatever has been
|
# The Emscripten linker needs the C++ flags in addition to whatever has been
|
||||||
# passed in with the target.
|
# passed in with the target.
|
||||||
list(APPEND emexe_LINK_FLAGS ${DRACO_CXX_FLAGS})
|
list(APPEND emexe_LINK_FLAGS ${DRACO_CXX_FLAGS})
|
||||||
|
|
||||||
if(DRACO_GLTF)
|
if(DRACO_GLTF_BITSTREAM)
|
||||||
draco_add_executable(NAME
|
# Add "_gltf" suffix to target output name.
|
||||||
${emexe_NAME}
|
draco_add_executable(
|
||||||
OUTPUT_NAME
|
NAME ${emexe_NAME}
|
||||||
${emexe_NAME}_gltf
|
OUTPUT_NAME ${emexe_NAME}_gltf
|
||||||
SOURCES
|
SOURCES ${emexe_SOURCES}
|
||||||
${emexe_SOURCES}
|
DEFINES ${emexe_DEFINES}
|
||||||
DEFINES
|
INCLUDES ${emexe_INCLUDES}
|
||||||
${emexe_DEFINES}
|
LINK_FLAGS ${emexe_LINK_FLAGS})
|
||||||
INCLUDES
|
|
||||||
${emexe_INCLUDES}
|
|
||||||
LINK_FLAGS
|
|
||||||
${emexe_LINK_FLAGS})
|
|
||||||
else()
|
else()
|
||||||
draco_add_executable(NAME ${emexe_NAME} SOURCES ${emexe_SOURCES} DEFINES
|
draco_add_executable(
|
||||||
${emexe_DEFINES} INCLUDES ${emexe_INCLUDES} LINK_FLAGS
|
NAME ${emexe_NAME}
|
||||||
${emexe_LINK_FLAGS})
|
SOURCES ${emexe_SOURCES}
|
||||||
|
DEFINES ${emexe_DEFINES}
|
||||||
|
INCLUDES ${emexe_INCLUDES}
|
||||||
|
LINK_FLAGS ${emexe_LINK_FLAGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach(feature ${emexe_FEATURES})
|
foreach(feature ${emexe_FEATURES})
|
||||||
draco_enable_feature(FEATURE ${feature} TARGETS ${emexe_NAME})
|
draco_enable_feature(FEATURE ${feature} TARGETS ${emexe_NAME})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set_property(SOURCE ${emexe_SOURCES}
|
set_property(
|
||||||
APPEND
|
SOURCE ${emexe_SOURCES}
|
||||||
PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
|
APPEND
|
||||||
|
PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
|
||||||
em_link_pre_js(${emexe_NAME} ${emexe_PRE_LINK_JS_SOURCES})
|
em_link_pre_js(${emexe_NAME} ${emexe_PRE_LINK_JS_SOURCES})
|
||||||
em_link_post_js(${emexe_NAME} "${emexe_GLUE_PATH}.js"
|
em_link_post_js(${emexe_NAME} "${emexe_GLUE_PATH}.js"
|
||||||
${emexe_POST_LINK_JS_SOURCES})
|
${emexe_POST_LINK_JS_SOURCES})
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_FLAGS_CMAKE_)
|
if(DRACO_CMAKE_DRACO_FLAGS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_FLAGS_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_FLAGS_CMAKE_
|
||||||
|
@ -24,7 +38,7 @@ macro(draco_set_compiler_flags_for_sources)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_source_files_properties(${compiler_SOURCES} PROPERTIES COMPILE_FLAGS
|
set_source_files_properties(${compiler_SOURCES} PROPERTIES COMPILE_FLAGS
|
||||||
${compiler_FLAGS})
|
${compiler_FLAGS})
|
||||||
|
|
||||||
if(DRACO_VERBOSE GREATER 1)
|
if(DRACO_VERBOSE GREATER 1)
|
||||||
foreach(source ${compiler_SOURCES})
|
foreach(source ${compiler_SOURCES})
|
||||||
|
@ -85,8 +99,8 @@ macro(draco_test_cxx_flag)
|
||||||
# are passed as a list it will remove the list separators, and attempt to run
|
# are passed as a list it will remove the list separators, and attempt to run
|
||||||
# a compile command using list entries concatenated together as a single
|
# a compile command using list entries concatenated together as a single
|
||||||
# argument. Avoid the problem by forcing the argument to be a string.
|
# argument. Avoid the problem by forcing the argument to be a string.
|
||||||
draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags)
|
draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags_string)
|
||||||
check_cxx_compiler_flag("${all_cxx_flags}" draco_all_cxx_flags_pass)
|
check_cxx_compiler_flag("${all_cxx_flags_string}" draco_all_cxx_flags_pass)
|
||||||
|
|
||||||
if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass)
|
if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass)
|
||||||
draco_die("Flag test failed for required flag(s): "
|
draco_die("Flag test failed for required flag(s): "
|
||||||
|
@ -245,3 +259,34 @@ macro(draco_set_cxx_flags)
|
||||||
draco_test_cxx_flag(FLAG_LIST_VAR_NAMES ${cxx_flag_lists})
|
draco_test_cxx_flag(FLAG_LIST_VAR_NAMES ${cxx_flag_lists})
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
# Collects Draco built-in and user-specified linker flags and tests them. Halts
|
||||||
|
# configuration and reports the error when any flags cause the build to fail.
|
||||||
|
#
|
||||||
|
# Note: draco_test_exe_linker_flag() does the real work of setting the flags and
|
||||||
|
# running the test compile commands.
|
||||||
|
macro(draco_set_exe_linker_flags)
|
||||||
|
unset(linker_flag_lists)
|
||||||
|
|
||||||
|
if(DRACO_VERBOSE)
|
||||||
|
message("draco_set_exe_linker_flags: "
|
||||||
|
"draco_base_exe_linker_flags=${draco_base_exe_linker_flags}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(draco_base_exe_linker_flags)
|
||||||
|
list(APPEND linker_flag_lists draco_base_exe_linker_flags)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(linker_flag_lists)
|
||||||
|
unset(test_linker_flags)
|
||||||
|
|
||||||
|
if(DRACO_VERBOSE)
|
||||||
|
message("draco_set_exe_linker_flags: "
|
||||||
|
"linker_flag_lists=${linker_flag_lists}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
draco_set_and_stringify(DEST test_linker_flags SOURCE_VARS
|
||||||
|
${linker_flag_lists})
|
||||||
|
draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME test_linker_flags)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_HELPERS_CMAKE_)
|
if(DRACO_CMAKE_DRACO_HELPERS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_HELPERS_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_HELPERS_CMAKE_
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_INSTALL_CMAKE_)
|
if(DRACO_CMAKE_DRACO_INSTALL_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_INSTALL_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_INSTALL_CMAKE_
|
||||||
set(DRACO_CMAKE_DRACO_INSTALL_CMAKE_ 1)
|
set(DRACO_CMAKE_DRACO_INSTALL_CMAKE_ 1)
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# Sets up the draco install targets. Must be called after the static library
|
# Sets up the draco install targets. Must be called after the static library
|
||||||
# target is created.
|
# target is created.
|
||||||
macro(draco_setup_install_target)
|
macro(draco_setup_install_target)
|
||||||
include(GNUInstallDirs)
|
set(bin_path "${CMAKE_INSTALL_BINDIR}")
|
||||||
|
set(data_path "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||||
# pkg-config: draco.pc
|
set(includes_path "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
set(libs_path "${CMAKE_INSTALL_LIBDIR}")
|
||||||
set(exec_prefix "\${prefix}")
|
|
||||||
set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
|
|
||||||
set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
|
|
||||||
set(draco_lib_name "draco")
|
|
||||||
|
|
||||||
configure_file("${draco_root}/cmake/draco.pc.template"
|
|
||||||
"${draco_build}/draco.pc" @ONLY NEWLINE_STYLE UNIX)
|
|
||||||
install(FILES "${draco_build}/draco.pc"
|
|
||||||
DESTINATION "${prefix}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
|
||||||
|
|
||||||
# CMake config: draco-config.cmake
|
|
||||||
set(DRACO_INCLUDE_DIRS "${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
|
|
||||||
configure_file("${draco_root}/cmake/draco-config.cmake.template"
|
|
||||||
"${draco_build}/draco-config.cmake" @ONLY NEWLINE_STYLE UNIX)
|
|
||||||
install(
|
|
||||||
FILES "${draco_build}/draco-config.cmake"
|
|
||||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/cmake")
|
|
||||||
|
|
||||||
foreach(file ${draco_sources})
|
foreach(file ${draco_sources})
|
||||||
if(file MATCHES "h$")
|
if(file MATCHES "h$")
|
||||||
|
@ -34,46 +34,88 @@ macro(draco_setup_install_target)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
list(REMOVE_DUPLICATES draco_api_includes)
|
||||||
|
|
||||||
# Strip $draco_src_root from the file paths: we need to install relative to
|
# Strip $draco_src_root from the file paths: we need to install relative to
|
||||||
# $include_directory.
|
# $include_directory.
|
||||||
list(TRANSFORM draco_api_includes REPLACE "${draco_src_root}/" "")
|
list(TRANSFORM draco_api_includes REPLACE "${draco_src_root}/" "")
|
||||||
set(include_directory "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
|
|
||||||
|
|
||||||
foreach(draco_api_include ${draco_api_includes})
|
foreach(draco_api_include ${draco_api_includes})
|
||||||
get_filename_component(file_directory ${draco_api_include} DIRECTORY)
|
get_filename_component(file_directory ${draco_api_include} DIRECTORY)
|
||||||
set(target_directory "${include_directory}/draco/${file_directory}")
|
set(target_directory "${includes_path}/draco/${file_directory}")
|
||||||
install(FILES ${draco_src_root}/${draco_api_include}
|
install(FILES ${draco_src_root}/${draco_api_include}
|
||||||
DESTINATION "${target_directory}")
|
DESTINATION "${target_directory}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
install(
|
install(FILES "${draco_build}/draco/draco_features.h"
|
||||||
FILES "${draco_build}/draco/draco_features.h"
|
DESTINATION "${includes_path}/draco/")
|
||||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/draco/")
|
|
||||||
|
|
||||||
install(TARGETS draco_decoder DESTINATION
|
install(TARGETS draco_decoder DESTINATION "${bin_path}")
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
|
install(TARGETS draco_encoder DESTINATION "${bin_path}")
|
||||||
install(TARGETS draco_encoder DESTINATION
|
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
|
if(DRACO_TRANSCODER_SUPPORTED)
|
||||||
|
install(TARGETS draco_transcoder DESTINATION "${bin_path}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
install(TARGETS draco DESTINATION
|
install(
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
TARGETS draco
|
||||||
|
EXPORT dracoExport
|
||||||
|
RUNTIME DESTINATION "${bin_path}"
|
||||||
|
ARCHIVE DESTINATION "${libs_path}"
|
||||||
|
LIBRARY DESTINATION "${libs_path}")
|
||||||
else()
|
else()
|
||||||
install(TARGETS draco_static DESTINATION
|
install(
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
TARGETS draco_static
|
||||||
|
EXPORT dracoExport
|
||||||
|
DESTINATION "${libs_path}")
|
||||||
|
|
||||||
if(BUILD_SHARED_LIBS)
|
if(BUILD_SHARED_LIBS)
|
||||||
install(TARGETS draco_shared DESTINATION
|
install(
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
TARGETS draco_shared
|
||||||
|
EXPORT dracoExport
|
||||||
|
RUNTIME DESTINATION "${bin_path}"
|
||||||
|
ARCHIVE DESTINATION "${libs_path}"
|
||||||
|
LIBRARY DESTINATION "${libs_path}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(DRACO_UNITY_PLUGIN)
|
if(DRACO_UNITY_PLUGIN)
|
||||||
install(TARGETS dracodec_unity DESTINATION
|
install(TARGETS dracodec_unity DESTINATION "${libs_path}")
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
|
||||||
endif()
|
|
||||||
if(DRACO_MAYA_PLUGIN)
|
|
||||||
install(TARGETS draco_maya_wrapper DESTINATION
|
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(DRACO_MAYA_PLUGIN)
|
||||||
|
install(TARGETS draco_maya_wrapper DESTINATION "${libs_path}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# pkg-config: draco.pc
|
||||||
|
configure_file("${draco_root}/cmake/draco.pc.template"
|
||||||
|
"${draco_build}/draco.pc" @ONLY NEWLINE_STYLE UNIX)
|
||||||
|
install(FILES "${draco_build}/draco.pc" DESTINATION "${libs_path}/pkgconfig")
|
||||||
|
|
||||||
|
# CMake config: draco-config.cmake
|
||||||
|
configure_package_config_file(
|
||||||
|
"${draco_root}/cmake/draco-config.cmake.template"
|
||||||
|
"${draco_build}/draco-config.cmake"
|
||||||
|
INSTALL_DESTINATION "${data_path}/cmake/draco")
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${draco_build}/draco-config-version.cmake"
|
||||||
|
VERSION ${DRACO_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion)
|
||||||
|
|
||||||
|
export(
|
||||||
|
EXPORT dracoExport
|
||||||
|
NAMESPACE draco::
|
||||||
|
FILE "${draco_build}/draco-targets.cmake")
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT dracoExport
|
||||||
|
NAMESPACE draco::
|
||||||
|
FILE draco-targets.cmake
|
||||||
|
DESTINATION "${data_path}/cmake/draco")
|
||||||
|
|
||||||
|
install(FILES "${draco_build}/draco-config.cmake"
|
||||||
|
"${draco_build}/draco-config-version.cmake"
|
||||||
|
DESTINATION "${data_path}/cmake/draco")
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_)
|
if(DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_
|
||||||
|
@ -61,17 +75,15 @@ macro(draco_process_intrinsics_sources)
|
||||||
unset(sse4_sources)
|
unset(sse4_sources)
|
||||||
list(APPEND sse4_sources ${arg_SOURCES})
|
list(APPEND sse4_sources ${arg_SOURCES})
|
||||||
|
|
||||||
list(FILTER sse4_sources INCLUDE REGEX
|
list(FILTER sse4_sources INCLUDE REGEX "${draco_sse4_source_file_suffix}$")
|
||||||
"${draco_sse4_source_file_suffix}$")
|
|
||||||
|
|
||||||
if(sse4_sources)
|
if(sse4_sources)
|
||||||
unset(sse4_flags)
|
unset(sse4_flags)
|
||||||
draco_get_intrinsics_flag_for_suffix(SUFFIX
|
draco_get_intrinsics_flag_for_suffix(
|
||||||
${draco_sse4_source_file_suffix}
|
SUFFIX ${draco_sse4_source_file_suffix} VARIABLE sse4_flags)
|
||||||
VARIABLE sse4_flags)
|
|
||||||
if(sse4_flags)
|
if(sse4_flags)
|
||||||
draco_set_compiler_flags_for_sources(SOURCES ${sse4_sources} FLAGS
|
draco_set_compiler_flags_for_sources(SOURCES ${sse4_sources} FLAGS
|
||||||
${sse4_flags})
|
${sse4_flags})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -79,17 +91,15 @@ macro(draco_process_intrinsics_sources)
|
||||||
if(DRACO_ENABLE_NEON AND draco_have_neon)
|
if(DRACO_ENABLE_NEON AND draco_have_neon)
|
||||||
unset(neon_sources)
|
unset(neon_sources)
|
||||||
list(APPEND neon_sources ${arg_SOURCES})
|
list(APPEND neon_sources ${arg_SOURCES})
|
||||||
list(FILTER neon_sources INCLUDE REGEX
|
list(FILTER neon_sources INCLUDE REGEX "${draco_neon_source_file_suffix}$")
|
||||||
"${draco_neon_source_file_suffix}$")
|
|
||||||
|
|
||||||
if(neon_sources AND DRACO_NEON_INTRINSICS_FLAG)
|
if(neon_sources AND DRACO_NEON_INTRINSICS_FLAG)
|
||||||
unset(neon_flags)
|
unset(neon_flags)
|
||||||
draco_get_intrinsics_flag_for_suffix(SUFFIX
|
draco_get_intrinsics_flag_for_suffix(
|
||||||
${draco_neon_source_file_suffix}
|
SUFFIX ${draco_neon_source_file_suffix} VARIABLE neon_flags)
|
||||||
VARIABLE neon_flags)
|
|
||||||
if(neon_flags)
|
if(neon_flags)
|
||||||
draco_set_compiler_flags_for_sources(SOURCES ${neon_sources} FLAGS
|
draco_set_compiler_flags_for_sources(SOURCES ${neon_sources} FLAGS
|
||||||
${neon_flags})
|
${neon_flags})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_OPTIONS_CMAKE_)
|
if(DRACO_CMAKE_DRACO_OPTIONS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_OPTIONS_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_OPTIONS_CMAKE_
|
||||||
|
@ -18,17 +32,22 @@ macro(draco_option)
|
||||||
cmake_parse_arguments(option "${optional_args}" "${single_value_args}"
|
cmake_parse_arguments(option "${optional_args}" "${single_value_args}"
|
||||||
"${multi_value_args}" ${ARGN})
|
"${multi_value_args}" ${ARGN})
|
||||||
|
|
||||||
if(NOT (option_NAME AND option_HELPSTRING AND DEFINED option_VALUE))
|
if(NOT
|
||||||
|
(option_NAME
|
||||||
|
AND option_HELPSTRING
|
||||||
|
AND DEFINED option_VALUE))
|
||||||
message(FATAL_ERROR "draco_option: NAME HELPSTRING and VALUE required.")
|
message(FATAL_ERROR "draco_option: NAME HELPSTRING and VALUE required.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(${option_NAME} ${option_HELPSTRING} ${option_VALUE})
|
option(${option_NAME} ${option_HELPSTRING} ${option_VALUE})
|
||||||
|
|
||||||
if(DRACO_VERBOSE GREATER 2)
|
if(DRACO_VERBOSE GREATER 2)
|
||||||
message("--------- draco_option ---------\n" "option_NAME=${option_NAME}\n"
|
message(
|
||||||
"option_HELPSTRING=${option_HELPSTRING}\n"
|
"--------- draco_option ---------\n"
|
||||||
"option_VALUE=${option_VALUE}\n"
|
"option_NAME=${option_NAME}\n"
|
||||||
"------------------------------------------\n")
|
"option_HELPSTRING=${option_HELPSTRING}\n"
|
||||||
|
"option_VALUE=${option_VALUE}\n"
|
||||||
|
"------------------------------------------\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND draco_options ${option_NAME})
|
list(APPEND draco_options ${option_NAME})
|
||||||
|
@ -44,33 +63,74 @@ endmacro()
|
||||||
|
|
||||||
# Set default options.
|
# Set default options.
|
||||||
macro(draco_set_default_options)
|
macro(draco_set_default_options)
|
||||||
draco_option(NAME DRACO_FAST HELPSTRING "Try to build faster libs." VALUE OFF)
|
draco_option(
|
||||||
draco_option(NAME DRACO_JS_GLUE HELPSTRING
|
NAME DRACO_FAST
|
||||||
"Enable JS Glue and JS targets when using Emscripten." VALUE ON)
|
HELPSTRING "Try to build faster libs."
|
||||||
draco_option(NAME DRACO_IE_COMPATIBLE HELPSTRING
|
VALUE OFF)
|
||||||
"Enable support for older IE builds when using Emscripten." VALUE
|
draco_option(
|
||||||
OFF)
|
NAME DRACO_JS_GLUE
|
||||||
draco_option(NAME DRACO_MESH_COMPRESSION HELPSTRING "Enable mesh compression."
|
HELPSTRING "Enable JS Glue and JS targets when using Emscripten."
|
||||||
VALUE ON)
|
VALUE ON)
|
||||||
draco_option(NAME DRACO_POINT_CLOUD_COMPRESSION HELPSTRING
|
draco_option(
|
||||||
"Enable point cloud compression." VALUE ON)
|
NAME DRACO_IE_COMPATIBLE
|
||||||
draco_option(NAME DRACO_PREDICTIVE_EDGEBREAKER HELPSTRING
|
HELPSTRING "Enable support for older IE builds when using Emscripten."
|
||||||
"Enable predictive edgebreaker." VALUE ON)
|
VALUE OFF)
|
||||||
draco_option(NAME DRACO_STANDARD_EDGEBREAKER HELPSTRING
|
draco_option(
|
||||||
"Enable stand edgebreaker." VALUE ON)
|
NAME DRACO_MESH_COMPRESSION
|
||||||
draco_option(NAME DRACO_BACKWARDS_COMPATIBILITY HELPSTRING
|
HELPSTRING "Enable mesh compression."
|
||||||
"Enable backwards compatibility." VALUE ON)
|
VALUE ON)
|
||||||
draco_option(NAME DRACO_DECODER_ATTRIBUTE_DEDUPLICATION HELPSTRING
|
draco_option(
|
||||||
"Enable attribute deduping." VALUE OFF)
|
NAME DRACO_POINT_CLOUD_COMPRESSION
|
||||||
draco_option(NAME DRACO_TESTS HELPSTRING "Enables tests." VALUE OFF)
|
HELPSTRING "Enable point cloud compression."
|
||||||
draco_option(NAME DRACO_WASM HELPSTRING "Enables WASM support." VALUE OFF)
|
VALUE ON)
|
||||||
draco_option(NAME DRACO_UNITY_PLUGIN HELPSTRING
|
draco_option(
|
||||||
"Build plugin library for Unity." VALUE OFF)
|
NAME DRACO_PREDICTIVE_EDGEBREAKER
|
||||||
draco_option(NAME DRACO_ANIMATION_ENCODING HELPSTRING "Enable animation."
|
HELPSTRING "Enable predictive edgebreaker."
|
||||||
VALUE OFF)
|
VALUE ON)
|
||||||
draco_option(NAME DRACO_GLTF HELPSTRING "Support GLTF." VALUE OFF)
|
draco_option(
|
||||||
draco_option(NAME DRACO_MAYA_PLUGIN HELPSTRING
|
NAME DRACO_STANDARD_EDGEBREAKER
|
||||||
"Build plugin library for Maya." VALUE OFF)
|
HELPSTRING "Enable stand edgebreaker."
|
||||||
|
VALUE ON)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_BACKWARDS_COMPATIBILITY
|
||||||
|
HELPSTRING "Enable backwards compatibility."
|
||||||
|
VALUE ON)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_DECODER_ATTRIBUTE_DEDUPLICATION
|
||||||
|
HELPSTRING "Enable attribute deduping."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_TESTS
|
||||||
|
HELPSTRING "Enables tests."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_WASM
|
||||||
|
HELPSTRING "Enables WASM support."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_UNITY_PLUGIN
|
||||||
|
HELPSTRING "Build plugin library for Unity."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_ANIMATION_ENCODING
|
||||||
|
HELPSTRING "Enable animation."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_GLTF_BITSTREAM
|
||||||
|
HELPSTRING "Draco GLTF extension bitstream specified features only."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_MAYA_PLUGIN
|
||||||
|
HELPSTRING "Build plugin library for Maya."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_TRANSCODER_SUPPORTED
|
||||||
|
HELPSTRING "Enable the Draco transcoder."
|
||||||
|
VALUE OFF)
|
||||||
|
draco_option(
|
||||||
|
NAME DRACO_DEBUG_COMPILER_WARNINGS
|
||||||
|
HELPSTRING "Turn on more warnings."
|
||||||
|
VALUE OFF)
|
||||||
draco_check_deprecated_options()
|
draco_check_deprecated_options()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
@ -117,14 +177,16 @@ macro(draco_check_deprecated_options)
|
||||||
DRACO_MAYA_PLUGIN)
|
DRACO_MAYA_PLUGIN)
|
||||||
draco_handle_deprecated_option(OLDNAME BUILD_USD_PLUGIN NEWNAME
|
draco_handle_deprecated_option(OLDNAME BUILD_USD_PLUGIN NEWNAME
|
||||||
BUILD_SHARED_LIBS)
|
BUILD_SHARED_LIBS)
|
||||||
|
draco_handle_deprecated_option(OLDNAME DRACO_GLTF NEWNAME
|
||||||
|
DRACO_GLTF_BITSTREAM)
|
||||||
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# Macro for setting Draco features based on user configuration. Features enabled
|
# Macro for setting Draco features based on user configuration. Features enabled
|
||||||
# by this macro are Draco global.
|
# by this macro are Draco global.
|
||||||
macro(draco_set_optional_features)
|
macro(draco_set_optional_features)
|
||||||
if(DRACO_GLTF)
|
if(DRACO_GLTF_BITSTREAM)
|
||||||
# Override settings when building for GLTF.
|
# Enable only the features included in the Draco GLTF bitstream spec.
|
||||||
draco_enable_feature(FEATURE "DRACO_MESH_COMPRESSION_SUPPORTED")
|
draco_enable_feature(FEATURE "DRACO_MESH_COMPRESSION_SUPPORTED")
|
||||||
draco_enable_feature(FEATURE "DRACO_NORMAL_ENCODING_SUPPORTED")
|
draco_enable_feature(FEATURE "DRACO_NORMAL_ENCODING_SUPPORTED")
|
||||||
draco_enable_feature(FEATURE "DRACO_STANDARD_EDGEBREAKER_SUPPORTED")
|
draco_enable_feature(FEATURE "DRACO_STANDARD_EDGEBREAKER_SUPPORTED")
|
||||||
|
@ -170,6 +232,11 @@ macro(draco_set_optional_features)
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(DRACO_TRANSCODER_SUPPORTED)
|
||||||
|
draco_enable_feature(FEATURE "DRACO_TRANSCODER_SUPPORTED")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# Macro that handles tracking of Draco preprocessor symbols for the purpose of
|
# Macro that handles tracking of Draco preprocessor symbols for the purpose of
|
||||||
|
@ -221,8 +288,56 @@ function(draco_generate_features_h)
|
||||||
file(APPEND "${draco_features_file_name}.new" "#define ${feature}\n")
|
file(APPEND "${draco_features_file_name}.new" "#define ${feature}\n")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"// Enable DRACO_DEBUG_COMPILER_WARNINGS at CMake generation \n"
|
||||||
|
"// time to remove these pragmas.\n")
|
||||||
|
|
||||||
|
# warning C4018: '<operator>': signed/unsigned mismatch.
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4018)\n")
|
||||||
|
|
||||||
|
# warning C4146: unary minus operator applied to unsigned type, result
|
||||||
|
# still unsigned
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4146)\n")
|
||||||
|
|
||||||
|
# warning C4244: 'return': conversion from '<type>' to '<type>', possible
|
||||||
|
# loss of data.
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4244)\n")
|
||||||
|
|
||||||
|
# warning C4267: 'initializing' conversion from '<type>' to '<type>',
|
||||||
|
# possible loss of data.
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4267)\n")
|
||||||
|
|
||||||
|
# warning C4305: 'context' : truncation from 'type1' to 'type2'.
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4305)\n")
|
||||||
|
|
||||||
|
# warning C4661: 'identifier' : no suitable definition provided for
|
||||||
|
# explicit template instantiation request.
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4661)\n")
|
||||||
|
|
||||||
|
# warning C4800: Implicit conversion from 'type' to bool. Possible
|
||||||
|
# information loss.
|
||||||
|
# Also, in older MSVC releases:
|
||||||
|
# warning C4800: 'type' : forcing value to bool 'true' or 'false'
|
||||||
|
# (performance warning).
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4800)\n")
|
||||||
|
|
||||||
|
# warning C4804: '<operator>': unsafe use of type '<type>' in operation.
|
||||||
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
|
"#pragma warning(disable:4804)\n")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
file(APPEND "${draco_features_file_name}.new"
|
file(APPEND "${draco_features_file_name}.new"
|
||||||
"\n#endif // DRACO_FEATURES_H_")
|
"\n#endif // DRACO_FEATURES_H_\n")
|
||||||
|
|
||||||
# Will replace ${draco_features_file_name} only if the file content has
|
# Will replace ${draco_features_file_name} only if the file content has
|
||||||
# changed. This prevents forced Draco rebuilds after CMake runs.
|
# changed. This prevents forced Draco rebuilds after CMake runs.
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_)
|
if(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_SANITIZER_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_SANITIZER_CMAKE_
|
||||||
|
@ -5,7 +19,9 @@ set(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_ 1)
|
||||||
|
|
||||||
# Handles the details of enabling sanitizers.
|
# Handles the details of enabling sanitizers.
|
||||||
macro(draco_configure_sanitizer)
|
macro(draco_configure_sanitizer)
|
||||||
if(DRACO_SANITIZE AND NOT EMSCRIPTEN AND NOT MSVC)
|
if(DRACO_SANITIZE
|
||||||
|
AND NOT EMSCRIPTEN
|
||||||
|
AND NOT MSVC)
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
if(DRACO_SANITIZE MATCHES "cfi")
|
if(DRACO_SANITIZE MATCHES "cfi")
|
||||||
list(APPEND SAN_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi")
|
list(APPEND SAN_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi")
|
||||||
|
@ -13,8 +29,8 @@ macro(draco_configure_sanitizer)
|
||||||
"-fuse-ld=gold")
|
"-fuse-ld=gold")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4
|
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4 AND DRACO_SANITIZE MATCHES
|
||||||
AND DRACO_SANITIZE MATCHES "integer|undefined")
|
"integer|undefined")
|
||||||
list(APPEND SAN_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s")
|
list(APPEND SAN_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_TARGETS_CMAKE_)
|
if(DRACO_CMAKE_DRACO_TARGETS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_TARGETS_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_TARGETS_CMAKE_
|
||||||
|
@ -51,26 +65,33 @@ macro(draco_add_executable)
|
||||||
unset(exe_LIB_DEPS)
|
unset(exe_LIB_DEPS)
|
||||||
set(optional_args TEST)
|
set(optional_args TEST)
|
||||||
set(single_value_args NAME OUTPUT_NAME)
|
set(single_value_args NAME OUTPUT_NAME)
|
||||||
set(multi_value_args SOURCES DEFINES INCLUDES COMPILE_FLAGS LINK_FLAGS
|
set(multi_value_args
|
||||||
OBJLIB_DEPS LIB_DEPS)
|
SOURCES
|
||||||
|
DEFINES
|
||||||
|
INCLUDES
|
||||||
|
COMPILE_FLAGS
|
||||||
|
LINK_FLAGS
|
||||||
|
OBJLIB_DEPS
|
||||||
|
LIB_DEPS)
|
||||||
|
|
||||||
cmake_parse_arguments(exe "${optional_args}" "${single_value_args}"
|
cmake_parse_arguments(exe "${optional_args}" "${single_value_args}"
|
||||||
"${multi_value_args}" ${ARGN})
|
"${multi_value_args}" ${ARGN})
|
||||||
|
|
||||||
if(DRACO_VERBOSE GREATER 1)
|
if(DRACO_VERBOSE GREATER 1)
|
||||||
message("--------- draco_add_executable ---------\n"
|
message(
|
||||||
"exe_TEST=${exe_TEST}\n"
|
"--------- draco_add_executable ---------\n"
|
||||||
"exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
|
"exe_TEST=${exe_TEST}\n"
|
||||||
"exe_NAME=${exe_NAME}\n"
|
"exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
|
||||||
"exe_OUTPUT_NAME=${exe_OUTPUT_NAME}\n"
|
"exe_NAME=${exe_NAME}\n"
|
||||||
"exe_SOURCES=${exe_SOURCES}\n"
|
"exe_OUTPUT_NAME=${exe_OUTPUT_NAME}\n"
|
||||||
"exe_DEFINES=${exe_DEFINES}\n"
|
"exe_SOURCES=${exe_SOURCES}\n"
|
||||||
"exe_INCLUDES=${exe_INCLUDES}\n"
|
"exe_DEFINES=${exe_DEFINES}\n"
|
||||||
"exe_COMPILE_FLAGS=${exe_COMPILE_FLAGS}\n"
|
"exe_INCLUDES=${exe_INCLUDES}\n"
|
||||||
"exe_LINK_FLAGS=${exe_LINK_FLAGS}\n"
|
"exe_COMPILE_FLAGS=${exe_COMPILE_FLAGS}\n"
|
||||||
"exe_OBJLIB_DEPS=${exe_OBJLIB_DEPS}\n"
|
"exe_LINK_FLAGS=${exe_LINK_FLAGS}\n"
|
||||||
"exe_LIB_DEPS=${exe_LIB_DEPS}\n"
|
"exe_OBJLIB_DEPS=${exe_OBJLIB_DEPS}\n"
|
||||||
"------------------------------------------\n")
|
"exe_LIB_DEPS=${exe_LIB_DEPS}\n"
|
||||||
|
"------------------------------------------\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT (exe_NAME AND exe_SOURCES))
|
if(NOT (exe_NAME AND exe_SOURCES))
|
||||||
|
@ -87,7 +108,12 @@ macro(draco_add_executable)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(${exe_NAME} ${exe_SOURCES})
|
add_executable(${exe_NAME} ${exe_SOURCES})
|
||||||
set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
|
|
||||||
|
target_compile_features(${exe_NAME} PUBLIC cxx_std_11)
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
|
set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(exe_OUTPUT_NAME)
|
if(exe_OUTPUT_NAME)
|
||||||
set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
|
set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
|
||||||
|
@ -104,8 +130,8 @@ macro(draco_add_executable)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(exe_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
|
if(exe_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
|
||||||
target_compile_options(${exe_NAME}
|
target_compile_options(${exe_NAME} PRIVATE ${exe_COMPILE_FLAGS}
|
||||||
PRIVATE ${exe_COMPILE_FLAGS} ${DRACO_CXX_FLAGS})
|
${DRACO_CXX_FLAGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS)
|
if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS)
|
||||||
|
@ -113,8 +139,8 @@ macro(draco_add_executable)
|
||||||
list(APPEND exe_LINK_FLAGS "${DRACO_EXE_LINKER_FLAGS}")
|
list(APPEND exe_LINK_FLAGS "${DRACO_EXE_LINKER_FLAGS}")
|
||||||
# LINK_FLAGS is managed as a string.
|
# LINK_FLAGS is managed as a string.
|
||||||
draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
|
draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
|
||||||
set_target_properties(${exe_NAME}
|
set_target_properties(${exe_NAME} PROPERTIES LINK_FLAGS
|
||||||
PROPERTIES LINK_FLAGS "${exe_LINK_FLAGS}")
|
"${exe_LINK_FLAGS}")
|
||||||
else()
|
else()
|
||||||
target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
|
target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
|
||||||
${DRACO_EXE_LINKER_FLAGS})
|
${DRACO_EXE_LINKER_FLAGS})
|
||||||
|
@ -136,12 +162,7 @@ macro(draco_add_executable)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(exe_LIB_DEPS)
|
if(exe_LIB_DEPS)
|
||||||
unset(exe_static)
|
if(CMAKE_CXX_COMPILER_ID MATCHES "^Clang|^GNU")
|
||||||
if("${CMAKE_EXE_LINKER_FLAGS} ${DRACO_EXE_LINKER_FLAGS}" MATCHES "static")
|
|
||||||
set(exe_static ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(exe_static AND CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
|
||||||
# Third party dependencies can introduce dependencies on system and test
|
# Third party dependencies can introduce dependencies on system and test
|
||||||
# libraries. Since the target created here is an executable, and CMake
|
# libraries. Since the target created here is an executable, and CMake
|
||||||
# does not provide a method of controlling order of link dependencies,
|
# does not provide a method of controlling order of link dependencies,
|
||||||
|
@ -149,6 +170,10 @@ macro(draco_add_executable)
|
||||||
# ensure that dependencies of third party targets can be resolved when
|
# ensure that dependencies of third party targets can be resolved when
|
||||||
# those dependencies happen to be resolved by dependencies of the current
|
# those dependencies happen to be resolved by dependencies of the current
|
||||||
# target.
|
# target.
|
||||||
|
# TODO(tomfinegan): For portability use LINK_GROUP with RESCAN instead of
|
||||||
|
# directly (ab)using compiler/linker specific flags once CMake v3.24 is in
|
||||||
|
# wider use. See:
|
||||||
|
# https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:LINK_GROUP
|
||||||
list(INSERT exe_LIB_DEPS 0 -Wl,--start-group)
|
list(INSERT exe_LIB_DEPS 0 -Wl,--start-group)
|
||||||
list(APPEND exe_LIB_DEPS -Wl,--end-group)
|
list(APPEND exe_LIB_DEPS -Wl,--end-group)
|
||||||
endif()
|
endif()
|
||||||
|
@ -209,27 +234,36 @@ macro(draco_add_library)
|
||||||
unset(lib_TARGET_PROPERTIES)
|
unset(lib_TARGET_PROPERTIES)
|
||||||
set(optional_args TEST)
|
set(optional_args TEST)
|
||||||
set(single_value_args NAME OUTPUT_NAME TYPE)
|
set(single_value_args NAME OUTPUT_NAME TYPE)
|
||||||
set(multi_value_args SOURCES DEFINES INCLUDES COMPILE_FLAGS LINK_FLAGS
|
set(multi_value_args
|
||||||
OBJLIB_DEPS LIB_DEPS PUBLIC_INCLUDES TARGET_PROPERTIES)
|
SOURCES
|
||||||
|
DEFINES
|
||||||
|
INCLUDES
|
||||||
|
COMPILE_FLAGS
|
||||||
|
LINK_FLAGS
|
||||||
|
OBJLIB_DEPS
|
||||||
|
LIB_DEPS
|
||||||
|
PUBLIC_INCLUDES
|
||||||
|
TARGET_PROPERTIES)
|
||||||
|
|
||||||
cmake_parse_arguments(lib "${optional_args}" "${single_value_args}"
|
cmake_parse_arguments(lib "${optional_args}" "${single_value_args}"
|
||||||
"${multi_value_args}" ${ARGN})
|
"${multi_value_args}" ${ARGN})
|
||||||
|
|
||||||
if(DRACO_VERBOSE GREATER 1)
|
if(DRACO_VERBOSE GREATER 1)
|
||||||
message("--------- draco_add_library ---------\n"
|
message(
|
||||||
"lib_TEST=${lib_TEST}\n"
|
"--------- draco_add_library ---------\n"
|
||||||
"lib_NAME=${lib_NAME}\n"
|
"lib_TEST=${lib_TEST}\n"
|
||||||
"lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
|
"lib_NAME=${lib_NAME}\n"
|
||||||
"lib_TYPE=${lib_TYPE}\n"
|
"lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
|
||||||
"lib_SOURCES=${lib_SOURCES}\n"
|
"lib_TYPE=${lib_TYPE}\n"
|
||||||
"lib_DEFINES=${lib_DEFINES}\n"
|
"lib_SOURCES=${lib_SOURCES}\n"
|
||||||
"lib_INCLUDES=${lib_INCLUDES}\n"
|
"lib_DEFINES=${lib_DEFINES}\n"
|
||||||
"lib_COMPILE_FLAGS=${lib_COMPILE_FLAGS}\n"
|
"lib_INCLUDES=${lib_INCLUDES}\n"
|
||||||
"lib_LINK_FLAGS=${lib_LINK_FLAGS}\n"
|
"lib_COMPILE_FLAGS=${lib_COMPILE_FLAGS}\n"
|
||||||
"lib_OBJLIB_DEPS=${lib_OBJLIB_DEPS}\n"
|
"lib_LINK_FLAGS=${lib_LINK_FLAGS}\n"
|
||||||
"lib_LIB_DEPS=${lib_LIB_DEPS}\n"
|
"lib_OBJLIB_DEPS=${lib_OBJLIB_DEPS}\n"
|
||||||
"lib_PUBLIC_INCLUDES=${lib_PUBLIC_INCLUDES}\n"
|
"lib_LIB_DEPS=${lib_LIB_DEPS}\n"
|
||||||
"---------------------------------------\n")
|
"lib_PUBLIC_INCLUDES=${lib_PUBLIC_INCLUDES}\n"
|
||||||
|
"---------------------------------------\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT (lib_NAME AND lib_TYPE))
|
if(NOT (lib_NAME AND lib_TYPE))
|
||||||
|
@ -256,14 +290,24 @@ macro(draco_add_library)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(${lib_NAME} ${lib_TYPE} ${lib_SOURCES})
|
add_library(${lib_NAME} ${lib_TYPE} ${lib_SOURCES})
|
||||||
|
|
||||||
|
target_compile_features(${lib_NAME} PUBLIC cxx_std_11)
|
||||||
|
|
||||||
|
target_include_directories(${lib_NAME} PUBLIC $<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
|
if(BUILD_SHARED_LIBS)
|
||||||
|
# Enable PIC for all targets in shared configurations.
|
||||||
|
set_target_properties(${lib_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(lib_SOURCES)
|
if(lib_SOURCES)
|
||||||
draco_process_intrinsics_sources(TARGET ${lib_NAME} SOURCES ${lib_SOURCES})
|
draco_process_intrinsics_sources(TARGET ${lib_NAME} SOURCES ${lib_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(lib_OUTPUT_NAME)
|
if(lib_OUTPUT_NAME)
|
||||||
if(NOT (BUILD_SHARED_LIBS AND MSVC))
|
if(NOT (BUILD_SHARED_LIBS AND MSVC))
|
||||||
set_target_properties(${lib_NAME}
|
set_target_properties(${lib_NAME} PROPERTIES OUTPUT_NAME
|
||||||
PROPERTIES OUTPUT_NAME ${lib_OUTPUT_NAME})
|
${lib_OUTPUT_NAME})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -280,8 +324,8 @@ macro(draco_add_library)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(lib_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
|
if(lib_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
|
||||||
target_compile_options(${lib_NAME}
|
target_compile_options(${lib_NAME} PRIVATE ${lib_COMPILE_FLAGS}
|
||||||
PRIVATE ${lib_COMPILE_FLAGS} ${DRACO_CXX_FLAGS})
|
${DRACO_CXX_FLAGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(lib_LINK_FLAGS)
|
if(lib_LINK_FLAGS)
|
||||||
|
@ -320,11 +364,12 @@ macro(draco_add_library)
|
||||||
set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# VERSION and SOVERSION as necessary
|
if(NOT EMSCRIPTEN)
|
||||||
if(NOT lib_TYPE STREQUAL STATIC AND NOT lib_TYPE STREQUAL MODULE)
|
# VERSION and SOVERSION as necessary
|
||||||
set_target_properties(${lib_NAME} PROPERTIES VERSION ${DRACO_VERSION})
|
if((lib_TYPE STREQUAL BUNDLE OR lib_TYPE STREQUAL SHARED) AND NOT MSVC)
|
||||||
if(NOT MSVC)
|
set_target_properties(
|
||||||
set_target_properties(${lib_NAME} PROPERTIES SOVERSION ${DRACO_SOVERSION})
|
${lib_NAME} PROPERTIES VERSION ${DRACO_SOVERSION}
|
||||||
|
SOVERSION ${DRACO_SOVERSION_MAJOR})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2021 The Draco Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
#ifndef DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
#ifndef DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
||||||
#define DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
#define DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
||||||
|
|
||||||
|
@ -9,5 +23,6 @@
|
||||||
|
|
||||||
#define DRACO_TEST_DATA_DIR "${DRACO_TEST_DATA_DIR}"
|
#define DRACO_TEST_DATA_DIR "${DRACO_TEST_DATA_DIR}"
|
||||||
#define DRACO_TEST_TEMP_DIR "${DRACO_TEST_TEMP_DIR}"
|
#define DRACO_TEST_TEMP_DIR "${DRACO_TEST_TEMP_DIR}"
|
||||||
|
#define DRACO_TEST_ROOT_DIR "${DRACO_TEST_ROOT_DIR}"
|
||||||
|
|
||||||
#endif // DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
#endif // DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_TESTS_CMAKE)
|
if(DRACO_CMAKE_DRACO_TESTS_CMAKE)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
@ -10,6 +24,13 @@ set(draco_factory_test_sources
|
||||||
"${draco_src_root}/io/file_reader_factory_test.cc"
|
"${draco_src_root}/io/file_reader_factory_test.cc"
|
||||||
"${draco_src_root}/io/file_writer_factory_test.cc")
|
"${draco_src_root}/io/file_writer_factory_test.cc")
|
||||||
|
|
||||||
|
list(
|
||||||
|
APPEND draco_test_common_sources
|
||||||
|
"${draco_src_root}/core/draco_test_base.h"
|
||||||
|
"${draco_src_root}/core/draco_test_utils.cc"
|
||||||
|
"${draco_src_root}/core/draco_test_utils.h"
|
||||||
|
"${draco_src_root}/core/status.cc")
|
||||||
|
|
||||||
list(
|
list(
|
||||||
APPEND
|
APPEND
|
||||||
draco_test_sources
|
draco_test_sources
|
||||||
|
@ -30,22 +51,23 @@ list(
|
||||||
"${draco_src_root}/compression/point_cloud/point_cloud_kd_tree_encoding_test.cc"
|
"${draco_src_root}/compression/point_cloud/point_cloud_kd_tree_encoding_test.cc"
|
||||||
"${draco_src_root}/compression/point_cloud/point_cloud_sequential_encoding_test.cc"
|
"${draco_src_root}/compression/point_cloud/point_cloud_sequential_encoding_test.cc"
|
||||||
"${draco_src_root}/core/buffer_bit_coding_test.cc"
|
"${draco_src_root}/core/buffer_bit_coding_test.cc"
|
||||||
"${draco_src_root}/core/draco_test_base.h"
|
|
||||||
"${draco_src_root}/core/draco_test_utils.cc"
|
|
||||||
"${draco_src_root}/core/draco_test_utils.h"
|
|
||||||
"${draco_src_root}/core/math_utils_test.cc"
|
"${draco_src_root}/core/math_utils_test.cc"
|
||||||
"${draco_src_root}/core/quantization_utils_test.cc"
|
"${draco_src_root}/core/quantization_utils_test.cc"
|
||||||
"${draco_src_root}/core/status_test.cc"
|
"${draco_src_root}/core/status_test.cc"
|
||||||
"${draco_src_root}/core/vector_d_test.cc"
|
"${draco_src_root}/core/vector_d_test.cc"
|
||||||
"${draco_src_root}/io/file_reader_test_common.h"
|
"${draco_src_root}/io/file_reader_test_common.h"
|
||||||
"${draco_src_root}/io/file_utils_test.cc"
|
"${draco_src_root}/io/file_utils_test.cc"
|
||||||
|
"${draco_src_root}/io/file_writer_utils_test.cc"
|
||||||
"${draco_src_root}/io/stdio_file_reader_test.cc"
|
"${draco_src_root}/io/stdio_file_reader_test.cc"
|
||||||
"${draco_src_root}/io/stdio_file_writer_test.cc"
|
"${draco_src_root}/io/stdio_file_writer_test.cc"
|
||||||
"${draco_src_root}/io/obj_decoder_test.cc"
|
"${draco_src_root}/io/obj_decoder_test.cc"
|
||||||
"${draco_src_root}/io/obj_encoder_test.cc"
|
"${draco_src_root}/io/obj_encoder_test.cc"
|
||||||
"${draco_src_root}/io/ply_decoder_test.cc"
|
"${draco_src_root}/io/ply_decoder_test.cc"
|
||||||
"${draco_src_root}/io/ply_reader_test.cc"
|
"${draco_src_root}/io/ply_reader_test.cc"
|
||||||
|
"${draco_src_root}/io/stl_decoder_test.cc"
|
||||||
|
"${draco_src_root}/io/stl_encoder_test.cc"
|
||||||
"${draco_src_root}/io/point_cloud_io_test.cc"
|
"${draco_src_root}/io/point_cloud_io_test.cc"
|
||||||
|
"${draco_src_root}/mesh/corner_table_test.cc"
|
||||||
"${draco_src_root}/mesh/mesh_are_equivalent_test.cc"
|
"${draco_src_root}/mesh/mesh_are_equivalent_test.cc"
|
||||||
"${draco_src_root}/mesh/mesh_cleanup_test.cc"
|
"${draco_src_root}/mesh/mesh_cleanup_test.cc"
|
||||||
"${draco_src_root}/mesh/triangle_soup_mesh_builder_test.cc"
|
"${draco_src_root}/mesh/triangle_soup_mesh_builder_test.cc"
|
||||||
|
@ -54,47 +76,71 @@ list(
|
||||||
"${draco_src_root}/point_cloud/point_cloud_builder_test.cc"
|
"${draco_src_root}/point_cloud/point_cloud_builder_test.cc"
|
||||||
"${draco_src_root}/point_cloud/point_cloud_test.cc")
|
"${draco_src_root}/point_cloud/point_cloud_test.cc")
|
||||||
|
|
||||||
list(APPEND draco_gtest_all
|
if(DRACO_TRANSCODER_SUPPORTED)
|
||||||
"${draco_root}/../googletest/googletest/src/gtest-all.cc")
|
list(
|
||||||
list(APPEND draco_gtest_main
|
APPEND draco_test_sources
|
||||||
"${draco_root}/../googletest/googletest/src/gtest_main.cc")
|
"${draco_src_root}/animation/animation_test.cc"
|
||||||
|
"${draco_src_root}/io/gltf_decoder_test.cc"
|
||||||
|
"${draco_src_root}/io/gltf_encoder_test.cc"
|
||||||
|
"${draco_src_root}/io/gltf_utils_test.cc"
|
||||||
|
"${draco_src_root}/io/gltf_test_helper.cc"
|
||||||
|
"${draco_src_root}/io/gltf_test_helper.h"
|
||||||
|
"${draco_src_root}/io/scene_io_test.cc"
|
||||||
|
"${draco_src_root}/io/texture_io_test.cc"
|
||||||
|
"${draco_src_root}/material/material_library_test.cc"
|
||||||
|
"${draco_src_root}/material/material_test.cc"
|
||||||
|
"${draco_src_root}/metadata/property_table_test.cc"
|
||||||
|
"${draco_src_root}/metadata/structural_metadata_test.cc"
|
||||||
|
"${draco_src_root}/scene/instance_array_test.cc"
|
||||||
|
"${draco_src_root}/scene/light_test.cc"
|
||||||
|
"${draco_src_root}/scene/mesh_group_test.cc"
|
||||||
|
"${draco_src_root}/scene/scene_test.cc"
|
||||||
|
"${draco_src_root}/scene/scene_are_equivalent_test.cc"
|
||||||
|
"${draco_src_root}/scene/scene_utils_test.cc"
|
||||||
|
"${draco_src_root}/scene/trs_matrix_test.cc"
|
||||||
|
"${draco_src_root}/texture/texture_library_test.cc"
|
||||||
|
"${draco_src_root}/texture/texture_map_test.cc"
|
||||||
|
"${draco_src_root}/texture/texture_transform_test.cc")
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
macro(draco_setup_test_targets)
|
macro(draco_setup_test_targets)
|
||||||
if(DRACO_TESTS)
|
if(DRACO_TESTS)
|
||||||
|
draco_setup_googletest()
|
||||||
|
|
||||||
if(NOT (EXISTS ${draco_gtest_all} AND EXISTS ${draco_gtest_main}))
|
if(NOT (EXISTS ${draco_gtest_all} AND EXISTS ${draco_gtest_main}))
|
||||||
message(FATAL "googletest must be a sibling directory of ${draco_root}.")
|
message(FATAL_ERROR "googletest missing, run git submodule update --init")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND draco_test_defines GTEST_HAS_PTHREAD=0)
|
list(APPEND draco_test_defines GTEST_HAS_PTHREAD=0)
|
||||||
|
|
||||||
draco_add_library(TEST
|
draco_add_library(
|
||||||
NAME
|
TEST
|
||||||
draco_gtest
|
NAME draco_test_common
|
||||||
TYPE
|
TYPE STATIC
|
||||||
STATIC
|
SOURCES ${draco_test_common_sources}
|
||||||
SOURCES
|
DEFINES ${draco_defines} ${draco_test_defines}
|
||||||
${draco_gtest_all}
|
INCLUDES ${draco_test_include_paths})
|
||||||
DEFINES
|
|
||||||
${draco_defines}
|
|
||||||
${draco_test_defines}
|
|
||||||
INCLUDES
|
|
||||||
${draco_test_include_paths})
|
|
||||||
|
|
||||||
draco_add_library(TEST
|
draco_add_library(
|
||||||
NAME
|
TEST
|
||||||
draco_gtest_main
|
NAME draco_gtest
|
||||||
TYPE
|
TYPE STATIC
|
||||||
STATIC
|
SOURCES ${draco_gtest_all}
|
||||||
SOURCES
|
DEFINES ${draco_defines} ${draco_test_defines}
|
||||||
${draco_gtest_main}
|
INCLUDES ${draco_test_include_paths})
|
||||||
DEFINES
|
|
||||||
${draco_defines}
|
draco_add_library(
|
||||||
${draco_test_defines}
|
TEST
|
||||||
INCLUDES
|
NAME draco_gtest_main
|
||||||
${draco_test_include_paths})
|
TYPE STATIC
|
||||||
|
SOURCES ${draco_gtest_main}
|
||||||
|
DEFINES ${draco_defines} ${draco_test_defines}
|
||||||
|
INCLUDES ${draco_test_include_paths})
|
||||||
|
|
||||||
set(DRACO_TEST_DATA_DIR "${draco_root}/testdata")
|
set(DRACO_TEST_DATA_DIR "${draco_root}/testdata")
|
||||||
set(DRACO_TEST_TEMP_DIR "${draco_build}/draco_test_temp")
|
set(DRACO_TEST_TEMP_DIR "${draco_build}/draco_test_temp")
|
||||||
|
set(DRACO_TEST_ROOT_DIR "${draco_root}")
|
||||||
file(MAKE_DIRECTORY "${DRACO_TEST_TEMP_DIR}")
|
file(MAKE_DIRECTORY "${DRACO_TEST_TEMP_DIR}")
|
||||||
|
|
||||||
# Sets DRACO_TEST_DATA_DIR and DRACO_TEST_TEMP_DIR.
|
# Sets DRACO_TEST_DATA_DIR and DRACO_TEST_TEMP_DIR.
|
||||||
|
@ -102,32 +148,24 @@ macro(draco_setup_test_targets)
|
||||||
"${draco_build}/testing/draco_test_config.h")
|
"${draco_build}/testing/draco_test_config.h")
|
||||||
|
|
||||||
# Create the test targets.
|
# Create the test targets.
|
||||||
draco_add_executable(NAME
|
draco_add_executable(
|
||||||
draco_tests
|
TEST
|
||||||
SOURCES
|
NAME draco_tests
|
||||||
${draco_test_sources}
|
SOURCES ${draco_test_sources}
|
||||||
DEFINES
|
DEFINES ${draco_defines} ${draco_test_defines}
|
||||||
${draco_defines}
|
INCLUDES ${draco_test_include_paths}
|
||||||
${draco_test_defines}
|
LIB_DEPS ${draco_dependency} draco_gtest draco_gtest_main
|
||||||
INCLUDES
|
draco_test_common)
|
||||||
${draco_test_include_paths}
|
|
||||||
LIB_DEPS
|
draco_add_executable(
|
||||||
draco_static
|
TEST
|
||||||
draco_gtest
|
NAME draco_factory_tests
|
||||||
draco_gtest_main)
|
SOURCES ${draco_factory_test_sources}
|
||||||
|
DEFINES ${draco_defines} ${draco_test_defines}
|
||||||
|
INCLUDES ${draco_test_include_paths}
|
||||||
|
LIB_DEPS ${draco_dependency} draco_gtest draco_gtest_main
|
||||||
|
draco_test_common)
|
||||||
|
|
||||||
|
|
||||||
draco_add_executable(NAME
|
|
||||||
draco_factory_tests
|
|
||||||
SOURCES
|
|
||||||
${draco_factory_test_sources}
|
|
||||||
DEFINES
|
|
||||||
${draco_defines}
|
|
||||||
${draco_test_defines}
|
|
||||||
INCLUDES
|
|
||||||
${draco_test_include_paths}
|
|
||||||
LIB_DEPS
|
|
||||||
draco_static
|
|
||||||
draco_gtest
|
|
||||||
draco_gtest_main)
|
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_DRACO_VARIABLES_CMAKE_)
|
if(DRACO_CMAKE_DRACO_VARIABLES_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_DRACO_VARIABLES_CMAKE_
|
endif() # DRACO_CMAKE_DRACO_VARIABLES_CMAKE_
|
||||||
|
@ -14,8 +28,7 @@ macro(draco_variable_must_be_directory variable_name)
|
||||||
|
|
||||||
if("${${variable_name}}" STREQUAL "")
|
if("${${variable_name}}" STREQUAL "")
|
||||||
message(
|
message(
|
||||||
FATAL_ERROR
|
FATAL_ERROR "Empty variable ${variable_name} is required to build draco.")
|
||||||
"Empty variable ${variable_name} is required to build draco.")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT IS_DIRECTORY "${${variable_name}}")
|
if(NOT IS_DIRECTORY "${${variable_name}}")
|
||||||
|
@ -44,11 +57,13 @@ macro(draco_dump_cmake_flag_variables)
|
||||||
list(APPEND flag_variables "CMAKE_CXX_FLAGS_INIT" "CMAKE_CXX_FLAGS"
|
list(APPEND flag_variables "CMAKE_CXX_FLAGS_INIT" "CMAKE_CXX_FLAGS"
|
||||||
"CMAKE_EXE_LINKER_FLAGS_INIT" "CMAKE_EXE_LINKER_FLAGS")
|
"CMAKE_EXE_LINKER_FLAGS_INIT" "CMAKE_EXE_LINKER_FLAGS")
|
||||||
if(CMAKE_BUILD_TYPE)
|
if(CMAKE_BUILD_TYPE)
|
||||||
list(APPEND flag_variables "CMAKE_BUILD_TYPE"
|
list(
|
||||||
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
|
APPEND flag_variables
|
||||||
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}"
|
"CMAKE_BUILD_TYPE"
|
||||||
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
|
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
|
||||||
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}")
|
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}"
|
||||||
|
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
|
||||||
|
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}")
|
||||||
endif()
|
endif()
|
||||||
foreach(flag_variable ${flag_variables})
|
foreach(flag_variable ${flag_variables})
|
||||||
message("${flag_variable}:${${flag_variable}}")
|
message("${flag_variable}:${${flag_variable}}")
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
if(DRACO_CMAKE_SANITIZERS_CMAKE_)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(DRACO_CMAKE_SANITIZERS_CMAKE_ 1)
|
|
||||||
|
|
||||||
if(MSVC OR NOT SANITIZE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include("${draco_root}/cmake/compiler_flags.cmake")
|
|
||||||
|
|
||||||
string(TOLOWER ${SANITIZE} SANITIZE)
|
|
||||||
|
|
||||||
# Require the sanitizer requested.
|
|
||||||
require_linker_flag("-fsanitize=${SANITIZE}")
|
|
||||||
require_compiler_flag("-fsanitize=${SANITIZE}" YES)
|
|
||||||
|
|
||||||
# Make callstacks accurate.
|
|
||||||
require_compiler_flag("-fno-omit-frame-pointer -fno-optimize-sibling-calls" YES)
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_
|
endif() # DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ANDROID_NDK_COMMON_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ANDROID_NDK_COMMON_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_
|
endif() # DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_
|
||||||
|
@ -16,9 +30,9 @@ if(NOT ANDROID_ABI)
|
||||||
set(ANDROID_ABI arm64-v8a)
|
set(ANDROID_ABI arm64-v8a)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Force arm mode for 32-bit targets (instead of the default thumb) to improve
|
# Force arm mode for 32-bit arm targets (instead of the default thumb) to
|
||||||
# performance.
|
# improve performance.
|
||||||
if(NOT ANDROID_ARM_MODE)
|
if(ANDROID_ABI MATCHES "^armeabi" AND NOT ANDROID_ARM_MODE)
|
||||||
set(ANDROID_ARM_MODE arm)
|
set(ANDROID_ARM_MODE arm)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARM_IOS_COMMON_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARM_IOS_COMMON_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
@ -13,5 +27,3 @@ set(CMAKE_C_COMPILER clang)
|
||||||
set(CMAKE_C_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")
|
set(CMAKE_C_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")
|
||||||
set(CMAKE_CXX_COMPILER clang++)
|
set(CMAKE_CXX_COMPILER clang++)
|
||||||
set(CMAKE_CXX_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")
|
set(CMAKE_CXX_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")
|
||||||
|
|
||||||
# TODO(tomfinegan): Handle bit code embedding.
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif() # DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_
|
endif() # DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARM64_ANDROID_NDK_LIBCPP_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARM64_ANDROID_NDK_LIBCPP_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_ 1)
|
set(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_ 1)
|
||||||
|
|
||||||
if(XCODE)
|
if(XCODE)
|
||||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
|
||||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARM64_LINUX_GCC_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARM64_LINUX_GCC_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_ANDROID_NDK_LIBCPP_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_ANDROID_NDK_LIBCPP_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_ 1)
|
set(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_ 1)
|
||||||
|
|
||||||
if(XCODE)
|
if(XCODE)
|
||||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
|
||||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_LINUX_GCC_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_LINUX_GCC_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_ 1)
|
set(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_ 1)
|
||||||
|
|
||||||
if(XCODE)
|
if(XCODE)
|
||||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
|
||||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_ 1)
|
set(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_ 1)
|
||||||
|
|
||||||
if(XCODE)
|
if(XCODE)
|
||||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
|
||||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_X86_ANDROID_NDK_LIBCPP_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_X86_ANDROID_NDK_LIBCPP_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_X86_64_ANDROID_NDK_LIBCPP_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_X86_64_ANDROID_NDK_LIBCPP_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
# Copyright 2021 The Draco Authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
# use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
# the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
if(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_)
|
if(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_ 1)
|
set(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_ 1)
|
||||||
|
|
||||||
if(XCODE)
|
if(XCODE)
|
||||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
|
||||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
if(DRACO_CMAKE_UTIL_CMAKE_)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(DRACO_CMAKE_UTIL_CMAKE_ 1)
|
|
||||||
|
|
||||||
# Creates dummy source file in $draco_build_dir named $basename.$extension and
|
|
||||||
# returns the full path to the dummy source file via the $out_file_path
|
|
||||||
# parameter.
|
|
||||||
function(create_dummy_source_file basename extension out_file_path)
|
|
||||||
set(dummy_source_file "${draco_build_dir}/${basename}.${extension}")
|
|
||||||
file(WRITE "${dummy_source_file}.new"
|
|
||||||
"// Generated file. DO NOT EDIT!\n"
|
|
||||||
"// ${target_name} needs a ${extension} file to force link language, \n"
|
|
||||||
"// or to silence a harmless CMake warning: Ignore me.\n"
|
|
||||||
"void ${target_name}_dummy_function(void) {}\n")
|
|
||||||
|
|
||||||
# Will replace ${dummy_source_file} only if the file content has changed.
|
|
||||||
# This prevents forced Draco rebuilds after CMake runs.
|
|
||||||
configure_file("${dummy_source_file}.new" "${dummy_source_file}")
|
|
||||||
file(REMOVE "${dummy_source_file}.new")
|
|
||||||
|
|
||||||
set(${out_file_path} ${dummy_source_file} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Convenience function for adding a dummy source file to $target_name using
|
|
||||||
# $extension as the file extension. Wraps create_dummy_source_file().
|
|
||||||
function(add_dummy_source_file_to_target target_name extension)
|
|
||||||
create_dummy_source_file("${target_name}" "${extension}" "dummy_source_file")
|
|
||||||
target_sources(${target_name} PRIVATE ${dummy_source_file})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Extracts the version number from $version_file and returns it to the user via
|
|
||||||
# $version_string_out_var. This is achieved by finding the first instance of the
|
|
||||||
# kDracoVersion variable and then removing everything but the string literal
|
|
||||||
# assigned to the variable. Quotes and semicolon are stripped from the returned
|
|
||||||
# string.
|
|
||||||
function(extract_version_string version_file version_string_out_var)
|
|
||||||
file(STRINGS "${version_file}" draco_version REGEX "kDracoVersion")
|
|
||||||
list(GET draco_version 0 draco_version)
|
|
||||||
string(REPLACE "static const char kDracoVersion[] = " "" draco_version
|
|
||||||
"${draco_version}")
|
|
||||||
string(REPLACE ";" "" draco_version "${draco_version}")
|
|
||||||
string(REPLACE "\"" "" draco_version "${draco_version}")
|
|
||||||
set("${version_string_out_var}" "${draco_version}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Sets CMake compiler launcher to $launcher_name when $launcher_name is found in
|
|
||||||
# $PATH. Warns user about ignoring build flag $launcher_flag when $launcher_name
|
|
||||||
# is not found in $PATH.
|
|
||||||
function(set_compiler_launcher launcher_flag launcher_name)
|
|
||||||
find_program(launcher_path "${launcher_name}")
|
|
||||||
if(launcher_path)
|
|
||||||
set(CMAKE_C_COMPILER_LAUNCHER "${launcher_path}" PARENT_SCOPE)
|
|
||||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${launcher_path}" PARENT_SCOPE)
|
|
||||||
message("--- Using ${launcher_name} as compiler launcher.")
|
|
||||||
else()
|
|
||||||
message(
|
|
||||||
WARNING "--- Cannot find ${launcher_name}, ${launcher_flag} ignored.")
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Terminates CMake execution when $var_name is unset in the environment. Sets
|
|
||||||
# CMake variable to the value of the environment variable when the variable is
|
|
||||||
# present in the environment.
|
|
||||||
macro(require_variable var_name)
|
|
||||||
if("$ENV{${var_name}}" STREQUAL "")
|
|
||||||
message(FATAL_ERROR "${var_name} must be set in environment.")
|
|
||||||
endif()
|
|
||||||
set_variable_if_unset(${var_name} "")
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Sets $var_name to $default_value if not already set.
|
|
||||||
macro(set_variable_if_unset var_name default_value)
|
|
||||||
if(NOT "$ENV{${var_name}}" STREQUAL "")
|
|
||||||
set(${var_name} $ENV{${var_name}})
|
|
||||||
elseif(NOT ${var_name})
|
|
||||||
set(${var_name} ${default_value})
|
|
||||||
endif()
|
|
||||||
endmacro()
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2019 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#include "draco/animation/animation.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
void Animation::Copy(const Animation &src) {
|
||||||
|
name_ = src.name_;
|
||||||
|
channels_.clear();
|
||||||
|
for (int i = 0; i < src.NumChannels(); ++i) {
|
||||||
|
std::unique_ptr<AnimationChannel> new_channel(new AnimationChannel());
|
||||||
|
new_channel->Copy(*src.GetChannel(i));
|
||||||
|
channels_.push_back(std::move(new_channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
samplers_.clear();
|
||||||
|
for (int i = 0; i < src.NumSamplers(); ++i) {
|
||||||
|
std::unique_ptr<AnimationSampler> new_sampler(new AnimationSampler());
|
||||||
|
new_sampler->Copy(*src.GetSampler(i));
|
||||||
|
samplers_.push_back(std::move(new_sampler));
|
||||||
|
}
|
||||||
|
|
||||||
|
node_animation_data_.clear();
|
||||||
|
for (int i = 0; i < src.NumNodeAnimationData(); ++i) {
|
||||||
|
std::unique_ptr<NodeAnimationData> new_data(new NodeAnimationData());
|
||||||
|
new_data->Copy(*src.GetNodeAnimationData(i));
|
||||||
|
node_animation_data_.push_back(std::move(new_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
|
@ -0,0 +1,149 @@
|
||||||
|
// Copyright 2019 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#ifndef DRACO_ANIMATION_ANIMATION_H_
|
||||||
|
#define DRACO_ANIMATION_ANIMATION_H_
|
||||||
|
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "draco/animation/node_animation_data.h"
|
||||||
|
#include "draco/core/status.h"
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
// Struct to hold information about an animation's sampler.
|
||||||
|
struct AnimationSampler {
|
||||||
|
enum class SamplerInterpolation { LINEAR, STEP, CUBICSPLINE };
|
||||||
|
|
||||||
|
static std::string InterpolationToString(SamplerInterpolation value) {
|
||||||
|
switch (value) {
|
||||||
|
case SamplerInterpolation::STEP:
|
||||||
|
return "STEP";
|
||||||
|
case SamplerInterpolation::CUBICSPLINE:
|
||||||
|
return "CUBICSPLINE";
|
||||||
|
default:
|
||||||
|
return "LINEAR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationSampler()
|
||||||
|
: input_index(-1),
|
||||||
|
interpolation_type(SamplerInterpolation::LINEAR),
|
||||||
|
output_index(-1) {}
|
||||||
|
|
||||||
|
void Copy(const AnimationSampler &src) {
|
||||||
|
input_index = src.input_index;
|
||||||
|
interpolation_type = src.interpolation_type;
|
||||||
|
output_index = src.output_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int input_index;
|
||||||
|
SamplerInterpolation interpolation_type;
|
||||||
|
int output_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Struct to hold information about an animation's channel.
|
||||||
|
struct AnimationChannel {
|
||||||
|
enum class ChannelTransformation { TRANSLATION, ROTATION, SCALE, WEIGHTS };
|
||||||
|
|
||||||
|
static std::string TransformationToString(ChannelTransformation value) {
|
||||||
|
switch (value) {
|
||||||
|
case ChannelTransformation::ROTATION:
|
||||||
|
return "rotation";
|
||||||
|
case ChannelTransformation::SCALE:
|
||||||
|
return "scale";
|
||||||
|
case ChannelTransformation::WEIGHTS:
|
||||||
|
return "weights";
|
||||||
|
default:
|
||||||
|
return "translation";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationChannel()
|
||||||
|
: target_index(-1),
|
||||||
|
transformation_type(ChannelTransformation::TRANSLATION),
|
||||||
|
sampler_index(-1) {}
|
||||||
|
|
||||||
|
void Copy(const AnimationChannel &src) {
|
||||||
|
target_index = src.target_index;
|
||||||
|
transformation_type = src.transformation_type;
|
||||||
|
sampler_index = src.sampler_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int target_index;
|
||||||
|
ChannelTransformation transformation_type;
|
||||||
|
int sampler_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is used to hold data and information of glTF animations.
|
||||||
|
class Animation {
|
||||||
|
public:
|
||||||
|
Animation() {}
|
||||||
|
|
||||||
|
void Copy(const Animation &src);
|
||||||
|
|
||||||
|
const std::string &GetName() const { return name_; }
|
||||||
|
void SetName(const std::string &name) { name_ = name; }
|
||||||
|
|
||||||
|
// Returns the number of channels in an animation.
|
||||||
|
int NumChannels() const { return channels_.size(); }
|
||||||
|
// Returns the number of samplers in an animation.
|
||||||
|
int NumSamplers() const { return samplers_.size(); }
|
||||||
|
// Returns the number of accessors in an animation.
|
||||||
|
int NumNodeAnimationData() const { return node_animation_data_.size(); }
|
||||||
|
|
||||||
|
// Returns a channel in the animation.
|
||||||
|
AnimationChannel *GetChannel(int index) { return channels_[index].get(); }
|
||||||
|
const AnimationChannel *GetChannel(int index) const {
|
||||||
|
return channels_[index].get();
|
||||||
|
}
|
||||||
|
// Returns a sampler in the animation.
|
||||||
|
AnimationSampler *GetSampler(int index) { return samplers_[index].get(); }
|
||||||
|
const AnimationSampler *GetSampler(int index) const {
|
||||||
|
return samplers_[index].get();
|
||||||
|
}
|
||||||
|
// Returns an accessor in the animation.
|
||||||
|
NodeAnimationData *GetNodeAnimationData(int index) {
|
||||||
|
return node_animation_data_[index].get();
|
||||||
|
}
|
||||||
|
const NodeAnimationData *GetNodeAnimationData(int index) const {
|
||||||
|
return node_animation_data_[index].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddNodeAnimationData(
|
||||||
|
std::unique_ptr<NodeAnimationData> node_animation_data) {
|
||||||
|
node_animation_data_.push_back(std::move(node_animation_data));
|
||||||
|
}
|
||||||
|
void AddSampler(std::unique_ptr<AnimationSampler> sampler) {
|
||||||
|
samplers_.push_back(std::move(sampler));
|
||||||
|
}
|
||||||
|
void AddChannel(std::unique_ptr<AnimationChannel> channel) {
|
||||||
|
channels_.push_back(std::move(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
std::vector<std::unique_ptr<AnimationSampler>> samplers_;
|
||||||
|
std::vector<std::unique_ptr<AnimationChannel>> channels_;
|
||||||
|
std::vector<std::unique_ptr<NodeAnimationData>> node_animation_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#endif // DRACO_ANIMATION_ANIMATION_H_
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright 2021 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#include "draco/animation/animation.h"
|
||||||
|
|
||||||
|
#include "draco/core/draco_test_base.h"
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
TEST(AnimationTest, TestCopy) {
|
||||||
|
// Test copying of animation data.
|
||||||
|
draco::Animation src_anim;
|
||||||
|
ASSERT_TRUE(src_anim.GetName().empty());
|
||||||
|
src_anim.SetName("Walking");
|
||||||
|
ASSERT_EQ(src_anim.GetName(), "Walking");
|
||||||
|
|
||||||
|
std::unique_ptr<draco::AnimationSampler> src_sampler_0(
|
||||||
|
new draco::AnimationSampler());
|
||||||
|
src_sampler_0->interpolation_type =
|
||||||
|
draco::AnimationSampler::SamplerInterpolation::CUBICSPLINE;
|
||||||
|
std::unique_ptr<draco::AnimationSampler> src_sampler_1(
|
||||||
|
new draco::AnimationSampler());
|
||||||
|
src_sampler_1->Copy(*src_sampler_0);
|
||||||
|
|
||||||
|
ASSERT_EQ(src_sampler_0->interpolation_type,
|
||||||
|
src_sampler_1->interpolation_type);
|
||||||
|
|
||||||
|
src_sampler_1->interpolation_type =
|
||||||
|
draco::AnimationSampler::SamplerInterpolation::STEP;
|
||||||
|
|
||||||
|
src_anim.AddSampler(std::move(src_sampler_0));
|
||||||
|
src_anim.AddSampler(std::move(src_sampler_1));
|
||||||
|
ASSERT_EQ(src_anim.NumSamplers(), 2);
|
||||||
|
|
||||||
|
std::unique_ptr<draco::AnimationChannel> src_channel(
|
||||||
|
new draco::AnimationChannel());
|
||||||
|
src_channel->transformation_type =
|
||||||
|
draco::AnimationChannel::ChannelTransformation::WEIGHTS;
|
||||||
|
src_anim.AddChannel(std::move(src_channel));
|
||||||
|
ASSERT_EQ(src_anim.NumChannels(), 1);
|
||||||
|
|
||||||
|
draco::Animation dst_anim;
|
||||||
|
dst_anim.Copy(src_anim);
|
||||||
|
|
||||||
|
ASSERT_EQ(dst_anim.GetName(), src_anim.GetName());
|
||||||
|
ASSERT_EQ(dst_anim.NumSamplers(), 2);
|
||||||
|
ASSERT_EQ(dst_anim.NumChannels(), 1);
|
||||||
|
|
||||||
|
ASSERT_EQ(dst_anim.GetSampler(0)->interpolation_type,
|
||||||
|
src_anim.GetSampler(0)->interpolation_type);
|
||||||
|
ASSERT_EQ(dst_anim.GetSampler(1)->interpolation_type,
|
||||||
|
src_anim.GetSampler(1)->interpolation_type);
|
||||||
|
ASSERT_EQ(dst_anim.GetChannel(0)->transformation_type,
|
||||||
|
src_anim.GetChannel(0)->transformation_type);
|
||||||
|
}
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
} // namespace
|
|
@ -26,8 +26,9 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
||||||
|
|
||||||
bool CreateAndAddTimestamps(int32_t num_frames) {
|
bool CreateAndAddTimestamps(int32_t num_frames) {
|
||||||
timestamps_.resize(num_frames);
|
timestamps_.resize(num_frames);
|
||||||
for (int i = 0; i < timestamps_.size(); ++i)
|
for (int i = 0; i < timestamps_.size(); ++i) {
|
||||||
timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
|
timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
|
||||||
|
}
|
||||||
return keyframe_animation_.SetTimestamps(timestamps_);
|
return keyframe_animation_.SetTimestamps(timestamps_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +36,9 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
||||||
uint32_t num_components) {
|
uint32_t num_components) {
|
||||||
// Create and add animation data with.
|
// Create and add animation data with.
|
||||||
animation_data_.resize(num_frames * num_components);
|
animation_data_.resize(num_frames * num_components);
|
||||||
for (int i = 0; i < animation_data_.size(); ++i)
|
for (int i = 0; i < animation_data_.size(); ++i) {
|
||||||
animation_data_[i] = static_cast<float>(i);
|
animation_data_[i] = static_cast<float>(i);
|
||||||
|
}
|
||||||
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
|
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
|
||||||
animation_data_);
|
animation_data_);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +51,7 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
||||||
ASSERT_EQ(animation0.num_animations(), animation1.num_animations());
|
ASSERT_EQ(animation0.num_animations(), animation1.num_animations());
|
||||||
|
|
||||||
if (quantized) {
|
if (quantized) {
|
||||||
// TODO(hemmer) : Add test for stable quantization.
|
// TODO(b/199760123) : Add test for stable quantization.
|
||||||
// Quantization will result in slightly different values.
|
// Quantization will result in slightly different values.
|
||||||
// Skip comparing values.
|
// Skip comparing values.
|
||||||
return;
|
return;
|
||||||
|
@ -109,9 +111,8 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_TRUE(
|
DRACO_ASSERT_OK(
|
||||||
encoder.EncodeKeyframeAnimation(keyframe_animation_, options, &buffer)
|
encoder.EncodeKeyframeAnimation(keyframe_animation_, options, &buffer));
|
||||||
.ok());
|
|
||||||
|
|
||||||
draco::DecoderBuffer dec_decoder;
|
draco::DecoderBuffer dec_decoder;
|
||||||
draco::KeyframeAnimationDecoder decoder;
|
draco::KeyframeAnimationDecoder decoder;
|
||||||
|
@ -122,8 +123,8 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
||||||
std::unique_ptr<KeyframeAnimation> decoded_animation(
|
std::unique_ptr<KeyframeAnimation> decoded_animation(
|
||||||
new KeyframeAnimation());
|
new KeyframeAnimation());
|
||||||
DecoderOptions dec_options;
|
DecoderOptions dec_options;
|
||||||
ASSERT_TRUE(
|
DRACO_ASSERT_OK(
|
||||||
decoder.Decode(dec_options, &dec_buffer, decoded_animation.get()).ok());
|
decoder.Decode(dec_options, &dec_buffer, decoded_animation.get()));
|
||||||
|
|
||||||
// Verify if animation before and after compression is identical.
|
// Verify if animation before and after compression is identical.
|
||||||
CompareAnimationData<num_components_t>(keyframe_animation_,
|
CompareAnimationData<num_components_t>(keyframe_animation_,
|
||||||
|
|
|
@ -24,8 +24,9 @@ class KeyframeAnimationTest : public ::testing::Test {
|
||||||
|
|
||||||
bool CreateAndAddTimestamps(int32_t num_frames) {
|
bool CreateAndAddTimestamps(int32_t num_frames) {
|
||||||
timestamps_.resize(num_frames);
|
timestamps_.resize(num_frames);
|
||||||
for (int i = 0; i < timestamps_.size(); ++i)
|
for (int i = 0; i < timestamps_.size(); ++i) {
|
||||||
timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
|
timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
|
||||||
|
}
|
||||||
return keyframe_animation_.SetTimestamps(timestamps_);
|
return keyframe_animation_.SetTimestamps(timestamps_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +34,9 @@ class KeyframeAnimationTest : public ::testing::Test {
|
||||||
uint32_t num_components) {
|
uint32_t num_components) {
|
||||||
// Create and add animation data with.
|
// Create and add animation data with.
|
||||||
animation_data_.resize(num_frames * num_components);
|
animation_data_.resize(num_frames * num_components);
|
||||||
for (int i = 0; i < animation_data_.size(); ++i)
|
for (int i = 0; i < animation_data_.size(); ++i) {
|
||||||
animation_data_[i] = static_cast<float>(i);
|
animation_data_[i] = static_cast<float>(i);
|
||||||
|
}
|
||||||
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
|
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
|
||||||
animation_data_);
|
animation_data_);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright 2019 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#ifndef DRACO_ANIMATION_NODE_ANIMATION_DATA_H_
|
||||||
|
#define DRACO_ANIMATION_NODE_ANIMATION_DATA_H_
|
||||||
|
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
#include "draco/core/hash_utils.h"
|
||||||
|
#include "draco/core/status.h"
|
||||||
|
#include "draco/core/status_or.h"
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
// This class is used to store information and data for animations that only
|
||||||
|
// affect the nodes.
|
||||||
|
// TODO(fgalligan): Think about changing the name of this class now that Skin
|
||||||
|
// is using it.
|
||||||
|
class NodeAnimationData {
|
||||||
|
public:
|
||||||
|
enum class Type { SCALAR, VEC3, VEC4, MAT4 };
|
||||||
|
|
||||||
|
NodeAnimationData() : type_(Type::SCALAR), count_(0), normalized_(false) {}
|
||||||
|
|
||||||
|
void Copy(const NodeAnimationData &src) {
|
||||||
|
type_ = src.type_;
|
||||||
|
count_ = src.count_;
|
||||||
|
normalized_ = src.normalized_;
|
||||||
|
data_ = src.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type() const { return type_; }
|
||||||
|
int count() const { return count_; }
|
||||||
|
bool normalized() const { return normalized_; }
|
||||||
|
|
||||||
|
std::vector<float> *GetMutableData() { return &data_; }
|
||||||
|
const std::vector<float> *GetData() const { return &data_; }
|
||||||
|
|
||||||
|
void SetType(Type type) { type_ = type; }
|
||||||
|
void SetCount(int count) { count_ = count; }
|
||||||
|
void SetNormalized(bool normalized) { normalized_ = normalized; }
|
||||||
|
|
||||||
|
int ComponentSize() const { return sizeof(float); }
|
||||||
|
int NumComponents() const {
|
||||||
|
switch (type_) {
|
||||||
|
case Type::SCALAR:
|
||||||
|
return 1;
|
||||||
|
case Type::VEC3:
|
||||||
|
return 3;
|
||||||
|
case Type::MAT4:
|
||||||
|
return 16;
|
||||||
|
default:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TypeAsString() const {
|
||||||
|
switch (type_) {
|
||||||
|
case Type::SCALAR:
|
||||||
|
return "SCALAR";
|
||||||
|
case Type::VEC3:
|
||||||
|
return "VEC3";
|
||||||
|
case Type::MAT4:
|
||||||
|
return "MAT4";
|
||||||
|
default:
|
||||||
|
return "VEC4";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const NodeAnimationData &nad) const {
|
||||||
|
return type_ == nad.type_ && count_ == nad.count_ &&
|
||||||
|
normalized_ == nad.normalized_ && data_ == nad.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type type_;
|
||||||
|
int count_;
|
||||||
|
bool normalized_;
|
||||||
|
std::vector<float> data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrapper class for hashing NodeAnimationData. When using different containers,
|
||||||
|
// this class is preferable instead of copying the data in NodeAnimationData
|
||||||
|
// every time.
|
||||||
|
class NodeAnimationDataHash {
|
||||||
|
public:
|
||||||
|
NodeAnimationDataHash() = delete;
|
||||||
|
NodeAnimationDataHash &operator=(const NodeAnimationDataHash &) = delete;
|
||||||
|
NodeAnimationDataHash(NodeAnimationDataHash &&) = delete;
|
||||||
|
NodeAnimationDataHash &operator=(NodeAnimationDataHash &&) = delete;
|
||||||
|
|
||||||
|
explicit NodeAnimationDataHash(const NodeAnimationData *nad)
|
||||||
|
: node_animation_data_(nad) {
|
||||||
|
hash_ = NodeAnimationDataHash::HashNodeAnimationData(*node_animation_data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeAnimationDataHash(const NodeAnimationDataHash &nadh) {
|
||||||
|
node_animation_data_ = nadh.node_animation_data_;
|
||||||
|
hash_ = nadh.hash_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const NodeAnimationDataHash &nadh) const {
|
||||||
|
return *node_animation_data_ == *nadh.node_animation_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Hash {
|
||||||
|
size_t operator()(const NodeAnimationDataHash &nadh) const {
|
||||||
|
return nadh.hash_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const NodeAnimationData *GetNodeAnimationData() {
|
||||||
|
return node_animation_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Returns a hash of |nad|.
|
||||||
|
static size_t HashNodeAnimationData(const NodeAnimationData &nad) {
|
||||||
|
size_t hash = 79; // Magic number.
|
||||||
|
hash = HashCombine(static_cast<int>(nad.type()), hash);
|
||||||
|
hash = HashCombine(nad.count(), hash);
|
||||||
|
hash = HashCombine(nad.normalized(), hash);
|
||||||
|
const uint64_t data_hash =
|
||||||
|
FingerprintString(reinterpret_cast<const char *>(nad.GetData()->data()),
|
||||||
|
nad.GetData()->size() * sizeof(float));
|
||||||
|
hash = HashCombine(data_hash, hash);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NodeAnimationData *node_animation_data_;
|
||||||
|
size_t hash_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#endif // DRACO_ANIMATION_NODE_ANIMATION_DATA_H_
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2019 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#include "draco/animation/skin.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
void Skin::Copy(const Skin &s) {
|
||||||
|
inverse_bind_matrices_.Copy(s.GetInverseBindMatrices());
|
||||||
|
joints_ = s.GetJoints();
|
||||||
|
joint_root_index_ = s.GetJointRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright 2019 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#ifndef DRACO_ANIMATION_SKIN_H_
|
||||||
|
#define DRACO_ANIMATION_SKIN_H_
|
||||||
|
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "draco/animation/node_animation_data.h"
|
||||||
|
#include "draco/scene/scene_indices.h"
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
// This class is used to store information on animation skins.
|
||||||
|
class Skin {
|
||||||
|
public:
|
||||||
|
Skin() : joint_root_index_(-1) {}
|
||||||
|
|
||||||
|
void Copy(const Skin &s);
|
||||||
|
|
||||||
|
NodeAnimationData &GetInverseBindMatrices() { return inverse_bind_matrices_; }
|
||||||
|
const NodeAnimationData &GetInverseBindMatrices() const {
|
||||||
|
return inverse_bind_matrices_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AddJoint(SceneNodeIndex index) {
|
||||||
|
joints_.push_back(index);
|
||||||
|
return joints_.size() - 1;
|
||||||
|
}
|
||||||
|
int NumJoints() const { return joints_.size(); }
|
||||||
|
SceneNodeIndex GetJoint(int index) const { return joints_[index]; }
|
||||||
|
SceneNodeIndex &GetJoint(int index) { return joints_[index]; }
|
||||||
|
const std::vector<SceneNodeIndex> &GetJoints() const { return joints_; }
|
||||||
|
|
||||||
|
void SetJointRoot(SceneNodeIndex index) { joint_root_index_ = index; }
|
||||||
|
SceneNodeIndex GetJointRoot() const { return joint_root_index_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeAnimationData inverse_bind_matrices_;
|
||||||
|
|
||||||
|
// List of node indices that make up the joint hierarchy.
|
||||||
|
std::vector<SceneNodeIndex> joints_;
|
||||||
|
SceneNodeIndex joint_root_index_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#endif // DRACO_ANIMATION_SKIN_H_
|
|
@ -28,12 +28,13 @@ std::unique_ptr<PointAttribute> AttributeTransform::InitTransformedAttribute(
|
||||||
const PointAttribute &src_attribute, int num_entries) {
|
const PointAttribute &src_attribute, int num_entries) {
|
||||||
const int num_components = GetTransformedNumComponents(src_attribute);
|
const int num_components = GetTransformedNumComponents(src_attribute);
|
||||||
const DataType dt = GetTransformedDataType(src_attribute);
|
const DataType dt = GetTransformedDataType(src_attribute);
|
||||||
GeometryAttribute va;
|
GeometryAttribute ga;
|
||||||
va.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
|
ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
|
||||||
num_components * DataTypeLength(dt), 0);
|
num_components * DataTypeLength(dt), 0);
|
||||||
std::unique_ptr<PointAttribute> transformed_attribute(new PointAttribute(va));
|
std::unique_ptr<PointAttribute> transformed_attribute(new PointAttribute(ga));
|
||||||
transformed_attribute->Reset(num_entries);
|
transformed_attribute->Reset(num_entries);
|
||||||
transformed_attribute->SetIdentityMapping();
|
transformed_attribute->SetIdentityMapping();
|
||||||
|
transformed_attribute->set_unique_id(src_attribute.unique_id());
|
||||||
return transformed_attribute;
|
return transformed_attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ GeometryAttribute::GeometryAttribute()
|
||||||
unique_id_(0) {}
|
unique_id_(0) {}
|
||||||
|
|
||||||
void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
|
void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
|
||||||
DataBuffer *buffer, int8_t num_components,
|
DataBuffer *buffer, uint8_t num_components,
|
||||||
DataType data_type, bool normalized,
|
DataType data_type, bool normalized,
|
||||||
int64_t byte_stride, int64_t byte_offset) {
|
int64_t byte_stride, int64_t byte_offset) {
|
||||||
buffer_ = buffer;
|
buffer_ = buffer;
|
||||||
|
|
|
@ -15,12 +15,18 @@
|
||||||
#ifndef DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
|
#ifndef DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
|
||||||
#define DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
|
#define DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "draco/attributes/geometry_indices.h"
|
#include "draco/attributes/geometry_indices.h"
|
||||||
#include "draco/core/data_buffer.h"
|
#include "draco/core/data_buffer.h"
|
||||||
#include "draco/core/hash_utils.h"
|
#include "draco/core/hash_utils.h"
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#include "draco/core/status.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
|
||||||
|
@ -51,6 +57,16 @@ class GeometryAttribute {
|
||||||
// predefined use case. Such attributes are often used for a shader specific
|
// predefined use case. Such attributes are often used for a shader specific
|
||||||
// data.
|
// data.
|
||||||
GENERIC,
|
GENERIC,
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// TODO(ostava): Adding a new attribute would be bit-stream change for GLTF.
|
||||||
|
// Older decoders wouldn't know what to do with this attribute type. This
|
||||||
|
// should be open-sourced only when we are ready to increase our bit-stream
|
||||||
|
// version.
|
||||||
|
TANGENT,
|
||||||
|
MATERIAL,
|
||||||
|
JOINTS,
|
||||||
|
WEIGHTS,
|
||||||
|
#endif
|
||||||
// Total number of different attribute types.
|
// Total number of different attribute types.
|
||||||
// Always keep behind all named attributes.
|
// Always keep behind all named attributes.
|
||||||
NAMED_ATTRIBUTES_COUNT,
|
NAMED_ATTRIBUTES_COUNT,
|
||||||
|
@ -58,7 +74,7 @@ class GeometryAttribute {
|
||||||
|
|
||||||
GeometryAttribute();
|
GeometryAttribute();
|
||||||
// Initializes and enables the attribute.
|
// Initializes and enables the attribute.
|
||||||
void Init(Type attribute_type, DataBuffer *buffer, int8_t num_components,
|
void Init(Type attribute_type, DataBuffer *buffer, uint8_t num_components,
|
||||||
DataType data_type, bool normalized, int64_t byte_stride,
|
DataType data_type, bool normalized, int64_t byte_stride,
|
||||||
int64_t byte_offset);
|
int64_t byte_offset);
|
||||||
bool IsValid() const { return buffer_ != nullptr; }
|
bool IsValid() const { return buffer_ != nullptr; }
|
||||||
|
@ -129,6 +145,17 @@ class GeometryAttribute {
|
||||||
buffer_->Write(byte_pos, value, byte_stride());
|
buffer_->Write(byte_pos, value, byte_stride());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// Sets a value of an attribute entry. The input |value| must have
|
||||||
|
// |input_num_components| entries and it will be automatically converted to
|
||||||
|
// the internal format used by the geometry attribute. If the conversion is
|
||||||
|
// not possible, an error status will be returned.
|
||||||
|
template <typename InputT>
|
||||||
|
Status ConvertAndSetAttributeValue(AttributeValueIndex avi,
|
||||||
|
int input_num_components,
|
||||||
|
const InputT *value);
|
||||||
|
#endif
|
||||||
|
|
||||||
// DEPRECATED: Use
|
// DEPRECATED: Use
|
||||||
// ConvertValue(AttributeValueIndex att_id,
|
// ConvertValue(AttributeValueIndex att_id,
|
||||||
// int out_num_components,
|
// int out_num_components,
|
||||||
|
@ -233,10 +260,11 @@ class GeometryAttribute {
|
||||||
// Returns the number of components that are stored for each entry.
|
// Returns the number of components that are stored for each entry.
|
||||||
// For position attribute this is usually three (x,y,z),
|
// For position attribute this is usually three (x,y,z),
|
||||||
// while texture coordinates have two components (u,v).
|
// while texture coordinates have two components (u,v).
|
||||||
int8_t num_components() const { return num_components_; }
|
uint8_t num_components() const { return num_components_; }
|
||||||
// Indicates whether the data type should be normalized before interpretation,
|
// Indicates whether the data type should be normalized before interpretation,
|
||||||
// that is, it should be divided by the max value of the data type.
|
// that is, it should be divided by the max value of the data type.
|
||||||
bool normalized() const { return normalized_; }
|
bool normalized() const { return normalized_; }
|
||||||
|
void set_normalized(bool normalized) { normalized_ = normalized; }
|
||||||
// The buffer storing the entire data of the attribute.
|
// The buffer storing the entire data of the attribute.
|
||||||
const DataBuffer *buffer() const { return buffer_; }
|
const DataBuffer *buffer() const { return buffer_; }
|
||||||
// Returns the number of bytes between two attribute entries, this is, at
|
// Returns the number of bytes between two attribute entries, this is, at
|
||||||
|
@ -260,7 +288,7 @@ class GeometryAttribute {
|
||||||
// T is the stored attribute data type.
|
// T is the stored attribute data type.
|
||||||
// OutT is the desired data type of the attribute.
|
// OutT is the desired data type of the attribute.
|
||||||
template <typename T, typename OutT>
|
template <typename T, typename OutT>
|
||||||
bool ConvertTypedValue(AttributeValueIndex att_id, int8_t out_num_components,
|
bool ConvertTypedValue(AttributeValueIndex att_id, uint8_t out_num_components,
|
||||||
OutT *out_value) const {
|
OutT *out_value) const {
|
||||||
const uint8_t *src_address = GetAddress(att_id);
|
const uint8_t *src_address = GetAddress(att_id);
|
||||||
|
|
||||||
|
@ -270,29 +298,10 @@ class GeometryAttribute {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const T in_value = *reinterpret_cast<const T *>(src_address);
|
const T in_value = *reinterpret_cast<const T *>(src_address);
|
||||||
|
if (!ConvertComponentValue<T, OutT>(in_value, normalized_,
|
||||||
// Make sure the in_value fits within the range of values that OutT
|
out_value + i)) {
|
||||||
// is able to represent. Perform the check only for integral types.
|
return false;
|
||||||
if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
|
|
||||||
static constexpr OutT kOutMin =
|
|
||||||
std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
|
|
||||||
if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out_value[i] = static_cast<OutT>(in_value);
|
|
||||||
// When converting integer to floating point, normalize the value if
|
|
||||||
// necessary.
|
|
||||||
if (std::is_integral<T>::value && std::is_floating_point<OutT>::value &&
|
|
||||||
normalized_) {
|
|
||||||
out_value[i] /= static_cast<OutT>(std::numeric_limits<T>::max());
|
|
||||||
}
|
|
||||||
// TODO(ostava): Add handling of normalized attributes when converting
|
|
||||||
// between different integer representations. If the attribute is
|
|
||||||
// normalized, integer values should be converted as if they represent 0-1
|
|
||||||
// range. E.g. when we convert uint16 to uint8, the range <0, 2^16 - 1>
|
|
||||||
// should be converted to range <0, 2^8 - 1>.
|
|
||||||
src_address += sizeof(T);
|
src_address += sizeof(T);
|
||||||
}
|
}
|
||||||
// Fill empty data for unused output components if needed.
|
// Fill empty data for unused output components if needed.
|
||||||
|
@ -302,12 +311,128 @@ class GeometryAttribute {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// Function that converts input |value| from type T to the internal attribute
|
||||||
|
// representation defined by OutT and |num_components_|.
|
||||||
|
template <typename T, typename OutT>
|
||||||
|
Status ConvertAndSetAttributeTypedValue(AttributeValueIndex avi,
|
||||||
|
int8_t input_num_components,
|
||||||
|
const T *value) {
|
||||||
|
uint8_t *address = GetAddress(avi);
|
||||||
|
|
||||||
|
// Convert all components available in both the original and output formats.
|
||||||
|
for (int i = 0; i < num_components_; ++i) {
|
||||||
|
if (!IsAddressValid(address)) {
|
||||||
|
return ErrorStatus("GeometryAttribute: Invalid address.");
|
||||||
|
}
|
||||||
|
OutT *const out_value = reinterpret_cast<OutT *>(address);
|
||||||
|
if (i < input_num_components) {
|
||||||
|
if (!ConvertComponentValue<T, OutT>(*(value + i), normalized_,
|
||||||
|
out_value)) {
|
||||||
|
return ErrorStatus(
|
||||||
|
"GeometryAttribute: Failed to convert component value.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*out_value = static_cast<OutT>(0);
|
||||||
|
}
|
||||||
|
address += sizeof(OutT);
|
||||||
|
}
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
// Converts |in_value| of type T into |out_value| of type OutT. If
|
||||||
|
// |normalized| is true, any conversion between floating point and integer
|
||||||
|
// values will be treating integers as normalized types (the entire integer
|
||||||
|
// range will be used to represent 0-1 floating point range).
|
||||||
|
template <typename T, typename OutT>
|
||||||
|
static bool ConvertComponentValue(const T &in_value, bool normalized,
|
||||||
|
OutT *out_value) {
|
||||||
|
// Make sure the |in_value| can be represented as an integral type OutT.
|
||||||
|
if (std::is_integral<OutT>::value) {
|
||||||
|
// Make sure the |in_value| fits within the range of values that OutT
|
||||||
|
// is able to represent. Perform the check only for integral types.
|
||||||
|
if (!std::is_same<T, bool>::value && std::is_integral<T>::value) {
|
||||||
|
static constexpr OutT kOutMin =
|
||||||
|
std::is_signed<T>::value ? std::numeric_limits<OutT>::min() : 0;
|
||||||
|
if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check conversion of floating point |in_value| to integral value OutT.
|
||||||
|
if (std::is_floating_point<T>::value) {
|
||||||
|
// Make sure the floating point |in_value| is not NaN and not Inf as
|
||||||
|
// integral type OutT is unable to represent these values.
|
||||||
|
if (sizeof(in_value) > sizeof(double)) {
|
||||||
|
if (std::isnan(static_cast<long double>(in_value)) ||
|
||||||
|
std::isinf(static_cast<long double>(in_value))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (sizeof(in_value) > sizeof(float)) {
|
||||||
|
if (std::isnan(static_cast<double>(in_value)) ||
|
||||||
|
std::isinf(static_cast<double>(in_value))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (std::isnan(static_cast<float>(in_value)) ||
|
||||||
|
std::isinf(static_cast<float>(in_value))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the floating point |in_value| fits within the range of
|
||||||
|
// values that integral type OutT is able to represent.
|
||||||
|
if (in_value < std::numeric_limits<OutT>::min() ||
|
||||||
|
in_value >= std::numeric_limits<OutT>::max()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::is_integral<T>::value && std::is_floating_point<OutT>::value &&
|
||||||
|
normalized) {
|
||||||
|
// When converting integer to floating point, normalize the value if
|
||||||
|
// necessary.
|
||||||
|
*out_value = static_cast<OutT>(in_value);
|
||||||
|
*out_value /= static_cast<OutT>(std::numeric_limits<T>::max());
|
||||||
|
} else if (std::is_floating_point<T>::value &&
|
||||||
|
std::is_integral<OutT>::value && normalized) {
|
||||||
|
// Converting from floating point to a normalized integer.
|
||||||
|
if (in_value > 1 || in_value < 0) {
|
||||||
|
// Normalized float values need to be between 0 and 1.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO(ostava): Consider allowing float to normalized integer conversion
|
||||||
|
// for 64-bit integer types. Currently it doesn't work because we don't
|
||||||
|
// have a floating point type that could store all 64 bit integers.
|
||||||
|
if (sizeof(OutT) > 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Expand the float to the range of the output integer and round it to the
|
||||||
|
// nearest representable value. Use doubles for the math to ensure the
|
||||||
|
// integer values are represented properly during the conversion process.
|
||||||
|
*out_value = static_cast<OutT>(std::floor(
|
||||||
|
in_value * static_cast<double>(std::numeric_limits<OutT>::max()) +
|
||||||
|
0.5));
|
||||||
|
} else {
|
||||||
|
*out_value = static_cast<OutT>(in_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ostava): Add handling of normalized attributes when converting
|
||||||
|
// between different integer representations. If the attribute is
|
||||||
|
// normalized, integer values should be converted as if they represent 0-1
|
||||||
|
// range. E.g. when we convert uint16 to uint8, the range <0, 2^16 - 1>
|
||||||
|
// should be converted to range <0, 2^8 - 1>.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DataBuffer *buffer_;
|
DataBuffer *buffer_;
|
||||||
// The buffer descriptor is stored at the time the buffer is attached to this
|
// The buffer descriptor is stored at the time the buffer is attached to this
|
||||||
// attribute. The purpose is to detect if any changes happened to the buffer
|
// attribute. The purpose is to detect if any changes happened to the buffer
|
||||||
// since the time it was attached.
|
// since the time it was attached.
|
||||||
DataBufferDescriptor buffer_descriptor_;
|
DataBufferDescriptor buffer_descriptor_;
|
||||||
int8_t num_components_;
|
uint8_t num_components_;
|
||||||
DataType data_type_;
|
DataType data_type_;
|
||||||
bool normalized_;
|
bool normalized_;
|
||||||
int64_t byte_stride_;
|
int64_t byte_stride_;
|
||||||
|
@ -323,6 +448,54 @@ class GeometryAttribute {
|
||||||
friend struct GeometryAttributeHasher;
|
friend struct GeometryAttributeHasher;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
template <typename InputT>
|
||||||
|
Status GeometryAttribute::ConvertAndSetAttributeValue(AttributeValueIndex avi,
|
||||||
|
int input_num_components,
|
||||||
|
const InputT *value) {
|
||||||
|
switch (this->data_type()) {
|
||||||
|
case DT_INT8:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, int8_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_UINT8:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, uint8_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_INT16:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, int16_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_UINT16:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, uint16_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_INT32:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, int32_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_UINT32:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, uint32_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_INT64:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, int64_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_UINT64:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, uint64_t>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_FLOAT32:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, float>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_FLOAT64:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, double>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
case DT_BOOL:
|
||||||
|
return ConvertAndSetAttributeTypedValue<InputT, bool>(
|
||||||
|
avi, input_num_components, value);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ErrorStatus(
|
||||||
|
"GeometryAttribute::SetAndConvertAttributeValue: Unsupported "
|
||||||
|
"attribute type.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Hashing support
|
// Hashing support
|
||||||
|
|
||||||
// Function object for using Attribute as a hash key.
|
// Function object for using Attribute as a hash key.
|
||||||
|
|
|
@ -222,4 +222,47 @@ AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
void PointAttribute::RemoveUnusedValues() {
|
||||||
|
if (is_mapping_identity()) {
|
||||||
|
return; // For identity mapping, all values are always used.
|
||||||
|
}
|
||||||
|
// For explicit mapping we need to check if any point is mapped to a value.
|
||||||
|
// If not we can delete the value.
|
||||||
|
IndexTypeVector<AttributeValueIndex, bool> is_value_used(size(), false);
|
||||||
|
int num_used_values = 0;
|
||||||
|
for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
|
||||||
|
const AttributeValueIndex avi = indices_map_[pi];
|
||||||
|
if (!is_value_used[avi]) {
|
||||||
|
is_value_used[avi] = true;
|
||||||
|
num_used_values++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_used_values == size()) {
|
||||||
|
return; // All values are used.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap the values and update the point to value mapping.
|
||||||
|
IndexTypeVector<AttributeValueIndex, AttributeValueIndex>
|
||||||
|
old_to_new_value_map(size(), kInvalidAttributeValueIndex);
|
||||||
|
AttributeValueIndex new_avi(0);
|
||||||
|
for (AttributeValueIndex avi(0); avi < size(); ++avi) {
|
||||||
|
if (!is_value_used[avi]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (avi != new_avi) {
|
||||||
|
SetAttributeValue(new_avi, GetAddress(avi));
|
||||||
|
}
|
||||||
|
old_to_new_value_map[avi] = new_avi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap all points to the new attribute values.
|
||||||
|
for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
|
||||||
|
indices_map_[pi] = old_to_new_value_map[indices_map_[pi]];
|
||||||
|
}
|
||||||
|
|
||||||
|
num_unique_entries_ = num_used_values;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
|
|
@ -133,6 +133,12 @@ class PointAttribute : public GeometryAttribute {
|
||||||
return attribute_transform_data_.get();
|
return attribute_transform_data_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// Removes unused values from the attribute. Value is unused when no point
|
||||||
|
// is mapped to the value. Only applicable when the mapping is not identity.
|
||||||
|
void RemoveUnusedValues();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
|
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -15,14 +15,16 @@
|
||||||
#include "draco/compression/attributes/attributes_encoder.h"
|
#include "draco/compression/attributes/attributes_encoder.h"
|
||||||
|
|
||||||
#include "draco/core/varint_encoding.h"
|
#include "draco/core/varint_encoding.h"
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
|
||||||
AttributesEncoder::AttributesEncoder()
|
AttributesEncoder::AttributesEncoder()
|
||||||
: point_cloud_encoder_(nullptr), point_cloud_(nullptr) {}
|
: point_cloud_encoder_(nullptr), point_cloud_(nullptr) {}
|
||||||
|
|
||||||
AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() {
|
AttributesEncoder::AttributesEncoder(int point_attrib_id)
|
||||||
AddAttributeId(att_id);
|
: AttributesEncoder() {
|
||||||
|
AddAttributeId(point_attrib_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) {
|
bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) {
|
||||||
|
@ -37,7 +39,15 @@ bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) {
|
||||||
for (uint32_t i = 0; i < num_attributes(); ++i) {
|
for (uint32_t i = 0; i < num_attributes(); ++i) {
|
||||||
const int32_t att_id = point_attribute_ids_[i];
|
const int32_t att_id = point_attribute_ids_[i];
|
||||||
const PointAttribute *const pa = point_cloud_->attribute(att_id);
|
const PointAttribute *const pa = point_cloud_->attribute(att_id);
|
||||||
out_buffer->Encode(static_cast<uint8_t>(pa->attribute_type()));
|
GeometryAttribute::Type type = pa->attribute_type();
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// Attribute types TANGENT, MATERIAL, JOINTS, and WEIGHTS are not supported
|
||||||
|
// in the official bitstream. They will be encoded as GENERIC.
|
||||||
|
if (type > GeometryAttribute::GENERIC) {
|
||||||
|
type = GeometryAttribute::GENERIC;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
out_buffer->Encode(static_cast<uint8_t>(type));
|
||||||
out_buffer->Encode(static_cast<uint8_t>(pa->data_type()));
|
out_buffer->Encode(static_cast<uint8_t>(pa->data_type()));
|
||||||
out_buffer->Encode(static_cast<uint8_t>(pa->num_components()));
|
out_buffer->Encode(static_cast<uint8_t>(pa->num_components()));
|
||||||
out_buffer->Encode(static_cast<uint8_t>(pa->normalized()));
|
out_buffer->Encode(static_cast<uint8_t>(pa->normalized()));
|
||||||
|
|
|
@ -72,16 +72,19 @@ class PointAttributeVectorOutputIterator {
|
||||||
|
|
||||||
Self &operator*() { return *this; }
|
Self &operator*() { return *this; }
|
||||||
// Still needed in some cases.
|
// Still needed in some cases.
|
||||||
// TODO(hemmer): remove.
|
// TODO(b/199760123): Remove.
|
||||||
// hardcoded to 3 based on legacy usage.
|
// hardcoded to 3 based on legacy usage.
|
||||||
const Self &operator=(const VectorD<CoeffT, 3> &val) {
|
const Self &operator=(const VectorD<CoeffT, 3> &val) {
|
||||||
DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute.
|
DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute.
|
||||||
AttributeTuple &att = attributes_[0];
|
AttributeTuple &att = attributes_[0];
|
||||||
PointAttribute *attribute = std::get<0>(att);
|
PointAttribute *attribute = std::get<0>(att);
|
||||||
|
const AttributeValueIndex avi = attribute->mapped_index(point_id_);
|
||||||
|
if (avi >= static_cast<uint32_t>(attribute->size())) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
const uint32_t &offset = std::get<1>(att);
|
const uint32_t &offset = std::get<1>(att);
|
||||||
DRACO_DCHECK_EQ(offset, 0); // expected to be zero
|
DRACO_DCHECK_EQ(offset, 0); // expected to be zero
|
||||||
attribute->SetAttributeValue(attribute->mapped_index(point_id_),
|
attribute->SetAttributeValue(avi, &val[0] + offset);
|
||||||
&val[0] + offset);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// Additional operator taking std::vector as argument.
|
// Additional operator taking std::vector as argument.
|
||||||
|
@ -89,6 +92,10 @@ class PointAttributeVectorOutputIterator {
|
||||||
for (auto index = 0; index < attributes_.size(); index++) {
|
for (auto index = 0; index < attributes_.size(); index++) {
|
||||||
AttributeTuple &att = attributes_[index];
|
AttributeTuple &att = attributes_[index];
|
||||||
PointAttribute *attribute = std::get<0>(att);
|
PointAttribute *attribute = std::get<0>(att);
|
||||||
|
const AttributeValueIndex avi = attribute->mapped_index(point_id_);
|
||||||
|
if (avi >= static_cast<uint32_t>(attribute->size())) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
const uint32_t &offset = std::get<1>(att);
|
const uint32_t &offset = std::get<1>(att);
|
||||||
const uint32_t &data_size = std::get<3>(att);
|
const uint32_t &data_size = std::get<3>(att);
|
||||||
const uint32_t &num_components = std::get<4>(att);
|
const uint32_t &num_components = std::get<4>(att);
|
||||||
|
@ -103,10 +110,6 @@ class PointAttributeVectorOutputIterator {
|
||||||
// redirect to copied data
|
// redirect to copied data
|
||||||
data_source = reinterpret_cast<uint32_t *>(data_);
|
data_source = reinterpret_cast<uint32_t *>(data_);
|
||||||
}
|
}
|
||||||
const AttributeValueIndex avi = attribute->mapped_index(point_id_);
|
|
||||||
if (avi >= static_cast<uint32_t>(attribute->size())) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
attribute->SetAttributeValue(avi, data_source);
|
attribute->SetAttributeValue(avi, data_source);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -195,54 +198,55 @@ bool KdTreeAttributesDecoder::DecodePortableAttributes(
|
||||||
data_size, num_components);
|
data_size, num_components);
|
||||||
total_dimensionality += num_components;
|
total_dimensionality += num_components;
|
||||||
}
|
}
|
||||||
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
|
typedef PointAttributeVectorOutputIterator<uint32_t> OutIt;
|
||||||
|
OutIt out_it(atts);
|
||||||
|
|
||||||
switch (compression_level) {
|
switch (compression_level) {
|
||||||
case 0: {
|
case 0: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<0> decoder(total_dimensionality);
|
if (!DecodePoints<0, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<1> decoder(total_dimensionality);
|
if (!DecodePoints<1, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<2> decoder(total_dimensionality);
|
if (!DecodePoints<2, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: {
|
case 3: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<3> decoder(total_dimensionality);
|
if (!DecodePoints<3, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<4> decoder(total_dimensionality);
|
if (!DecodePoints<4, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 5: {
|
case 5: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<5> decoder(total_dimensionality);
|
if (!DecodePoints<5, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 6: {
|
case 6: {
|
||||||
DynamicIntegerPointsKdTreeDecoder<6> decoder(total_dimensionality);
|
if (!DecodePoints<6, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
&out_it)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -253,6 +257,19 @@ bool KdTreeAttributesDecoder::DecodePortableAttributes(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int level_t, typename OutIteratorT>
|
||||||
|
bool KdTreeAttributesDecoder::DecodePoints(int total_dimensionality,
|
||||||
|
int num_expected_points,
|
||||||
|
DecoderBuffer *in_buffer,
|
||||||
|
OutIteratorT *out_iterator) {
|
||||||
|
DynamicIntegerPointsKdTreeDecoder<level_t> decoder(total_dimensionality);
|
||||||
|
if (!decoder.DecodePoints(in_buffer, *out_iterator, num_expected_points) ||
|
||||||
|
decoder.num_decoded_points() != num_expected_points) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||||
DecoderBuffer *in_buffer) {
|
DecoderBuffer *in_buffer) {
|
||||||
if (in_buffer->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 3)) {
|
if (in_buffer->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 3)) {
|
||||||
|
@ -336,6 +353,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (method == KdTreeAttributesEncodingMethod::kKdTreeQuantizationEncoding) {
|
if (method == KdTreeAttributesEncodingMethod::kKdTreeQuantizationEncoding) {
|
||||||
|
// This method only supports one attribute with exactly three components.
|
||||||
|
if (atts.size() != 1 || std::get<4>(atts[0]) != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
uint8_t compression_level = 0;
|
uint8_t compression_level = 0;
|
||||||
if (!in_buffer->Decode(&compression_level)) {
|
if (!in_buffer->Decode(&compression_level)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -376,7 +397,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||||
GetDecoder()->point_cloud()->attribute(att_id);
|
GetDecoder()->point_cloud()->attribute(att_id);
|
||||||
attr->Reset(num_points);
|
attr->Reset(num_points);
|
||||||
attr->SetIdentityMapping();
|
attr->SetIdentityMapping();
|
||||||
};
|
}
|
||||||
|
|
||||||
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
|
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
|
||||||
|
|
||||||
|
@ -455,7 +476,11 @@ bool KdTreeAttributesDecoder::TransformAttributeBackToSignedType(
|
||||||
att->GetValue(avi, &unsigned_val[0]);
|
att->GetValue(avi, &unsigned_val[0]);
|
||||||
for (int c = 0; c < att->num_components(); ++c) {
|
for (int c = 0; c < att->num_components(); ++c) {
|
||||||
// Up-cast |unsigned_val| to int32_t to ensure we don't overflow it for
|
// Up-cast |unsigned_val| to int32_t to ensure we don't overflow it for
|
||||||
// smaller data types.
|
// smaller data types. But first check that the up-casting does not cause
|
||||||
|
// signed integer overflow.
|
||||||
|
if (unsigned_val[c] > std::numeric_limits<int32_t>::max()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
signed_val[c] = static_cast<SignedDataTypeT>(
|
signed_val[c] = static_cast<SignedDataTypeT>(
|
||||||
static_cast<int32_t>(unsigned_val[c]) +
|
static_cast<int32_t>(unsigned_val[c]) +
|
||||||
min_signed_values_[num_processed_signed_components + c]);
|
min_signed_values_[num_processed_signed_components + c]);
|
||||||
|
|
|
@ -31,6 +31,10 @@ class KdTreeAttributesDecoder : public AttributesDecoder {
|
||||||
bool TransformAttributesToOriginalFormat() override;
|
bool TransformAttributesToOriginalFormat() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template <int level_t, typename OutIteratorT>
|
||||||
|
bool DecodePoints(int total_dimensionality, int num_expected_points,
|
||||||
|
DecoderBuffer *in_buffer, OutIteratorT *out_iterator);
|
||||||
|
|
||||||
template <typename SignedDataTypeT>
|
template <typename SignedDataTypeT>
|
||||||
bool TransformAttributeBackToSignedType(PointAttribute *att,
|
bool TransformAttributeBackToSignedType(PointAttribute *att,
|
||||||
int num_processed_signed_components);
|
int num_processed_signed_components);
|
||||||
|
|
|
@ -61,7 +61,7 @@ class OctahedronToolBox {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
quantization_bits_ = q;
|
quantization_bits_ = q;
|
||||||
max_quantized_value_ = (1 << quantization_bits_) - 1;
|
max_quantized_value_ = (1u << quantization_bits_) - 1;
|
||||||
max_value_ = max_quantized_value_ - 1;
|
max_value_ = max_quantized_value_ - 1;
|
||||||
dequantization_scale_ = 2.f / max_value_;
|
dequantization_scale_ = 2.f / max_value_;
|
||||||
center_value_ = max_value_ / 2;
|
center_value_ = max_value_ / 2;
|
||||||
|
@ -208,7 +208,9 @@ class OctahedronToolBox {
|
||||||
DRACO_DCHECK_LE(t, center_value_);
|
DRACO_DCHECK_LE(t, center_value_);
|
||||||
DRACO_DCHECK_GE(s, -center_value_);
|
DRACO_DCHECK_GE(s, -center_value_);
|
||||||
DRACO_DCHECK_GE(t, -center_value_);
|
DRACO_DCHECK_GE(t, -center_value_);
|
||||||
return std::abs(s) + std::abs(t) <= center_value_;
|
const uint32_t st =
|
||||||
|
static_cast<uint32_t>(std::abs(s)) + static_cast<uint32_t>(std::abs(t));
|
||||||
|
return st <= center_value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvertDiamond(int32_t *s, int32_t *t) const {
|
void InvertDiamond(int32_t *s, int32_t *t) const {
|
||||||
|
@ -230,19 +232,29 @@ class OctahedronToolBox {
|
||||||
sign_t = (*t > 0) ? 1 : -1;
|
sign_t = (*t > 0) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int32_t corner_point_s = sign_s * center_value_;
|
// Perform the addition and subtraction using unsigned integers to avoid
|
||||||
const int32_t corner_point_t = sign_t * center_value_;
|
// signed integer overflows for bad data. Note that the result will be
|
||||||
*s = 2 * *s - corner_point_s;
|
// unchanged for non-overflowing cases.
|
||||||
*t = 2 * *t - corner_point_t;
|
const uint32_t corner_point_s = sign_s * center_value_;
|
||||||
|
const uint32_t corner_point_t = sign_t * center_value_;
|
||||||
|
uint32_t us = *s;
|
||||||
|
uint32_t ut = *t;
|
||||||
|
us = us + us - corner_point_s;
|
||||||
|
ut = ut + ut - corner_point_t;
|
||||||
if (sign_s * sign_t >= 0) {
|
if (sign_s * sign_t >= 0) {
|
||||||
int32_t temp = *s;
|
uint32_t temp = us;
|
||||||
*s = -*t;
|
us = -ut;
|
||||||
*t = -temp;
|
ut = -temp;
|
||||||
} else {
|
} else {
|
||||||
std::swap(*s, *t);
|
std::swap(us, ut);
|
||||||
}
|
}
|
||||||
*s = (*s + corner_point_s) / 2;
|
us = us + corner_point_s;
|
||||||
*t = (*t + corner_point_t) / 2;
|
ut = ut + corner_point_t;
|
||||||
|
|
||||||
|
*s = us;
|
||||||
|
*t = ut;
|
||||||
|
*s /= 2;
|
||||||
|
*t /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvertDirection(int32_t *s, int32_t *t) const {
|
void InvertDirection(int32_t *s, int32_t *t) const {
|
||||||
|
@ -318,7 +330,7 @@ class OctahedronToolBox {
|
||||||
|
|
||||||
// Remaining coordinate can be computed by projecting the (y, z) values onto
|
// Remaining coordinate can be computed by projecting the (y, z) values onto
|
||||||
// the surface of the octahedron.
|
// the surface of the octahedron.
|
||||||
const float x = 1.f - abs(y) - abs(z);
|
const float x = 1.f - std::abs(y) - std::abs(z);
|
||||||
|
|
||||||
// |x| is essentially a signed distance from the diagonal edges of the
|
// |x| is essentially a signed distance from the diagonal edges of the
|
||||||
// diamond shown on the figure above. It is positive for all points in the
|
// diamond shown on the figure above. It is positive for all points in the
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
|
#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
|
||||||
#define DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
|
#define DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -99,11 +101,17 @@ class PointDVector {
|
||||||
data_(n_items * dimensionality),
|
data_(n_items * dimensionality),
|
||||||
data0_(data_.data()) {}
|
data0_(data_.data()) {}
|
||||||
// random access iterator
|
// random access iterator
|
||||||
class PointDVectorIterator
|
class PointDVectorIterator {
|
||||||
: public std::iterator<std::random_access_iterator_tag, size_t, size_t> {
|
|
||||||
friend class PointDVector;
|
friend class PointDVector;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Iterator traits expected by std libraries.
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using value_type = size_t;
|
||||||
|
using difference_type = size_t;
|
||||||
|
using pointer = PointDVector *;
|
||||||
|
using reference = PointDVector &;
|
||||||
|
|
||||||
// std::iter_swap is called inside of std::partition and needs this
|
// std::iter_swap is called inside of std::partition and needs this
|
||||||
// specialized support
|
// specialized support
|
||||||
PseudoPointD<internal_t> operator*() const {
|
PseudoPointD<internal_t> operator*() const {
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h"
|
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h"
|
||||||
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h"
|
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h"
|
||||||
#include "draco/compression/bit_coders/rans_bit_decoder.h"
|
#include "draco/compression/bit_coders/rans_bit_decoder.h"
|
||||||
|
#include "draco/core/math_utils.h"
|
||||||
#include "draco/core/varint_decoding.h"
|
#include "draco/core/varint_decoding.h"
|
||||||
#include "draco/draco_features.h"
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
|
@ -161,7 +162,8 @@ bool MeshPredictionSchemeConstrainedMultiParallelogramDecoder<
|
||||||
if (!is_crease) {
|
if (!is_crease) {
|
||||||
++num_used_parallelograms;
|
++num_used_parallelograms;
|
||||||
for (int j = 0; j < num_components; ++j) {
|
for (int j = 0; j < num_components; ++j) {
|
||||||
multi_pred_vals[j] += pred_vals[i][j];
|
multi_pred_vals[j] =
|
||||||
|
AddAsUnsigned(multi_pred_vals[j], pred_vals[i][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,6 +212,9 @@ bool MeshPredictionSchemeConstrainedMultiParallelogramDecoder<
|
||||||
if (!DecodeVarint<uint32_t>(&num_flags, buffer)) {
|
if (!DecodeVarint<uint32_t>(&num_flags, buffer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (num_flags > this->mesh_data().corner_table()->num_corners()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (num_flags > 0) {
|
if (num_flags > 0) {
|
||||||
is_crease_edge_[i].resize(num_flags);
|
is_crease_edge_[i].resize(num_flags);
|
||||||
RAnsBitDecoder decoder;
|
RAnsBitDecoder decoder;
|
||||||
|
|
|
@ -392,7 +392,7 @@ bool MeshPredictionSchemeConstrainedMultiParallelogramEncoder<
|
||||||
RAnsBitEncoder encoder;
|
RAnsBitEncoder encoder;
|
||||||
encoder.StartEncoding();
|
encoder.StartEncoding();
|
||||||
// Encode the crease edge flags in the reverse vertex order that is needed
|
// Encode the crease edge flags in the reverse vertex order that is needed
|
||||||
// be the decoder. Note that for the currently supported mode, each vertex
|
// by the decoder. Note that for the currently supported mode, each vertex
|
||||||
// has exactly |num_used_parallelograms| edges that need to be encoded.
|
// has exactly |num_used_parallelograms| edges that need to be encoded.
|
||||||
for (int j = static_cast<int>(is_crease_edge_[i].size()) -
|
for (int j = static_cast<int>(is_crease_edge_[i].size()) -
|
||||||
num_used_parallelograms;
|
num_used_parallelograms;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h"
|
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h"
|
||||||
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h"
|
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h"
|
||||||
|
#include "draco/core/math_utils.h"
|
||||||
#include "draco/draco_features.h"
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
@ -89,7 +90,8 @@ bool MeshPredictionSchemeMultiParallelogramDecoder<DataTypeT, TransformT,
|
||||||
p, corner_id, table, *vertex_to_data_map, out_data,
|
p, corner_id, table, *vertex_to_data_map, out_data,
|
||||||
num_components, parallelogram_pred_vals.get())) {
|
num_components, parallelogram_pred_vals.get())) {
|
||||||
for (int c = 0; c < num_components; ++c) {
|
for (int c = 0; c < num_components; ++c) {
|
||||||
pred_vals[c] += parallelogram_pred_vals[c];
|
pred_vals[c] =
|
||||||
|
AddAsUnsigned(pred_vals[c], parallelogram_pred_vals[c]);
|
||||||
}
|
}
|
||||||
++num_parallelograms;
|
++num_parallelograms;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ class MeshPredictionSchemeTexCoordsDecoder
|
||||||
static_cast<float>(data[data_offset + 1]));
|
static_cast<float>(data[data_offset + 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data,
|
bool ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data,
|
||||||
int data_id);
|
int data_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -123,6 +123,10 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data,
|
ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data,
|
||||||
int /* size */, int num_components,
|
int /* size */, int num_components,
|
||||||
const PointIndex *entry_to_point_id_map) {
|
const PointIndex *entry_to_point_id_map) {
|
||||||
|
if (num_components != 2) {
|
||||||
|
// Corrupt/malformed input. Two output components are req'd.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
num_components_ = num_components;
|
num_components_ = num_components;
|
||||||
entry_to_point_id_map_ = entry_to_point_id_map;
|
entry_to_point_id_map_ = entry_to_point_id_map;
|
||||||
predicted_value_ =
|
predicted_value_ =
|
||||||
|
@ -133,7 +137,9 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
static_cast<int>(this->mesh_data().data_to_corner_map()->size());
|
static_cast<int>(this->mesh_data().data_to_corner_map()->size());
|
||||||
for (int p = 0; p < corner_map_size; ++p) {
|
for (int p = 0; p < corner_map_size; ++p) {
|
||||||
const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p);
|
const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p);
|
||||||
ComputePredictedValue(corner_id, out_data, p);
|
if (!ComputePredictedValue(corner_id, out_data, p)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const int dst_offset = p * num_components;
|
const int dst_offset = p * num_components;
|
||||||
this->transform().ComputeOriginalValue(
|
this->transform().ComputeOriginalValue(
|
||||||
|
@ -159,6 +165,11 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
if (num_orientations == 0) {
|
if (num_orientations == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (num_orientations > this->mesh_data().corner_table()->num_corners()) {
|
||||||
|
// We can't have more orientations than the maximum number of decoded
|
||||||
|
// values.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
orientations_.resize(num_orientations);
|
orientations_.resize(num_orientations);
|
||||||
bool last_orientation = true;
|
bool last_orientation = true;
|
||||||
RAnsBitDecoder decoder;
|
RAnsBitDecoder decoder;
|
||||||
|
@ -177,7 +188,7 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataTypeT, class TransformT, class MeshDataT>
|
template <typename DataTypeT, class TransformT, class MeshDataT>
|
||||||
void MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data,
|
ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data,
|
||||||
int data_id) {
|
int data_id) {
|
||||||
// Compute the predicted UV coordinate from the positions on all corners
|
// Compute the predicted UV coordinate from the positions on all corners
|
||||||
|
@ -206,9 +217,17 @@ void MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
const Vector2f p_uv = GetTexCoordForEntryId(prev_data_id, data);
|
const Vector2f p_uv = GetTexCoordForEntryId(prev_data_id, data);
|
||||||
if (p_uv == n_uv) {
|
if (p_uv == n_uv) {
|
||||||
// We cannot do a reliable prediction on degenerated UV triangles.
|
// We cannot do a reliable prediction on degenerated UV triangles.
|
||||||
predicted_value_[0] = static_cast<int>(p_uv[0]);
|
// Technically floats > INT_MAX are undefined, but compilers will
|
||||||
predicted_value_[1] = static_cast<int>(p_uv[1]);
|
// convert those values to INT_MIN. We are being explicit here for asan.
|
||||||
return;
|
for (const int i : {0, 1}) {
|
||||||
|
if (std::isnan(p_uv[i]) || static_cast<double>(p_uv[i]) > INT_MAX ||
|
||||||
|
static_cast<double>(p_uv[i]) < INT_MIN) {
|
||||||
|
predicted_value_[i] = INT_MIN;
|
||||||
|
} else {
|
||||||
|
predicted_value_[i] = static_cast<int>(p_uv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get positions at all corners.
|
// Get positions at all corners.
|
||||||
|
@ -282,32 +301,40 @@ void MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
const float pnvs = pn_uv[1] * s + n_uv[1];
|
const float pnvs = pn_uv[1] * s + n_uv[1];
|
||||||
const float pnvt = pn_uv[1] * t;
|
const float pnvt = pn_uv[1] * t;
|
||||||
Vector2f predicted_uv;
|
Vector2f predicted_uv;
|
||||||
|
if (orientations_.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// When decoding the data, we already know which orientation to use.
|
// When decoding the data, we already know which orientation to use.
|
||||||
const bool orientation = orientations_.back();
|
const bool orientation = orientations_.back();
|
||||||
orientations_.pop_back();
|
orientations_.pop_back();
|
||||||
if (orientation)
|
if (orientation) {
|
||||||
predicted_uv = Vector2f(pnus - pnvt, pnvs + pnut);
|
predicted_uv = Vector2f(pnus - pnvt, pnvs + pnut);
|
||||||
else
|
} else {
|
||||||
predicted_uv = Vector2f(pnus + pnvt, pnvs - pnut);
|
predicted_uv = Vector2f(pnus + pnvt, pnvs - pnut);
|
||||||
|
}
|
||||||
if (std::is_integral<DataTypeT>::value) {
|
if (std::is_integral<DataTypeT>::value) {
|
||||||
// Round the predicted value for integer types.
|
// Round the predicted value for integer types.
|
||||||
if (std::isnan(predicted_uv[0])) {
|
// Technically floats > INT_MAX are undefined, but compilers will
|
||||||
|
// convert those values to INT_MIN. We are being explicit here for asan.
|
||||||
|
const double u = floor(predicted_uv[0] + 0.5);
|
||||||
|
if (std::isnan(u) || u > INT_MAX || u < INT_MIN) {
|
||||||
predicted_value_[0] = INT_MIN;
|
predicted_value_[0] = INT_MIN;
|
||||||
} else {
|
} else {
|
||||||
predicted_value_[0] = static_cast<int>(floor(predicted_uv[0] + 0.5));
|
predicted_value_[0] = static_cast<int>(u);
|
||||||
}
|
}
|
||||||
if (std::isnan(predicted_uv[1])) {
|
const double v = floor(predicted_uv[1] + 0.5);
|
||||||
|
if (std::isnan(v) || v > INT_MAX || v < INT_MIN) {
|
||||||
predicted_value_[1] = INT_MIN;
|
predicted_value_[1] = INT_MIN;
|
||||||
} else {
|
} else {
|
||||||
predicted_value_[1] = static_cast<int>(floor(predicted_uv[1] + 0.5));
|
predicted_value_[1] = static_cast<int>(v);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
predicted_value_[0] = static_cast<int>(predicted_uv[0]);
|
predicted_value_[0] = static_cast<int>(predicted_uv[0]);
|
||||||
predicted_value_[1] = static_cast<int>(predicted_uv[1]);
|
predicted_value_[1] = static_cast<int>(predicted_uv[1]);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// Else we don't have available textures on both corners. For such case we
|
// Else we don't have available textures on both corners. For such case we
|
||||||
// can't use positions for predicting the uv value and we resort to delta
|
// can't use positions for predicting the uv value and we resort to delta
|
||||||
|
@ -330,12 +357,13 @@ void MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
||||||
for (int i = 0; i < num_components_; ++i) {
|
for (int i = 0; i < num_components_; ++i) {
|
||||||
predicted_value_[i] = 0;
|
predicted_value_[i] = 0;
|
||||||
}
|
}
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < num_components_; ++i) {
|
for (int i = 0; i < num_components_; ++i) {
|
||||||
predicted_value_[i] = data[data_offset + i];
|
predicted_value_[i] = data[data_offset + i];
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
|
|
@ -98,7 +98,10 @@ bool MeshPredictionSchemeTexCoordsPortableEncoder<DataTypeT, TransformT,
|
||||||
static_cast<int>(this->mesh_data().data_to_corner_map()->size() - 1);
|
static_cast<int>(this->mesh_data().data_to_corner_map()->size() - 1);
|
||||||
p >= 0; --p) {
|
p >= 0; --p) {
|
||||||
const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p);
|
const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p);
|
||||||
predictor_.template ComputePredictedValue<true>(corner_id, in_data, p);
|
if (!predictor_.template ComputePredictedValue<true>(corner_id, in_data,
|
||||||
|
p)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const int dst_offset = p * num_components;
|
const int dst_offset = p * num_components;
|
||||||
this->transform().ComputeCorrection(in_data + dst_offset,
|
this->transform().ComputeCorrection(in_data + dst_offset,
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "draco/attributes/point_attribute.h"
|
#include "draco/attributes/point_attribute.h"
|
||||||
#include "draco/core/math_utils.h"
|
#include "draco/core/math_utils.h"
|
||||||
#include "draco/core/vector_d.h"
|
#include "draco/core/vector_d.h"
|
||||||
|
@ -105,10 +108,14 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
next_data_id = mesh_data_.vertex_to_data_map()->at(next_vert_id);
|
next_data_id = mesh_data_.vertex_to_data_map()->at(next_vert_id);
|
||||||
prev_data_id = mesh_data_.vertex_to_data_map()->at(prev_vert_id);
|
prev_data_id = mesh_data_.vertex_to_data_map()->at(prev_vert_id);
|
||||||
|
|
||||||
|
typedef VectorD<int64_t, 2> Vec2;
|
||||||
|
typedef VectorD<int64_t, 3> Vec3;
|
||||||
|
typedef VectorD<uint64_t, 2> Vec2u;
|
||||||
|
|
||||||
if (prev_data_id < data_id && next_data_id < data_id) {
|
if (prev_data_id < data_id && next_data_id < data_id) {
|
||||||
// Both other corners have available UV coordinates for prediction.
|
// Both other corners have available UV coordinates for prediction.
|
||||||
const VectorD<int64_t, 2> n_uv = GetTexCoordForEntryId(next_data_id, data);
|
const Vec2 n_uv = GetTexCoordForEntryId(next_data_id, data);
|
||||||
const VectorD<int64_t, 2> p_uv = GetTexCoordForEntryId(prev_data_id, data);
|
const Vec2 p_uv = GetTexCoordForEntryId(prev_data_id, data);
|
||||||
if (p_uv == n_uv) {
|
if (p_uv == n_uv) {
|
||||||
// We cannot do a reliable prediction on degenerated UV triangles.
|
// We cannot do a reliable prediction on degenerated UV triangles.
|
||||||
predicted_value_[0] = p_uv[0];
|
predicted_value_[0] = p_uv[0];
|
||||||
|
@ -117,9 +124,9 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get positions at all corners.
|
// Get positions at all corners.
|
||||||
const VectorD<int64_t, 3> tip_pos = GetPositionForEntryId(data_id);
|
const Vec3 tip_pos = GetPositionForEntryId(data_id);
|
||||||
const VectorD<int64_t, 3> next_pos = GetPositionForEntryId(next_data_id);
|
const Vec3 next_pos = GetPositionForEntryId(next_data_id);
|
||||||
const VectorD<int64_t, 3> prev_pos = GetPositionForEntryId(prev_data_id);
|
const Vec3 prev_pos = GetPositionForEntryId(prev_data_id);
|
||||||
// We use the positions of the above triangle to predict the texture
|
// We use the positions of the above triangle to predict the texture
|
||||||
// coordinate on the tip corner C.
|
// coordinate on the tip corner C.
|
||||||
// To convert the triangle into the UV coordinate system we first compute
|
// To convert the triangle into the UV coordinate system we first compute
|
||||||
|
@ -135,17 +142,17 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
// Where next_pos is point (N), prev_pos is point (P) and tip_pos is the
|
// Where next_pos is point (N), prev_pos is point (P) and tip_pos is the
|
||||||
// position of predicted coordinate (C).
|
// position of predicted coordinate (C).
|
||||||
//
|
//
|
||||||
const VectorD<int64_t, 3> pn = prev_pos - next_pos;
|
const Vec3 pn = prev_pos - next_pos;
|
||||||
const uint64_t pn_norm2_squared = pn.SquaredNorm();
|
const uint64_t pn_norm2_squared = pn.SquaredNorm();
|
||||||
if (pn_norm2_squared != 0) {
|
if (pn_norm2_squared != 0) {
|
||||||
// Compute the projection of C onto PN by computing dot product of CN with
|
// Compute the projection of C onto PN by computing dot product of CN with
|
||||||
// PN and normalizing it by length of PN. This gives us a factor |s| where
|
// PN and normalizing it by length of PN. This gives us a factor |s| where
|
||||||
// |s = PN.Dot(CN) / PN.SquaredNorm2()|. This factor can be used to
|
// |s = PN.Dot(CN) / PN.SquaredNorm2()|. This factor can be used to
|
||||||
// compute X in UV space |X_UV| as |X_UV = N_UV + s * PN_UV|.
|
// compute X in UV space |X_UV| as |X_UV = N_UV + s * PN_UV|.
|
||||||
const VectorD<int64_t, 3> cn = tip_pos - next_pos;
|
const Vec3 cn = tip_pos - next_pos;
|
||||||
const int64_t cn_dot_pn = pn.Dot(cn);
|
const int64_t cn_dot_pn = pn.Dot(cn);
|
||||||
|
|
||||||
const VectorD<int64_t, 2> pn_uv = p_uv - n_uv;
|
const Vec2 pn_uv = p_uv - n_uv;
|
||||||
// Because we perform all computations with integers, we don't explicitly
|
// Because we perform all computations with integers, we don't explicitly
|
||||||
// compute the normalized factor |s|, but rather we perform all operations
|
// compute the normalized factor |s|, but rather we perform all operations
|
||||||
// over UV vectors in a non-normalized coordinate system scaled with a
|
// over UV vectors in a non-normalized coordinate system scaled with a
|
||||||
|
@ -153,19 +160,30 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
//
|
//
|
||||||
// x_uv = X_UV * PN.Norm2Squared()
|
// x_uv = X_UV * PN.Norm2Squared()
|
||||||
//
|
//
|
||||||
const VectorD<int64_t, 2> x_uv =
|
const int64_t n_uv_absmax_element =
|
||||||
n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
|
std::max(std::abs(n_uv[0]), std::abs(n_uv[1]));
|
||||||
|
if (n_uv_absmax_element >
|
||||||
|
std::numeric_limits<int64_t>::max() / pn_norm2_squared) {
|
||||||
|
// Return false if the below multiplication would overflow.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const int64_t pn_uv_absmax_element =
|
||||||
|
std::max(std::abs(pn_uv[0]), std::abs(pn_uv[1]));
|
||||||
|
if (cn_dot_pn >
|
||||||
|
std::numeric_limits<int64_t>::max() / pn_uv_absmax_element) {
|
||||||
|
// Return false if squared length calculation would overflow.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const Vec2 x_uv = n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
|
||||||
const int64_t pn_absmax_element =
|
const int64_t pn_absmax_element =
|
||||||
std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2]));
|
std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2]));
|
||||||
if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) {
|
if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) {
|
||||||
// return false if squared length calculation would overflow.
|
// Return false if squared length calculation would overflow.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute squared length of vector CX in position coordinate system:
|
// Compute squared length of vector CX in position coordinate system:
|
||||||
const VectorD<int64_t, 3> x_pos =
|
const Vec3 x_pos = next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
|
||||||
next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
|
|
||||||
const uint64_t cx_norm2_squared = (tip_pos - x_pos).SquaredNorm();
|
const uint64_t cx_norm2_squared = (tip_pos - x_pos).SquaredNorm();
|
||||||
|
|
||||||
// Compute vector CX_UV in the uv space by rotating vector PN_UV by 90
|
// Compute vector CX_UV in the uv space by rotating vector PN_UV by 90
|
||||||
|
@ -182,7 +200,7 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
//
|
//
|
||||||
// cx_uv = CX.Norm2() * PN.Norm2() * Rot(PN_UV)
|
// cx_uv = CX.Norm2() * PN.Norm2() * Rot(PN_UV)
|
||||||
//
|
//
|
||||||
VectorD<int64_t, 2> cx_uv(pn_uv[1], -pn_uv[0]); // Rotated PN_UV.
|
Vec2 cx_uv(pn_uv[1], -pn_uv[0]); // Rotated PN_UV.
|
||||||
// Compute CX.Norm2() * PN.Norm2()
|
// Compute CX.Norm2() * PN.Norm2()
|
||||||
const uint64_t norm_squared =
|
const uint64_t norm_squared =
|
||||||
IntSqrt(cx_norm2_squared * pn_norm2_squared);
|
IntSqrt(cx_norm2_squared * pn_norm2_squared);
|
||||||
|
@ -191,17 +209,15 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
|
|
||||||
// Predicted uv coordinate is then computed by either adding or
|
// Predicted uv coordinate is then computed by either adding or
|
||||||
// subtracting CX_UV to/from X_UV.
|
// subtracting CX_UV to/from X_UV.
|
||||||
VectorD<int64_t, 2> predicted_uv;
|
Vec2 predicted_uv;
|
||||||
if (is_encoder_t) {
|
if (is_encoder_t) {
|
||||||
// When encoding, compute both possible vectors and determine which one
|
// When encoding, compute both possible vectors and determine which one
|
||||||
// results in a better prediction.
|
// results in a better prediction.
|
||||||
// Both vectors need to be transformed back from the scaled space to
|
// Both vectors need to be transformed back from the scaled space to
|
||||||
// the real UV coordinate space.
|
// the real UV coordinate space.
|
||||||
const VectorD<int64_t, 2> predicted_uv_0((x_uv + cx_uv) /
|
const Vec2 predicted_uv_0((x_uv + cx_uv) / pn_norm2_squared);
|
||||||
pn_norm2_squared);
|
const Vec2 predicted_uv_1((x_uv - cx_uv) / pn_norm2_squared);
|
||||||
const VectorD<int64_t, 2> predicted_uv_1((x_uv - cx_uv) /
|
const Vec2 c_uv = GetTexCoordForEntryId(data_id, data);
|
||||||
pn_norm2_squared);
|
|
||||||
const VectorD<int64_t, 2> c_uv = GetTexCoordForEntryId(data_id, data);
|
|
||||||
if ((c_uv - predicted_uv_0).SquaredNorm() <
|
if ((c_uv - predicted_uv_0).SquaredNorm() <
|
||||||
(c_uv - predicted_uv_1).SquaredNorm()) {
|
(c_uv - predicted_uv_1).SquaredNorm()) {
|
||||||
predicted_uv = predicted_uv_0;
|
predicted_uv = predicted_uv_0;
|
||||||
|
@ -217,10 +233,12 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||||
}
|
}
|
||||||
const bool orientation = orientations_.back();
|
const bool orientation = orientations_.back();
|
||||||
orientations_.pop_back();
|
orientations_.pop_back();
|
||||||
|
// Perform operations in unsigned type to avoid signed integer overflow.
|
||||||
|
// Note that the result will be the same (for non-overflowing values).
|
||||||
if (orientation) {
|
if (orientation) {
|
||||||
predicted_uv = (x_uv + cx_uv) / pn_norm2_squared;
|
predicted_uv = Vec2(Vec2u(x_uv) + Vec2u(cx_uv)) / pn_norm2_squared;
|
||||||
} else {
|
} else {
|
||||||
predicted_uv = (x_uv - cx_uv) / pn_norm2_squared;
|
predicted_uv = Vec2(Vec2u(x_uv) - Vec2u(cx_uv)) / pn_norm2_squared;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
predicted_value_[0] = static_cast<int>(predicted_uv[0]);
|
predicted_value_[0] = static_cast<int>(predicted_uv[0]);
|
||||||
|
|
|
@ -18,22 +18,58 @@ namespace draco {
|
||||||
|
|
||||||
PredictionSchemeMethod SelectPredictionMethod(
|
PredictionSchemeMethod SelectPredictionMethod(
|
||||||
int att_id, const PointCloudEncoder *encoder) {
|
int att_id, const PointCloudEncoder *encoder) {
|
||||||
if (encoder->options()->GetSpeed() >= 10) {
|
return SelectPredictionMethod(att_id, *encoder->options(), encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
PredictionSchemeMethod SelectPredictionMethod(
|
||||||
|
int att_id, const EncoderOptions &options,
|
||||||
|
const PointCloudEncoder *encoder) {
|
||||||
|
if (options.GetSpeed() >= 10) {
|
||||||
// Selected fastest, though still doing some compression.
|
// Selected fastest, though still doing some compression.
|
||||||
return PREDICTION_DIFFERENCE;
|
return PREDICTION_DIFFERENCE;
|
||||||
}
|
}
|
||||||
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
||||||
// Use speed setting to select the best encoding method.
|
// Use speed setting to select the best encoding method.
|
||||||
|
const int att_quant =
|
||||||
|
options.GetAttributeInt(att_id, "quantization_bits", -1);
|
||||||
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
|
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
|
||||||
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
|
if (att_quant != -1 &&
|
||||||
if (encoder->options()->GetSpeed() < 4) {
|
att->attribute_type() == GeometryAttribute::TEX_COORD &&
|
||||||
|
att->num_components() == 2) {
|
||||||
|
// Texture coordinate predictor needs a position attribute that is either
|
||||||
|
// integer or quantized. For numerical reasons, we require the position
|
||||||
|
// quantization to be at most 21 bits and the 2*position_quantization +
|
||||||
|
// uv_quantization < 64 (TODO(b/231259902)).
|
||||||
|
const PointAttribute *const pos_att =
|
||||||
|
encoder->point_cloud()->GetNamedAttribute(
|
||||||
|
GeometryAttribute::POSITION);
|
||||||
|
bool is_pos_att_valid = false;
|
||||||
|
if (pos_att) {
|
||||||
|
if (IsDataTypeIntegral(pos_att->data_type())) {
|
||||||
|
is_pos_att_valid = true;
|
||||||
|
} else {
|
||||||
|
// Check quantization of the position attribute.
|
||||||
|
const int pos_att_id = encoder->point_cloud()->GetNamedAttributeId(
|
||||||
|
GeometryAttribute::POSITION);
|
||||||
|
const int pos_quant =
|
||||||
|
options.GetAttributeInt(pos_att_id, "quantization_bits", -1);
|
||||||
|
// Must be quantized but the quantization is restricted to 21 bits and
|
||||||
|
// 2*|pos_quant|+|att_quant| must be smaller than 64 bits.
|
||||||
|
if (pos_quant > 0 && pos_quant <= 21 &&
|
||||||
|
2 * pos_quant + att_quant < 64) {
|
||||||
|
is_pos_att_valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_pos_att_valid && options.GetSpeed() < 4) {
|
||||||
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
|
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
|
||||||
return MESH_PREDICTION_TEX_COORDS_PORTABLE;
|
return MESH_PREDICTION_TEX_COORDS_PORTABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (att->attribute_type() == GeometryAttribute::NORMAL) {
|
if (att->attribute_type() == GeometryAttribute::NORMAL) {
|
||||||
#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
|
#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
|
||||||
if (encoder->options()->GetSpeed() < 4) {
|
if (options.GetSpeed() < 4) {
|
||||||
// Use geometric normal prediction for speeds 0, 1, 2, 3.
|
// Use geometric normal prediction for speeds 0, 1, 2, 3.
|
||||||
// For this prediction, the position attribute needs to be either
|
// For this prediction, the position attribute needs to be either
|
||||||
// integer or quantized as well.
|
// integer or quantized as well.
|
||||||
|
@ -43,8 +79,8 @@ PredictionSchemeMethod SelectPredictionMethod(
|
||||||
encoder->point_cloud()->GetNamedAttribute(
|
encoder->point_cloud()->GetNamedAttribute(
|
||||||
GeometryAttribute::POSITION);
|
GeometryAttribute::POSITION);
|
||||||
if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) ||
|
if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) ||
|
||||||
encoder->options()->GetAttributeInt(
|
options.GetAttributeInt(pos_att_id, "quantization_bits",
|
||||||
pos_att_id, "quantization_bits", -1) > 0)) {
|
-1) > 0)) {
|
||||||
return MESH_PREDICTION_GEOMETRIC_NORMAL;
|
return MESH_PREDICTION_GEOMETRIC_NORMAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,11 +88,10 @@ PredictionSchemeMethod SelectPredictionMethod(
|
||||||
return PREDICTION_DIFFERENCE; // default
|
return PREDICTION_DIFFERENCE; // default
|
||||||
}
|
}
|
||||||
// Handle other attribute types.
|
// Handle other attribute types.
|
||||||
if (encoder->options()->GetSpeed() >= 8) {
|
if (options.GetSpeed() >= 8) {
|
||||||
return PREDICTION_DIFFERENCE;
|
return PREDICTION_DIFFERENCE;
|
||||||
}
|
}
|
||||||
if (encoder->options()->GetSpeed() >= 2 ||
|
if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) {
|
||||||
encoder->point_cloud()->num_points() < 40) {
|
|
||||||
// Parallelogram prediction is used for speeds 2 - 7 or when the overhead
|
// Parallelogram prediction is used for speeds 2 - 7 or when the overhead
|
||||||
// of using constrained multi-parallelogram would be too high.
|
// of using constrained multi-parallelogram would be too high.
|
||||||
return MESH_PREDICTION_PARALLELOGRAM;
|
return MESH_PREDICTION_PARALLELOGRAM;
|
||||||
|
|
|
@ -38,6 +38,10 @@ namespace draco {
|
||||||
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||||
const PointCloudEncoder *encoder);
|
const PointCloudEncoder *encoder);
|
||||||
|
|
||||||
|
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||||
|
const EncoderOptions &options,
|
||||||
|
const PointCloudEncoder *encoder);
|
||||||
|
|
||||||
// Factory class for creating mesh prediction schemes.
|
// Factory class for creating mesh prediction schemes.
|
||||||
template <typename DataTypeT>
|
template <typename DataTypeT>
|
||||||
struct MeshPredictionSchemeEncoderFactory {
|
struct MeshPredictionSchemeEncoderFactory {
|
||||||
|
@ -97,10 +101,11 @@ CreatePredictionSchemeForEncoder(PredictionSchemeMethod method, int att_id,
|
||||||
// template nature of the prediction schemes).
|
// template nature of the prediction schemes).
|
||||||
const MeshEncoder *const mesh_encoder =
|
const MeshEncoder *const mesh_encoder =
|
||||||
static_cast<const MeshEncoder *>(encoder);
|
static_cast<const MeshEncoder *>(encoder);
|
||||||
|
const uint16_t bitstream_version = kDracoMeshBitstreamVersion;
|
||||||
auto ret = CreateMeshPredictionScheme<
|
auto ret = CreateMeshPredictionScheme<
|
||||||
MeshEncoder, PredictionSchemeEncoder<DataTypeT, TransformT>,
|
MeshEncoder, PredictionSchemeEncoder<DataTypeT, TransformT>,
|
||||||
MeshPredictionSchemeEncoderFactory<DataTypeT>>(
|
MeshPredictionSchemeEncoderFactory<DataTypeT>>(
|
||||||
mesh_encoder, method, att_id, transform, kDracoMeshBitstreamVersion);
|
mesh_encoder, method, att_id, transform, bitstream_version);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h"
|
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h"
|
||||||
#include "draco/core/decoder_buffer.h"
|
#include "draco/core/decoder_buffer.h"
|
||||||
#include "draco/core/macros.h"
|
#include "draco/core/macros.h"
|
||||||
|
#include "draco/core/math_utils.h"
|
||||||
#include "draco/core/vector_d.h"
|
#include "draco/core/vector_d.h"
|
||||||
|
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
@ -98,9 +99,8 @@ class PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform
|
||||||
if (!pred_is_in_bottom_left) {
|
if (!pred_is_in_bottom_left) {
|
||||||
pred = this->RotatePoint(pred, rotation_count);
|
pred = this->RotatePoint(pred, rotation_count);
|
||||||
}
|
}
|
||||||
Point2 orig = pred + corr;
|
Point2 orig(this->ModMax(AddAsUnsigned(pred[0], corr[0])),
|
||||||
orig[0] = this->ModMax(orig[0]);
|
this->ModMax(AddAsUnsigned(pred[1], corr[1])));
|
||||||
orig[1] = this->ModMax(orig[1]);
|
|
||||||
if (!pred_is_in_bottom_left) {
|
if (!pred_is_in_bottom_left) {
|
||||||
const int32_t reverse_rotation_count = (4 - rotation_count) % 4;
|
const int32_t reverse_rotation_count = (4 - rotation_count) % 4;
|
||||||
orig = this->RotatePoint(orig, reverse_rotation_count);
|
orig = this->RotatePoint(orig, reverse_rotation_count);
|
||||||
|
|
|
@ -25,10 +25,10 @@ class PredictionSchemeNormalOctahedronCanonicalizedTransformTest
|
||||||
Transform;
|
Transform;
|
||||||
typedef Transform::Point2 Point2;
|
typedef Transform::Point2 Point2;
|
||||||
|
|
||||||
void TestComputeCorrection(const Transform &transform, const int32_t &ox,
|
void TestComputeCorrection(const Transform &transform, const int32_t ox,
|
||||||
const int32_t &oy, const int32_t &px,
|
const int32_t oy, const int32_t px,
|
||||||
const int32_t &py, const int32_t &cx,
|
const int32_t py, const int32_t cx,
|
||||||
const int32_t &cy) {
|
const int32_t cy) {
|
||||||
const int32_t o[2] = {ox + 7, oy + 7};
|
const int32_t o[2] = {ox + 7, oy + 7};
|
||||||
const int32_t p[2] = {px + 7, py + 7};
|
const int32_t p[2] = {px + 7, py + 7};
|
||||||
int32_t corr[2] = {500, 500};
|
int32_t corr[2] = {500, 500};
|
||||||
|
@ -38,7 +38,7 @@ class PredictionSchemeNormalOctahedronCanonicalizedTransformTest
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestGetRotationCount(const Transform &transform, const Point2 &pred,
|
void TestGetRotationCount(const Transform &transform, const Point2 &pred,
|
||||||
const int32_t &rot_dir) {
|
const int32_t rot_dir) {
|
||||||
const int32_t rotation_count = transform.GetRotationCount(pred);
|
const int32_t rotation_count = transform.GetRotationCount(pred);
|
||||||
ASSERT_EQ(rot_dir, rotation_count);
|
ASSERT_EQ(rot_dir, rotation_count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,19 +80,31 @@ class PredictionSchemeNormalOctahedronDecodingTransform
|
||||||
private:
|
private:
|
||||||
Point2 ComputeOriginalValue(Point2 pred, const Point2 &corr) const {
|
Point2 ComputeOriginalValue(Point2 pred, const Point2 &corr) const {
|
||||||
const Point2 t(this->center_value(), this->center_value());
|
const Point2 t(this->center_value(), this->center_value());
|
||||||
pred = pred - t;
|
typedef typename std::make_unsigned<DataTypeT>::type UnsignedDataTypeT;
|
||||||
|
typedef VectorD<UnsignedDataTypeT, 2> Point2u;
|
||||||
|
|
||||||
|
// Perform the addition in unsigned type to avoid signed integer overflow.
|
||||||
|
// Note that the result will be the same (for non-overflowing values).
|
||||||
|
pred = Point2(Point2u(pred) - Point2u(t));
|
||||||
|
|
||||||
const bool pred_is_in_diamond = this->IsInDiamond(pred[0], pred[1]);
|
const bool pred_is_in_diamond = this->IsInDiamond(pred[0], pred[1]);
|
||||||
if (!pred_is_in_diamond) {
|
if (!pred_is_in_diamond) {
|
||||||
this->InvertDiamond(&pred[0], &pred[1]);
|
this->InvertDiamond(&pred[0], &pred[1]);
|
||||||
}
|
}
|
||||||
Point2 orig = pred + corr;
|
|
||||||
|
// Perform the addition in unsigned type to avoid signed integer overflow.
|
||||||
|
// Note that the result will be the same (for non-overflowing values).
|
||||||
|
Point2 orig(Point2u(pred) + Point2u(corr));
|
||||||
|
|
||||||
orig[0] = this->ModMax(orig[0]);
|
orig[0] = this->ModMax(orig[0]);
|
||||||
orig[1] = this->ModMax(orig[1]);
|
orig[1] = this->ModMax(orig[1]);
|
||||||
if (!pred_is_in_diamond) {
|
if (!pred_is_in_diamond) {
|
||||||
this->InvertDiamond(&orig[0], &orig[1]);
|
this->InvertDiamond(&orig[0], &orig[1]);
|
||||||
}
|
}
|
||||||
orig = orig + t;
|
|
||||||
|
// Perform the addition in unsigned type to avoid signed integer overflow.
|
||||||
|
// Note that the result will be the same (for non-overflowing values).
|
||||||
|
orig = Point2(Point2u(orig) + Point2u(t));
|
||||||
return orig;
|
return orig;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,10 +23,10 @@ class PredictionSchemeNormalOctahedronTransformTest : public ::testing::Test {
|
||||||
Transform;
|
Transform;
|
||||||
typedef Transform::Point2 Point2;
|
typedef Transform::Point2 Point2;
|
||||||
|
|
||||||
void TestComputeCorrection(const Transform &transform, const int32_t &ox,
|
void TestComputeCorrection(const Transform &transform, const int32_t ox,
|
||||||
const int32_t &oy, const int32_t &px,
|
const int32_t oy, const int32_t px,
|
||||||
const int32_t &py, const int32_t &cx,
|
const int32_t py, const int32_t cx,
|
||||||
const int32_t &cy) {
|
const int32_t cy) {
|
||||||
const int32_t o[2] = {ox + 7, oy + 7};
|
const int32_t o[2] = {ox + 7, oy + 7};
|
||||||
const int32_t p[2] = {px + 7, py + 7};
|
const int32_t p[2] = {px + 7, py + 7};
|
||||||
int32_t corr[2] = {500, 500};
|
int32_t corr[2] = {500, 500};
|
||||||
|
|
|
@ -70,10 +70,10 @@ class PredictionSchemeWrapTransformBase {
|
||||||
clamped_value_[i] = predicted_val[i];
|
clamped_value_[i] = predicted_val[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &clamped_value_[0];
|
return clamped_value_.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(hemmer): Consider refactoring to avoid this dummy.
|
// TODO(b/199760123): Consider refactoring to avoid this dummy.
|
||||||
int quantization_bits() const {
|
int quantization_bits() const {
|
||||||
DRACO_DCHECK(false);
|
DRACO_DCHECK(false);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -148,8 +148,9 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < num_values; ++i) {
|
for (size_t i = 0; i < num_values; ++i) {
|
||||||
if (!in_buffer->Decode(portable_attribute_data + i, num_bytes))
|
if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) {
|
||||||
|
|
||||||
void SequentialIntegerAttributeDecoder::PreparePortableAttribute(
|
void SequentialIntegerAttributeDecoder::PreparePortableAttribute(
|
||||||
int num_entries, int num_components) {
|
int num_entries, int num_components) {
|
||||||
GeometryAttribute va;
|
GeometryAttribute ga;
|
||||||
va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
|
ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
|
||||||
false, num_components * DataTypeLength(DT_INT32), 0);
|
false, num_components * DataTypeLength(DT_INT32), 0);
|
||||||
std::unique_ptr<PointAttribute> port_att(new PointAttribute(va));
|
std::unique_ptr<PointAttribute> port_att(new PointAttribute(ga));
|
||||||
port_att->SetIdentityMapping();
|
port_att->SetIdentityMapping();
|
||||||
port_att->Reset(num_entries);
|
port_att->Reset(num_entries);
|
||||||
|
port_att->set_unique_id(attribute()->unique_id());
|
||||||
SetPortableAttribute(std::move(port_att));
|
SetPortableAttribute(std::move(port_att));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,9 +138,11 @@ bool SequentialIntegerAttributeEncoder::EncodeValues(
|
||||||
// All integer values are initialized. Process them using the prediction
|
// All integer values are initialized. Process them using the prediction
|
||||||
// scheme if we have one.
|
// scheme if we have one.
|
||||||
if (prediction_scheme_) {
|
if (prediction_scheme_) {
|
||||||
prediction_scheme_->ComputeCorrectionValues(
|
if (!prediction_scheme_->ComputeCorrectionValues(
|
||||||
portable_attribute_data, &encoded_data[0], num_values, num_components,
|
portable_attribute_data, &encoded_data[0], num_values,
|
||||||
point_ids.data());
|
num_components, point_ids.data())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prediction_scheme_ == nullptr ||
|
if (prediction_scheme_ == nullptr ||
|
||||||
|
|
|
@ -20,8 +20,9 @@ namespace draco {
|
||||||
|
|
||||||
bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder,
|
bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder,
|
||||||
int attribute_id) {
|
int attribute_id) {
|
||||||
if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id))
|
if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
// Currently this encoder works only for 3-component normal vectors.
|
// Currently this encoder works only for 3-component normal vectors.
|
||||||
if (attribute()->num_components() != 3) {
|
if (attribute()->num_components() != 3) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -47,14 +47,13 @@ class DirectBitDecoder {
|
||||||
|
|
||||||
// Decode the next |nbits| and return the sequence in |value|. |nbits| must be
|
// Decode the next |nbits| and return the sequence in |value|. |nbits| must be
|
||||||
// > 0 and <= 32.
|
// > 0 and <= 32.
|
||||||
void DecodeLeastSignificantBits32(int nbits, uint32_t *value) {
|
bool DecodeLeastSignificantBits32(int nbits, uint32_t *value) {
|
||||||
DRACO_DCHECK_EQ(true, nbits <= 32);
|
DRACO_DCHECK_EQ(true, nbits <= 32);
|
||||||
DRACO_DCHECK_EQ(true, nbits > 0);
|
DRACO_DCHECK_EQ(true, nbits > 0);
|
||||||
const int remaining = 32 - num_used_bits_;
|
const int remaining = 32 - num_used_bits_;
|
||||||
if (nbits <= remaining) {
|
if (nbits <= remaining) {
|
||||||
if (pos_ == bits_.end()) {
|
if (pos_ == bits_.end()) {
|
||||||
*value = 0;
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
*value = (*pos_ << num_used_bits_) >> (32 - nbits);
|
*value = (*pos_ << num_used_bits_) >> (32 - nbits);
|
||||||
num_used_bits_ += nbits;
|
num_used_bits_ += nbits;
|
||||||
|
@ -64,8 +63,7 @@ class DirectBitDecoder {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pos_ + 1 == bits_.end()) {
|
if (pos_ + 1 == bits_.end()) {
|
||||||
*value = 0;
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const uint32_t value_l = ((*pos_) << num_used_bits_);
|
const uint32_t value_l = ((*pos_) << num_used_bits_);
|
||||||
num_used_bits_ = nbits - remaining;
|
num_used_bits_ = nbits - remaining;
|
||||||
|
@ -73,6 +71,7 @@ class DirectBitDecoder {
|
||||||
const uint32_t value_r = (*pos_) >> (32 - num_used_bits_);
|
const uint32_t value_r = (*pos_) >> (32 - num_used_bits_);
|
||||||
*value = (value_l >> (32 - num_used_bits_ - remaining)) | value_r;
|
*value = (value_l >> (32 - num_used_bits_ - remaining)) | value_r;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EndDecoding() {}
|
void EndDecoding() {}
|
||||||
|
|
|
@ -65,6 +65,10 @@ class EncoderOptionsBase : public DracoOptions<AttributeKeyT> {
|
||||||
this->SetGlobalInt("encoding_speed", encoding_speed);
|
this->SetGlobalInt("encoding_speed", encoding_speed);
|
||||||
this->SetGlobalInt("decoding_speed", decoding_speed);
|
this->SetGlobalInt("decoding_speed", decoding_speed);
|
||||||
}
|
}
|
||||||
|
bool IsSpeedSet() const {
|
||||||
|
return this->IsGlobalOptionSet("encoding_speed") ||
|
||||||
|
this->IsGlobalOptionSet("decoding_speed");
|
||||||
|
}
|
||||||
|
|
||||||
// Sets a given feature as supported or unsupported by the target decoder.
|
// Sets a given feature as supported or unsupported by the target decoder.
|
||||||
// Encoder will always use only supported features when encoding the input
|
// Encoder will always use only supported features when encoding the input
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "draco/compression/encode.h"
|
||||||
#include "draco/core/draco_test_base.h"
|
#include "draco/core/draco_test_base.h"
|
||||||
#include "draco/core/draco_test_utils.h"
|
#include "draco/core/draco_test_utils.h"
|
||||||
#include "draco/io/file_utils.h"
|
#include "draco/io/file_utils.h"
|
||||||
|
#include "draco/io/obj_encoder.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -166,4 +168,78 @@ TEST_F(DecodeTest, TestSkipAttributeTransformWithNoQuantization) {
|
||||||
ASSERT_EQ(pos_att->GetAttributeTransformData(), nullptr);
|
ASSERT_EQ(pos_att->GetAttributeTransformData(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DecodeTest, TestSkipAttributeTransformUniqueId) {
|
||||||
|
// Tests that decoders preserve unique id of attributes even when their
|
||||||
|
// attribute transforms are skipped.
|
||||||
|
const std::string file_name = "cube_att.obj";
|
||||||
|
auto src_mesh = draco::ReadMeshFromTestFile(file_name);
|
||||||
|
ASSERT_NE(src_mesh, nullptr);
|
||||||
|
|
||||||
|
constexpr int kPosUniqueId = 7;
|
||||||
|
constexpr int kNormUniqueId = 42;
|
||||||
|
// Set unique ids for some of the attributes.
|
||||||
|
src_mesh
|
||||||
|
->attribute(
|
||||||
|
src_mesh->GetNamedAttributeId(draco::GeometryAttribute::POSITION))
|
||||||
|
->set_unique_id(kPosUniqueId);
|
||||||
|
src_mesh
|
||||||
|
->attribute(
|
||||||
|
src_mesh->GetNamedAttributeId(draco::GeometryAttribute::NORMAL))
|
||||||
|
->set_unique_id(kNormUniqueId);
|
||||||
|
|
||||||
|
draco::EncoderBuffer encoder_buffer;
|
||||||
|
draco::Encoder encoder;
|
||||||
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 10);
|
||||||
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 11);
|
||||||
|
encoder.EncodeMeshToBuffer(*src_mesh, &encoder_buffer);
|
||||||
|
|
||||||
|
// Create a draco decoding buffer.
|
||||||
|
draco::DecoderBuffer buffer;
|
||||||
|
buffer.Init(encoder_buffer.data(), encoder_buffer.size());
|
||||||
|
|
||||||
|
// First we decode the mesh without skipping the attribute transforms.
|
||||||
|
draco::Decoder decoder_no_skip;
|
||||||
|
std::unique_ptr<draco::Mesh> mesh_no_skip =
|
||||||
|
decoder_no_skip.DecodeMeshFromBuffer(&buffer).value();
|
||||||
|
ASSERT_NE(mesh_no_skip, nullptr);
|
||||||
|
|
||||||
|
// Now we decode it again while skipping some attributes.
|
||||||
|
draco::Decoder decoder_skip;
|
||||||
|
// Make sure we skip dequantization for the position and normal attribute.
|
||||||
|
decoder_skip.SetSkipAttributeTransform(draco::GeometryAttribute::POSITION);
|
||||||
|
decoder_skip.SetSkipAttributeTransform(draco::GeometryAttribute::NORMAL);
|
||||||
|
|
||||||
|
// Decode the input data into a geometry.
|
||||||
|
buffer.Init(encoder_buffer.data(), encoder_buffer.size());
|
||||||
|
std::unique_ptr<draco::Mesh> mesh_skip =
|
||||||
|
decoder_skip.DecodeMeshFromBuffer(&buffer).value();
|
||||||
|
ASSERT_NE(mesh_skip, nullptr);
|
||||||
|
|
||||||
|
// Compare the unique ids.
|
||||||
|
const draco::PointAttribute *const pos_att_no_skip =
|
||||||
|
mesh_no_skip->GetNamedAttribute(draco::GeometryAttribute::POSITION);
|
||||||
|
ASSERT_NE(pos_att_no_skip, nullptr);
|
||||||
|
ASSERT_EQ(pos_att_no_skip->data_type(), draco::DataType::DT_FLOAT32);
|
||||||
|
|
||||||
|
const draco::PointAttribute *const pos_att_skip =
|
||||||
|
mesh_skip->GetNamedAttribute(draco::GeometryAttribute::POSITION);
|
||||||
|
ASSERT_NE(pos_att_skip, nullptr);
|
||||||
|
ASSERT_EQ(pos_att_skip->data_type(), draco::DataType::DT_INT32);
|
||||||
|
|
||||||
|
const draco::PointAttribute *const norm_att_no_skip =
|
||||||
|
mesh_no_skip->GetNamedAttribute(draco::GeometryAttribute::NORMAL);
|
||||||
|
ASSERT_NE(norm_att_no_skip, nullptr);
|
||||||
|
ASSERT_EQ(norm_att_no_skip->data_type(), draco::DataType::DT_FLOAT32);
|
||||||
|
|
||||||
|
const draco::PointAttribute *const norm_att_skip =
|
||||||
|
mesh_skip->GetNamedAttribute(draco::GeometryAttribute::NORMAL);
|
||||||
|
ASSERT_NE(norm_att_skip, nullptr);
|
||||||
|
ASSERT_EQ(norm_att_skip->data_type(), draco::DataType::DT_INT32);
|
||||||
|
|
||||||
|
ASSERT_EQ(pos_att_skip->unique_id(), pos_att_no_skip->unique_id());
|
||||||
|
ASSERT_EQ(norm_att_skip->unique_id(), norm_att_no_skip->unique_id());
|
||||||
|
std::cout << pos_att_skip->unique_id() << " " << norm_att_skip->unique_id()
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2022 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#include "draco/compression/draco_compression_options.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
SpatialQuantizationOptions::SpatialQuantizationOptions(int quantization_bits) {
|
||||||
|
SetQuantizationBits(quantization_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpatialQuantizationOptions::SetQuantizationBits(int quantization_bits) {
|
||||||
|
mode_ = LOCAL_QUANTIZATION_BITS;
|
||||||
|
quantization_bits_ = quantization_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpatialQuantizationOptions::AreQuantizationBitsDefined() const {
|
||||||
|
return mode_ == LOCAL_QUANTIZATION_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpatialQuantizationOptions &SpatialQuantizationOptions::SetGrid(float spacing) {
|
||||||
|
mode_ = GLOBAL_GRID;
|
||||||
|
spacing_ = spacing;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpatialQuantizationOptions::operator==(
|
||||||
|
const SpatialQuantizationOptions &other) const {
|
||||||
|
if (mode_ != other.mode_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mode_ == LOCAL_QUANTIZATION_BITS) {
|
||||||
|
if (quantization_bits_ != other.quantization_bits_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (mode_ == GLOBAL_GRID) {
|
||||||
|
if (spacing_ != other.spacing_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright 2019 The Draco Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#ifndef DRACO_COMPRESSION_DRACO_COMPRESSION_OPTIONS_H_
|
||||||
|
#define DRACO_COMPRESSION_DRACO_COMPRESSION_OPTIONS_H_
|
||||||
|
|
||||||
|
#include "draco/draco_features.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#include "draco/core/status.h"
|
||||||
|
|
||||||
|
namespace draco {
|
||||||
|
|
||||||
|
// Quantization options for positions. Currently there are two modes for
|
||||||
|
// quantizing positions:
|
||||||
|
//
|
||||||
|
// 1. Quantization bits:
|
||||||
|
// - User defined number of quantization bits that is evenly distributed
|
||||||
|
// to cover the compressed geometry.
|
||||||
|
// 2. Grid:
|
||||||
|
// - Positions are snapped to a global grid defined by grid spacing.
|
||||||
|
// - This method is primarily intended to be used when the location of
|
||||||
|
// quantized vertices needs to be consistent between multiple
|
||||||
|
// geometries.
|
||||||
|
class SpatialQuantizationOptions {
|
||||||
|
public:
|
||||||
|
explicit SpatialQuantizationOptions(int quantization_bits);
|
||||||
|
|
||||||
|
// Sets quantization bits that are going to be used for the compressed
|
||||||
|
// geometry. If the geometry is a scene, the same number of quantization bits
|
||||||
|
// is going to be applied to each mesh of the scene. Quantized values are
|
||||||
|
// going to be distributed within the bounds of individual meshes.
|
||||||
|
void SetQuantizationBits(int quantization_bits);
|
||||||
|
|
||||||
|
// If this returns true, quantization_bits() should be used to get the
|
||||||
|
// desired number of quantization bits for compression. Otherwise the grid
|
||||||
|
// mode is selected and spacing() should be used to get the desired grid
|
||||||
|
// spacing.
|
||||||
|
bool AreQuantizationBitsDefined() const;
|
||||||
|
const int quantization_bits() const { return quantization_bits_; }
|
||||||
|
|
||||||
|
// Defines quantization grid used for the compressed geometry. All vertices
|
||||||
|
// are going to be snapped to the nearest grid vertex that corresponds to an
|
||||||
|
// integer quantized position. |spacing| defines the distance between two grid
|
||||||
|
// vertices. E.g. a grid with |spacing| = 10 would have grid vertices at
|
||||||
|
// locations {10 * i, 10 * j, 10 * k} where i, j, k are integer numbers.
|
||||||
|
SpatialQuantizationOptions &SetGrid(float spacing);
|
||||||
|
|
||||||
|
const float spacing() const { return spacing_; }
|
||||||
|
|
||||||
|
bool operator==(const SpatialQuantizationOptions &other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Mode { LOCAL_QUANTIZATION_BITS, GLOBAL_GRID };
|
||||||
|
Mode mode_ = LOCAL_QUANTIZATION_BITS;
|
||||||
|
int quantization_bits_; // Default quantization bits for positions.
|
||||||
|
float spacing_ = 0.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO(fgalligan): Add support for unified_position_quantization.
|
||||||
|
// Struct to hold Draco compression options.
|
||||||
|
struct DracoCompressionOptions {
|
||||||
|
int compression_level = 7; // compression level [0-10], most=10, least=0.
|
||||||
|
SpatialQuantizationOptions quantization_position{11};
|
||||||
|
int quantization_bits_normal = 8;
|
||||||
|
int quantization_bits_tex_coord = 10;
|
||||||
|
int quantization_bits_color = 8;
|
||||||
|
int quantization_bits_generic = 8;
|
||||||
|
int quantization_bits_tangent = 8;
|
||||||
|
int quantization_bits_weight = 8;
|
||||||
|
bool find_non_degenerate_texture_quantization = false;
|
||||||
|
|
||||||
|
bool operator==(const DracoCompressionOptions &other) const {
|
||||||
|
return compression_level == other.compression_level &&
|
||||||
|
quantization_position == other.quantization_position &&
|
||||||
|
quantization_bits_normal == other.quantization_bits_normal &&
|
||||||
|
quantization_bits_tex_coord == other.quantization_bits_tex_coord &&
|
||||||
|
quantization_bits_color == other.quantization_bits_color &&
|
||||||
|
quantization_bits_generic == other.quantization_bits_generic &&
|
||||||
|
quantization_bits_tangent == other.quantization_bits_tangent &&
|
||||||
|
quantization_bits_weight == other.quantization_bits_weight &&
|
||||||
|
find_non_degenerate_texture_quantization ==
|
||||||
|
other.find_non_degenerate_texture_quantization;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const DracoCompressionOptions &other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status Check() const {
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Compression level", compression_level, 0, 10));
|
||||||
|
if (quantization_position.AreQuantizationBitsDefined()) {
|
||||||
|
DRACO_RETURN_IF_ERROR(Validate("Position quantization",
|
||||||
|
quantization_position.quantization_bits(),
|
||||||
|
0, 30));
|
||||||
|
} else {
|
||||||
|
if (quantization_position.spacing() <= 0.f) {
|
||||||
|
return ErrorStatus("Position quantization spacing is invalid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Normals quantization", quantization_bits_normal, 0, 30));
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Tex coord quantization", quantization_bits_tex_coord, 0, 30));
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Color quantization", quantization_bits_color, 0, 30));
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Generic quantization", quantization_bits_generic, 0, 30));
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Tangent quantization", quantization_bits_tangent, 0, 30));
|
||||||
|
DRACO_RETURN_IF_ERROR(
|
||||||
|
Validate("Weights quantization", quantization_bits_weight, 0, 30));
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Status Validate(const std::string &name, int value, int min, int max) {
|
||||||
|
if (value < min || value > max) {
|
||||||
|
const std::string range =
|
||||||
|
"[" + std::to_string(min) + "-" + std::to_string(max) + "].";
|
||||||
|
return Status(Status::DRACO_ERROR, name + " is out of range " + range);
|
||||||
|
}
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace draco
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#endif // DRACO_COMPRESSION_DRACO_COMPRESSION_OPTIONS_H_
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "draco/compression/draco_compression_options.h"
|
||||||
|
|
||||||
|
#include "draco/core/draco_test_utils.h"
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(DracoCompressionOptionsTest, TestPositionQuantizationBits) {
|
||||||
|
// Test verifies that we can define draco compression options using
|
||||||
|
// quantization bits.
|
||||||
|
draco::SpatialQuantizationOptions options(10);
|
||||||
|
|
||||||
|
// Quantization bits should be used by default.
|
||||||
|
ASSERT_TRUE(options.AreQuantizationBitsDefined());
|
||||||
|
ASSERT_EQ(options.quantization_bits(), 10);
|
||||||
|
|
||||||
|
// Change the quantization bits.
|
||||||
|
options.SetQuantizationBits(9);
|
||||||
|
ASSERT_TRUE(options.AreQuantizationBitsDefined());
|
||||||
|
ASSERT_EQ(options.quantization_bits(), 9);
|
||||||
|
|
||||||
|
// If we select the grid, quantization bits should not be used.
|
||||||
|
options.SetGrid(0.5f);
|
||||||
|
ASSERT_FALSE(options.AreQuantizationBitsDefined());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DracoCompressionOptionsTest, TestPositionQuantizationGrid) {
|
||||||
|
// Test verifies that we can define draco compression options using
|
||||||
|
// quantization grid.
|
||||||
|
draco::SpatialQuantizationOptions options(10);
|
||||||
|
|
||||||
|
// Quantization bits should be used by default.
|
||||||
|
ASSERT_TRUE(options.AreQuantizationBitsDefined());
|
||||||
|
|
||||||
|
// Set the grid parameters.
|
||||||
|
options.SetGrid(0.25f);
|
||||||
|
ASSERT_FALSE(options.AreQuantizationBitsDefined());
|
||||||
|
|
||||||
|
ASSERT_EQ(options.spacing(), 0.25f);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
|
@ -129,7 +129,6 @@ class Encoder
|
||||||
// call of EncodePointCloudToBuffer or EncodeMeshToBuffer is going to fail.
|
// call of EncodePointCloudToBuffer or EncodeMeshToBuffer is going to fail.
|
||||||
void SetEncodingMethod(int encoding_method);
|
void SetEncodingMethod(int encoding_method);
|
||||||
|
|
||||||
protected:
|
|
||||||
// Creates encoder options for the expert encoder used during the actual
|
// Creates encoder options for the expert encoder used during the actual
|
||||||
// encoding.
|
// encoding.
|
||||||
EncoderOptions CreateExpertEncoderOptions(const PointCloud &pc) const;
|
EncoderOptions CreateExpertEncoderOptions(const PointCloud &pc) const;
|
||||||
|
|
|
@ -98,7 +98,7 @@ class EncoderBase {
|
||||||
"Invalid prediction scheme for attribute type.");
|
"Invalid prediction scheme for attribute type.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(hemmer): Try to enable more prediction schemes for normals.
|
// TODO(b/199760123): Try to enable more prediction schemes for normals.
|
||||||
if (att_type == GeometryAttribute::NORMAL) {
|
if (att_type == GeometryAttribute::NORMAL) {
|
||||||
if (!(prediction_scheme == PREDICTION_DIFFERENCE ||
|
if (!(prediction_scheme == PREDICTION_DIFFERENCE ||
|
||||||
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
|
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "draco/core/draco_test_base.h"
|
#include "draco/core/draco_test_base.h"
|
||||||
#include "draco/core/draco_test_utils.h"
|
#include "draco/core/draco_test_utils.h"
|
||||||
#include "draco/core/vector_d.h"
|
#include "draco/core/vector_d.h"
|
||||||
|
#include "draco/io/file_utils.h"
|
||||||
#include "draco/io/obj_decoder.h"
|
#include "draco/io/obj_decoder.h"
|
||||||
#include "draco/mesh/triangle_soup_mesh_builder.h"
|
#include "draco/mesh/triangle_soup_mesh_builder.h"
|
||||||
#include "draco/point_cloud/point_cloud_builder.h"
|
#include "draco/point_cloud/point_cloud_builder.h"
|
||||||
|
@ -213,16 +214,14 @@ class EncodeTest : public ::testing::Test {
|
||||||
draco::Decoder decoder;
|
draco::Decoder decoder;
|
||||||
|
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
auto maybe_mesh = decoder.DecodeMeshFromBuffer(&decoder_buffer);
|
DRACO_ASSIGN_OR_ASSERT(auto decoded_mesh,
|
||||||
ASSERT_TRUE(maybe_mesh.ok());
|
decoder.DecodeMeshFromBuffer(&decoder_buffer));
|
||||||
auto decoded_mesh = std::move(maybe_mesh).value();
|
|
||||||
ASSERT_NE(decoded_mesh, nullptr);
|
ASSERT_NE(decoded_mesh, nullptr);
|
||||||
ASSERT_EQ(decoded_mesh->num_points(), encoder.num_encoded_points());
|
ASSERT_EQ(decoded_mesh->num_points(), encoder.num_encoded_points());
|
||||||
ASSERT_EQ(decoded_mesh->num_faces(), encoder.num_encoded_faces());
|
ASSERT_EQ(decoded_mesh->num_faces(), encoder.num_encoded_faces());
|
||||||
} else {
|
} else {
|
||||||
auto maybe_pc = decoder.DecodePointCloudFromBuffer(&decoder_buffer);
|
DRACO_ASSIGN_OR_ASSERT(
|
||||||
ASSERT_TRUE(maybe_pc.ok());
|
auto decoded_pc, decoder.DecodePointCloudFromBuffer(&decoder_buffer));
|
||||||
auto decoded_pc = std::move(maybe_pc).value();
|
|
||||||
ASSERT_EQ(decoded_pc->num_points(), encoder.num_encoded_points());
|
ASSERT_EQ(decoded_pc->num_points(), encoder.num_encoded_points());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,7 +273,7 @@ TEST_F(EncodeTest, TestLinesObj) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 16);
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 16);
|
||||||
|
|
||||||
draco::EncoderBuffer buffer;
|
draco::EncoderBuffer buffer;
|
||||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(EncodeTest, TestQuantizedInfinity) {
|
TEST_F(EncodeTest, TestQuantizedInfinity) {
|
||||||
|
@ -315,7 +314,7 @@ TEST_F(EncodeTest, TestUnquantizedInfinity) {
|
||||||
encoder.SetEncodingMethod(draco::POINT_CLOUD_SEQUENTIAL_ENCODING);
|
encoder.SetEncodingMethod(draco::POINT_CLOUD_SEQUENTIAL_ENCODING);
|
||||||
|
|
||||||
draco::EncoderBuffer buffer;
|
draco::EncoderBuffer buffer;
|
||||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(EncodeTest, TestQuantizedAndUnquantizedAttributes) {
|
TEST_F(EncodeTest, TestQuantizedAndUnquantizedAttributes) {
|
||||||
|
@ -330,7 +329,7 @@ TEST_F(EncodeTest, TestQuantizedAndUnquantizedAttributes) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 11);
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 11);
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 0);
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 0);
|
||||||
draco::EncoderBuffer buffer;
|
draco::EncoderBuffer buffer;
|
||||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(EncodeTest, TestKdTreeEncoding) {
|
TEST_F(EncodeTest, TestKdTreeEncoding) {
|
||||||
|
@ -348,7 +347,7 @@ TEST_F(EncodeTest, TestKdTreeEncoding) {
|
||||||
// Now set quantization for the position attribute which should make
|
// Now set quantization for the position attribute which should make
|
||||||
// the encoder happy.
|
// the encoder happy.
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 16);
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 16);
|
||||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(EncodeTest, TestTrackingOfNumberOfEncodedEntries) {
|
TEST_F(EncodeTest, TestTrackingOfNumberOfEncodedEntries) {
|
||||||
|
@ -373,7 +372,7 @@ TEST_F(EncodeTest, TestTrackingOfNumberOfEncodedEntriesNotSet) {
|
||||||
draco::EncoderBuffer buffer;
|
draco::EncoderBuffer buffer;
|
||||||
draco::Encoder encoder;
|
draco::Encoder encoder;
|
||||||
|
|
||||||
ASSERT_TRUE(encoder.EncodeMeshToBuffer(*mesh, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer));
|
||||||
ASSERT_EQ(encoder.num_encoded_points(), 0);
|
ASSERT_EQ(encoder.num_encoded_points(), 0);
|
||||||
ASSERT_EQ(encoder.num_encoded_faces(), 0);
|
ASSERT_EQ(encoder.num_encoded_faces(), 0);
|
||||||
}
|
}
|
||||||
|
@ -404,4 +403,170 @@ TEST_F(EncodeTest, TestNoPosQuantizationNormalCoding) {
|
||||||
ASSERT_NE(decoded_mesh, nullptr);
|
ASSERT_NE(decoded_mesh, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
TEST_F(EncodeTest, TestDracoCompressionOptions) {
|
||||||
|
// This test verifies that we can set the encoder's compression options via
|
||||||
|
// draco::Mesh's compression options.
|
||||||
|
const auto mesh = draco::ReadMeshFromTestFile("test_nm.obj");
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
|
||||||
|
// First set compression level and quantization manually.
|
||||||
|
draco::Encoder encoder_manual;
|
||||||
|
draco::EncoderBuffer buffer_manual;
|
||||||
|
encoder_manual.SetAttributeQuantization(draco::GeometryAttribute::POSITION,
|
||||||
|
8);
|
||||||
|
encoder_manual.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 7);
|
||||||
|
encoder_manual.SetSpeedOptions(4, 4);
|
||||||
|
|
||||||
|
DRACO_ASSERT_OK(encoder_manual.EncodeMeshToBuffer(*mesh, &buffer_manual));
|
||||||
|
|
||||||
|
// Now do the same with options provided via DracoCompressionOptions.
|
||||||
|
draco::DracoCompressionOptions compression_options;
|
||||||
|
compression_options.compression_level = 6;
|
||||||
|
compression_options.quantization_position.SetQuantizationBits(8);
|
||||||
|
compression_options.quantization_bits_normal = 7;
|
||||||
|
mesh->SetCompressionOptions(compression_options);
|
||||||
|
mesh->SetCompressionEnabled(true);
|
||||||
|
|
||||||
|
draco::Encoder encoder_auto;
|
||||||
|
draco::EncoderBuffer buffer_auto;
|
||||||
|
DRACO_ASSERT_OK(encoder_auto.EncodeMeshToBuffer(*mesh, &buffer_auto));
|
||||||
|
|
||||||
|
// Ensure that both encoders produce the same result.
|
||||||
|
ASSERT_EQ(buffer_manual.size(), buffer_auto.size());
|
||||||
|
|
||||||
|
// Now change some of the mesh's compression settings and ensure the
|
||||||
|
// compression changes as well.
|
||||||
|
compression_options.compression_level = 7;
|
||||||
|
mesh->SetCompressionOptions(compression_options);
|
||||||
|
buffer_auto.Clear();
|
||||||
|
DRACO_ASSERT_OK(encoder_auto.EncodeMeshToBuffer(*mesh, &buffer_auto));
|
||||||
|
ASSERT_NE(buffer_manual.size(), buffer_auto.size());
|
||||||
|
|
||||||
|
// Check that |mesh| compression options do not override the encoder options.
|
||||||
|
mesh->GetCompressionOptions().compression_level = 10;
|
||||||
|
mesh->GetCompressionOptions().quantization_position.SetQuantizationBits(10);
|
||||||
|
mesh->GetCompressionOptions().quantization_bits_normal = 10;
|
||||||
|
draco::EncoderBuffer buffer;
|
||||||
|
DRACO_ASSERT_OK(encoder_manual.EncodeMeshToBuffer(*mesh, &buffer));
|
||||||
|
ASSERT_EQ(buffer.size(), buffer_manual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EncodeTest, TestDracoCompressionOptionsManualOverride) {
|
||||||
|
// This test verifies that we can use encoder's option to override compression
|
||||||
|
// options provided in draco::Mesh's compression options.
|
||||||
|
const auto mesh = draco::ReadMeshFromTestFile("test_nm.obj");
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
|
||||||
|
// Set some compression options.
|
||||||
|
draco::DracoCompressionOptions compression_options;
|
||||||
|
compression_options.compression_level = 6;
|
||||||
|
compression_options.quantization_position.SetQuantizationBits(8);
|
||||||
|
compression_options.quantization_bits_normal = 7;
|
||||||
|
mesh->SetCompressionOptions(compression_options);
|
||||||
|
mesh->SetCompressionEnabled(true);
|
||||||
|
|
||||||
|
draco::Encoder encoder;
|
||||||
|
draco::EncoderBuffer buffer_no_override;
|
||||||
|
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer_no_override));
|
||||||
|
|
||||||
|
// Now override some options and ensure the compression is different.
|
||||||
|
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 5);
|
||||||
|
draco::EncoderBuffer buffer_with_override;
|
||||||
|
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer_with_override));
|
||||||
|
ASSERT_LT(buffer_with_override.size(), buffer_no_override.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EncodeTest, TestDracoCompressionOptionsGridQuantization) {
|
||||||
|
// Test verifies that we can set position quantization via grid spacing.
|
||||||
|
|
||||||
|
// 1x1x1 cube.
|
||||||
|
const auto mesh = draco::ReadMeshFromTestFile("cube_att.obj");
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
mesh->SetCompressionEnabled(true);
|
||||||
|
|
||||||
|
// Set grid quantization for positions.
|
||||||
|
draco::DracoCompressionOptions compression_options;
|
||||||
|
// This should result in 10x10x10 quantization.
|
||||||
|
compression_options.quantization_position.SetGrid(0.1);
|
||||||
|
mesh->SetCompressionOptions(compression_options);
|
||||||
|
|
||||||
|
draco::ExpertEncoder encoder(*mesh);
|
||||||
|
draco::EncoderBuffer buffer;
|
||||||
|
DRACO_ASSERT_OK(encoder.EncodeToBuffer(&buffer));
|
||||||
|
|
||||||
|
// The grid options should be reflected in the |encoder|. Check that the
|
||||||
|
// computed values are correct.
|
||||||
|
const int pos_att_id =
|
||||||
|
mesh->GetNamedAttributeId(draco::GeometryAttribute::POSITION);
|
||||||
|
draco::Vector3f origin;
|
||||||
|
encoder.options().GetAttributeVector(pos_att_id, "quantization_origin", 3,
|
||||||
|
&origin[0]);
|
||||||
|
ASSERT_EQ(origin, draco::Vector3f(0.f, 0.f, 0.f));
|
||||||
|
|
||||||
|
// We need 4 quantization bits (for 10 values).
|
||||||
|
ASSERT_EQ(
|
||||||
|
encoder.options().GetAttributeInt(pos_att_id, "quantization_bits", -1),
|
||||||
|
4);
|
||||||
|
|
||||||
|
// The quantization range should be ((1 << quantization_bits) - 1) * spacing.
|
||||||
|
ASSERT_NEAR(encoder.options().GetAttributeFloat(pos_att_id,
|
||||||
|
"quantization_range", 0.f),
|
||||||
|
15.f * 0.1f, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EncodeTest, TestDracoCompressionOptionsGridQuantizationWithOffset) {
|
||||||
|
// Test verifies that we can set position quantization via grid spacing when
|
||||||
|
// the geometry is not perfectly aligned with the quantization grid.
|
||||||
|
|
||||||
|
// 1x1x1 cube.
|
||||||
|
const auto mesh = draco::ReadMeshFromTestFile("cube_att.obj");
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
|
||||||
|
// Move all positions a bit.
|
||||||
|
auto *pos_att = mesh->attribute(
|
||||||
|
mesh->GetNamedAttributeId(draco::GeometryAttribute::POSITION));
|
||||||
|
for (draco::AttributeValueIndex avi(0); avi < pos_att->size(); ++avi) {
|
||||||
|
draco::Vector3f pos;
|
||||||
|
pos_att->GetValue(avi, &pos[0]);
|
||||||
|
pos = pos + draco::Vector3f(-0.55f, 0.65f, 10.75f);
|
||||||
|
pos_att->SetAttributeValue(avi, &pos[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh->SetCompressionEnabled(true);
|
||||||
|
|
||||||
|
// Set grid quantization for positions.
|
||||||
|
draco::DracoCompressionOptions compression_options;
|
||||||
|
// This should result in 16x16x16 quantization if the grid was perfectly
|
||||||
|
// aligned but since it is not we should expect 17 or 18 values per component.
|
||||||
|
compression_options.quantization_position.SetGrid(0.0625f);
|
||||||
|
mesh->SetCompressionOptions(compression_options);
|
||||||
|
|
||||||
|
draco::ExpertEncoder encoder(*mesh);
|
||||||
|
draco::EncoderBuffer buffer;
|
||||||
|
DRACO_ASSERT_OK(encoder.EncodeToBuffer(&buffer));
|
||||||
|
|
||||||
|
// The grid options should be reflected in the |encoder|. Check that the
|
||||||
|
// computed values are correct.
|
||||||
|
const int pos_att_id =
|
||||||
|
mesh->GetNamedAttributeId(draco::GeometryAttribute::POSITION);
|
||||||
|
draco::Vector3f origin;
|
||||||
|
encoder.options().GetAttributeVector(pos_att_id, "quantization_origin", 3,
|
||||||
|
&origin[0]);
|
||||||
|
// The origin is the first lower value on the quantization grid for each
|
||||||
|
// component of the mesh.
|
||||||
|
ASSERT_EQ(origin, draco::Vector3f(-0.5625f, 0.625f, 10.75f));
|
||||||
|
|
||||||
|
// We need 5 quantization bits (for 17-18 values).
|
||||||
|
ASSERT_EQ(
|
||||||
|
encoder.options().GetAttributeInt(pos_att_id, "quantization_bits", -1),
|
||||||
|
5);
|
||||||
|
|
||||||
|
// The quantization range should be ((1 << quantization_bits) - 1) * spacing.
|
||||||
|
ASSERT_NEAR(encoder.options().GetAttributeFloat(pos_att_id,
|
||||||
|
"quantization_range", 0.f),
|
||||||
|
31.f * 0.0625f, 1e-6f);
|
||||||
|
}
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -391,7 +391,6 @@ class RAnsEncoder {
|
||||||
ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE;
|
ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE;
|
||||||
ans_.state /= DRACO_ANS_IO_BASE;
|
ans_.state /= DRACO_ANS_IO_BASE;
|
||||||
}
|
}
|
||||||
// TODO(ostava): The division and multiplication should be optimized.
|
|
||||||
ans_.state =
|
ans_.state =
|
||||||
(ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob;
|
(ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,13 @@ bool RAnsSymbolDecoder<unique_symbols_bit_length_t>::Create(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check that decoded number of symbols is not unreasonably high. Remaining
|
||||||
|
// buffer size must be at least |num_symbols| / 64 bytes to contain the
|
||||||
|
// probability table. The |prob_data| below is one byte but it can be
|
||||||
|
// theoretically stored for each 64th symbol.
|
||||||
|
if (num_symbols_ / 64 > buffer->remaining_size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
probability_table_.resize(num_symbols_);
|
probability_table_.resize(num_symbols_);
|
||||||
if (num_symbols_ == 0) {
|
if (num_symbols_ == 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -125,8 +125,8 @@ bool RAnsSymbolEncoder<unique_symbols_bit_length_t>::Create(
|
||||||
for (int i = 0; i < num_symbols; ++i) {
|
for (int i = 0; i < num_symbols; ++i) {
|
||||||
sorted_probabilities[i] = i;
|
sorted_probabilities[i] = i;
|
||||||
}
|
}
|
||||||
std::sort(sorted_probabilities.begin(), sorted_probabilities.end(),
|
std::stable_sort(sorted_probabilities.begin(), sorted_probabilities.end(),
|
||||||
ProbabilityLess(&probability_table_));
|
ProbabilityLess(&probability_table_));
|
||||||
if (total_rans_prob < rans_precision_) {
|
if (total_rans_prob < rans_precision_) {
|
||||||
// This happens rather infrequently, just add the extra needed precision
|
// This happens rather infrequently, just add the extra needed precision
|
||||||
// to the most frequent symbol.
|
// to the most frequent symbol.
|
||||||
|
|
|
@ -72,7 +72,7 @@ bool DecodeTaggedSymbols(uint32_t num_values, int num_components,
|
||||||
int value_id = 0;
|
int value_id = 0;
|
||||||
for (uint32_t i = 0; i < num_values; i += num_components) {
|
for (uint32_t i = 0; i < num_values; i += num_components) {
|
||||||
// Decode the tag.
|
// Decode the tag.
|
||||||
const int bit_length = tag_decoder.DecodeSymbol();
|
const uint32_t bit_length = tag_decoder.DecodeSymbol();
|
||||||
// Decode the actual value.
|
// Decode the actual value.
|
||||||
for (int j = 0; j < num_components; ++j) {
|
for (int j = 0; j < num_components; ++j) {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
//
|
//
|
||||||
#include "draco/compression/expert_encode.h"
|
#include "draco/compression/expert_encode.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "draco/compression/mesh/mesh_edgebreaker_encoder.h"
|
#include "draco/compression/mesh/mesh_edgebreaker_encoder.h"
|
||||||
#include "draco/compression/mesh/mesh_sequential_encoder.h"
|
#include "draco/compression/mesh/mesh_sequential_encoder.h"
|
||||||
#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED
|
#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED
|
||||||
|
@ -21,6 +27,9 @@
|
||||||
#include "draco/compression/point_cloud/point_cloud_sequential_encoder.h"
|
#include "draco/compression/point_cloud/point_cloud_sequential_encoder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
#include "draco/core/bit_utils.h"
|
||||||
|
#endif
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
|
||||||
ExpertEncoder::ExpertEncoder(const PointCloud &point_cloud)
|
ExpertEncoder::ExpertEncoder(const PointCloud &point_cloud)
|
||||||
|
@ -101,6 +110,11 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
|
||||||
|
|
||||||
Status ExpertEncoder::EncodeMeshToBuffer(const Mesh &m,
|
Status ExpertEncoder::EncodeMeshToBuffer(const Mesh &m,
|
||||||
EncoderBuffer *out_buffer) {
|
EncoderBuffer *out_buffer) {
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// Apply DracoCompressionOptions associated with the mesh.
|
||||||
|
DRACO_RETURN_IF_ERROR(ApplyCompressionOptions(m));
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
std::unique_ptr<MeshEncoder> encoder;
|
std::unique_ptr<MeshEncoder> encoder;
|
||||||
// Select the encoding method only based on the provided options.
|
// Select the encoding method only based on the provided options.
|
||||||
int encoding_method = options().GetGlobalInt("encoding_method", -1);
|
int encoding_method = options().GetGlobalInt("encoding_method", -1);
|
||||||
|
@ -118,6 +132,7 @@ Status ExpertEncoder::EncodeMeshToBuffer(const Mesh &m,
|
||||||
encoder = std::unique_ptr<MeshEncoder>(new MeshSequentialEncoder());
|
encoder = std::unique_ptr<MeshEncoder>(new MeshSequentialEncoder());
|
||||||
}
|
}
|
||||||
encoder->SetMesh(m);
|
encoder->SetMesh(m);
|
||||||
|
|
||||||
DRACO_RETURN_IF_ERROR(encoder->Encode(options(), out_buffer));
|
DRACO_RETURN_IF_ERROR(encoder->Encode(options(), out_buffer));
|
||||||
|
|
||||||
set_num_encoded_points(encoder->num_encoded_points());
|
set_num_encoded_points(encoder->num_encoded_points());
|
||||||
|
@ -179,4 +194,107 @@ Status ExpertEncoder::SetAttributePredictionScheme(
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
Status ExpertEncoder::ApplyCompressionOptions(const Mesh &mesh) {
|
||||||
|
if (!mesh.IsCompressionEnabled()) {
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
const auto &compression_options = mesh.GetCompressionOptions();
|
||||||
|
|
||||||
|
// Set any encoder options that haven't been explicitly set by users (don't
|
||||||
|
// override existing options).
|
||||||
|
if (!options().IsSpeedSet()) {
|
||||||
|
options().SetSpeed(10 - compression_options.compression_level,
|
||||||
|
10 - compression_options.compression_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ai = 0; ai < mesh.num_attributes(); ++ai) {
|
||||||
|
if (options().IsAttributeOptionSet(ai, "quantization_bits")) {
|
||||||
|
continue; // Don't override options that have been set.
|
||||||
|
}
|
||||||
|
int quantization_bits = 0;
|
||||||
|
const auto type = mesh.attribute(ai)->attribute_type();
|
||||||
|
switch (type) {
|
||||||
|
case GeometryAttribute::POSITION:
|
||||||
|
if (compression_options.quantization_position
|
||||||
|
.AreQuantizationBitsDefined()) {
|
||||||
|
quantization_bits =
|
||||||
|
compression_options.quantization_position.quantization_bits();
|
||||||
|
} else {
|
||||||
|
DRACO_RETURN_IF_ERROR(ApplyGridQuantization(mesh, ai));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GeometryAttribute::TEX_COORD:
|
||||||
|
quantization_bits = compression_options.quantization_bits_tex_coord;
|
||||||
|
break;
|
||||||
|
case GeometryAttribute::NORMAL:
|
||||||
|
quantization_bits = compression_options.quantization_bits_normal;
|
||||||
|
break;
|
||||||
|
case GeometryAttribute::COLOR:
|
||||||
|
quantization_bits = compression_options.quantization_bits_color;
|
||||||
|
break;
|
||||||
|
case GeometryAttribute::TANGENT:
|
||||||
|
quantization_bits = compression_options.quantization_bits_tangent;
|
||||||
|
break;
|
||||||
|
case GeometryAttribute::WEIGHTS:
|
||||||
|
quantization_bits = compression_options.quantization_bits_weight;
|
||||||
|
break;
|
||||||
|
case GeometryAttribute::GENERIC:
|
||||||
|
quantization_bits = compression_options.quantization_bits_generic;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (quantization_bits > 0) {
|
||||||
|
options().SetAttributeInt(ai, "quantization_bits", quantization_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
Status ExpertEncoder::ApplyGridQuantization(const Mesh &mesh,
|
||||||
|
int attribute_index) {
|
||||||
|
const auto compression_options = mesh.GetCompressionOptions();
|
||||||
|
if (mesh.attribute(attribute_index)->num_components() != 3) {
|
||||||
|
return ErrorStatus(
|
||||||
|
"Invalid number of components: Grid quantization is currently "
|
||||||
|
"supported only for 3D positions.");
|
||||||
|
}
|
||||||
|
const float spacing = compression_options.quantization_position.spacing();
|
||||||
|
// Compute quantization properties based on the grid spacing.
|
||||||
|
const auto &bbox = mesh.ComputeBoundingBox();
|
||||||
|
// Snap min and max points of the |bbox| to the quantization grid vertices.
|
||||||
|
Vector3f min_pos;
|
||||||
|
int num_values = 0; // Number of values that we need to encode.
|
||||||
|
for (int c = 0; c < 3; ++c) {
|
||||||
|
// Min / max position on grid vertices in grid coordinates.
|
||||||
|
const float min_grid_pos = floor(bbox.GetMinPoint()[c] / spacing);
|
||||||
|
const float max_grid_pos = ceil(bbox.GetMaxPoint()[c] / spacing);
|
||||||
|
|
||||||
|
// Min pos on grid vertex in mesh coordinates.
|
||||||
|
min_pos[c] = min_grid_pos * spacing;
|
||||||
|
|
||||||
|
const float component_num_values =
|
||||||
|
static_cast<int>(max_grid_pos) - static_cast<int>(min_grid_pos) + 1;
|
||||||
|
if (component_num_values > num_values) {
|
||||||
|
num_values = component_num_values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now compute the number of bits needed to encode |num_values|.
|
||||||
|
int bits = MostSignificantBit(num_values);
|
||||||
|
if ((1 << bits) < num_values) {
|
||||||
|
// If the |num_values| is larger than number of values representable by
|
||||||
|
// |bits|, we need to use one more bit. This will be almost always true
|
||||||
|
// unless |num_values| was equal to 1 << |bits|.
|
||||||
|
bits++;
|
||||||
|
}
|
||||||
|
// Compute the range in mesh coordinates that matches the quantization bits.
|
||||||
|
// Note there are n-1 intervals between the |n| quantization values.
|
||||||
|
const float range = ((1 << bits) - 1) * spacing;
|
||||||
|
SetAttributeExplicitQuantization(attribute_index, bits, 3, min_pos.data(),
|
||||||
|
range);
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
|
|
@ -138,6 +138,12 @@ class ExpertEncoder : public EncoderBase<EncoderOptions> {
|
||||||
|
|
||||||
Status EncodeMeshToBuffer(const Mesh &m, EncoderBuffer *out_buffer);
|
Status EncodeMeshToBuffer(const Mesh &m, EncoderBuffer *out_buffer);
|
||||||
|
|
||||||
|
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||||
|
// Applies compression options stored in |mesh|.
|
||||||
|
Status ApplyCompressionOptions(const Mesh &mesh);
|
||||||
|
Status ApplyGridQuantization(const Mesh &mesh, int attribute_index);
|
||||||
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
|
||||||
const PointCloud *point_cloud_;
|
const PointCloud *point_cloud_;
|
||||||
const Mesh *mesh_;
|
const Mesh *mesh_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -454,7 +454,7 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Decode connectivity of non-position attributes.
|
// Decode connectivity of non-position attributes.
|
||||||
if (attribute_data_.size() > 0) {
|
if (!attribute_data_.empty()) {
|
||||||
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
||||||
if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) {
|
if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) {
|
||||||
for (CornerIndex ci(0); ci < corner_table_->num_corners(); ci += 3) {
|
for (CornerIndex ci(0); ci < corner_table_->num_corners(); ci += 3) {
|
||||||
|
@ -484,7 +484,10 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity() {
|
||||||
attribute_data_[i].connectivity_data.AddSeamEdge(CornerIndex(c));
|
attribute_data_[i].connectivity_data.AddSeamEdge(CornerIndex(c));
|
||||||
}
|
}
|
||||||
// Recompute vertices from the newly added seam edges.
|
// Recompute vertices from the newly added seam edges.
|
||||||
attribute_data_[i].connectivity_data.RecomputeVertices(nullptr, nullptr);
|
if (!attribute_data_[i].connectivity_data.RecomputeVertices(nullptr,
|
||||||
|
nullptr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_encoding_data_.Init(corner_table_->num_vertices());
|
pos_encoding_data_.Init(corner_table_->num_vertices());
|
||||||
|
@ -574,6 +577,17 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
const CornerIndex corner_b =
|
const CornerIndex corner_b =
|
||||||
corner_table_->Next(corner_table_->LeftMostCorner(vertex_x));
|
corner_table_->Next(corner_table_->LeftMostCorner(vertex_x));
|
||||||
|
|
||||||
|
if (corner_a == corner_b) {
|
||||||
|
// All matched corners must be different.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (corner_table_->Opposite(corner_a) != kInvalidCornerIndex ||
|
||||||
|
corner_table_->Opposite(corner_b) != kInvalidCornerIndex) {
|
||||||
|
// One of the corners is already opposite to an existing face, which
|
||||||
|
// should not happen unless the input was tampered with.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// New tip corner.
|
// New tip corner.
|
||||||
const CornerIndex corner(3 * face.value());
|
const CornerIndex corner(3 * face.value());
|
||||||
// Update opposite corner mappings.
|
// Update opposite corner mappings.
|
||||||
|
@ -616,6 +630,11 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
const CornerIndex corner_a = active_corner_stack.back();
|
const CornerIndex corner_a = active_corner_stack.back();
|
||||||
|
if (corner_table_->Opposite(corner_a) != kInvalidCornerIndex) {
|
||||||
|
// Active corner is already opposite to an existing face, which should
|
||||||
|
// not happen unless the input was tampered with.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// First corner on the new face is either corner "l" or "r".
|
// First corner on the new face is either corner "l" or "r".
|
||||||
const CornerIndex corner(3 * face.value());
|
const CornerIndex corner(3 * face.value());
|
||||||
|
@ -681,10 +700,14 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
}
|
}
|
||||||
const CornerIndex corner_a = active_corner_stack.back();
|
const CornerIndex corner_a = active_corner_stack.back();
|
||||||
|
|
||||||
|
if (corner_a == corner_b) {
|
||||||
|
// All matched corners must be different.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (corner_table_->Opposite(corner_a) != kInvalidCornerIndex ||
|
if (corner_table_->Opposite(corner_a) != kInvalidCornerIndex ||
|
||||||
corner_table_->Opposite(corner_b) != kInvalidCornerIndex) {
|
corner_table_->Opposite(corner_b) != kInvalidCornerIndex) {
|
||||||
// One of the corners is already opposite to an existing face, which
|
// One of the corners is already opposite to an existing face, which
|
||||||
// should not happen unless the input was tempered with.
|
// should not happen unless the input was tampered with.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,9 +736,15 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
|
|
||||||
// Also update the vertex id at corner "n" and all corners that are
|
// Also update the vertex id at corner "n" and all corners that are
|
||||||
// connected to it in the CCW direction.
|
// connected to it in the CCW direction.
|
||||||
|
const CornerIndex first_corner = corner_n;
|
||||||
while (corner_n != kInvalidCornerIndex) {
|
while (corner_n != kInvalidCornerIndex) {
|
||||||
corner_table_->MapCornerToVertex(corner_n, vertex_p);
|
corner_table_->MapCornerToVertex(corner_n, vertex_p);
|
||||||
corner_n = corner_table_->SwingLeft(corner_n);
|
corner_n = corner_table_->SwingLeft(corner_n);
|
||||||
|
if (corner_n == first_corner) {
|
||||||
|
// We reached the start again which should not happen for split
|
||||||
|
// symbols.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Make sure the old vertex n is now mapped to an invalid corner (make it
|
// Make sure the old vertex n is now mapped to an invalid corner (make it
|
||||||
// isolated).
|
// isolated).
|
||||||
|
@ -800,7 +829,7 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
return -1; // Unexpected number of decoded vertices.
|
return -1; // Unexpected number of decoded vertices.
|
||||||
}
|
}
|
||||||
// Decode start faces and connect them to the faces from the active stack.
|
// Decode start faces and connect them to the faces from the active stack.
|
||||||
while (active_corner_stack.size() > 0) {
|
while (!active_corner_stack.empty()) {
|
||||||
const CornerIndex corner = active_corner_stack.back();
|
const CornerIndex corner = active_corner_stack.back();
|
||||||
active_corner_stack.pop_back();
|
active_corner_stack.pop_back();
|
||||||
const bool interior_face =
|
const bool interior_face =
|
||||||
|
@ -842,6 +871,18 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
const CornerIndex corner_c =
|
const CornerIndex corner_c =
|
||||||
corner_table_->Next(corner_table_->LeftMostCorner(vert_x));
|
corner_table_->Next(corner_table_->LeftMostCorner(vert_x));
|
||||||
|
|
||||||
|
if (corner == corner_b || corner == corner_c || corner_b == corner_c) {
|
||||||
|
// All matched corners must be different.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (corner_table_->Opposite(corner) != kInvalidCornerIndex ||
|
||||||
|
corner_table_->Opposite(corner_b) != kInvalidCornerIndex ||
|
||||||
|
corner_table_->Opposite(corner_c) != kInvalidCornerIndex) {
|
||||||
|
// One of the corners is already opposite to an existing face, which
|
||||||
|
// should not happen unless the input was tampered with.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const VertexIndex vert_p =
|
const VertexIndex vert_p =
|
||||||
corner_table_->Vertex(corner_table_->Next(corner_c));
|
corner_table_->Vertex(corner_table_->Next(corner_c));
|
||||||
|
|
||||||
|
@ -894,6 +935,11 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||||
VertexCornersIterator<CornerTable> vcit(corner_table_.get(), src_vert);
|
VertexCornersIterator<CornerTable> vcit(corner_table_.get(), src_vert);
|
||||||
for (; !vcit.End(); ++vcit) {
|
for (; !vcit.End(); ++vcit) {
|
||||||
const CornerIndex cid = vcit.Corner();
|
const CornerIndex cid = vcit.Corner();
|
||||||
|
if (corner_table_->Vertex(cid) != src_vert) {
|
||||||
|
// Vertex mapped to |cid| was not |src_vert|. This indicates corrupted
|
||||||
|
// data and we should terminate the decoding.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
corner_table_->MapCornerToVertex(cid, invalid_vert);
|
corner_table_->MapCornerToVertex(cid, invalid_vert);
|
||||||
}
|
}
|
||||||
corner_table_->SetLeftMostCorner(invalid_vert,
|
corner_table_->SetLeftMostCorner(invalid_vert,
|
||||||
|
|
|
@ -31,7 +31,6 @@ bool MeshEdgebreakerEncoder::InitializeEncoder() {
|
||||||
impl_ = nullptr;
|
impl_ = nullptr;
|
||||||
// For tiny meshes it's usually better to use the basic edgebreaker as the
|
// For tiny meshes it's usually better to use the basic edgebreaker as the
|
||||||
// overhead of the predictive one may turn out to be too big.
|
// overhead of the predictive one may turn out to be too big.
|
||||||
// TODO(b/111065939): Check if this can be improved.
|
|
||||||
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
|
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
|
||||||
|
|
||||||
int selected_edgebreaker_method =
|
int selected_edgebreaker_method =
|
||||||
|
|
|
@ -408,7 +408,7 @@ Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
|
||||||
init_face_connectivity_corners.begin(),
|
init_face_connectivity_corners.begin(),
|
||||||
init_face_connectivity_corners.end());
|
init_face_connectivity_corners.end());
|
||||||
// Encode connectivity for all non-position attributes.
|
// Encode connectivity for all non-position attributes.
|
||||||
if (attribute_data_.size() > 0) {
|
if (!attribute_data_.empty()) {
|
||||||
// Use the same order of corner that will be used by the decoder.
|
// Use the same order of corner that will be used by the decoder.
|
||||||
visited_faces_.assign(mesh_->num_faces(), false);
|
visited_faces_.assign(mesh_->num_faces(), false);
|
||||||
for (CornerIndex ci : processed_connectivity_corners_) {
|
for (CornerIndex ci : processed_connectivity_corners_) {
|
||||||
|
|
|
@ -177,7 +177,6 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface {
|
||||||
uint32_t num_split_symbols_;
|
uint32_t num_split_symbols_;
|
||||||
|
|
||||||
// Struct holding data used for encoding each non-position attribute.
|
// Struct holding data used for encoding each non-position attribute.
|
||||||
// TODO(ostava): This should be probably renamed to something better.
|
|
||||||
struct AttributeData {
|
struct AttributeData {
|
||||||
AttributeData() : attribute_index(-1), is_connectivity_used(true) {}
|
AttributeData() : attribute_index(-1), is_connectivity_used(true) {}
|
||||||
int attribute_index;
|
int attribute_index;
|
||||||
|
|
|
@ -44,7 +44,7 @@ class MeshEdgebreakerEncodingTest : public ::testing::Test {
|
||||||
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
||||||
encoder_options.SetSpeed(10 - compression_level, 10 - compression_level);
|
encoder_options.SetSpeed(10 - compression_level, 10 - compression_level);
|
||||||
encoder.SetMesh(*mesh);
|
encoder.SetMesh(*mesh);
|
||||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer));
|
||||||
|
|
||||||
DecoderBuffer dec_buffer;
|
DecoderBuffer dec_buffer;
|
||||||
dec_buffer.Init(buffer.data(), buffer.size());
|
dec_buffer.Init(buffer.data(), buffer.size());
|
||||||
|
@ -52,15 +52,14 @@ class MeshEdgebreakerEncodingTest : public ::testing::Test {
|
||||||
|
|
||||||
std::unique_ptr<Mesh> decoded_mesh(new Mesh());
|
std::unique_ptr<Mesh> decoded_mesh(new Mesh());
|
||||||
DecoderOptions dec_options;
|
DecoderOptions dec_options;
|
||||||
ASSERT_TRUE(
|
DRACO_ASSERT_OK(
|
||||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh.get()).ok());
|
decoder.Decode(dec_options, &dec_buffer, decoded_mesh.get()));
|
||||||
|
|
||||||
// Cleanup the input mesh to make sure that input and output can be
|
// Cleanup the input mesh to make sure that input and output can be
|
||||||
// compared (edgebreaker method discards degenerated triangles and isolated
|
// compared (edgebreaker method discards degenerated triangles and isolated
|
||||||
// vertices).
|
// vertices).
|
||||||
const MeshCleanupOptions options;
|
const MeshCleanupOptions options;
|
||||||
MeshCleanup cleanup;
|
DRACO_ASSERT_OK(MeshCleanup::Cleanup(mesh, options));
|
||||||
ASSERT_TRUE(cleanup(mesh, options)) << "Failed to clean the input mesh.";
|
|
||||||
|
|
||||||
MeshAreEquivalent eq;
|
MeshAreEquivalent eq;
|
||||||
ASSERT_TRUE(eq(*mesh, *decoded_mesh.get()))
|
ASSERT_TRUE(eq(*mesh, *decoded_mesh.get()))
|
||||||
|
@ -102,8 +101,8 @@ TEST_F(MeshEdgebreakerEncodingTest, TestEncoderReuse) {
|
||||||
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
||||||
encoder.SetMesh(*mesh);
|
encoder.SetMesh(*mesh);
|
||||||
EncoderBuffer buffer_0, buffer_1;
|
EncoderBuffer buffer_0, buffer_1;
|
||||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer_0).ok());
|
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer_0));
|
||||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer_1).ok());
|
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer_1));
|
||||||
|
|
||||||
// Make sure both buffer are identical.
|
// Make sure both buffer are identical.
|
||||||
ASSERT_EQ(buffer_0.size(), buffer_1.size());
|
ASSERT_EQ(buffer_0.size(), buffer_1.size());
|
||||||
|
@ -123,7 +122,7 @@ TEST_F(MeshEdgebreakerEncodingTest, TestDecoderReuse) {
|
||||||
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
||||||
encoder.SetMesh(*mesh);
|
encoder.SetMesh(*mesh);
|
||||||
EncoderBuffer buffer;
|
EncoderBuffer buffer;
|
||||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer));
|
||||||
|
|
||||||
DecoderBuffer dec_buffer;
|
DecoderBuffer dec_buffer;
|
||||||
dec_buffer.Init(buffer.data(), buffer.size());
|
dec_buffer.Init(buffer.data(), buffer.size());
|
||||||
|
@ -133,13 +132,13 @@ TEST_F(MeshEdgebreakerEncodingTest, TestDecoderReuse) {
|
||||||
// Decode the mesh two times.
|
// Decode the mesh two times.
|
||||||
std::unique_ptr<Mesh> decoded_mesh_0(new Mesh());
|
std::unique_ptr<Mesh> decoded_mesh_0(new Mesh());
|
||||||
DecoderOptions dec_options;
|
DecoderOptions dec_options;
|
||||||
ASSERT_TRUE(
|
DRACO_ASSERT_OK(
|
||||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_0.get()).ok());
|
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_0.get()));
|
||||||
|
|
||||||
dec_buffer.Init(buffer.data(), buffer.size());
|
dec_buffer.Init(buffer.data(), buffer.size());
|
||||||
std::unique_ptr<Mesh> decoded_mesh_1(new Mesh());
|
std::unique_ptr<Mesh> decoded_mesh_1(new Mesh());
|
||||||
ASSERT_TRUE(
|
DRACO_ASSERT_OK(
|
||||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_1.get()).ok());
|
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_1.get()));
|
||||||
|
|
||||||
// Make sure both of the meshes are identical.
|
// Make sure both of the meshes are identical.
|
||||||
MeshAreEquivalent eq;
|
MeshAreEquivalent eq;
|
||||||
|
@ -169,7 +168,7 @@ TEST_F(MeshEdgebreakerEncodingTest, TestSingleConnectivityEncoding) {
|
||||||
encoder.SetAttributeQuantization(GeometryAttribute::TEX_COORD, 8);
|
encoder.SetAttributeQuantization(GeometryAttribute::TEX_COORD, 8);
|
||||||
encoder.SetAttributeQuantization(GeometryAttribute::NORMAL, 8);
|
encoder.SetAttributeQuantization(GeometryAttribute::NORMAL, 8);
|
||||||
encoder.SetEncodingMethod(MESH_EDGEBREAKER_ENCODING);
|
encoder.SetEncodingMethod(MESH_EDGEBREAKER_ENCODING);
|
||||||
ASSERT_TRUE(encoder.EncodeMeshToBuffer(*mesh, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer));
|
||||||
|
|
||||||
DecoderBuffer dec_buffer;
|
DecoderBuffer dec_buffer;
|
||||||
dec_buffer.Init(buffer.data(), buffer.size());
|
dec_buffer.Init(buffer.data(), buffer.size());
|
||||||
|
@ -216,7 +215,7 @@ TEST_F(MeshEdgebreakerEncodingTest, TestWrongAttributeOrder) {
|
||||||
encoder.SetAttributeQuantization(GeometryAttribute::POSITION, 8);
|
encoder.SetAttributeQuantization(GeometryAttribute::POSITION, 8);
|
||||||
encoder.SetAttributeQuantization(GeometryAttribute::NORMAL, 8);
|
encoder.SetAttributeQuantization(GeometryAttribute::NORMAL, 8);
|
||||||
encoder.SetEncodingMethod(MESH_EDGEBREAKER_ENCODING);
|
encoder.SetEncodingMethod(MESH_EDGEBREAKER_ENCODING);
|
||||||
ASSERT_TRUE(encoder.EncodeMeshToBuffer(*mesh, &buffer).ok());
|
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer));
|
||||||
|
|
||||||
DecoderBuffer dec_buffer;
|
DecoderBuffer dec_buffer;
|
||||||
dec_buffer.Init(buffer.data(), buffer.size());
|
dec_buffer.Init(buffer.data(), buffer.size());
|
||||||
|
|
|
@ -50,8 +50,6 @@ namespace draco {
|
||||||
// \ / S \ / / E \
|
// \ / S \ / / E \
|
||||||
// *-------* *-------*
|
// *-------* *-------*
|
||||||
//
|
//
|
||||||
// TODO(ostava): Get rid of the topology bit pattern. It's important only for
|
|
||||||
// encoding but the algorithms should use EdgebreakerSymbol instead.
|
|
||||||
enum EdgebreakerTopologyBitPattern {
|
enum EdgebreakerTopologyBitPattern {
|
||||||
TOPOLOGY_C = 0x0, // 0
|
TOPOLOGY_C = 0x0, // 0
|
||||||
TOPOLOGY_S = 0x1, // 1 0 0
|
TOPOLOGY_S = 0x1, // 1 0 0
|
||||||
|
|
|
@ -129,7 +129,11 @@ class MeshEdgebreakerTraversalValenceDecoder
|
||||||
if (context_counter < 0) {
|
if (context_counter < 0) {
|
||||||
return TOPOLOGY_INVALID;
|
return TOPOLOGY_INVALID;
|
||||||
}
|
}
|
||||||
const int symbol_id = context_symbols_[active_context_][context_counter];
|
const uint32_t symbol_id =
|
||||||
|
context_symbols_[active_context_][context_counter];
|
||||||
|
if (symbol_id > 4) {
|
||||||
|
return TOPOLOGY_INVALID;
|
||||||
|
}
|
||||||
last_symbol_ = edge_breaker_symbol_to_topology_id[symbol_id];
|
last_symbol_ = edge_breaker_symbol_to_topology_id[symbol_id];
|
||||||
} else {
|
} else {
|
||||||
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue