Compare commits

...

140 Commits

Author SHA1 Message Date
Ashley Rogers 6ff8de351e
Merge 111429032d into 3e68c7a1c2 2025-11-21 20:09:31 +00:00
Ashley Rogers 111429032d Merge from main
cesium-native / Quick Checks (push) Has been cancelled Details
cesium-native / Linting (push) Has been cancelled Details
cesium-native / Documentation (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.build_type}} (Debug, windows-2022) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.build_type}} (RelWithDebInfo, windows-2022) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.compiler}} / ${{matrix.build_type}} (Debug, clang, macos-13) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.compiler}} / ${{matrix.build_type}} (Debug, clang, ubuntu-22.04) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.compiler}} / ${{matrix.build_type}} (Debug, gcc, ubuntu-24.04) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.compiler}} / ${{matrix.build_type}} (RelWithDebInfo, clang, macos-13) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.compiler}} / ${{matrix.build_type}} (RelWithDebInfo, clang, ubuntu-22.04) (push) Has been cancelled Details
cesium-native / ${{matrix.platform}} / ${{matrix.compiler}} / ${{matrix.build_type}} (RelWithDebInfo, gcc, ubuntu-24.04) (push) Has been cancelled Details
cesium-native / Emscripten v${{matrix.version}} ${{matrix.memory}}bit memory (32, 3.1.39) (push) Has been cancelled Details
cesium-native / Emscripten v${{matrix.version}} ${{matrix.memory}}bit memory (32, 4.0.13) (push) Has been cancelled Details
cesium-native / Emscripten v${{matrix.version}} ${{matrix.memory}}bit memory (64, 4.0.13) (push) Has been cancelled Details
2025-11-21 14:56:00 -05:00
Tim Moore 3e68c7a1c2
Merge pull request #1272 from rbois-bentley/fix_modp_b64_search
Fix modp_b64 search fail when path to ezvcpkg contains a directory named debug
2025-11-18 19:00:04 +01:00
Kevin Ring 577ec52e8c Bump to v0.54.0. 2025-11-17 11:30:10 +11:00
Richard Bois 2bdeadac3d When searching for modp_b64 libraries, ignore all presence of /debug in the search paths except those ending with /debug. 2025-11-14 14:45:58 -05:00
Kevin Ring e876c133c8
Merge pull request #1267 from brendan-duncan/experiment_wasm
Add support for building cesium-native with Unity Web
2025-11-10 14:56:17 +11:00
Kevin Ring e9a9415539 Better implementation of hashing on 32/64 bit platforms.
Because function overloading didn't work the way I had hoped.
2025-11-10 14:02:26 +11:00
Kevin Ring d92188a276 Implement 32-bit hash combine function from Boost. 2025-11-10 13:40:33 +11:00
Kevin Ring c5ea386972 Add option to disable libjpeg-turbo.
Instead of always disabling it for Emscripten, when this is really only
need when building for Unity.
2025-11-10 13:16:50 +11:00
Kevin Ring 8b86d7f3d7 Use any version >= 24. 2025-11-07 23:11:03 +11:00
Kevin Ring 3f372f75a4 Use Node 24 for WASM64 tests. 2025-11-07 23:09:57 +11:00
Kevin Ring 77715ec5e5 Fix 64-bit Emscripten build. 2025-11-07 21:04:56 +11:00
Kevin Ring 198c22c795 Fix typo. 2025-11-07 17:00:31 +11:00
Kevin Ring 110382a8db Add WASM64 build. 2025-11-07 16:50:38 +11:00
Kevin Ring d9d31300d7 Clean up and centralize compiler flags. 2025-11-07 16:41:47 +11:00
Kevin Ring 65b6c866a0 clang-tidy 2025-11-06 22:59:14 +11:00
Kevin Ring c96485f98c Yet another attempt at the data build. 2025-11-06 22:53:27 +11:00
Kevin Ring 22e9dbcd7c Remove unnecessary package.json. 2025-11-06 17:53:36 +11:00
Kevin Ring f42203eb71 Improve web server for testing WebAssembly builds. 2025-11-06 17:51:21 +11:00
Kevin Ring ccba7b2510 More coding convention tweaks. 2025-11-06 17:50:48 +11:00
Kevin Ring 00c35a1ffc Remove tidyhtml specific compiler option. 2025-11-06 17:37:32 +11:00
Kevin Ring 221611fd21 Fix data build that I thought was working... 2025-11-06 17:24:39 +11:00
Kevin Ring 58e8bafe71 Remove workaround for tidyhtml.
cesium-native doesn't depend on tidy-html, so a workaround for it
doesn't belong here.
2025-11-06 16:06:19 +11:00
Kevin Ring eecc1e9411 Fix (and simplify) test data embedding. 2025-11-06 15:36:39 +11:00
Kevin Ring 5f06bc153e Minor tweaks for coding conventions. 2025-11-06 15:36:23 +11:00
Kevin Ring b23852cddd Merge remote-tracking branch 'origin/main' into experiment_wasm 2025-11-06 11:10:05 +11:00
Kevin Ring d1bffc5d37 Switch back to main vcpkg repo. 2025-11-06 10:28:31 +11:00
Kevin Ring 1e9f39df84 Add no-dso option on Emscripten 3.1.39. 2025-11-05 22:38:24 +11:00
Kevin Ring de6f08b7bc Try removing openssl overlay port again. 2025-11-05 16:22:06 +11:00
Kevin Ring b33640a9ff Use vcpkg from my PR.
https://github.com/microsoft/vcpkg/pull/48137
2025-11-05 15:52:20 +11:00
Kevin Ring 0aaaee207e Fix hash and feature name. 2025-11-04 20:53:08 +11:00
Kevin Ring 25cc1e89ca Only install [core] features of ktx. 2025-11-04 20:07:25 +11:00
Kevin Ring 16be63a245 Use KTX-Software branch from my PR.
https://github.com/KhronosGroup/KTX-Software/pull/1075
2025-11-04 19:22:58 +11:00
Ashley Rogers 097ca8c26a Tell clang-tidy to not worry about it 2025-10-30 14:34:57 -04:00
Ashley Rogers 54c22fddb5 Add include to fix glm issue 2025-10-30 13:47:19 -04:00
Ashley Rogers 7734cff91c More recent vcpkg commit for cmake fix 2025-10-30 10:24:28 -04:00
Ashley Rogers 90a24654f7 Update vcpkg commit 2025-10-29 17:45:56 -04:00
Kevin Ring 8d9ee6fee6 Suppress incorrect clang-tidy warning.
As of glm v1.0.2, and at least on Windows, an include of
`<glm/gtc/quaternion.hpp>` is required in order for
`glm::dmat4x4(rotationQuat)` to compile successfully. Otherwise, the
compiler complains about missing `mat4_cast`.

However, clang-tidy does not recognize that this header is required, and
throws a `misc-include-cleaner` warning. Possibly because it's not
required under clang.
2025-10-29 17:00:45 +11:00
Kevin Ring 52e5736b4a Try again to remove blend2d and upgrade vcpkg.
Now that yesterday's vcpkg breakage has been reverted.
2025-10-29 14:49:15 +11:00
Ashley Rogers d3b0ccbeaa Regenerate gltf 2025-10-28 18:12:00 -04:00
Ashley Rogers 30cc96901b Remove spz overlay port, draft-splat-spz branch of gltf 2025-10-28 17:44:40 -04:00
Ashley Rogers 8c6f35b008 Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-10-28 17:43:38 -04:00
Kevin Ring 12ee3f00b5 Revert change that was only necessary after glm upgrade. 2025-10-28 20:55:47 +11:00
Kevin Ring 3080d41edb Re-add blend2d overlay port.
This is an exact copy of:
0cb190f991/ports/blend2d
2025-10-28 19:42:04 +11:00
Kevin Ring b800becaae Revert to 2025.09.17 version of vcpkg.
The pre-release version I tried to use to get the blend2d changes has a
problem that causes builds to fail when using the vcpkg executable
included in the GitHub Actions images. See here:
https://github.com/microsoft/vcpkg/pull/30396#issuecomment-3452587376

So I'll restore the blend2d changes as an overlay port in a separate
commit.
2025-10-28 19:38:38 +11:00
Kevin Ring f66d9dacf6 More thorough removal of cpp-httplib from wasm builds. 2025-10-28 19:33:48 +11:00
Kevin Ring 077e9f3765 Disable cpp-httplib on Emscripten, rather than downgrading it.
The older version has known CVEs, and anyway it's only used to host a
web server for an OAuth2 flow, which isn't going to work on the web
anyway.
2025-10-28 18:43:15 +11:00
Kevin Ring 60faebd4d2 Update vcpkg and remove blend2d overlay port.
This vcpkg version is not tagged, but was chosen because it includes
https://github.com/microsoft/vcpkg/pull/47969.
2025-10-28 18:07:33 +11:00
Kevin Ring b948b9cbfd Update spz overlay with latest from PR. 2025-10-28 17:57:49 +11:00
Kevin Ring 8df7a1f98d Update spz to v2.1.0.
This overlay port comes directly from this PR into vcpkg:
https://github.com/microsoft/vcpkg/pull/47983
2025-10-28 14:45:10 +11:00
Kevin Ring c913278446 Re-add blend2d overlay port.
This is needed until https://github.com/microsoft/vcpkg/pull/47969 is
merged and we've updated to a vcpkg version that includes it.

Without it, builds with blend2d's `jit` feature disabled (Emscripten)
fail because the package erroneously attempts to
`find_dependency(asmjit)` even when there's no asmjit to find (because
it's disabled).
2025-10-27 18:58:50 +11:00
Kevin Ring 0e53ac995d Remove blend2d overlay.
Once again it doesn't seem to be necessary locally. Let's see what CI
says.
2025-10-27 17:14:08 +11:00
Kevin Ring a93b082380 Remove debug step. 2025-10-27 16:47:21 +11:00
Kevin Ring eaf77c07f1 Don't remove directory.
Even though I'm unclear why it's a problem.
2025-10-27 16:43:04 +11:00
Kevin Ring 84a9574e7b Don't let actions/checkout delete everything. 2025-10-27 16:39:38 +11:00
Kevin Ring 5e554d3638 More github actions flailing. 2025-10-27 16:34:16 +11:00
Kevin Ring e390112e21 Debug failed sparse checkout. 2025-10-27 16:32:07 +11:00
Kevin Ring 97883d1451 Add overlay port for ada-url in Emscripten 3.1.39 build. 2025-10-27 16:24:14 +11:00
Kevin Ring a72529e9cb Add Emscripten 4.0.13 build. 2025-10-27 15:44:36 +11:00
Kevin Ring 000d27cbb1 Remove ada-url overlay port.
It doesn't seem to be doing anything useful, and the build is fine
locally without it.
2025-10-27 14:48:48 +11:00
Kevin Ring d0427df530 Consistently use non-header-only spdlog. 2025-10-27 11:17:24 +11:00
Kevin Ring f6d83fb859 Fix dodgy store of a reference to a temporary in a global variable.
This appears to have been the cause of the crash in the WebAssembly
tests.
2025-10-24 19:48:18 +11:00
Kevin Ring 34cc5236a4 A little cmake and vcpkg cleanup. 2025-10-23 20:49:26 +11:00
Kevin Ring 33d5640416 Update spz overlay port.
It now matches the official vcpkg one as of `2025.09.17`, plus it adds
the `loadSpz.patch` patch to add an overload of loadSpz taking a raw
pointer.
2025-10-23 20:47:46 +11:00
Kevin Ring 9c41f33c83 Merge remote-tracking branch 'origin/trouble-with-triplets' into gaussian-splats 2025-10-23 17:43:39 +11:00
Brendan Duncan 8d3d70a930 set EXIT_RUNTIME so test runner exits 2025-10-22 21:47:23 -06:00
Kevin Ring 62ef5734da Don't let OpenSSL try to dlopen in wasm builds. 2025-10-23 10:17:28 +11:00
Kevin Ring e4c0150a4d Back to ezvcpkg for now. 2025-10-22 21:50:49 +11:00
Kevin Ring 614458ed9b Don't use ezvcpg for wasm build, attempt to run tests. 2025-10-22 20:19:33 +11:00
Kevin Ring b40e3ecbc0 Use wasmXX-emscripten-cesium triplets.
Rather than overlaying the built-in wasm32-emscripten.
2025-10-22 19:54:10 +11:00
Kevin Ring f54db5f321 clang-tidy 2025-10-21 20:38:55 +11:00
Kevin Ring fb0123673e Make openssl configure script exectuable.
To fix all the posixy platforms.
2025-10-21 19:55:10 +11:00
Kevin Ring f245947101 clang-format 2025-10-21 18:33:21 +11:00
Kevin Ring 39c1ac8c62 Use the overlay triplets. 2025-10-21 18:29:13 +11:00
Kevin Ring 167a728aa0 Merge remote-tracking branch 'origin/main' into experiment_wasm 2025-10-21 16:41:23 +11:00
Brendan Duncan 5d44fd4670 fix wasm build errors 2025-10-20 22:40:24 -06:00
Kevin Ring d66de9af3b Better job name. 2025-10-20 21:54:26 +11:00
Kevin Ring 9787c25d84 Attemp to add wasm build to CI. 2025-10-20 21:46:45 +11:00
Brendan Duncan c754a5fdec clang-format 2025-10-19 21:13:22 -06:00
Brendan Duncan cf18fd06b4 Merge branch 'main' into experiment_wasm 2025-10-19 13:41:36 -06:00
Kevin Ring fc68020535 Remove explicit zlib dependency. 2025-10-17 16:17:01 +11:00
Ashley Rogers 1cdb48a8da Fix include style 2025-10-14 16:45:20 -04:00
Ashley Rogers 5a28968283 Will this fix it? 2025-10-14 16:40:08 -04:00
Ashley Rogers 557f2b2898 Fix clang build 2025-10-14 16:28:45 -04:00
Ashley Rogers d5ca2caf9f Fix tests 2025-10-14 15:35:46 -04:00
Ashley Rogers eef757a96f clang-tidy fixes 2025-10-14 15:04:08 -04:00
Ashley Rogers 956a3820a7 Update CHANGES.md 2025-10-14 14:50:14 -04:00
Ashley Rogers fd85c8ed6a Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-10-14 14:49:45 -04:00
Ashley Rogers fd19709464 Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-10-10 15:02:36 -04:00
Brendan Duncan 3b1b0f9e73 don't check in package-lock.json 2025-10-05 20:01:17 -06:00
Brendan Duncan de5ed6e7ba code cleanup 2025-10-05 17:13:42 -06:00
Brendan Duncan 733bc2c05d clean up to match main 2025-10-05 17:11:41 -06:00
Brendan Duncan 99f1404fe7 clean-up merge changes 2025-10-05 17:07:32 -06:00
Brendan Duncan abf28c5ecc Fix merge errors 2025-10-05 16:56:04 -06:00
Brendan Duncan 1c13589457 Merge branch 'main' into experiment_wasm
# Conflicts:
#	CHANGES.md
#	Cesium3DTilesSelection/src/RasterOverlayCollection.cpp
#	CesiumRasterOverlays/include/CesiumRasterOverlays/RasterOverlayTileProvider.h
#	CesiumRasterOverlays/src/RasterOverlayTileProvider.cpp
2025-10-05 15:16:11 -06:00
Ashley Rogers 1ca38cd6e7 Change to how spherical harmonics are copied to the buffer. 2025-09-26 15:36:29 -04:00
Ashley Rogers 99355d423e Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-09-24 11:02:41 -04:00
Brendan Duncan 50b1530722 don't need specialized wasm compiler flags anymore 2025-09-22 08:05:31 -06:00
Brendan Duncan 56f2dc8e8b fix wasm build after merger 2025-09-20 19:49:52 -06:00
Brendan Duncan 1aa2788d33 Merge branch 'main' into experiment_wasm
# Conflicts:
#	CMakeLists.txt
2025-09-20 11:33:19 -06:00
Ashley Rogers 6b45940fd5 Write colors directly as floats 2025-09-12 09:47:03 -04:00
Brendan Duncan 3f416be76d Add EM_CONFIG to VCPKG_ENV_PASSTHROUGH_UNTRACKED 2025-09-03 22:32:37 -06:00
Ashley Rogers 9da2c9c8d9 Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-09-03 10:37:44 -04:00
Brendan Duncan 90d1c96818 disable blend2d wasm install for now 2025-08-31 18:24:32 -06:00
Ashley Rogers dc8ce97b1d Conform accessor types to required values 2025-08-29 16:46:35 -04:00
Ashley Rogers 641e9f0b9e SPZ loading fixes 2025-08-29 10:57:59 -04:00
Ashley Rogers 8a72d9357a Fix attribute names in SPZ loader 2025-08-28 18:21:14 -04:00
Ashley Rogers cb2c5a1458 Missing a return... 2025-08-28 16:00:46 -04:00
Ashley Rogers 2105e5b235 Quietly map older versions of the SPZ extension 2025-08-28 15:56:33 -04:00
Ashley Rogers 0193409bc0 SPZ test, fixes 2025-08-28 14:11:19 -04:00
Brendan Duncan b7330ea1b5 fix typo from wasm32 builds 2025-08-27 12:00:48 -06:00
Brendan Duncan a37c73e776 Add option to build wasm64 2025-08-27 09:39:46 -06:00
Brendan Duncan 6e43196dd0 install blend2d for wasm builds 2025-08-26 13:38:13 -06:00
Ashley Rogers 0d8ef62517 Update to match spz2 renaming 2025-08-26 13:20:54 -04:00
Ashley Rogers 01ef36e6ed Rename SPZ extension 2025-08-26 11:45:04 -04:00
Ashley Rogers 99ddaec2e0 Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-08-26 11:35:05 -04:00
Brendan Duncan 88c3716272 clean up 32-bit warmings 2025-08-25 15:38:10 -06:00
Brendan Duncan 1ff50143bc 32-bit warning fixes 2025-08-25 08:51:23 -06:00
Brendan Duncan 1e1663bba7 Add HAS_FUTIME to emscripten defines for tidyhtml 2025-08-23 21:59:24 -06:00
Brendan Duncan 8329b52169 Start working on size_t warnings on 32-bit 2025-08-23 10:28:49 -06:00
Brendan Duncan a5e925c597 wasm build fix 2025-08-22 21:21:25 -06:00
Brendan Duncan f465fd9435 wasm build updates 2025-08-22 21:08:23 -06:00
Ashley Rogers d2f5d780ce Zlib dependency 2025-08-22 11:22:04 -04:00
Ashley Rogers 6efafe6bc9 Just use non-ng zlib, seems to have fewer issues 2025-08-20 13:44:35 -04:00
Ashley Rogers 9258a5b79a Use zlib-ng for spz 2025-08-20 11:41:00 -04:00
Ashley Rogers 32dff5e051 Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-08-20 11:05:28 -04:00
Ashley Rogers b6896cf807 Use overlay port for spz 2025-08-19 15:20:16 -04:00
Ashley Rogers d687c267db Implement spz decoding 2025-08-19 14:43:44 -04:00
Brendan Duncan ca2f95b1ce comment out use of std::formatter 2025-08-18 23:42:02 -06:00
Ashley Rogers cf5cfe000a Add SPZ extension, library 2025-08-15 14:11:42 -04:00
Ashley Rogers fe8d2f0cea Merge branch 'main' of github.com:CesiumGS/cesium-native into gaussian-splats 2025-08-15 14:00:17 -04:00
Brendan Duncan 852ba2ddaf fix non-wasm build 2025-08-12 17:16:39 -06:00
Brendan Duncan 0ab8381d61 Fix up wasm32 cmake build 2025-08-07 22:22:44 -06:00
Brendan Duncan c71c3263ca change MAXIMUM_MEMORY to wasm32 limit 2025-08-07 22:21:51 -06:00
Brendan Duncan 22f50cefb5 re-add blend2d to wasm build 2025-08-06 21:34:08 -06:00
Brendan Duncan 70185b6304 changes to get compilation going 2025-08-06 09:28:52 -06:00
Brendan Duncan 7703c0c7fc disable blend2d and CesiumVectorData from wasm builds 2025-08-05 22:41:29 -06:00
Brendan Duncan 89263366e9 add missing cmake updates 2025-08-05 22:23:16 -06:00
Brendan Duncan 2c830aa233 WIP experiment with wasm32 2025-08-04 11:37:43 -06:00
Ashley Rogers d6e4d5d847 KHR_gaussian_splatting extension 2025-07-11 10:22:17 -04:00
70 changed files with 2207 additions and 127 deletions

