commit
0ed957f70a
|
@ -1,102 +1,137 @@
|
|||
# Generated with cmake-format 0.5.1
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 2
|
||||
|
||||
# If arglists are longer than this, break them always
|
||||
max_subargs_per_line = 10
|
||||
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = False
|
||||
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = False
|
||||
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on its own line
|
||||
dangle_parens = False
|
||||
|
||||
# What character to use for bulleted lists
|
||||
bullet_char = '*'
|
||||
|
||||
# What character to use as punctuation after numerals in an enumerated list
|
||||
enum_char = '.'
|
||||
|
||||
# What style line endings to use in the output.
|
||||
line_ending = u'unix'
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = u'lower'
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = u'unchanged'
|
||||
|
||||
# Specify structure for custom cmake functions
|
||||
additional_commands = {
|
||||
"foo": {
|
||||
"flags": [
|
||||
"BAR",
|
||||
"BAZ"
|
||||
],
|
||||
"kwargs": {
|
||||
"HEADERS": "*",
|
||||
"DEPENDS": "*",
|
||||
"SOURCES": "*"
|
||||
with section('parse'):
|
||||
# Specify structure for custom cmake functions
|
||||
additional_commands = {
|
||||
'draco_add_emscripten_executable': {
|
||||
'kwargs': {
|
||||
'NAME': '*',
|
||||
'SOURCES': '*',
|
||||
'OUTPUT_NAME': '*',
|
||||
'DEFINES': '*',
|
||||
'INCLUDES': '*',
|
||||
'COMPILE_FLAGS': '*',
|
||||
'LINK_FLAGS': '*',
|
||||
'OBJLIB_DEPS': '*',
|
||||
'LIB_DEPS': '*',
|
||||
'GLUE_PATH': '*',
|
||||
'PRE_LINK_JS_SOURCES': '*',
|
||||
'POST_LINK_JS_SOURCES': '*',
|
||||
'FEATURES': '*',
|
||||
},
|
||||
'pargs': 0,
|
||||
},
|
||||
'draco_add_executable': {
|
||||
'kwargs': {
|
||||
'NAME': '*',
|
||||
'SOURCES': '*',
|
||||
'OUTPUT_NAME': '*',
|
||||
'TEST': 0,
|
||||
'DEFINES': '*',
|
||||
'INCLUDES': '*',
|
||||
'COMPILE_FLAGS': '*',
|
||||
'LINK_FLAGS': '*',
|
||||
'OBJLIB_DEPS': '*',
|
||||
'LIB_DEPS': '*',
|
||||
},
|
||||
'pargs': 0,
|
||||
},
|
||||
'draco_add_library': {
|
||||
'kwargs': {
|
||||
'NAME': '*',
|
||||
'TYPE': '*',
|
||||
'SOURCES': '*',
|
||||
'TEST': 0,
|
||||
'OUTPUT_NAME': '*',
|
||||
'DEFINES': '*',
|
||||
'INCLUDES': '*',
|
||||
'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
|
||||
always_wrap = []
|
||||
with section('format'):
|
||||
# Formatting options.
|
||||
|
||||
# Specify the order of wrapping algorithms during successive reflow attempts
|
||||
algorithm_order = [0, 1, 2, 3, 4]
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
||||
# If true, the argument lists which are known to be sortable will be sorted
|
||||
# lexicographicall
|
||||
autosort = False
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 2
|
||||
|
||||
# enable comment markup parsing and reflow
|
||||
enable_markup = True
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = False
|
||||
|
||||
# If comment markup is enabled, don't reflow the first comment block in
|
||||
# eachlistfile. Use this to preserve formatting of your
|
||||
# copyright/licensestatements.
|
||||
first_comment_is_literal = False
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = False
|
||||
|
||||
# If comment markup is enabled, don't reflow any comment block which matchesthis
|
||||
# (regex) pattern. Default is `None` (disabled).
|
||||
literal_comment_pattern = None
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on its own line.
|
||||
dangle_parens = False
|
||||
|
||||
# Regular expression to match preformat fences in comments
|
||||
# default=r'^\s*([`~]{3}[`~]*)(.*)$'
|
||||
fence_pattern = u'^\\s*([`~]{3}[`~]*)(.*)$'
|
||||
# Do not sort argument lists.
|
||||
enable_sort = False
|
||||
|
||||
# Regular expression to match rulers in comments
|
||||
# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
|
||||
ruler_pattern = u'^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
|
||||
# What style line endings to use in the output.
|
||||
line_ending = 'unix'
|
||||
|
||||
# If true, emit the unicode byte-order mark (BOM) at the start of the file
|
||||
emit_byteorder_mark = False
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = 'canonical'
|
||||
|
||||
# If a comment line starts with at least this many consecutive hash characters,
|
||||
# then don't lstrip() them off. This allows for lazy hash rulers where the first
|
||||
# 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 = {}
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = 'upper'
|
||||
|
|
|
@ -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)
|
||||
* [Windows](#windows)
|
||||
* [CMake Build Configuration](#cmake-build-configuration)
|
||||
* [Transcoder](#transcoder)
|
||||
* [Debugging and Optimization](#debugging-and-optimization)
|
||||
* [Googletest Integration](#googletest-integration)
|
||||
* [Third Party Libraries](#third-party-libraries)
|
||||
* [Javascript Encoder/Decoder](#javascript-encoderdecoder)
|
||||
* [WebAssembly Decoder](#webassembly-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
|
||||
-------------------------
|
||||
|
||||
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
|
||||
--------------------------
|
||||
|
||||
|
@ -114,17 +153,52 @@ $ cmake ../ -DDRACO_SANITIZE=address
|
|||
Googletest Integration
|
||||
----------------------
|
||||
|
||||
Draco includes testing support built using Googletest. To enable Googletest unit
|
||||
test support the DRACO_TESTS cmake variable must be turned on at cmake
|
||||
generation time:
|
||||
Draco includes testing support built using Googletest. The Googletest repository
|
||||
is included as a submodule of the Draco git repository. Run the following
|
||||
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
|
||||
$ cmake ../ -DDRACO_TESTS=ON
|
||||
~~~~~
|
||||
|
||||
When cmake is used as shown in the above example the googletest directory must
|
||||
be a sibling of the Draco repository root directory. To run the tests execute
|
||||
`draco_tests` from your build output 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
|
||||
-------------------
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,10 +2,93 @@
|
|||
<img width="350px" src="docs/artwork/draco3d-vert.svg" />
|
||||
</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
|
||||
=======
|
||||
|
||||
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
|
||||
* Using the versioned www.gstatic.com WASM and Javascript decoders is now
|
||||
recommended. To use v1.4.1, use this URL:
|
||||
|
@ -129,6 +212,7 @@ _**Contents**_
|
|||
* [Encoding Tool](#encoding-tool)
|
||||
* [Encoding Point Clouds](#encoding-point-clouds)
|
||||
* [Decoding Tool](#decoding-tool)
|
||||
* [glTF Transcoding Tool](#gltf-transcoding-tool)
|
||||
* [C++ Decoder API](#c-decoder-api)
|
||||
* [Javascript Encoder API](#javascript-encoder-api)
|
||||
* [Javascript Decoder API](#javascript-decoder-api)
|
||||
|
@ -136,6 +220,7 @@ _**Contents**_
|
|||
* [Metadata API](#metadata-api)
|
||||
* [NPM Package](#npm-package)
|
||||
* [three.js Renderer Example](#threejs-renderer-example)
|
||||
* [GStatic Javascript Builds](#gstatic-javascript-builds)
|
||||
* [Support](#support)
|
||||
* [License](#license)
|
||||
* [References](#references)
|
||||
|
@ -170,16 +255,18 @@ Command Line Applications
|
|||
------------------------
|
||||
|
||||
The default target created from the build files will be the `draco_encoder`
|
||||
and `draco_decoder` command line applications. For both applications, if you
|
||||
run them without any arguments or `-h`, the applications will output usage and
|
||||
options.
|
||||
and `draco_decoder` command line applications. Additionally, `draco_transcoder`
|
||||
is generated when CMake is run with the DRACO_TRANSCODER_SUPPORTED variable set
|
||||
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
|
||||
-------------
|
||||
|
||||
`draco_encoder` will read OBJ or PLY files as input, and output Draco-encoded
|
||||
files. We have included Stanford's [Bunny] mesh for testing. The basic command
|
||||
line looks like this:
|
||||
`draco_encoder` will read OBJ, STL or PLY files as input, and output
|
||||
Draco-encoded files. We have included Stanford's [Bunny] mesh for testing. The
|
||||
basic command line looks like this:
|
||||
|
||||
~~~~~ bash
|
||||
./draco_encoder -i testdata/bun_zipper.ply -o out.drc
|
||||
|
@ -232,15 +319,34 @@ and denser point clouds.
|
|||
Decoding Tool
|
||||
-------------
|
||||
|
||||
`draco_decoder` will read Draco files as input, and output OBJ or PLY files.
|
||||
The basic command line looks like this:
|
||||
`draco_decoder` will read Draco files as input, and output OBJ, STL or PLY
|
||||
files. The basic command line looks like this:
|
||||
|
||||
~~~~~ bash
|
||||
./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
|
||||
-------------
|
||||
---------------
|
||||
|
||||
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
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
=======
|
||||
|
||||
|
|
|
@ -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@")
|
||||
set(DRACO_LIBRARIES "draco")
|
||||
@PACKAGE_INIT@
|
||||
|
||||
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@
|
||||
Description: Draco geometry de(com)pression library.
|
||||
Version: @DRACO_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -ldraco
|
||||
Cflags: -I@includes_path@
|
||||
Libs: -L@libs_path@ -ldraco
|
||||
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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_
|
||||
|
@ -17,10 +31,6 @@ macro(set_draco_target)
|
|||
endif()
|
||||
set(draco_plugin_dependency draco_static)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Configures flags and sets build system globals.
|
||||
|
@ -36,23 +46,37 @@ macro(draco_set_build_definitions)
|
|||
endif()
|
||||
|
||||
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"
|
||||
"${draco_build}")
|
||||
|
||||
if(DRACO_ABSL)
|
||||
list(APPEND draco_include_path "${draco_root}/third_party/abseil-cpp")
|
||||
if(DRACO_TRANSCODER_SUPPORTED)
|
||||
draco_setup_eigen()
|
||||
draco_setup_filesystem()
|
||||
draco_setup_tinygltf()
|
||||
|
||||
|
||||
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"
|
||||
"DRACO_FLAGS_SRCDIR=\"${draco_root}\""
|
||||
"DRACO_FLAGS_TMPDIR=\"/tmp\"")
|
||||
|
@ -63,11 +87,22 @@ macro(draco_set_build_definitions)
|
|||
if(BUILD_SHARED_LIBS)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
endif()
|
||||
else()
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
# Ensure 64-bit platforms can support large files.
|
||||
list(APPEND draco_defines "_LARGEFILE_SOURCE" "_FILE_OFFSET_BITS=64")
|
||||
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()
|
||||
|
||||
if(ANDROID)
|
||||
|
@ -102,13 +137,9 @@ macro(draco_set_build_definitions)
|
|||
set(draco_neon_source_file_suffix "neon.cc")
|
||||
set(draco_sse4_source_file_suffix "sse4.cc")
|
||||
|
||||
if((${CMAKE_CXX_COMPILER_ID}
|
||||
STREQUAL
|
||||
"GNU"
|
||||
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 5)
|
||||
OR (${CMAKE_CXX_COMPILER_ID}
|
||||
STREQUAL
|
||||
"Clang"
|
||||
if((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
|
||||
VERSION_LESS 5)
|
||||
OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"
|
||||
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4))
|
||||
message(
|
||||
WARNING "GNU/GCC < v5 or Clang/LLVM < v4, ENABLING COMPATIBILITY MODE.")
|
||||
|
@ -117,7 +148,9 @@ macro(draco_set_build_definitions)
|
|||
|
||||
if(EMSCRIPTEN)
|
||||
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()
|
||||
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_
|
||||
|
@ -18,39 +32,64 @@ endmacro()
|
|||
|
||||
# Obtains the required Emscripten flags for Draco targets.
|
||||
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_single_arg_opts FLAG_LIST_VAR)
|
||||
set(em_single_arg_opts FLAG_LIST_VAR_COMPILER FLAG_LIST_VAR_LINKER)
|
||||
set(em_multi_arg_opts)
|
||||
cmake_parse_arguments(em "${em_flags}" "${em_single_arg_opts}"
|
||||
"${em_multi_arg_opts}" ${ARGN})
|
||||
if(NOT em_FLAG_LIST_VAR)
|
||||
message(FATAL "draco_get_required_emscripten_flags: FLAG_LIST_VAR required")
|
||||
if(NOT em_FLAG_LIST_VAR_COMPILER)
|
||||
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()
|
||||
|
||||
if(DRACO_JS_GLUE)
|
||||
unset(required_flags)
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sALLOW_MEMORY_GROWTH=1")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-Wno-almost-asm")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "--memory-init-file" "0")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-fno-omit-frame-pointer")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sMODULARIZE=1")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sNO_FILESYSTEM=1")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sEXPORTED_RUNTIME_METHODS=[]")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sPRECISE_F32=1")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_EXIT=0")
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_REJECTION=0")
|
||||
# TODO(tomfinegan): Revisit splitting of compile/link flags for Emscripten,
|
||||
# and drop -Wno-unused-command-line-argument. Emscripten complains about
|
||||
# what are supposedly link-only flags sent with compile commands, but then
|
||||
# proceeds to produce broken code if the warnings are heeded.
|
||||
list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
|
||||
"-Wno-unused-command-line-argument")
|
||||
|
||||
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-Wno-almost-asm")
|
||||
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--memory-init-file" "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)
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "--llvm-lto" "1")
|
||||
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--llvm-lto" "1")
|
||||
endif()
|
||||
|
||||
# The WASM flag is reported as linker only.
|
||||
if(DRACO_WASM)
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=1")
|
||||
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=1")
|
||||
else()
|
||||
list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=0")
|
||||
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=0")
|
||||
endif()
|
||||
|
||||
# The LEGACY_VM_SUPPORT flag is reported as linker only.
|
||||
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()
|
||||
endmacro()
|
||||
|
@ -66,9 +105,10 @@ macro(draco_generate_emscripten_glue)
|
|||
"${glue_multi_arg_opts}" ${ARGN})
|
||||
|
||||
if(DRACO_VERBOSE GREATER 1)
|
||||
message("--------- draco_generate_emscripten_glue -----------\n"
|
||||
message(
|
||||
"--------- draco_generate_emscripten_glue -----------\n"
|
||||
"glue_INPUT_IDL=${glue_INPUT_IDL}\n"
|
||||
"glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n" ]
|
||||
"glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n"
|
||||
"----------------------------------------------------\n")
|
||||
endif()
|
||||
|
||||
|
@ -79,17 +119,17 @@ macro(draco_generate_emscripten_glue)
|
|||
endif()
|
||||
|
||||
# Generate the glue source.
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE}
|
||||
$ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
||||
${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
|
||||
if(NOT EXISTS "${glue_OUTPUT_PATH}.cpp")
|
||||
message(FATAL_ERROR "JS glue generation failed for ${glue_INPUT_IDL}.")
|
||||
endif()
|
||||
|
||||
# Create a dependency so that it regenerated on edits.
|
||||
add_custom_command(OUTPUT "${glue_OUTPUT_PATH}.cpp"
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
$ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
||||
add_custom_command(
|
||||
OUTPUT "${glue_OUTPUT_PATH}.cpp"
|
||||
COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
|
||||
${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
|
||||
DEPENDS ${draco_js_dec_idl}
|
||||
COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
|
||||
|
@ -120,8 +160,14 @@ macro(draco_add_emscripten_executable)
|
|||
unset(emexe_LINK_FLAGS)
|
||||
set(optional_args)
|
||||
set(single_value_args NAME GLUE_PATH)
|
||||
set(multi_value_args SOURCES DEFINES FEATURES INCLUDES LINK_FLAGS
|
||||
PRE_LINK_JS_SOURCES POST_LINK_JS_SOURCES)
|
||||
set(multi_value_args
|
||||
SOURCES
|
||||
DEFINES
|
||||
FEATURES
|
||||
INCLUDES
|
||||
LINK_FLAGS
|
||||
PRE_LINK_JS_SOURCES
|
||||
POST_LINK_JS_SOURCES)
|
||||
|
||||
cmake_parse_arguments(emexe "${optional_args}" "${single_value_args}"
|
||||
"${multi_value_args}" ${ARGN})
|
||||
|
@ -136,7 +182,8 @@ macro(draco_add_emscripten_executable)
|
|||
endif()
|
||||
|
||||
if(DRACO_VERBOSE GREATER 1)
|
||||
message("--------- draco_add_emscripten_executable ---------\n"
|
||||
message(
|
||||
"--------- draco_add_emscripten_executable ---------\n"
|
||||
"emexe_NAME=${emexe_NAME}\n"
|
||||
"emexe_SOURCES=${emexe_SOURCES}\n"
|
||||
"emexe_DEFINES=${emexe_DEFINES}\n"
|
||||
|
@ -153,30 +200,30 @@ macro(draco_add_emscripten_executable)
|
|||
# passed in with the target.
|
||||
list(APPEND emexe_LINK_FLAGS ${DRACO_CXX_FLAGS})
|
||||
|
||||
if(DRACO_GLTF)
|
||||
draco_add_executable(NAME
|
||||
${emexe_NAME}
|
||||
OUTPUT_NAME
|
||||
${emexe_NAME}_gltf
|
||||
SOURCES
|
||||
${emexe_SOURCES}
|
||||
DEFINES
|
||||
${emexe_DEFINES}
|
||||
INCLUDES
|
||||
${emexe_INCLUDES}
|
||||
LINK_FLAGS
|
||||
${emexe_LINK_FLAGS})
|
||||
if(DRACO_GLTF_BITSTREAM)
|
||||
# Add "_gltf" suffix to target output name.
|
||||
draco_add_executable(
|
||||
NAME ${emexe_NAME}
|
||||
OUTPUT_NAME ${emexe_NAME}_gltf
|
||||
SOURCES ${emexe_SOURCES}
|
||||
DEFINES ${emexe_DEFINES}
|
||||
INCLUDES ${emexe_INCLUDES}
|
||||
LINK_FLAGS ${emexe_LINK_FLAGS})
|
||||
else()
|
||||
draco_add_executable(NAME ${emexe_NAME} SOURCES ${emexe_SOURCES} DEFINES
|
||||
${emexe_DEFINES} INCLUDES ${emexe_INCLUDES} LINK_FLAGS
|
||||
${emexe_LINK_FLAGS})
|
||||
draco_add_executable(
|
||||
NAME ${emexe_NAME}
|
||||
SOURCES ${emexe_SOURCES}
|
||||
DEFINES ${emexe_DEFINES}
|
||||
INCLUDES ${emexe_INCLUDES}
|
||||
LINK_FLAGS ${emexe_LINK_FLAGS})
|
||||
endif()
|
||||
|
||||
foreach(feature ${emexe_FEATURES})
|
||||
draco_enable_feature(FEATURE ${feature} TARGETS ${emexe_NAME})
|
||||
endforeach()
|
||||
|
||||
set_property(SOURCE ${emexe_SOURCES}
|
||||
set_property(
|
||||
SOURCE ${emexe_SOURCES}
|
||||
APPEND
|
||||
PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
|
||||
em_link_pre_js(${emexe_NAME} ${emexe_PRE_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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_FLAGS_CMAKE_
|
||||
|
@ -85,8 +99,8 @@ macro(draco_test_cxx_flag)
|
|||
# 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
|
||||
# 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)
|
||||
check_cxx_compiler_flag("${all_cxx_flags}" draco_all_cxx_flags_pass)
|
||||
draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags_string)
|
||||
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)
|
||||
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})
|
||||
endif()
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_INSTALL_CMAKE_
|
||||
set(DRACO_CMAKE_DRACO_INSTALL_CMAKE_ 1)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Sets up the draco install targets. Must be called after the static library
|
||||
# target is created.
|
||||
macro(draco_setup_install_target)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# pkg-config: draco.pc
|
||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||
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")
|
||||
set(bin_path "${CMAKE_INSTALL_BINDIR}")
|
||||
set(data_path "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
set(includes_path "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
set(libs_path "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
foreach(file ${draco_sources})
|
||||
if(file MATCHES "h$")
|
||||
|
@ -34,46 +34,88 @@ macro(draco_setup_install_target)
|
|||
endif()
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES draco_api_includes)
|
||||
|
||||
# Strip $draco_src_root from the file paths: we need to install relative to
|
||||
# $include_directory.
|
||||
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})
|
||||
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}
|
||||
DESTINATION "${target_directory}")
|
||||
endforeach()
|
||||
|
||||
install(
|
||||
FILES "${draco_build}/draco/draco_features.h"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/draco/")
|
||||
install(FILES "${draco_build}/draco/draco_features.h"
|
||||
DESTINATION "${includes_path}/draco/")
|
||||
|
||||
install(TARGETS draco_decoder DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
|
||||
install(TARGETS draco_encoder DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
|
||||
install(TARGETS draco_decoder DESTINATION "${bin_path}")
|
||||
install(TARGETS draco_encoder DESTINATION "${bin_path}")
|
||||
|
||||
if(DRACO_TRANSCODER_SUPPORTED)
|
||||
install(TARGETS draco_transcoder DESTINATION "${bin_path}")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
install(TARGETS draco DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
install(
|
||||
TARGETS draco
|
||||
EXPORT dracoExport
|
||||
RUNTIME DESTINATION "${bin_path}"
|
||||
ARCHIVE DESTINATION "${libs_path}"
|
||||
LIBRARY DESTINATION "${libs_path}")
|
||||
else()
|
||||
install(TARGETS draco_static DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
install(
|
||||
TARGETS draco_static
|
||||
EXPORT dracoExport
|
||||
DESTINATION "${libs_path}")
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
install(TARGETS draco_shared DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
install(
|
||||
TARGETS draco_shared
|
||||
EXPORT dracoExport
|
||||
RUNTIME DESTINATION "${bin_path}"
|
||||
ARCHIVE DESTINATION "${libs_path}"
|
||||
LIBRARY DESTINATION "${libs_path}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DRACO_UNITY_PLUGIN)
|
||||
install(TARGETS dracodec_unity DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
if(DRACO_MAYA_PLUGIN)
|
||||
install(TARGETS draco_maya_wrapper DESTINATION
|
||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
install(TARGETS dracodec_unity DESTINATION "${libs_path}")
|
||||
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()
|
||||
|
|
|
@ -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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_
|
||||
|
@ -61,14 +75,12 @@ macro(draco_process_intrinsics_sources)
|
|||
unset(sse4_sources)
|
||||
list(APPEND sse4_sources ${arg_SOURCES})
|
||||
|
||||
list(FILTER sse4_sources INCLUDE REGEX
|
||||
"${draco_sse4_source_file_suffix}$")
|
||||
list(FILTER sse4_sources INCLUDE REGEX "${draco_sse4_source_file_suffix}$")
|
||||
|
||||
if(sse4_sources)
|
||||
unset(sse4_flags)
|
||||
draco_get_intrinsics_flag_for_suffix(SUFFIX
|
||||
${draco_sse4_source_file_suffix}
|
||||
VARIABLE sse4_flags)
|
||||
draco_get_intrinsics_flag_for_suffix(
|
||||
SUFFIX ${draco_sse4_source_file_suffix} VARIABLE sse4_flags)
|
||||
if(sse4_flags)
|
||||
draco_set_compiler_flags_for_sources(SOURCES ${sse4_sources} FLAGS
|
||||
${sse4_flags})
|
||||
|
@ -79,14 +91,12 @@ macro(draco_process_intrinsics_sources)
|
|||
if(DRACO_ENABLE_NEON AND draco_have_neon)
|
||||
unset(neon_sources)
|
||||
list(APPEND neon_sources ${arg_SOURCES})
|
||||
list(FILTER neon_sources INCLUDE REGEX
|
||||
"${draco_neon_source_file_suffix}$")
|
||||
list(FILTER neon_sources INCLUDE REGEX "${draco_neon_source_file_suffix}$")
|
||||
|
||||
if(neon_sources AND DRACO_NEON_INTRINSICS_FLAG)
|
||||
unset(neon_flags)
|
||||
draco_get_intrinsics_flag_for_suffix(SUFFIX
|
||||
${draco_neon_source_file_suffix}
|
||||
VARIABLE neon_flags)
|
||||
draco_get_intrinsics_flag_for_suffix(
|
||||
SUFFIX ${draco_neon_source_file_suffix} VARIABLE neon_flags)
|
||||
if(neon_flags)
|
||||
draco_set_compiler_flags_for_sources(SOURCES ${neon_sources} FLAGS
|
||||
${neon_flags})
|
||||
|
|
|
@ -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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_OPTIONS_CMAKE_
|
||||
|
@ -18,14 +32,19 @@ macro(draco_option)
|
|||
cmake_parse_arguments(option "${optional_args}" "${single_value_args}"
|
||||
"${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.")
|
||||
endif()
|
||||
|
||||
option(${option_NAME} ${option_HELPSTRING} ${option_VALUE})
|
||||
|
||||
if(DRACO_VERBOSE GREATER 2)
|
||||
message("--------- draco_option ---------\n" "option_NAME=${option_NAME}\n"
|
||||
message(
|
||||
"--------- draco_option ---------\n"
|
||||
"option_NAME=${option_NAME}\n"
|
||||
"option_HELPSTRING=${option_HELPSTRING}\n"
|
||||
"option_VALUE=${option_VALUE}\n"
|
||||
"------------------------------------------\n")
|
||||
|
@ -44,33 +63,74 @@ endmacro()
|
|||
|
||||
# Set default options.
|
||||
macro(draco_set_default_options)
|
||||
draco_option(NAME DRACO_FAST HELPSTRING "Try to build faster libs." VALUE OFF)
|
||||
draco_option(NAME DRACO_JS_GLUE HELPSTRING
|
||||
"Enable JS Glue and JS targets when using Emscripten." VALUE ON)
|
||||
draco_option(NAME DRACO_IE_COMPATIBLE HELPSTRING
|
||||
"Enable support for older IE builds when using Emscripten." VALUE
|
||||
OFF)
|
||||
draco_option(NAME DRACO_MESH_COMPRESSION HELPSTRING "Enable mesh compression."
|
||||
VALUE ON)
|
||||
draco_option(NAME DRACO_POINT_CLOUD_COMPRESSION HELPSTRING
|
||||
"Enable point cloud compression." VALUE ON)
|
||||
draco_option(NAME DRACO_PREDICTIVE_EDGEBREAKER HELPSTRING
|
||||
"Enable predictive edgebreaker." VALUE ON)
|
||||
draco_option(NAME DRACO_STANDARD_EDGEBREAKER 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."
|
||||
draco_option(
|
||||
NAME DRACO_FAST
|
||||
HELPSTRING "Try to build faster libs."
|
||||
VALUE OFF)
|
||||
draco_option(
|
||||
NAME DRACO_JS_GLUE
|
||||
HELPSTRING "Enable JS Glue and JS targets when using Emscripten."
|
||||
VALUE ON)
|
||||
draco_option(
|
||||
NAME DRACO_IE_COMPATIBLE
|
||||
HELPSTRING "Enable support for older IE builds when using Emscripten."
|
||||
VALUE OFF)
|
||||
draco_option(
|
||||
NAME DRACO_MESH_COMPRESSION
|
||||
HELPSTRING "Enable mesh compression."
|
||||
VALUE ON)
|
||||
draco_option(
|
||||
NAME DRACO_POINT_CLOUD_COMPRESSION
|
||||
HELPSTRING "Enable point cloud compression."
|
||||
VALUE ON)
|
||||
draco_option(
|
||||
NAME DRACO_PREDICTIVE_EDGEBREAKER
|
||||
HELPSTRING "Enable predictive edgebreaker."
|
||||
VALUE ON)
|
||||
draco_option(
|
||||
NAME DRACO_STANDARD_EDGEBREAKER
|
||||
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_option(NAME DRACO_GLTF HELPSTRING "Support GLTF." VALUE OFF)
|
||||
draco_option(NAME DRACO_MAYA_PLUGIN HELPSTRING
|
||||
"Build plugin library for Maya." VALUE OFF)
|
||||
draco_check_deprecated_options()
|
||||
endmacro()
|
||||
|
||||
|
@ -117,14 +177,16 @@ macro(draco_check_deprecated_options)
|
|||
DRACO_MAYA_PLUGIN)
|
||||
draco_handle_deprecated_option(OLDNAME BUILD_USD_PLUGIN NEWNAME
|
||||
BUILD_SHARED_LIBS)
|
||||
draco_handle_deprecated_option(OLDNAME DRACO_GLTF NEWNAME
|
||||
DRACO_GLTF_BITSTREAM)
|
||||
|
||||
endmacro()
|
||||
|
||||
# Macro for setting Draco features based on user configuration. Features enabled
|
||||
# by this macro are Draco global.
|
||||
macro(draco_set_optional_features)
|
||||
if(DRACO_GLTF)
|
||||
# Override settings when building for GLTF.
|
||||
if(DRACO_GLTF_BITSTREAM)
|
||||
# Enable only the features included in the Draco GLTF bitstream spec.
|
||||
draco_enable_feature(FEATURE "DRACO_MESH_COMPRESSION_SUPPORTED")
|
||||
draco_enable_feature(FEATURE "DRACO_NORMAL_ENCODING_SUPPORTED")
|
||||
draco_enable_feature(FEATURE "DRACO_STANDARD_EDGEBREAKER_SUPPORTED")
|
||||
|
@ -170,6 +232,11 @@ macro(draco_set_optional_features)
|
|||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
if(DRACO_TRANSCODER_SUPPORTED)
|
||||
draco_enable_feature(FEATURE "DRACO_TRANSCODER_SUPPORTED")
|
||||
endif()
|
||||
|
||||
|
||||
endmacro()
|
||||
|
||||
# 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")
|
||||
endforeach()
|
||||
|
||||
if(MSVC)
|
||||
if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
|
||||
file(APPEND "${draco_features_file_name}.new"
|
||||
"\n#endif // DRACO_FEATURES_H_")
|
||||
"// 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"
|
||||
"\n#endif // DRACO_FEATURES_H_\n")
|
||||
|
||||
# Will replace ${draco_features_file_name} only if the file content has
|
||||
# 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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_SANITIZER_CMAKE_
|
||||
|
@ -5,7 +19,9 @@ set(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_ 1)
|
|||
|
||||
# Handles the details of enabling sanitizers.
|
||||
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(DRACO_SANITIZE MATCHES "cfi")
|
||||
list(APPEND SAN_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi")
|
||||
|
@ -13,8 +29,8 @@ macro(draco_configure_sanitizer)
|
|||
"-fuse-ld=gold")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4
|
||||
AND DRACO_SANITIZE MATCHES "integer|undefined")
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4 AND DRACO_SANITIZE MATCHES
|
||||
"integer|undefined")
|
||||
list(APPEND SAN_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s")
|
||||
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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_TARGETS_CMAKE_
|
||||
|
@ -51,14 +65,21 @@ macro(draco_add_executable)
|
|||
unset(exe_LIB_DEPS)
|
||||
set(optional_args TEST)
|
||||
set(single_value_args NAME OUTPUT_NAME)
|
||||
set(multi_value_args SOURCES DEFINES INCLUDES COMPILE_FLAGS LINK_FLAGS
|
||||
OBJLIB_DEPS LIB_DEPS)
|
||||
set(multi_value_args
|
||||
SOURCES
|
||||
DEFINES
|
||||
INCLUDES
|
||||
COMPILE_FLAGS
|
||||
LINK_FLAGS
|
||||
OBJLIB_DEPS
|
||||
LIB_DEPS)
|
||||
|
||||
cmake_parse_arguments(exe "${optional_args}" "${single_value_args}"
|
||||
"${multi_value_args}" ${ARGN})
|
||||
|
||||
if(DRACO_VERBOSE GREATER 1)
|
||||
message("--------- draco_add_executable ---------\n"
|
||||
message(
|
||||
"--------- draco_add_executable ---------\n"
|
||||
"exe_TEST=${exe_TEST}\n"
|
||||
"exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
|
||||
"exe_NAME=${exe_NAME}\n"
|
||||
|
@ -87,7 +108,12 @@ macro(draco_add_executable)
|
|||
endif()
|
||||
|
||||
add_executable(${exe_NAME} ${exe_SOURCES})
|
||||
|
||||
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)
|
||||
set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
|
||||
|
@ -104,8 +130,8 @@ macro(draco_add_executable)
|
|||
endif()
|
||||
|
||||
if(exe_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
|
||||
target_compile_options(${exe_NAME}
|
||||
PRIVATE ${exe_COMPILE_FLAGS} ${DRACO_CXX_FLAGS})
|
||||
target_compile_options(${exe_NAME} PRIVATE ${exe_COMPILE_FLAGS}
|
||||
${DRACO_CXX_FLAGS})
|
||||
endif()
|
||||
|
||||
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}")
|
||||
# LINK_FLAGS is managed as a string.
|
||||
draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
|
||||
set_target_properties(${exe_NAME}
|
||||
PROPERTIES LINK_FLAGS "${exe_LINK_FLAGS}")
|
||||
set_target_properties(${exe_NAME} PROPERTIES LINK_FLAGS
|
||||
"${exe_LINK_FLAGS}")
|
||||
else()
|
||||
target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
|
||||
${DRACO_EXE_LINKER_FLAGS})
|
||||
|
@ -136,12 +162,7 @@ macro(draco_add_executable)
|
|||
endif()
|
||||
|
||||
if(exe_LIB_DEPS)
|
||||
unset(exe_static)
|
||||
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")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "^Clang|^GNU")
|
||||
# Third party dependencies can introduce dependencies on system and test
|
||||
# libraries. Since the target created here is an executable, and CMake
|
||||
# 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
|
||||
# those dependencies happen to be resolved by dependencies of the current
|
||||
# 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(APPEND exe_LIB_DEPS -Wl,--end-group)
|
||||
endif()
|
||||
|
@ -209,14 +234,23 @@ macro(draco_add_library)
|
|||
unset(lib_TARGET_PROPERTIES)
|
||||
set(optional_args TEST)
|
||||
set(single_value_args NAME OUTPUT_NAME TYPE)
|
||||
set(multi_value_args SOURCES DEFINES INCLUDES COMPILE_FLAGS LINK_FLAGS
|
||||
OBJLIB_DEPS LIB_DEPS PUBLIC_INCLUDES TARGET_PROPERTIES)
|
||||
set(multi_value_args
|
||||
SOURCES
|
||||
DEFINES
|
||||
INCLUDES
|
||||
COMPILE_FLAGS
|
||||
LINK_FLAGS
|
||||
OBJLIB_DEPS
|
||||
LIB_DEPS
|
||||
PUBLIC_INCLUDES
|
||||
TARGET_PROPERTIES)
|
||||
|
||||
cmake_parse_arguments(lib "${optional_args}" "${single_value_args}"
|
||||
"${multi_value_args}" ${ARGN})
|
||||
|
||||
if(DRACO_VERBOSE GREATER 1)
|
||||
message("--------- draco_add_library ---------\n"
|
||||
message(
|
||||
"--------- draco_add_library ---------\n"
|
||||
"lib_TEST=${lib_TEST}\n"
|
||||
"lib_NAME=${lib_NAME}\n"
|
||||
"lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
|
||||
|
@ -256,14 +290,24 @@ macro(draco_add_library)
|
|||
endif()
|
||||
|
||||
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)
|
||||
draco_process_intrinsics_sources(TARGET ${lib_NAME} SOURCES ${lib_SOURCES})
|
||||
endif()
|
||||
|
||||
if(lib_OUTPUT_NAME)
|
||||
if(NOT (BUILD_SHARED_LIBS AND MSVC))
|
||||
set_target_properties(${lib_NAME}
|
||||
PROPERTIES OUTPUT_NAME ${lib_OUTPUT_NAME})
|
||||
set_target_properties(${lib_NAME} PROPERTIES OUTPUT_NAME
|
||||
${lib_OUTPUT_NAME})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -280,8 +324,8 @@ macro(draco_add_library)
|
|||
endif()
|
||||
|
||||
if(lib_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
|
||||
target_compile_options(${lib_NAME}
|
||||
PRIVATE ${lib_COMPILE_FLAGS} ${DRACO_CXX_FLAGS})
|
||||
target_compile_options(${lib_NAME} PRIVATE ${lib_COMPILE_FLAGS}
|
||||
${DRACO_CXX_FLAGS})
|
||||
endif()
|
||||
|
||||
if(lib_LINK_FLAGS)
|
||||
|
@ -320,11 +364,12 @@ macro(draco_add_library)
|
|||
set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
|
||||
endif()
|
||||
|
||||
if(NOT EMSCRIPTEN)
|
||||
# VERSION and SOVERSION as necessary
|
||||
if(NOT lib_TYPE STREQUAL STATIC AND NOT lib_TYPE STREQUAL MODULE)
|
||||
set_target_properties(${lib_NAME} PROPERTIES VERSION ${DRACO_VERSION})
|
||||
if(NOT MSVC)
|
||||
set_target_properties(${lib_NAME} PROPERTIES SOVERSION ${DRACO_SOVERSION})
|
||||
if((lib_TYPE STREQUAL BUNDLE OR lib_TYPE STREQUAL SHARED) AND NOT MSVC)
|
||||
set_target_properties(
|
||||
${lib_NAME} PROPERTIES VERSION ${DRACO_SOVERSION}
|
||||
SOVERSION ${DRACO_SOVERSION_MAJOR})
|
||||
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_
|
||||
#define DRACO_TESTING_DRACO_TEST_CONFIG_H_
|
||||
|
||||
|
@ -9,5 +23,6 @@
|
|||
|
||||
#define DRACO_TEST_DATA_DIR "${DRACO_TEST_DATA_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_
|
||||
|
|
|
@ -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)
|
||||
return()
|
||||
endif()
|
||||
|
@ -10,6 +24,13 @@ set(draco_factory_test_sources
|
|||
"${draco_src_root}/io/file_reader_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(
|
||||
APPEND
|
||||
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_sequential_encoding_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/quantization_utils_test.cc"
|
||||
"${draco_src_root}/core/status_test.cc"
|
||||
"${draco_src_root}/core/vector_d_test.cc"
|
||||
"${draco_src_root}/io/file_reader_test_common.h"
|
||||
"${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_writer_test.cc"
|
||||
"${draco_src_root}/io/obj_decoder_test.cc"
|
||||
"${draco_src_root}/io/obj_encoder_test.cc"
|
||||
"${draco_src_root}/io/ply_decoder_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}/mesh/corner_table_test.cc"
|
||||
"${draco_src_root}/mesh/mesh_are_equivalent_test.cc"
|
||||
"${draco_src_root}/mesh/mesh_cleanup_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_test.cc")
|
||||
|
||||
list(APPEND draco_gtest_all
|
||||
"${draco_root}/../googletest/googletest/src/gtest-all.cc")
|
||||
list(APPEND draco_gtest_main
|
||||
"${draco_root}/../googletest/googletest/src/gtest_main.cc")
|
||||
if(DRACO_TRANSCODER_SUPPORTED)
|
||||
list(
|
||||
APPEND draco_test_sources
|
||||
"${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)
|
||||
if(DRACO_TESTS)
|
||||
draco_setup_googletest()
|
||||
|
||||
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()
|
||||
|
||||
list(APPEND draco_test_defines GTEST_HAS_PTHREAD=0)
|
||||
|
||||
draco_add_library(TEST
|
||||
NAME
|
||||
draco_gtest
|
||||
TYPE
|
||||
STATIC
|
||||
SOURCES
|
||||
${draco_gtest_all}
|
||||
DEFINES
|
||||
${draco_defines}
|
||||
${draco_test_defines}
|
||||
INCLUDES
|
||||
${draco_test_include_paths})
|
||||
draco_add_library(
|
||||
TEST
|
||||
NAME draco_test_common
|
||||
TYPE STATIC
|
||||
SOURCES ${draco_test_common_sources}
|
||||
DEFINES ${draco_defines} ${draco_test_defines}
|
||||
INCLUDES ${draco_test_include_paths})
|
||||
|
||||
draco_add_library(TEST
|
||||
NAME
|
||||
draco_gtest_main
|
||||
TYPE
|
||||
STATIC
|
||||
SOURCES
|
||||
${draco_gtest_main}
|
||||
DEFINES
|
||||
${draco_defines}
|
||||
${draco_test_defines}
|
||||
INCLUDES
|
||||
${draco_test_include_paths})
|
||||
draco_add_library(
|
||||
TEST
|
||||
NAME draco_gtest
|
||||
TYPE STATIC
|
||||
SOURCES ${draco_gtest_all}
|
||||
DEFINES ${draco_defines} ${draco_test_defines}
|
||||
INCLUDES ${draco_test_include_paths})
|
||||
|
||||
draco_add_library(
|
||||
TEST
|
||||
NAME draco_gtest_main
|
||||
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_TEMP_DIR "${draco_build}/draco_test_temp")
|
||||
set(DRACO_TEST_ROOT_DIR "${draco_root}")
|
||||
file(MAKE_DIRECTORY "${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")
|
||||
|
||||
# Create the test targets.
|
||||
draco_add_executable(NAME
|
||||
draco_tests
|
||||
SOURCES
|
||||
${draco_test_sources}
|
||||
DEFINES
|
||||
${draco_defines}
|
||||
${draco_test_defines}
|
||||
INCLUDES
|
||||
${draco_test_include_paths}
|
||||
LIB_DEPS
|
||||
draco_static
|
||||
draco_gtest
|
||||
draco_gtest_main)
|
||||
draco_add_executable(
|
||||
TEST
|
||||
NAME draco_tests
|
||||
SOURCES ${draco_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(
|
||||
TEST
|
||||
NAME draco_factory_tests
|
||||
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()
|
||||
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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_DRACO_VARIABLES_CMAKE_
|
||||
|
@ -14,8 +28,7 @@ macro(draco_variable_must_be_directory variable_name)
|
|||
|
||||
if("${${variable_name}}" STREQUAL "")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Empty variable ${variable_name} is required to build draco.")
|
||||
FATAL_ERROR "Empty variable ${variable_name} is required to build draco.")
|
||||
endif()
|
||||
|
||||
if(NOT IS_DIRECTORY "${${variable_name}}")
|
||||
|
@ -44,7 +57,9 @@ macro(draco_dump_cmake_flag_variables)
|
|||
list(APPEND flag_variables "CMAKE_CXX_FLAGS_INIT" "CMAKE_CXX_FLAGS"
|
||||
"CMAKE_EXE_LINKER_FLAGS_INIT" "CMAKE_EXE_LINKER_FLAGS")
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
list(APPEND flag_variables "CMAKE_BUILD_TYPE"
|
||||
list(
|
||||
APPEND flag_variables
|
||||
"CMAKE_BUILD_TYPE"
|
||||
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
|
||||
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}"
|
||||
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
|
||||
|
|
|
@ -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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif() # DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_
|
||||
|
@ -16,9 +30,9 @@ if(NOT ANDROID_ABI)
|
|||
set(ANDROID_ABI arm64-v8a)
|
||||
endif()
|
||||
|
||||
# Force arm mode for 32-bit targets (instead of the default thumb) to improve
|
||||
# performance.
|
||||
if(NOT ANDROID_ARM_MODE)
|
||||
# Force arm mode for 32-bit arm targets (instead of the default thumb) to
|
||||
# improve performance.
|
||||
if(ANDROID_ABI MATCHES "^armeabi" AND NOT ANDROID_ARM_MODE)
|
||||
set(ANDROID_ARM_MODE arm)
|
||||
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_)
|
||||
return()
|
||||
endif()
|
||||
|
@ -13,5 +27,3 @@ set(CMAKE_C_COMPILER clang)
|
|||
set(CMAKE_C_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(CMAKE_CXX_COMPILER clang++)
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif()
|
||||
set(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_ 1)
|
||||
|
||||
if(XCODE)
|
||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif()
|
||||
set(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_ 1)
|
||||
|
||||
if(XCODE)
|
||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif()
|
||||
set(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_ 1)
|
||||
|
||||
if(XCODE)
|
||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||
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_)
|
||||
return()
|
||||
endif()
|
||||
set(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_ 1)
|
||||
|
||||
if(XCODE)
|
||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
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_)
|
||||
return()
|
||||
endif()
|
||||
set(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_ 1)
|
||||
|
||||
if(XCODE)
|
||||
# TODO(tomfinegan): Handle arm builds in Xcode.
|
||||
message(FATAL_ERROR "This toolchain does not support Xcode.")
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
return keyframe_animation_.SetTimestamps(timestamps_);
|
||||
}
|
||||
|
||||
|
@ -35,8 +36,9 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
|||
uint32_t num_components) {
|
||||
// Create and add animation data with.
|
||||
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);
|
||||
}
|
||||
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
|
||||
animation_data_);
|
||||
}
|
||||
|
@ -49,7 +51,7 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
|||
ASSERT_EQ(animation0.num_animations(), animation1.num_animations());
|
||||
|
||||
if (quantized) {
|
||||
// TODO(hemmer) : Add test for stable quantization.
|
||||
// TODO(b/199760123) : Add test for stable quantization.
|
||||
// Quantization will result in slightly different values.
|
||||
// Skip comparing values.
|
||||
return;
|
||||
|
@ -109,9 +111,8 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
|||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(
|
||||
encoder.EncodeKeyframeAnimation(keyframe_animation_, options, &buffer)
|
||||
.ok());
|
||||
DRACO_ASSERT_OK(
|
||||
encoder.EncodeKeyframeAnimation(keyframe_animation_, options, &buffer));
|
||||
|
||||
draco::DecoderBuffer dec_decoder;
|
||||
draco::KeyframeAnimationDecoder decoder;
|
||||
|
@ -122,8 +123,8 @@ class KeyframeAnimationEncodingTest : public ::testing::Test {
|
|||
std::unique_ptr<KeyframeAnimation> decoded_animation(
|
||||
new KeyframeAnimation());
|
||||
DecoderOptions dec_options;
|
||||
ASSERT_TRUE(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_animation.get()).ok());
|
||||
DRACO_ASSERT_OK(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_animation.get()));
|
||||
|
||||
// Verify if animation before and after compression is identical.
|
||||
CompareAnimationData<num_components_t>(keyframe_animation_,
|
||||
|
|
|
@ -24,8 +24,9 @@ class KeyframeAnimationTest : public ::testing::Test {
|
|||
|
||||
bool CreateAndAddTimestamps(int32_t 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);
|
||||
}
|
||||
return keyframe_animation_.SetTimestamps(timestamps_);
|
||||
}
|
||||
|
||||
|
@ -33,8 +34,9 @@ class KeyframeAnimationTest : public ::testing::Test {
|
|||
uint32_t num_components) {
|
||||
// Create and add animation data with.
|
||||
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);
|
||||
}
|
||||
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
|
||||
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 int num_components = GetTransformedNumComponents(src_attribute);
|
||||
const DataType dt = GetTransformedDataType(src_attribute);
|
||||
GeometryAttribute va;
|
||||
va.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
|
||||
GeometryAttribute ga;
|
||||
ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
|
||||
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->SetIdentityMapping();
|
||||
transformed_attribute->set_unique_id(src_attribute.unique_id());
|
||||
return transformed_attribute;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ GeometryAttribute::GeometryAttribute()
|
|||
unique_id_(0) {}
|
||||
|
||||
void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
|
||||
DataBuffer *buffer, int8_t num_components,
|
||||
DataBuffer *buffer, uint8_t num_components,
|
||||
DataType data_type, bool normalized,
|
||||
int64_t byte_stride, int64_t byte_offset) {
|
||||
buffer_ = buffer;
|
||||
|
|
|
@ -15,12 +15,18 @@
|
|||
#ifndef DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
|
||||
#define DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "draco/attributes/geometry_indices.h"
|
||||
#include "draco/core/data_buffer.h"
|
||||
#include "draco/core/hash_utils.h"
|
||||
#include "draco/draco_features.h"
|
||||
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||
#include "draco/core/status.h"
|
||||
#endif
|
||||
|
||||
namespace draco {
|
||||
|
||||
|
@ -51,6 +57,16 @@ class GeometryAttribute {
|
|||
// predefined use case. Such attributes are often used for a shader specific
|
||||
// data.
|
||||
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.
|
||||
// Always keep behind all named attributes.
|
||||
NAMED_ATTRIBUTES_COUNT,
|
||||
|
@ -58,7 +74,7 @@ class GeometryAttribute {
|
|||
|
||||
GeometryAttribute();
|
||||
// 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,
|
||||
int64_t byte_offset);
|
||||
bool IsValid() const { return buffer_ != nullptr; }
|
||||
|
@ -129,6 +145,17 @@ class GeometryAttribute {
|
|||
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
|
||||
// ConvertValue(AttributeValueIndex att_id,
|
||||
// int out_num_components,
|
||||
|
@ -233,10 +260,11 @@ class GeometryAttribute {
|
|||
// Returns the number of components that are stored for each entry.
|
||||
// For position attribute this is usually three (x,y,z),
|
||||
// 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,
|
||||
// that is, it should be divided by the max value of the data type.
|
||||
bool normalized() const { return normalized_; }
|
||||
void set_normalized(bool normalized) { normalized_ = normalized; }
|
||||
// The buffer storing the entire data of the attribute.
|
||||
const DataBuffer *buffer() const { return buffer_; }
|
||||
// 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.
|
||||
// OutT is the desired data type of the attribute.
|
||||
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 {
|
||||
const uint8_t *src_address = GetAddress(att_id);
|
||||
|
||||
|
@ -270,29 +298,10 @@ class GeometryAttribute {
|
|||
return false;
|
||||
}
|
||||
const T in_value = *reinterpret_cast<const T *>(src_address);
|
||||
|
||||
// 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_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()) {
|
||||
if (!ConvertComponentValue<T, OutT>(in_value, normalized_,
|
||||
out_value + i)) {
|
||||
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);
|
||||
}
|
||||
// Fill empty data for unused output components if needed.
|
||||
|
@ -302,12 +311,128 @@ class GeometryAttribute {
|
|||
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_;
|
||||
// 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
|
||||
// since the time it was attached.
|
||||
DataBufferDescriptor buffer_descriptor_;
|
||||
int8_t num_components_;
|
||||
uint8_t num_components_;
|
||||
DataType data_type_;
|
||||
bool normalized_;
|
||||
int64_t byte_stride_;
|
||||
|
@ -323,6 +448,54 @@ class GeometryAttribute {
|
|||
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
|
||||
|
||||
// Function object for using Attribute as a hash key.
|
||||
|
|
|
@ -222,4 +222,47 @@ AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
|
|||
}
|
||||
#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
|
||||
|
|
|
@ -133,6 +133,12 @@ class PointAttribute : public GeometryAttribute {
|
|||
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:
|
||||
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
|
||||
template <typename T>
|
||||
|
|
|
@ -15,14 +15,16 @@
|
|||
#include "draco/compression/attributes/attributes_encoder.h"
|
||||
|
||||
#include "draco/core/varint_encoding.h"
|
||||
#include "draco/draco_features.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
AttributesEncoder::AttributesEncoder()
|
||||
: point_cloud_encoder_(nullptr), point_cloud_(nullptr) {}
|
||||
|
||||
AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() {
|
||||
AddAttributeId(att_id);
|
||||
AttributesEncoder::AttributesEncoder(int point_attrib_id)
|
||||
: AttributesEncoder() {
|
||||
AddAttributeId(point_attrib_id);
|
||||
}
|
||||
|
||||
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) {
|
||||
const int32_t att_id = point_attribute_ids_[i];
|
||||
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->num_components()));
|
||||
out_buffer->Encode(static_cast<uint8_t>(pa->normalized()));
|
||||
|
|
|
@ -72,16 +72,19 @@ class PointAttributeVectorOutputIterator {
|
|||
|
||||
Self &operator*() { return *this; }
|
||||
// Still needed in some cases.
|
||||
// TODO(hemmer): remove.
|
||||
// TODO(b/199760123): Remove.
|
||||
// hardcoded to 3 based on legacy usage.
|
||||
const Self &operator=(const VectorD<CoeffT, 3> &val) {
|
||||
DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute.
|
||||
AttributeTuple &att = attributes_[0];
|
||||
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);
|
||||
DRACO_DCHECK_EQ(offset, 0); // expected to be zero
|
||||
attribute->SetAttributeValue(attribute->mapped_index(point_id_),
|
||||
&val[0] + offset);
|
||||
attribute->SetAttributeValue(avi, &val[0] + offset);
|
||||
return *this;
|
||||
}
|
||||
// Additional operator taking std::vector as argument.
|
||||
|
@ -89,6 +92,10 @@ class PointAttributeVectorOutputIterator {
|
|||
for (auto index = 0; index < attributes_.size(); index++) {
|
||||
AttributeTuple &att = attributes_[index];
|
||||
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 &data_size = std::get<3>(att);
|
||||
const uint32_t &num_components = std::get<4>(att);
|
||||
|
@ -103,10 +110,6 @@ class PointAttributeVectorOutputIterator {
|
|||
// redirect to copied 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);
|
||||
}
|
||||
return *this;
|
||||
|
@ -195,54 +198,55 @@ bool KdTreeAttributesDecoder::DecodePortableAttributes(
|
|||
data_size, num_components);
|
||||
total_dimensionality += num_components;
|
||||
}
|
||||
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
|
||||
typedef PointAttributeVectorOutputIterator<uint32_t> OutIt;
|
||||
OutIt out_it(atts);
|
||||
|
||||
switch (compression_level) {
|
||||
case 0: {
|
||||
DynamicIntegerPointsKdTreeDecoder<0> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<0, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
DynamicIntegerPointsKdTreeDecoder<1> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<1, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
DynamicIntegerPointsKdTreeDecoder<2> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<2, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
DynamicIntegerPointsKdTreeDecoder<3> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<3, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
DynamicIntegerPointsKdTreeDecoder<4> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<4, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
DynamicIntegerPointsKdTreeDecoder<5> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<5, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
DynamicIntegerPointsKdTreeDecoder<6> decoder(total_dimensionality);
|
||||
if (!decoder.DecodePoints(in_buffer, out_it)) {
|
||||
if (!DecodePoints<6, OutIt>(total_dimensionality, num_points, in_buffer,
|
||||
&out_it)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -253,6 +257,19 @@ bool KdTreeAttributesDecoder::DecodePortableAttributes(
|
|||
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(
|
||||
DecoderBuffer *in_buffer) {
|
||||
if (in_buffer->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 3)) {
|
||||
|
@ -336,6 +353,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
|||
return false;
|
||||
}
|
||||
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;
|
||||
if (!in_buffer->Decode(&compression_level)) {
|
||||
return false;
|
||||
|
@ -376,7 +397,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
|||
GetDecoder()->point_cloud()->attribute(att_id);
|
||||
attr->Reset(num_points);
|
||||
attr->SetIdentityMapping();
|
||||
};
|
||||
}
|
||||
|
||||
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
|
||||
|
||||
|
@ -455,7 +476,11 @@ bool KdTreeAttributesDecoder::TransformAttributeBackToSignedType(
|
|||
att->GetValue(avi, &unsigned_val[0]);
|
||||
for (int c = 0; c < att->num_components(); ++c) {
|
||||
// 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>(
|
||||
static_cast<int32_t>(unsigned_val[c]) +
|
||||
min_signed_values_[num_processed_signed_components + c]);
|
||||
|
|
|
@ -31,6 +31,10 @@ class KdTreeAttributesDecoder : public AttributesDecoder {
|
|||
bool TransformAttributesToOriginalFormat() override;
|
||||
|
||||
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>
|
||||
bool TransformAttributeBackToSignedType(PointAttribute *att,
|
||||
int num_processed_signed_components);
|
||||
|
|
|
@ -61,7 +61,7 @@ class OctahedronToolBox {
|
|||
return false;
|
||||
}
|
||||
quantization_bits_ = q;
|
||||
max_quantized_value_ = (1 << quantization_bits_) - 1;
|
||||
max_quantized_value_ = (1u << quantization_bits_) - 1;
|
||||
max_value_ = max_quantized_value_ - 1;
|
||||
dequantization_scale_ = 2.f / max_value_;
|
||||
center_value_ = max_value_ / 2;
|
||||
|
@ -208,7 +208,9 @@ class OctahedronToolBox {
|
|||
DRACO_DCHECK_LE(t, center_value_);
|
||||
DRACO_DCHECK_GE(s, -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 {
|
||||
|
@ -230,19 +232,29 @@ class OctahedronToolBox {
|
|||
sign_t = (*t > 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
const int32_t corner_point_s = sign_s * center_value_;
|
||||
const int32_t corner_point_t = sign_t * center_value_;
|
||||
*s = 2 * *s - corner_point_s;
|
||||
*t = 2 * *t - corner_point_t;
|
||||
// Perform the addition and subtraction using unsigned integers to avoid
|
||||
// signed integer overflows for bad data. Note that the result will be
|
||||
// unchanged for non-overflowing cases.
|
||||
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) {
|
||||
int32_t temp = *s;
|
||||
*s = -*t;
|
||||
*t = -temp;
|
||||
uint32_t temp = us;
|
||||
us = -ut;
|
||||
ut = -temp;
|
||||
} else {
|
||||
std::swap(*s, *t);
|
||||
std::swap(us, ut);
|
||||
}
|
||||
*s = (*s + corner_point_s) / 2;
|
||||
*t = (*t + corner_point_t) / 2;
|
||||
us = us + corner_point_s;
|
||||
ut = ut + corner_point_t;
|
||||
|
||||
*s = us;
|
||||
*t = ut;
|
||||
*s /= 2;
|
||||
*t /= 2;
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
@ -99,11 +101,17 @@ class PointDVector {
|
|||
data_(n_items * dimensionality),
|
||||
data0_(data_.data()) {}
|
||||
// random access iterator
|
||||
class PointDVectorIterator
|
||||
: public std::iterator<std::random_access_iterator_tag, size_t, size_t> {
|
||||
class PointDVectorIterator {
|
||||
friend class PointDVector;
|
||||
|
||||
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
|
||||
// specialized support
|
||||
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_parallelogram_shared.h"
|
||||
#include "draco/compression/bit_coders/rans_bit_decoder.h"
|
||||
#include "draco/core/math_utils.h"
|
||||
#include "draco/core/varint_decoding.h"
|
||||
#include "draco/draco_features.h"
|
||||
|
||||
|
@ -161,7 +162,8 @@ bool MeshPredictionSchemeConstrainedMultiParallelogramDecoder<
|
|||
if (!is_crease) {
|
||||
++num_used_parallelograms;
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
if (num_flags > this->mesh_data().corner_table()->num_corners()) {
|
||||
return false;
|
||||
}
|
||||
if (num_flags > 0) {
|
||||
is_crease_edge_[i].resize(num_flags);
|
||||
RAnsBitDecoder decoder;
|
||||
|
|
|
@ -392,7 +392,7 @@ bool MeshPredictionSchemeConstrainedMultiParallelogramEncoder<
|
|||
RAnsBitEncoder encoder;
|
||||
encoder.StartEncoding();
|
||||
// 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.
|
||||
for (int j = static_cast<int>(is_crease_edge_[i].size()) -
|
||||
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_parallelogram_shared.h"
|
||||
#include "draco/core/math_utils.h"
|
||||
#include "draco/draco_features.h"
|
||||
|
||||
namespace draco {
|
||||
|
@ -89,7 +90,8 @@ bool MeshPredictionSchemeMultiParallelogramDecoder<DataTypeT, TransformT,
|
|||
p, corner_id, table, *vertex_to_data_map, out_data,
|
||||
num_components, parallelogram_pred_vals.get())) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ class MeshPredictionSchemeTexCoordsDecoder
|
|||
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);
|
||||
|
||||
private:
|
||||
|
@ -123,6 +123,10 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
|||
ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data,
|
||||
int /* size */, int num_components,
|
||||
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;
|
||||
entry_to_point_id_map_ = entry_to_point_id_map;
|
||||
predicted_value_ =
|
||||
|
@ -133,7 +137,9 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
|||
static_cast<int>(this->mesh_data().data_to_corner_map()->size());
|
||||
for (int p = 0; p < corner_map_size; ++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;
|
||||
this->transform().ComputeOriginalValue(
|
||||
|
@ -159,6 +165,11 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
|||
if (num_orientations == 0) {
|
||||
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);
|
||||
bool last_orientation = true;
|
||||
RAnsBitDecoder decoder;
|
||||
|
@ -177,7 +188,7 @@ bool MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, 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,
|
||||
int data_id) {
|
||||
// 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);
|
||||
if (p_uv == n_uv) {
|
||||
// We cannot do a reliable prediction on degenerated UV triangles.
|
||||
predicted_value_[0] = static_cast<int>(p_uv[0]);
|
||||
predicted_value_[1] = static_cast<int>(p_uv[1]);
|
||||
return;
|
||||
// Technically floats > INT_MAX are undefined, but compilers will
|
||||
// convert those values to INT_MIN. We are being explicit here for asan.
|
||||
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.
|
||||
|
@ -282,32 +301,40 @@ void MeshPredictionSchemeTexCoordsDecoder<DataTypeT, TransformT, MeshDataT>::
|
|||
const float pnvs = pn_uv[1] * s + n_uv[1];
|
||||
const float pnvt = pn_uv[1] * t;
|
||||
Vector2f predicted_uv;
|
||||
if (orientations_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// When decoding the data, we already know which orientation to use.
|
||||
const bool orientation = orientations_.back();
|
||||
orientations_.pop_back();
|
||||
if (orientation)
|
||||
if (orientation) {
|
||||
predicted_uv = Vector2f(pnus - pnvt, pnvs + pnut);
|
||||
else
|
||||
} else {
|
||||
predicted_uv = Vector2f(pnus + pnvt, pnvs - pnut);
|
||||
|
||||
}
|
||||
if (std::is_integral<DataTypeT>::value) {
|
||||
// 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;
|
||||
} 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;
|
||||
} else {
|
||||
predicted_value_[1] = static_cast<int>(floor(predicted_uv[1] + 0.5));
|
||||
predicted_value_[1] = static_cast<int>(v);
|
||||
}
|
||||
} else {
|
||||
predicted_value_[0] = static_cast<int>(predicted_uv[0]);
|
||||
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
|
||||
// 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) {
|
||||
predicted_value_[i] = 0;
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_components_; ++i) {
|
||||
predicted_value_[i] = data[data_offset + i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
|
|
@ -98,7 +98,10 @@ bool MeshPredictionSchemeTexCoordsPortableEncoder<DataTypeT, TransformT,
|
|||
static_cast<int>(this->mesh_data().data_to_corner_map()->size() - 1);
|
||||
p >= 0; --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;
|
||||
this->transform().ComputeCorrection(in_data + dst_offset,
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "draco/attributes/point_attribute.h"
|
||||
#include "draco/core/math_utils.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);
|
||||
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) {
|
||||
// Both other corners have available UV coordinates for prediction.
|
||||
const VectorD<int64_t, 2> n_uv = GetTexCoordForEntryId(next_data_id, data);
|
||||
const VectorD<int64_t, 2> p_uv = GetTexCoordForEntryId(prev_data_id, data);
|
||||
const Vec2 n_uv = GetTexCoordForEntryId(next_data_id, data);
|
||||
const Vec2 p_uv = GetTexCoordForEntryId(prev_data_id, data);
|
||||
if (p_uv == n_uv) {
|
||||
// We cannot do a reliable prediction on degenerated UV triangles.
|
||||
predicted_value_[0] = p_uv[0];
|
||||
|
@ -117,9 +124,9 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
|||
}
|
||||
|
||||
// Get positions at all corners.
|
||||
const VectorD<int64_t, 3> tip_pos = GetPositionForEntryId(data_id);
|
||||
const VectorD<int64_t, 3> next_pos = GetPositionForEntryId(next_data_id);
|
||||
const VectorD<int64_t, 3> prev_pos = GetPositionForEntryId(prev_data_id);
|
||||
const Vec3 tip_pos = GetPositionForEntryId(data_id);
|
||||
const Vec3 next_pos = GetPositionForEntryId(next_data_id);
|
||||
const Vec3 prev_pos = GetPositionForEntryId(prev_data_id);
|
||||
// We use the positions of the above triangle to predict the texture
|
||||
// coordinate on the tip corner C.
|
||||
// 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
|
||||
// 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();
|
||||
if (pn_norm2_squared != 0) {
|
||||
// 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
|
||||
// |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|.
|
||||
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 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
|
||||
// compute the normalized factor |s|, but rather we perform all operations
|
||||
// over UV vectors in a non-normalized coordinate system scaled with a
|
||||
|
@ -153,19 +160,30 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
|||
//
|
||||
// x_uv = X_UV * PN.Norm2Squared()
|
||||
//
|
||||
const VectorD<int64_t, 2> x_uv =
|
||||
n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
|
||||
|
||||
const int64_t n_uv_absmax_element =
|
||||
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 =
|
||||
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) {
|
||||
// return false if squared length calculation would overflow.
|
||||
// Return false if squared length calculation would overflow.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute squared length of vector CX in position coordinate system:
|
||||
const VectorD<int64_t, 3> x_pos =
|
||||
next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
|
||||
const Vec3 x_pos = next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
|
||||
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
|
||||
|
@ -182,7 +200,7 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
|||
//
|
||||
// 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()
|
||||
const uint64_t norm_squared =
|
||||
IntSqrt(cx_norm2_squared * pn_norm2_squared);
|
||||
|
@ -191,17 +209,15 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
|||
|
||||
// Predicted uv coordinate is then computed by either adding or
|
||||
// subtracting CX_UV to/from X_UV.
|
||||
VectorD<int64_t, 2> predicted_uv;
|
||||
Vec2 predicted_uv;
|
||||
if (is_encoder_t) {
|
||||
// When encoding, compute both possible vectors and determine which one
|
||||
// results in a better prediction.
|
||||
// Both vectors need to be transformed back from the scaled space to
|
||||
// the real UV coordinate space.
|
||||
const VectorD<int64_t, 2> predicted_uv_0((x_uv + cx_uv) /
|
||||
pn_norm2_squared);
|
||||
const VectorD<int64_t, 2> predicted_uv_1((x_uv - cx_uv) /
|
||||
pn_norm2_squared);
|
||||
const VectorD<int64_t, 2> c_uv = GetTexCoordForEntryId(data_id, data);
|
||||
const Vec2 predicted_uv_0((x_uv + cx_uv) / pn_norm2_squared);
|
||||
const Vec2 predicted_uv_1((x_uv - cx_uv) / pn_norm2_squared);
|
||||
const Vec2 c_uv = GetTexCoordForEntryId(data_id, data);
|
||||
if ((c_uv - predicted_uv_0).SquaredNorm() <
|
||||
(c_uv - predicted_uv_1).SquaredNorm()) {
|
||||
predicted_uv = predicted_uv_0;
|
||||
|
@ -217,10 +233,12 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
|||
}
|
||||
const bool orientation = orientations_.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) {
|
||||
predicted_uv = (x_uv + cx_uv) / pn_norm2_squared;
|
||||
predicted_uv = Vec2(Vec2u(x_uv) + Vec2u(cx_uv)) / pn_norm2_squared;
|
||||
} 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]);
|
||||
|
|
|
@ -18,22 +18,58 @@ namespace draco {
|
|||
|
||||
PredictionSchemeMethod SelectPredictionMethod(
|
||||
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.
|
||||
return PREDICTION_DIFFERENCE;
|
||||
}
|
||||
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
||||
// 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);
|
||||
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
|
||||
if (encoder->options()->GetSpeed() < 4) {
|
||||
if (att_quant != -1 &&
|
||||
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.
|
||||
return MESH_PREDICTION_TEX_COORDS_PORTABLE;
|
||||
}
|
||||
}
|
||||
if (att->attribute_type() == GeometryAttribute::NORMAL) {
|
||||
#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
|
||||
if (encoder->options()->GetSpeed() < 4) {
|
||||
if (options.GetSpeed() < 4) {
|
||||
// Use geometric normal prediction for speeds 0, 1, 2, 3.
|
||||
// For this prediction, the position attribute needs to be either
|
||||
// integer or quantized as well.
|
||||
|
@ -43,8 +79,8 @@ PredictionSchemeMethod SelectPredictionMethod(
|
|||
encoder->point_cloud()->GetNamedAttribute(
|
||||
GeometryAttribute::POSITION);
|
||||
if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) ||
|
||||
encoder->options()->GetAttributeInt(
|
||||
pos_att_id, "quantization_bits", -1) > 0)) {
|
||||
options.GetAttributeInt(pos_att_id, "quantization_bits",
|
||||
-1) > 0)) {
|
||||
return MESH_PREDICTION_GEOMETRIC_NORMAL;
|
||||
}
|
||||
}
|
||||
|
@ -52,11 +88,10 @@ PredictionSchemeMethod SelectPredictionMethod(
|
|||
return PREDICTION_DIFFERENCE; // default
|
||||
}
|
||||
// Handle other attribute types.
|
||||
if (encoder->options()->GetSpeed() >= 8) {
|
||||
if (options.GetSpeed() >= 8) {
|
||||
return PREDICTION_DIFFERENCE;
|
||||
}
|
||||
if (encoder->options()->GetSpeed() >= 2 ||
|
||||
encoder->point_cloud()->num_points() < 40) {
|
||||
if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) {
|
||||
// Parallelogram prediction is used for speeds 2 - 7 or when the overhead
|
||||
// of using constrained multi-parallelogram would be too high.
|
||||
return MESH_PREDICTION_PARALLELOGRAM;
|
||||
|
|
|
@ -38,6 +38,10 @@ namespace draco {
|
|||
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||
const PointCloudEncoder *encoder);
|
||||
|
||||
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||
const EncoderOptions &options,
|
||||
const PointCloudEncoder *encoder);
|
||||
|
||||
// Factory class for creating mesh prediction schemes.
|
||||
template <typename DataTypeT>
|
||||
struct MeshPredictionSchemeEncoderFactory {
|
||||
|
@ -97,10 +101,11 @@ CreatePredictionSchemeForEncoder(PredictionSchemeMethod method, int att_id,
|
|||
// template nature of the prediction schemes).
|
||||
const MeshEncoder *const mesh_encoder =
|
||||
static_cast<const MeshEncoder *>(encoder);
|
||||
const uint16_t bitstream_version = kDracoMeshBitstreamVersion;
|
||||
auto ret = CreateMeshPredictionScheme<
|
||||
MeshEncoder, PredictionSchemeEncoder<DataTypeT, TransformT>,
|
||||
MeshPredictionSchemeEncoderFactory<DataTypeT>>(
|
||||
mesh_encoder, method, att_id, transform, kDracoMeshBitstreamVersion);
|
||||
mesh_encoder, method, att_id, transform, bitstream_version);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h"
|
||||
#include "draco/core/decoder_buffer.h"
|
||||
#include "draco/core/macros.h"
|
||||
#include "draco/core/math_utils.h"
|
||||
#include "draco/core/vector_d.h"
|
||||
|
||||
namespace draco {
|
||||
|
@ -98,9 +99,8 @@ class PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform
|
|||
if (!pred_is_in_bottom_left) {
|
||||
pred = this->RotatePoint(pred, rotation_count);
|
||||
}
|
||||
Point2 orig = pred + corr;
|
||||
orig[0] = this->ModMax(orig[0]);
|
||||
orig[1] = this->ModMax(orig[1]);
|
||||
Point2 orig(this->ModMax(AddAsUnsigned(pred[0], corr[0])),
|
||||
this->ModMax(AddAsUnsigned(pred[1], corr[1])));
|
||||
if (!pred_is_in_bottom_left) {
|
||||
const int32_t reverse_rotation_count = (4 - rotation_count) % 4;
|
||||
orig = this->RotatePoint(orig, reverse_rotation_count);
|
||||
|
|
|
@ -25,10 +25,10 @@ class PredictionSchemeNormalOctahedronCanonicalizedTransformTest
|
|||
Transform;
|
||||
typedef Transform::Point2 Point2;
|
||||
|
||||
void TestComputeCorrection(const Transform &transform, const int32_t &ox,
|
||||
const int32_t &oy, const int32_t &px,
|
||||
const int32_t &py, const int32_t &cx,
|
||||
const int32_t &cy) {
|
||||
void TestComputeCorrection(const Transform &transform, const int32_t ox,
|
||||
const int32_t oy, const int32_t px,
|
||||
const int32_t py, const int32_t cx,
|
||||
const int32_t cy) {
|
||||
const int32_t o[2] = {ox + 7, oy + 7};
|
||||
const int32_t p[2] = {px + 7, py + 7};
|
||||
int32_t corr[2] = {500, 500};
|
||||
|
@ -38,7 +38,7 @@ class PredictionSchemeNormalOctahedronCanonicalizedTransformTest
|
|||
}
|
||||
|
||||
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);
|
||||
ASSERT_EQ(rot_dir, rotation_count);
|
||||
}
|
||||
|
|
|
@ -80,19 +80,31 @@ class PredictionSchemeNormalOctahedronDecodingTransform
|
|||
private:
|
||||
Point2 ComputeOriginalValue(Point2 pred, const Point2 &corr) const {
|
||||
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]);
|
||||
if (!pred_is_in_diamond) {
|
||||
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[1] = this->ModMax(orig[1]);
|
||||
if (!pred_is_in_diamond) {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,10 +23,10 @@ class PredictionSchemeNormalOctahedronTransformTest : public ::testing::Test {
|
|||
Transform;
|
||||
typedef Transform::Point2 Point2;
|
||||
|
||||
void TestComputeCorrection(const Transform &transform, const int32_t &ox,
|
||||
const int32_t &oy, const int32_t &px,
|
||||
const int32_t &py, const int32_t &cx,
|
||||
const int32_t &cy) {
|
||||
void TestComputeCorrection(const Transform &transform, const int32_t ox,
|
||||
const int32_t oy, const int32_t px,
|
||||
const int32_t py, const int32_t cx,
|
||||
const int32_t cy) {
|
||||
const int32_t o[2] = {ox + 7, oy + 7};
|
||||
const int32_t p[2] = {px + 7, py + 7};
|
||||
int32_t corr[2] = {500, 500};
|
||||
|
|
|
@ -70,10 +70,10 @@ class PredictionSchemeWrapTransformBase {
|
|||
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 {
|
||||
DRACO_DCHECK(false);
|
||||
return -1;
|
||||
|
|
|
@ -148,11 +148,12 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues(
|
|||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_values > 0 && (prediction_scheme_ == nullptr ||
|
||||
!prediction_scheme_->AreCorrectionsPositive())) {
|
||||
|
@ -228,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) {
|
|||
|
||||
void SequentialIntegerAttributeDecoder::PreparePortableAttribute(
|
||||
int num_entries, int num_components) {
|
||||
GeometryAttribute va;
|
||||
va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
|
||||
GeometryAttribute ga;
|
||||
ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
|
||||
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->Reset(num_entries);
|
||||
port_att->set_unique_id(attribute()->unique_id());
|
||||
SetPortableAttribute(std::move(port_att));
|
||||
}
|
||||
|
||||
|
|
|
@ -138,9 +138,11 @@ bool SequentialIntegerAttributeEncoder::EncodeValues(
|
|||
// All integer values are initialized. Process them using the prediction
|
||||
// scheme if we have one.
|
||||
if (prediction_scheme_) {
|
||||
prediction_scheme_->ComputeCorrectionValues(
|
||||
portable_attribute_data, &encoded_data[0], num_values, num_components,
|
||||
point_ids.data());
|
||||
if (!prediction_scheme_->ComputeCorrectionValues(
|
||||
portable_attribute_data, &encoded_data[0], num_values,
|
||||
num_components, point_ids.data())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (prediction_scheme_ == nullptr ||
|
||||
|
|
|
@ -20,8 +20,9 @@ namespace draco {
|
|||
|
||||
bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder,
|
||||
int attribute_id) {
|
||||
if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id))
|
||||
if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) {
|
||||
return false;
|
||||
}
|
||||
// Currently this encoder works only for 3-component normal vectors.
|
||||
if (attribute()->num_components() != 3) {
|
||||
return false;
|
||||
|
|
|
@ -47,14 +47,13 @@ class DirectBitDecoder {
|
|||
|
||||
// Decode the next |nbits| and return the sequence in |value|. |nbits| must be
|
||||
// > 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 > 0);
|
||||
const int remaining = 32 - num_used_bits_;
|
||||
if (nbits <= remaining) {
|
||||
if (pos_ == bits_.end()) {
|
||||
*value = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
*value = (*pos_ << num_used_bits_) >> (32 - nbits);
|
||||
num_used_bits_ += nbits;
|
||||
|
@ -64,8 +63,7 @@ class DirectBitDecoder {
|
|||
}
|
||||
} else {
|
||||
if (pos_ + 1 == bits_.end()) {
|
||||
*value = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const uint32_t value_l = ((*pos_) << num_used_bits_);
|
||||
num_used_bits_ = nbits - remaining;
|
||||
|
@ -73,6 +71,7 @@ class DirectBitDecoder {
|
|||
const uint32_t value_r = (*pos_) >> (32 - num_used_bits_);
|
||||
*value = (value_l >> (32 - num_used_bits_ - remaining)) | value_r;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndDecoding() {}
|
||||
|
|
|
@ -65,6 +65,10 @@ class EncoderOptionsBase : public DracoOptions<AttributeKeyT> {
|
|||
this->SetGlobalInt("encoding_speed", encoding_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.
|
||||
// Encoder will always use only supported features when encoding the input
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
#include <cinttypes>
|
||||
#include <sstream>
|
||||
|
||||
#include "draco/compression/encode.h"
|
||||
#include "draco/core/draco_test_base.h"
|
||||
#include "draco/core/draco_test_utils.h"
|
||||
#include "draco/io/file_utils.h"
|
||||
#include "draco/io/obj_encoder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -166,4 +168,78 @@ TEST_F(DecodeTest, TestSkipAttributeTransformWithNoQuantization) {
|
|||
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
|
||||
|
|
|
@ -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.
|
||||
void SetEncodingMethod(int encoding_method);
|
||||
|
||||
protected:
|
||||
// Creates encoder options for the expert encoder used during the actual
|
||||
// encoding.
|
||||
EncoderOptions CreateExpertEncoderOptions(const PointCloud &pc) const;
|
||||
|
|
|
@ -98,7 +98,7 @@ class EncoderBase {
|
|||
"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 (!(prediction_scheme == PREDICTION_DIFFERENCE ||
|
||||
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "draco/core/draco_test_base.h"
|
||||
#include "draco/core/draco_test_utils.h"
|
||||
#include "draco/core/vector_d.h"
|
||||
#include "draco/io/file_utils.h"
|
||||
#include "draco/io/obj_decoder.h"
|
||||
#include "draco/mesh/triangle_soup_mesh_builder.h"
|
||||
#include "draco/point_cloud/point_cloud_builder.h"
|
||||
|
@ -213,16 +214,14 @@ class EncodeTest : public ::testing::Test {
|
|||
draco::Decoder decoder;
|
||||
|
||||
if (mesh) {
|
||||
auto maybe_mesh = decoder.DecodeMeshFromBuffer(&decoder_buffer);
|
||||
ASSERT_TRUE(maybe_mesh.ok());
|
||||
auto decoded_mesh = std::move(maybe_mesh).value();
|
||||
DRACO_ASSIGN_OR_ASSERT(auto decoded_mesh,
|
||||
decoder.DecodeMeshFromBuffer(&decoder_buffer));
|
||||
ASSERT_NE(decoded_mesh, nullptr);
|
||||
ASSERT_EQ(decoded_mesh->num_points(), encoder.num_encoded_points());
|
||||
ASSERT_EQ(decoded_mesh->num_faces(), encoder.num_encoded_faces());
|
||||
} else {
|
||||
auto maybe_pc = decoder.DecodePointCloudFromBuffer(&decoder_buffer);
|
||||
ASSERT_TRUE(maybe_pc.ok());
|
||||
auto decoded_pc = std::move(maybe_pc).value();
|
||||
DRACO_ASSIGN_OR_ASSERT(
|
||||
auto decoded_pc, decoder.DecodePointCloudFromBuffer(&decoder_buffer));
|
||||
ASSERT_EQ(decoded_pc->num_points(), encoder.num_encoded_points());
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +273,7 @@ TEST_F(EncodeTest, TestLinesObj) {
|
|||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 16);
|
||||
|
||||
draco::EncoderBuffer buffer;
|
||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||
}
|
||||
|
||||
TEST_F(EncodeTest, TestQuantizedInfinity) {
|
||||
|
@ -315,7 +314,7 @@ TEST_F(EncodeTest, TestUnquantizedInfinity) {
|
|||
encoder.SetEncodingMethod(draco::POINT_CLOUD_SEQUENTIAL_ENCODING);
|
||||
|
||||
draco::EncoderBuffer buffer;
|
||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||
}
|
||||
|
||||
TEST_F(EncodeTest, TestQuantizedAndUnquantizedAttributes) {
|
||||
|
@ -330,7 +329,7 @@ TEST_F(EncodeTest, TestQuantizedAndUnquantizedAttributes) {
|
|||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 11);
|
||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 0);
|
||||
draco::EncoderBuffer buffer;
|
||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||
}
|
||||
|
||||
TEST_F(EncodeTest, TestKdTreeEncoding) {
|
||||
|
@ -348,7 +347,7 @@ TEST_F(EncodeTest, TestKdTreeEncoding) {
|
|||
// Now set quantization for the position attribute which should make
|
||||
// the encoder happy.
|
||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 16);
|
||||
ASSERT_TRUE(encoder.EncodePointCloudToBuffer(*pc, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.EncodePointCloudToBuffer(*pc, &buffer));
|
||||
}
|
||||
|
||||
TEST_F(EncodeTest, TestTrackingOfNumberOfEncodedEntries) {
|
||||
|
@ -373,7 +372,7 @@ TEST_F(EncodeTest, TestTrackingOfNumberOfEncodedEntriesNotSet) {
|
|||
draco::EncoderBuffer buffer;
|
||||
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_faces(), 0);
|
||||
}
|
||||
|
@ -404,4 +403,170 @@ TEST_F(EncodeTest, TestNoPosQuantizationNormalCoding) {
|
|||
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
|
||||
|
|
|
@ -391,7 +391,6 @@ class RAnsEncoder {
|
|||
ans_.buf[ans_.buf_offset++] = 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 / p) * rans_precision + ans_.state % p + sym->cum_prob;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,13 @@ bool RAnsSymbolDecoder<unique_symbols_bit_length_t>::Create(
|
|||
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_);
|
||||
if (num_symbols_ == 0) {
|
||||
return true;
|
||||
|
|
|
@ -125,7 +125,7 @@ bool RAnsSymbolEncoder<unique_symbols_bit_length_t>::Create(
|
|||
for (int i = 0; i < num_symbols; ++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_));
|
||||
if (total_rans_prob < rans_precision_) {
|
||||
// This happens rather infrequently, just add the extra needed precision
|
||||
|
|
|
@ -72,7 +72,7 @@ bool DecodeTaggedSymbols(uint32_t num_values, int num_components,
|
|||
int value_id = 0;
|
||||
for (uint32_t i = 0; i < num_values; i += num_components) {
|
||||
// Decode the tag.
|
||||
const int bit_length = tag_decoder.DecodeSymbol();
|
||||
const uint32_t bit_length = tag_decoder.DecodeSymbol();
|
||||
// Decode the actual value.
|
||||
for (int j = 0; j < num_components; ++j) {
|
||||
uint32_t val;
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
//
|
||||
#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_sequential_encoder.h"
|
||||
#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED
|
||||
|
@ -21,6 +27,9 @@
|
|||
#include "draco/compression/point_cloud/point_cloud_sequential_encoder.h"
|
||||
#endif
|
||||
|
||||
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||
#include "draco/core/bit_utils.h"
|
||||
#endif
|
||||
namespace draco {
|
||||
|
||||
ExpertEncoder::ExpertEncoder(const PointCloud &point_cloud)
|
||||
|
@ -101,6 +110,11 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
|
|||
|
||||
Status ExpertEncoder::EncodeMeshToBuffer(const Mesh &m,
|
||||
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;
|
||||
// Select the encoding method only based on the provided options.
|
||||
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->SetMesh(m);
|
||||
|
||||
DRACO_RETURN_IF_ERROR(encoder->Encode(options(), out_buffer));
|
||||
|
||||
set_num_encoded_points(encoder->num_encoded_points());
|
||||
|
@ -179,4 +194,107 @@ Status ExpertEncoder::SetAttributePredictionScheme(
|
|||
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
|
||||
|
|
|
@ -138,6 +138,12 @@ class ExpertEncoder : public EncoderBase<EncoderOptions> {
|
|||
|
||||
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 Mesh *mesh_;
|
||||
};
|
||||
|
|
|
@ -454,7 +454,7 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity() {
|
|||
#endif
|
||||
|
||||
// Decode connectivity of non-position attributes.
|
||||
if (attribute_data_.size() > 0) {
|
||||
if (!attribute_data_.empty()) {
|
||||
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
||||
if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) {
|
||||
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));
|
||||
}
|
||||
// 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());
|
||||
|
@ -574,6 +577,17 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
const CornerIndex corner_b =
|
||||
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.
|
||||
const CornerIndex corner(3 * face.value());
|
||||
// Update opposite corner mappings.
|
||||
|
@ -616,6 +630,11 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
return -1;
|
||||
}
|
||||
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".
|
||||
const CornerIndex corner(3 * face.value());
|
||||
|
@ -681,10 +700,14 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
}
|
||||
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 ||
|
||||
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 tempered with.
|
||||
// should not happen unless the input was tampered with.
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -713,9 +736,15 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
|
||||
// Also update the vertex id at corner "n" and all corners that are
|
||||
// connected to it in the CCW direction.
|
||||
const CornerIndex first_corner = corner_n;
|
||||
while (corner_n != kInvalidCornerIndex) {
|
||||
corner_table_->MapCornerToVertex(corner_n, vertex_p);
|
||||
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
|
||||
// isolated).
|
||||
|
@ -800,7 +829,7 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
return -1; // Unexpected number of decoded vertices.
|
||||
}
|
||||
// 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();
|
||||
active_corner_stack.pop_back();
|
||||
const bool interior_face =
|
||||
|
@ -842,6 +871,18 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
const CornerIndex corner_c =
|
||||
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 =
|
||||
corner_table_->Vertex(corner_table_->Next(corner_c));
|
||||
|
||||
|
@ -894,6 +935,11 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
|||
VertexCornersIterator<CornerTable> vcit(corner_table_.get(), src_vert);
|
||||
for (; !vcit.End(); ++vcit) {
|
||||
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_->SetLeftMostCorner(invalid_vert,
|
||||
|
|
|
@ -31,7 +31,6 @@ bool MeshEdgebreakerEncoder::InitializeEncoder() {
|
|||
impl_ = nullptr;
|
||||
// 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.
|
||||
// TODO(b/111065939): Check if this can be improved.
|
||||
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
|
||||
|
||||
int selected_edgebreaker_method =
|
||||
|
|
|
@ -408,7 +408,7 @@ Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
|
|||
init_face_connectivity_corners.begin(),
|
||||
init_face_connectivity_corners.end());
|
||||
// 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.
|
||||
visited_faces_.assign(mesh_->num_faces(), false);
|
||||
for (CornerIndex ci : processed_connectivity_corners_) {
|
||||
|
|
|
@ -177,7 +177,6 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface {
|
|||
uint32_t num_split_symbols_;
|
||||
|
||||
// Struct holding data used for encoding each non-position attribute.
|
||||
// TODO(ostava): This should be probably renamed to something better.
|
||||
struct AttributeData {
|
||||
AttributeData() : attribute_index(-1), is_connectivity_used(true) {}
|
||||
int attribute_index;
|
||||
|
|
|
@ -44,7 +44,7 @@ class MeshEdgebreakerEncodingTest : public ::testing::Test {
|
|||
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
||||
encoder_options.SetSpeed(10 - compression_level, 10 - compression_level);
|
||||
encoder.SetMesh(*mesh);
|
||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer));
|
||||
|
||||
DecoderBuffer dec_buffer;
|
||||
dec_buffer.Init(buffer.data(), buffer.size());
|
||||
|
@ -52,15 +52,14 @@ class MeshEdgebreakerEncodingTest : public ::testing::Test {
|
|||
|
||||
std::unique_ptr<Mesh> decoded_mesh(new Mesh());
|
||||
DecoderOptions dec_options;
|
||||
ASSERT_TRUE(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh.get()).ok());
|
||||
DRACO_ASSERT_OK(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh.get()));
|
||||
|
||||
// Cleanup the input mesh to make sure that input and output can be
|
||||
// compared (edgebreaker method discards degenerated triangles and isolated
|
||||
// vertices).
|
||||
const MeshCleanupOptions options;
|
||||
MeshCleanup cleanup;
|
||||
ASSERT_TRUE(cleanup(mesh, options)) << "Failed to clean the input mesh.";
|
||||
DRACO_ASSERT_OK(MeshCleanup::Cleanup(mesh, options));
|
||||
|
||||
MeshAreEquivalent eq;
|
||||
ASSERT_TRUE(eq(*mesh, *decoded_mesh.get()))
|
||||
|
@ -102,8 +101,8 @@ TEST_F(MeshEdgebreakerEncodingTest, TestEncoderReuse) {
|
|||
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
||||
encoder.SetMesh(*mesh);
|
||||
EncoderBuffer buffer_0, buffer_1;
|
||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer_0).ok());
|
||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer_1).ok());
|
||||
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer_0));
|
||||
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer_1));
|
||||
|
||||
// Make sure both buffer are identical.
|
||||
ASSERT_EQ(buffer_0.size(), buffer_1.size());
|
||||
|
@ -123,7 +122,7 @@ TEST_F(MeshEdgebreakerEncodingTest, TestDecoderReuse) {
|
|||
EncoderOptions encoder_options = EncoderOptions::CreateDefaultOptions();
|
||||
encoder.SetMesh(*mesh);
|
||||
EncoderBuffer buffer;
|
||||
ASSERT_TRUE(encoder.Encode(encoder_options, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.Encode(encoder_options, &buffer));
|
||||
|
||||
DecoderBuffer dec_buffer;
|
||||
dec_buffer.Init(buffer.data(), buffer.size());
|
||||
|
@ -133,13 +132,13 @@ TEST_F(MeshEdgebreakerEncodingTest, TestDecoderReuse) {
|
|||
// Decode the mesh two times.
|
||||
std::unique_ptr<Mesh> decoded_mesh_0(new Mesh());
|
||||
DecoderOptions dec_options;
|
||||
ASSERT_TRUE(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_0.get()).ok());
|
||||
DRACO_ASSERT_OK(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_0.get()));
|
||||
|
||||
dec_buffer.Init(buffer.data(), buffer.size());
|
||||
std::unique_ptr<Mesh> decoded_mesh_1(new Mesh());
|
||||
ASSERT_TRUE(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_1.get()).ok());
|
||||
DRACO_ASSERT_OK(
|
||||
decoder.Decode(dec_options, &dec_buffer, decoded_mesh_1.get()));
|
||||
|
||||
// Make sure both of the meshes are identical.
|
||||
MeshAreEquivalent eq;
|
||||
|
@ -169,7 +168,7 @@ TEST_F(MeshEdgebreakerEncodingTest, TestSingleConnectivityEncoding) {
|
|||
encoder.SetAttributeQuantization(GeometryAttribute::TEX_COORD, 8);
|
||||
encoder.SetAttributeQuantization(GeometryAttribute::NORMAL, 8);
|
||||
encoder.SetEncodingMethod(MESH_EDGEBREAKER_ENCODING);
|
||||
ASSERT_TRUE(encoder.EncodeMeshToBuffer(*mesh, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer));
|
||||
|
||||
DecoderBuffer dec_buffer;
|
||||
dec_buffer.Init(buffer.data(), buffer.size());
|
||||
|
@ -216,7 +215,7 @@ TEST_F(MeshEdgebreakerEncodingTest, TestWrongAttributeOrder) {
|
|||
encoder.SetAttributeQuantization(GeometryAttribute::POSITION, 8);
|
||||
encoder.SetAttributeQuantization(GeometryAttribute::NORMAL, 8);
|
||||
encoder.SetEncodingMethod(MESH_EDGEBREAKER_ENCODING);
|
||||
ASSERT_TRUE(encoder.EncodeMeshToBuffer(*mesh, &buffer).ok());
|
||||
DRACO_ASSERT_OK(encoder.EncodeMeshToBuffer(*mesh, &buffer));
|
||||
|
||||
DecoderBuffer dec_buffer;
|
||||
dec_buffer.Init(buffer.data(), buffer.size());
|
||||
|
|
|
@ -50,8 +50,6 @@ namespace draco {
|
|||
// \ / 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 {
|
||||
TOPOLOGY_C = 0x0, // 0
|
||||
TOPOLOGY_S = 0x1, // 1 0 0
|
||||
|
|
|
@ -129,7 +129,11 @@ class MeshEdgebreakerTraversalValenceDecoder
|
|||
if (context_counter < 0) {
|
||||
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];
|
||||
} else {
|
||||
#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