View File

@ -217,3 +217,70 @@ jobs:
run: | run: |
cd build cd build
ctest -V ctest -V
EmscriptenBuild:
strategy:
fail-fast: false
matrix:
version: [ "3.1.39", "4.0.13" ]
memory: [ "32", "64" ]
exclude:
- version: "3.1.39"
memory: "64"
name: Emscripten v${{matrix.version}} ${{matrix.memory}}bit memory
env:
CACHE_KEY: "emscripten-${{matrix.version}}-${{matrix.memory}}"
runs-on: windows-2022
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Use NodeJS 24 for WebAssembly 64-bit memory support
if: ${{ matrix.memory == '64' }}
uses: actions/setup-node@v6
with:
node-version: '>=24'
- name: Checkout vcpkg 2025.02.14 packages for use with Emscripten 3.1.39
if: ${{ matrix.version == '3.1.39' }}
uses: actions/checkout@v4
with:
repository: microsoft/vcpkg
clean: false
ref: 2025.02.14
path: extern/vcpkg/temp
sparse-checkout-cone-mode: false
sparse-checkout: |
ports/ada-url
- name: Move overlay ports to the correct location
if: ${{ matrix.version == '3.1.39' }}
run: |
mv extern/vcpkg/temp/ports/* extern/vcpkg/ports/
- name: Add OpenSSL "no-dso" option on older Emscripten versions
if: ${{ matrix.version == '3.1.39' }}
run: |
echo "
if(PORT MATCHES "openssl")
set(VCPKG_CONFIGURE_MAKE_OPTIONS "no-dso")
endif()
" >> extern/vcpkg/triplets/wasm32-emscripten-cesium.cmake
- name: Install latest CMake 3 and Ninja
uses: lukka/get-cmake@latest
with:
cmakeVersion: "3.31.6"
- name: Install nasm
uses: ilammy/setup-nasm@v1
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{matrix.version}}
- name: Verify
run: emcc -v
- name: Compile Debug Configuration
run: |
$env:VCPKG_ROOT="$env:VCPKG_INSTALLATION_ROOT"
$MEMORYPROPERTY="${{matrix.memory}}" -eq "64" ? "-DCESIUM_WASM64=ON" : ""
emcmake cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug $MEMORYPROPERTY
cmake --build build --config Debug --parallel
- name: Test Debug Configuration
run: |
node build/CesiumNativeTests/cesium-native-tests.js

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
build build
build-*
doxygen doxygen
Testing Testing
node_modules node_modules
@ -8,7 +9,5 @@ CMakeSettings.json
.cache .cache
*.DS_Store *.DS_Store
test.db test.db
build-wsl
.idea .idea
build-debug
clang-tidy.log clang-tidy.log

View File

@ -1,5 +1,11 @@
# Change Log # Change Log
### v0.54.0 - 2025-11-17
##### Additions :tada:
- Cesium Native can now be built with Emscripten.
### v0.53.0 - 2025-11-03 ### v0.53.0 - 2025-11-03
##### Breaking Changes :mega: ##### Breaking Changes :mega:
@ -13,6 +19,11 @@
- Added `Uri::ensureTrailingSlash`, which is helpful when the `Uri` represents a base URL. - Added `Uri::ensureTrailingSlash`, which is helpful when the `Uri` represents a base URL.
- Added `GltfModifier`, which can be used to modify tile glTFs as they load, as well as apply new modifications to them later. - Added `GltfModifier`, which can be used to modify tile glTFs as they load, as well as apply new modifications to them later.
##### Additions :tada:
- Added support for the `KHR_gaussian_splatting` extension.
- SPZ payloads for `KHR_guassian_splatting` using the `KHR_gaussian_splatting_compression_spz_2` extension will now be decoded.
##### Fixes :wrench: ##### Fixes :wrench:
- Fixed a bug in `GoogleMapTilesRasterOverlay` that tried to parse credits from an erroneous viewport service response. - Fixed a bug in `GoogleMapTilesRasterOverlay` that tried to parse credits from an erroneous viewport service response.

View File

@ -4,6 +4,14 @@ if (NOT VCPKG_LIBRARY_LINKAGE)
set(VCPKG_LIBRARY_LINKAGE static) set(VCPKG_LIBRARY_LINKAGE static)
endif() endif()
get_filename_component(toolchainFile "${CMAKE_TOOLCHAIN_FILE}" NAME)
if(toolchainFile STREQUAL "Emscripten.cmake")
set(CESIUM_TARGET_WASM ON)
# Include the toolchain directly as ezvcpkg will overwrite the
# toolchain before it's loaded
include(${CMAKE_TOOLCHAIN_FILE})
endif()
# By default, Use ezvcpkg to install dependencies. But don't use # By default, Use ezvcpkg to install dependencies. But don't use
# ezvcpkg if it appears that this configuration is using vcpkg # ezvcpkg if it appears that this configuration is using vcpkg
# manifest mode already, either by building cesium-native directly, # manifest mode already, either by building cesium-native directly,
@ -24,6 +32,13 @@ endif()
option(CESIUM_USE_EZVCPKG "use ezvcpkg helper" ${CESIUM_USE_EZVCPKG_DEFAULT}) option(CESIUM_USE_EZVCPKG "use ezvcpkg helper" ${CESIUM_USE_EZVCPKG_DEFAULT})
option(CESIUM_DISABLE_CURL "Disable cesium-native's use of libcurl" OFF) option(CESIUM_DISABLE_CURL "Disable cesium-native's use of libcurl" OFF)
option(CESIUM_DISABLE_LIBJPEG_TURBO "Disable cesium-native's use of libjpeg-turbo. JPEG images will be decoded with STB instead." OFF)
option(CESIUM_WASM64 "Enable 64-bit WebAssembly target" OFF)
if (CESIUM_TARGET_WASM)
# Make sure curl is disabled on wasm builds, as it is not supported.
set(CESIUM_DISABLE_CURL ON)
endif()
if(CESIUM_USE_EZVCPKG) if(CESIUM_USE_EZVCPKG)
# Keep vcpkg from running in manifset mode. It will try to because # Keep vcpkg from running in manifset mode. It will try to because
@ -50,6 +65,15 @@ if (NOT VCPKG_TRIPLET)
elseif(DETECTED_VCPKG_TRIPLET STREQUAL "x64-windows") elseif(DETECTED_VCPKG_TRIPLET STREQUAL "x64-windows")
# cesium-native requires static linking on Windows # cesium-native requires static linking on Windows
set(VCPKG_TRIPLET "x64-windows-static-md") set(VCPKG_TRIPLET "x64-windows-static-md")
elseif(DETECTED_VCPKG_TRIPLET STREQUAL "wasm32-emscripten")
# Use our custom triplet for wasm builds. Most importantly, this
# enables multithreading support. Also switch to 64-bit wasm if
# requested.
if (CESIUM_WASM64)
set(VCPKG_TRIPLET "wasm64-emscripten-cesium")
else()
set(VCPKG_TRIPLET "wasm32-emscripten-cesium")
endif()
else() else()
set(VCPKG_TRIPLET "${DETECTED_VCPKG_TRIPLET}") set(VCPKG_TRIPLET "${DETECTED_VCPKG_TRIPLET}")
endif() endif()
@ -87,6 +111,10 @@ if (NOT VCPKG_OVERLAY_TRIPLETS)
endif() endif()
endif() endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/triplets")
list(APPEND VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/triplets")
endif()
message(STATUS "VCPKG_OVERLAY_TRIPLETS ${VCPKG_OVERLAY_TRIPLETS}") message(STATUS "VCPKG_OVERLAY_TRIPLETS ${VCPKG_OVERLAY_TRIPLETS}")
# These packages are used in the public headers of Cesium libraries, so we need to distribute the headers and binaries # These packages are used in the public headers of Cesium libraries, so we need to distribute the headers and binaries
@ -98,13 +126,13 @@ set(PACKAGES_PUBLIC asyncplusplus expected-lite fmt glm rapidjson spdlog stb ada
# to distribute the binaries for linking, but not the headers, as downstream consumers don't need them # to distribute the binaries for linking, but not the headers, as downstream consumers don't need them
# OpenSSL and abseil are both dependencies of s2geometry # OpenSSL and abseil are both dependencies of s2geometry
set(PACKAGES_PRIVATE set(PACKAGES_PRIVATE
abseil draco ktx modp-base64 meshoptimizer openssl s2geometry abseil draco ktx[core] modp-base64 meshoptimizer openssl s2geometry
libjpeg-turbo sqlite3 tinyxml2 libwebp zlib-ng picosha2 sqlite3 tinyxml2 libwebp zlib-ng picosha2
earcut-hpp cpp-httplib[core] libmorton zstd earcut-hpp libmorton zstd spz zlib
) )
# asmjit needed by blend2d on non-iOS platforms (iOS doesn't support JIT) # asmjit needed by blend2d on non-iOS platforms (iOS and Wasm don't support JIT)
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS") if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
list(APPEND PACKAGES_PRIVATE blend2d asmjit) list(APPEND PACKAGES_PRIVATE blend2d asmjit)
else() else()
# Use [core] feature to disable default jit feature. # Use [core] feature to disable default jit feature.
@ -115,16 +143,37 @@ if(NOT CESIUM_DISABLE_CURL)
list(APPEND PACKAGES_PRIVATE curl) list(APPEND PACKAGES_PRIVATE curl)
endif() endif()
if(NOT CESIUM_DISABLE_LIBJPEG_TURBO)
list(APPEND PACKAGES_PRIVATE libjpeg-turbo)
endif()
# We use cpp-httplib to host a local web server for OAuth2 authorization. That's not
# going to work at all on the web, and the latest versions of cpp-httplib only support
# 64-bit platforms anyway, so skip it entirely for WebAssembly builds.
if(NOT CESIUM_TARGET_WASM)
list(APPEND PACKAGES_PRIVATE "cpp-httplib[core]")
endif()
# Packages only used for testing # Packages only used for testing
set(PACKAGES_TEST doctest) set(PACKAGES_TEST doctest)
if(CESIUM_TARGET_WASM)
# vcpkg will attempt to second-guess our CMAKE_C_COMPILER setting, choosing to go with the value of CC instead.
# While normally this is the correct value to go with, for wasm we need to be using emcc and em++.
# So we set CC and CXX to emcc and em++ here so vcpkg will pick them up properly.
# Does this make sense? No. Does it work? Somehow. ¯\_()_/¯
set(ENV{CC} ${CMAKE_C_COMPILER})
set(ENV{CXX} ${CMAKE_CXX_COMPILER})
endif()
if(CESIUM_USE_EZVCPKG) if(CESIUM_USE_EZVCPKG)
set(PACKAGES_ALL ${PACKAGES_PUBLIC}) set(PACKAGES_ALL ${PACKAGES_PUBLIC})
list(APPEND PACKAGES_ALL ${PACKAGES_PRIVATE}) list(APPEND PACKAGES_ALL ${PACKAGES_PRIVATE})
list(APPEND PACKAGES_ALL ${PACKAGES_TEST}) list(APPEND PACKAGES_ALL ${PACKAGES_TEST})
ezvcpkg_fetch( ezvcpkg_fetch(
COMMIT 2025.09.17 COMMIT afc0a2e01ae104a2474216a2df0e8d78516fd5af
REPO microsoft/vcpkg
PACKAGES ${PACKAGES_ALL} PACKAGES ${PACKAGES_ALL}
# Clean the build trees after building, so that we don't use a ton a disk space on the CI cache # Clean the build trees after building, so that we don't use a ton a disk space on the CI cache
CLEAN_BUILDTREES CLEAN_BUILDTREES
@ -145,10 +194,20 @@ endif()
include("cmake/defaults.cmake") include("cmake/defaults.cmake")
project(cesium-native project(cesium-native
VERSION 0.53.0 VERSION 0.54.0
LANGUAGES CXX C LANGUAGES CXX C
) )
if(CESIUM_TARGET_WASM)
if(CESIUM_WASM64)
set(CMAKE_SIZEOF_VOID_P 8)
else()
set(CMAKE_SIZEOF_VOID_P 4)
endif()
# Tells emscripten to output an HTML harness for the generated WASM
set(CMAKE_EXECUTABLE_SUFFIX ".html")
endif()
include(GNUInstallDirs) include(GNUInstallDirs)
include(CMakeDependentOption) include(CMakeDependentOption)
@ -318,21 +377,20 @@ find_package(doctest CONFIG REQUIRED)
find_package(draco CONFIG REQUIRED) find_package(draco CONFIG REQUIRED)
find_package(expected-lite CONFIG REQUIRED) find_package(expected-lite CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED) find_package(glm CONFIG REQUIRED)
find_package(httplib CONFIG REQUIRED)
find_package(Ktx CONFIG REQUIRED) find_package(Ktx CONFIG REQUIRED)
find_package(libjpeg-turbo CONFIG REQUIRED)
find_package(libmorton CONFIG REQUIRED) find_package(libmorton CONFIG REQUIRED)
find_package(meshoptimizer CONFIG REQUIRED) find_package(meshoptimizer CONFIG REQUIRED)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(s2 CONFIG REQUIRED) find_package(s2 CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED) find_package(spdlog CONFIG REQUIRED)
find_package(spz CONFIG REQUIRED)
find_package(tinyxml2 CONFIG REQUIRED) find_package(tinyxml2 CONFIG REQUIRED)
find_package(unofficial-sqlite3 CONFIG REQUIRED) find_package(unofficial-sqlite3 CONFIG REQUIRED)
find_package(WebP CONFIG REQUIRED) find_package(WebP CONFIG REQUIRED)
find_package(zlib-ng CONFIG REQUIRED) find_package(zlib-ng CONFIG REQUIRED)
# asmjit should not be included with iOS builds as iOS doesn't support JIT compilation. # asmjit should not be included with iOS or Wasm builds as they don't support JIT compilation.
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS") if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
find_package(asmjit CONFIG REQUIRED) find_package(asmjit CONFIG REQUIRED)
endif() endif()
@ -340,6 +398,14 @@ if(NOT CESIUM_DISABLE_CURL)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
endif() endif()
if(NOT CESIUM_DISABLE_LIBJPEG_TURBO)
find_package(libjpeg-turbo CONFIG REQUIRED)
endif()
if(NOT CESIUM_TARGET_WASM)
find_package(httplib CONFIG REQUIRED)
endif()
# Private Library (s2geometry) # Private Library (s2geometry)
add_subdirectory(extern EXCLUDE_FROM_ALL) add_subdirectory(extern EXCLUDE_FROM_ALL)

View File

@ -234,7 +234,7 @@ public:
bool isContentAvailable( bool isContentAvailable(
const CesiumGeometry::QuadtreeTileID& subtreeId, const CesiumGeometry::QuadtreeTileID& subtreeId,
const CesiumGeometry::QuadtreeTileID& tileId, const CesiumGeometry::QuadtreeTileID& tileId,
uint64_t contentId) const noexcept; size_t contentId) const noexcept;
/** /**
* @brief Determines if content for a given tile in the octree is available. * @brief Determines if content for a given tile in the octree is available.
@ -247,7 +247,7 @@ public:
bool isContentAvailable( bool isContentAvailable(
const CesiumGeometry::OctreeTileID& subtreeId, const CesiumGeometry::OctreeTileID& subtreeId,
const CesiumGeometry::OctreeTileID& tileId, const CesiumGeometry::OctreeTileID& tileId,
uint64_t contentId) const noexcept; size_t contentId) const noexcept;
/** /**
* @brief Determines if content for a given tile in the subtree is available. * @brief Determines if content for a given tile in the subtree is available.
@ -262,7 +262,7 @@ public:
bool isContentAvailable( bool isContentAvailable(
uint32_t relativeTileLevel, uint32_t relativeTileLevel,
uint64_t relativeTileMortonId, uint64_t relativeTileMortonId,
uint64_t contentId) const noexcept; size_t contentId) const noexcept;
/** /**
* @brief Sets the availability state of the content for a given tile in the * @brief Sets the availability state of the content for a given tile in the
@ -276,7 +276,7 @@ public:
void setContentAvailable( void setContentAvailable(
const CesiumGeometry::QuadtreeTileID& subtreeId, const CesiumGeometry::QuadtreeTileID& subtreeId,
const CesiumGeometry::QuadtreeTileID& tileId, const CesiumGeometry::QuadtreeTileID& tileId,
uint64_t contentId, size_t contentId,
bool isAvailable) noexcept; bool isAvailable) noexcept;
/** /**
@ -291,7 +291,7 @@ public:
void setContentAvailable( void setContentAvailable(
const CesiumGeometry::OctreeTileID& subtreeId, const CesiumGeometry::OctreeTileID& subtreeId,
const CesiumGeometry::OctreeTileID& tileId, const CesiumGeometry::OctreeTileID& tileId,
uint64_t contentId, size_t contentId,
bool isAvailable) noexcept; bool isAvailable) noexcept;
/** /**
@ -309,7 +309,7 @@ public:
void setContentAvailable( void setContentAvailable(
uint32_t relativeTileLevel, uint32_t relativeTileLevel,
uint64_t relativeTileMortonId, uint64_t relativeTileMortonId,
uint64_t contentId, size_t contentId,
bool isAvailable) noexcept; bool isAvailable) noexcept;
/** /**

View File

@ -1014,7 +1014,10 @@ void copyStringsToBuffers(
for (const auto& str : arrayMember.GetArray()) { for (const auto& str : arrayMember.GetArray()) {
OffsetType byteLength = static_cast<OffsetType>( OffsetType byteLength = static_cast<OffsetType>(
str.GetStringLength() * sizeof(rapidjson::Value::Ch)); str.GetStringLength() * sizeof(rapidjson::Value::Ch));
std::memcpy(valueBuffer.data() + offset, str.GetString(), byteLength); std::memcpy(
valueBuffer.data() + offset,
str.GetString(),
size_t(byteLength));
std::memcpy( std::memcpy(
offsetBuffer.data() + offsetIndex * sizeof(OffsetType), offsetBuffer.data() + offsetIndex * sizeof(OffsetType),
&offset, &offset,
@ -1075,8 +1078,7 @@ void updateStringArrayProperty(
++it; ++it;
} }
const uint64_t totalByteLength = const size_t totalByteLength = totalCharCount * sizeof(rapidjson::Value::Ch);
totalCharCount * sizeof(rapidjson::Value::Ch);
std::vector<std::byte> valueBuffer; std::vector<std::byte> valueBuffer;
std::vector<std::byte> stringOffsetBuffer; std::vector<std::byte> stringOffsetBuffer;
PropertyComponentType stringOffsetType = PropertyComponentType::None; PropertyComponentType stringOffsetType = PropertyComponentType::None;

View File

@ -823,7 +823,7 @@ void decodeDracoMetadata(
const std::unique_ptr<draco::PointCloud>& pPointCloud, const std::unique_ptr<draco::PointCloud>& pPointCloud,
rapidjson::Document& batchTableJson, rapidjson::Document& batchTableJson,
PntsContent& parsedContent) { PntsContent& parsedContent) {
const uint64_t pointsLength = parsedContent.pointsLength; const size_t pointsLength = parsedContent.pointsLength;
std::vector<std::byte>& data = parsedContent.dracoBatchTableBinary; std::vector<std::byte>& data = parsedContent.dracoBatchTableBinary;
const auto& dracoMetadataSemantics = parsedContent.dracoMetadataSemantics; const auto& dracoMetadataSemantics = parsedContent.dracoMetadataSemantics;

View File

@ -281,7 +281,7 @@ void SubtreeAvailability::setTileAvailable(
bool SubtreeAvailability::isContentAvailable( bool SubtreeAvailability::isContentAvailable(
const CesiumGeometry::QuadtreeTileID& subtreeId, const CesiumGeometry::QuadtreeTileID& subtreeId,
const CesiumGeometry::QuadtreeTileID& tileId, const CesiumGeometry::QuadtreeTileID& tileId,
uint64_t contentId) const noexcept { size_t contentId) const noexcept {
uint64_t relativeTileMortonIdx = uint64_t relativeTileMortonIdx =
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId); ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
return this->isContentAvailable( return this->isContentAvailable(
@ -293,7 +293,7 @@ bool SubtreeAvailability::isContentAvailable(
bool SubtreeAvailability::isContentAvailable( bool SubtreeAvailability::isContentAvailable(
const CesiumGeometry::OctreeTileID& subtreeId, const CesiumGeometry::OctreeTileID& subtreeId,
const CesiumGeometry::OctreeTileID& tileId, const CesiumGeometry::OctreeTileID& tileId,
uint64_t contentId) const noexcept { size_t contentId) const noexcept {
uint64_t relativeTileMortonIdx = uint64_t relativeTileMortonIdx =
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId); ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
return this->isContentAvailable( return this->isContentAvailable(
@ -305,7 +305,7 @@ bool SubtreeAvailability::isContentAvailable(
bool SubtreeAvailability::isContentAvailable( bool SubtreeAvailability::isContentAvailable(
uint32_t relativeTileLevel, uint32_t relativeTileLevel,
uint64_t relativeTileMortonId, uint64_t relativeTileMortonId,
uint64_t contentId) const noexcept { size_t contentId) const noexcept {
if (contentId >= this->_contentAvailability.size()) if (contentId >= this->_contentAvailability.size())
return false; return false;
return isAvailable( return isAvailable(
@ -317,7 +317,7 @@ bool SubtreeAvailability::isContentAvailable(
void SubtreeAvailability::setContentAvailable( void SubtreeAvailability::setContentAvailable(
const CesiumGeometry::QuadtreeTileID& subtreeId, const CesiumGeometry::QuadtreeTileID& subtreeId,
const CesiumGeometry::QuadtreeTileID& tileId, const CesiumGeometry::QuadtreeTileID& tileId,
uint64_t contentId, size_t contentId,
bool isAvailable) noexcept { bool isAvailable) noexcept {
uint64_t relativeTileMortonIdx = uint64_t relativeTileMortonIdx =
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId); ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
@ -331,7 +331,7 @@ void SubtreeAvailability::setContentAvailable(
void SubtreeAvailability::setContentAvailable( void SubtreeAvailability::setContentAvailable(
const CesiumGeometry::OctreeTileID& subtreeId, const CesiumGeometry::OctreeTileID& subtreeId,
const CesiumGeometry::OctreeTileID& tileId, const CesiumGeometry::OctreeTileID& tileId,
uint64_t contentId, size_t contentId,
bool isAvailable) noexcept { bool isAvailable) noexcept {
uint64_t relativeTileMortonIdx = uint64_t relativeTileMortonIdx =
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId); ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
@ -345,7 +345,7 @@ void SubtreeAvailability::setContentAvailable(
void SubtreeAvailability::setContentAvailable( void SubtreeAvailability::setContentAvailable(
uint32_t relativeTileLevel, uint32_t relativeTileLevel,
uint64_t relativeTileMortonId, uint64_t relativeTileMortonId,
uint64_t contentId, size_t contentId,
bool isAvailable) noexcept { bool isAvailable) noexcept {
if (contentId < this->_contentAvailability.size()) { if (contentId < this->_contentAvailability.size()) {
this->setAvailable( this->setAvailable(
@ -518,7 +518,7 @@ bool SubtreeAvailability::isAvailableUsingBufferView(
const SubtreeBufferViewAvailability* bufferViewAvailability = const SubtreeBufferViewAvailability* bufferViewAvailability =
std::get_if<SubtreeBufferViewAvailability>(&availabilityView); std::get_if<SubtreeBufferViewAvailability>(&availabilityView);
const uint64_t byteIndex = availabilityBitIndex / 8; const size_t byteIndex = size_t(availabilityBitIndex / 8);
if (byteIndex >= bufferViewAvailability->view.size()) { if (byteIndex >= bufferViewAvailability->view.size()) {
return false; return false;
} }
@ -541,7 +541,7 @@ void SubtreeAvailability::setAvailableUsingBufferView(
const SubtreeBufferViewAvailability* pBufferViewAvailability = const SubtreeBufferViewAvailability* pBufferViewAvailability =
std::get_if<SubtreeBufferViewAvailability>(&availabilityView); std::get_if<SubtreeBufferViewAvailability>(&availabilityView);
const uint64_t byteIndex = availabilityBitIndex / 8; const size_t byteIndex = size_t(availabilityBitIndex / 8);
if (byteIndex >= pBufferViewAvailability->view.size()) { if (byteIndex >= pBufferViewAvailability->view.size()) {
// Attempting to set an invalid tile. Assert, but otherwise ignore it. // Attempting to set an invalid tile. Assert, but otherwise ignore it.
CESIUM_ASSERT(false); CESIUM_ASSERT(false);

View File

@ -67,8 +67,8 @@ void markTileAvailableForQuadtree(
uint64_t availabilityBitIndex = uint64_t availabilityBitIndex =
numOfTilesFromRootToParentLevel + numOfTilesFromRootToParentLevel +
libmorton::morton2D_64_encode(tileID.x, tileID.y); libmorton::morton2D_64_encode(tileID.x, tileID.y);
const uint64_t byteIndex = availabilityBitIndex / 8; const size_t byteIndex = size_t(availabilityBitIndex / 8);
const uint64_t bitIndex = availabilityBitIndex % 8; const size_t bitIndex = size_t(availabilityBitIndex % 8);
available[byteIndex] |= std::byte(1 << bitIndex); available[byteIndex] |= std::byte(1 << bitIndex);
} }
@ -79,7 +79,7 @@ void markSubtreeAvailableForQuadtree(
libmorton::morton2D_64_encode(tileID.x, tileID.y); libmorton::morton2D_64_encode(tileID.x, tileID.y);
const uint64_t byteIndex = availabilityBitIndex / 8; const uint64_t byteIndex = availabilityBitIndex / 8;
const uint64_t bitIndex = availabilityBitIndex % 8; const uint64_t bitIndex = availabilityBitIndex % 8;
available[byteIndex] |= std::byte(1 << bitIndex); available[(size_t)byteIndex] |= std::byte(1 << bitIndex);
} }
using SubtreeContentInput = using SubtreeContentInput =
@ -140,17 +140,17 @@ SubtreeContent createSubtreeContent(
: 0; : 0;
std::vector<std::byte> availabilityBuffer( std::vector<std::byte> availabilityBuffer(
bufferSize + bufferSize + subtreeBufferSize); size_t(bufferSize + bufferSize + subtreeBufferSize));
std::span<std::byte> contentAvailabilityBuffer( std::span<std::byte> contentAvailabilityBuffer(
availabilityBuffer.data(), availabilityBuffer.data(),
bufferSize); size_t(bufferSize));
std::span<std::byte> tileAvailabilityBuffer( std::span<std::byte> tileAvailabilityBuffer(
availabilityBuffer.data() + bufferSize, availabilityBuffer.data() + bufferSize,
bufferSize); size_t(bufferSize));
std::span<std::byte> subtreeAvailabilityBuffer( std::span<std::byte> subtreeAvailabilityBuffer(
availabilityBuffer.data() + bufferSize + bufferSize, availabilityBuffer.data() + bufferSize + bufferSize,
subtreeBufferSize); size_t(subtreeBufferSize));
SubtreeAvailability::AvailabilityView tileAvailability = std::visit( SubtreeAvailability::AvailabilityView tileAvailability = std::visit(
GetAvailabilityView{tileAvailabilityBuffer, false}, GetAvailabilityView{tileAvailabilityBuffer, false},
@ -486,9 +486,9 @@ TEST_CASE("Test SubtreeAvailability methods") {
subtree.bufferViews[1].buffer = 1; subtree.bufferViews[1].buffer = 1;
subtree.bufferViews[2].buffer = 2; subtree.bufferViews[2].buffer = 2;
contentAvailabilityBuffer.resize(bufferSize); contentAvailabilityBuffer.resize(size_t(bufferSize));
tileAvailabilityBuffer.resize(bufferSize); tileAvailabilityBuffer.resize(size_t(bufferSize));
subtreeAvailabilityBuffer.resize(subtreeBufferSize); subtreeAvailabilityBuffer.resize(size_t(subtreeBufferSize));
subtree.buffers[0].byteLength = subtree.bufferViews[0].byteLength = subtree.buffers[0].byteLength = subtree.bufferViews[0].byteLength =
int64_t(bufferSize); int64_t(bufferSize);
@ -622,18 +622,18 @@ TEST_CASE("Test parsing subtree format") {
subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize(); subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize();
subtreeHeader.binaryByteLength = subtreeBuffers.buffers.size(); subtreeHeader.binaryByteLength = subtreeBuffers.buffers.size();
std::vector<std::byte> buffer( std::vector<std::byte> buffer(size_t(
sizeof(subtreeHeader) + subtreeHeader.jsonByteLength + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength +
subtreeHeader.binaryByteLength); subtreeHeader.binaryByteLength));
std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader)); std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader));
std::memcpy( std::memcpy(
buffer.data() + sizeof(subtreeHeader), buffer.data() + sizeof(subtreeHeader),
subtreeJsonBuffer.GetString(), subtreeJsonBuffer.GetString(),
subtreeHeader.jsonByteLength); size_t(subtreeHeader.jsonByteLength));
std::memcpy( std::memcpy(
buffer.data() + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength, buffer.data() + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength,
subtreeBuffers.buffers.data(), subtreeBuffers.buffers.data(),
subtreeHeader.binaryByteLength); size_t(subtreeHeader.binaryByteLength));
// mock the request // mock the request
auto pMockResponse = std::make_unique<SimpleAssetResponse>( auto pMockResponse = std::make_unique<SimpleAssetResponse>(
@ -711,18 +711,18 @@ TEST_CASE("Test parsing subtree format") {
subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize(); subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize();
subtreeHeader.binaryByteLength = subtreeContent.buffers.size(); subtreeHeader.binaryByteLength = subtreeContent.buffers.size();
std::vector<std::byte> buffer( std::vector<std::byte> buffer(size_t(
sizeof(subtreeHeader) + subtreeHeader.jsonByteLength + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength +
subtreeHeader.binaryByteLength); subtreeHeader.binaryByteLength));
std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader)); std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader));
std::memcpy( std::memcpy(
buffer.data() + sizeof(subtreeHeader), buffer.data() + sizeof(subtreeHeader),
subtreeJsonBuffer.GetString(), subtreeJsonBuffer.GetString(),
subtreeHeader.jsonByteLength); size_t(subtreeHeader.jsonByteLength));
std::memcpy( std::memcpy(
buffer.data() + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength, buffer.data() + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength,
subtreeContent.buffers.data(), subtreeContent.buffers.data(),
subtreeHeader.binaryByteLength); size_t(subtreeHeader.binaryByteLength));
// mock the request // mock the request
auto pMockResponse = std::make_unique<SimpleAssetResponse>( auto pMockResponse = std::make_unique<SimpleAssetResponse>(
@ -799,14 +799,14 @@ TEST_CASE("Test parsing subtree format") {
subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize(); subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize();
subtreeHeader.binaryByteLength = 0; subtreeHeader.binaryByteLength = 0;
std::vector<std::byte> buffer( std::vector<std::byte> buffer(size_t(
sizeof(subtreeHeader) + subtreeHeader.jsonByteLength + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength +
subtreeHeader.binaryByteLength); subtreeHeader.binaryByteLength));
std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader)); std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader));
std::memcpy( std::memcpy(
buffer.data() + sizeof(subtreeHeader), buffer.data() + sizeof(subtreeHeader),
subtreeJsonBuffer.GetString(), subtreeJsonBuffer.GetString(),
subtreeHeader.jsonByteLength); size_t(subtreeHeader.jsonByteLength));
// mock the request // mock the request
auto pMockResponse = std::make_unique<SimpleAssetResponse>( auto pMockResponse = std::make_unique<SimpleAssetResponse>(

View File

@ -165,12 +165,12 @@ Future<ReadJsonResult<Subtree>> SubtreeFileReader::loadBinary(
} }
ReadJsonResult<Subtree> result = this->_reader.readFromJson( ReadJsonResult<Subtree> result = this->_reader.readFromJson(
data.subspan(sizeof(SubtreeHeader), header->jsonByteLength)); data.subspan(sizeof(SubtreeHeader), size_t(header->jsonByteLength)));
if (result.value) { if (result.value) {
std::span<const std::byte> binaryChunk = data.subspan( std::span<const std::byte> binaryChunk = data.subspan(
sizeof(SubtreeHeader) + header->jsonByteLength, sizeof(SubtreeHeader) + size_t(header->jsonByteLength),
header->binaryByteLength); size_t(header->binaryByteLength));
if (binaryChunk.size() > 0) { if (binaryChunk.size() > 0) {
if (result.value->buffers.empty()) { if (result.value->buffers.empty()) {
@ -207,7 +207,7 @@ Future<ReadJsonResult<Subtree>> SubtreeFileReader::loadBinary(
buffer.cesium.data = std::vector<std::byte>( buffer.cesium.data = std::vector<std::byte>(
binaryChunk.begin(), binaryChunk.begin(),
binaryChunk.begin() + buffer.byteLength); binaryChunk.begin() + ptrdiff_t(buffer.byteLength));
} }
} }

View File

@ -52,7 +52,7 @@ target_link_libraries(Cesium3DTilesSelection
CesiumQuantizedMeshTerrain CesiumQuantizedMeshTerrain
CesiumRasterOverlays CesiumRasterOverlays
CesiumUtility CesiumUtility
spdlog::spdlog spdlog::spdlog_header_only spdlog::spdlog
# PRIVATE # PRIVATE
libmorton::libmorton libmorton::libmorton
draco::draco draco::draco

View File

@ -40,7 +40,7 @@ cesium_target_include_directories(
target_link_libraries(CesiumAsync target_link_libraries(CesiumAsync
PUBLIC PUBLIC
CesiumUtility CesiumUtility
spdlog::spdlog spdlog::spdlog_header_only spdlog::spdlog
Async++ Async++
PRIVATE PRIVATE
unofficial::sqlite3::sqlite3 unofficial::sqlite3::sqlite3

View File

@ -44,6 +44,12 @@ target_link_libraries(CesiumClientCommon
PRIVATE PRIVATE
picosha2::picosha2 picosha2::picosha2
modp_b64::modp_b64 modp_b64::modp_b64
httplib::httplib
OpenSSL::Crypto OpenSSL::Crypto
) )
if (NOT CESIUM_TARGET_WASM)
target_link_libraries(CesiumClientCommon
PRIVATE
httplib::httplib
)
endif()

View File

@ -13,7 +13,6 @@
#include <CesiumUtility/joinToString.h> #include <CesiumUtility/joinToString.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <httplib.h>
#include <modp_b64.h> #include <modp_b64.h>
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <rapidjson/error/en.h> #include <rapidjson/error/en.h>
@ -34,6 +33,13 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
// Using httplib for the internal HTTP server to receive the OAuth2 redirect URI
// is certainly not going to work on the web. And cpp-httplib only supports
// 64-bit platforms, so we can't even build it for 32-bit emscripten targets.
#ifndef __EMSCRIPTEN__
#include <httplib.h>
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4244) #pragma warning(disable : 4244)
@ -59,6 +65,7 @@ using namespace CesiumUtility;
namespace CesiumClientCommon { namespace CesiumClientCommon {
namespace { namespace {
#ifndef __EMSCRIPTEN__
std::string encodeBase64(const std::vector<uint8_t>& bytes) { std::string encodeBase64(const std::vector<uint8_t>& bytes) {
const size_t count = modp_b64_encode_len(bytes.size()); const size_t count = modp_b64_encode_len(bytes.size());
std::string result(count, 0); std::string result(count, 0);
@ -72,7 +79,7 @@ std::string encodeBase64(const std::vector<uint8_t>& bytes) {
// in [RFC7636 Appendix A](https://tools.ietf.org/html/rfc7636#appendix-A) // in [RFC7636 Appendix A](https://tools.ietf.org/html/rfc7636#appendix-A)
const size_t firstPaddingIndex = result.find('='); const size_t firstPaddingIndex = result.find('=');
if (firstPaddingIndex != std::string::npos) { if (firstPaddingIndex != std::string::npos) {
result.erase(result.begin() + int64_t(firstPaddingIndex), result.end()); result.erase(result.begin() + ptrdiff_t(firstPaddingIndex), result.end());
} }
std::replace(result.begin(), result.end(), '+', '-'); std::replace(result.begin(), result.end(), '+', '-');
std::replace(result.begin(), result.end(), '/', '_'); std::replace(result.begin(), result.end(), '/', '_');
@ -170,17 +177,28 @@ std::string createAuthorizationErrorHtml(
exception.what(), exception.what(),
applicationName); applicationName);
} }
#endif // #ifndef __EMSCRIPTEN__
} // namespace } // namespace
CesiumAsync::Future<Result<OAuth2TokenResponse>> OAuth2PKCE::authorize( CesiumAsync::Future<Result<OAuth2TokenResponse>> OAuth2PKCE::authorize(
const CesiumAsync::AsyncSystem& asyncSystem, const CesiumAsync::AsyncSystem& asyncSystem,
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor, [[maybe_unused]] const std::shared_ptr<CesiumAsync::IAssetAccessor>&
const std::string& friendlyApplicationName, pAssetAccessor,
const OAuth2ClientOptions& clientOptions, [[maybe_unused]] const std::string& friendlyApplicationName,
const std::vector<std::string>& scopes, [[maybe_unused]] const OAuth2ClientOptions& clientOptions,
std::function<void(const std::string&)>&& openUrlCallback, [[maybe_unused]] const std::vector<std::string>& scopes,
const std::string& tokenEndpointUrl, [[maybe_unused]] std::function<void(const std::string&)>&& openUrlCallback,
const std::string& authorizeBaseUrl) { [[maybe_unused]] const std::string& tokenEndpointUrl,
[[maybe_unused]] const std::string& authorizeBaseUrl) {
#ifdef __EMSCRIPTEN__
// Currently we just fail the authorization attempt in Emscripten / web
// builds. In theory, we can do a more web-oriented authorization flow here
// instead.
return asyncSystem.createResolvedFuture<Result<OAuth2TokenResponse>>(
Result<OAuth2TokenResponse>(
ErrorList::error("OAuth2 PKCE authorization is not supported in "
"Emscripten / WebAssembly builds.")));
#else // #ifdef __EMSCRIPTEN__
auto promise = asyncSystem.createPromise<Result<OAuth2TokenResponse>>(); auto promise = asyncSystem.createPromise<Result<OAuth2TokenResponse>>();
std::shared_ptr<httplib::Server> pServer = std::shared_ptr<httplib::Server> pServer =
@ -332,6 +350,7 @@ CesiumAsync::Future<Result<OAuth2TokenResponse>> OAuth2PKCE::authorize(
openUrlCallback(authorizeUrl); openUrlCallback(authorizeUrl);
return promise.getFuture(); return promise.getFuture();
#endif // #ifdef __EMSCRIPTEN__ #else
} }
CesiumAsync::Future<Result<OAuth2TokenResponse>> CesiumAsync::Future<Result<OAuth2TokenResponse>>

View File

@ -0,0 +1,121 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/Library.h>
#include <CesiumUtility/ExtensibleObject.h>
#include <string>
namespace CesiumGltf {
/**
* @brief Data defining a 3D Gaussian Splat primitive.
*/
struct CESIUMGLTF_API ExtensionKhrGaussianSplatting final
: public CesiumUtility::ExtensibleObject {
/**
* @brief The original name of this type.
*/
static constexpr const char* TypeName = "ExtensionKhrGaussianSplatting";
/** @brief The official name of the extension. This should be the same as its
* key in the `extensions` object. */
static constexpr const char* ExtensionName = "KHR_gaussian_splatting";
/**
* @brief Known values for Optional property specifying how to project the
* Gaussians to achieve a perspective correct value. This property defaults to
* perspective.
*/
struct Projection {
/** @brief `perspective` */
inline static const std::string perspective = "perspective";
/** @brief `orthographic` */
inline static const std::string orthographic = "orthographic";
};
/**
* @brief Known values for Optional property specifying how to sort the
* Gaussians during rendering. This property defaults to cameraDistance.
*/
struct SortingMethod {
/** @brief `cameraDistance` */
inline static const std::string cameraDistance = "cameraDistance";
/** @brief `zDepth` */
inline static const std::string zDepth = "zDepth";
};
/**
* @brief Known values for Optional property specifying the color space of the
* spherical harmonics. This property defaults to BT.709.
*/
struct ColorSpace {
/** @brief `BT.709` */
inline static const std::string BT_709 = "BT.709";
/** @brief `BT.2020-ITU` */
inline static const std::string BT_2020_ITU = "BT.2020-ITU";
/** @brief `BT.2020-HLG` */
inline static const std::string BT_2020_HLG = "BT.2020-HLG";
/** @brief `BT.2020-PQ` */
inline static const std::string BT_2020_PQ = "BT.2020-PQ";
/** @brief `Display-P3` */
inline static const std::string Display_P3 = "Display-P3";
/** @brief `linear` */
inline static const std::string linear = "linear";
};
/**
* @brief Optional property specifying parameters regarding the kernel used to
* generate the Gaussians. This property defaults to ellipse.
*/
std::string kernel = "ellipse";
/**
* @brief Optional property specifying how to project the Gaussians to achieve
* a perspective correct value. This property defaults to perspective.
*
* Known values are defined in {@link Projection}.
*
*/
std::string projection = Projection::perspective;
/**
* @brief Optional property specifying how to sort the Gaussians during
* rendering. This property defaults to cameraDistance.
*
* Known values are defined in {@link SortingMethod}.
*
*/
std::string sortingMethod = SortingMethod::cameraDistance;
/**
* @brief Optional property specifying the color space of the spherical
* harmonics. This property defaults to BT.709.
*
* Known values are defined in {@link ColorSpace}.
*
*/
std::string colorSpace = ColorSpace::BT_709;
/**
* @brief Calculates the size in bytes of this object, including the contents
* of all collections, pointers, and strings. This will NOT include the size
* of any extensions attached to the object. Calling this method may be slow
* as it requires traversing the object's entire structure.
*/
int64_t getSizeBytes() const {
int64_t accum = 0;
accum += int64_t(sizeof(ExtensionKhrGaussianSplatting));
accum += CesiumUtility::ExtensibleObject::getSizeBytes() -
int64_t(sizeof(CesiumUtility::ExtensibleObject));
accum += int64_t(this->kernel.capacity() * sizeof(char));
return accum;
}
};
} // namespace CesiumGltf

View File

@ -0,0 +1,46 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/Library.h>
#include <CesiumUtility/ExtensibleObject.h>
#include <cstdint>
namespace CesiumGltf {
/**
* @brief Compressed data for SPZ v2 primitive.
*/
struct CESIUMGLTF_API ExtensionKhrGaussianSplattingCompressionSpz2 final
: public CesiumUtility::ExtensibleObject {
/**
* @brief The original name of this type.
*/
static constexpr const char* TypeName =
"ExtensionKhrGaussianSplattingCompressionSpz2";
/** @brief The official name of the extension. This should be the same as its
* key in the `extensions` object. */
static constexpr const char* ExtensionName =
"KHR_gaussian_splatting_compression_spz_2";
/**
* @brief The index of the bufferView.
*/
int32_t bufferView = -1;
/**
* @brief Calculates the size in bytes of this object, including the contents
* of all collections, pointers, and strings. This will NOT include the size
* of any extensions attached to the object. Calling this method may be slow
* as it requires traversing the object's entire structure.
*/
int64_t getSizeBytes() const {
int64_t accum = 0;
accum += int64_t(sizeof(ExtensionKhrGaussianSplattingCompressionSpz2));
accum += CesiumUtility::ExtensibleObject::getSizeBytes() -
int64_t(sizeof(CesiumUtility::ExtensibleObject));
return accum;
}
};
} // namespace CesiumGltf

View File

@ -0,0 +1,53 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/Library.h>
#include <CesiumUtility/ExtensibleObject.h>
#include <string>
namespace CesiumGltf {
/**
* @brief Optional rendering hints for rendering the 3D Gaussian splats.
* Renderers are free to ignore any of these.
*/
struct CESIUMGLTF_API ExtensionKhrGaussianSplattingHintsValue final
: public CesiumUtility::ExtensibleObject {
/**
* @brief The original name of this type.
*/
static constexpr const char* TypeName =
"ExtensionKhrGaussianSplattingHintsValue";
/**
* @brief Provides a hint specifying how to project the Gaussians to achieve a
* perspective correct value. This is a freeform field that defaults to
* perspective. See the extension specification for further known types.
*/
std::string projection = "perspective";
/**
* @brief Provides a hint specifying how to sort the Gaussians during
* rendering. This is a freeform field defaulting to cameraDistance. See the
* extension specification for further known types.
*/
std::string sortingMethod = "cameraDistance";
/**
* @brief Calculates the size in bytes of this object, including the contents
* of all collections, pointers, and strings. This will NOT include the size
* of any extensions attached to the object. Calling this method may be slow
* as it requires traversing the object's entire structure.
*/
int64_t getSizeBytes() const {
int64_t accum = 0;
accum += int64_t(sizeof(ExtensionKhrGaussianSplattingHintsValue));
accum += CesiumUtility::ExtensibleObject::getSizeBytes() -
int64_t(sizeof(CesiumUtility::ExtensibleObject));
accum += int64_t(this->projection.capacity() * sizeof(char));
accum += int64_t(this->sortingMethod.capacity() * sizeof(char));
return accum;
}
};
} // namespace CesiumGltf

View File

@ -22,7 +22,7 @@ struct CESIUMGLTF_API ExtensionTextureWebp final
static constexpr const char* ExtensionName = "EXT_texture_webp"; static constexpr const char* ExtensionName = "EXT_texture_webp";
/** /**
* @brief The index of the images node which points to a WebP image. * @brief The index of the WebP image.
*/ */
int32_t source = -1; int32_t source = -1;

View File

@ -2823,7 +2823,7 @@ private:
} }
uint64_t totalLength = stringOffsets.back(); uint64_t totalLength = stringOffsets.back();
result.data.resize(totalLength); result.data.resize(size_t(totalLength));
for (size_t i = 0; i < strings.size(); ++i) { for (size_t i = 0; i < strings.size(); ++i) {
std::memcpy( std::memcpy(
result.data.data() + stringOffsets[i], result.data.data() + stringOffsets[i],

View File

@ -44,7 +44,12 @@
#include <glm/ext/quaternion_double.hpp> #include <glm/ext/quaternion_double.hpp>
#include <glm/ext/vector_float3.hpp> #include <glm/ext/vector_float3.hpp>
#include <glm/geometric.hpp> #include <glm/geometric.hpp>
#include <glm/gtc/quaternion.hpp> // NOLINT(misc-include-cleaner)
#include <glm/gtx/norm.hpp> #include <glm/gtx/norm.hpp>
// Despite what clang-tidy will say, we *do* actually need this include or we'll
// get a "missing mat4_cast" error.
// NOLINTNEXTLINE
#include <glm/gtc/quaternion.hpp>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -408,7 +413,7 @@ ErrorList Model::merge(Model&& rhs) {
std::copy( std::copy(
pRhsDefaultScene->nodes.begin(), pRhsDefaultScene->nodes.begin(),
pRhsDefaultScene->nodes.end(), pRhsDefaultScene->nodes.end(),
newScene.nodes.begin() + int64_t(originalNodeCount)); newScene.nodes.begin() + ptrdiff_t(originalNodeCount));
// No need to update indices because they've already been updated when // No need to update indices because they've already been updated when
// we copied them from rhs to this. // we copied them from rhs to this.

View File

@ -28,7 +28,7 @@ template <typename T>
PropertyViewStatusType checkOffsetsBuffer( PropertyViewStatusType checkOffsetsBuffer(
const std::span<const std::byte>& offsetBuffer, const std::span<const std::byte>& offsetBuffer,
size_t valueBufferSize, size_t valueBufferSize,
size_t instanceCount, uint64_t instanceCount,
bool checkBitSize, bool checkBitSize,
PropertyViewStatusType offsetsNotSortedError, PropertyViewStatusType offsetsNotSortedError,
PropertyViewStatusType offsetOutOfBoundsError) noexcept { PropertyViewStatusType offsetOutOfBoundsError) noexcept {

View File

@ -50,6 +50,7 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cassert> #include <cassert>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
@ -1158,8 +1159,8 @@ void deleteBufferRange(
// Actually remove the bytes from the buffer. // Actually remove the bytes from the buffer.
pBuffer->byteLength -= bytesToRemove; pBuffer->byteLength -= bytesToRemove;
pBuffer->cesium.data.erase( pBuffer->cesium.data.erase(
pBuffer->cesium.data.begin() + start, pBuffer->cesium.data.begin() + ptrdiff_t(start),
pBuffer->cesium.data.begin() + end); pBuffer->cesium.data.begin() + ptrdiff_t(end));
} }
} // namespace } // namespace

View File

@ -62,6 +62,21 @@ target_link_libraries(CesiumGltfReader
meshoptimizer::meshoptimizer meshoptimizer::meshoptimizer
modp_b64::modp_b64 modp_b64::modp_b64
KTX::ktx KTX::ktx
WebP::webp WebP::webpdecoder spz::spz
WebP::webp
WebP::webpdecoder
)
if(CESIUM_DISABLE_LIBJPEG_TURBO)
target_compile_definitions(
CesiumGltfReader
PRIVATE
CESIUM_DISABLE_LIBJPEG_TURBO
)
else()
target_link_libraries(
CesiumGltfReader
PRIVATE
$<IF:$<TARGET_EXISTS:libjpeg-turbo::turbojpeg>,libjpeg-turbo::turbojpeg,libjpeg-turbo::turbojpeg-static> $<IF:$<TARGET_EXISTS:libjpeg-turbo::turbojpeg>,libjpeg-turbo::turbojpeg,libjpeg-turbo::turbojpeg-static>
) )
endif()

View File

@ -0,0 +1,79 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h>
#include <CesiumGltfReader/Library.h>
#include <CesiumJsonReader/JsonReader.h>
#include <CesiumJsonReader/JsonReaderOptions.h>
#include <rapidjson/fwd.h>
#include <span>
#include <vector>
namespace CesiumGltf {
struct ExtensionKhrGaussianSplattingCompressionSpz2;
} // namespace CesiumGltf
namespace CesiumGltfReader {
/**
* @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2
* "ExtensionKhrGaussianSplattingCompressionSpz2" instances from JSON.
*/
class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingCompressionSpz2Reader {
public:
/**
* @brief Constructs a new instance.
*/
ExtensionKhrGaussianSplattingCompressionSpz2Reader();
/**
* @brief Gets the options controlling how the JSON is read.
*/
CesiumJsonReader::JsonReaderOptions& getOptions();
/**
* @brief Gets the options controlling how the JSON is read.
*/
const CesiumJsonReader::JsonReaderOptions& getOptions() const;
/**
* @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz2
* from a byte buffer.
*
* @param data The buffer from which to read the instance.
* @return The result of reading the instance.
*/
CesiumJsonReader::ReadJsonResult<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>
readFromJson(const std::span<const std::byte>& data) const;
/**
* @brief Reads an instance of ExtensionKhrGaussianSplattingCompressionSpz2
* from a rapidJson::Value.
*
* @param value The value from which to read the instance.
* @return The result of reading the instance.
*/
CesiumJsonReader::ReadJsonResult<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>
readFromJson(const rapidjson::Value& value) const;
/**
* @brief Reads an array of instances of
* ExtensionKhrGaussianSplattingCompressionSpz2 from a rapidJson::Value.
*
* @param value The value from which to read the array of instances.
* @return The result of reading the array of instances.
*/
CesiumJsonReader::ReadJsonResult<
std::vector<CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>>
readArrayFromJson(const rapidjson::Value& value) const;
private:
CesiumJsonReader::JsonReaderOptions _options;
};
} // namespace CesiumGltfReader

View File

@ -0,0 +1,79 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/ExtensionKhrGaussianSplattingHintsValue.h>
#include <CesiumGltfReader/Library.h>
#include <CesiumJsonReader/JsonReader.h>
#include <CesiumJsonReader/JsonReaderOptions.h>
#include <rapidjson/fwd.h>
#include <span>
#include <vector>
namespace CesiumGltf {
struct ExtensionKhrGaussianSplattingHintsValue;
} // namespace CesiumGltf
namespace CesiumGltfReader {
/**
* @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplattingHintsValue
* "ExtensionKhrGaussianSplattingHintsValue" instances from JSON.
*/
class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingHintsValueReader {
public:
/**
* @brief Constructs a new instance.
*/
ExtensionKhrGaussianSplattingHintsValueReader();
/**
* @brief Gets the options controlling how the JSON is read.
*/
CesiumJsonReader::JsonReaderOptions& getOptions();
/**
* @brief Gets the options controlling how the JSON is read.
*/
const CesiumJsonReader::JsonReaderOptions& getOptions() const;
/**
* @brief Reads an instance of ExtensionKhrGaussianSplattingHintsValue from a
* byte buffer.
*
* @param data The buffer from which to read the instance.
* @return The result of reading the instance.
*/
CesiumJsonReader::ReadJsonResult<
CesiumGltf::ExtensionKhrGaussianSplattingHintsValue>
readFromJson(const std::span<const std::byte>& data) const;
/**
* @brief Reads an instance of ExtensionKhrGaussianSplattingHintsValue from a
* rapidJson::Value.
*
* @param value The value from which to read the instance.
* @return The result of reading the instance.
*/
CesiumJsonReader::ReadJsonResult<
CesiumGltf::ExtensionKhrGaussianSplattingHintsValue>
readFromJson(const rapidjson::Value& value) const;
/**
* @brief Reads an array of instances of
* ExtensionKhrGaussianSplattingHintsValue from a rapidJson::Value.
*
* @param value The value from which to read the array of instances.
* @return The result of reading the array of instances.
*/
CesiumJsonReader::ReadJsonResult<
std::vector<CesiumGltf::ExtensionKhrGaussianSplattingHintsValue>>
readArrayFromJson(const rapidjson::Value& value) const;
private:
CesiumJsonReader::JsonReaderOptions _options;
};
} // namespace CesiumGltfReader

View File

@ -0,0 +1,77 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltfReader/Library.h>
#include <CesiumJsonReader/JsonReader.h>
#include <CesiumJsonReader/JsonReaderOptions.h>
#include <rapidjson/fwd.h>
#include <span>
#include <vector>
namespace CesiumGltf {
struct ExtensionKhrGaussianSplatting;
} // namespace CesiumGltf
namespace CesiumGltfReader {
/**
* @brief Reads \ref CesiumGltf::ExtensionKhrGaussianSplatting
* "ExtensionKhrGaussianSplatting" instances from JSON.
*/
class CESIUMGLTFREADER_API ExtensionKhrGaussianSplattingReader {
public:
/**
* @brief Constructs a new instance.
*/
ExtensionKhrGaussianSplattingReader();
/**
* @brief Gets the options controlling how the JSON is read.
*/
CesiumJsonReader::JsonReaderOptions& getOptions();
/**
* @brief Gets the options controlling how the JSON is read.
*/
const CesiumJsonReader::JsonReaderOptions& getOptions() const;
/**
* @brief Reads an instance of ExtensionKhrGaussianSplatting from a byte
* buffer.
*
* @param data The buffer from which to read the instance.
* @return The result of reading the instance.
*/
CesiumJsonReader::ReadJsonResult<CesiumGltf::ExtensionKhrGaussianSplatting>
readFromJson(const std::span<const std::byte>& data) const;
/**
* @brief Reads an instance of ExtensionKhrGaussianSplatting from a
* rapidJson::Value.
*
* @param value The value from which to read the instance.
* @return The result of reading the instance.
*/
CesiumJsonReader::ReadJsonResult<CesiumGltf::ExtensionKhrGaussianSplatting>
readFromJson(const rapidjson::Value& value) const;
/**
* @brief Reads an array of instances of ExtensionKhrGaussianSplatting from a
* rapidJson::Value.
*
* @param value The value from which to read the array of instances.
* @return The result of reading the array of instances.
*/
CesiumJsonReader::ReadJsonResult<
std::vector<CesiumGltf::ExtensionKhrGaussianSplatting>>
readArrayFromJson(const rapidjson::Value& value) const;
private:
CesiumJsonReader::JsonReaderOptions _options;
};
} // namespace CesiumGltfReader

View File

@ -0,0 +1,48 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h>
#include <CesiumJsonReader/ExtensibleObjectJsonHandler.h>
#include <CesiumJsonReader/IntegerJsonHandler.h>
namespace CesiumJsonReader {
class JsonReaderOptions;
} // namespace CesiumJsonReader
namespace CesiumGltfReader {
class ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler
: public CesiumJsonReader::ExtensibleObjectJsonHandler,
public CesiumJsonReader::IExtensionJsonHandler {
public:
using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2;
static constexpr const char* ExtensionName =
"KHR_gaussian_splatting_compression_spz_2";
explicit ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler(
const CesiumJsonReader::JsonReaderOptions& options) noexcept;
void reset(
IJsonHandler* pParentHandler,
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pObject);
IJsonHandler* readObjectKey(const std::string_view& str) override;
void reset(
IJsonHandler* pParentHandler,
CesiumUtility::ExtensibleObject& o,
const std::string_view& extensionName) override;
IJsonHandler& getHandler() override { return *this; }
protected:
IJsonHandler* readObjectKeyExtensionKhrGaussianSplattingCompressionSpz2(
const std::string& objectType,
const std::string_view& str,
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& o);
private:
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* _pObject = nullptr;
CesiumJsonReader::IntegerJsonHandler<int32_t> _bufferView;
};
} // namespace CesiumGltfReader

View File

@ -0,0 +1,38 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/ExtensionKhrGaussianSplattingHintsValue.h>
#include <CesiumJsonReader/ExtensibleObjectJsonHandler.h>
#include <CesiumJsonReader/StringJsonHandler.h>
namespace CesiumJsonReader {
class JsonReaderOptions;
} // namespace CesiumJsonReader
namespace CesiumGltfReader {
class ExtensionKhrGaussianSplattingHintsValueJsonHandler
: public CesiumJsonReader::ExtensibleObjectJsonHandler {
public:
using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingHintsValue;
explicit ExtensionKhrGaussianSplattingHintsValueJsonHandler(
const CesiumJsonReader::JsonReaderOptions& options) noexcept;
void reset(
IJsonHandler* pParentHandler,
CesiumGltf::ExtensionKhrGaussianSplattingHintsValue* pObject);
IJsonHandler* readObjectKey(const std::string_view& str) override;
protected:
IJsonHandler* readObjectKeyExtensionKhrGaussianSplattingHintsValue(
const std::string& objectType,
const std::string_view& str,
CesiumGltf::ExtensionKhrGaussianSplattingHintsValue& o);
private:
CesiumGltf::ExtensionKhrGaussianSplattingHintsValue* _pObject = nullptr;
CesiumJsonReader::StringJsonHandler _projection;
CesiumJsonReader::StringJsonHandler _sortingMethod;
};
} // namespace CesiumGltfReader

View File

@ -0,0 +1,50 @@
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
#pragma once
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumJsonReader/ExtensibleObjectJsonHandler.h>
#include <CesiumJsonReader/StringJsonHandler.h>
namespace CesiumJsonReader {
class JsonReaderOptions;
} // namespace CesiumJsonReader
namespace CesiumGltfReader {
class ExtensionKhrGaussianSplattingJsonHandler
: public CesiumJsonReader::ExtensibleObjectJsonHandler,
public CesiumJsonReader::IExtensionJsonHandler {
public:
using ValueType = CesiumGltf::ExtensionKhrGaussianSplatting;
static constexpr const char* ExtensionName = "KHR_gaussian_splatting";
explicit ExtensionKhrGaussianSplattingJsonHandler(
const CesiumJsonReader::JsonReaderOptions& options) noexcept;
void reset(
IJsonHandler* pParentHandler,
CesiumGltf::ExtensionKhrGaussianSplatting* pObject);
IJsonHandler* readObjectKey(const std::string_view& str) override;
void reset(
IJsonHandler* pParentHandler,
CesiumUtility::ExtensibleObject& o,
const std::string_view& extensionName) override;
IJsonHandler& getHandler() override { return *this; }
protected:
IJsonHandler* readObjectKeyExtensionKhrGaussianSplatting(
const std::string& objectType,
const std::string_view& str,
CesiumGltf::ExtensionKhrGaussianSplatting& o);
private:
CesiumGltf::ExtensionKhrGaussianSplatting* _pObject = nullptr;
CesiumJsonReader::StringJsonHandler _kernel;
CesiumJsonReader::StringJsonHandler _projection;
CesiumJsonReader::StringJsonHandler _sortingMethod;
CesiumJsonReader::StringJsonHandler _colorSpace;
};
} // namespace CesiumGltfReader

View File

@ -2974,6 +2974,260 @@ ExtensionExtPrimitiveVoxelsReader::readArrayFromJson(
return CesiumJsonReader::JsonReader::readJson(value, handler); return CesiumJsonReader::JsonReader::readJson(value, handler);
} }
} // namespace CesiumGltfReader
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
// NOLINTBEGIN(readability-duplicate-include)
#include "ExtensionKhrGaussianSplattingJsonHandler.h"
#include "registerReaderExtensions.h"
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltfReader/ExtensionKhrGaussianSplattingReader.h>
#include <CesiumJsonReader/ArrayJsonHandler.h>
#include <CesiumJsonReader/ExtensibleObjectJsonHandler.h>
#include <CesiumJsonReader/IJsonHandler.h>
#include <CesiumJsonReader/JsonReader.h>
#include <CesiumUtility/Assert.h>
#include <CesiumUtility/ExtensibleObject.h>
#include <rapidjson/document.h>
#include <any>
#include <cstddef>
#include <span>
#include <string>
#include <string_view>
#include <vector>
// NOLINTEND(readability-duplicate-include)
namespace CesiumGltfReader {
ExtensionKhrGaussianSplattingJsonHandler::
ExtensionKhrGaussianSplattingJsonHandler(
const CesiumJsonReader::JsonReaderOptions& options) noexcept
: CesiumJsonReader::ExtensibleObjectJsonHandler(options),
_kernel(),
_projection(),
_sortingMethod(),
_colorSpace() {}
void ExtensionKhrGaussianSplattingJsonHandler::reset(
CesiumJsonReader::IJsonHandler* pParentHandler,
CesiumGltf::ExtensionKhrGaussianSplatting* pObject) {
CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject);
this->_pObject = pObject;
}
CesiumJsonReader::IJsonHandler*
ExtensionKhrGaussianSplattingJsonHandler::readObjectKey(
const std::string_view& str) {
CESIUM_ASSERT(this->_pObject);
return this->readObjectKeyExtensionKhrGaussianSplatting(
CesiumGltf::ExtensionKhrGaussianSplatting::TypeName,
str,
*this->_pObject);
}
void ExtensionKhrGaussianSplattingJsonHandler::reset(
CesiumJsonReader::IJsonHandler* pParentHandler,
CesiumUtility::ExtensibleObject& o,
const std::string_view& extensionName) {
std::any& value =
o.extensions
.emplace(extensionName, CesiumGltf::ExtensionKhrGaussianSplatting())
.first->second;
this->reset(
pParentHandler,
&std::any_cast<CesiumGltf::ExtensionKhrGaussianSplatting&>(value));
}
CesiumJsonReader::IJsonHandler* ExtensionKhrGaussianSplattingJsonHandler::
readObjectKeyExtensionKhrGaussianSplatting(
const std::string& objectType,
const std::string_view& str,
CesiumGltf::ExtensionKhrGaussianSplatting& o) {
using namespace std::string_literals;
if ("kernel"s == str) {
return property("kernel", this->_kernel, o.kernel);
}
if ("projection"s == str) {
return property("projection", this->_projection, o.projection);
}
if ("sortingMethod"s == str) {
return property("sortingMethod", this->_sortingMethod, o.sortingMethod);
}
if ("colorSpace"s == str) {
return property("colorSpace", this->_colorSpace, o.colorSpace);
}
return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject);
}
ExtensionKhrGaussianSplattingReader::ExtensionKhrGaussianSplattingReader() {
registerReaderExtensions(this->_options);
}
CesiumJsonReader::JsonReaderOptions&
ExtensionKhrGaussianSplattingReader::getOptions() {
return this->_options;
}
const CesiumJsonReader::JsonReaderOptions&
ExtensionKhrGaussianSplattingReader::getOptions() const {
return this->_options;
}
CesiumJsonReader::ReadJsonResult<CesiumGltf::ExtensionKhrGaussianSplatting>
ExtensionKhrGaussianSplattingReader::readFromJson(
const std::span<const std::byte>& data) const {
ExtensionKhrGaussianSplattingJsonHandler handler(this->_options);
return CesiumJsonReader::JsonReader::readJson(data, handler);
}
CesiumJsonReader::ReadJsonResult<CesiumGltf::ExtensionKhrGaussianSplatting>
ExtensionKhrGaussianSplattingReader::readFromJson(
const rapidjson::Value& value) const {
ExtensionKhrGaussianSplattingJsonHandler handler(this->_options);
return CesiumJsonReader::JsonReader::readJson(value, handler);
}
CesiumJsonReader::ReadJsonResult<
std::vector<CesiumGltf::ExtensionKhrGaussianSplatting>>
ExtensionKhrGaussianSplattingReader::readArrayFromJson(
const rapidjson::Value& value) const {
CesiumJsonReader::ArrayJsonHandler<
CesiumGltf::ExtensionKhrGaussianSplatting,
ExtensionKhrGaussianSplattingJsonHandler>
handler(this->_options);
return CesiumJsonReader::JsonReader::readJson(value, handler);
}
} // namespace CesiumGltfReader
// This file was generated by generate-classes.
// DO NOT EDIT THIS FILE!
// NOLINTBEGIN(readability-duplicate-include)
#include "ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h"
#include "registerReaderExtensions.h"
#include <CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h>
#include <CesiumGltfReader/ExtensionKhrGaussianSplattingCompressionSpz2Reader.h>
#include <CesiumJsonReader/ArrayJsonHandler.h>
#include <CesiumJsonReader/ExtensibleObjectJsonHandler.h>
#include <CesiumJsonReader/IJsonHandler.h>
#include <CesiumJsonReader/JsonReader.h>
#include <CesiumUtility/Assert.h>
#include <CesiumUtility/ExtensibleObject.h>
#include <rapidjson/document.h>
#include <any>
#include <cstddef>
#include <span>
#include <string>
#include <string_view>
#include <vector>
// NOLINTEND(readability-duplicate-include)
namespace CesiumGltfReader {
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler(
const CesiumJsonReader::JsonReaderOptions& options) noexcept
: CesiumJsonReader::ExtensibleObjectJsonHandler(options), _bufferView() {}
void ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::reset(
CesiumJsonReader::IJsonHandler* pParentHandler,
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pObject) {
CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject);
this->_pObject = pObject;
}
CesiumJsonReader::IJsonHandler*
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::readObjectKey(
const std::string_view& str) {
CESIUM_ASSERT(this->_pObject);
return this->readObjectKeyExtensionKhrGaussianSplattingCompressionSpz2(
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::TypeName,
str,
*this->_pObject);
}
void ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::reset(
CesiumJsonReader::IJsonHandler* pParentHandler,
CesiumUtility::ExtensibleObject& o,
const std::string_view& extensionName) {
std::any& value =
o.extensions
.emplace(
extensionName,
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2())
.first->second;
this->reset(
pParentHandler,
&std::any_cast<CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2&>(
value));
}
CesiumJsonReader::IJsonHandler*
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler::
readObjectKeyExtensionKhrGaussianSplattingCompressionSpz2(
const std::string& objectType,
const std::string_view& str,
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& o) {
using namespace std::string_literals;
if ("bufferView"s == str) {
return property("bufferView", this->_bufferView, o.bufferView);
}
return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject);
}
ExtensionKhrGaussianSplattingCompressionSpz2Reader::
ExtensionKhrGaussianSplattingCompressionSpz2Reader() {
registerReaderExtensions(this->_options);
}
CesiumJsonReader::JsonReaderOptions&
ExtensionKhrGaussianSplattingCompressionSpz2Reader::getOptions() {
return this->_options;
}
const CesiumJsonReader::JsonReaderOptions&
ExtensionKhrGaussianSplattingCompressionSpz2Reader::getOptions() const {
return this->_options;
}
CesiumJsonReader::ReadJsonResult<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>
ExtensionKhrGaussianSplattingCompressionSpz2Reader::readFromJson(
const std::span<const std::byte>& data) const {
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler handler(
this->_options);
return CesiumJsonReader::JsonReader::readJson(data, handler);
}
CesiumJsonReader::ReadJsonResult<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>
ExtensionKhrGaussianSplattingCompressionSpz2Reader::readFromJson(
const rapidjson::Value& value) const {
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler handler(
this->_options);
return CesiumJsonReader::JsonReader::readJson(value, handler);
}
CesiumJsonReader::ReadJsonResult<
std::vector<CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>>
ExtensionKhrGaussianSplattingCompressionSpz2Reader::readArrayFromJson(
const rapidjson::Value& value) const {
CesiumJsonReader::ArrayJsonHandler<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2,
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler>
handler(this->_options);
return CesiumJsonReader::JsonReader::readJson(value, handler);
}
} // namespace CesiumGltfReader } // namespace CesiumGltfReader
// This file was generated by generate-classes. // This file was generated by generate-classes.
// DO NOT EDIT THIS FILE! // DO NOT EDIT THIS FILE!

View File

@ -16,6 +16,8 @@
#include "ExtensionExtPrimitiveVoxelsJsonHandler.h" #include "ExtensionExtPrimitiveVoxelsJsonHandler.h"
#include "ExtensionExtStructuralMetadataJsonHandler.h" #include "ExtensionExtStructuralMetadataJsonHandler.h"
#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" #include "ExtensionKhrDracoMeshCompressionJsonHandler.h"
#include "ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler.h"
#include "ExtensionKhrGaussianSplattingJsonHandler.h"
#include "ExtensionKhrImplicitShapesJsonHandler.h" #include "ExtensionKhrImplicitShapesJsonHandler.h"
#include "ExtensionKhrMaterialsUnlitJsonHandler.h" #include "ExtensionKhrMaterialsUnlitJsonHandler.h"
#include "ExtensionKhrTextureBasisuJsonHandler.h" #include "ExtensionKhrTextureBasisuJsonHandler.h"
@ -30,6 +32,7 @@
#include <CesiumGltf/Buffer.h> #include <CesiumGltf/Buffer.h>
#include <CesiumGltf/BufferView.h> #include <CesiumGltf/BufferView.h>
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltf/FeatureIdTexture.h> #include <CesiumGltf/FeatureIdTexture.h>
#include <CesiumGltf/Material.h> #include <CesiumGltf/Material.h>
#include <CesiumGltf/MaterialNormalTextureInfo.h> #include <CesiumGltf/MaterialNormalTextureInfo.h>
@ -81,6 +84,9 @@ void registerReaderExtensions(CesiumJsonReader::JsonReaderOptions& options) {
options.registerExtension< options.registerExtension<
CesiumGltf::MeshPrimitive, CesiumGltf::MeshPrimitive,
ExtensionExtPrimitiveVoxelsJsonHandler>(); ExtensionExtPrimitiveVoxelsJsonHandler>();
options.registerExtension<
CesiumGltf::MeshPrimitive,
ExtensionKhrGaussianSplattingJsonHandler>();
options.registerExtension< options.registerExtension<
CesiumGltf::Node, CesiumGltf::Node,
ExtensionExtInstanceFeaturesJsonHandler>(); ExtensionExtInstanceFeaturesJsonHandler>();
@ -132,5 +138,8 @@ void registerReaderExtensions(CesiumJsonReader::JsonReaderOptions& options) {
options.registerExtension< options.registerExtension<
CesiumGltf::Shape, CesiumGltf::Shape,
ExtensionExtImplicitCylinderRegionJsonHandler>(); ExtensionExtImplicitCylinderRegionJsonHandler>();
options.registerExtension<
CesiumGltf::ExtensionKhrGaussianSplatting,
ExtensionKhrGaussianSplattingCompressionSpz2JsonHandler>();
} }
} // namespace CesiumGltfReader } // namespace CesiumGltfReader

View File

@ -89,6 +89,13 @@ struct CESIUMGLTFREADER_API GltfReaderOptions {
*/ */
bool decodeMeshOptData = true; bool decodeMeshOptData = true;
/**
* @brief Whether gaussian splatting data are decompressed as part of the load
* process, or left in the compressed format according to the
* KHR_gaussian_splatting_compression_spz extension.
*/
bool decodeSpz = true;
/** /**
* @brief Whether the quantized mesh data are dequantized and converted to * @brief Whether the quantized mesh data are dequantized and converted to
* floating-point values when loading, according to the KHR_mesh_quantization * floating-point values when loading, according to the KHR_mesh_quantization

View File

@ -3,6 +3,7 @@
#include "decodeDataUrls.h" #include "decodeDataUrls.h"
#include "decodeDraco.h" #include "decodeDraco.h"
#include "decodeMeshOpt.h" #include "decodeMeshOpt.h"
#include "decodeSpz.h"
#include "dequantizeMeshData.h" #include "dequantizeMeshData.h"
#include "registerReaderExtensions.h" #include "registerReaderExtensions.h"
@ -245,7 +246,7 @@ GltfReaderResult readBinaryGltf(
buffer.cesium.data = std::vector<std::byte>( buffer.cesium.data = std::vector<std::byte>(
binaryChunk.begin(), binaryChunk.begin(),
binaryChunk.begin() + buffer.byteLength); binaryChunk.begin() + (ptrdiff_t)buffer.byteLength);
} }
return result; return result;
@ -359,6 +360,10 @@ void postprocess(GltfReaderResult& readGltf, const GltfReaderOptions& options) {
decodeMeshOpt(model, readGltf); decodeMeshOpt(model, readGltf);
} }
if (options.decodeSpz && hasSpzExtension(readGltf)) {
decodeSpz(readGltf);
}
if (options.dequantizeMeshData && if (options.dequantizeMeshData &&
std::find( std::find(
model.extensionsUsed.begin(), model.extensionsUsed.begin(),

View File

@ -5,7 +5,6 @@
#include <CesiumUtility/Tracing.h> #include <CesiumUtility/Tracing.h>
#include <ktx.h> #include <ktx.h>
#include <turbojpeg.h>
#include <webp/decode.h> #include <webp/decode.h>
#include <algorithm> #include <algorithm>
@ -28,6 +27,10 @@
#define STB_IMAGE_RESIZE_STATIC #define STB_IMAGE_RESIZE_STATIC
#include <stb_image_resize2.h> #include <stb_image_resize2.h>
#ifndef CESIUM_DISABLE_LIBJPEG_TURBO
#include <turbojpeg.h>
#endif
namespace CesiumGltfReader { namespace CesiumGltfReader {
using namespace CesiumGltf; using namespace CesiumGltf;
@ -287,6 +290,7 @@ ImageReaderResult ImageDecoder::readImage(
} }
{ {
#ifndef CESIUM_DISABLE_LIBJPEG_TURBO
tjhandle tjInstance = tjInitDecompress(); tjhandle tjInstance = tjInitDecompress();
int inSubsamp, inColorspace; int inSubsamp, inColorspace;
if (!tjDecompressHeader3( if (!tjDecompressHeader3(
@ -316,7 +320,9 @@ ImageReaderResult ImageDecoder::readImage(
result.errors.emplace_back("Unable to decode JPEG"); result.errors.emplace_back("Unable to decode JPEG");
result.pImage = nullptr; result.pImage = nullptr;
} }
} else { } else
#endif // !CESIUM_DISABLE_LIBJPEG_TURBO
{
CESIUM_TRACE("Decode PNG"); CESIUM_TRACE("Decode PNG");
image.bytesPerChannel = 1; image.bytesPerChannel = 1;
image.channels = 4; image.channels = 4;
@ -349,7 +355,9 @@ ImageReaderResult ImageDecoder::readImage(
result.errors.emplace_back(stbi_failure_reason()); result.errors.emplace_back(stbi_failure_reason());
} }
} }
#ifndef CESIUM_DISABLE_LIBJPEG_TURBO
tjDestroy(tjInstance); tjDestroy(tjInstance);
#endif
} }
return result; return result;
} }

View File

@ -76,7 +76,7 @@ std::unique_ptr<draco::Mesh> decodeBufferViewToDracoMesh(
const std::span<const std::byte> data( const std::span<const std::byte> data(
buffer.cesium.data.data() + bufferView.byteOffset, buffer.cesium.data.data() + bufferView.byteOffset,
static_cast<uint64_t>(bufferView.byteLength)); static_cast<size_t>(bufferView.byteLength));
draco::DecoderBuffer decodeBuffer; draco::DecoderBuffer decodeBuffer;
decodeBuffer.Init(reinterpret_cast<const char*>(data.data()), data.size()); decodeBuffer.Init(reinterpret_cast<const char*>(data.data()), data.size());

View File

@ -0,0 +1,483 @@
#include "decodeSpz.h"
#include <CesiumGltf/Accessor.h>
#include <CesiumGltf/Buffer.h>
#include <CesiumGltf/BufferView.h>
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h>
#include <CesiumGltf/Mesh.h>
#include <CesiumGltf/MeshPrimitive.h>
#include <CesiumGltf/Model.h>
#include <CesiumGltfReader/GltfReader.h>
#include <CesiumUtility/Assert.h>
#include <CesiumUtility/JsonValue.h>
#include <CesiumUtility/Tracing.h>
#include <fmt/format.h>
#include <glm/fwd.hpp>
#include <load-spz.h>
#include <splat-types.h>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace CesiumGltfReader {
namespace {
const float SH_C0 = 0.282095f;
const std::string ALTERNATE_EXT_NAME1 = "KHR_spz_gaussian_splats_compression";
const std::string ALTERNATE_EXT_NAME2 =
"KHR_gaussian_splatting_compression_spz";
std::unique_ptr<spz::GaussianCloud> decodeBufferViewToGaussianCloud(
GltfReaderResult& readGltf,
CesiumGltf::MeshPrimitive& /* primitive */,
const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& spz) {
CESIUM_TRACE("CesiumGltfReader::decodeBufferViewToGaussianCloud");
CESIUM_ASSERT(readGltf.model);
CesiumGltf::Model& model = readGltf.model.value();
CesiumGltf::BufferView* pBufferView =
CesiumGltf::Model::getSafe(&model.bufferViews, spz.bufferView);
if (!pBufferView) {
readGltf.warnings.emplace_back("SPZ bufferView index is invalid.");
return nullptr;
}
const CesiumGltf::BufferView& bufferView = *pBufferView;
CesiumGltf::Buffer* pBuffer =
CesiumGltf::Model::getSafe(&model.buffers, bufferView.buffer);
if (!pBuffer) {
readGltf.warnings.emplace_back(
"SPZ bufferView has an invalid buffer index.");
return nullptr;
}
CesiumGltf::Buffer& buffer = *pBuffer;
if (bufferView.byteOffset < 0 || bufferView.byteLength < 0 ||
bufferView.byteOffset + bufferView.byteLength >
static_cast<int64_t>(buffer.cesium.data.size())) {
readGltf.warnings.emplace_back("SPZ bufferView extends beyond its buffer.");
return nullptr;
}
spz::GaussianCloud gaussians = spz::loadSpz(
reinterpret_cast<uint8_t*>(
buffer.cesium.data.data() + bufferView.byteOffset),
static_cast<int32_t>(bufferView.byteLength),
spz::UnpackOptions{spz::CoordinateSystem::UNSPECIFIED});
return std::make_unique<spz::GaussianCloud>(std::move(gaussians));
}
CesiumGltf::Accessor* findAccessor(
GltfReaderResult& readGltf,
CesiumGltf::MeshPrimitive& primitive,
const std::string& attributeName) {
const std::unordered_map<std::string, int32_t>::iterator attributeIt =
primitive.attributes.find(attributeName);
if (attributeIt == primitive.attributes.end()) {
readGltf.warnings.emplace_back(
"Failed to find " + attributeName +
" attribute on KHR_gaussian_splatting_compression_spz_2 primitive");
return nullptr;
}
CESIUM_ASSERT(readGltf.model);
CesiumGltf::Accessor* pAccessor = CesiumGltf::Model::getSafe(
&readGltf.model->accessors,
attributeIt->second);
if (!pAccessor) {
readGltf.warnings.emplace_back(
"Failed to find accessor at index " +
std::to_string(attributeIt->second));
return nullptr;
}
return pAccessor;
}
void copyShCoeff(
GltfReaderResult& readGltf,
CesiumGltf::MeshPrimitive& primitive,
CesiumGltf::Buffer& buffer,
spz::GaussianCloud* pGaussian,
int degree,
int coeffIndex) {
size_t base = 0;
size_t stride = 0;
if (degree == 1) {
stride = 9;
} else if (degree == 2) {
stride = 24;
base = 9;
} else if (degree == 3) {
stride = 45;
base = 24;
}
CesiumGltf::Accessor* pAccessor = findAccessor(
readGltf,
primitive,
fmt::format(
"KHR_gaussian_splatting:SH_DEGREE_{}_COEF_{}",
degree,
coeffIndex));
if (!pAccessor) {
return;
}
CESIUM_ASSERT(readGltf.model);
// Some gaussian splats seem to set this value as VEC4, even though the spec
// requires VEC3.
pAccessor->type = CesiumGltf::Accessor::Type::VEC3;
pAccessor->bufferView =
static_cast<int32_t>(readGltf.model->bufferViews.size());
CesiumGltf::BufferView& bufferView =
readGltf.model->bufferViews.emplace_back();
bufferView.buffer = static_cast<int32_t>(readGltf.model->buffers.size() - 1);
bufferView.byteLength = static_cast<int64_t>(
sizeof(float) * static_cast<size_t>(pGaussian->numPoints) * 3);
size_t start = buffer.cesium.data.size();
bufferView.byteOffset = static_cast<int64_t>(start);
buffer.cesium.data.resize(start + static_cast<size_t>(bufferView.byteLength));
for (size_t i = 0; i < static_cast<size_t>(pGaussian->numPoints); i++) {
const size_t idx = i * stride + base + static_cast<size_t>(coeffIndex) * 3;
std::memcpy(
buffer.cesium.data.data() + start,
pGaussian->sh.data() + idx,
sizeof(float) * 3);
start += sizeof(float) * 3;
}
}
void decodePrimitive(
GltfReaderResult& readGltf,
CesiumGltf::MeshPrimitive& primitive,
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& spz) {
CESIUM_TRACE("CesiumGltfReader::decodePrimitive");
CESIUM_ASSERT(readGltf.model);
// TODO: handle different accessor component types
std::unique_ptr<spz::GaussianCloud> pGaussian =
decodeBufferViewToGaussianCloud(readGltf, primitive, spz);
if (!pGaussian) {
return;
}
const size_t bufferLength =
sizeof(float) * (pGaussian->positions.size() + pGaussian->scales.size() +
pGaussian->scales.size() + pGaussian->rotations.size() +
pGaussian->alphas.size() + pGaussian->colors.size() +
pGaussian->sh.size());
CesiumGltf::Buffer& buffer = readGltf.model->buffers.emplace_back();
buffer.byteLength = static_cast<int64_t>(bufferLength);
buffer.cesium.data.reserve(bufferLength);
// Position and rotation can be copied verbatim
CesiumGltf::Accessor* pPosAccessor =
findAccessor(readGltf, primitive, "POSITION");
if (pPosAccessor) {
pPosAccessor->type = CesiumGltf::Accessor::Type::VEC3;
pPosAccessor->bufferView =
static_cast<int32_t>(readGltf.model->bufferViews.size());
CesiumGltf::BufferView& bufferView =
readGltf.model->bufferViews.emplace_back();
bufferView.buffer =
static_cast<int32_t>(readGltf.model->buffers.size() - 1);
bufferView.byteLength =
static_cast<int64_t>(sizeof(float) * pGaussian->positions.size());
size_t start = buffer.cesium.data.size();
bufferView.byteOffset = static_cast<int64_t>(start);
buffer.cesium.data.resize(
start + static_cast<size_t>(bufferView.byteLength));
memcpy(
buffer.cesium.data.data() + start,
pGaussian->positions.data(),
sizeof(float) * pGaussian->positions.size());
}
CesiumGltf::Accessor* pRotAccessor =
findAccessor(readGltf, primitive, "KHR_gaussian_splatting:ROTATION");
if (pRotAccessor) {
pRotAccessor->type = CesiumGltf::Accessor::Type::VEC4;
pRotAccessor->bufferView =
static_cast<int32_t>(readGltf.model->bufferViews.size());
CesiumGltf::BufferView& bufferView =
readGltf.model->bufferViews.emplace_back();
bufferView.buffer =
static_cast<int32_t>(readGltf.model->buffers.size() - 1);
bufferView.byteLength =
static_cast<int64_t>(sizeof(float) * pGaussian->rotations.size());
size_t start = buffer.cesium.data.size();
bufferView.byteOffset = static_cast<int64_t>(start);
buffer.cesium.data.resize(
start + static_cast<size_t>(bufferView.byteLength));
memcpy(
buffer.cesium.data.data() + start,
pGaussian->rotations.data(),
sizeof(float) * pGaussian->rotations.size());
}
// Color needs to be interleaved with alphas and have its values converted
CesiumGltf::Accessor* pColorAccessor =
findAccessor(readGltf, primitive, "COLOR_0");
if (pColorAccessor) {
pColorAccessor->type = CesiumGltf::Accessor::Type::VEC4;
pColorAccessor->componentType = CesiumGltf::Accessor::ComponentType::FLOAT;
pColorAccessor->bufferView =
static_cast<int32_t>(readGltf.model->bufferViews.size());
CesiumGltf::BufferView& bufferView =
readGltf.model->bufferViews.emplace_back();
bufferView.buffer =
static_cast<int32_t>(readGltf.model->buffers.size() - 1);
bufferView.byteLength = static_cast<int64_t>(
(pGaussian->colors.size() + pGaussian->alphas.size()) * sizeof(float));
size_t start = buffer.cesium.data.size();
buffer.cesium.data.resize(
start + static_cast<size_t>(bufferView.byteLength));
bufferView.byteOffset = static_cast<int64_t>(start);
for (size_t i = 0; i < pGaussian->alphas.size(); i++) {
glm::fvec4 color(
0.5 + pGaussian->colors[i * 3] * SH_C0,
0.5 + pGaussian->colors[i * 3 + 1] * SH_C0,
0.5 + pGaussian->colors[i * 3 + 2] * SH_C0,
1.0 / (1.0 + exp(-pGaussian->alphas[i])));
memcpy(
buffer.cesium.data.data() + start + i * sizeof(glm::fvec4),
&color,
sizeof(glm::fvec4));
}
}
// Scale needs to be converted
CesiumGltf::Accessor* pScaleAccessor =
findAccessor(readGltf, primitive, "KHR_gaussian_splatting:SCALE");
if (pScaleAccessor) {
pScaleAccessor->type = CesiumGltf::Accessor::Type::VEC3;
pScaleAccessor->bufferView =
static_cast<int32_t>(readGltf.model->bufferViews.size());
CesiumGltf::BufferView& bufferView =
readGltf.model->bufferViews.emplace_back();
bufferView.buffer =
static_cast<int32_t>(readGltf.model->buffers.size() - 1);
bufferView.byteLength =
static_cast<int64_t>(sizeof(float) * pGaussian->scales.size());
size_t start = buffer.cesium.data.size();
buffer.cesium.data.resize(
start + static_cast<size_t>(bufferView.byteLength));
bufferView.byteOffset = static_cast<int64_t>(start);
for (size_t i = 0; i < pGaussian->scales.size(); i++) {
float scale = exp(pGaussian->scales[i]);
memcpy(
buffer.cesium.data.data() + start + i * sizeof(float),
&scale,
sizeof(float));
}
}
if (pGaussian->shDegree > 0) {
for (int i = 0; i < 3; i++) {
copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 1, i);
}
}
if (pGaussian->shDegree > 1) {
for (int i = 0; i < 5; i++) {
copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 2, i);
}
}
if (pGaussian->shDegree > 2) {
for (int i = 0; i < 7; i++) {
copyShCoeff(readGltf, primitive, buffer, pGaussian.get(), 3, i);
}
}
}
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2*
addExtensionFromJsonValue(
const std::string& extName,
CesiumGltfReader::GltfReaderResult& readGltf,
CesiumGltf::ExtensionKhrGaussianSplatting& splatting,
CesiumUtility::JsonValue* pKhrJson) {
if (!pKhrJson->isObject()) {
readGltf.errors.push_back(fmt::format("Invalid {} extension", extName));
return nullptr;
}
const CesiumUtility::JsonValue::Object::const_iterator it =
pKhrJson->getObject().find("bufferView");
if (it == pKhrJson->getObject().end()) {
readGltf.errors.push_back(
fmt::format("No `bufferView` property found on {} extension", extName));
return nullptr;
}
if (!it->second.isInt64() && !it->second.isUint64()) {
readGltf.errors.push_back(fmt::format(
"`bufferView` property on {} extension must be an integer value",
extName));
return nullptr;
}
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& ext =
splatting.addExtension<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>();
ext.bufferView = it->second.isInt64()
? static_cast<int32_t>(it->second.getInt64())
: static_cast<int32_t>(it->second.getUint64());
return &ext;
}
// Maps attribute names from older versions of the extension to the names from
// the current version of the extension.
void fixAttributeNames(CesiumGltf::MeshPrimitive& primitive) {
std::vector<std::string> attributesToConvert;
attributesToConvert.reserve(primitive.attributes.size());
for (std::pair<const std::string, int32_t>& attribute :
primitive.attributes) {
if (attribute.first == "_SCALE" || attribute.first == "_ROTATION" ||
attribute.first.starts_with("_SH_DEGREE_")) {
attributesToConvert.push_back(attribute.first);
}
}
for (const std::string& oldName : attributesToConvert) {
const int32_t accessorIndex = primitive.attributes[oldName];
primitive.attributes.erase(oldName);
primitive.attributes.emplace(
"KHR_gaussian_splatting:" + oldName.substr(1),
accessorIndex);
}
}
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2*
getAndMaybeConvertSpzExtension(
CesiumGltfReader::GltfReaderResult& readGltf,
CesiumGltf::MeshPrimitive& primitive,
CesiumGltf::ExtensionKhrGaussianSplatting& splatting) {
// Check for the real thing.
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pSpz =
splatting.getExtension<
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2>();
if (pSpz) {
return pSpz;
}
// Check for the old versions.
CesiumUtility::JsonValue* pKhrSpz =
primitive.getGenericExtension(ALTERNATE_EXT_NAME1);
if (pKhrSpz != nullptr) {
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pResult =
addExtensionFromJsonValue(
ALTERNATE_EXT_NAME1,
readGltf,
splatting,
pKhrSpz);
primitive.extensions.erase(ALTERNATE_EXT_NAME1);
return pResult;
}
CesiumUtility::JsonValue* pSpzNoVersion =
splatting.getGenericExtension(ALTERNATE_EXT_NAME2);
if (pSpzNoVersion != nullptr) {
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pResult =
addExtensionFromJsonValue(
ALTERNATE_EXT_NAME2,
readGltf,
splatting,
pSpzNoVersion);
primitive.extensions.erase(ALTERNATE_EXT_NAME2);
return pResult;
}
return nullptr;
}
} // namespace
void decodeSpz(CesiumGltfReader::GltfReaderResult& readGltf) {
CESIUM_TRACE("CesiumGltfReader::decodeSpz");
if (!readGltf.model) {
return;
}
CesiumGltf::Model& model = readGltf.model.value();
for (CesiumGltf::Mesh& mesh : model.meshes) {
for (CesiumGltf::MeshPrimitive& primitive : mesh.primitives) {
// KHR_spz_gaussian_splats_compression has no KHR_gaussian_splatting
// extension attached Just throw one on there to make this easier
if (primitive.extensions.contains(ALTERNATE_EXT_NAME1)) {
primitive.addExtension<CesiumGltf::ExtensionKhrGaussianSplatting>();
}
CesiumGltf::ExtensionKhrGaussianSplatting* pSplat =
primitive.getExtension<CesiumGltf::ExtensionKhrGaussianSplatting>();
if (!pSplat) {
continue;
}
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2* pSpz =
getAndMaybeConvertSpzExtension(readGltf, primitive, *pSplat);
if (!pSpz) {
continue;
}
fixAttributeNames(primitive);
decodePrimitive(readGltf, primitive, *pSpz);
// Remove the SPZ extension as it no longer applies.
pSplat->extensions.erase(
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::
ExtensionName);
}
}
model.removeExtensionRequired(
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::ExtensionName);
model.removeExtensionRequired(ALTERNATE_EXT_NAME1);
model.removeExtensionRequired(ALTERNATE_EXT_NAME2);
}
bool hasSpzExtension(GltfReaderResult& readGltf) {
CESIUM_ASSERT(readGltf.model);
if (readGltf.model->isExtensionUsed(
CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2::
ExtensionName)) {
return true;
}
if (readGltf.model->isExtensionUsed(ALTERNATE_EXT_NAME1)) {
return true;
}
if (readGltf.model->isExtensionUsed(ALTERNATE_EXT_NAME2)) {
return true;
}
return false;
}
} // namespace CesiumGltfReader

View File

@ -0,0 +1,8 @@
#pragma once
namespace CesiumGltfReader {
struct GltfReaderResult;
void decodeSpz(GltfReaderResult& readGltf);
bool hasSpzExtension(GltfReaderResult& readGltf);
} // namespace CesiumGltfReader

View File

@ -813,3 +813,54 @@ TEST_CASE("GltfReader::postprocessGltf") {
CHECK(s == "test"); CHECK(s == "test");
} }
} }
TEST_CASE("SPZ decoding works properly") {
SUBCASE("Basic model with one vertex no spherical harmonics") {
GltfReader reader;
GltfReaderResult result = reader.readGltf(readFile(
std::filesystem::path(CesiumGltfReader_TEST_DATA_DIR) / "SpzSplat" /
"basic.glb"));
REQUIRE(result.model);
const Model& model = result.model.value();
REQUIRE(model.meshes.size() == 1);
REQUIRE(model.meshes[0].primitives.size() == 1);
const std::unordered_map<std::string, int32_t>& attributes =
model.meshes[0].primitives[0].attributes;
CHECK(attributes.size() == 4);
REQUIRE(attributes.contains("POSITION"));
AccessorView<glm::vec3> positionView(model, attributes.at("POSITION"));
REQUIRE(positionView.status() == AccessorViewStatus::Valid);
REQUIRE(positionView.size() == 1);
CHECK(positionView[0] == glm::vec3(1.0, 2.0, 3.0));
REQUIRE(attributes.contains("COLOR_0"));
AccessorView<glm::vec4> colorView(model, attributes.at("COLOR_0"));
REQUIRE(colorView.status() == AccessorViewStatus::Valid);
REQUIRE(colorView.size() == 1);
CHECK(
colorView[0] ==
glm::vec4(0.570062876, 0.643813193, 0.710188448, 0.501960814));
REQUIRE(attributes.contains("KHR_gaussian_splatting:ROTATION"));
AccessorView<glm::vec4> rotationView(
model,
attributes.at("KHR_gaussian_splatting:ROTATION"));
REQUIRE(rotationView.status() == AccessorViewStatus::Valid);
REQUIRE(rotationView.size() == 1);
CHECK(
rotationView[0] ==
glm::vec4(0.003921628, -0.709803939, 0.709804058, 0.0));
REQUIRE(attributes.contains("KHR_gaussian_splatting:SCALE"));
AccessorView<glm::vec3> scaleView(
model,
attributes.at("KHR_gaussian_splatting:SCALE"));
REQUIRE(scaleView.status() == AccessorViewStatus::Valid);
REQUIRE(scaleView.size() == 1);
CHECK(scaleView[0] == glm::vec3(20.085537, 7.38905621, 2.71828175));
}
}

Binary file not shown.

View File

@ -38,6 +38,8 @@
#include <CesiumGltf/ExtensionExtPrimitiveVoxels.h> #include <CesiumGltf/ExtensionExtPrimitiveVoxels.h>
#include <CesiumGltf/ExtensionExtStructuralMetadata.h> #include <CesiumGltf/ExtensionExtStructuralMetadata.h>
#include <CesiumGltf/ExtensionKhrDracoMeshCompression.h> #include <CesiumGltf/ExtensionKhrDracoMeshCompression.h>
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h>
#include <CesiumGltf/ExtensionKhrImplicitShapes.h> #include <CesiumGltf/ExtensionKhrImplicitShapes.h>
#include <CesiumGltf/ExtensionKhrMaterialsUnlit.h> #include <CesiumGltf/ExtensionKhrMaterialsUnlit.h>
#include <CesiumGltf/ExtensionKhrTextureBasisu.h> #include <CesiumGltf/ExtensionKhrTextureBasisu.h>
@ -218,6 +220,16 @@ void writeJson(
CesiumJsonWriter::JsonWriter& jsonWriter, CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context); const CesiumJsonWriter::ExtensionWriterContext& context);
void writeJson(
const CesiumGltf::ExtensionKhrGaussianSplatting& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context);
void writeJson(
const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context);
void writeJson( void writeJson(
const CesiumGltf::Padding& obj, const CesiumGltf::Padding& obj,
CesiumJsonWriter::JsonWriter& jsonWriter, CesiumJsonWriter::JsonWriter& jsonWriter,
@ -1174,6 +1186,56 @@ void writeJson(
jsonWriter.EndObject(); jsonWriter.EndObject();
} }
void writeJson(
const CesiumGltf::ExtensionKhrGaussianSplatting& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context) {
jsonWriter.StartObject();
if (obj.kernel != "ellipse") {
jsonWriter.Key("kernel");
writeJson(obj.kernel, jsonWriter, context);
}
if (obj.projection !=
CesiumGltf::ExtensionKhrGaussianSplatting::Projection::perspective) {
jsonWriter.Key("projection");
writeJson(obj.projection, jsonWriter, context);
}
if (obj.sortingMethod != CesiumGltf::ExtensionKhrGaussianSplatting::
SortingMethod::cameraDistance) {
jsonWriter.Key("sortingMethod");
writeJson(obj.sortingMethod, jsonWriter, context);
}
if (obj.colorSpace !=
CesiumGltf::ExtensionKhrGaussianSplatting::ColorSpace::BT_709) {
jsonWriter.Key("colorSpace");
writeJson(obj.colorSpace, jsonWriter, context);
}
writeExtensibleObject(obj, jsonWriter, context);
jsonWriter.EndObject();
}
void writeJson(
const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context) {
jsonWriter.StartObject();
if (obj.bufferView > -1) {
jsonWriter.Key("bufferView");
writeJson(obj.bufferView, jsonWriter, context);
}
writeExtensibleObject(obj, jsonWriter, context);
jsonWriter.EndObject();
}
void writeJson( void writeJson(
const CesiumGltf::Padding& obj, const CesiumGltf::Padding& obj,
CesiumJsonWriter::JsonWriter& jsonWriter, CesiumJsonWriter::JsonWriter& jsonWriter,
@ -2892,6 +2954,20 @@ void ExtensionExtPrimitiveVoxelsJsonWriter::write(
writeJson(obj, jsonWriter, context); writeJson(obj, jsonWriter, context);
} }
void ExtensionKhrGaussianSplattingJsonWriter::write(
const CesiumGltf::ExtensionKhrGaussianSplatting& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context) {
writeJson(obj, jsonWriter, context);
}
void ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter::write(
const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context) {
writeJson(obj, jsonWriter, context);
}
void PaddingJsonWriter::write( void PaddingJsonWriter::write(
const CesiumGltf::Padding& obj, const CesiumGltf::Padding& obj,
CesiumJsonWriter::JsonWriter& jsonWriter, CesiumJsonWriter::JsonWriter& jsonWriter,

View File

@ -34,6 +34,8 @@ struct ExtensionKhrImplicitShapes;
struct ExtensionExtImplicitEllipsoidRegion; struct ExtensionExtImplicitEllipsoidRegion;
struct ExtensionExtImplicitCylinderRegion; struct ExtensionExtImplicitCylinderRegion;
struct ExtensionExtPrimitiveVoxels; struct ExtensionExtPrimitiveVoxels;
struct ExtensionKhrGaussianSplatting;
struct ExtensionKhrGaussianSplattingCompressionSpz2;
struct Padding; struct Padding;
struct Shape; struct Shape;
struct Cylinder; struct Cylinder;
@ -402,6 +404,33 @@ struct ExtensionExtPrimitiveVoxelsJsonWriter {
const CesiumJsonWriter::ExtensionWriterContext& context); const CesiumJsonWriter::ExtensionWriterContext& context);
}; };
struct ExtensionKhrGaussianSplattingJsonWriter {
using ValueType = CesiumGltf::ExtensionKhrGaussianSplatting;
/** @brief The official name of the extension. This should be the same as its
* key in the `extensions` object. */
static constexpr const char* ExtensionName = "KHR_gaussian_splatting";
static void write(
const CesiumGltf::ExtensionKhrGaussianSplatting& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context);
};
struct ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter {
using ValueType = CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2;
/** @brief The official name of the extension. This should be the same as its
* key in the `extensions` object. */
static constexpr const char* ExtensionName =
"KHR_gaussian_splatting_compression_spz_2";
static void write(
const CesiumGltf::ExtensionKhrGaussianSplattingCompressionSpz2& obj,
CesiumJsonWriter::JsonWriter& jsonWriter,
const CesiumJsonWriter::ExtensionWriterContext& context);
};
struct PaddingJsonWriter { struct PaddingJsonWriter {
using ValueType = CesiumGltf::Padding; using ValueType = CesiumGltf::Padding;

View File

@ -7,6 +7,7 @@
#include <CesiumGltf/Buffer.h> #include <CesiumGltf/Buffer.h>
#include <CesiumGltf/BufferView.h> #include <CesiumGltf/BufferView.h>
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltf/FeatureIdTexture.h> #include <CesiumGltf/FeatureIdTexture.h>
#include <CesiumGltf/Material.h> #include <CesiumGltf/Material.h>
#include <CesiumGltf/MaterialNormalTextureInfo.h> #include <CesiumGltf/MaterialNormalTextureInfo.h>
@ -34,6 +35,8 @@
#include <CesiumGltf/ExtensionExtPrimitiveVoxels.h> #include <CesiumGltf/ExtensionExtPrimitiveVoxels.h>
#include <CesiumGltf/ExtensionExtStructuralMetadata.h> #include <CesiumGltf/ExtensionExtStructuralMetadata.h>
#include <CesiumGltf/ExtensionKhrDracoMeshCompression.h> #include <CesiumGltf/ExtensionKhrDracoMeshCompression.h>
#include <CesiumGltf/ExtensionKhrGaussianSplatting.h>
#include <CesiumGltf/ExtensionKhrGaussianSplattingCompressionSpz2.h>
#include <CesiumGltf/ExtensionKhrImplicitShapes.h> #include <CesiumGltf/ExtensionKhrImplicitShapes.h>
#include <CesiumGltf/ExtensionKhrMaterialsUnlit.h> #include <CesiumGltf/ExtensionKhrMaterialsUnlit.h>
#include <CesiumGltf/ExtensionKhrTextureBasisu.h> #include <CesiumGltf/ExtensionKhrTextureBasisu.h>
@ -86,6 +89,9 @@ void registerWriterExtensions(
context.registerExtension< context.registerExtension<
CesiumGltf::MeshPrimitive, CesiumGltf::MeshPrimitive,
ExtensionExtPrimitiveVoxelsJsonWriter>(); ExtensionExtPrimitiveVoxelsJsonWriter>();
context.registerExtension<
CesiumGltf::MeshPrimitive,
ExtensionKhrGaussianSplattingJsonWriter>();
context.registerExtension< context.registerExtension<
CesiumGltf::Node, CesiumGltf::Node,
ExtensionExtInstanceFeaturesJsonWriter>(); ExtensionExtInstanceFeaturesJsonWriter>();
@ -136,5 +142,8 @@ void registerWriterExtensions(
context.registerExtension< context.registerExtension<
CesiumGltf::Shape, CesiumGltf::Shape,
ExtensionExtImplicitCylinderRegionJsonWriter>(); ExtensionExtImplicitCylinderRegionJsonWriter>();
context.registerExtension<
CesiumGltf::ExtensionKhrGaussianSplatting,
ExtensionKhrGaussianSplattingCompressionSpz2JsonWriter>();
} }
} // namespace CesiumGltfWriter } // namespace CesiumGltfWriter

View File

@ -613,6 +613,7 @@ TEST_CASE("Writes glb with binaryChunkByteAlignment of 8") {
REQUIRE(glbBytesExtraPadding.size() == 88); REQUIRE(glbBytesExtraPadding.size() == 88);
} }
#ifndef __EMSCRIPTEN__
TEST_CASE("Reports an error if asked to write a GLB larger than 4GB") { TEST_CASE("Reports an error if asked to write a GLB larger than 4GB") {
CesiumGltf::Model model; CesiumGltf::Model model;
model.asset.version = "2.0"; model.asset.version = "2.0";
@ -628,3 +629,4 @@ TEST_CASE("Reports an error if asked to write a GLB larger than 4GB") {
REQUIRE(!result.errors.empty()); REQUIRE(!result.errors.empty());
CHECK(result.gltfBytes.empty()); CHECK(result.gltfBytes.empty());
} }
#endif // __EMSCRIPTEN__

View File

@ -23,7 +23,7 @@ using namespace CesiumNativeTests;
using namespace CesiumUtility; using namespace CesiumUtility;
namespace { namespace {
const std::string& REDIRECT_PATH = "/dummy/auth/path"; const std::string REDIRECT_PATH = "/dummy/auth/path";
const int REDIRECT_PORT = 49013; const int REDIRECT_PORT = 49013;
std::shared_ptr<Connection> std::shared_ptr<Connection>

View File

@ -38,6 +38,14 @@ cesium_glob_files(test_headers
) )
set(test_include_directories ${CMAKE_CURRENT_LIST_DIR}/include) set(test_include_directories ${CMAKE_CURRENT_LIST_DIR}/include)
if(CESIUM_TARGET_WASM)
target_link_options(
cesium-native-tests
PRIVATE
"-sEXIT_RUNTIME=1"
)
endif()
# Iterate through all targets, extracting their private sources and test sources / test headers # Iterate through all targets, extracting their private sources and test sources / test headers
foreach(target ${cesium_native_targets}) foreach(target ${cesium_native_targets})
get_target_property(target_test_sources ${target} TEST_SOURCES) get_target_property(target_test_sources ${target} TEST_SOURCES)
@ -75,6 +83,41 @@ foreach(target ${cesium_native_targets})
endif() endif()
endforeach() endforeach()
if(CESIUM_TARGET_WASM)
file(GLOB directories_list LIST_DIRECTORIES true "${CMAKE_SOURCE_DIR}/Cesium*")
set(FILE_PACKAGER_ARGS "")
set(TEST_DATA_FILES "")
foreach(dir ${directories_list})
if(IS_DIRECTORY ${dir}/test/data)
list(APPEND FILE_PACKAGER_ARGS "--embed" "${dir}/test/data")
file(GLOB_RECURSE data_files "${dir}/test/data/*")
list(APPEND TEST_DATA_FILES ${data_files})
endif()
endforeach()
list(APPEND FILE_PACKAGER_ARGS "--embed" "${CMAKE_SOURCE_DIR}/data")
if(CESIUM_WASM64)
list(APPEND FILE_PACKAGER_ARGS "--wasm64")
endif()
set(CESIUM_NATIVE_TESTS_DATA_OBJ ${CMAKE_CURRENT_BINARY_DIR}/cesium-native-tests-data.o)
add_custom_command(
COMMENT "Generating test data object file"
OUTPUT ${CESIUM_NATIVE_TESTS_DATA_OBJ}
COMMAND ${EMSCRIPTEN_ROOT_PATH}/tools/file_packager none.data ${FILE_PACKAGER_ARGS} --obj-output=${CESIUM_NATIVE_TESTS_DATA_OBJ}
VERBATIM
DEPENDS ${TEST_DATA_FILES}
)
target_sources(
cesium-native-tests
PRIVATE
${CESIUM_NATIVE_TESTS_DATA_OBJ}
)
endif()
target_sources( target_sources(
cesium-native-tests cesium-native-tests
PRIVATE PRIVATE
@ -99,9 +142,12 @@ PRIVATE
target_compile_definitions(cesium-native-tests target_compile_definitions(cesium-native-tests
PRIVATE PRIVATE
CESIUM_NATIVE_DATA_DIR=\"${CMAKE_CURRENT_LIST_DIR}/../data\" CESIUM_NATIVE_DATA_DIR=\"${CMAKE_SOURCE_DIR}/data\"
) )
include(CTest) include(CTest)
include(doctest) include(doctest)
if(NOT CESIUM_TARGET_WASM)
# doctest_discover_tests can't handle the target being an html file, so we just avoid it on a wasm build
doctest_discover_tests(cesium-native-tests) doctest_discover_tests(cesium-native-tests)
endif()

View File

@ -43,10 +43,10 @@ std::unique_ptr<SimpleAssetResponse> readFileUri(const std::string& uri) {
if (!file) { if (!file) {
return response(404); return response(404);
} }
std::streamsize size = file.tellg(); std::streamoff size = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
result.resize(static_cast<size_t>(size)); result.resize(size_t(size));
file.read(reinterpret_cast<char*>(result.data()), size); file.read(reinterpret_cast<char*>(result.data()), std::streamsize(size));
if (!file) { if (!file) {
return response(503); return response(503);
} else { } else {

View File

@ -12,11 +12,11 @@ std::vector<std::byte> readFile(const std::filesystem::path& fileName) {
std::ifstream file(fileName, std::ios::binary | std::ios::ate); std::ifstream file(fileName, std::ios::binary | std::ios::ate);
REQUIRE(file); REQUIRE(file);
std::streamsize size = file.tellg(); std::streamoff size = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
std::vector<std::byte> buffer(static_cast<size_t>(size)); std::vector<std::byte> buffer{size_t(size)};
file.read(reinterpret_cast<char*>(buffer.data()), size); file.read(reinterpret_cast<char*>(buffer.data()), std::streamsize(size));
return buffer; return buffer;
} }

View File

@ -506,7 +506,7 @@ void addSkirts(
westEdgeIndices.begin(), westEdgeIndices.begin(),
westEdgeIndices.end(), westEdgeIndices.end(),
sortEdgeIndices.begin(), sortEdgeIndices.begin(),
sortEdgeIndices.begin() + westVertexCount, sortEdgeIndices.begin() + ptrdiff_t(westVertexCount),
[&uvsAndHeights](auto lhs, auto rhs) noexcept { [&uvsAndHeights](auto lhs, auto rhs) noexcept {
return uvsAndHeights[lhs].y < uvsAndHeights[rhs].y; return uvsAndHeights[lhs].y < uvsAndHeights[rhs].y;
}); });
@ -539,7 +539,7 @@ void addSkirts(
southEdgeIndices.begin(), southEdgeIndices.begin(),
southEdgeIndices.end(), southEdgeIndices.end(),
sortEdgeIndices.begin(), sortEdgeIndices.begin(),
sortEdgeIndices.begin() + southVertexCount, sortEdgeIndices.begin() + ptrdiff_t(southVertexCount),
[&uvsAndHeights](auto lhs, auto rhs) noexcept { [&uvsAndHeights](auto lhs, auto rhs) noexcept {
return uvsAndHeights[lhs].x > uvsAndHeights[rhs].x; return uvsAndHeights[lhs].x > uvsAndHeights[rhs].x;
}); });
@ -572,7 +572,7 @@ void addSkirts(
eastEdgeIndices.begin(), eastEdgeIndices.begin(),
eastEdgeIndices.end(), eastEdgeIndices.end(),
sortEdgeIndices.begin(), sortEdgeIndices.begin(),
sortEdgeIndices.begin() + eastVertexCount, sortEdgeIndices.begin() + ptrdiff_t(eastVertexCount),
[&uvsAndHeights](auto lhs, auto rhs) noexcept { [&uvsAndHeights](auto lhs, auto rhs) noexcept {
return uvsAndHeights[lhs].y > uvsAndHeights[rhs].y; return uvsAndHeights[lhs].y > uvsAndHeights[rhs].y;
}); });
@ -605,7 +605,7 @@ void addSkirts(
northEdgeIndices.begin(), northEdgeIndices.begin(),
northEdgeIndices.end(), northEdgeIndices.end(),
sortEdgeIndices.begin(), sortEdgeIndices.begin(),
sortEdgeIndices.begin() + northVertexCount, sortEdgeIndices.begin() + ptrdiff_t(northVertexCount),
[&uvsAndHeights](auto lhs, auto rhs) noexcept { [&uvsAndHeights](auto lhs, auto rhs) noexcept {
return uvsAndHeights[lhs].x < uvsAndHeights[rhs].x; return uvsAndHeights[lhs].x < uvsAndHeights[rhs].x;
}); });
@ -754,11 +754,10 @@ QuantizedMeshMetadataResult processMetadata(
// decode position without skirt, but preallocate position buffer to include // decode position without skirt, but preallocate position buffer to include
// skirt as well // skirt as well
std::vector<std::byte> outputPositionsBuffer( std::vector<std::byte> outputPositionsBuffer(
static_cast<uint64_t>((vertexCount + skirtVertexCount) * 3) * size_t((vertexCount + skirtVertexCount) * 3) * sizeof(float));
sizeof(float));
std::span<float> outputPositions( std::span<float> outputPositions(
reinterpret_cast<float*>(outputPositionsBuffer.data()), reinterpret_cast<float*>(outputPositionsBuffer.data()),
static_cast<size_t>((vertexCount + skirtVertexCount) * 3)); size_t((vertexCount + skirtVertexCount) * 3));
size_t positionOutputIndex = 0; size_t positionOutputIndex = 0;
const glm::dvec3 center( const glm::dvec3 center(

View File

@ -51,6 +51,7 @@ target_link_libraries(CesiumRasterOverlays
CesiumUtility CesiumUtility
CesiumVectorData CesiumVectorData
nonstd::expected-lite nonstd::expected-lite
spdlog::spdlog
PRIVATE PRIVATE
tinyxml2::tinyxml2 tinyxml2::tinyxml2
) )

View File

@ -591,7 +591,7 @@ RasterOverlayUtilities::upsampleGltfForRasterOverlays(
// We're assuming here that nothing references primitives by index, so we // We're assuming here that nothing references primitives by index, so we
// can remove them without any drama. // can remove them without any drama.
if (!keep) { if (!keep) {
mesh.primitives.erase(mesh.primitives.begin() + int64_t(i)); mesh.primitives.erase(mesh.primitives.begin() + ptrdiff_t(i));
--i; --i;
} }
containsPrimitives |= !mesh.primitives.empty(); containsPrimitives |= !mesh.primitives.empty();

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <cstdint>
namespace CesiumUtility { namespace CesiumUtility {
@ -17,7 +18,7 @@ struct Hash {
* @param second The second hash value. * @param second The second hash value.
* @return A new hash value which is a combination of the two. * @return A new hash value which is a combination of the two.
*/ */
static std::size_t combine(std::size_t first, std::size_t second); static size_t combine(size_t first, size_t second);
}; };
} // namespace CesiumUtility } // namespace CesiumUtility

View File

@ -1,6 +1,8 @@
#include <CesiumUtility/Hash.h> #include <CesiumUtility/Hash.h>
#include <climits>
#include <cstddef> #include <cstddef>
#include <cstdint>
namespace CesiumUtility { namespace CesiumUtility {
@ -59,8 +61,11 @@ namespace CesiumUtility {
// (https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html) // (https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html)
namespace { namespace {
inline std::size_t mix(std::size_t x) { template <size_t Bits> struct hash_mix_impl;
std::size_t const m = 0xe9846af9b1a615d;
template <> struct hash_mix_impl<64> {
inline static uint64_t fn(uint64_t x) {
uint64_t const m = 0xe9846af9b1a615d;
x ^= x >> 32; x ^= x >> 32;
x *= m; x *= m;
@ -70,12 +75,36 @@ inline std::size_t mix(std::size_t x) {
return x; return x;
} }
};
// This function is adapted from Boost v1.86.0, `hash_mix_impl<32>` function.
//
// hash_mix for 32 bit size_t
//
// We use the "best xmxmx" implementation from
// https://github.com/skeeto/hash-prospector/issues/19
template <> struct hash_mix_impl<32> {
inline static uint32_t fn(uint32_t x) {
uint32_t const m1 = 0x21f0aaad;
uint32_t const m2 = 0x735a2d97;
x ^= x >> 16;
x *= m1;
x ^= x >> 15;
x *= m2;
x ^= x >> 15;
return x;
}
};
} // namespace } // namespace
// This function is adapted from Boost's `hash_combine`. // This function is adapted from Boost's `hash_combine`.
std::size_t Hash::combine(std::size_t first, std::size_t second) { size_t Hash::combine(size_t first, size_t second) {
return mix(first + 0x9e3779b9 + second); // This will truncate bits on 32-bit builds.
return hash_mix_impl<sizeof(size_t) * CHAR_BIT>::fn(
first + size_t(0x9e3779b9) + second);
} }
} // namespace CesiumUtility } // namespace CesiumUtility

View File

@ -44,7 +44,7 @@ cesium_target_include_directories(
${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/src
) )
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS") if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
set(CESIUM_VECTOR_DATA_ASMJIT_DEPENDENCY asmjit::asmjit) set(CESIUM_VECTOR_DATA_ASMJIT_DEPENDENCY asmjit::asmjit)
endif() endif()

View File

@ -94,7 +94,7 @@ VectorRasterizer::VectorRasterizer(
imageHeight, imageHeight,
BL_FORMAT_PRGB32, BL_FORMAT_PRGB32,
reinterpret_cast<void*>(pData), reinterpret_cast<void*>(pData),
(int64_t)imageWidth * (int64_t)this->_imageAsset->channels); intptr_t(imageWidth) * intptr_t(this->_imageAsset->channels));
this->_context.begin(this->_image); this->_context.begin(this->_image);
// Initialize the image as all transparent. // Initialize the image as all transparent.

View File

@ -3,3 +3,14 @@
# else() # else()
# add_compile_options(-Werror -Wall -Wextra -Wconversion -Wpedantic -Wshadow -Wsign-conversion) # add_compile_options(-Werror -Wall -Wextra -Wconversion -Wpedantic -Wshadow -Wsign-conversion)
# endif() # endif()
if(CESIUM_TARGET_WASM)
add_compile_options(-pthread -msimd128 -mnontrapping-fptoint -mbulk-memory -fwasm-exceptions -sSUPPORT_LONGJMP=wasm)
add_link_options(-pthread -sALLOW_MEMORY_GROWTH=1 -sPTHREAD_POOL_SIZE=4 -sMAXIMUM_MEMORY=4294967296 -sMIN_NODE_VERSION=200000 -sINITIAL_MEMORY=268435456 -sSTACK_SIZE=1048576 -fwasm-exceptions -mbulk-memory -mnontrapping-fptoint -msse4.2 -sWASM_BIGINT -sSUPPORT_LONGJMP=wasm -sFORCE_FILESYSTEM -sPROXY_TO_PTHREAD)
add_link_options($<$<CONFIG:Debug>:-gsource-map>)
if (CESIUM_WASM64)
add_compile_options(-sMEMORY64=1)
add_link_options(-sMEMORY64=1)
endif()
endif()

View File

@ -21,6 +21,7 @@ find_dependency(meshoptimizer CONFIG REQUIRED)
find_dependency(OpenSSL REQUIRED) find_dependency(OpenSSL REQUIRED)
find_dependency(s2 CONFIG REQUIRED) find_dependency(s2 CONFIG REQUIRED)
find_dependency(spdlog CONFIG REQUIRED) find_dependency(spdlog CONFIG REQUIRED)
find_dependency(spz CONFIG REQUIRED)
find_dependency(tinyxml2 CONFIG REQUIRED) find_dependency(tinyxml2 CONFIG REQUIRED)
find_dependency(unofficial-sqlite3 CONFIG REQUIRED) find_dependency(unofficial-sqlite3 CONFIG REQUIRED)
find_dependency(WebP CONFIG REQUIRED) find_dependency(WebP CONFIG REQUIRED)

View File

@ -1,4 +1,6 @@
if(ANDROID) if(CESIUM_TARGET_WASM)
set(DETECTED_VCPKG_TRIPLET "wasm32-emscripten")
elseif(ANDROID)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(DETECTED_VCPKG_TRIPLET "x64-android") set(DETECTED_VCPKG_TRIPLET "x64-android")
else() else()

View File

@ -161,7 +161,7 @@ macro(EZVCPKG_BOOTSTRAP)
endmacro() endmacro()
macro(EZVCPKG_BUILD) macro(EZVCPKG_BUILD)
set(INSTALL_COMMAND "${EZVCPKG_EXE}" --vcpkg-root "${EZVCPKG_DIR}" install --triplet ${VCPKG_TRIPLET}) set(INSTALL_COMMAND "${EZVCPKG_EXE}" --allow-unsupported --vcpkg-root "${EZVCPKG_DIR}" install --triplet ${VCPKG_TRIPLET})
if (DEFINED VCPKG_OVERLAY_PORTS) if (DEFINED VCPKG_OVERLAY_PORTS)
if (CMAKE_HOST_WIN32) if (CMAKE_HOST_WIN32)

View File

@ -9,7 +9,7 @@ find_library(modp_b64_DEBUG_LIBRARIES
# vcpkg specific locations for debug libraries if they are not already found # vcpkg specific locations for debug libraries if they are not already found
set(modpbase64SavePrefixPath ${CMAKE_PREFIX_PATH}) set(modpbase64SavePrefixPath ${CMAKE_PREFIX_PATH})
list(FILTER CMAKE_PREFIX_PATH INCLUDE REGEX "/debug") list(FILTER CMAKE_PREFIX_PATH INCLUDE REGEX "/debug$")
find_library(modp_b64_DEBUG_LIBRARIES find_library(modp_b64_DEBUG_LIBRARIES
NAMES NAMES
modpbase64 modpbase64
@ -18,7 +18,7 @@ find_library(modp_b64_DEBUG_LIBRARIES
set(CMAKE_PREFIX_PATH ${modpbase64SavePrefixPath}) set(CMAKE_PREFIX_PATH ${modpbase64SavePrefixPath})
set(modpbase64SavePrefixPath ${CMAKE_PREFIX_PATH}) set(modpbase64SavePrefixPath ${CMAKE_PREFIX_PATH})
list(FILTER CMAKE_PREFIX_PATH EXCLUDE REGEX "/debug") list(FILTER CMAKE_PREFIX_PATH EXCLUDE REGEX "/debug$")
find_library(modp_b64_LIBRARIES NAMES modpbase64 libmodpbase64) find_library(modp_b64_LIBRARIES NAMES modpbase64 libmodpbase64)
set(CMAKE_PREFIX_PATH ${modpbase64SavePrefixPath}) set(CMAKE_PREFIX_PATH ${modpbase64SavePrefixPath})

77
extern/vcpkg/ports/ktx/portfile.cmake vendored Normal file
View File

@ -0,0 +1,77 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO kring/KTX-Software # KhronosGroup/KTX-Software
REF "v${VERSION}"
SHA512 fa20457fc0f0b117f4d6b406baa338091a85bcc46f60ca440dcd483388c67c550c81da3618d70d748e12850e32e0c1d82e9e8dc8522849074f40cc455723ac97
HEAD_REF master
)
file(REMOVE "${SOURCE_PATH}/other_include/zstd_errors.h")
file(REMOVE_RECURSE "${SOURCE_PATH}/external/basisu/zstd")
file(REMOVE_RECURSE "${SOURCE_PATH}/lib/basisu/zstd")
vcpkg_list(SET OPTIONS)
if(VCPKG_TARGET_IS_WINDOWS)
vcpkg_acquire_msys(MSYS_ROOT
PACKAGES
bash
DIRECT_PACKAGES
# Required for "getopt"
"https://mirror.msys2.org/msys/x86_64/util-linux-2.40.2-2-x86_64.pkg.tar.zst"
bf45b16cd470f8d82a9fe03842a09da2e6c60393c11f4be0bab354655072c7a461afc015b9c07f9f5c87a0e382cd867e4f079ede0d42f1589aa99ebbb3f76309
# Required for "dos2unix"
"https://mirror.msys2.org/msys/x86_64/dos2unix-7.5.3-1-x86_64.pkg.tar.zst"
ab5f88b10577b1d195d9b7b74c1a46d9e715c5fac21e8da3d590f345294190ed1ce7fde37d765f51ba01c2f6706c077123d4c69cfd0981729fdcb3d30f85bc6d
)
vcpkg_add_to_path("${MSYS_ROOT}/usr/bin")
vcpkg_list(APPEND OPTIONS "-DBASH_EXECUTABLE=${MSYS_ROOT}/usr/bin/bash.exe")
endif()
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
tools KTX_FEATURE_TOOLS
vulkan LIBKTX_FEATURE_VK_UPLOAD
js KTX_FEATURE_JS
)
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
-DKTX_GIT_VERSION_FULL=v${VERSION}
-DKTX_FEATURE_TESTS=OFF
-DKTX_FEATURE_LOADTEST_APPS=OFF
-DKTX_FEATURE_EMBEDDED_ZSTD=OFF
-DKTX_FEATURE_EMBEDDED_TOOLS_DEPENDENCIES=OFF
-DLIBKTX_FEATURE_APPLE_FRAMEWORK=OFF
${FEATURE_OPTIONS}
${OPTIONS}
DISABLE_PARALLEL_CONFIGURE
)
vcpkg_cmake_install()
if(tools IN_LIST FEATURES)
vcpkg_copy_tools(
TOOL_NAMES
ktx
toktx
ktxsc
ktxinfo
ktx2ktx2
ktx2check
AUTO_CLEAN
)
else()
vcpkg_copy_pdbs()
endif()
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/ktx)
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin" "${CURRENT_PACKAGES_DIR}/debug/bin")
endif()
file(GLOB LICENSE_FILES "${SOURCE_PATH}/LICENSES/*")
file(COPY ${LICENSE_FILES} DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/LICENSES")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.md")

46
extern/vcpkg/ports/ktx/vcpkg.json vendored Normal file
View File

@ -0,0 +1,46 @@
{
"name": "ktx",
"version-semver": "4.4.2-plus-vcpkg-patches",
"description": [
"The Khronos KTX library and tools.",
"Functions for writing and reading KTX files, and instantiating OpenGL®, OpenGL ES™ and Vulkan® textures from them."
],
"homepage": "https://github.com/KhronosGroup/KTX-Software",
"license": null,
"supports": "arm64 | x64 | !windows",
"dependencies": [
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
},
"zstd"
],
"features": {
"tools": {
"description": "Build tools",
"supports": "!android & !uwp",
"dependencies": [
"cxxopts",
"fmt"
]
},
"vulkan": {
"description": "Build Vulkan support",
"supports": "!emscripten"
},
"js": {
"description": "Build JavaScript interface wrappers",
"supports": "emscripten"
}
},
"default-features": [
{
"name": "js",
"platform": "emscripten"
}
]
}

View File

@ -0,0 +1,29 @@
set(VCPKG_ENV_PASSTHROUGH_UNTRACKED EMSCRIPTEN_ROOT EMSDK PATH EM_CONFIG)
if(NOT DEFINED ENV{EMSCRIPTEN_ROOT})
find_path(EMSCRIPTEN_ROOT "emcc")
else()
set(EMSCRIPTEN_ROOT "$ENV{EMSCRIPTEN_ROOT}")
endif()
if(NOT EMSCRIPTEN_ROOT)
if(NOT DEFINED ENV{EMSDK})
message(FATAL_ERROR "The emcc compiler not found in PATH")
endif()
set(EMSCRIPTEN_ROOT "$ENV{EMSDK}/upstream/emscripten")
endif()
if(NOT EXISTS "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
message(FATAL_ERROR "Emscripten.cmake toolchain file not found")
endif()
set(VCPKG_TARGET_ARCHITECTURE wasm32)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Emscripten)
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
# These lines are the key difference between this triplet and the wasm32-emscripten that comes with vcpkg.
# They set specific compiler and linker flags needed to use cesium-native on the web, particularly as part of Unity.
set(_configureFlags "-pthread -msimd128 -mnontrapping-fptoint -mbulk-memory -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -DSIZEOF_SIZE_T=4")
set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DCMAKE_C_FLAGS=${_configureFlags} -DCMAKE_CXX_FLAGS=${_configureFlags} -DCMAKE_EXE_LINKER_FLAGS=${_configureFlags})

View File

@ -0,0 +1,29 @@
set(VCPKG_ENV_PASSTHROUGH_UNTRACKED EMSCRIPTEN_ROOT EMSDK PATH EM_CONFIG)
if(NOT DEFINED ENV{EMSCRIPTEN_ROOT})
find_path(EMSCRIPTEN_ROOT "emcc")
else()
set(EMSCRIPTEN_ROOT "$ENV{EMSCRIPTEN_ROOT}")
endif()
if(NOT EMSCRIPTEN_ROOT)
if(NOT DEFINED ENV{EMSDK})
message(FATAL_ERROR "The emcc compiler not found in PATH")
endif()
set(EMSCRIPTEN_ROOT "$ENV{EMSDK}/upstream/emscripten")
endif()
if(NOT EXISTS "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
message(FATAL_ERROR "Emscripten.cmake toolchain file not found")
endif()
set(VCPKG_TARGET_ARCHITECTURE wasm32)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Emscripten)
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
# These lines are the key difference between this triplet and the wasm32-emscripten that comes with vcpkg.
# They set specific compiler and linker flags needed to use cesium-native on the web, particularly as part of Unity.
set(_configureFlags "-sMEMORY64=1 -pthread -msimd128 -mnontrapping-fptoint -mbulk-memory -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -DSIZEOF_SIZE_T=8")
set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DCMAKE_C_FLAGS=${_configureFlags} -DCMAKE_CXX_FLAGS=${_configureFlags} -DCMAKE_EXE_LINKER_FLAGS=${_configureFlags})

View File

@ -1,6 +1,6 @@
{ {
"name": "cesium-native", "name": "cesium-native",
"version": "0.53.0", "version": "0.54.0",
"description": "Cesium 3D Geospatial for C++", "description": "Cesium 3D Geospatial for C++",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@ -12,7 +12,8 @@
"generate-gltf": "cd tools/generate-classes && npm run generate-gltf && cd ../.. && npm run format", "generate-gltf": "cd tools/generate-classes && npm run generate-gltf && cd ../.. && npm run format",
"generate-3d-tiles": "cd tools/generate-classes && npm run generate-3d-tiles && cd ../.. && npm run format", "generate-3d-tiles": "cd tools/generate-classes && npm run generate-3d-tiles && cd ../.. && npm run format",
"generate-quantized-mesh-terrain": "cd tools/generate-classes && npm run generate-quantized-mesh-terrain && cd ../.. && npm run format", "generate-quantized-mesh-terrain": "cd tools/generate-classes && npm run generate-quantized-mesh-terrain && cd ../.. && npm run format",
"conform-includes": "node tools/conform-includes.js" "conform-includes": "node tools/conform-includes.js",
"test-wasm": "node tools/test-wasm-server"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -31,6 +32,7 @@
"homepage": "https://github.com/CesiumGS/cesium-native#readme", "homepage": "https://github.com/CesiumGS/cesium-native#readme",
"devDependencies": { "devDependencies": {
"clang-format": "^1.5.0", "clang-format": "^1.5.0",
"doxygen-awesome-css": "https://github.com/jothepro/doxygen-awesome-css#v2.3.4" "doxygen-awesome-css": "https://github.com/jothepro/doxygen-awesome-css#v2.3.4",
"express": "^5.1.0"
} }
} }

View File

@ -163,6 +163,12 @@
}, },
"EXT_primitive_voxels glTF Mesh Primitive extension": { "EXT_primitive_voxels glTF Mesh Primitive extension": {
"overrideName": "ExtensionExtPrimitiveVoxels" "overrideName": "ExtensionExtPrimitiveVoxels"
},
"KHR_gaussian_splatting glTF Mesh Primitive Extension": {
"overrideName": "ExtensionKhrGaussianSplatting"
},
"KHR_gaussian_splatting_compression_spz_2 glTF Mesh Primitive Extension": {
"overrideName": "ExtensionKhrGaussianSplattingCompressionSpz2"
} }
}, },
"extensions": [ "extensions": [
@ -287,6 +293,20 @@
{ {
"extensionName": "EXT_primitive_voxels", "extensionName": "EXT_primitive_voxels",
"schema": "Vendor/EXT_primitive_voxels/schema/mesh.primitive.EXT_primitive_voxels.schema.json" "schema": "Vendor/EXT_primitive_voxels/schema/mesh.primitive.EXT_primitive_voxels.schema.json"
},
{
"extensionName": "KHR_gaussian_splatting",
"schema": "Khronos/KHR_gaussian_splatting/schema/mesh.primitive.KHR_gaussian_splatting.schema.json",
"attachTo": [
"mesh.primitive"
]
},
{
"extensionName": "KHR_gaussian_splatting_compression_spz_2",
"schema": "Khronos/KHR_gaussian_splatting_compression_spz_2/schema/mesh.primitive.KHR_gaussian_splatting_compression_spz_2.schema.json",
"attachTo": [
"mesh.primitive.KHR_gaussian_splatting"
]
} }
] ]
} }

View File

@ -1,5 +1,5 @@
function makeIdentifier(s) { function makeIdentifier(s) {
return s.replace(/\//g, "_"); return s.replace(/[\/\.-]/g, "_");
} }
module.exports = makeIdentifier; module.exports = makeIdentifier;

View File

@ -0,0 +1,56 @@
const express = require("express");
const fs = require("fs");
const app = express();
const port = 3123;
app.use(express.static("./", {
setHeaders: (res, path, stat) => {
res.set("Cross-Origin-Opener-Policy", "same-origin");
res.set("Cross-Origin-Embedder-Policy", "require-corp");
}
}));
const emsdk = process.env.EMSDK;
if (emsdk && emsdk.length > 0) {
console.log(`Using emsdk at: ${emsdk}`);
app.use("/emsdk/emscripten", express.static(`${emsdk}/upstream/emscripten`, {
setHeaders: (res, path, stat) => {
res.set("Cross-Origin-Opener-Policy", "same-origin");
res.set("Cross-Origin-Embedder-Policy", "require-corp");
}
}));
app.use("/emsdk/upstream", express.static(`${emsdk}/upstream`, {
setHeaders: (res, path, stat) => {
res.set("Cross-Origin-Opener-Policy", "same-origin");
res.set("Cross-Origin-Embedder-Policy", "require-corp");
}
}));
} else {
console.log("Not mapping emsdk path because EMSDK environment variable is not set.");
}
const ezvcpkg = process.env.EZVCPKG_BASEDIR;
if (!ezvcpkg || ezvcpkg.length === 0) {
ezvcpkg = `${process.env.HOME ?? ""}/.ezvcpkg`;
}
if (fs.existsSync(ezvcpkg)) {
console.log(`Using ezvcpkg at: ${ezvcpkg}`);
app.use("/ezvcpkg", express.static(ezvcpkg, {
setHeaders: (res, path, stat) => {
res.set("Cross-Origin-Opener-Policy", "same-origin");
res.set("Cross-Origin-Embedder-Policy", "require-corp");
}
}));
} else {
console.log("Not mapping ezvcpkg path because EZVCPKG_BASEDIR environment variable is not set or directory does not exist.");
}
app.listen(port, () => {
console.log(`listening on port ${port}`);
});

View File

@ -1,7 +1,7 @@
{ {
"default-registry": { "default-registry": {
"kind": "git", "kind": "git",
"baseline": "4334d8b4c8916018600212ab4dd4bbdc343065d1", "baseline": "afc0a2e01ae104a2474216a2df0e8d78516fd5af",
"repository": "https://github.com/microsoft/vcpkg" "repository": "https://github.com/microsoft/vcpkg"
}, },
"registries": [ "registries": [

View File

@ -2,7 +2,10 @@
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"dependencies": [ "dependencies": [
"asyncplusplus", "asyncplusplus",
"curl", {
"name": "curl",
"platform": "!wasm32"
},
"doctest", "doctest",
"expected-lite", "expected-lite",
"glm", "glm",
@ -24,7 +27,10 @@
"zlib-ng", "zlib-ng",
"picosha2", "picosha2",
"earcut-hpp", "earcut-hpp",
"cpp-httplib", {
"name": "cpp-httplib",
"platform": "!wasm32"
},
"libmorton", "libmorton",
"zstd", "zstd",
{ {
@ -33,14 +39,16 @@
"features": [ "features": [
{ {
"name": "jit", "name": "jit",
"platform": "!ios" "platform": "!ios&!wasm32"
} }
] ]
}, },
{ {
"name": "asmjit", "name": "asmjit",
"platform": "!ios" "platform": "!ios&!wasm32"
} },
"spz",
"zlib"
] ]
} }