Compare commits
303 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
5b3b30e0d9 | |
|
|
5745cb84b4 | |
|
|
8666d2a783 | |
|
|
2685803664 | |
|
|
dc53b707d1 | |
|
|
b497c643ae | |
|
|
b8b1417c5b | |
|
|
612352eee9 | |
|
|
f8c4fd7530 | |
|
|
9aea35d9c3 | |
|
|
473f3ccbd5 | |
|
|
54b3b5764c | |
|
|
8f2c1a9f54 | |
|
|
1b4700ecd2 | |
|
|
a5d8e17300 | |
|
|
3bff311dee | |
|
|
ed344cddb3 | |
|
|
fbbaf4452a | |
|
|
fd8aaef4be | |
|
|
32e509eb95 | |
|
|
002d00e3f8 | |
|
|
77fff1077a | |
|
|
a8df93e235 | |
|
|
ced27961e4 | |
|
|
7213eed62f | |
|
|
551c2bb67c | |
|
|
642bd2dbc5 | |
|
|
d6b2882148 | |
|
|
8ede044fc4 | |
|
|
c1b5107758 | |
|
|
9db1f17a11 | |
|
|
c3b7c131b3 | |
|
|
b59305d4dd | |
|
|
8c7ee9507a | |
|
|
65dacbdb1b | |
|
|
436bb9be86 | |
|
|
2757937ea2 | |
|
|
11cf3812d2 | |
|
|
47e8533e18 | |
|
|
e4f46ba4e6 | |
|
|
a911d9f0ac | |
|
|
c71daed34a | |
|
|
cce023d8ae | |
|
|
8d9fc928bb | |
|
|
e554a7d72c | |
|
|
0b5616089e | |
|
|
79a1c7bcdc | |
|
|
4cabc9aaf9 | |
|
|
d5920f6b5d | |
|
|
7a7f50877c | |
|
|
2cecdd9c2d | |
|
|
81bcaf7755 | |
|
|
541f55289c | |
|
|
7a6f14ae86 | |
|
|
3e68c7a1c2 | |
|
|
32ced86a1f | |
|
|
a6a56c9ecf | |
|
|
081906aeff | |
|
|
684b9742d2 | |
|
|
5564afd7cb | |
|
|
d3fb02136d | |
|
|
577ec52e8c | |
|
|
2bdeadac3d | |
|
|
864e328ed8 | |
|
|
9fe157b4e2 | |
|
|
2421678466 | |
|
|
8271d59a3b | |
|
|
ca5104f3b7 | |
|
|
cefcafd82a | |
|
|
e876c133c8 | |
|
|
e9a9415539 | |
|
|
d92188a276 | |
|
|
c5ea386972 | |
|
|
8b86d7f3d7 | |
|
|
3f372f75a4 | |
|
|
77715ec5e5 | |
|
|
198c22c795 | |
|
|
110382a8db | |
|
|
d9d31300d7 | |
|
|
65b6c866a0 | |
|
|
c96485f98c | |
|
|
22e9dbcd7c | |
|
|
f42203eb71 | |
|
|
ccba7b2510 | |
|
|
00c35a1ffc | |
|
|
221611fd21 | |
|
|
58e8bafe71 | |
|
|
eecc1e9411 | |
|
|
5f06bc153e | |
|
|
b23852cddd | |
|
|
d1bffc5d37 | |
|
|
1e9f39df84 | |
|
|
de6f08b7bc | |
|
|
b33640a9ff | |
|
|
0aaaee207e | |
|
|
25cc1e89ca | |
|
|
16be63a245 | |
|
|
ab8de592a4 | |
|
|
f24824b430 | |
|
|
bd1d4eee4a | |
|
|
9c3e6f36fe | |
|
|
6fefe44a38 | |
|
|
5828ffd207 | |
|
|
551174f38d | |
|
|
8d9ee6fee6 | |
|
|
52e5736b4a | |
|
|
216314428b | |
|
|
55bbae20fe | |
|
|
c0de4d1da8 | |
|
|
afec183d53 | |
|
|
12ee3f00b5 | |
|
|
3080d41edb | |
|
|
b800becaae | |
|
|
f66d9dacf6 | |
|
|
077e9f3765 | |
|
|
60faebd4d2 | |
|
|
c9cff48b84 | |
|
|
a0e17767a0 | |
|
|
23ab650a0a | |
|
|
c913278446 | |
|
|
0e53ac995d | |
|
|
a93b082380 | |
|
|
eaf77c07f1 | |
|
|
84a9574e7b | |
|
|
5e554d3638 | |
|
|
e390112e21 | |
|
|
97883d1451 | |
|
|
a72529e9cb | |
|
|
000d27cbb1 | |
|
|
d0427df530 | |
|
|
f6d83fb859 | |
|
|
74e0ba7eb1 | |
|
|
8d3d70a930 | |
|
|
62ef5734da | |
|
|
e4c0150a4d | |
|
|
614458ed9b | |
|
|
b40e3ecbc0 | |
|
|
0656963653 | |
|
|
6778fe613c | |
|
|
410300c26a | |
|
|
c6687f4ddf | |
|
|
a6528aea33 | |
|
|
f54db5f321 | |
|
|
fb0123673e | |
|
|
f245947101 | |
|
|
39c1ac8c62 | |
|
|
167a728aa0 | |
|
|
5d44fd4670 | |
|
|
aa5646dbf5 | |
|
|
49a4409a8f | |
|
|
4f96d33d6b | |
|
|
c89796a0ac | |
|
|
dc10421be2 | |
|
|
7dc335dcf8 | |
|
|
91d2f5a3ca | |
|
|
15af0de635 | |
|
|
d66de9af3b | |
|
|
9787c25d84 | |
|
|
c754a5fdec | |
|
|
cf18fd06b4 | |
|
|
0e6df07ccd | |
|
|
32d275ef0b | |
|
|
a9640afc13 | |
|
|
dbe2c1f15d | |
|
|
7016cdf1b3 | |
|
|
121d9c2678 | |
|
|
af5c118986 | |
|
|
8f8a101aa4 | |
|
|
63f1353457 | |
|
|
7a8e96a857 | |
|
|
b2b9a1cd0d | |
|
|
7210acd3d3 | |
|
|
fa7b2d2bcc | |
|
|
315f5a55c3 | |
|
|
751cf36965 | |
|
|
753e35379b | |
|
|
6b35ee3f87 | |
|
|
7425f5caef | |
|
|
6cbd974f2e | |
|
|
bef3bd23a6 | |
|
|
70a7f91aed | |
|
|
00e8a9729d | |
|
|
d8631d0a6d | |
|
|
af5bf48cc8 | |
|
|
9e0db1b8c9 | |
|
|
05502dd87b | |
|
|
308f87f09a | |
|
|
0efdec7b43 | |
|
|
6da0610f3c | |
|
|
f0de38ccdb | |
|
|
e732d04cb9 | |
|
|
21aa95f481 | |
|
|
ac2ea44bfd | |
|
|
237f51cc38 | |
|
|
33cba63e85 | |
|
|
3b1b0f9e73 | |
|
|
de5ed6e7ba | |
|
|
733bc2c05d | |
|
|
99f1404fe7 | |
|
|
abf28c5ecc | |
|
|
1c13589457 | |
|
|
3ab91770f7 | |
|
|
e30f39940b | |
|
|
de2621a5e7 | |
|
|
8aa8664a83 | |
|
|
a891d3f996 | |
|
|
602bf3b452 | |
|
|
50b1530722 | |
|
|
56f2dc8e8b | |
|
|
1aa2788d33 | |
|
|
6a6819b7af | |
|
|
9cb588a405 | |
|
|
f4716c85e8 | |
|
|
03efa8a1cf | |
|
|
276b3a698d | |
|
|
3f416be76d | |
|
|
90d1c96818 | |
|
|
8884c086dd | |
|
|
619e180227 | |
|
|
618f285bdc | |
|
|
b7330ea1b5 | |
|
|
a37c73e776 | |
|
|
47b961556b | |
|
|
8987f0ecd7 | |
|
|
6e43196dd0 | |
|
|
de4d12dfe2 | |
|
|
be1812a06a | |
|
|
cf8014d616 | |
|
|
47f07ae907 | |
|
|
e7c5f3d665 | |
|
|
aed82a6bc6 | |
|
|
88c3716272 | |
|
|
1ff50143bc | |
|
|
4796e16f86 | |
|
|
a4f66ed062 | |
|
|
113f8702b9 | |
|
|
3ffbbc5a15 | |
|
|
1e1663bba7 | |
|
|
8329b52169 | |
|
|
a5e925c597 | |
|
|
f465fd9435 | |
|
|
77bbca121a | |
|
|
852d3cc131 | |
|
|
e9f170b926 | |
|
|
2332a727b7 | |
|
|
0f9d3dce1c | |
|
|
f02dd5f114 | |
|
|
99a0aa6f08 | |
|
|
cd2ca6997e | |
|
|
ad640dd72b | |
|
|
57262a6eae | |
|
|
c0631035b9 | |
|
|
f7e116bc7f | |
|
|
5a427f7447 | |
|
|
fc2bc11cf3 | |
|
|
c20dafac57 | |
|
|
f07af52bc6 | |
|
|
a124802e3a | |
|
|
4d2d125fbb | |
|
|
1dbfd68f67 | |
|
|
ca2f95b1ce | |
|
|
20fe18b00b | |
|
|
0e04d023b8 | |
|
|
1b34e31d33 | |
|
|
15e19045c6 | |
|
|
b4b104d94b | |
|
|
728fb20fc0 | |
|
|
ae039df78a | |
|
|
852ba2ddaf | |
|
|
8fac814750 | |
|
|
effb99af71 | |
|
|
e6c63b3342 | |
|
|
f5314830d8 | |
|
|
b6f90e3041 | |
|
|
87aae94cbf | |
|
|
12614410f7 | |
|
|
f6396a8d86 | |
|
|
21707e1484 | |
|
|
287a24adff | |
|
|
67e35d7efd | |
|
|
6e19881ea3 | |
|
|
0ab8381d61 | |
|
|
c71c3263ca | |
|
|
22f50cefb5 | |
|
|
70185b6304 | |
|
|
7703c0c7fc | |
|
|
89263366e9 | |
|
|
2c830aa233 | |
|
|
c5fc641212 | |
|
|
b3eb6e134f | |
|
|
e8e4fad106 | |
|
|
e2485f2dda | |
|
|
8012240b26 | |
|
|
ef80d583d1 | |
|
|
2b7af4c1b7 | |
|
|
581f1dd35d | |
|
|
031204a6a1 | |
|
|
c60e7dbbb1 | |
|
|
29d30d9330 | |
|
|
29445be9fd | |
|
|
3828bbeea0 | |
|
|
4c9c7e28f1 | |
|
|
297d6d66b1 |
|
|
@ -217,3 +217,70 @@ jobs:
|
|||
run: |
|
||||
cd build
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
build
|
||||
build-*
|
||||
doxygen
|
||||
Testing
|
||||
node_modules
|
||||
|
|
@ -8,7 +9,5 @@ CMakeSettings.json
|
|||
.cache
|
||||
*.DS_Store
|
||||
test.db
|
||||
build-wsl
|
||||
.idea
|
||||
build-debug
|
||||
clang-tidy.log
|
||||
|
|
|
|||
53
CHANGES.md
53
CHANGES.md
|
|
@ -1,5 +1,57 @@
|
|||
# Change Log
|
||||
|
||||
### ? - ?
|
||||
|
||||
##### Breaking Changes :mega:
|
||||
|
||||
- `RasterOverlay::createTileProvider` now receives a reference to `CreateRasterOverlayTileProviderParameters` instead of a large number of individual parameters.
|
||||
- The constructor parameters for `RasterOverlayTileProvider` and `QuadtreeRasterOverlayTileProvider` have changed.
|
||||
- The `getCredit` method has been removed from `RasterOverlayCreditProvider`. Use `getCredits` instead.
|
||||
|
||||
##### Additions :tada:
|
||||
|
||||
- Added the concept of a `CreditSource`. Every `Credit` in a `CreditSystem` has a source, and these can be mapped back to `Tileset` and `RasterOverlayTileProvider` (via their `getCreditSource` methods) in order to determine which dataset created which credits.
|
||||
- Added `TilesetViewGroup::isCreditReferenced`, which can be used to determine if a particular view group references a particular `Credit`.
|
||||
- Added `CreditReferencer::isCreditReferenced`, which can be used to determine if the referencer is currently referencing a particular `Credit`.
|
||||
- `CreditSystem::getSnapshot` now takes an optional parameter specifying if and how to filter `Credits` with identical HTML strings.
|
||||
|
||||
##### Fixes :wrench:
|
||||
|
||||
- The cmake install process previously didn't install `zlib`, which is required by `libcurl`.
|
||||
|
||||
### v0.54.0 - 2025-11-17
|
||||
|
||||
##### Additions :tada:
|
||||
|
||||
- Cesium Native can now be built with Emscripten.
|
||||
|
||||
### v0.53.0 - 2025-11-03
|
||||
|
||||
##### Breaking Changes :mega:
|
||||
|
||||
- Upgraded vcpkg to `2025.09.17`. This was previously done in v0.52.0 and reverted in v0.52.1.
|
||||
- Removed `refreshTileProviderWithNewKey` from `BingMapsRasterOverlay` and `refreshTileProviderWithNewUrlAndHeaders` from `TileMapServiceRasterOverlay`. These were no longer used after the raster overlay refactor in `v0.52.0`.
|
||||
|
||||
##### Additions :tada:
|
||||
|
||||
- Added `AzureMapsRasterOverlay`.
|
||||
- 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.
|
||||
|
||||
##### Fixes :wrench:
|
||||
|
||||
- Fixed a bug in `GoogleMapTilesRasterOverlay` that tried to parse credits from an erroneous viewport service response.
|
||||
- Fixed issues with `GeoJsonRasterOverlay` with certain types of data.
|
||||
- Polygons with holes should now display correctly.
|
||||
- Using a GeoJSON file with data on either side of the antimeridian should now display correctly instead of causing the entire overlay to disappear.
|
||||
- Fixed a bug with credits not showing on-screen when `showCreditsOnScreen` was enabled on `GoogleMapTilesRasterOverlay`.
|
||||
|
||||
### v0.52.1 - 2025-10-01
|
||||
|
||||
##### Breaking Changes :mega:
|
||||
|
||||
- Reverted vcpkg update that could interfere with builds on headless macOS.
|
||||
|
||||
### v0.52.0 - 2025-10-01
|
||||
|
||||
##### Breaking Changes :mega:
|
||||
|
|
@ -19,6 +71,7 @@
|
|||
- Removed `getOverlays`, `getTileProviders`, and `getPlaceholderTileProviders` from `RasterOverlayCollection`. Use `getActivatedOverlays` instead.
|
||||
- `SharedAssetDepot` now uses a templatized "context" instead of separate `AsyncSystem` and `IAssetAccessor` parameters. It defaults to `SharedAssetContext`.
|
||||
- Removed `RasterOverlay::getCredits`, which was not actually used anywhere. Use `RasterOverlayTileProvider::addCredits` instead.
|
||||
- Upgraded vcpkg to `2025.09.17`.
|
||||
|
||||
##### Additions :tada:
|
||||
|
||||
|
|
|
|||
117
CMakeLists.txt
117
CMakeLists.txt
|
|
@ -4,6 +4,14 @@ if (NOT VCPKG_LIBRARY_LINKAGE)
|
|||
set(VCPKG_LIBRARY_LINKAGE static)
|
||||
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
|
||||
# ezvcpkg if it appears that this configuration is using vcpkg
|
||||
# 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_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)
|
||||
# Keep vcpkg from running in manifset mode. It will try to because
|
||||
|
|
@ -50,12 +65,28 @@ if (NOT VCPKG_TRIPLET)
|
|||
elseif(DETECTED_VCPKG_TRIPLET STREQUAL "x64-windows")
|
||||
# cesium-native requires static linking on Windows
|
||||
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()
|
||||
set(VCPKG_TRIPLET "${DETECTED_VCPKG_TRIPLET}")
|
||||
endif()
|
||||
if (NOT CESIUM_USE_EZVCPKG)
|
||||
set(VCPKG_TARGET_TRIPLET "${VCPKG_TRIPLET}")
|
||||
endif()
|
||||
|
||||
# If we're using ezvcpkg, ezvcpkg will update CMAKE_TOOLCHAIN_FILE to point to the vcpkg toolchain.
|
||||
# Which means that when we hit the `project` function call below, cmake will load the vcpkg
|
||||
# toolchain file. If VCPKG_TARGET_TRIPLET isn't set by that time, vcpkg will set it itself, and
|
||||
# maybe not to what we want. So set VCPKG_TARGET_TRIPLET explicit here so that we're sure to get
|
||||
# the right one.
|
||||
#
|
||||
# If we're _not_ using ezvcpkg, then we also must set VCPKG_TARGET_TRIPLET, but for a different reason.
|
||||
# VCPKG_TRIPLET is only an ezvcpkg thing, vcpkg itself only knows about VCPKG_TARGET_TRIPLET.
|
||||
set(VCPKG_TARGET_TRIPLET "${VCPKG_TRIPLET}")
|
||||
endif()
|
||||
|
||||
message(STATUS "VCPKG_TRIPLET ${VCPKG_TRIPLET}")
|
||||
|
|
@ -80,6 +111,10 @@ if (NOT VCPKG_OVERLAY_TRIPLETS)
|
|||
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}")
|
||||
|
||||
# These packages are used in the public headers of Cesium libraries, so we need to distribute the headers and binaries
|
||||
|
|
@ -91,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
|
||||
# OpenSSL and abseil are both dependencies of s2geometry
|
||||
set(PACKAGES_PRIVATE
|
||||
abseil draco ktx modp-base64 meshoptimizer openssl s2geometry
|
||||
libjpeg-turbo sqlite3 tinyxml2 libwebp zlib-ng picosha2
|
||||
earcut-hpp cpp-httplib[core] libmorton zstd
|
||||
abseil draco ktx[core] modp-base64 meshoptimizer openssl s2geometry
|
||||
sqlite3 tinyxml2 libwebp zlib-ng picosha2
|
||||
earcut-hpp libmorton zstd
|
||||
)
|
||||
|
||||
# asmjit needed by blend2d on non-iOS platforms (iOS doesn't support JIT)
|
||||
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
# asmjit needed by blend2d on non-iOS platforms (iOS and Wasm don't support JIT)
|
||||
if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
list(APPEND PACKAGES_PRIVATE blend2d asmjit)
|
||||
else()
|
||||
# Use [core] feature to disable default jit feature.
|
||||
|
|
@ -105,19 +140,40 @@ else()
|
|||
endif()
|
||||
|
||||
if(NOT CESIUM_DISABLE_CURL)
|
||||
list(APPEND PACKAGES_PRIVATE curl)
|
||||
list(APPEND PACKAGES_PRIVATE curl zlib)
|
||||
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
|
||||
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)
|
||||
set(PACKAGES_ALL ${PACKAGES_PUBLIC})
|
||||
list(APPEND PACKAGES_ALL ${PACKAGES_PRIVATE})
|
||||
list(APPEND PACKAGES_ALL ${PACKAGES_TEST})
|
||||
|
||||
ezvcpkg_fetch(
|
||||
COMMIT 2025.09.17
|
||||
COMMIT afc0a2e01ae104a2474216a2df0e8d78516fd5af
|
||||
REPO microsoft/vcpkg
|
||||
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_BUILDTREES
|
||||
|
|
@ -138,10 +194,20 @@ endif()
|
|||
include("cmake/defaults.cmake")
|
||||
|
||||
project(cesium-native
|
||||
VERSION 0.52.0
|
||||
VERSION 0.54.0
|
||||
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(CMakeDependentOption)
|
||||
|
||||
|
|
@ -284,10 +350,16 @@ endif()
|
|||
|
||||
# On the CI builds, I have to do this explicitly for some reason or it fails to find the vcpkg packages.
|
||||
# The toolchain is supposed to manage this, but I haven't figured out why it isn't yet.
|
||||
|
||||
# One reason the toolchain won't manage this: it's not being run at all. That happens when this CMakeLists.txt
|
||||
# is invoked from another one via add_subdirectory, and the parent project has already loaded the toolchain
|
||||
# before ezvcpkg sets it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}/share/s2")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}/share")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}")
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$")
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "${PACKAGE_BUILD_DIR}/debug")
|
||||
endif()
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "${PACKAGE_BUILD_DIR}")
|
||||
|
||||
# Find the VCPKG dependnecies
|
||||
# Note that while we could push these into the extern/CMakeLists.txt as an organization tidy-up, that would require
|
||||
|
|
@ -295,26 +367,24 @@ list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}")
|
|||
# they won't be visible in this scope nor any of the subdirectories for the actual libraries.
|
||||
#
|
||||
# However, for some of the vcpkg built libraries where they don't provide a prope cmake config file, we have to declare
|
||||
# and imporeted library target ourselves. This is the case for modp_b64::modp_b64, picosha2::picosha2 and earcut. In
|
||||
# an imported library target ourselves. This is the case for modp_b64::modp_b64, picosha2::picosha2 and earcut. In
|
||||
# these cases, we *do* have the somewhat ugly and verbose details in the extern/CMakeLists.txt file.
|
||||
#
|
||||
# XXX Above comment should be obsoleted by these first calls to
|
||||
# find_package, which resolve to our own modules that provide
|
||||
# targets. If needed, they can be installed with CMake config files
|
||||
# etc.
|
||||
find_package(zlib-ng REQUIRED)
|
||||
find_package(modp_b64 REQUIRED)
|
||||
|
||||
find_package(ada CONFIG REQUIRED)
|
||||
find_package(Async++ CONFIG REQUIRED)
|
||||
find_package(blend2d CONFIG REQUIRED)
|
||||
find_package(doctest CONFIG REQUIRED)
|
||||
find_package(draco CONFIG REQUIRED)
|
||||
find_package(expected-lite CONFIG REQUIRED)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
find_package(httplib CONFIG REQUIRED)
|
||||
find_package(Ktx CONFIG REQUIRED)
|
||||
find_package(libmorton CONFIG REQUIRED)
|
||||
find_package(libjpeg-turbo CONFIG REQUIRED)
|
||||
find_package(meshoptimizer CONFIG REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(s2 CONFIG REQUIRED)
|
||||
|
|
@ -322,9 +392,10 @@ find_package(spdlog CONFIG REQUIRED)
|
|||
find_package(tinyxml2 CONFIG REQUIRED)
|
||||
find_package(unofficial-sqlite3 CONFIG REQUIRED)
|
||||
find_package(WebP CONFIG REQUIRED)
|
||||
find_package(blend2d CONFIG REQUIRED)
|
||||
# asmjit should not be included with iOS builds as iOS doesn't support JIT compilation.
|
||||
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
find_package(zlib-ng CONFIG REQUIRED)
|
||||
|
||||
# asmjit should not be included with iOS or Wasm builds as they don't support JIT compilation.
|
||||
if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
find_package(asmjit CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
|
|
@ -332,9 +403,12 @@ if(NOT CESIUM_DISABLE_CURL)
|
|||
find_package(CURL REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT CESIUM_DISABLE_LIBJPEG_TURBO)
|
||||
find_package(libjpeg-turbo CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT CESIUM_DISABLE_CURL)
|
||||
find_package(CURL REQUIRED)
|
||||
if(NOT CESIUM_TARGET_WASM)
|
||||
find_package(httplib CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
# Private Library (s2geometry)
|
||||
|
|
@ -386,7 +460,6 @@ if(CESIUM_INSTALL_STATIC_LIBS AND CESIUM_INSTALL_HEADERS)
|
|||
DESTINATION ${CMAKE_INSTALL_DATADIR}/cesium-native/cmake)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cmake/modules/Findzlib-ng.cmake"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cmake/modules/Findmodp_b64.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/cesium-native/cmake)
|
||||
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ public:
|
|||
bool isContentAvailable(
|
||||
const CesiumGeometry::QuadtreeTileID& subtreeId,
|
||||
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.
|
||||
|
|
@ -247,7 +247,7 @@ public:
|
|||
bool isContentAvailable(
|
||||
const CesiumGeometry::OctreeTileID& subtreeId,
|
||||
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.
|
||||
|
|
@ -262,7 +262,7 @@ public:
|
|||
bool isContentAvailable(
|
||||
uint32_t relativeTileLevel,
|
||||
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
|
||||
|
|
@ -276,7 +276,7 @@ public:
|
|||
void setContentAvailable(
|
||||
const CesiumGeometry::QuadtreeTileID& subtreeId,
|
||||
const CesiumGeometry::QuadtreeTileID& tileId,
|
||||
uint64_t contentId,
|
||||
size_t contentId,
|
||||
bool isAvailable) noexcept;
|
||||
|
||||
/**
|
||||
|
|
@ -291,7 +291,7 @@ public:
|
|||
void setContentAvailable(
|
||||
const CesiumGeometry::OctreeTileID& subtreeId,
|
||||
const CesiumGeometry::OctreeTileID& tileId,
|
||||
uint64_t contentId,
|
||||
size_t contentId,
|
||||
bool isAvailable) noexcept;
|
||||
|
||||
/**
|
||||
|
|
@ -309,7 +309,7 @@ public:
|
|||
void setContentAvailable(
|
||||
uint32_t relativeTileLevel,
|
||||
uint64_t relativeTileMortonId,
|
||||
uint64_t contentId,
|
||||
size_t contentId,
|
||||
bool isAvailable) noexcept;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1014,7 +1014,10 @@ void copyStringsToBuffers(
|
|||
for (const auto& str : arrayMember.GetArray()) {
|
||||
OffsetType byteLength = static_cast<OffsetType>(
|
||||
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(
|
||||
offsetBuffer.data() + offsetIndex * sizeof(OffsetType),
|
||||
&offset,
|
||||
|
|
@ -1075,8 +1078,7 @@ void updateStringArrayProperty(
|
|||
++it;
|
||||
}
|
||||
|
||||
const uint64_t totalByteLength =
|
||||
totalCharCount * sizeof(rapidjson::Value::Ch);
|
||||
const size_t totalByteLength = totalCharCount * sizeof(rapidjson::Value::Ch);
|
||||
std::vector<std::byte> valueBuffer;
|
||||
std::vector<std::byte> stringOffsetBuffer;
|
||||
PropertyComponentType stringOffsetType = PropertyComponentType::None;
|
||||
|
|
|
|||
|
|
@ -823,7 +823,7 @@ void decodeDracoMetadata(
|
|||
const std::unique_ptr<draco::PointCloud>& pPointCloud,
|
||||
rapidjson::Document& batchTableJson,
|
||||
PntsContent& parsedContent) {
|
||||
const uint64_t pointsLength = parsedContent.pointsLength;
|
||||
const size_t pointsLength = parsedContent.pointsLength;
|
||||
std::vector<std::byte>& data = parsedContent.dracoBatchTableBinary;
|
||||
|
||||
const auto& dracoMetadataSemantics = parsedContent.dracoMetadataSemantics;
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ void SubtreeAvailability::setTileAvailable(
|
|||
bool SubtreeAvailability::isContentAvailable(
|
||||
const CesiumGeometry::QuadtreeTileID& subtreeId,
|
||||
const CesiumGeometry::QuadtreeTileID& tileId,
|
||||
uint64_t contentId) const noexcept {
|
||||
size_t contentId) const noexcept {
|
||||
uint64_t relativeTileMortonIdx =
|
||||
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
|
||||
return this->isContentAvailable(
|
||||
|
|
@ -293,7 +293,7 @@ bool SubtreeAvailability::isContentAvailable(
|
|||
bool SubtreeAvailability::isContentAvailable(
|
||||
const CesiumGeometry::OctreeTileID& subtreeId,
|
||||
const CesiumGeometry::OctreeTileID& tileId,
|
||||
uint64_t contentId) const noexcept {
|
||||
size_t contentId) const noexcept {
|
||||
uint64_t relativeTileMortonIdx =
|
||||
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
|
||||
return this->isContentAvailable(
|
||||
|
|
@ -305,7 +305,7 @@ bool SubtreeAvailability::isContentAvailable(
|
|||
bool SubtreeAvailability::isContentAvailable(
|
||||
uint32_t relativeTileLevel,
|
||||
uint64_t relativeTileMortonId,
|
||||
uint64_t contentId) const noexcept {
|
||||
size_t contentId) const noexcept {
|
||||
if (contentId >= this->_contentAvailability.size())
|
||||
return false;
|
||||
return isAvailable(
|
||||
|
|
@ -317,7 +317,7 @@ bool SubtreeAvailability::isContentAvailable(
|
|||
void SubtreeAvailability::setContentAvailable(
|
||||
const CesiumGeometry::QuadtreeTileID& subtreeId,
|
||||
const CesiumGeometry::QuadtreeTileID& tileId,
|
||||
uint64_t contentId,
|
||||
size_t contentId,
|
||||
bool isAvailable) noexcept {
|
||||
uint64_t relativeTileMortonIdx =
|
||||
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
|
||||
|
|
@ -331,7 +331,7 @@ void SubtreeAvailability::setContentAvailable(
|
|||
void SubtreeAvailability::setContentAvailable(
|
||||
const CesiumGeometry::OctreeTileID& subtreeId,
|
||||
const CesiumGeometry::OctreeTileID& tileId,
|
||||
uint64_t contentId,
|
||||
size_t contentId,
|
||||
bool isAvailable) noexcept {
|
||||
uint64_t relativeTileMortonIdx =
|
||||
ImplicitTilingUtilities::computeRelativeMortonIndex(subtreeId, tileId);
|
||||
|
|
@ -345,7 +345,7 @@ void SubtreeAvailability::setContentAvailable(
|
|||
void SubtreeAvailability::setContentAvailable(
|
||||
uint32_t relativeTileLevel,
|
||||
uint64_t relativeTileMortonId,
|
||||
uint64_t contentId,
|
||||
size_t contentId,
|
||||
bool isAvailable) noexcept {
|
||||
if (contentId < this->_contentAvailability.size()) {
|
||||
this->setAvailable(
|
||||
|
|
@ -518,7 +518,7 @@ bool SubtreeAvailability::isAvailableUsingBufferView(
|
|||
const SubtreeBufferViewAvailability* bufferViewAvailability =
|
||||
std::get_if<SubtreeBufferViewAvailability>(&availabilityView);
|
||||
|
||||
const uint64_t byteIndex = availabilityBitIndex / 8;
|
||||
const size_t byteIndex = size_t(availabilityBitIndex / 8);
|
||||
if (byteIndex >= bufferViewAvailability->view.size()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -541,7 +541,7 @@ void SubtreeAvailability::setAvailableUsingBufferView(
|
|||
const SubtreeBufferViewAvailability* pBufferViewAvailability =
|
||||
std::get_if<SubtreeBufferViewAvailability>(&availabilityView);
|
||||
|
||||
const uint64_t byteIndex = availabilityBitIndex / 8;
|
||||
const size_t byteIndex = size_t(availabilityBitIndex / 8);
|
||||
if (byteIndex >= pBufferViewAvailability->view.size()) {
|
||||
// Attempting to set an invalid tile. Assert, but otherwise ignore it.
|
||||
CESIUM_ASSERT(false);
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ void markTileAvailableForQuadtree(
|
|||
uint64_t availabilityBitIndex =
|
||||
numOfTilesFromRootToParentLevel +
|
||||
libmorton::morton2D_64_encode(tileID.x, tileID.y);
|
||||
const uint64_t byteIndex = availabilityBitIndex / 8;
|
||||
const uint64_t bitIndex = availabilityBitIndex % 8;
|
||||
const size_t byteIndex = size_t(availabilityBitIndex / 8);
|
||||
const size_t bitIndex = size_t(availabilityBitIndex % 8);
|
||||
available[byteIndex] |= std::byte(1 << bitIndex);
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ void markSubtreeAvailableForQuadtree(
|
|||
libmorton::morton2D_64_encode(tileID.x, tileID.y);
|
||||
const uint64_t byteIndex = availabilityBitIndex / 8;
|
||||
const uint64_t bitIndex = availabilityBitIndex % 8;
|
||||
available[byteIndex] |= std::byte(1 << bitIndex);
|
||||
available[(size_t)byteIndex] |= std::byte(1 << bitIndex);
|
||||
}
|
||||
|
||||
using SubtreeContentInput =
|
||||
|
|
@ -140,17 +140,17 @@ SubtreeContent createSubtreeContent(
|
|||
: 0;
|
||||
|
||||
std::vector<std::byte> availabilityBuffer(
|
||||
bufferSize + bufferSize + subtreeBufferSize);
|
||||
size_t(bufferSize + bufferSize + subtreeBufferSize));
|
||||
|
||||
std::span<std::byte> contentAvailabilityBuffer(
|
||||
availabilityBuffer.data(),
|
||||
bufferSize);
|
||||
size_t(bufferSize));
|
||||
std::span<std::byte> tileAvailabilityBuffer(
|
||||
availabilityBuffer.data() + bufferSize,
|
||||
bufferSize);
|
||||
size_t(bufferSize));
|
||||
std::span<std::byte> subtreeAvailabilityBuffer(
|
||||
availabilityBuffer.data() + bufferSize + bufferSize,
|
||||
subtreeBufferSize);
|
||||
size_t(subtreeBufferSize));
|
||||
|
||||
SubtreeAvailability::AvailabilityView tileAvailability = std::visit(
|
||||
GetAvailabilityView{tileAvailabilityBuffer, false},
|
||||
|
|
@ -486,9 +486,9 @@ TEST_CASE("Test SubtreeAvailability methods") {
|
|||
subtree.bufferViews[1].buffer = 1;
|
||||
subtree.bufferViews[2].buffer = 2;
|
||||
|
||||
contentAvailabilityBuffer.resize(bufferSize);
|
||||
tileAvailabilityBuffer.resize(bufferSize);
|
||||
subtreeAvailabilityBuffer.resize(subtreeBufferSize);
|
||||
contentAvailabilityBuffer.resize(size_t(bufferSize));
|
||||
tileAvailabilityBuffer.resize(size_t(bufferSize));
|
||||
subtreeAvailabilityBuffer.resize(size_t(subtreeBufferSize));
|
||||
|
||||
subtree.buffers[0].byteLength = subtree.bufferViews[0].byteLength =
|
||||
int64_t(bufferSize);
|
||||
|
|
@ -622,18 +622,18 @@ TEST_CASE("Test parsing subtree format") {
|
|||
subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize();
|
||||
subtreeHeader.binaryByteLength = subtreeBuffers.buffers.size();
|
||||
|
||||
std::vector<std::byte> buffer(
|
||||
std::vector<std::byte> buffer(size_t(
|
||||
sizeof(subtreeHeader) + subtreeHeader.jsonByteLength +
|
||||
subtreeHeader.binaryByteLength);
|
||||
subtreeHeader.binaryByteLength));
|
||||
std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader));
|
||||
std::memcpy(
|
||||
buffer.data() + sizeof(subtreeHeader),
|
||||
subtreeJsonBuffer.GetString(),
|
||||
subtreeHeader.jsonByteLength);
|
||||
size_t(subtreeHeader.jsonByteLength));
|
||||
std::memcpy(
|
||||
buffer.data() + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength,
|
||||
subtreeBuffers.buffers.data(),
|
||||
subtreeHeader.binaryByteLength);
|
||||
size_t(subtreeHeader.binaryByteLength));
|
||||
|
||||
// mock the request
|
||||
auto pMockResponse = std::make_unique<SimpleAssetResponse>(
|
||||
|
|
@ -711,18 +711,18 @@ TEST_CASE("Test parsing subtree format") {
|
|||
subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize();
|
||||
subtreeHeader.binaryByteLength = subtreeContent.buffers.size();
|
||||
|
||||
std::vector<std::byte> buffer(
|
||||
std::vector<std::byte> buffer(size_t(
|
||||
sizeof(subtreeHeader) + subtreeHeader.jsonByteLength +
|
||||
subtreeHeader.binaryByteLength);
|
||||
subtreeHeader.binaryByteLength));
|
||||
std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader));
|
||||
std::memcpy(
|
||||
buffer.data() + sizeof(subtreeHeader),
|
||||
subtreeJsonBuffer.GetString(),
|
||||
subtreeHeader.jsonByteLength);
|
||||
size_t(subtreeHeader.jsonByteLength));
|
||||
std::memcpy(
|
||||
buffer.data() + sizeof(subtreeHeader) + subtreeHeader.jsonByteLength,
|
||||
subtreeContent.buffers.data(),
|
||||
subtreeHeader.binaryByteLength);
|
||||
size_t(subtreeHeader.binaryByteLength));
|
||||
|
||||
// mock the request
|
||||
auto pMockResponse = std::make_unique<SimpleAssetResponse>(
|
||||
|
|
@ -799,14 +799,14 @@ TEST_CASE("Test parsing subtree format") {
|
|||
subtreeHeader.jsonByteLength = subtreeJsonBuffer.GetSize();
|
||||
subtreeHeader.binaryByteLength = 0;
|
||||
|
||||
std::vector<std::byte> buffer(
|
||||
std::vector<std::byte> buffer(size_t(
|
||||
sizeof(subtreeHeader) + subtreeHeader.jsonByteLength +
|
||||
subtreeHeader.binaryByteLength);
|
||||
subtreeHeader.binaryByteLength));
|
||||
std::memcpy(buffer.data(), &subtreeHeader, sizeof(subtreeHeader));
|
||||
std::memcpy(
|
||||
buffer.data() + sizeof(subtreeHeader),
|
||||
subtreeJsonBuffer.GetString(),
|
||||
subtreeHeader.jsonByteLength);
|
||||
size_t(subtreeHeader.jsonByteLength));
|
||||
|
||||
// mock the request
|
||||
auto pMockResponse = std::make_unique<SimpleAssetResponse>(
|
||||
|
|
|
|||
|
|
@ -165,12 +165,12 @@ Future<ReadJsonResult<Subtree>> SubtreeFileReader::loadBinary(
|
|||
}
|
||||
|
||||
ReadJsonResult<Subtree> result = this->_reader.readFromJson(
|
||||
data.subspan(sizeof(SubtreeHeader), header->jsonByteLength));
|
||||
data.subspan(sizeof(SubtreeHeader), size_t(header->jsonByteLength)));
|
||||
|
||||
if (result.value) {
|
||||
std::span<const std::byte> binaryChunk = data.subspan(
|
||||
sizeof(SubtreeHeader) + header->jsonByteLength,
|
||||
header->binaryByteLength);
|
||||
sizeof(SubtreeHeader) + size_t(header->jsonByteLength),
|
||||
size_t(header->binaryByteLength));
|
||||
|
||||
if (binaryChunk.size() > 0) {
|
||||
if (result.value->buffers.empty()) {
|
||||
|
|
@ -207,7 +207,7 @@ Future<ReadJsonResult<Subtree>> SubtreeFileReader::loadBinary(
|
|||
|
||||
buffer.cesium.data = std::vector<std::byte>(
|
||||
binaryChunk.begin(),
|
||||
binaryChunk.begin() + buffer.byteLength);
|
||||
binaryChunk.begin() + ptrdiff_t(buffer.byteLength));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ target_link_libraries(Cesium3DTilesSelection
|
|||
CesiumQuantizedMeshTerrain
|
||||
CesiumRasterOverlays
|
||||
CesiumUtility
|
||||
spdlog::spdlog spdlog::spdlog_header_only
|
||||
spdlog::spdlog
|
||||
# PRIVATE
|
||||
libmorton::libmorton
|
||||
draco::draco
|
||||
|
|
|
|||
|
|
@ -0,0 +1,273 @@
|
|||
#pragma once
|
||||
|
||||
#include <Cesium3DTilesSelection/GltfModifierState.h>
|
||||
#include <Cesium3DTilesSelection/Tile.h>
|
||||
#include <Cesium3DTilesSelection/TileLoadRequester.h>
|
||||
#include <CesiumAsync/AsyncSystem.h>
|
||||
#include <CesiumAsync/Future.h>
|
||||
#include <CesiumGltf/Model.h>
|
||||
|
||||
#include <spdlog/fwd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace CesiumAsync {
|
||||
|
||||
class IAssetAccessor;
|
||||
|
||||
} // namespace CesiumAsync
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
class TilesetMetadata;
|
||||
class TilesetContentManager;
|
||||
|
||||
/**
|
||||
* @brief The input to @ref GltfModifier::apply.
|
||||
*/
|
||||
struct GltfModifierInput {
|
||||
/**
|
||||
* @brief The version of the @ref GltfModifier, as returned by
|
||||
* @ref GltfModifier::getCurrentVersion at the start of the modification.
|
||||
*
|
||||
* This is provided because calling @ref GltfModifier::getCurrentVersion
|
||||
* may return a newer version if @ref GltfModifier::trigger is called
|
||||
* again while @ref GltfModifier::apply is running in a worker thread.
|
||||
*/
|
||||
int64_t version;
|
||||
|
||||
/**
|
||||
* @brief The async system that can be used to do work in threads.
|
||||
*/
|
||||
CesiumAsync::AsyncSystem asyncSystem;
|
||||
|
||||
/**
|
||||
* @brief An asset accessor that can be used to obtain additional assets.
|
||||
*/
|
||||
std::shared_ptr<CesiumAsync::IAssetAccessor> pAssetAccessor;
|
||||
|
||||
/**
|
||||
* @brief The logger.
|
||||
*/
|
||||
std::shared_ptr<spdlog::logger> pLogger;
|
||||
|
||||
/**
|
||||
* @brief The model to be modified.
|
||||
*/
|
||||
const CesiumGltf::Model& previousModel;
|
||||
|
||||
/**
|
||||
* @brief The transformation of the model's coordinates to the tileset's
|
||||
* coordinate system.
|
||||
*/
|
||||
glm::dmat4 tileTransform;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The output of @ref GltfModifier::apply.
|
||||
*/
|
||||
struct GltfModifierOutput {
|
||||
/**
|
||||
* @brief The new, modified model.
|
||||
*/
|
||||
CesiumGltf::Model modifiedModel;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstract class that allows modifying a tile's glTF model after it
|
||||
* has been loaded.
|
||||
*
|
||||
* An example modification is merging or splitting the primitives in the glTF.
|
||||
* Merging primitives can lead to improved rendering performance. Splitting
|
||||
* primitives allows different materials to be assigned to parts that were
|
||||
* initially in the same primitive.
|
||||
*
|
||||
* The `GltfModifier` can be applied several times during the lifetime of the
|
||||
* model, depending on current needs. For this reason, the `GltfModifer` has a
|
||||
* @ref getCurrentVersion, which can be incremented by calling
|
||||
* @ref trigger. When the version is incremented, the `GltfModifier` will be
|
||||
* re-applied to all previously-modified models.
|
||||
*
|
||||
* The version number of a modified glTF is stored in the
|
||||
* @ref GltfModifierVersionExtension extension.
|
||||
*
|
||||
* A just-constructed modifier is considered nilpotent, meaning nothing will
|
||||
* happen until @ref trigger has been called at least once.
|
||||
*
|
||||
* The @ref apply function is called from a worker thread. All other methods
|
||||
* must only be called from the main thread.
|
||||
*/
|
||||
class GltfModifier : private TileLoadRequester {
|
||||
public:
|
||||
/**
|
||||
* @brief Gets the current version number, or `std::nullopt` if the
|
||||
* `GltfModifier` is currently inactive.
|
||||
*
|
||||
* Returns `std::nullopt` when in the default nilpotent state where glTFs will
|
||||
* not be modified at all. Calling @ref trigger once will set the version
|
||||
* number to 0 and activate the `GltfModifier`. Calling it successive times
|
||||
* will increment the version number and re-apply modification to all
|
||||
* previously-modified models.
|
||||
*/
|
||||
std::optional<int64_t> getCurrentVersion() const;
|
||||
|
||||
/**
|
||||
* @brief Checks if this `GltfModifier` is active.
|
||||
*
|
||||
* This method returns true if the current version is greater than or equal to
|
||||
* 0, indicating that @ref trigger has been called at least once.
|
||||
*/
|
||||
bool isActive() const;
|
||||
|
||||
/**
|
||||
* @brief Call this the first time to activate this `GltfModifier` after it
|
||||
* has been constructed in its default nilpotent state and set the
|
||||
* @ref getCurrentVersion to 0. Call it successive times to increment
|
||||
* @ref getCurrentVersion and reapply modification to all
|
||||
* previously-modified models without unloading them.
|
||||
*
|
||||
* While the `GltfModifier` is being reapplied for a new version, the display
|
||||
* may show a mix of tiles with the old and new versions.
|
||||
*/
|
||||
void trigger();
|
||||
|
||||
/**
|
||||
* @brief Implement this method to apply custom modification to a glTF model.
|
||||
* It is called by the @ref Tileset from within a worker thread.
|
||||
*
|
||||
* This method will be called for each @ref Tile during the content load
|
||||
* process if @ref trigger has been called at least once. It will also be
|
||||
* called again for already-loaded tiles for successive calls to
|
||||
* @ref trigger.
|
||||
*
|
||||
* @param input The input to the glTF modification.
|
||||
* @return A future that resolves to a @ref GltfModifierOutput with the
|
||||
* new model, or to `std::nullopt` if the model does not need to be modified.
|
||||
*/
|
||||
virtual CesiumAsync::Future<std::optional<GltfModifierOutput>>
|
||||
apply(GltfModifierInput&& input) = 0;
|
||||
|
||||
/**
|
||||
* @brief Checks if the given tile needs to be processed by this
|
||||
* `GltfModifier` in a worker thread.
|
||||
*
|
||||
* @param tile The tile to check.
|
||||
* @returns `true` if the tile needs to be processed by the `GltfModifier` in
|
||||
* a worker thread, or `false` otherwise.
|
||||
*/
|
||||
bool needsWorkerThreadModification(const Tile& tile) const;
|
||||
|
||||
/**
|
||||
* @brief Checks if the given tile needs to be processed by this
|
||||
* `GltfModifier` in the main thread.
|
||||
|
||||
* @param tile The tile to check.
|
||||
* @returns `true` if the tile needs to be processed by the `GltfModifier` in
|
||||
* the main thread, or `false` otherwise.
|
||||
*/
|
||||
bool needsMainThreadModification(const Tile& tile) const;
|
||||
|
||||
protected:
|
||||
GltfModifier();
|
||||
virtual ~GltfModifier();
|
||||
|
||||
/**
|
||||
* @brief Notifies this instance that it has been registered with a
|
||||
* @ref Tileset.
|
||||
*
|
||||
* This method is called after the tileset's root tile is known but
|
||||
* before @ref Tileset::getRootTileAvailableEvent has been raised.
|
||||
*
|
||||
* This method is called from the main thread. Override this method to respond
|
||||
* to this event.
|
||||
*
|
||||
* @param asyncSystem The async system with which to do background work.
|
||||
* @param pAssetAccessor The asset accessor to use to retrieve any additional
|
||||
* assets.
|
||||
* @param pLogger The logger to which to log errors and warnings that occur
|
||||
* during preparation of the `GltfModifier`.
|
||||
* @param tilesetMetadata The metadata associated with the tileset.
|
||||
* @param rootTile The root tile of the tileset.
|
||||
* @returns A future that resolves when the `GltfModifier` is ready to modify
|
||||
* glTF instances for this tileset. Tileset loading will not proceed until
|
||||
* this future resolves. If the future rejects, tileset load will proceed but
|
||||
* the `GltfModifier` will not be used.
|
||||
*/
|
||||
virtual CesiumAsync::Future<void> onRegister(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const TilesetMetadata& tilesetMetadata,
|
||||
const Tile& rootTile);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* @brief Called by @ref Tileset when this instance has been registered
|
||||
* with it. To add custom behavior on registration, override the other
|
||||
* overload of this method.
|
||||
*/
|
||||
CesiumAsync::Future<void> onRegister(
|
||||
TilesetContentManager& contentManager,
|
||||
const TilesetMetadata& tilesetMetadata,
|
||||
const Tile& rootTile);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* @brief Called by @ref Tileset when this instance has been unregistered
|
||||
* from it.
|
||||
*/
|
||||
void onUnregister(TilesetContentManager& contentManager);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* @brief Called by @ref Tileset when the given tile leaves the
|
||||
* @ref TileLoadState::ContentLoading state but it was loaded with an
|
||||
* older @ref GltfModifier version. The tile will be queued for a call
|
||||
* to @ref apply in a worker thread.
|
||||
*
|
||||
* This method is called from the main thread.
|
||||
*
|
||||
* @param tile The tile that has just left the
|
||||
* @ref TileLoadState::ContentLoading state.
|
||||
*/
|
||||
void onOldVersionContentLoadingComplete(const Tile& tile);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* @brief Called by @ref Tileset when @ref apply has finished running on a
|
||||
* previously-loaded tile. The tile will be queued to finish its loading in
|
||||
* the main thread.
|
||||
*
|
||||
* This method is called from the main thread.
|
||||
*
|
||||
* @param tile The tile that has just been processed by @ref apply.
|
||||
*/
|
||||
void onWorkerThreadApplyComplete(const Tile& tile);
|
||||
|
||||
// TileLoadRequester implementation
|
||||
double getWeight() const override;
|
||||
bool hasMoreTilesToLoadInWorkerThread() const override;
|
||||
const Tile* getNextTileToLoadInWorkerThread() override;
|
||||
bool hasMoreTilesToLoadInMainThread() const override;
|
||||
const Tile* getNextTileToLoadInMainThread() override;
|
||||
|
||||
std::optional<int64_t> _currentVersion;
|
||||
|
||||
const Tile* _pRootTile;
|
||||
|
||||
// Ideally these would be weak pointers, but we don't currently have a good
|
||||
// way to do that.
|
||||
std::vector<Tile::ConstPointer> _workerThreadQueue;
|
||||
std::vector<Tile::ConstPointer> _mainThreadQueue;
|
||||
|
||||
friend class TilesetContentManager;
|
||||
friend class MockTilesetContentManagerForGltfModifier;
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
/** The state of the @ref GltfModifier process for a given tile content's model.
|
||||
*/
|
||||
enum class GltfModifierState {
|
||||
/** Modifier is not currently processing this tile. */
|
||||
Idle,
|
||||
|
||||
/** Worker-thread phase is in progress. */
|
||||
WorkerRunning,
|
||||
|
||||
/**
|
||||
* The worker-thread phase is complete, but the main-thread phase is not done
|
||||
* yet. When the main thread phase eventually runs, it will call @ref
|
||||
* TileRenderContent::replaceWithModifiedModel and then transition the @ref
|
||||
* GltfModifier back to the `Idle` state.
|
||||
*/
|
||||
WorkerDone,
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#include <Cesium3DTilesSelection/Library.h>
|
||||
#include <CesiumUtility/ExtensibleObject.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace CesiumGltf {
|
||||
struct Model;
|
||||
}
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
/** @brief An extension holding the "version" of a glTF produced by
|
||||
* {@link GltfModifier}.
|
||||
*/
|
||||
struct CESIUM3DTILESSELECTION_API GltfModifierVersionExtension
|
||||
: public CesiumUtility::ExtensibleObject {
|
||||
/**
|
||||
* @brief Gets the version number of the given model, or `std::nullopt` if
|
||||
* the model does not have the `GltfModifierVersionExtension` attached to it
|
||||
* yet.
|
||||
*/
|
||||
static std::optional<int64_t>
|
||||
getVersion(const CesiumGltf::Model& model) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the version number of the given model to the given value.
|
||||
*
|
||||
* This method creates the `GltfModifierVersionExtension` and attaches it to
|
||||
* the `Model` if it does not already exist. If it does exist, the
|
||||
* version number is updated.
|
||||
*/
|
||||
static void setVersion(CesiumGltf::Model& model, int64_t version) noexcept;
|
||||
|
||||
/**
|
||||
* @brief The original name of this type.
|
||||
*/
|
||||
static constexpr const char* TypeName = "GltfModifierVersionExtension";
|
||||
/**
|
||||
* @brief The official name of the extension. This should be the same as its
|
||||
* key in the `extensions` object.
|
||||
* */
|
||||
static constexpr const char* ExtensionName =
|
||||
"CESIUM_INTERNAL_gltf_modifier_version";
|
||||
|
||||
/**
|
||||
* @brief The current {@link GltfModifier} version number of the model.
|
||||
*/
|
||||
int64_t version = 0;
|
||||
|
||||
/**
|
||||
* @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(GltfModifierVersionExtension));
|
||||
accum += CesiumUtility::ExtensibleObject::getSizeBytes() -
|
||||
int64_t(sizeof(CesiumUtility::ExtensibleObject));
|
||||
return accum;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
namespace Cesium3DTilesSelection {
|
||||
class TilesetContentLoader;
|
||||
class GltfModifier;
|
||||
|
||||
#ifdef CESIUM_DEBUG_TILE_UNLOADING
|
||||
class TileReferenceCountTracker {
|
||||
|
|
@ -538,18 +539,24 @@ public:
|
|||
/**
|
||||
* @brief Determines if this tile requires worker-thread loading.
|
||||
*
|
||||
* @param pModifier The optional glTF modifier. If not `nullptr`, this method
|
||||
* will return true if the tile needs worker thread glTF modification. See
|
||||
* {@link TilesetExternals::pGltfModifier}.
|
||||
* @return true if this Tile needs further work done in a worker thread to
|
||||
* load it; otherwise, false.
|
||||
*/
|
||||
bool needsWorkerThreadLoading() const noexcept;
|
||||
bool needsWorkerThreadLoading(const GltfModifier* pModifier) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Determines if this tile requires main-thread loading.
|
||||
*
|
||||
* @param pModifier The optional glTF modifier. If not `nullptr`, this method
|
||||
* will return true if the tile needs worker thread glTF modification. See
|
||||
* {@link TilesetExternals::pGltfModifier}.
|
||||
* @return true if this Tile needs further work done in the main thread to
|
||||
* load it; otherwise, false.
|
||||
*/
|
||||
bool needsMainThreadLoading() const noexcept;
|
||||
bool needsMainThreadLoading(const GltfModifier* pModifier) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Adds a reference to this tile. A live reference will keep this tile
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <Cesium3DTilesSelection/GltfModifierState.h>
|
||||
#include <Cesium3DTilesSelection/Library.h>
|
||||
#include <Cesium3DTilesSelection/TilesetMetadata.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
|
|
@ -161,17 +162,19 @@ public:
|
|||
void setCredits(const std::vector<CesiumUtility::Credit>& credits);
|
||||
|
||||
/**
|
||||
* @brief Get the render resources created for the glTF model of the content
|
||||
* @brief Get the renderer resources created for the glTF model of the
|
||||
* content.
|
||||
*
|
||||
* @return The render resources that is created for the glTF model
|
||||
* @return The renderer resources that are created for the glTF model
|
||||
*/
|
||||
void* getRenderResources() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the render resources created for the glTF model of the content
|
||||
* @brief Set the renderer resources created for the glTF model of the
|
||||
* content.
|
||||
*
|
||||
* @param pRenderResources The render resources that is created for the glTF
|
||||
* model
|
||||
* @param pRenderResources The renderer resources that are created for the
|
||||
* glTF model.
|
||||
*/
|
||||
void setRenderResources(void* pRenderResources) noexcept;
|
||||
|
||||
|
|
@ -195,9 +198,67 @@ public:
|
|||
*/
|
||||
void setLodTransitionFadePercentage(float percentage) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the state of the {@link GltfModifier} processing of this
|
||||
* tile's content.
|
||||
* */
|
||||
GltfModifierState getGltfModifierState() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the state of the {@link GltfModifier} processing of this
|
||||
* tile's content.
|
||||
*/
|
||||
void setGltfModifierState(GltfModifierState modifierState) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the modified model produced by the {@link GltfModifier} that is
|
||||
* not yet available for rendering.
|
||||
* */
|
||||
const std::optional<CesiumGltf::Model>& getModifiedModel() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the renderer resources for the modified model produced by the
|
||||
* {@link GltfModifier} that is not yet available for rendering. These resources
|
||||
* are created by {@link IPrepareRendererResources::prepareInLoadThread}.
|
||||
*/
|
||||
void* getModifiedRenderResources() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Stores the modified model and associated renderer resources produced
|
||||
* by the {@link GltfModifier} that are not yet available for rendering. The
|
||||
* renderer resources are created by
|
||||
* {@link IPrepareRendererResources::prepareInLoadThread}.
|
||||
*/
|
||||
void setModifiedModelAndRenderResources(
|
||||
CesiumGltf::Model&& modifiedModel,
|
||||
void* pModifiedRenderResources) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Resets the modified model and renderer resources after they have
|
||||
* been determined to be outdated and have been freed with
|
||||
* {@link IPrepareRendererResources::free}.
|
||||
*/
|
||||
void resetModifiedModelAndRenderResources() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Overwrites this instance's model and renderer resources with the
|
||||
* modified ones produced by {@link GltfModifier}. The new model and
|
||||
* resources become eligible for rendering.
|
||||
*
|
||||
* After this method returns, {@link getModifiedModel} will return
|
||||
* `std::nullopt` and {@link getModifiedRenderResources} will return
|
||||
* `nullptr`.
|
||||
*/
|
||||
void replaceWithModifiedModel() noexcept;
|
||||
|
||||
private:
|
||||
CesiumGltf::Model _model;
|
||||
void* _pRenderResources;
|
||||
|
||||
GltfModifierState _modifierState;
|
||||
std::optional<CesiumGltf::Model> _modifiedModel;
|
||||
void* _pModifiedRenderResources;
|
||||
|
||||
CesiumRasterOverlays::RasterOverlayDetails _rasterOverlayDetails;
|
||||
std::vector<CesiumUtility::Credit> _credits;
|
||||
float _lodTransitionFadePercentage;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,12 @@ public:
|
|||
*/
|
||||
void unregister() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Determines if this requester is currently registered with a
|
||||
* {@link Tileset}.
|
||||
*/
|
||||
bool isRegistered() const noexcept;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructs a new instance.
|
||||
|
|
@ -142,7 +148,7 @@ private:
|
|||
CesiumUtility::IntrusivePointer<TilesetContentManager>
|
||||
_pTilesetContentManager;
|
||||
|
||||
friend class Tileset;
|
||||
friend class TilesetContentManager;
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ struct CESIUM3DTILESSELECTION_API TileLoadResult {
|
|||
/**
|
||||
* @brief The up axis of glTF content.
|
||||
*/
|
||||
CesiumGeometry::Axis glTFUpAxis;
|
||||
CesiumGeometry::Axis glTFUpAxis = CesiumGeometry::Axis::Y;
|
||||
|
||||
/**
|
||||
* @brief A tile can potentially store a more fit bounding volume along with
|
||||
|
|
|
|||
|
|
@ -141,6 +141,12 @@ public:
|
|||
*/
|
||||
void setShowCreditsOnScreen(bool showCreditsOnScreen) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the @ref CesiumUtility::CreditSource that identifies this
|
||||
* tileset's credits with the @ref CesiumUtility::CreditSystem.
|
||||
*/
|
||||
const CesiumUtility::CreditSource& getCreditSource() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the {@link TilesetExternals} that summarize the external
|
||||
* interfaces used by this tileset.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ class CreditSystem;
|
|||
}
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
class IPrepareRendererResources;
|
||||
class GltfModifier;
|
||||
|
||||
/**
|
||||
* @brief External interfaces used by a {@link Tileset}.
|
||||
|
|
@ -76,6 +78,14 @@ public:
|
|||
*/
|
||||
CesiumUtility::IntrusivePointer<TilesetSharedAssetSystem> pSharedAssetSystem =
|
||||
TilesetSharedAssetSystem::getDefault();
|
||||
|
||||
/**
|
||||
* Optional user-controlled tile loading post-processing stage that can modify
|
||||
* the glTF meshes (e.g., split or merge them).
|
||||
*
|
||||
* @see Cesium3DTilesSelection::GltfModifier
|
||||
*/
|
||||
std::shared_ptr<GltfModifier> pGltfModifier = {};
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@
|
|||
#include <CesiumUtility/TreeTraversalState.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
class GltfModifier;
|
||||
class Tile;
|
||||
class Tileset;
|
||||
class TilesetContentManager;
|
||||
|
|
@ -96,8 +98,13 @@ public:
|
|||
* undefined behavior in release builds.
|
||||
*
|
||||
* @param task The tile load task to add to the queue.
|
||||
* @param pModifier The optional glTF modifier. If not `nullptr`, this method
|
||||
* will also add the tile to load queue if it needs glTF modification. See
|
||||
* {@link TilesetExternals::pGltfModifier}.
|
||||
*/
|
||||
void addToLoadQueue(const TileLoadTask& task);
|
||||
void addToLoadQueue(
|
||||
const TileLoadTask& task,
|
||||
const std::shared_ptr<GltfModifier>& pModifier = nullptr);
|
||||
|
||||
/**
|
||||
* @brief A checkpoint within this view group's load queue.
|
||||
|
|
@ -157,8 +164,11 @@ public:
|
|||
size_t getMainThreadLoadQueueLength() const;
|
||||
|
||||
/**
|
||||
* @brief Starts a new frame, clearing the set of tiles to be loaded so that a
|
||||
* new set can be selected.
|
||||
* @brief Starts a new frame.
|
||||
*
|
||||
* This method clears the set of tiles to be loaded so that a new set can be
|
||||
* selected. It also makes the current tile selection state the previous one
|
||||
* and releases references to tiles in the old previous one.
|
||||
*
|
||||
* @param tileset The tileset that is starting the new frame.
|
||||
* @param frameState The state of the new frame.
|
||||
|
|
@ -167,11 +177,9 @@ public:
|
|||
startNewFrame(const Tileset& tileset, const TilesetFrameState& frameState);
|
||||
|
||||
/**
|
||||
* @brief Finishes the current frame by making the current tile selection
|
||||
* state the previous one and releasing references to tiles in the old
|
||||
* previous one.
|
||||
* @brief Finishes the current frame.
|
||||
*
|
||||
* This method also updates the load progress percentage returned by
|
||||
* This method updates the load progress percentage returned by
|
||||
* {@link getPreviousLoadProgressPercentage} and makes sure credits used by
|
||||
* this view group have been referenced on the
|
||||
* {@link CesiumUtility::CreditSystem}.
|
||||
|
|
@ -218,6 +226,24 @@ public:
|
|||
/** @inheritdoc */
|
||||
const Tile* getNextTileToLoadInMainThread() override;
|
||||
|
||||
/**
|
||||
* @brief Checks if a given credit is referenced in the most recently
|
||||
* completed frame.
|
||||
*
|
||||
* Note that this method checks the most recently _completed_ frame. So, after
|
||||
* a call to @ref finishFrame (the common case), this method will check the
|
||||
* frame that was just finished. If called in between calls to @ref
|
||||
* startNewFrame and @ref finishFrame (i.e., during the course of a call to
|
||||
* @ref Tileset::updateViewGroup), it will check the frame prior to the
|
||||
* current, in-progress one, because the current one has not yet been
|
||||
* completed.
|
||||
*
|
||||
* @param credit The credit to test.
|
||||
* @return True if the credit was referenced in this view group's most
|
||||
* recently completed frame.
|
||||
*/
|
||||
bool isCreditReferenced(CesiumUtility::Credit credit) const noexcept;
|
||||
|
||||
private:
|
||||
double _weight = 1.0;
|
||||
std::vector<TileLoadTask> _mainThreadLoadQueue;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
#include "TilesetContentManager.h"
|
||||
|
||||
#include <Cesium3DTilesSelection/GltfModifier.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierState.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierVersionExtension.h>
|
||||
#include <Cesium3DTilesSelection/LoadedTileEnumerator.h>
|
||||
#include <Cesium3DTilesSelection/Tile.h>
|
||||
#include <Cesium3DTilesSelection/TileContent.h>
|
||||
#include <Cesium3DTilesSelection/TileLoadRequester.h>
|
||||
#include <Cesium3DTilesSelection/TilesetExternals.h>
|
||||
#include <CesiumAsync/AsyncSystem.h>
|
||||
#include <CesiumAsync/Future.h>
|
||||
#include <CesiumGltf/Model.h>
|
||||
#include <CesiumUtility/Assert.h>
|
||||
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
GltfModifier::GltfModifier()
|
||||
: _currentVersion(),
|
||||
_pRootTile(nullptr),
|
||||
_workerThreadQueue(),
|
||||
_mainThreadQueue(){};
|
||||
|
||||
GltfModifier::~GltfModifier() = default;
|
||||
|
||||
std::optional<int64_t> GltfModifier::getCurrentVersion() const {
|
||||
return this->_currentVersion;
|
||||
}
|
||||
|
||||
bool GltfModifier::isActive() const {
|
||||
return this->getCurrentVersion().has_value();
|
||||
}
|
||||
|
||||
void GltfModifier::trigger() {
|
||||
if (!this->_currentVersion) {
|
||||
this->_currentVersion = 0;
|
||||
} else {
|
||||
++(*this->_currentVersion);
|
||||
}
|
||||
|
||||
if (!this->isRegistered()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add all already-loaded tiles to this requester's worker thread load queue.
|
||||
// Tiles that are in ContentLoading will be added to this queue when they
|
||||
// finish.
|
||||
LoadedConstTileEnumerator enumerator(this->_pRootTile);
|
||||
for (const Tile& tile : enumerator) {
|
||||
if (this->needsWorkerThreadModification(tile)) {
|
||||
this->_workerThreadQueue.emplace_back(&tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GltfModifier::needsWorkerThreadModification(const Tile& tile) const {
|
||||
std::optional<int64_t> modelVersion = this->getCurrentVersion();
|
||||
if (!modelVersion)
|
||||
return false;
|
||||
|
||||
// If the tile is not loaded at all, there's no need to modify it.
|
||||
if (tile.getState() != TileLoadState::Done &&
|
||||
tile.getState() != TileLoadState::ContentLoaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const TileRenderContent* pRenderContent =
|
||||
tile.getContent().getRenderContent();
|
||||
|
||||
// If a tile has no render content, there's nothing to modify.
|
||||
if (!pRenderContent)
|
||||
return false;
|
||||
|
||||
// We can't modify a tile for which modification is already in progress.
|
||||
if (pRenderContent->getGltfModifierState() ==
|
||||
GltfModifierState::WorkerRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If modification is WorkerDone, and the version is already up-to-date, we
|
||||
// don't need to do it again. But if it's outdated, we want to run the worker
|
||||
// thread modification again.
|
||||
if (pRenderContent->getGltfModifierState() == GltfModifierState::WorkerDone) {
|
||||
const std::optional<CesiumGltf::Model>& maybeModifiedModel =
|
||||
pRenderContent->getModifiedModel();
|
||||
bool hasUpToDateModifiedModel =
|
||||
maybeModifiedModel && GltfModifierVersionExtension::getVersion(
|
||||
*maybeModifiedModel) == modelVersion;
|
||||
return !hasUpToDateModifiedModel;
|
||||
} else {
|
||||
// Worker is idle. Modification is needed if the model version is out of
|
||||
// date.
|
||||
CESIUM_ASSERT(
|
||||
pRenderContent->getGltfModifierState() == GltfModifierState::Idle);
|
||||
bool hasUpToDateModel = GltfModifierVersionExtension::getVersion(
|
||||
pRenderContent->getModel()) == modelVersion;
|
||||
return !hasUpToDateModel;
|
||||
}
|
||||
}
|
||||
|
||||
bool GltfModifier::needsMainThreadModification(const Tile& tile) const {
|
||||
std::optional<int64_t> modelVersion = this->getCurrentVersion();
|
||||
if (!modelVersion)
|
||||
return false;
|
||||
|
||||
// Only tiles already Done loading need main thread modification. For
|
||||
// ContentLoaded, the modified mesh is applied by the normal transition to
|
||||
// Done.
|
||||
if (tile.getState() != TileLoadState::Done)
|
||||
return false;
|
||||
|
||||
// Only tiles with render content can be modified.
|
||||
const TileRenderContent* pRenderContent =
|
||||
tile.getContent().getRenderContent();
|
||||
if (!pRenderContent)
|
||||
return false;
|
||||
|
||||
// We only need to do main thread processing after the worker thread
|
||||
// processing has completed.
|
||||
if (pRenderContent->getGltfModifierState() != GltfModifierState::WorkerDone) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We only need to do main thread processing if there's a modified model.
|
||||
const std::optional<CesiumGltf::Model>& maybeModifiedModel =
|
||||
pRenderContent->getModifiedModel();
|
||||
if (!maybeModifiedModel)
|
||||
return false;
|
||||
|
||||
// If the version of the modified model is wrong (outdated), there's no point
|
||||
// in doing main thread processing. We need to do worker thread processing
|
||||
// again first.
|
||||
if (GltfModifierVersionExtension::getVersion(*maybeModifiedModel) !=
|
||||
modelVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CesiumAsync::Future<void> GltfModifier::onRegister(
|
||||
TilesetContentManager& contentManager,
|
||||
const TilesetMetadata& tilesetMetadata,
|
||||
const Tile& rootTile) {
|
||||
this->_pRootTile = &rootTile;
|
||||
contentManager.registerTileRequester(*this);
|
||||
|
||||
const TilesetExternals& externals = contentManager.getExternals();
|
||||
return this->onRegister(
|
||||
externals.asyncSystem,
|
||||
externals.pAssetAccessor,
|
||||
externals.pLogger,
|
||||
tilesetMetadata,
|
||||
rootTile);
|
||||
}
|
||||
|
||||
void GltfModifier::onUnregister(TilesetContentManager& /* contentManager */) {
|
||||
this->unregister();
|
||||
this->_mainThreadQueue.clear();
|
||||
this->_workerThreadQueue.clear();
|
||||
}
|
||||
|
||||
CesiumAsync::Future<void> GltfModifier::onRegister(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& /* pAssetAccessor */,
|
||||
const std::shared_ptr<spdlog::logger>& /* pLogger */,
|
||||
const TilesetMetadata& /* tilesetMetadata */,
|
||||
const Tile& /* rootTile */) {
|
||||
return asyncSystem.createResolvedFuture();
|
||||
}
|
||||
|
||||
void GltfModifier::onOldVersionContentLoadingComplete(const Tile& tile) {
|
||||
CESIUM_ASSERT(
|
||||
tile.getState() == TileLoadState::ContentLoaded ||
|
||||
tile.getState() == TileLoadState::Failed ||
|
||||
tile.getState() == TileLoadState::FailedTemporarily);
|
||||
if (tile.getState() == TileLoadState::ContentLoaded) {
|
||||
// Tile just transitioned from ContentLoading -> ContentLoaded, but it did
|
||||
// so based on the load version. Add it to the worker thread queue in order
|
||||
// to re-run the GltfModifier on it.
|
||||
if (this->isRegistered() && this->needsWorkerThreadModification(tile)) {
|
||||
this->_workerThreadQueue.emplace_back(&tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GltfModifier::onWorkerThreadApplyComplete(const Tile& tile) {
|
||||
// GltfModifier::apply just finished, so now we need to do the main-thread
|
||||
// processing of the new version. But if the new version is already outdated,
|
||||
// we need to do worker thread modification (again) instead of main thread
|
||||
// modification.
|
||||
if (this->isRegistered()) {
|
||||
if (tile.needsMainThreadLoading(this)) {
|
||||
this->_mainThreadQueue.emplace_back(&tile);
|
||||
} else if (tile.needsWorkerThreadLoading(this)) {
|
||||
this->_workerThreadQueue.emplace_back(&tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double GltfModifier::getWeight() const { return 0.5; }
|
||||
|
||||
bool GltfModifier::hasMoreTilesToLoadInWorkerThread() const {
|
||||
return !this->_workerThreadQueue.empty();
|
||||
}
|
||||
|
||||
const Tile* GltfModifier::getNextTileToLoadInWorkerThread() {
|
||||
CESIUM_ASSERT(!this->_workerThreadQueue.empty());
|
||||
const Tile* pResult = this->_workerThreadQueue.back().get();
|
||||
this->_workerThreadQueue.pop_back();
|
||||
return pResult;
|
||||
}
|
||||
|
||||
bool GltfModifier::hasMoreTilesToLoadInMainThread() const {
|
||||
return !this->_mainThreadQueue.empty();
|
||||
}
|
||||
|
||||
const Tile* GltfModifier::getNextTileToLoadInMainThread() {
|
||||
CESIUM_ASSERT(!this->_mainThreadQueue.empty());
|
||||
const Tile* pResult = this->_mainThreadQueue.back().get();
|
||||
this->_mainThreadQueue.pop_back();
|
||||
return pResult;
|
||||
}
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#include <Cesium3DTilesSelection/GltfModifierVersionExtension.h>
|
||||
#include <CesiumGltf/Model.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
/* static */ std::optional<int64_t> GltfModifierVersionExtension::getVersion(
|
||||
const CesiumGltf::Model& model) noexcept {
|
||||
const auto* pExtension = model.getExtension<GltfModifierVersionExtension>();
|
||||
return pExtension ? std::make_optional(pExtension->version) : std::nullopt;
|
||||
}
|
||||
|
||||
/* static */ void GltfModifierVersionExtension::setVersion(
|
||||
CesiumGltf::Model& model,
|
||||
int64_t version) noexcept {
|
||||
auto* pExtension = model.getExtension<GltfModifierVersionExtension>();
|
||||
if (!pExtension) {
|
||||
pExtension = &model.addExtension<GltfModifierVersionExtension>();
|
||||
}
|
||||
pExtension->version = version;
|
||||
}
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#include "TilesetContentManager.h"
|
||||
|
||||
#include <Cesium3DTilesSelection/GltfModifier.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierVersionExtension.h>
|
||||
#include <Cesium3DTilesSelection/RasterMappedTo3DTile.h>
|
||||
#include <Cesium3DTilesSelection/Tile.h>
|
||||
#include <Cesium3DTilesSelection/TileContent.h>
|
||||
|
|
@ -18,6 +20,7 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -271,16 +274,34 @@ bool anyRasterOverlaysNeedLoading(const Tile& tile) noexcept {
|
|||
|
||||
} // namespace
|
||||
|
||||
bool Tile::needsWorkerThreadLoading() const noexcept {
|
||||
TileLoadState state = this->getState();
|
||||
return state == TileLoadState::Unloaded ||
|
||||
state == TileLoadState::FailedTemporarily ||
|
||||
anyRasterOverlaysNeedLoading(*this);
|
||||
bool Tile::needsWorkerThreadLoading(
|
||||
const GltfModifier* pModifier) const noexcept {
|
||||
if (this->getState() == TileLoadState::Unloaded ||
|
||||
this->getState() == TileLoadState::FailedTemporarily)
|
||||
return true;
|
||||
|
||||
if (pModifier && pModifier->needsWorkerThreadModification(*this))
|
||||
return true;
|
||||
|
||||
if (anyRasterOverlaysNeedLoading(*this))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Tile::needsMainThreadLoading() const noexcept {
|
||||
return this->getState() == TileLoadState::ContentLoaded &&
|
||||
this->isRenderContent();
|
||||
bool Tile::needsMainThreadLoading(
|
||||
const GltfModifier* pModifier) const noexcept {
|
||||
// Only render content needs main thread loading.
|
||||
if (!this->isRenderContent())
|
||||
return false;
|
||||
|
||||
if (this->getState() == TileLoadState::ContentLoaded)
|
||||
return true;
|
||||
|
||||
if (pModifier && pModifier->needsMainThreadModification(*this))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Tile::setParent(Tile* pParent) noexcept {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#include <Cesium3DTilesSelection/GltfModifierState.h>
|
||||
#include <Cesium3DTilesSelection/TileContent.h>
|
||||
#include <CesiumGltf/Model.h>
|
||||
#include <CesiumUtility/Assert.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
|
@ -14,22 +17,69 @@ namespace Cesium3DTilesSelection {
|
|||
TileRenderContent::TileRenderContent(CesiumGltf::Model&& model)
|
||||
: _model{std::move(model)},
|
||||
_pRenderResources{nullptr},
|
||||
_modifierState{GltfModifierState::Idle},
|
||||
_modifiedModel{},
|
||||
_pModifiedRenderResources(nullptr),
|
||||
_rasterOverlayDetails{},
|
||||
_credits{},
|
||||
_lodTransitionFadePercentage{0.0f} {}
|
||||
|
||||
const CesiumGltf::Model& TileRenderContent::getModel() const noexcept {
|
||||
return _model;
|
||||
return this->_model;
|
||||
}
|
||||
|
||||
CesiumGltf::Model& TileRenderContent::getModel() noexcept { return _model; }
|
||||
CesiumGltf::Model& TileRenderContent::getModel() noexcept {
|
||||
return this->_model;
|
||||
}
|
||||
|
||||
void TileRenderContent::setModel(const CesiumGltf::Model& model) {
|
||||
_model = model;
|
||||
this->_model = model;
|
||||
}
|
||||
|
||||
void TileRenderContent::setModel(CesiumGltf::Model&& model) {
|
||||
_model = std::move(model);
|
||||
this->_model = std::move(model);
|
||||
}
|
||||
|
||||
GltfModifierState TileRenderContent::getGltfModifierState() const noexcept {
|
||||
return this->_modifierState;
|
||||
}
|
||||
|
||||
void TileRenderContent::setGltfModifierState(
|
||||
GltfModifierState modifierState) noexcept {
|
||||
this->_modifierState = modifierState;
|
||||
}
|
||||
|
||||
const std::optional<CesiumGltf::Model>&
|
||||
TileRenderContent::getModifiedModel() const noexcept {
|
||||
return this->_modifiedModel;
|
||||
}
|
||||
|
||||
void TileRenderContent::setModifiedModelAndRenderResources(
|
||||
CesiumGltf::Model&& modifiedModel,
|
||||
void* pModifiedRenderResources) noexcept {
|
||||
this->_modifiedModel = std::move(modifiedModel);
|
||||
this->_pModifiedRenderResources = pModifiedRenderResources;
|
||||
}
|
||||
|
||||
void* TileRenderContent::getModifiedRenderResources() const noexcept {
|
||||
return this->_pModifiedRenderResources;
|
||||
}
|
||||
|
||||
void TileRenderContent::resetModifiedModelAndRenderResources() noexcept {
|
||||
this->_pModifiedRenderResources = nullptr;
|
||||
this->_modifiedModel.reset();
|
||||
}
|
||||
|
||||
void TileRenderContent::replaceWithModifiedModel() noexcept {
|
||||
CESIUM_ASSERT(this->_modifiedModel);
|
||||
if (this->_modifiedModel) {
|
||||
this->_model = std::move(*this->_modifiedModel);
|
||||
// reset after move because this is tested for nullopt in
|
||||
// Tile::needsWorkerThreadLoading:
|
||||
this->_modifiedModel.reset();
|
||||
this->_pRenderResources = this->_pModifiedRenderResources;
|
||||
this->_pModifiedRenderResources = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const RasterOverlayDetails&
|
||||
|
|
@ -92,20 +142,20 @@ TileContent::TileContent(std::unique_ptr<TileExternalContent>&& content)
|
|||
: _contentKind{std::move(content)} {}
|
||||
|
||||
void TileContent::setContentKind(TileUnknownContent content) {
|
||||
_contentKind = content;
|
||||
this->_contentKind = content;
|
||||
}
|
||||
|
||||
void TileContent::setContentKind(TileEmptyContent content) {
|
||||
_contentKind = content;
|
||||
this->_contentKind = content;
|
||||
}
|
||||
|
||||
void TileContent::setContentKind(
|
||||
std::unique_ptr<TileExternalContent>&& content) {
|
||||
_contentKind = std::move(content);
|
||||
this->_contentKind = std::move(content);
|
||||
}
|
||||
|
||||
void TileContent::setContentKind(std::unique_ptr<TileRenderContent>&& content) {
|
||||
_contentKind = std::move(content);
|
||||
this->_contentKind = std::move(content);
|
||||
}
|
||||
|
||||
bool TileContent::isUnknownContent() const noexcept {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ void TileLoadRequester::unregister() noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
bool TileLoadRequester::isRegistered() const noexcept {
|
||||
return this->_pTilesetContentManager != nullptr;
|
||||
}
|
||||
|
||||
TileLoadRequester::TileLoadRequester() noexcept
|
||||
: _pTilesetContentManager(nullptr) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,10 @@ void Tileset::setShowCreditsOnScreen(bool showCreditsOnScreen) noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
const CesiumUtility::CreditSource& Tileset::getCreditSource() const noexcept {
|
||||
return this->_pTilesetContentManager->getCreditSource();
|
||||
}
|
||||
|
||||
const Tile* Tileset::getRootTile() const noexcept {
|
||||
return this->_pTilesetContentManager->getRootTile();
|
||||
}
|
||||
|
|
@ -468,18 +472,7 @@ void Tileset::loadTiles() {
|
|||
}
|
||||
|
||||
void Tileset::registerLoadRequester(TileLoadRequester& requester) {
|
||||
if (requester._pTilesetContentManager == this->_pTilesetContentManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requester._pTilesetContentManager != nullptr) {
|
||||
requester._pTilesetContentManager->unregisterTileRequester(requester);
|
||||
}
|
||||
|
||||
requester._pTilesetContentManager = this->_pTilesetContentManager;
|
||||
if (requester._pTilesetContentManager != nullptr) {
|
||||
requester._pTilesetContentManager->registerTileRequester(requester);
|
||||
}
|
||||
this->_pTilesetContentManager->registerTileRequester(requester);
|
||||
}
|
||||
|
||||
int32_t Tileset::getNumberOfTilesLoaded() const {
|
||||
|
|
@ -1115,6 +1108,24 @@ bool Tileset::_kickDescendantsAndRenderTile(
|
|||
selectionState.kick();
|
||||
});
|
||||
|
||||
// If any kicked tiles were rendered last frame, add them to the
|
||||
// tilesFadingOut. This is unlikely! It would imply that a tile rendered last
|
||||
// frame has suddenly become unrenderable, and therefore eligible for kicking.
|
||||
//
|
||||
// In general, it's possible that a Tile previously traversed has been deleted
|
||||
// completely, so we have to be careful about dereferencing the Tile pointers
|
||||
// given to the callback below. However, we can be certain that a Tile that
|
||||
// was rendered last frame has _not_ been deleted yet.
|
||||
traversalState.forEachPreviousDescendant(
|
||||
[&result](
|
||||
const Tile::Pointer& pTile,
|
||||
const TileSelectionState& previousState) {
|
||||
addToTilesFadingOutIfPreviouslyRendered(
|
||||
previousState.getResult(),
|
||||
*pTile,
|
||||
result);
|
||||
});
|
||||
|
||||
// Remove all descendants from the render list and add this tile.
|
||||
std::vector<Tile::ConstPointer>& renderList = result.tilesToRenderThisFrame;
|
||||
renderList.erase(
|
||||
|
|
@ -1140,8 +1151,8 @@ bool Tileset::_kickDescendantsAndRenderTile(
|
|||
getPreviousState(frameState.viewGroup, tile).getResult();
|
||||
const bool wasRenderedLastFrame =
|
||||
lastFrameSelectionState == TileSelectionState::Result::Rendered;
|
||||
const bool wasReallyRenderedLastFrame =
|
||||
wasRenderedLastFrame && tile.isRenderable();
|
||||
const bool isRenderable = tile.isRenderable();
|
||||
const bool wasReallyRenderedLastFrame = wasRenderedLastFrame && isRenderable;
|
||||
|
||||
if (!wasReallyRenderedLastFrame &&
|
||||
traversalDetails.notYetRenderableCount >
|
||||
|
|
@ -1165,10 +1176,8 @@ bool Tileset::_kickDescendantsAndRenderTile(
|
|||
queuedForLoad = true;
|
||||
}
|
||||
|
||||
bool isRenderable = tile.isRenderable();
|
||||
traversalDetails.allAreRenderable = isRenderable;
|
||||
traversalDetails.anyWereRenderedLastFrame =
|
||||
isRenderable && wasRenderedLastFrame;
|
||||
traversalDetails.anyWereRenderedLastFrame = wasReallyRenderedLastFrame;
|
||||
|
||||
return queuedForLoad;
|
||||
}
|
||||
|
|
@ -1515,7 +1524,8 @@ void Tileset::addTileToLoadQueue(
|
|||
TileLoadPriorityGroup priorityGroup,
|
||||
double priority) {
|
||||
frameState.viewGroup.addToLoadQueue(
|
||||
TileLoadTask{&tile, priorityGroup, priority});
|
||||
TileLoadTask{&tile, priorityGroup, priority},
|
||||
this->_externals.pGltfModifier);
|
||||
}
|
||||
|
||||
Tileset::TraversalDetails Tileset::createTraversalDetailsForSingleTile(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#include "TilesetJsonLoader.h"
|
||||
|
||||
#include <Cesium3DTilesSelection/BoundingVolume.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifier.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierState.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierVersionExtension.h>
|
||||
#include <Cesium3DTilesSelection/IPrepareRendererResources.h>
|
||||
#include <Cesium3DTilesSelection/RasterMappedTo3DTile.h>
|
||||
#include <Cesium3DTilesSelection/RasterOverlayCollection.h>
|
||||
|
|
@ -45,6 +48,7 @@
|
|||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayUtilities.h>
|
||||
#include <CesiumUtility/Assert.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/Math.h>
|
||||
#include <CesiumUtility/ReferenceCounted.h>
|
||||
|
|
@ -71,6 +75,7 @@
|
|||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
|
@ -555,7 +560,8 @@ postProcessContentInWorkerThread(
|
|||
TileLoadResult&& result,
|
||||
std::vector<CesiumGeospatial::Projection>&& projections,
|
||||
TileContentLoadInfo&& tileLoadInfo,
|
||||
const std::any& rendererOptions) {
|
||||
const std::any& rendererOptions,
|
||||
const std::shared_ptr<GltfModifier>& pGltfModifier) {
|
||||
CESIUM_ASSERT(
|
||||
result.state == TileLoadResultState::Success &&
|
||||
"This function requires result to be success");
|
||||
|
|
@ -581,6 +587,9 @@ postProcessContentInWorkerThread(
|
|||
gltfOptions.pSharedAssetSystem = tileLoadInfo.pSharedAssetSystem;
|
||||
}
|
||||
|
||||
std::optional<int64_t> version =
|
||||
pGltfModifier ? pGltfModifier->getCurrentVersion() : std::nullopt;
|
||||
|
||||
auto asyncSystem = tileLoadInfo.asyncSystem;
|
||||
auto pAssetAccessor = result.pAssetAccessor;
|
||||
return CesiumGltfReader::GltfReader::resolveExternalData(
|
||||
|
|
@ -593,8 +602,9 @@ postProcessContentInWorkerThread(
|
|||
.thenInWorkerThread([result = std::move(result),
|
||||
projections = std::move(projections),
|
||||
tileLoadInfo = std::move(tileLoadInfo),
|
||||
rendererOptions](CesiumGltfReader::GltfReaderResult&&
|
||||
gltfResult) mutable {
|
||||
version,
|
||||
pGltfModifier](CesiumGltfReader::GltfReaderResult&&
|
||||
gltfResult) mutable {
|
||||
if (!gltfResult.errors.empty()) {
|
||||
if (result.pCompletedRequest) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
|
|
@ -627,12 +637,11 @@ postProcessContentInWorkerThread(
|
|||
}
|
||||
|
||||
if (!gltfResult.model) {
|
||||
return tileLoadInfo.asyncSystem.createResolvedFuture(
|
||||
TileLoadResultAndRenderResources{
|
||||
TileLoadResult::createFailedResult(
|
||||
result.pAssetAccessor,
|
||||
nullptr),
|
||||
nullptr});
|
||||
return tileLoadInfo.asyncSystem
|
||||
.createResolvedFuture(TileLoadResult::createFailedResult(
|
||||
result.pAssetAccessor,
|
||||
nullptr))
|
||||
.thenPassThrough(std::move(tileLoadInfo));
|
||||
}
|
||||
|
||||
result.contentKind = std::move(*gltfResult.model);
|
||||
|
|
@ -645,6 +654,51 @@ postProcessContentInWorkerThread(
|
|||
std::move(projections),
|
||||
tileLoadInfo);
|
||||
|
||||
if (pGltfModifier && version) {
|
||||
// Apply the glTF modifier right away, otherwise it will be
|
||||
// triggered immediately after the renderer-side resources
|
||||
// have been created, which is both inefficient and a cause
|
||||
// of visual glitches (the model will appear briefly in its
|
||||
// unmodified state before stabilizing)
|
||||
const CesiumGltf::Model& model =
|
||||
std::get<CesiumGltf::Model>(result.contentKind);
|
||||
return pGltfModifier
|
||||
->apply(GltfModifierInput{
|
||||
.version = *version,
|
||||
.asyncSystem = tileLoadInfo.asyncSystem,
|
||||
.pAssetAccessor = tileLoadInfo.pAssetAccessor,
|
||||
.pLogger = tileLoadInfo.pLogger,
|
||||
.previousModel = model,
|
||||
.tileTransform = tileLoadInfo.tileTransform})
|
||||
.thenInWorkerThread(
|
||||
[result = std::move(result), version](
|
||||
std::optional<GltfModifierOutput>&& modified) mutable {
|
||||
if (modified) {
|
||||
result.contentKind = std::move(modified->modifiedModel);
|
||||
}
|
||||
|
||||
CesiumGltf::Model* pModel =
|
||||
std::get_if<CesiumGltf::Model>(&result.contentKind);
|
||||
if (pModel) {
|
||||
GltfModifierVersionExtension::setVersion(
|
||||
*pModel,
|
||||
*version);
|
||||
}
|
||||
|
||||
return result;
|
||||
})
|
||||
.thenPassThrough(std::move(tileLoadInfo));
|
||||
} else {
|
||||
return tileLoadInfo.asyncSystem
|
||||
.createResolvedFuture(std::move(result))
|
||||
.thenPassThrough(std::move(tileLoadInfo));
|
||||
}
|
||||
})
|
||||
.thenInWorkerThread([rendererOptions](
|
||||
std::tuple<TileContentLoadInfo, TileLoadResult>&&
|
||||
tuple) {
|
||||
auto& [tileLoadInfo, result] = tuple;
|
||||
|
||||
// create render resources
|
||||
if (tileLoadInfo.pPrepareRendererResources) {
|
||||
return tileLoadInfo.pPrepareRendererResources->prepareInLoadThread(
|
||||
|
|
@ -659,6 +713,20 @@ postProcessContentInWorkerThread(
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<Credit> createUserCredit(
|
||||
const TilesetOptions& tilesetOptions,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const CreditSource& creditSource) {
|
||||
if (!tilesetOptions.credit || !pCreditSystem)
|
||||
return std::nullopt;
|
||||
|
||||
return pCreditSystem->createCredit(
|
||||
creditSource,
|
||||
*tilesetOptions.credit,
|
||||
tilesetOptions.showCreditsOnScreen);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TilesetContentManager::TilesetContentManager(
|
||||
|
|
@ -669,13 +737,8 @@ TilesetContentManager::TilesetContentManager(
|
|||
: _externals{externals},
|
||||
_requestHeaders{tilesetOptions.requestHeaders},
|
||||
_pLoader{std::move(pLoader)},
|
||||
_pRootTile{std::move(pRootTile)},
|
||||
_userCredit(
|
||||
(tilesetOptions.credit && externals.pCreditSystem)
|
||||
? std::optional<Credit>(externals.pCreditSystem->createCredit(
|
||||
tilesetOptions.credit.value(),
|
||||
tilesetOptions.showCreditsOnScreen))
|
||||
: std::nullopt),
|
||||
_pRootTile{nullptr},
|
||||
_userCredit(),
|
||||
_tilesetCredits{},
|
||||
_overlayCollection(
|
||||
LoadedTileEnumerator(pRootTile.get()),
|
||||
|
|
@ -697,14 +760,27 @@ TilesetContentManager::TilesetContentManager(
|
|||
_roundRobinValueWorker(0.0),
|
||||
_roundRobinValueMain(0.0),
|
||||
_requesterFractions(),
|
||||
_requestersWithRequests() {
|
||||
_requestersWithRequests(),
|
||||
_creditSource(externals.pCreditSystem) {
|
||||
CESIUM_ASSERT(this->_pLoader != nullptr);
|
||||
|
||||
this->_userCredit = createUserCredit(
|
||||
tilesetOptions,
|
||||
externals.pCreditSystem,
|
||||
this->_creditSource);
|
||||
this->_upsampler.setOwner(*this);
|
||||
|
||||
CESIUM_ASSERT(this->_pLoader != nullptr);
|
||||
this->_overlayCollection.setLoadedTileEnumerator(
|
||||
LoadedTileEnumerator(this->_pRootTile.get()));
|
||||
this->_pLoader->setOwner(*this);
|
||||
this->_rootTileAvailablePromise.resolve();
|
||||
this->notifyTileStartLoading(nullptr);
|
||||
|
||||
this->registerGltfModifier(pRootTile.get())
|
||||
.thenInMainThread([this, pRootTile = std::move(pRootTile)]() mutable {
|
||||
this->_pRootTile = std::move(pRootTile);
|
||||
this->_overlayCollection.setLoadedTileEnumerator(
|
||||
LoadedTileEnumerator(this->_pRootTile.get()));
|
||||
this->_pLoader->setOwner(*this);
|
||||
this->_rootTileAvailablePromise.resolve();
|
||||
this->notifyTileDoneLoading(this->_pRootTile.get());
|
||||
});
|
||||
}
|
||||
|
||||
TilesetContentManager::TilesetContentManager(
|
||||
|
|
@ -715,12 +791,7 @@ TilesetContentManager::TilesetContentManager(
|
|||
_requestHeaders{tilesetOptions.requestHeaders},
|
||||
_pLoader{},
|
||||
_pRootTile{},
|
||||
_userCredit(
|
||||
(tilesetOptions.credit && externals.pCreditSystem)
|
||||
? std::optional<Credit>(externals.pCreditSystem->createCredit(
|
||||
tilesetOptions.credit.value(),
|
||||
tilesetOptions.showCreditsOnScreen))
|
||||
: std::nullopt),
|
||||
_userCredit(),
|
||||
_tilesetCredits{},
|
||||
_overlayCollection(
|
||||
LoadedTileEnumerator(nullptr),
|
||||
|
|
@ -742,7 +813,13 @@ TilesetContentManager::TilesetContentManager(
|
|||
_roundRobinValueWorker(0.0),
|
||||
_roundRobinValueMain(0.0),
|
||||
_requesterFractions(),
|
||||
_requestersWithRequests() {
|
||||
_requestersWithRequests(),
|
||||
_creditSource(externals.pCreditSystem) {
|
||||
this->_userCredit = createUserCredit(
|
||||
tilesetOptions,
|
||||
externals.pCreditSystem,
|
||||
this->_creditSource);
|
||||
|
||||
this->_upsampler.setOwner(*this);
|
||||
|
||||
if (!url.empty()) {
|
||||
|
|
@ -846,6 +923,13 @@ TilesetContentManager::TilesetContentManager(
|
|||
return asyncSystem.createResolvedFuture(std::move(result));
|
||||
}
|
||||
})
|
||||
.thenInMainThread(
|
||||
[thiz](TilesetContentLoaderResult<TilesetContentLoader>&& result) {
|
||||
return thiz->registerGltfModifier(result.pRootTile.get())
|
||||
.thenImmediately([result = std::move(result)]() mutable {
|
||||
return std::move(result);
|
||||
});
|
||||
})
|
||||
.thenInMainThread(
|
||||
[thiz, errorCallback = tilesetOptions.loadErrorCallback](
|
||||
TilesetContentLoaderResult<TilesetContentLoader>&& result) {
|
||||
|
|
@ -876,12 +960,7 @@ TilesetContentManager::TilesetContentManager(
|
|||
_requestHeaders{tilesetOptions.requestHeaders},
|
||||
_pLoader{},
|
||||
_pRootTile{},
|
||||
_userCredit(
|
||||
(tilesetOptions.credit && externals.pCreditSystem)
|
||||
? std::optional<Credit>(externals.pCreditSystem->createCredit(
|
||||
tilesetOptions.credit.value(),
|
||||
tilesetOptions.showCreditsOnScreen))
|
||||
: std::nullopt),
|
||||
_userCredit(),
|
||||
_tilesetCredits{},
|
||||
_overlayCollection(
|
||||
LoadedTileEnumerator(nullptr),
|
||||
|
|
@ -903,7 +982,13 @@ TilesetContentManager::TilesetContentManager(
|
|||
_roundRobinValueWorker(0.0),
|
||||
_roundRobinValueMain(0.0),
|
||||
_requesterFractions(),
|
||||
_requestersWithRequests() {
|
||||
_requestersWithRequests(),
|
||||
_creditSource(externals.pCreditSystem) {
|
||||
this->_userCredit = createUserCredit(
|
||||
tilesetOptions,
|
||||
externals.pCreditSystem,
|
||||
this->_creditSource);
|
||||
|
||||
this->_upsampler.setOwner(*this);
|
||||
|
||||
if (loaderFactory.isValid()) {
|
||||
|
|
@ -928,6 +1013,13 @@ TilesetContentManager::TilesetContentManager(
|
|||
|
||||
loaderFactory
|
||||
.createLoader(externals, tilesetOptions, authorizationChangeListener)
|
||||
.thenInMainThread(
|
||||
[thiz](TilesetContentLoaderResult<TilesetContentLoader>&& result) {
|
||||
return thiz->registerGltfModifier(result.pRootTile.get())
|
||||
.thenImmediately([result = std::move(result)]() mutable {
|
||||
return std::move(result);
|
||||
});
|
||||
})
|
||||
.thenInMainThread(
|
||||
[thiz, errorCallback = tilesetOptions.loadErrorCallback](
|
||||
TilesetContentLoaderResult<TilesetContentLoader>&& result) {
|
||||
|
|
@ -981,11 +1073,203 @@ TilesetContentManager::~TilesetContentManager() noexcept {
|
|||
this->_destructionCompletePromise.resolve();
|
||||
}
|
||||
|
||||
void TilesetContentManager::reapplyGltfModifier(
|
||||
Tile& tile,
|
||||
const TilesetOptions& tilesetOptions,
|
||||
TileRenderContent* pRenderContent) noexcept {
|
||||
// An existing modified model must be the wrong version (or we wouldn't be
|
||||
// here), so discard it.
|
||||
if (pRenderContent->getModifiedModel()) {
|
||||
CESIUM_ASSERT(
|
||||
pRenderContent->getGltfModifierState() ==
|
||||
GltfModifierState::WorkerDone);
|
||||
this->_externals.pPrepareRendererResources->free(
|
||||
tile,
|
||||
pRenderContent->getModifiedRenderResources(),
|
||||
nullptr);
|
||||
pRenderContent->resetModifiedModelAndRenderResources();
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::Idle);
|
||||
}
|
||||
|
||||
this->notifyTileStartLoading(&tile);
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::WorkerRunning);
|
||||
|
||||
const CesiumGltf::Model& previousModel = pRenderContent->getModel();
|
||||
|
||||
const TilesetExternals& externals = this->getExternals();
|
||||
|
||||
// Get the version here, in the main thread, because it may change while the
|
||||
// worker is running.
|
||||
CESIUM_ASSERT(externals.pGltfModifier->getCurrentVersion());
|
||||
int64_t version = externals.pGltfModifier->getCurrentVersion().value_or(-1);
|
||||
|
||||
// It is safe to capture the TilesetExternals and Model by reference because
|
||||
// the TilesetContentManager guarantees both will continue to exist and are
|
||||
// immutable while modification is in progress.
|
||||
//
|
||||
// This is largely true of Tile as well, except that Tiles are nodes in a
|
||||
// larger graph, and the entire graph is _not_ guaranteed to be immutable. So
|
||||
// best to avoid handing a `Tile` instance to a worker thread.
|
||||
//
|
||||
// We capture an IntrusivePointer to a Tile in the main thread continuations
|
||||
// at the end in order to keep the Tile, its content, and the
|
||||
// TilesetContentManager alive during the entire process.
|
||||
externals.asyncSystem
|
||||
.runInWorkerThread([&externals,
|
||||
&previousModel,
|
||||
version,
|
||||
tileTransform = tile.getTransform()] {
|
||||
return externals.pGltfModifier->apply(GltfModifierInput{
|
||||
.version = version,
|
||||
.asyncSystem = externals.asyncSystem,
|
||||
.pAssetAccessor = externals.pAssetAccessor,
|
||||
.pLogger = externals.pLogger,
|
||||
.previousModel = previousModel,
|
||||
.tileTransform = tileTransform});
|
||||
})
|
||||
.thenInWorkerThread([&externals,
|
||||
&previousModel,
|
||||
pRenderContent,
|
||||
tileTransform = tile.getTransform(),
|
||||
tileBoundingVolume = tile.getBoundingVolume(),
|
||||
tileContentBoundingVolume =
|
||||
tile.getContentBoundingVolume(),
|
||||
rendererOptions = tilesetOptions.rendererOptions](
|
||||
std::optional<GltfModifierOutput>&& modified) {
|
||||
TileLoadResult tileLoadResult;
|
||||
tileLoadResult.state = TileLoadResultState::Success;
|
||||
tileLoadResult.pAssetAccessor = externals.pAssetAccessor;
|
||||
tileLoadResult.rasterOverlayDetails =
|
||||
pRenderContent->getRasterOverlayDetails();
|
||||
tileLoadResult.initialBoundingVolume = tileBoundingVolume;
|
||||
tileLoadResult.initialContentBoundingVolume = tileContentBoundingVolume;
|
||||
|
||||
{
|
||||
const CesiumGltf::Model& model =
|
||||
modified ? modified->modifiedModel : previousModel;
|
||||
const auto it = model.extras.find("gltfUpAxis");
|
||||
if (it != model.extras.end()) {
|
||||
tileLoadResult.glTFUpAxis = static_cast<CesiumGeometry::Axis>(
|
||||
it->second.getSafeNumberOrDefault(1));
|
||||
}
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
tileLoadResult.contentKind = std::move(modified->modifiedModel);
|
||||
} else {
|
||||
tileLoadResult.contentKind = previousModel;
|
||||
}
|
||||
|
||||
if (modified && externals.pPrepareRendererResources) {
|
||||
return externals.pPrepareRendererResources->prepareInLoadThread(
|
||||
externals.asyncSystem,
|
||||
std::move(tileLoadResult),
|
||||
tileTransform,
|
||||
rendererOptions);
|
||||
} else {
|
||||
return externals.asyncSystem
|
||||
.createResolvedFuture<TileLoadResultAndRenderResources>(
|
||||
TileLoadResultAndRenderResources{
|
||||
std::move(tileLoadResult),
|
||||
nullptr});
|
||||
}
|
||||
})
|
||||
.thenInMainThread([this, version, pTile = Tile::Pointer(&tile)](
|
||||
TileLoadResultAndRenderResources&& pair) {
|
||||
TileRenderContent* pRenderContent =
|
||||
pTile->getContent().getRenderContent();
|
||||
CESIUM_ASSERT(pRenderContent != nullptr);
|
||||
|
||||
this->notifyTileDoneLoading(pTile.get());
|
||||
|
||||
if (std::holds_alternative<TileUnknownContent>(
|
||||
pair.result.contentKind)) {
|
||||
// GltfModifier did not actually modify the model.
|
||||
pRenderContent->resetModifiedModelAndRenderResources();
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::Idle);
|
||||
|
||||
// Even though the GltfModifier chose not to modify anything, the
|
||||
// model is now up-to-date with the version that triggered this run.
|
||||
GltfModifierVersionExtension::setVersion(
|
||||
pRenderContent->getModel(),
|
||||
version);
|
||||
} else if (pTile->getState() == TileLoadState::ContentLoaded) {
|
||||
// This Tile is in the ContentLoaded state, which means that it was
|
||||
// (partially) loaded before the GltfModifier triggered to the current
|
||||
// version. In that case, we need to free the previous renderer
|
||||
// resources but can then send the tile through the rest of the normal
|
||||
// pipeline. We know a Tile in the ContentLoaded state isn't already
|
||||
// being rendered.
|
||||
if (this->_externals.pPrepareRendererResources) {
|
||||
this->_externals.pPrepareRendererResources->free(
|
||||
*pTile,
|
||||
pRenderContent->getRenderResources(),
|
||||
nullptr);
|
||||
}
|
||||
pRenderContent->setModel(
|
||||
std::move(std::get<CesiumGltf::Model>(pair.result.contentKind)));
|
||||
pRenderContent->setRenderResources(pair.pRenderResources);
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::Idle);
|
||||
|
||||
// The model is now up-to-date with the version that triggered this
|
||||
// run.
|
||||
GltfModifierVersionExtension::setVersion(
|
||||
pRenderContent->getModel(),
|
||||
version);
|
||||
} else {
|
||||
// This is a reapply of the GltfModifier to an already loaded and
|
||||
// potentially rendered tile.
|
||||
CESIUM_ASSERT(pTile->getState() == TileLoadState::Done);
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::WorkerDone);
|
||||
|
||||
// The modified model is up-to-date with the version that triggered
|
||||
// this run.
|
||||
CesiumGltf::Model& modifiedModel =
|
||||
std::get<CesiumGltf::Model>(pair.result.contentKind);
|
||||
GltfModifierVersionExtension::setVersion(modifiedModel, version);
|
||||
|
||||
pRenderContent->setModifiedModelAndRenderResources(
|
||||
std::move(modifiedModel),
|
||||
pair.pRenderResources);
|
||||
this->_externals.pGltfModifier->onWorkerThreadApplyComplete(*pTile);
|
||||
}
|
||||
})
|
||||
.catchInMainThread(
|
||||
[this, pTile = Tile::Pointer(&tile), &externals, version](
|
||||
std::exception&& e) {
|
||||
pTile->getContent().getRenderContent()->setGltfModifierState(
|
||||
GltfModifierState::WorkerDone);
|
||||
this->notifyTileDoneLoading(pTile.get());
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
externals.pLogger,
|
||||
"An unexpected error occurred when reapplying GltfModifier: {}",
|
||||
e.what());
|
||||
|
||||
// Even though the GltfModifier failed, we mark the model up-to-date
|
||||
// with the version that triggered this run so that we won't try to
|
||||
// run again for this version.
|
||||
TileRenderContent* pRenderContent =
|
||||
pTile->getContent().getRenderContent();
|
||||
CESIUM_ASSERT(pRenderContent != nullptr);
|
||||
GltfModifierVersionExtension::setVersion(
|
||||
pRenderContent->getModel(),
|
||||
version);
|
||||
});
|
||||
}
|
||||
|
||||
void TilesetContentManager::loadTileContent(
|
||||
Tile& tile,
|
||||
const TilesetOptions& tilesetOptions) {
|
||||
CESIUM_TRACE("TilesetContentManager::loadTileContent");
|
||||
|
||||
if (this->_externals.pGltfModifier &&
|
||||
this->_externals.pGltfModifier->needsWorkerThreadModification(tile)) {
|
||||
TileRenderContent* pRenderContent = tile.getContent().getRenderContent();
|
||||
CESIUM_ASSERT(pRenderContent != nullptr);
|
||||
this->reapplyGltfModifier(tile, tilesetOptions, pRenderContent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tile.getState() == TileLoadState::Unloading) {
|
||||
// We can't load a tile that is unloading; it has to finish unloading first.
|
||||
return;
|
||||
|
|
@ -1079,9 +1363,13 @@ void TilesetContentManager::loadTileContent(
|
|||
CesiumUtility::IntrusivePointer<TilesetContentManager> thiz = this;
|
||||
|
||||
pLoader->loadTileContent(loadInput)
|
||||
.thenImmediately([tileLoadInfo = std::move(tileLoadInfo),
|
||||
.thenImmediately([asyncSystem = this->_externals.asyncSystem,
|
||||
pAssetAccessor = this->_externals.pAssetAccessor,
|
||||
pLogger = this->_externals.pLogger,
|
||||
tileLoadInfo = std::move(tileLoadInfo),
|
||||
projections = std::move(projections),
|
||||
rendererOptions = tilesetOptions.rendererOptions](
|
||||
rendererOptions = tilesetOptions.rendererOptions,
|
||||
pGltfModifier = _externals.pGltfModifier](
|
||||
TileLoadResult&& result) mutable {
|
||||
// the reason we run immediate continuation, instead of in the
|
||||
// worker thread, is that the loader may run the task in the main
|
||||
|
|
@ -1092,17 +1380,18 @@ void TilesetContentManager::loadTileContent(
|
|||
// worker thread if the content is a render content
|
||||
if (result.state == TileLoadResultState::Success) {
|
||||
if (std::holds_alternative<CesiumGltf::Model>(result.contentKind)) {
|
||||
auto asyncSystem = tileLoadInfo.asyncSystem;
|
||||
return asyncSystem.runInWorkerThread(
|
||||
[result = std::move(result),
|
||||
projections = std::move(projections),
|
||||
tileLoadInfo = std::move(tileLoadInfo),
|
||||
rendererOptions]() mutable {
|
||||
rendererOptions,
|
||||
pGltfModifier]() mutable {
|
||||
return postProcessContentInWorkerThread(
|
||||
std::move(result),
|
||||
std::move(projections),
|
||||
std::move(tileLoadInfo),
|
||||
rendererOptions);
|
||||
rendererOptions,
|
||||
pGltfModifier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1114,6 +1403,19 @@ void TilesetContentManager::loadTileContent(
|
|||
.thenInMainThread([pTile, thiz](TileLoadResultAndRenderResources&& pair) {
|
||||
setTileContent(*pTile, std::move(pair.result), pair.pRenderResources);
|
||||
thiz->notifyTileDoneLoading(pTile.get());
|
||||
|
||||
if (thiz->_externals.pGltfModifier) {
|
||||
const TileRenderContent* pRenderContent =
|
||||
pTile->getContent().getRenderContent();
|
||||
CESIUM_ASSERT(!pRenderContent || !pRenderContent->getModifiedModel());
|
||||
if (pRenderContent &&
|
||||
GltfModifierVersionExtension::getVersion(
|
||||
pRenderContent->getModel()) !=
|
||||
thiz->_externals.pGltfModifier->getCurrentVersion()) {
|
||||
thiz->_externals.pGltfModifier->onOldVersionContentLoadingComplete(
|
||||
*pTile);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catchInMainThread([pLogger = this->_externals.pLogger, pTile, thiz](
|
||||
std::exception&& e) {
|
||||
|
|
@ -1175,6 +1477,31 @@ UnloadTileContentResult TilesetContentManager::unloadTileContent(Tile& tile) {
|
|||
}
|
||||
|
||||
TileLoadState state = tile.getState();
|
||||
// Test if a glTF modifier is in progress.
|
||||
if (this->_externals.pGltfModifier) {
|
||||
TileRenderContent* pRenderContent = tile.getContent().getRenderContent();
|
||||
if (pRenderContent) {
|
||||
switch (pRenderContent->getGltfModifierState()) {
|
||||
case GltfModifierState::WorkerRunning:
|
||||
// Worker thread is running, we cannot unload yet.
|
||||
return UnloadTileContentResult::Keep;
|
||||
case GltfModifierState::WorkerDone:
|
||||
// Free temporary render resources.
|
||||
CESIUM_ASSERT(pRenderContent->getModifiedRenderResources());
|
||||
if (this->_externals.pPrepareRendererResources) {
|
||||
this->_externals.pPrepareRendererResources->free(
|
||||
tile,
|
||||
pRenderContent->getModifiedRenderResources(),
|
||||
nullptr);
|
||||
}
|
||||
pRenderContent->resetModifiedModelAndRenderResources();
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::Idle);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state == TileLoadState::Unloaded) {
|
||||
return UnloadTileContentResult::Remove;
|
||||
}
|
||||
|
|
@ -1353,13 +1680,46 @@ int64_t TilesetContentManager::getTotalDataUsed() const noexcept {
|
|||
void TilesetContentManager::finishLoading(
|
||||
Tile& tile,
|
||||
const TilesetOptions& tilesetOptions) {
|
||||
CESIUM_ASSERT(tile.getState() == TileLoadState::ContentLoaded);
|
||||
|
||||
// Run the main thread part of loading.
|
||||
TileContent& content = tile.getContent();
|
||||
TileRenderContent* pRenderContent = content.getRenderContent();
|
||||
|
||||
CESIUM_ASSERT(pRenderContent != nullptr);
|
||||
// If this tile doesn't have render content, there's nothing to finish
|
||||
// loading.
|
||||
TileRenderContent* pRenderContent = content.getRenderContent();
|
||||
if (pRenderContent == nullptr)
|
||||
return;
|
||||
|
||||
if (this->_externals.pGltfModifier &&
|
||||
this->_externals.pGltfModifier->needsMainThreadModification(tile)) {
|
||||
// Free outdated render resources before replacing them.
|
||||
if (this->_externals.pPrepareRendererResources) {
|
||||
this->_externals.pPrepareRendererResources->free(
|
||||
tile,
|
||||
nullptr,
|
||||
pRenderContent->getRenderResources());
|
||||
}
|
||||
|
||||
// Replace model and render resources with the newly modified versions,
|
||||
// discarding the old ones
|
||||
pRenderContent->replaceWithModifiedModel();
|
||||
|
||||
// Run the main thread part of loading.
|
||||
if (this->_externals.pPrepareRendererResources) {
|
||||
pRenderContent->setRenderResources(
|
||||
this->_externals.pPrepareRendererResources->prepareInMainThread(
|
||||
tile,
|
||||
pRenderContent->getRenderResources()));
|
||||
} else {
|
||||
pRenderContent->setRenderResources(nullptr);
|
||||
}
|
||||
|
||||
pRenderContent->setGltfModifierState(GltfModifierState::Idle);
|
||||
return;
|
||||
}
|
||||
|
||||
// None of the processing below makes sense until the Tile hits the
|
||||
// ContentLoaded state.
|
||||
if (tile.getState() != TileLoadState::ContentLoaded)
|
||||
return;
|
||||
|
||||
// add copyright
|
||||
CreditSystem* pCreditSystem = this->_externals.pCreditSystem.get();
|
||||
|
|
@ -1372,6 +1732,7 @@ void TilesetContentManager::finishLoading(
|
|||
|
||||
for (const std::string_view& creditString : creditStrings) {
|
||||
credits.emplace_back(pCreditSystem->createCredit(
|
||||
this->_creditSource,
|
||||
std::string(creditString),
|
||||
tilesetOptions.showCreditsOnScreen));
|
||||
}
|
||||
|
|
@ -1379,6 +1740,7 @@ void TilesetContentManager::finishLoading(
|
|||
pRenderContent->setCredits(credits);
|
||||
}
|
||||
|
||||
// Run the main thread part of loading.
|
||||
void* pWorkerRenderResources = pRenderContent->getRenderResources();
|
||||
if (this->_externals.pPrepareRendererResources) {
|
||||
void* pMainThreadRenderResources =
|
||||
|
|
@ -1480,6 +1842,16 @@ void TilesetContentManager::clearChildrenRecursively(Tile* pTile) noexcept {
|
|||
|
||||
void TilesetContentManager::registerTileRequester(
|
||||
TileLoadRequester& requester) {
|
||||
if (requester._pTilesetContentManager.get() == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requester._pTilesetContentManager != nullptr) {
|
||||
requester._pTilesetContentManager->unregisterTileRequester(requester);
|
||||
}
|
||||
|
||||
requester._pTilesetContentManager = this;
|
||||
|
||||
CESIUM_ASSERT(
|
||||
std::find(
|
||||
this->_requesters.begin(),
|
||||
|
|
@ -1496,6 +1868,8 @@ void TilesetContentManager::unregisterTileRequester(
|
|||
if (it != this->_requesters.end()) {
|
||||
this->_requesters.erase(it);
|
||||
}
|
||||
|
||||
requester._pTilesetContentManager = nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
@ -1671,14 +2045,7 @@ void TilesetContentManager::processMainThreadLoadRequests(
|
|||
if (pToLoad->_referenceCount == 0)
|
||||
continue;
|
||||
|
||||
// We double-check that the tile is still in the ContentLoaded state here,
|
||||
// in case something (such as a child that needs to upsample from this
|
||||
// parent) already pushed the tile into the Done state. Because in that
|
||||
// case, calling finishLoading here would assert or crash.
|
||||
if (pToLoad->getState() == TileLoadState::ContentLoaded &&
|
||||
pToLoad->isRenderContent()) {
|
||||
this->finishLoading(*pToLoad, options);
|
||||
}
|
||||
this->finishLoading(*pToLoad, options);
|
||||
|
||||
auto time = std::chrono::system_clock::now();
|
||||
if (timeBudget > 0.0 && time >= end) {
|
||||
|
|
@ -1689,6 +2056,13 @@ void TilesetContentManager::processMainThreadLoadRequests(
|
|||
|
||||
void TilesetContentManager::markTilesetDestroyed() noexcept {
|
||||
this->_tilesetDestroyed = true;
|
||||
|
||||
// Unregister the GltfModifier. This will not destroy it, but it will ensure
|
||||
// it releases any references it holds to this TilesetContentManager so that
|
||||
// the TilesetContentManager can be destroyed.
|
||||
if (this->_externals.pGltfModifier) {
|
||||
this->_externals.pGltfModifier->onUnregister(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetContentManager::releaseReference() const {
|
||||
|
|
@ -1706,6 +2080,17 @@ void TilesetContentManager::releaseReference() const {
|
|||
}
|
||||
}
|
||||
|
||||
TilesetExternals& TilesetContentManager::getExternals() {
|
||||
return this->_externals;
|
||||
}
|
||||
const TilesetExternals& TilesetContentManager::getExternals() const {
|
||||
return this->_externals;
|
||||
}
|
||||
|
||||
const CreditSource& TilesetContentManager::getCreditSource() const noexcept {
|
||||
return this->_creditSource;
|
||||
}
|
||||
|
||||
void TilesetContentManager::setTileContent(
|
||||
Tile& tile,
|
||||
TileLoadResult&& result,
|
||||
|
|
@ -1950,9 +2335,11 @@ void TilesetContentManager::propagateTilesetContentLoaderResult(
|
|||
this->_tilesetCredits.reserve(
|
||||
this->_tilesetCredits.size() + result.credits.size());
|
||||
for (const auto& creditResult : result.credits) {
|
||||
this->_tilesetCredits.emplace_back(_externals.pCreditSystem->createCredit(
|
||||
creditResult.creditText,
|
||||
creditResult.showOnScreen));
|
||||
this->_tilesetCredits.emplace_back(
|
||||
this->_externals.pCreditSystem->createCredit(
|
||||
this->_creditSource,
|
||||
creditResult.creditText,
|
||||
creditResult.showOnScreen));
|
||||
}
|
||||
|
||||
this->_requestHeaders = std::move(result.requestHeaders);
|
||||
|
|
@ -1963,4 +2350,27 @@ void TilesetContentManager::propagateTilesetContentLoaderResult(
|
|||
LoadedTileEnumerator(this->_pRootTile.get()));
|
||||
this->_pLoader->setOwner(*this);
|
||||
}
|
||||
|
||||
CesiumAsync::Future<void>
|
||||
TilesetContentManager::registerGltfModifier(const Tile* pRootTile) {
|
||||
std::shared_ptr<GltfModifier> pGltfModifier =
|
||||
this->getExternals().pGltfModifier;
|
||||
|
||||
if (pGltfModifier && pRootTile) {
|
||||
const TileExternalContent* pExternal =
|
||||
pRootTile->getContent().getExternalContent();
|
||||
return pGltfModifier
|
||||
->onRegister(
|
||||
*this,
|
||||
pExternal ? pExternal->metadata : TilesetMetadata(),
|
||||
*pRootTile)
|
||||
.catchInMainThread([this](std::exception&&) {
|
||||
// Disable the failed glTF modifier.
|
||||
this->getExternals().pGltfModifier.reset();
|
||||
});
|
||||
}
|
||||
|
||||
return this->getExternals().asyncSystem.createResolvedFuture();
|
||||
}
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -180,6 +180,11 @@ public:
|
|||
void markTilesetDestroyed() noexcept;
|
||||
void releaseReference() const;
|
||||
|
||||
TilesetExternals& getExternals();
|
||||
const TilesetExternals& getExternals() const;
|
||||
|
||||
const CesiumUtility::CreditSource& getCreditSource() const noexcept;
|
||||
|
||||
private:
|
||||
static void setTileContent(
|
||||
Tile& tile,
|
||||
|
|
@ -201,6 +206,11 @@ private:
|
|||
|
||||
void notifyTileUnloading(const Tile* pTile) noexcept;
|
||||
|
||||
void reapplyGltfModifier(
|
||||
Tile& tile,
|
||||
const TilesetOptions& tilesetOptions,
|
||||
TileRenderContent* pRenderContent) noexcept;
|
||||
|
||||
template <class TilesetContentLoaderType>
|
||||
void propagateTilesetContentLoaderResult(
|
||||
TilesetLoadType type,
|
||||
|
|
@ -208,6 +218,8 @@ private:
|
|||
loadErrorCallback,
|
||||
TilesetContentLoaderResult<TilesetContentLoaderType>&& result);
|
||||
|
||||
CesiumAsync::Future<void> registerGltfModifier(const Tile* pRootTile);
|
||||
|
||||
TilesetExternals _externals;
|
||||
std::vector<CesiumAsync::IAssetAccessor::THeader> _requestHeaders;
|
||||
std::unique_ptr<TilesetContentLoader> _pLoader;
|
||||
|
|
@ -242,5 +254,7 @@ private:
|
|||
// These are scratch space, stored here to avoid heap allocations.
|
||||
std::vector<double> _requesterFractions;
|
||||
std::vector<TileLoadRequester*> _requestersWithRequests;
|
||||
|
||||
CesiumUtility::CreditSource _creditSource;
|
||||
};
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@ ViewUpdateResult& TilesetViewGroup::getViewUpdateResult() {
|
|||
return this->_updateResult;
|
||||
}
|
||||
|
||||
void TilesetViewGroup::addToLoadQueue(const TileLoadTask& task) {
|
||||
void TilesetViewGroup::addToLoadQueue(
|
||||
const TileLoadTask& task,
|
||||
const std::shared_ptr<GltfModifier>& pModifier) {
|
||||
Tile* pTile = task.pTile;
|
||||
CESIUM_ASSERT(pTile != nullptr);
|
||||
|
||||
|
|
@ -61,9 +63,9 @@ void TilesetViewGroup::addToLoadQueue(const TileLoadTask& task) {
|
|||
[&](const TileLoadTask& task) { return task.pTile == pTile; }) ==
|
||||
this->_mainThreadLoadQueue.end());
|
||||
|
||||
if (pTile->needsWorkerThreadLoading()) {
|
||||
if (pTile->needsWorkerThreadLoading(pModifier.get())) {
|
||||
this->_workerThreadLoadQueue.emplace_back(task);
|
||||
} else if (pTile->needsMainThreadLoading()) {
|
||||
} else if (pTile->needsMainThreadLoading(pModifier.get())) {
|
||||
this->_mainThreadLoadQueue.emplace_back(task);
|
||||
} else if (
|
||||
pTile->getState() == TileLoadState::ContentLoading ||
|
||||
|
|
@ -257,4 +259,9 @@ const Tile* TilesetViewGroup::getNextTileToLoadInMainThread() {
|
|||
return pResult;
|
||||
}
|
||||
|
||||
bool TilesetViewGroup::isCreditReferenced(
|
||||
CesiumUtility::Credit credit) const noexcept {
|
||||
return this->_previousFrameCredits.isCreditReferenced(credit);
|
||||
}
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <Cesium3DTilesSelection/Tile.h>
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
void MockTilesetContentManagerTestFixture::setTileLoadState(
|
||||
Cesium3DTilesSelection::Tile& tile,
|
||||
Cesium3DTilesSelection::TileLoadState loadState) {
|
||||
|
|
@ -14,4 +15,11 @@ void MockTilesetContentManagerTestFixture::setTileShouldContinueUpdating(
|
|||
bool shouldContinueUpdating) {
|
||||
tile.setMightHaveLatentChildren(shouldContinueUpdating);
|
||||
}
|
||||
|
||||
void MockTilesetContentManagerTestFixture::setTileContent(
|
||||
Cesium3DTilesSelection::Tile& tile,
|
||||
Cesium3DTilesSelection::TileContent&& content) {
|
||||
tile._content = std::move(content);
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -12,5 +12,10 @@ public:
|
|||
static void setTileShouldContinueUpdating(
|
||||
Cesium3DTilesSelection::Tile& tile,
|
||||
bool shouldContinueToBeUpdating);
|
||||
|
||||
static void setTileContent(
|
||||
Cesium3DTilesSelection::Tile& tile,
|
||||
Cesium3DTilesSelection::TileContent&& content);
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -1,200 +0,0 @@
|
|||
#include <CesiumUtility/CreditSystem.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace CesiumUtility;
|
||||
|
||||
TEST_CASE("Test basic credit handling") {
|
||||
|
||||
CreditSystem creditSystem;
|
||||
|
||||
std::string html0 = "<html>Credit0</html>";
|
||||
std::string html1 = "<html>Credit1</html>";
|
||||
std::string html2 = "<html>Credit2</html>";
|
||||
|
||||
Credit credit0 = creditSystem.createCredit(html0);
|
||||
Credit credit1 = creditSystem.createCredit(html1);
|
||||
Credit credit2 = creditSystem.createCredit(html2);
|
||||
|
||||
REQUIRE(creditSystem.getHtml(credit1) == html1);
|
||||
|
||||
// Frame 0: Add 0 and 1
|
||||
{
|
||||
creditSystem.addCreditReference(credit0);
|
||||
creditSystem.addCreditReference(credit1);
|
||||
const CreditsSnapshot& snapshot0 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow0{credit0, credit1};
|
||||
REQUIRE(snapshot0.currentCredits == expectedShow0);
|
||||
|
||||
std::vector<Credit> expectedHide0{};
|
||||
REQUIRE(snapshot0.removedCredits == expectedHide0);
|
||||
}
|
||||
|
||||
// Start frame 1: Add 2, remove 0
|
||||
{
|
||||
creditSystem.addCreditReference(credit2);
|
||||
creditSystem.removeCreditReference(credit0);
|
||||
const CreditsSnapshot& snapshot1 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow1{credit1, credit2};
|
||||
REQUIRE(snapshot1.currentCredits == expectedShow1);
|
||||
|
||||
std::vector<Credit> expectedHide1{credit0};
|
||||
REQUIRE(snapshot1.removedCredits == expectedHide1);
|
||||
}
|
||||
|
||||
// Start frame 2: Add nothing, remove 1 and 2
|
||||
{
|
||||
creditSystem.removeCreditReference(credit1);
|
||||
creditSystem.removeCreditReference(credit2);
|
||||
const CreditsSnapshot& snapshot2 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow2{};
|
||||
REQUIRE(snapshot2.currentCredits == expectedShow2);
|
||||
|
||||
std::vector<Credit> expectedHide2{credit1, credit2};
|
||||
REQUIRE(snapshot2.removedCredits == expectedHide2);
|
||||
}
|
||||
|
||||
// Start frame 3: Add nothing, remove nothing
|
||||
{
|
||||
const CreditsSnapshot& snapshot3 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow3{};
|
||||
REQUIRE(snapshot3.currentCredits == expectedShow3);
|
||||
|
||||
std::vector<Credit> expectedHide3{};
|
||||
REQUIRE(snapshot3.removedCredits == expectedHide3);
|
||||
}
|
||||
|
||||
// Start frame 4: Add 2, remove nothing
|
||||
{
|
||||
creditSystem.addCreditReference(credit2);
|
||||
const CreditsSnapshot& snapshot4 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow4{credit2};
|
||||
REQUIRE(snapshot4.currentCredits == expectedShow4);
|
||||
|
||||
std::vector<Credit> expectedHide4{};
|
||||
REQUIRE(snapshot4.removedCredits == expectedHide4);
|
||||
}
|
||||
|
||||
// Start frame 5: Remove and then re-add 2
|
||||
{
|
||||
creditSystem.removeCreditReference(credit2);
|
||||
creditSystem.addCreditReference(credit2);
|
||||
const CreditsSnapshot& snapshot5 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow5{credit2};
|
||||
REQUIRE(snapshot5.currentCredits == expectedShow5);
|
||||
|
||||
std::vector<Credit> expectedHide5{};
|
||||
REQUIRE(snapshot5.removedCredits == expectedHide5);
|
||||
}
|
||||
|
||||
// Start frame 6: Add and then remove 1
|
||||
{
|
||||
creditSystem.addCreditReference(credit1);
|
||||
creditSystem.removeCreditReference(credit1);
|
||||
const CreditsSnapshot& snapshot6 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow6{credit2};
|
||||
REQUIRE(snapshot6.currentCredits == expectedShow6);
|
||||
|
||||
std::vector<Credit> expectedHide6{};
|
||||
REQUIRE(snapshot6.removedCredits == expectedHide6);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test wrong credit handling") {
|
||||
|
||||
CreditSystem creditSystemA;
|
||||
CreditSystem creditSystemB;
|
||||
|
||||
std::string html0 = "<html>Credit0</html>";
|
||||
std::string html1 = "<html>Credit1</html>";
|
||||
|
||||
Credit creditA0 = creditSystemA.createCredit(html0);
|
||||
Credit creditA1 = creditSystemA.createCredit(html1);
|
||||
|
||||
/*Credit creditB0 = */ creditSystemB.createCredit(html0);
|
||||
|
||||
// NOTE: This is using a Credit from a different credit
|
||||
// system, which coincidentally has a valid ID here.
|
||||
// This is not (and can hardly be) checked right now,
|
||||
// so this returns a valid HTML string:
|
||||
REQUIRE(creditSystemB.getHtml(creditA0) == html0);
|
||||
|
||||
REQUIRE(creditSystemB.getHtml(creditA1) != html1);
|
||||
}
|
||||
|
||||
TEST_CASE("Test sorting credits by frequency") {
|
||||
|
||||
CreditSystem creditSystem;
|
||||
|
||||
std::string html0 = "<html>Credit0</html>";
|
||||
std::string html1 = "<html>Credit1</html>";
|
||||
std::string html2 = "<html>Credit2</html>";
|
||||
|
||||
Credit credit0 = creditSystem.createCredit(html0);
|
||||
Credit credit1 = creditSystem.createCredit(html1);
|
||||
Credit credit2 = creditSystem.createCredit(html2);
|
||||
|
||||
REQUIRE(creditSystem.getHtml(credit1) == html1);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
creditSystem.addCreditReference(credit0);
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
creditSystem.addCreditReference(credit1);
|
||||
}
|
||||
creditSystem.addCreditReference(credit2);
|
||||
|
||||
const CreditsSnapshot& snapshot0 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow0{credit0, credit1, credit2};
|
||||
REQUIRE(snapshot0.currentCredits == expectedShow0);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
creditSystem.addCreditReference(credit2);
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
creditSystem.removeCreditReference(credit0);
|
||||
}
|
||||
|
||||
const CreditsSnapshot& snapshot1 = creditSystem.getSnapshot();
|
||||
|
||||
std::vector<Credit> expectedShow1{credit2, credit1, credit0};
|
||||
REQUIRE(snapshot1.currentCredits == expectedShow1);
|
||||
}
|
||||
|
||||
TEST_CASE("Test setting showOnScreen on credits") {
|
||||
|
||||
CreditSystem creditSystem;
|
||||
|
||||
std::string html0 = "<html>Credit0</html>";
|
||||
std::string html1 = "<html>Credit1</html>";
|
||||
std::string html2 = "<html>Credit2</html>";
|
||||
|
||||
Credit credit0 = creditSystem.createCredit(html0, true);
|
||||
Credit credit1 = creditSystem.createCredit(html1, false);
|
||||
Credit credit2 = creditSystem.createCredit(html2, true);
|
||||
|
||||
REQUIRE(creditSystem.getHtml(credit1) == html1);
|
||||
|
||||
CHECK(creditSystem.shouldBeShownOnScreen(credit0) == true);
|
||||
CHECK(creditSystem.shouldBeShownOnScreen(credit1) == false);
|
||||
CHECK(creditSystem.shouldBeShownOnScreen(credit2) == true);
|
||||
|
||||
creditSystem.setShowOnScreen(credit0, false);
|
||||
creditSystem.setShowOnScreen(credit1, true);
|
||||
creditSystem.setShowOnScreen(credit2, true);
|
||||
|
||||
CHECK(creditSystem.shouldBeShownOnScreen(credit0) == false);
|
||||
CHECK(creditSystem.shouldBeShownOnScreen(credit1) == true);
|
||||
CHECK(creditSystem.shouldBeShownOnScreen(credit2) == true);
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
#include "MockTilesetContentManager.h"
|
||||
#include "TilesetContentManager.h"
|
||||
|
||||
#include <Cesium3DTilesSelection/EllipsoidTilesetLoader.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifier.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierVersionExtension.h>
|
||||
#include <Cesium3DTilesSelection/Tile.h>
|
||||
#include <Cesium3DTilesSelection/TileContent.h>
|
||||
#include <Cesium3DTilesSelection/TileLoadRequester.h>
|
||||
#include <CesiumGeometry/BoundingSphere.h>
|
||||
#include <CesiumGltf/Model.h>
|
||||
#include <CesiumNativeTests/SimpleAssetAccessor.h>
|
||||
#include <CesiumNativeTests/SimpleTaskProcessor.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace Cesium3DTilesSelection;
|
||||
using namespace CesiumAsync;
|
||||
using namespace CesiumNativeTests;
|
||||
using namespace CesiumUtility;
|
||||
|
||||
namespace Cesium3DTilesSelection {
|
||||
|
||||
class MockTilesetContentManagerForGltfModifier {
|
||||
public:
|
||||
static TileLoadRequester* getTileLoadRequester(GltfModifier& modifier) {
|
||||
return &modifier;
|
||||
}
|
||||
|
||||
static const TileLoadRequester*
|
||||
getTileLoadRequester(const GltfModifier& modifier) {
|
||||
return &modifier;
|
||||
}
|
||||
|
||||
static void
|
||||
onOldVersionContentLoadingComplete(GltfModifier& modifier, const Tile& tile) {
|
||||
modifier.onOldVersionContentLoadingComplete(tile);
|
||||
}
|
||||
|
||||
static void
|
||||
onUnregister(GltfModifier& modifier, TilesetContentManager& contentManager) {
|
||||
return modifier.onUnregister(contentManager);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
||||
namespace {
|
||||
|
||||
class MockGltfModifier : public GltfModifier {
|
||||
public:
|
||||
CesiumAsync::Future<std::optional<GltfModifierOutput>>
|
||||
apply(GltfModifierInput&& input) override {
|
||||
++applyCallCount;
|
||||
return input.asyncSystem
|
||||
.createResolvedFuture<std::optional<GltfModifierOutput>>(std::nullopt);
|
||||
}
|
||||
|
||||
int32_t applyCallCount = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("GltfModifier") {
|
||||
TilesetExternals externals{
|
||||
.pAssetAccessor = std::make_shared<SimpleAssetAccessor>(
|
||||
std::map<std::string, std::shared_ptr<SimpleAssetRequest>>()),
|
||||
.pPrepareRendererResources = nullptr,
|
||||
.asyncSystem = AsyncSystem(std::make_shared<SimpleTaskProcessor>()),
|
||||
.pCreditSystem = std::make_shared<CreditSystem>(),
|
||||
.pGltfModifier = std::make_shared<MockGltfModifier>()};
|
||||
|
||||
std::unique_ptr<Tileset> pTileset =
|
||||
EllipsoidTilesetLoader::createTileset(externals, TilesetOptions{});
|
||||
|
||||
pTileset->getRootTileAvailableEvent().waitInMainThread();
|
||||
|
||||
Tile* pTile = const_cast<Tile*>(pTileset->getRootTile());
|
||||
std::shared_ptr<GltfModifier> pModifier =
|
||||
pTileset->getExternals().pGltfModifier;
|
||||
|
||||
MockTilesetContentManagerTestFixture::setTileLoadState(
|
||||
*pTile,
|
||||
TileLoadState::ContentLoaded);
|
||||
|
||||
TileContent content;
|
||||
content.setContentKind(
|
||||
std::make_unique<TileRenderContent>(CesiumGltf::Model{}));
|
||||
MockTilesetContentManagerTestFixture::setTileContent(
|
||||
*pTile,
|
||||
std::move(content));
|
||||
|
||||
pTile->addReference();
|
||||
|
||||
SUBCASE("has empty load queues on construction") {
|
||||
const TileLoadRequester* pRequester =
|
||||
MockTilesetContentManagerForGltfModifier::getTileLoadRequester(
|
||||
*pModifier);
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInMainThread());
|
||||
}
|
||||
|
||||
SUBCASE("queues tiles for worker thread loading after trigger") {
|
||||
TileLoadRequester* pRequester =
|
||||
MockTilesetContentManagerForGltfModifier::getTileLoadRequester(
|
||||
*pModifier);
|
||||
|
||||
// Initially inactive, no queuing should happen
|
||||
MockTilesetContentManagerForGltfModifier::
|
||||
onOldVersionContentLoadingComplete(*pModifier, *pTile);
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
|
||||
// After trigger, tile should be queued
|
||||
pModifier->trigger();
|
||||
CHECK(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
|
||||
// Get next tile should return our tile and empty the queue
|
||||
const Tile* pNext = pRequester->getNextTileToLoadInWorkerThread();
|
||||
CHECK(pNext == pTile);
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
|
||||
SUBCASE("multiple tiles") {
|
||||
REQUIRE(!pTile->getChildren().empty());
|
||||
Tile* pTile2 = &pTile->getChildren()[0];
|
||||
|
||||
// Make the second tile loaded, too.
|
||||
MockTilesetContentManagerTestFixture::setTileLoadState(
|
||||
*pTile2,
|
||||
TileLoadState::ContentLoaded);
|
||||
|
||||
TileContent content2;
|
||||
content2.setContentKind(
|
||||
std::make_unique<TileRenderContent>(CesiumGltf::Model{}));
|
||||
MockTilesetContentManagerTestFixture::setTileContent(
|
||||
*pTile2,
|
||||
std::move(content2));
|
||||
|
||||
// Add a reference for the content, and for a child with a reference.
|
||||
pTile2->addReference();
|
||||
pTile->addReference();
|
||||
|
||||
pModifier->trigger();
|
||||
|
||||
CHECK(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
const Tile* pNext1 = pRequester->getNextTileToLoadInWorkerThread();
|
||||
CHECK(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
const Tile* pNext2 = pRequester->getNextTileToLoadInWorkerThread();
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
|
||||
bool bothTilesReturned = (pNext1 == pTile && pNext2 == pTile2) ||
|
||||
(pNext1 == pTile2 && pNext2 == pTile);
|
||||
CHECK(bothTilesReturned);
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("clears load queues on unregister") {
|
||||
const TileLoadRequester* pRequester =
|
||||
MockTilesetContentManagerForGltfModifier::getTileLoadRequester(
|
||||
*pModifier);
|
||||
|
||||
pModifier->trigger();
|
||||
CHECK(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
|
||||
pTileset.reset();
|
||||
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInWorkerThread());
|
||||
CHECK_FALSE(pRequester->hasMoreTilesToLoadInMainThread());
|
||||
}
|
||||
|
||||
SUBCASE("trigger causes modifier to be reapplied and version number to be "
|
||||
"updated") {
|
||||
const TileRenderContent* pRenderContent =
|
||||
pTile->getContent().getRenderContent();
|
||||
REQUIRE(pRenderContent);
|
||||
|
||||
CHECK(
|
||||
GltfModifierVersionExtension::getVersion(pRenderContent->getModel()) ==
|
||||
std::nullopt);
|
||||
|
||||
pModifier->trigger();
|
||||
REQUIRE(pModifier->getCurrentVersion() == 0);
|
||||
|
||||
while (GltfModifierVersionExtension::getVersion(
|
||||
pRenderContent->getModel()) != 0) {
|
||||
pTileset->loadTiles();
|
||||
externals.asyncSystem.dispatchMainThreadTasks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -110,6 +110,8 @@ TEST_CASE("TileLoadRequester") {
|
|||
|
||||
auto pTileset = EllipsoidTilesetLoader::createTileset(externals);
|
||||
|
||||
externals.asyncSystem.dispatchMainThreadTasks();
|
||||
|
||||
const Tile* pRoot = pTileset->getRootTile();
|
||||
REQUIRE(pRoot != nullptr);
|
||||
REQUIRE(pRoot->getChildren().size() == 2);
|
||||
|
|
@ -177,6 +179,8 @@ TEST_CASE("TileLoadRequester") {
|
|||
std::move(pRootTile),
|
||||
options);
|
||||
|
||||
externals.asyncSystem.dispatchMainThreadTasks();
|
||||
|
||||
const Tile* pRoot = pTileset->getRootTile();
|
||||
REQUIRE(pRoot != nullptr);
|
||||
REQUIRE(pRoot->getChildren().size() == 100);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include "TilesetJsonLoader.h"
|
||||
|
||||
#include <Cesium3DTilesContent/registerAllTileContentTypes.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifier.h>
|
||||
#include <Cesium3DTilesSelection/GltfModifierVersionExtension.h>
|
||||
#include <Cesium3DTilesSelection/RasterOverlayCollection.h>
|
||||
#include <Cesium3DTilesSelection/Tile.h>
|
||||
#include <Cesium3DTilesSelection/TileLoadResult.h>
|
||||
|
|
@ -38,6 +40,7 @@
|
|||
#include <CesiumNativeTests/SimpleAssetResponse.h>
|
||||
#include <CesiumNativeTests/SimpleTaskProcessor.h>
|
||||
#include <CesiumNativeTests/readFile.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/DebugColorizeTilesRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
|
@ -496,6 +499,8 @@ TEST_CASE("Test tile state machine") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
// test manager loading
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, options);
|
||||
|
|
@ -603,6 +608,8 @@ TEST_CASE("Test tile state machine") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
// test manager loading
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, options);
|
||||
|
|
@ -681,6 +688,8 @@ TEST_CASE("Test tile state machine") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
// test manager loading
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, options);
|
||||
|
|
@ -781,6 +790,8 @@ TEST_CASE("Test tile state machine") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
Tile& upsampledTile = tile.getChildren().back();
|
||||
|
||||
|
|
@ -938,6 +949,8 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
// test the gltf model
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, {});
|
||||
|
|
@ -1008,6 +1021,8 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
// test the gltf model
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, options);
|
||||
|
|
@ -1074,6 +1089,8 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, {});
|
||||
pManager->waitUntilIdle();
|
||||
|
|
@ -1122,7 +1139,8 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
// add raster overlay
|
||||
pManager->getRasterOverlayCollection().add(
|
||||
new DebugColorizeTilesRasterOverlay("DebugOverlay"));
|
||||
asyncSystem.dispatchMainThreadTasks();
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
SUBCASE(
|
||||
"Generate raster overlay details when tile doesn't have loose region") {
|
||||
|
|
@ -1312,24 +1330,13 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
class AlwaysMoreDetailProvider : public RasterOverlayTileProvider {
|
||||
public:
|
||||
AlwaysMoreDetailProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle)
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
coverageRectangle) {}
|
||||
|
||||
|
|
@ -1358,29 +1365,18 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
AlwaysMoreDetailRasterOverlay() : RasterOverlay("AlwaysMoreDetail") {}
|
||||
|
||||
CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<
|
||||
CesiumUtility::CreditSystem>& /* pCreditSystem */,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override {
|
||||
return asyncSystem.createResolvedFuture(CreateTileProviderResult(
|
||||
CesiumUtility::IntrusivePointer<RasterOverlayTileProvider>(
|
||||
new AlwaysMoreDetailProvider(
|
||||
pOwner ? pOwner : this,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
nullptr,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
CesiumGeospatial::GeographicProjection(),
|
||||
projectRectangleSimple(
|
||||
return parameters.externals.asyncSystem.createResolvedFuture(
|
||||
CreateTileProviderResult(
|
||||
CesiumUtility::IntrusivePointer<RasterOverlayTileProvider>(
|
||||
new AlwaysMoreDetailProvider(
|
||||
this,
|
||||
parameters,
|
||||
CesiumGeospatial::GeographicProjection(),
|
||||
GlobeRectangle::MAXIMUM)))));
|
||||
projectRectangleSimple(
|
||||
CesiumGeospatial::GeographicProjection(),
|
||||
GlobeRectangle::MAXIMUM)))));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1417,7 +1413,8 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
|
||||
pManager->getRasterOverlayCollection().add(
|
||||
new AlwaysMoreDetailRasterOverlay());
|
||||
asyncSystem.dispatchMainThreadTasks();
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
SUBCASE(
|
||||
"Generate raster overlay details when tile doesn't have loose region") {
|
||||
|
|
@ -1639,7 +1636,8 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") {
|
|||
// add raster overlay
|
||||
pManager->getRasterOverlayCollection().add(
|
||||
new DebugColorizeTilesRasterOverlay("DebugOverlay"));
|
||||
asyncSystem.dispatchMainThreadTasks();
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, {});
|
||||
|
|
@ -1827,9 +1825,158 @@ TEST_CASE("IPrepareRendererResources::prepareInLoadThread parameters") {
|
|||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, options);
|
||||
pManager->waitUntilIdle();
|
||||
pManager->unloadTileContent(tile);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test glTF modifier state machine") {
|
||||
Cesium3DTilesContent::registerAllTileContentTypes();
|
||||
|
||||
// create mock tileset externals
|
||||
auto pMockedAssetAccessor = std::make_shared<SimpleAssetAccessor>(
|
||||
std::map<std::string, std::shared_ptr<SimpleAssetRequest>>{});
|
||||
auto pMockedPrepareRendererResources =
|
||||
std::make_shared<SimplePrepareRendererResource>();
|
||||
CesiumAsync::AsyncSystem asyncSystem{std::make_shared<SimpleTaskProcessor>()};
|
||||
auto pMockedCreditSystem = std::make_shared<CreditSystem>();
|
||||
|
||||
TilesetExternals externals{
|
||||
pMockedAssetAccessor,
|
||||
pMockedPrepareRendererResources,
|
||||
asyncSystem,
|
||||
pMockedCreditSystem};
|
||||
|
||||
class SimpleGltfModifier : public GltfModifier {
|
||||
public:
|
||||
SimpleGltfModifier() {}
|
||||
|
||||
int applyCallCount = 0;
|
||||
CesiumAsync::Future<std::optional<GltfModifierOutput>>
|
||||
apply(GltfModifierInput&& input) override {
|
||||
++applyCallCount;
|
||||
GltfModifierOutput output{.modifiedModel = input.previousModel};
|
||||
return input.asyncSystem.createResolvedFuture(
|
||||
std::make_optional(std::move(output)));
|
||||
}
|
||||
|
||||
int onRegisterCallCount = 0;
|
||||
CesiumAsync::Future<void> onRegister(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>&,
|
||||
const std::shared_ptr<spdlog::logger>&,
|
||||
const TilesetMetadata&,
|
||||
const Tile&) override {
|
||||
++onRegisterCallCount;
|
||||
return asyncSystem.createResolvedFuture();
|
||||
}
|
||||
};
|
||||
|
||||
auto pGltfModifier = std::make_shared<SimpleGltfModifier>();
|
||||
externals.pGltfModifier = pGltfModifier;
|
||||
|
||||
auto pMockedLoader = std::make_unique<SimpleTilesetContentLoader>();
|
||||
pMockedLoader->mockLoadTileContent = {
|
||||
CesiumGltf::Model(),
|
||||
CesiumGeometry::Axis::Y,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
TileLoadResultState::Success};
|
||||
|
||||
// create tile
|
||||
auto pRootTile = std::make_unique<Tile>(pMockedLoader.get());
|
||||
|
||||
// Give the tile an ID so it is eligible for unloading.
|
||||
pRootTile->setTileID("foo");
|
||||
|
||||
// create manager
|
||||
TilesetOptions options{};
|
||||
options.contentOptions.generateMissingNormalsSmooth = true;
|
||||
|
||||
IntrusivePointer<TilesetContentManager> pManager = new TilesetContentManager{
|
||||
externals,
|
||||
options,
|
||||
std::move(pMockedLoader),
|
||||
std::move(pRootTile)};
|
||||
|
||||
pManager->waitUntilIdle();
|
||||
|
||||
CHECK(pGltfModifier->onRegisterCallCount == 1);
|
||||
|
||||
// test manager loading
|
||||
Tile& tile = *pManager->getRootTile();
|
||||
pManager->loadTileContent(tile, options);
|
||||
pManager->waitUntilIdle();
|
||||
pManager->updateTileContent(tile, options);
|
||||
CHECK(tile.getState() == TileLoadState::Done);
|
||||
CHECK(tile.getContent().isRenderContent());
|
||||
// Constructed modifier is nilpotent until the first call to trigger(), so:
|
||||
CHECK(pGltfModifier->applyCallCount == 0);
|
||||
CHECK(pMockedPrepareRendererResources->totalAllocation == 1);
|
||||
|
||||
int expectedCallCount = 1;
|
||||
auto const& applyModifier = [&]() {
|
||||
pGltfModifier->trigger();
|
||||
CHECK(tile.needsWorkerThreadLoading(pGltfModifier.get()));
|
||||
// Start worker-thread phase of glTF modifier.
|
||||
pManager->loadTileContent(tile, options);
|
||||
// Unloading should be refused while worker-thread is running.
|
||||
CHECK(pManager->unloadTileContent(tile) == UnloadTileContentResult::Keep);
|
||||
// Wait completion of worker-thread phase.
|
||||
pManager->waitUntilIdle();
|
||||
CHECK(!tile.needsWorkerThreadLoading(pGltfModifier.get()));
|
||||
CHECK(tile.needsMainThreadLoading(pGltfModifier.get()));
|
||||
CHECK(pGltfModifier->applyCallCount == expectedCallCount);
|
||||
// The temporary renderer resource should have been created.
|
||||
CHECK(pMockedPrepareRendererResources->totalAllocation == 2);
|
||||
|
||||
SUBCASE("Perform main-thread phase of glTF modifier") {
|
||||
pManager->finishLoading(tile, options);
|
||||
CHECK(!tile.needsWorkerThreadLoading(pGltfModifier.get()));
|
||||
CHECK(!tile.needsMainThreadLoading(pGltfModifier.get()));
|
||||
// The temporary renderer resource should have been freed.
|
||||
CHECK(pGltfModifier->applyCallCount == expectedCallCount);
|
||||
CHECK(pMockedPrepareRendererResources->totalAllocation == 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Increment modifier version, thus requiring a first glTF modifier of the
|
||||
// already loaded tile
|
||||
applyModifier();
|
||||
|
||||
// Unload tile so that we can now test loading the tile with an _active_
|
||||
// modifier
|
||||
CHECK(pManager->unloadTileContent(tile));
|
||||
CHECK(pMockedPrepareRendererResources->totalAllocation == 0);
|
||||
|
||||
++expectedCallCount;
|
||||
// loaded tile below will be already processed by the glTF modifier
|
||||
pManager->loadTileContent(tile, options);
|
||||
pManager->waitUntilIdle();
|
||||
pManager->updateTileContent(tile, options);
|
||||
CHECK(tile.getState() == TileLoadState::Done);
|
||||
CHECK(tile.getContent().isRenderContent());
|
||||
// After the tile is loaded, glTF modifier should not be needed,
|
||||
// as it has already been done as part of the loading.
|
||||
CHECK(!tile.needsWorkerThreadLoading(pGltfModifier.get()));
|
||||
CHECK(!tile.needsMainThreadLoading(pGltfModifier.get()));
|
||||
CHECK(pGltfModifier->applyCallCount == expectedCallCount);
|
||||
CHECK(pMockedPrepareRendererResources->totalAllocation == 1);
|
||||
|
||||
++expectedCallCount;
|
||||
// Increment modifier version, thus requiring a new glTF modifier.
|
||||
applyModifier();
|
||||
|
||||
SUBCASE("Unload tile after main-thread phase of glTF modifier") {
|
||||
CHECK(pManager->unloadTileContent(tile));
|
||||
CHECK(pMockedPrepareRendererResources->totalAllocation == 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ cesium_target_include_directories(
|
|||
target_link_libraries(CesiumAsync
|
||||
PUBLIC
|
||||
CesiumUtility
|
||||
spdlog::spdlog spdlog::spdlog_header_only
|
||||
spdlog::spdlog
|
||||
Async++
|
||||
PRIVATE
|
||||
unofficial::sqlite3::sqlite3
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@ target_link_libraries(CesiumClientCommon
|
|||
PRIVATE
|
||||
picosha2::picosha2
|
||||
modp_b64::modp_b64
|
||||
httplib::httplib
|
||||
OpenSSL::Crypto
|
||||
)
|
||||
|
||||
if (NOT CESIUM_TARGET_WASM)
|
||||
target_link_libraries(CesiumClientCommon
|
||||
PRIVATE
|
||||
httplib::httplib
|
||||
)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <CesiumUtility/joinToString.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <httplib.h>
|
||||
#include <modp_b64.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
|
|
@ -34,6 +33,13 @@
|
|||
#include <utility>
|
||||
#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
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
|
|
@ -59,6 +65,7 @@ using namespace CesiumUtility;
|
|||
namespace CesiumClientCommon {
|
||||
|
||||
namespace {
|
||||
#ifndef __EMSCRIPTEN__
|
||||
std::string encodeBase64(const std::vector<uint8_t>& bytes) {
|
||||
const size_t count = modp_b64_encode_len(bytes.size());
|
||||
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)
|
||||
const size_t firstPaddingIndex = result.find('=');
|
||||
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(), '/', '_');
|
||||
|
|
@ -170,17 +177,28 @@ std::string createAuthorizationErrorHtml(
|
|||
exception.what(),
|
||||
applicationName);
|
||||
}
|
||||
#endif // #ifndef __EMSCRIPTEN__
|
||||
} // namespace
|
||||
|
||||
CesiumAsync::Future<Result<OAuth2TokenResponse>> OAuth2PKCE::authorize(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::string& friendlyApplicationName,
|
||||
const OAuth2ClientOptions& clientOptions,
|
||||
const std::vector<std::string>& scopes,
|
||||
std::function<void(const std::string&)>&& openUrlCallback,
|
||||
const std::string& tokenEndpointUrl,
|
||||
const std::string& authorizeBaseUrl) {
|
||||
[[maybe_unused]] const std::shared_ptr<CesiumAsync::IAssetAccessor>&
|
||||
pAssetAccessor,
|
||||
[[maybe_unused]] const std::string& friendlyApplicationName,
|
||||
[[maybe_unused]] const OAuth2ClientOptions& clientOptions,
|
||||
[[maybe_unused]] const std::vector<std::string>& scopes,
|
||||
[[maybe_unused]] std::function<void(const std::string&)>&& openUrlCallback,
|
||||
[[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>>();
|
||||
|
||||
std::shared_ptr<httplib::Server> pServer =
|
||||
|
|
@ -332,6 +350,7 @@ CesiumAsync::Future<Result<OAuth2TokenResponse>> OAuth2PKCE::authorize(
|
|||
openUrlCallback(authorizeUrl);
|
||||
|
||||
return promise.getFuture();
|
||||
#endif // #ifdef __EMSCRIPTEN__ #else
|
||||
}
|
||||
|
||||
CesiumAsync::Future<Result<OAuth2TokenResponse>>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <CesiumGeospatial/Library.h>
|
||||
#include <CesiumUtility/Math.h>
|
||||
|
||||
#include <glm/ext/vector_double2.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace CesiumGeospatial {
|
||||
|
|
@ -259,6 +261,18 @@ public:
|
|||
*/
|
||||
GlobeRectangle computeUnion(const GlobeRectangle& other) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Computes the normalized position of the given cartographic
|
||||
* coordinate on this globe rectangle, with (0.0, 0.0) representing southwest
|
||||
* and (1.0, 1.0) representing northeast. The returned coordinates vary
|
||||
* linearly with longitude and latitude within the rectangle.
|
||||
*
|
||||
* @param cartographic The cartographic coordinate to transform.
|
||||
* @return The normalized coordinates.
|
||||
*/
|
||||
glm::dvec2
|
||||
computeNormalizedCoordinates(const Cartographic& cartographic) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Splits this rectangle at the anti-meridian (180 degrees longitude),
|
||||
* if necessary.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <CesiumUtility/Math.h>
|
||||
|
||||
#include <glm/common.hpp>
|
||||
#include <glm/ext/vector_double2.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
|
@ -142,6 +143,22 @@ GlobeRectangle::computeUnion(const GlobeRectangle& other) const noexcept {
|
|||
glm::max(this->_north, other._north));
|
||||
}
|
||||
|
||||
glm::dvec2 GlobeRectangle::computeNormalizedCoordinates(
|
||||
const Cartographic& cartographic) const noexcept {
|
||||
double east = this->_east;
|
||||
double cartoLong = cartographic.longitude;
|
||||
if (east < this->_west) {
|
||||
east += CesiumUtility::Math::TwoPi;
|
||||
if (cartoLong < this->_west) {
|
||||
cartoLong += CesiumUtility::Math::TwoPi;
|
||||
}
|
||||
}
|
||||
|
||||
return glm::dvec2(
|
||||
(cartoLong - this->_west) / (east - this->_west),
|
||||
(cartographic.latitude - this->_south) / (this->_north - this->_south));
|
||||
}
|
||||
|
||||
std::pair<GlobeRectangle, std::optional<GlobeRectangle>>
|
||||
GlobeRectangle::splitAtAntiMeridian() const noexcept {
|
||||
if (this->_west <= this->_east) {
|
||||
|
|
|
|||
|
|
@ -199,3 +199,60 @@ TEST_CASE("GlobeRectangle::contains") {
|
|||
CHECK(wrapping.contains(Cartographic(-3.14, 0.2)));
|
||||
CHECK(!wrapping.contains(Cartographic(0.0, 0.2)));
|
||||
}
|
||||
|
||||
TEST_CASE("GlobeRectangle::computeNormalizedCoordinates") {
|
||||
GlobeRectangle simple(0.0, 0.0, 1.0, 1.0);
|
||||
CHECK(
|
||||
simple.computeNormalizedCoordinates(Cartographic(0.1, 0.1)) ==
|
||||
glm::dvec2(0.1, 0.1));
|
||||
CHECK(
|
||||
simple.computeNormalizedCoordinates(Cartographic(0, 0.0)) ==
|
||||
glm::dvec2(0.0, 0.0));
|
||||
CHECK(
|
||||
simple.computeNormalizedCoordinates(Cartographic(1.0, 1.0)) ==
|
||||
glm::dvec2(1.0, 1.0));
|
||||
|
||||
GlobeRectangle wrapping =
|
||||
GlobeRectangle::fromDegrees(175.0, 0.0, -175.0, 10.0);
|
||||
CHECK(
|
||||
wrapping.computeNormalizedCoordinates(
|
||||
Cartographic::fromDegrees(175.0, 5.0)) == glm::dvec2(0.0, 0.5));
|
||||
CHECK(
|
||||
wrapping.computeNormalizedCoordinates(
|
||||
Cartographic::fromDegrees(180.0, 10.0)) == glm::dvec2(0.5, 1.0));
|
||||
CHECK(
|
||||
wrapping.computeNormalizedCoordinates(
|
||||
Cartographic::fromDegrees(-180.0, 0.0)) == glm::dvec2(0.5, 0.0));
|
||||
CHECK(Math::equalsEpsilon(
|
||||
wrapping.computeNormalizedCoordinates(
|
||||
Cartographic::fromDegrees(-177.5, 0.0)),
|
||||
glm::dvec2(0.75, 0.0),
|
||||
Math::Epsilon6));
|
||||
CHECK(
|
||||
wrapping.computeNormalizedCoordinates(
|
||||
Cartographic::fromDegrees(-175, 0.0)) == glm::dvec2(1.0, 0.0));
|
||||
|
||||
GlobeRectangle tile = GlobeRectangle::fromDegrees(0.5, 0, 1.0, 0.5);
|
||||
CHECK(Math::equalsEpsilon(
|
||||
tile.computeNormalizedCoordinates(Cartographic::fromDegrees(0.25, 0.25)),
|
||||
glm::dvec2(-0.5, 0.5),
|
||||
Math::Epsilon6));
|
||||
CHECK(Math::equalsEpsilon(
|
||||
tile.computeNormalizedCoordinates(Cartographic::fromDegrees(0.5, 0.75)),
|
||||
glm::dvec2(0, 1.5),
|
||||
Math::Epsilon6));
|
||||
CHECK(Math::equalsEpsilon(
|
||||
tile.computeNormalizedCoordinates(Cartographic::fromDegrees(0.75, 0.25)),
|
||||
glm::dvec2(0.5, 0.5),
|
||||
Math::Epsilon6));
|
||||
|
||||
GlobeRectangle bigWrapping =
|
||||
GlobeRectangle::fromDegrees(179.0, -10.0, 10.0, 10.0);
|
||||
CHECK(Math::equalsEpsilon(
|
||||
bigWrapping.computeNormalizedCoordinates(
|
||||
Cartographic::fromDegrees(5.0, 0.0)),
|
||||
// Rectangle width is 191 degrees, position is 5 degrees west of east
|
||||
// edge.
|
||||
glm::dvec2(186.0 / 191.0, 0.5),
|
||||
Math::Epsilon6));
|
||||
}
|
||||
|
|
@ -2823,7 +2823,7 @@ private:
|
|||
}
|
||||
|
||||
uint64_t totalLength = stringOffsets.back();
|
||||
result.data.resize(totalLength);
|
||||
result.data.resize(size_t(totalLength));
|
||||
for (size_t i = 0; i < strings.size(); ++i) {
|
||||
std::memcpy(
|
||||
result.data.data() + stringOffsets[i],
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include <glm/ext/quaternion_double.hpp>
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <glm/geometric.hpp>
|
||||
#include <glm/gtc/quaternion.hpp> // NOLINT(misc-include-cleaner)
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
|
@ -408,7 +409,7 @@ ErrorList Model::merge(Model&& rhs) {
|
|||
std::copy(
|
||||
pRhsDefaultScene->nodes.begin(),
|
||||
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
|
||||
// we copied them from rhs to this.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ template <typename T>
|
|||
PropertyViewStatusType checkOffsetsBuffer(
|
||||
const std::span<const std::byte>& offsetBuffer,
|
||||
size_t valueBufferSize,
|
||||
size_t instanceCount,
|
||||
uint64_t instanceCount,
|
||||
bool checkBitSize,
|
||||
PropertyViewStatusType offsetsNotSortedError,
|
||||
PropertyViewStatusType offsetOutOfBoundsError) noexcept {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
|
@ -1158,8 +1159,8 @@ void deleteBufferRange(
|
|||
// Actually remove the bytes from the buffer.
|
||||
pBuffer->byteLength -= bytesToRemove;
|
||||
pBuffer->cesium.data.erase(
|
||||
pBuffer->cesium.data.begin() + start,
|
||||
pBuffer->cesium.data.begin() + end);
|
||||
pBuffer->cesium.data.begin() + ptrdiff_t(start),
|
||||
pBuffer->cesium.data.begin() + ptrdiff_t(end));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -62,6 +62,20 @@ target_link_libraries(CesiumGltfReader
|
|||
meshoptimizer::meshoptimizer
|
||||
modp_b64::modp_b64
|
||||
KTX::ktx
|
||||
WebP::webp WebP::webpdecoder
|
||||
$<IF:$<TARGET_EXISTS:libjpeg-turbo::turbojpeg>,libjpeg-turbo::turbojpeg,libjpeg-turbo::turbojpeg-static>
|
||||
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>
|
||||
)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ GltfReaderResult readBinaryGltf(
|
|||
|
||||
buffer.cesium.data = std::vector<std::byte>(
|
||||
binaryChunk.begin(),
|
||||
binaryChunk.begin() + buffer.byteLength);
|
||||
binaryChunk.begin() + (ptrdiff_t)buffer.byteLength);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include <CesiumUtility/Tracing.h>
|
||||
|
||||
#include <ktx.h>
|
||||
#include <turbojpeg.h>
|
||||
#include <webp/decode.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
|
@ -28,6 +27,10 @@
|
|||
#define STB_IMAGE_RESIZE_STATIC
|
||||
#include <stb_image_resize2.h>
|
||||
|
||||
#ifndef CESIUM_DISABLE_LIBJPEG_TURBO
|
||||
#include <turbojpeg.h>
|
||||
#endif
|
||||
|
||||
namespace CesiumGltfReader {
|
||||
|
||||
using namespace CesiumGltf;
|
||||
|
|
@ -287,6 +290,7 @@ ImageReaderResult ImageDecoder::readImage(
|
|||
}
|
||||
|
||||
{
|
||||
#ifndef CESIUM_DISABLE_LIBJPEG_TURBO
|
||||
tjhandle tjInstance = tjInitDecompress();
|
||||
int inSubsamp, inColorspace;
|
||||
if (!tjDecompressHeader3(
|
||||
|
|
@ -316,7 +320,9 @@ ImageReaderResult ImageDecoder::readImage(
|
|||
result.errors.emplace_back("Unable to decode JPEG");
|
||||
result.pImage = nullptr;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
#endif // !CESIUM_DISABLE_LIBJPEG_TURBO
|
||||
{
|
||||
CESIUM_TRACE("Decode PNG");
|
||||
image.bytesPerChannel = 1;
|
||||
image.channels = 4;
|
||||
|
|
@ -349,7 +355,9 @@ ImageReaderResult ImageDecoder::readImage(
|
|||
result.errors.emplace_back(stbi_failure_reason());
|
||||
}
|
||||
}
|
||||
#ifndef CESIUM_DISABLE_LIBJPEG_TURBO
|
||||
tjDestroy(tjInstance);
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ std::unique_ptr<draco::Mesh> decodeBufferViewToDracoMesh(
|
|||
|
||||
const std::span<const std::byte> data(
|
||||
buffer.cesium.data.data() + bufferView.byteOffset,
|
||||
static_cast<uint64_t>(bufferView.byteLength));
|
||||
static_cast<size_t>(bufferView.byteLength));
|
||||
|
||||
draco::DecoderBuffer decodeBuffer;
|
||||
decodeBuffer.Init(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
|
|
|
|||
|
|
@ -613,6 +613,7 @@ TEST_CASE("Writes glb with binaryChunkByteAlignment of 8") {
|
|||
REQUIRE(glbBytesExtraPadding.size() == 88);
|
||||
}
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
TEST_CASE("Reports an error if asked to write a GLB larger than 4GB") {
|
||||
CesiumGltf::Model model;
|
||||
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());
|
||||
CHECK(result.gltfBytes.empty());
|
||||
}
|
||||
#endif // __EMSCRIPTEN__
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ using namespace CesiumNativeTests;
|
|||
using namespace CesiumUtility;
|
||||
|
||||
namespace {
|
||||
const std::string& REDIRECT_PATH = "/dummy/auth/path";
|
||||
const std::string REDIRECT_PATH = "/dummy/auth/path";
|
||||
const int REDIRECT_PORT = 49013;
|
||||
|
||||
std::shared_ptr<Connection>
|
||||
|
|
@ -169,4 +169,4 @@ TEST_CASE("CesiumITwinClient::Connection::geospatialFeatureCollections") {
|
|||
collection.storageCrs ==
|
||||
"https://www.opengis.net/def/crs/EPSG/0/32615");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ cesium_glob_files(test_headers
|
|||
)
|
||||
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
|
||||
foreach(target ${cesium_native_targets})
|
||||
get_target_property(target_test_sources ${target} TEST_SOURCES)
|
||||
|
|
@ -75,6 +83,41 @@ foreach(target ${cesium_native_targets})
|
|||
endif()
|
||||
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(
|
||||
cesium-native-tests
|
||||
PRIVATE
|
||||
|
|
@ -99,9 +142,12 @@ PRIVATE
|
|||
|
||||
target_compile_definitions(cesium-native-tests
|
||||
PRIVATE
|
||||
CESIUM_NATIVE_DATA_DIR=\"${CMAKE_CURRENT_LIST_DIR}/../data\"
|
||||
CESIUM_NATIVE_DATA_DIR=\"${CMAKE_SOURCE_DIR}/data\"
|
||||
)
|
||||
|
||||
include(CTest)
|
||||
include(doctest)
|
||||
doctest_discover_tests(cesium-native-tests)
|
||||
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)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ std::unique_ptr<SimpleAssetResponse> readFileUri(const std::string& uri) {
|
|||
if (!file) {
|
||||
return response(404);
|
||||
}
|
||||
std::streamsize size = file.tellg();
|
||||
std::streamoff size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
result.resize(static_cast<size_t>(size));
|
||||
file.read(reinterpret_cast<char*>(result.data()), size);
|
||||
result.resize(size_t(size));
|
||||
file.read(reinterpret_cast<char*>(result.data()), std::streamsize(size));
|
||||
if (!file) {
|
||||
return response(503);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ std::vector<std::byte> readFile(const std::filesystem::path& fileName) {
|
|||
std::ifstream file(fileName, std::ios::binary | std::ios::ate);
|
||||
REQUIRE(file);
|
||||
|
||||
std::streamsize size = file.tellg();
|
||||
std::streamoff size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<std::byte> buffer(static_cast<size_t>(size));
|
||||
file.read(reinterpret_cast<char*>(buffer.data()), size);
|
||||
std::vector<std::byte> buffer{size_t(size)};
|
||||
file.read(reinterpret_cast<char*>(buffer.data()), std::streamsize(size));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ void addSkirts(
|
|||
westEdgeIndices.begin(),
|
||||
westEdgeIndices.end(),
|
||||
sortEdgeIndices.begin(),
|
||||
sortEdgeIndices.begin() + westVertexCount,
|
||||
sortEdgeIndices.begin() + ptrdiff_t(westVertexCount),
|
||||
[&uvsAndHeights](auto lhs, auto rhs) noexcept {
|
||||
return uvsAndHeights[lhs].y < uvsAndHeights[rhs].y;
|
||||
});
|
||||
|
|
@ -539,7 +539,7 @@ void addSkirts(
|
|||
southEdgeIndices.begin(),
|
||||
southEdgeIndices.end(),
|
||||
sortEdgeIndices.begin(),
|
||||
sortEdgeIndices.begin() + southVertexCount,
|
||||
sortEdgeIndices.begin() + ptrdiff_t(southVertexCount),
|
||||
[&uvsAndHeights](auto lhs, auto rhs) noexcept {
|
||||
return uvsAndHeights[lhs].x > uvsAndHeights[rhs].x;
|
||||
});
|
||||
|
|
@ -572,7 +572,7 @@ void addSkirts(
|
|||
eastEdgeIndices.begin(),
|
||||
eastEdgeIndices.end(),
|
||||
sortEdgeIndices.begin(),
|
||||
sortEdgeIndices.begin() + eastVertexCount,
|
||||
sortEdgeIndices.begin() + ptrdiff_t(eastVertexCount),
|
||||
[&uvsAndHeights](auto lhs, auto rhs) noexcept {
|
||||
return uvsAndHeights[lhs].y > uvsAndHeights[rhs].y;
|
||||
});
|
||||
|
|
@ -605,7 +605,7 @@ void addSkirts(
|
|||
northEdgeIndices.begin(),
|
||||
northEdgeIndices.end(),
|
||||
sortEdgeIndices.begin(),
|
||||
sortEdgeIndices.begin() + northVertexCount,
|
||||
sortEdgeIndices.begin() + ptrdiff_t(northVertexCount),
|
||||
[&uvsAndHeights](auto lhs, auto rhs) noexcept {
|
||||
return uvsAndHeights[lhs].x < uvsAndHeights[rhs].x;
|
||||
});
|
||||
|
|
@ -754,11 +754,10 @@ QuantizedMeshMetadataResult processMetadata(
|
|||
// decode position without skirt, but preallocate position buffer to include
|
||||
// skirt as well
|
||||
std::vector<std::byte> outputPositionsBuffer(
|
||||
static_cast<uint64_t>((vertexCount + skirtVertexCount) * 3) *
|
||||
sizeof(float));
|
||||
size_t((vertexCount + skirtVertexCount) * 3) * sizeof(float));
|
||||
std::span<float> outputPositions(
|
||||
reinterpret_cast<float*>(outputPositionsBuffer.data()),
|
||||
static_cast<size_t>((vertexCount + skirtVertexCount) * 3));
|
||||
size_t((vertexCount + skirtVertexCount) * 3));
|
||||
size_t positionOutputIndex = 0;
|
||||
|
||||
const glm::dvec3 center(
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ target_link_libraries(CesiumRasterOverlays
|
|||
CesiumUtility
|
||||
CesiumVectorData
|
||||
nonstd::expected-lite
|
||||
spdlog::spdlog
|
||||
PRIVATE
|
||||
tinyxml2::tinyxml2
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
#pragma once
|
||||
|
||||
#include <CesiumAsync/IAssetRequest.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
|
||||
/**
|
||||
* @brief Supported values for @ref AzureMapsSessionParameters::tilesetId. See
|
||||
* the [official
|
||||
* documentation](https://learn.microsoft.com/en-us/rest/api/maps/render/get-map-tile?tabs=HTTP#tilesetid)
|
||||
* for all standard values. Note that some tileset IDs return vector data, which
|
||||
* is currently unsupported.
|
||||
*/
|
||||
struct AzureMapsTilesetId {
|
||||
/**
|
||||
* @brief All layers with Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string baseRoad = "microsoft.base.road";
|
||||
|
||||
/**
|
||||
* @brief All layers with Azure Maps' dark grey style.
|
||||
*/
|
||||
inline static const std::string baseDarkGrey = "microsoft.base.darkgrey";
|
||||
|
||||
/**
|
||||
* @brief Label data in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string baseLabelsRoad = "microsoft.base.labels.road";
|
||||
|
||||
/**
|
||||
* @brief Label data in Azure Maps' dark grey style.
|
||||
*/
|
||||
inline static const std::string baseLabelsDarkGrey =
|
||||
"microsoft.base.labels.darkgrey";
|
||||
|
||||
/**
|
||||
* @brief Road, boundary and label data in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string baseHybridRoad = "microsoft.base.hybrid.road";
|
||||
|
||||
/**
|
||||
* @brief Road, boundary and label data in Azure Maps' dark grey style.
|
||||
*/
|
||||
inline static const std::string baseHybridDarkGrey =
|
||||
"microsoft.base.hybrid.darkgrey";
|
||||
|
||||
/**
|
||||
* @brief A combination of satellite or aerial imagery. Only available in S1
|
||||
* and G2 pricing SKU.
|
||||
*/
|
||||
inline static const std::string imagery = "microsoft.imagery";
|
||||
|
||||
/**
|
||||
* @brief Shaded relief and terra layers.
|
||||
*/
|
||||
inline static const std::string terra = "microsoft.terra.main";
|
||||
|
||||
/**
|
||||
* @brief Weather radar tiles. Latest weather radar images including areas of
|
||||
* rain, snow, ice and mixed conditions. For more information on the Azure
|
||||
* Maps Weather service coverage, see [Azure Maps weather services
|
||||
* coverage](https://learn.microsoft.com/en-us/azure/azure-maps/weather-coverage).
|
||||
* For more information on Radar data, see [Weather services in Azure
|
||||
* Maps](https://learn.microsoft.com/en-us/azure/azure-maps/weather-services-concepts#radar-images).
|
||||
*/
|
||||
inline static const std::string weatherRadar = "microsoft.weather.radar.main";
|
||||
|
||||
/**
|
||||
* @brief Weather infrared tiles. Latest Infrared Satellite images show
|
||||
* clouds by their temperature. For more information on the Azure Maps Weather
|
||||
* service coverage, see [Azure Maps weather services
|
||||
* coverage](https://learn.microsoft.com/en-us/azure/azure-maps/weather-coverage).
|
||||
* For more information on Radar data, see [Weather services in Azure
|
||||
* Maps](https://learn.microsoft.com/en-us/azure/azure-maps/weather-services-concepts#radar-images).
|
||||
*/
|
||||
inline static const std::string weatherInfrared =
|
||||
"microsoft.weather.infrared.main";
|
||||
|
||||
/**
|
||||
* @brief Absolute traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficAbsolute =
|
||||
"microsoft.traffic.absolute.main";
|
||||
|
||||
/**
|
||||
* @brief Relative traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficRelativeMain =
|
||||
"microsoft.traffic.relative.main";
|
||||
|
||||
/**
|
||||
* @brief Relative traffic tiles in Azure Maps' dark style.
|
||||
*/
|
||||
inline static const std::string trafficRelativeDark =
|
||||
"microsoft.traffic.relative.dark";
|
||||
|
||||
/**
|
||||
* @brief Delay traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficDelay = "microsoft.traffic.delay.main";
|
||||
|
||||
/**
|
||||
* @brief Reduced traffic tiles in Azure Maps' main style.
|
||||
*/
|
||||
inline static const std::string trafficReduced =
|
||||
"microsoft.traffic.reduced.main";
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Session parameters for an Azure Maps overlay.
|
||||
*/
|
||||
struct AzureMapsSessionParameters {
|
||||
/**
|
||||
* @brief The Azure Maps subscription key to use.
|
||||
*/
|
||||
std::string key;
|
||||
|
||||
/**
|
||||
* @brief The version number of Azure Maps API.
|
||||
*/
|
||||
std::string apiVersion{"2024-04-01"};
|
||||
|
||||
/**
|
||||
* @brief A tileset is a collection of raster or vector data broken up into a
|
||||
* uniform grid of square tiles at preset zoom levels. Every tileset has a
|
||||
* tilesetId to use when making requests. The tilesetId for tilesets created
|
||||
* using [Azure Maps Creator](https://aka.ms/amcreator) are generated through
|
||||
* the [Tileset Create
|
||||
* API](https://learn.microsoft.com/en-us/rest/api/maps-creator/tileset).
|
||||
*
|
||||
* The supported ready-to-use tilesets supplied by Azure Maps are listed
|
||||
* [here](https://learn.microsoft.com/en-us/rest/api/maps/render/get-map-tile?view=rest-maps-2025-01-01&tabs=HTTP#tilesetid).
|
||||
*/
|
||||
std::string tilesetId{AzureMapsTilesetId::baseRoad};
|
||||
|
||||
/**
|
||||
* @brief The language in which search results should be returned. Should be
|
||||
* one of the supported [IETF language
|
||||
* tags](https://en.wikipedia.org/wiki/IETF_language_tag), case insensitive.
|
||||
* When data in the specified language is not available for a specific field,
|
||||
* default language is used.
|
||||
*
|
||||
* Refer to [Supported
|
||||
* Languages](https://learn.microsoft.com/en-us/azure/azure-maps/supported-languages)
|
||||
* for details.
|
||||
*/
|
||||
std::string language{"en-US"};
|
||||
|
||||
/**
|
||||
* @brief The view (also called the "user region") of a certain country/region
|
||||
* for which to show the correct maps. Quoting the Azure Maps' documentation:
|
||||
*
|
||||
* "Different countries/regions have different views of such regions, and the
|
||||
* View parameter allows your application to comply with the view required by
|
||||
* the country/region your application will be serving. By default, the View
|
||||
* parameter is set to "Unified" even if you haven't defined it in the
|
||||
* request. It is your responsibility to determine the location of your users,
|
||||
* and then set the View parameter correctly for that location. Alternatively,
|
||||
* you have the option to set 'View=Auto', which will return the map data
|
||||
* based on the IP address of the request. The View parameter in Azure Maps
|
||||
* must be used in compliance with applicable laws, including those regarding
|
||||
* mapping, of the country/region where maps, images and other data and third
|
||||
* party content that you are authorized to access via Azure Maps is made
|
||||
* available. Example: view=IN."
|
||||
*
|
||||
* Refer to [Supported Views](https://aka.ms/AzureMapsLocalizationViews) for
|
||||
* details and to see the available Views.
|
||||
*/
|
||||
std::string view{"US"};
|
||||
|
||||
/**
|
||||
* @brief Whether or not the @ref AzureMapsRasterOverlay should show the
|
||||
* Azure Maps logo.
|
||||
*
|
||||
* Azure requires the logo to be shown, so setting this to false is only
|
||||
* valid when something else is already showing the logo.
|
||||
*/
|
||||
bool showLogo = true;
|
||||
|
||||
/**
|
||||
* @brief The base URL for the Azure Maps API.
|
||||
*/
|
||||
std::string apiBaseUrl{"https://atlas.microsoft.com/"};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A @ref RasterOverlay that retrieves imagery from the Azure Maps API.
|
||||
*/
|
||||
class CESIUMRASTEROVERLAYS_API AzureMapsRasterOverlay final
|
||||
: public RasterOverlay {
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a new instance.
|
||||
*
|
||||
* @param name The user-given name of this overlay layer.
|
||||
* @param sessionParameters The session parameters for this overlay.
|
||||
* @param overlayOptions The @ref RasterOverlayOptions for this instance.
|
||||
*/
|
||||
AzureMapsRasterOverlay(
|
||||
const std::string& name,
|
||||
const AzureMapsSessionParameters& sessionParameters,
|
||||
const RasterOverlayOptions& overlayOptions = {});
|
||||
virtual ~AzureMapsRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
private:
|
||||
AzureMapsSessionParameters _sessionParameters;
|
||||
};
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <CesiumAsync/IAssetRequest.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
||||
|
|
@ -107,32 +106,10 @@ public:
|
|||
virtual ~BingMapsRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
/**
|
||||
* @brief Refresh a previously-created tile provider using a new key.
|
||||
*
|
||||
* Calling this method on a tile provider that was not created by this \ref
|
||||
* BingMapsRasterOverlay will lead to undefined behavior.
|
||||
*
|
||||
* @param pProvider The previously-created tile provider.
|
||||
* @param newKey The new key to use.
|
||||
*/
|
||||
CesiumAsync::Future<void> refreshTileProviderWithNewKey(
|
||||
const CesiumUtility::IntrusivePointer<RasterOverlayTileProvider>&
|
||||
pProvider,
|
||||
const std::string& newKey);
|
||||
|
||||
private:
|
||||
static const std::string BING_LOGO_HTML;
|
||||
|
||||
std::string _url;
|
||||
std::string _key;
|
||||
std::string _mapStyle;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayExternals.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
|
||||
namespace CesiumUtility {
|
||||
class CreditSource;
|
||||
}
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
|
||||
class RasterOverlay;
|
||||
|
||||
/**
|
||||
* @brief Parameters passed to \ref RasterOverlay::createTileProvider.
|
||||
*/
|
||||
struct CESIUMRASTEROVERLAYS_API CreateRasterOverlayTileProviderParameters {
|
||||
/**
|
||||
* @brief The external interfaces for use by the raster overlay tile provider.
|
||||
*/
|
||||
RasterOverlayExternals externals;
|
||||
|
||||
/**
|
||||
* @brief The overlay that owns the overlay that is creating the tile
|
||||
* provider.
|
||||
*
|
||||
* If nullptr, this overlay is not aggregated, and the owner of the tile
|
||||
* provider is the overlay that created it.
|
||||
*/
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner{nullptr};
|
||||
|
||||
/**
|
||||
* @brief The credit source that the new tile provider should use for its
|
||||
* credits.
|
||||
*
|
||||
* If nullptr, a new credit source will be created for the tile provider.
|
||||
*/
|
||||
std::shared_ptr<CesiumUtility::CreditSource> pCreditSource{nullptr};
|
||||
};
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
@ -24,13 +24,7 @@ public:
|
|||
* @copydoc RasterOverlay::createTileProvider
|
||||
*/
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,13 +86,7 @@ public:
|
|||
virtual ~GeoJsonDocumentRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -252,8 +252,8 @@ struct GoogleMapTilesNewSessionParameters {
|
|||
};
|
||||
|
||||
/**
|
||||
* @brief A `RasterOverlay` that retrieves imagery from the [Google Maps Tiles
|
||||
* API](https://developers.google.com/maps/documentation/tile).
|
||||
* @brief A @ref RasterOverlay that retrieves imagery from the [Google Maps
|
||||
* Tiles API](https://developers.google.com/maps/documentation/tile).
|
||||
*/
|
||||
class CESIUMRASTEROVERLAYS_API GoogleMapTilesRasterOverlay
|
||||
: public RasterOverlay {
|
||||
|
|
@ -286,24 +286,12 @@ public:
|
|||
|
||||
/** @inheritdoc */
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
private:
|
||||
CesiumAsync::Future<CreateTileProviderResult> createNewSession(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) const;
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const;
|
||||
|
||||
std::optional<GoogleMapTilesNewSessionParameters> _newSessionParameters;
|
||||
std::optional<GoogleMapTilesExistingSession> _existingSession;
|
||||
|
|
|
|||
|
|
@ -62,13 +62,7 @@ public:
|
|||
void setAssetOptions(const std::optional<std::string>& options) noexcept;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
protected:
|
||||
|
|
@ -126,11 +120,10 @@ private:
|
|||
};
|
||||
|
||||
/** @private */
|
||||
struct Bing {
|
||||
std::string key;
|
||||
struct Azure2D {
|
||||
std::string url;
|
||||
std::string mapStyle;
|
||||
std::string culture;
|
||||
std::string tilesetId;
|
||||
std::string key;
|
||||
};
|
||||
|
||||
/** @private */
|
||||
|
|
@ -144,7 +137,21 @@ private:
|
|||
uint32_t tileHeight;
|
||||
};
|
||||
|
||||
std::variant<std::monostate, TileMapService, Bing, Google2D> options{};
|
||||
/** @private */
|
||||
struct Bing {
|
||||
std::string key;
|
||||
std::string url;
|
||||
std::string mapStyle;
|
||||
std::string culture;
|
||||
};
|
||||
|
||||
std::variant<std::monostate, TileMapService, Azure2D, Google2D, Bing>
|
||||
options{};
|
||||
|
||||
void parseAzure2DOptions(const rapidjson::Document& ionResponse);
|
||||
void parseGoogle2DOptions(const rapidjson::Document& ionResponse);
|
||||
void parseBingOptions(const rapidjson::Document& ionResponse);
|
||||
void parseTileMapServiceOptions(const rapidjson::Document& ionResponse);
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, ExternalAssetEndpoint> endpointCache;
|
||||
|
|
|
|||
|
|
@ -30,39 +30,26 @@ namespace CesiumRasterOverlays {
|
|||
*/
|
||||
class CESIUMRASTEROVERLAYS_API QuadtreeRasterOverlayTileProvider
|
||||
: public RasterOverlayTileProvider {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a new instance.
|
||||
*
|
||||
* @param pOwner The raster overlay that created this tile provider.
|
||||
* @param asyncSystem The async system used to do work in threads.
|
||||
* @param pAssetAccessor The interface used to obtain assets (tiles, etc.) for
|
||||
* this raster overlay.
|
||||
* @param pCreditSystem The credit system that receives this tile provider's
|
||||
* credits.
|
||||
* @param credit The {@link CesiumUtility::Credit} for this tile provider, if it exists.
|
||||
* @param pPrepareRendererResources The interface used to prepare raster
|
||||
* images for rendering.
|
||||
* @param pLogger The logger to which to send messages about the tile provider
|
||||
* and tiles.
|
||||
* @param pCreator The \ref RasterOverlay that directly created this instance.
|
||||
* This will become the owner of this instance if another owner is not
|
||||
* specified in \ref CreateRasterOverlayTileProviderParameters::pOwner.
|
||||
* @param parameters The parameters for creating the tile provider.
|
||||
* @param projection The {@link CesiumGeospatial::Projection}.
|
||||
* @param tilingScheme The tiling scheme to be used by this {@link QuadtreeRasterOverlayTileProvider}.
|
||||
* @param coverageRectangle The {@link CesiumGeometry::Rectangle}.
|
||||
* @param coverageRectangle The rectangle that bounds all the area covered by
|
||||
* this overlay, expressed in projected coordinates.
|
||||
* @param minimumLevel The minimum quadtree tile level.
|
||||
* @param maximumLevel The maximum quadtree tile level.
|
||||
* @param imageWidth The image width.
|
||||
* @param imageHeight The image height.
|
||||
*/
|
||||
QuadtreeRasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ namespace CesiumRasterOverlays {
|
|||
|
||||
class ActivatedRasterOverlay;
|
||||
class IPrepareRasterOverlayRendererResources;
|
||||
class RasterOverlayTileProvider;
|
||||
class RasterOverlayExternals;
|
||||
class RasterOverlayTileProvider;
|
||||
struct CreateRasterOverlayTileProviderParameters;
|
||||
|
||||
/**
|
||||
* @brief Options for loading raster overlays.
|
||||
|
|
@ -219,28 +220,12 @@ public:
|
|||
* @brief Begins asynchronous creation of a tile provider for this overlay
|
||||
* and eventually returns it via a Future.
|
||||
*
|
||||
* @param asyncSystem The async system used to do work in threads.
|
||||
* @param pAssetAccessor The interface used to download assets like overlay
|
||||
* metadata and tiles.
|
||||
* @param pCreditSystem The {@link CesiumUtility::CreditSystem} to use when creating a
|
||||
* per-TileProvider {@link CesiumUtility::Credit}.
|
||||
* @param pPrepareRendererResources The interface used to prepare raster
|
||||
* images for rendering.
|
||||
* @param pLogger The logger to which to send messages about the tile provider
|
||||
* and tiles.
|
||||
* @param pOwner The overlay that owns this overlay, or nullptr if this
|
||||
* overlay is not aggregated.
|
||||
* @param parameters The parameters for creating the tile provider.
|
||||
* @return The future that resolves to the tile provider when it is ready, or
|
||||
* to error details in the case of an error.
|
||||
*/
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const = 0;
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const = 0;
|
||||
|
||||
private:
|
||||
struct DestructionCompleteDetails {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public:
|
|||
* This may only be `nullptr` if the raster overlay does not attempt to
|
||||
* download any resources.
|
||||
*/
|
||||
std::shared_ptr<CesiumAsync::IAssetAccessor> pAssetAccessor;
|
||||
std::shared_ptr<CesiumAsync::IAssetAccessor> pAssetAccessor = nullptr;
|
||||
|
||||
/**
|
||||
* @brief The @ref IPrepareRasterOverlayRendererResources that is used to
|
||||
|
|
@ -34,7 +34,7 @@ public:
|
|||
* for raster overlays.
|
||||
*/
|
||||
std::shared_ptr<IPrepareRasterOverlayRendererResources>
|
||||
pPrepareRendererResources;
|
||||
pPrepareRendererResources = nullptr;
|
||||
|
||||
/**
|
||||
* @brief The async system to use to do work in threads.
|
||||
|
|
@ -49,7 +49,7 @@ public:
|
|||
* While not recommended, this may be `nullptr` if the client does not need to
|
||||
* receive credits.
|
||||
*/
|
||||
std::shared_ptr<CesiumUtility::CreditSystem> pCreditSystem;
|
||||
std::shared_ptr<CesiumUtility::CreditSystem> pCreditSystem = nullptr;
|
||||
|
||||
/**
|
||||
* @brief A spdlog logger that will receive log messages.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace CesiumRasterOverlays {
|
|||
class RasterOverlay;
|
||||
class RasterOverlayTile;
|
||||
class IPrepareRasterOverlayRendererResources;
|
||||
struct CreateRasterOverlayTileProviderParameters;
|
||||
|
||||
/**
|
||||
* @brief Summarizes the result of loading an image of a {@link RasterOverlay}.
|
||||
|
|
@ -139,32 +140,17 @@ public:
|
|||
/**
|
||||
* @brief Creates a new instance.
|
||||
*
|
||||
* @param pOwner The raster overlay that created this tile provider.
|
||||
* @param externals The external interfaces for use by the raster overlay.
|
||||
* @param pCreator The \ref RasterOverlay that directly created this instance.
|
||||
* This will become the owner of this instance if another owner is not
|
||||
* specified in \ref CreateRasterOverlayTileProviderParameters::pOwner.
|
||||
* @param parameters The parameters for creating the tile provider.
|
||||
* @param projection The {@link CesiumGeospatial::Projection}.
|
||||
* @param coverageRectangle The rectangle that bounds all the area covered by
|
||||
* this overlay, expressed in projected coordinates.
|
||||
*/
|
||||
RasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const RasterOverlayExternals& externals,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new instance.
|
||||
* @deprecated Use the overload that takes a \ref RasterOverlayExternals
|
||||
* instead.
|
||||
*/
|
||||
RasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle) noexcept;
|
||||
|
||||
|
|
@ -233,12 +219,27 @@ public:
|
|||
const CesiumGeometry::Rectangle& getCoverageRectangle() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the per-TileProvider {@link CesiumUtility::Credit} if one exists.
|
||||
* @deprecated Implement {@link addCredits} instead.
|
||||
* @brief Gets the @ref CesiumUtility::CreditSource that identifies this
|
||||
* raster overlay's credits with the @ref CesiumUtility::CreditSystem.
|
||||
*/
|
||||
[[deprecated(
|
||||
"Use addCredits instead.")]] const std::optional<CesiumUtility::Credit>&
|
||||
getCredit() const noexcept;
|
||||
const CesiumUtility::CreditSource& getCreditSource() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the collection of credits that should be shown whenever this
|
||||
* tile provider is shown.
|
||||
*
|
||||
* If called on a non-const instance, the returned collection may be modified
|
||||
* to add or remove credits.
|
||||
*
|
||||
* The credits in this collection will be added to the @ref
|
||||
* CesiumUtility::CreditReferencer in @ref addCredits.
|
||||
*/
|
||||
std::vector<CesiumUtility::Credit>& getCredits() noexcept;
|
||||
|
||||
/**
|
||||
* @copydoc getCredits
|
||||
*/
|
||||
const std::vector<CesiumUtility::Credit>& getCredits() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Loads the image for a tile.
|
||||
|
|
@ -286,9 +287,10 @@ private:
|
|||
|
||||
CesiumUtility::IntrusivePointer<RasterOverlay> _pOwner;
|
||||
RasterOverlayExternals _externals;
|
||||
std::optional<CesiumUtility::Credit> _credit;
|
||||
std::vector<CesiumUtility::Credit> _credits;
|
||||
CesiumGeospatial::Projection _projection;
|
||||
CesiumGeometry::Rectangle _coverageRectangle;
|
||||
std::optional<DestructionCompleteDetails> _destructionCompleteDetails;
|
||||
std::shared_ptr<CesiumUtility::CreditSource> _pCreditSource;
|
||||
};
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -50,13 +50,7 @@ public:
|
|||
virtual ~RasterizedPolygonsOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -106,36 +106,9 @@ public:
|
|||
virtual ~TileMapServiceRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
/**
|
||||
* @brief Refresh a previously-created tile provider using a new URL and
|
||||
* request headers. This is primarily useful to refresh an access token after
|
||||
* it expires.
|
||||
*
|
||||
* Calling this method on a tile provider that was not created by this \ref
|
||||
* TileMapServiceRasterOverlay will lead to undefined behavior.
|
||||
*
|
||||
* @param pProvider The previously-created tile provider.
|
||||
* @param newUrl The new URL to use. If `std::nullopt`, the existing URL is
|
||||
* unchanged.
|
||||
* @param newHeaders The new request headers to use. If `std::nullopt`, the
|
||||
* existing headers are unchanged.
|
||||
*/
|
||||
CesiumAsync::Future<void> refreshTileProviderWithNewUrlAndHeaders(
|
||||
const CesiumUtility::IntrusivePointer<RasterOverlayTileProvider>&
|
||||
pProvider,
|
||||
const std::optional<std::string>& newUrl,
|
||||
const std::optional<std::vector<CesiumAsync::IAssetAccessor::THeader>>&
|
||||
newHeaders);
|
||||
|
||||
private:
|
||||
std::string _url;
|
||||
std::vector<CesiumAsync::IAssetAccessor::THeader> _headers;
|
||||
|
|
|
|||
|
|
@ -119,13 +119,7 @@ public:
|
|||
_options(urlTemplateOptions) {}
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -88,13 +88,7 @@ public:
|
|||
virtual ~WebMapServiceRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -140,13 +140,7 @@ public:
|
|||
virtual ~WebMapTileServiceRasterOverlay() override;
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,591 @@
|
|||
#include <CesiumAsync/Future.h>
|
||||
#include <CesiumAsync/IAssetAccessor.h>
|
||||
#include <CesiumAsync/IAssetResponse.h>
|
||||
#include <CesiumGeometry/QuadtreeTileID.h>
|
||||
#include <CesiumGeometry/Rectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
#include <CesiumJsonReader/JsonObjectJsonHandler.h>
|
||||
#include <CesiumJsonReader/JsonReader.h>
|
||||
#include <CesiumRasterOverlays/AzureMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/ErrorList.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/JsonHelpers.h>
|
||||
#include <CesiumUtility/JsonValue.h>
|
||||
#include <CesiumUtility/Uri.h>
|
||||
#include <CesiumUtility/joinToString.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace CesiumAsync;
|
||||
using namespace CesiumGeometry;
|
||||
using namespace CesiumGeospatial;
|
||||
using namespace CesiumJsonReader;
|
||||
using namespace CesiumUtility;
|
||||
|
||||
namespace {
|
||||
std::unordered_map<std::string, std::vector<std::byte>> sessionCache;
|
||||
} // namespace
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
const std::string AZURE_MAPS_LOGO_HTML =
|
||||
"<img alt=\"Microsoft Azure\" "
|
||||
"src=\"data:image/"
|
||||
"png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAM0AAAAnCAYAAACsY8yNAAAAAXNSR0IB2cksfwAAAAlwSFlzAA"
|
||||
"ALEwAACxMBAJqcGAAACaFJREFUeJztWweMVUUU3QUUUURBUIqBFZBFUbGgQQFDlCi2KAr2Hl2w"
|
||||
"oRRFxQgaVDYrxIINBCyASrHFFRCU2KMIlgixF4wVdBELosD1HuaO7/757/333vJ1/"
|
||||
"8c5ycnfd+fOvGl35s6dtyUlHh4eHh4eHh4eHh4eHh4e/2/8ckL7mWm4pl/"
|
||||
"7GT+d2q7lmLklZ4x6rmRmGt4wv+"
|
||||
"TYum6vh8dmgw2B0pCNZh0bze5sNJVsCJSSV9Z1ez08NhveaDw8UsIbjYdHSnij2TJBRE2ZBzB7"
|
||||
"MTvVdX22KGzpRsMTphVzMLPDf/"
|
||||
"3uugK39RLmV8yNZPBVXddpi0IhGQ0P7vHMvxRXMJvFtYF1Zjr5hom8DfM7mTjfM1vnq98KFdzG"
|
||||
"E5l/Uia+yVPZw1Uf/46dLB/"
|
||||
"lFh0KzGj6UTb6x+"
|
||||
"RpK4OocaWk7cfcILL1zL3z2XeFBm5fPebr0l7sMmczd2R2ZjZg7sMcz5xci7KR/y2nnyv/"
|
||||
"jXYUPIrAaGZjMuTIMyEkjzWarZnXM99g3oTnfPdfIYHMOeYb6YP3nbRy5jpJW1CLsrsx10p+"
|
||||
"uxAtYzbKXwuKBAVsNHaA4FZ1idBvwvxC9Fa7RvN/"
|
||||
"A7e7BfMH6YNFTloX1T+1MZp7Vf5n5RduYI/8taBIUMBGM40C33xchP4pauW71TUa/"
|
||||
"m3IPJNZwTyN2cDJD5ejB3MM80HmI8xK5uFWV95RIb9wf/"
|
||||
"qKzlXMrVRZcH2GMCcxHybjBp3D3C6i7nsyR4rudCmzd4jetlL3KtGdLO/"
|
||||
"e39E7nzmMuUb64EOpt+Vo1T/LlbxrrjGRsrdn/"
|
||||
"ip5n8O7tQFF5NnLeX8onT4GG4a036adpOTHKDl22AOZN0o/"
|
||||
"7qr0OjCHMu8m45VcziyLa3NOFLDRnM58W/"
|
||||
"7+lFnf0S1lzpH0xWQiRhbWaODPfy2yz0lNYP67GXMq82fKxk/"
|
||||
"MtqL3ocg+Zl6kJs+m8pjbMK+jIOCggXPUIuYhTt37q3ppzHf0Dma+TNkHe2AVGSPdVnR/"
|
||||
"C9FJgthdmTLH5Swyi80KeYZHsFNInssTvHut08dAU6ecVirtHSVfoOSXkvFILHqKDuqqo4gWH5"
|
||||
"EywNQoYKPBSjJcPR/q6JZRMOHRaYmNhswONIcy8RnzRSkTE6G9M6BrKXAZ/"
|
||||
"ymPeZdTzifMJZQ50b8lWd3IBC5+FDkCGLOYj4lsgWpfRzLGa/"
|
||||
"EHmbPZCiXDDlsl+v+m0cwSXdSxlchuUmVUhOTBmKwLoZ3A+"
|
||||
"B3o9DFQG6OpcdrUk8wCZwNEcN3hXt5PwbigLgfGtT0UP/"
|
||||
"ffbUoarh5QNnHVGW13GVtdOmDMvJIpKXlUzOC4RrM7BSs7ttd6Sne8yDGRd6Z0RoMVer3IsRL1"
|
||||
"sGWTcQcGosyQAYXu4TKQuDTcV5WD95yo6gejfkLlnSjyQUo2QunDkHvL3whgLFJ69zCbS1p9yt"
|
||||
"zxYOS7Sb3bMVeK/CUyRm3ZTZX3gpL/"
|
||||
"42JGjElz9S6cZUpFrscm0RmJ9Y6mIBhRTRKYoc03Giwu8Exaow/JuI/"
|
||||
"2bIdFpovK14OCxfahJPXOxvSaNmlZb9qqBmvm1G/"
|
||||
"y+5OlrVOycUynukZTSsGhEx1TLnqNKPDdbxVZGqNZLjIM+"
|
||||
"pExdbIDmnXo5ecH1DvDVttmFKxsG6Q+2m2ZSM45S/IhVG6NETtXYycd/"
|
||||
"VKpyhkk8rwHAihzRznPqcNLqm05vzogs4jYuqFPy1Ta5hrNSCdPhUrrF1KX+ZJWy/"
|
||||
"ur6TWrU3Ils+"
|
||||
"Nfz5SO3ji3pCYlL4vp2AyjERlWELuljxDZafKMVaubyBIZjchsyPQVCpm0Tp3sgGLFaqLk2A0+"
|
||||
"UPXoHJF/iapXdzIBALvSbZA6XEiyk0ies1SeaRHlHq107hVZXo2GzOK0TPLA/"
|
||||
"cMq3UbxFlXmhBzlNCZzdWD7qndEHwO1MRrXddeRPgRZ7nP4iaRtTNIP2ZheQyn5J7PT+"
|
||||
"uqSSprH9UvHVGcakbWkYHK+SuYQ+"
|
||||
"qQ8v8fcRvSSGk250ns0rnvUgOLwuLWS70DGXQPgM7eJyD9Pva8PmRUad0f6QhaLAi4Ou0qewSo"
|
||||
"tKnJ4kNKZLbJ8Gw1cOrtTor5fSj9a6sM3AiVRkcJrVXun5OhjoDZG08XJM5sSIkk/"
|
||||
"ZKPAjUbkQ0WGAcQtt3VdhimdpEbTUelVx3UPRRsNVs8vJA2rcFlE/"
|
||||
"lfU+7oreVcyQYRfVToCBjsxL1ay+yLKPczVofwbzXhKDhh+"
|
||||
"35AysDtZg3mNHFfT6WPANZrWKi2p0Tyi0hBMGhzFJP2QjeIwmnYUrHir5BeTbQ+"
|
||||
"lk9RocGC2h1FM+"
|
||||
"rKYOkUZDe5sXo2ZMA1VfTFxWjjpONTDZXtX1f08ynS9MNHCzj1DlM4lIktqNAtztVn0cR6zrhm"
|
||||
"CLaMjOEOVe49TBiKFb0oaIm/"
|
||||
"7RrxruSqjzEk7QKUlNRp93su4z8oPisBoJG0+"
|
||||
"ZQIumo6mpQkEVCtdBBrcS08cxJvK36FGI2nnqnKwo7RQaTAqHTKfJvJDyPkIlZ+"
|
||||
"vVnowBkQD7eSHsZ3s6MMA7C6HxaOTyHMZTWf1jo9yjYPoX0DBjj43h14zpYdzXzuRY0F4XL0z8"
|
||||
"jzLaQuV3mAnbZJKS2o0fVXapkhhyDsRFcy6X0qG4jEaHI713UdPJz2N0eDSUF9GYqWHK4KV82n"
|
||||
"mL5R9TxNmNLjY1KskJnKVlIOzjJ1M2G06Sx58BQA3bILUeQQFB1PsgDZCOFCVC/"
|
||||
"cPExBnodskvwVC8TYMnMtosMvqeyYckPElROglH5mbf4uLY8btedHDjjtcZOeq9q+R+"
|
||||
"s8IIXbj8ykI9qDvx5H5uuExyryYTGo08CYWq/"
|
||||
"S3pJ8RVELIfyqZYEzo51nxKB6jwQS1W33WSknpvwg4lII7DRf47D3WaCQddyTLIsoBECzoo/"
|
||||
"RHRughkjbcKRufhYR9DWD1MbkaKf1Io5F0HMjd2/GsMSETfNFfh+f8lwrKNPClInO/PI/"
|
||||
"Cprsi5lMRbbxNPScyGtUXb1M00K7yXO2KRmEZDb5XqhJmhXBZdpykZa2OZNwem7e3yBAyvU5k1"
|
||||
"1D2TlEucqyqCA3j/PAQmW+h7MXbVZIfv/"
|
||||
"Xd94oOImmYODiALpaycLEJt6tVyDtvJuNuLiXj1iEMegQ5X3OTcfGwK95OZjXHJMDdyB1kXBD3"
|
||||
"0yIEJ0ZJfQeF1BP9MVTKQh2rKfx7t71VX14R1mZHv6XSHyvvqUpI28/oQ5zn8A0gvta4U/"
|
||||
"qkqdIdot5ZoeS7RNQLruOlUh7GBTvOM9L/"
|
||||
"vaLGMx4FZDQeHsUBbzQeHinhjcbDIyW80Xh4pIQ3Gg8PDw8PDw8PDw8PDw8PDw8PDw8Pj9T4G6"
|
||||
"U/URjRT3IrAAAAAElFTkSuQmCC\"/>";
|
||||
|
||||
namespace {
|
||||
Rectangle createRectangle(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
pOwner->getOptions().ellipsoid);
|
||||
}
|
||||
|
||||
QuadtreeTilingScheme createTilingScheme(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return QuadtreeTilingScheme(createRectangle(pOwner), 1, 1);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class AzureMapsRasterOverlayTileProvider final
|
||||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
AzureMapsRasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const std::string& credit,
|
||||
const std::string& baseUrl,
|
||||
const std::string& apiVersion,
|
||||
const std::string& tilesetId,
|
||||
const std::string& key,
|
||||
const std::string& tileEndpoint,
|
||||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel,
|
||||
uint32_t imageSize,
|
||||
bool showLogo);
|
||||
|
||||
virtual ~AzureMapsRasterOverlayTileProvider() = default;
|
||||
|
||||
void update(const AzureMapsRasterOverlayTileProvider& newProvider) {
|
||||
this->_baseUrl = newProvider._baseUrl;
|
||||
this->_apiVersion = newProvider._apiVersion;
|
||||
this->_tilesetId = newProvider._tilesetId;
|
||||
this->_key = newProvider._key;
|
||||
this->_tileEndpoint = newProvider._tileEndpoint;
|
||||
}
|
||||
|
||||
CesiumAsync::Future<void> loadCredits();
|
||||
|
||||
protected:
|
||||
virtual CesiumAsync::Future<LoadedRasterOverlayImage> loadQuadtreeTileImage(
|
||||
const CesiumGeometry::QuadtreeTileID& tileID) const override;
|
||||
|
||||
private:
|
||||
std::string _baseUrl;
|
||||
std::string _apiVersion;
|
||||
std::string _tilesetId;
|
||||
std::string _key;
|
||||
std::string _tileEndpoint;
|
||||
};
|
||||
|
||||
AzureMapsRasterOverlay::AzureMapsRasterOverlay(
|
||||
const std::string& name,
|
||||
const AzureMapsSessionParameters& sessionParameters,
|
||||
const RasterOverlayOptions& overlayOptions)
|
||||
: RasterOverlay(name, overlayOptions),
|
||||
_sessionParameters(sessionParameters) {
|
||||
Uri baseUrl(this->_sessionParameters.apiBaseUrl);
|
||||
baseUrl.ensureTrailingSlash();
|
||||
this->_sessionParameters.apiBaseUrl = baseUrl.toString();
|
||||
}
|
||||
|
||||
AzureMapsRasterOverlay::~AzureMapsRasterOverlay() = default;
|
||||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
AzureMapsRasterOverlay::createTileProvider(
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
Uri tilesetUri(this->_sessionParameters.apiBaseUrl, "map/tileset");
|
||||
|
||||
UriQuery tilesetQuery(tilesetUri);
|
||||
tilesetQuery.setValue("api-version", this->_sessionParameters.apiVersion);
|
||||
tilesetQuery.setValue("tilesetId", this->_sessionParameters.tilesetId);
|
||||
tilesetQuery.setValue("subscription-key", this->_sessionParameters.key);
|
||||
tilesetQuery.setValue("language", this->_sessionParameters.language);
|
||||
tilesetQuery.setValue("view", this->_sessionParameters.view);
|
||||
tilesetUri.setQuery(tilesetQuery.toQueryString());
|
||||
|
||||
std::string tilesetUrl = std::string(tilesetUri.toString());
|
||||
|
||||
IntrusivePointer<const AzureMapsRasterOverlay> thiz = this;
|
||||
|
||||
auto handleResponse =
|
||||
[parameters, thiz](
|
||||
const std::shared_ptr<IAssetRequest>& pRequest,
|
||||
const std::span<const std::byte>& data) -> CreateTileProviderResult {
|
||||
JsonObjectJsonHandler handler{};
|
||||
ReadJsonResult<JsonValue> response = JsonReader::readJson(data, handler);
|
||||
|
||||
if (!response.value) {
|
||||
ErrorList errorList{};
|
||||
errorList.errors = std::move(response.errors);
|
||||
errorList.warnings = std::move(response.warnings);
|
||||
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = errorList.format("Failed to parse response from Azure "
|
||||
"Maps tileset API service:")});
|
||||
}
|
||||
|
||||
if (!response.value->isObject()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service was not a "
|
||||
"JSON object."});
|
||||
}
|
||||
const JsonValue::Object& responseObject = response.value->getObject();
|
||||
|
||||
uint32_t tileSize = 256u;
|
||||
uint32_t minimumLevel = 0u;
|
||||
uint32_t maximumLevel = 22u;
|
||||
|
||||
// "tileSize" is an optional enum property that is delivered as a string.
|
||||
std::string tileSizeEnum = "256";
|
||||
auto it = responseObject.find("tileSize");
|
||||
if (it != responseObject.end() && it->second.isString()) {
|
||||
tileSizeEnum = it->second.getString();
|
||||
}
|
||||
|
||||
try {
|
||||
tileSize = static_cast<uint32_t>(std::stoul(tileSizeEnum));
|
||||
} catch (std::exception&) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'tileSize' property."});
|
||||
}
|
||||
|
||||
it = responseObject.find("minzoom");
|
||||
if (it != responseObject.end() && it->second.isNumber()) {
|
||||
minimumLevel = it->second.getSafeNumberOrDefault<uint32_t>(0);
|
||||
} else if (it != responseObject.end()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'minzoom' property."});
|
||||
}
|
||||
|
||||
it = responseObject.find("maxzoom");
|
||||
if (it != responseObject.end() && it->second.isNumber()) {
|
||||
maximumLevel = it->second.getSafeNumberOrDefault<uint32_t>(0);
|
||||
} else if (it != responseObject.end()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'maxzoom' property."});
|
||||
}
|
||||
|
||||
std::vector<std::string> tiles;
|
||||
it = responseObject.find("tiles");
|
||||
if (it != responseObject.end()) {
|
||||
tiles = it->second.getArrayOfStrings(std::string());
|
||||
}
|
||||
|
||||
if (tiles.empty()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = "Response from Azure Maps tileset API service did not "
|
||||
"contain a valid "
|
||||
"'tiles' property."});
|
||||
}
|
||||
|
||||
std::string tileEndpoint;
|
||||
for (const std::string& endpoint : tiles) {
|
||||
// Azure Maps documentation: "If multiple endpoints are specified, clients
|
||||
// may use any combination of endpoints. All endpoints MUST return the
|
||||
// same content for the same URL."
|
||||
// This just picks the first non-empty string endpoint.
|
||||
if (!endpoint.empty()) {
|
||||
tileEndpoint = endpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tileEndpoint.empty()) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::TileProvider,
|
||||
pRequest,
|
||||
"Azure Maps returned no valid endpoints for the given tilesetId."});
|
||||
}
|
||||
|
||||
std::string topLevelCredit;
|
||||
|
||||
it = responseObject.find("attribution");
|
||||
if (it != responseObject.end() && it->second.isString()) {
|
||||
topLevelCredit = it->second.getString();
|
||||
}
|
||||
|
||||
auto* pProvider = new AzureMapsRasterOverlayTileProvider(
|
||||
thiz,
|
||||
parameters,
|
||||
topLevelCredit,
|
||||
thiz->_sessionParameters.apiBaseUrl,
|
||||
thiz->_sessionParameters.apiVersion,
|
||||
thiz->_sessionParameters.tilesetId,
|
||||
thiz->_sessionParameters.key,
|
||||
tileEndpoint,
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
tileSize,
|
||||
thiz->_sessionParameters.showLogo);
|
||||
|
||||
// Start loading credits, but don't wait for the load to finish.
|
||||
pProvider->loadCredits();
|
||||
|
||||
return pProvider;
|
||||
};
|
||||
|
||||
auto cacheResultIt = sessionCache.find(tilesetUrl);
|
||||
if (cacheResultIt != sessionCache.end()) {
|
||||
return parameters.externals.asyncSystem.createResolvedFuture(
|
||||
handleResponse(nullptr, std::span<std::byte>(cacheResultIt->second)));
|
||||
}
|
||||
|
||||
return parameters.externals.pAssetAccessor
|
||||
->get(parameters.externals.asyncSystem, tilesetUrl)
|
||||
.thenInMainThread(
|
||||
[tilesetUrl,
|
||||
handleResponse](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
-> CreateTileProviderResult {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
|
||||
if (!pResponse) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::TileProvider,
|
||||
pRequest,
|
||||
"No response received from Azure Maps imagery tileset "
|
||||
"service."});
|
||||
}
|
||||
|
||||
if (pResponse->statusCode() < 200 ||
|
||||
pResponse->statusCode() >= 300) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message = fmt::format(
|
||||
"Azure Maps API tileset request service returned "
|
||||
"HTTP status code {}.",
|
||||
pResponse->statusCode())});
|
||||
}
|
||||
|
||||
CreateTileProviderResult handleResponseResult =
|
||||
handleResponse(pRequest, pResponse->data());
|
||||
|
||||
// If the response successfully created a tile provider, cache it.
|
||||
if (handleResponseResult) {
|
||||
sessionCache[tilesetUrl] = std::vector<std::byte>(
|
||||
pResponse->data().begin(),
|
||||
pResponse->data().end());
|
||||
}
|
||||
|
||||
return handleResponseResult;
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
CesiumAsync::Future<rapidjson::Document> fetchAttributionData(
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const std::string& apiBaseUrl,
|
||||
const std::string& apiVersion,
|
||||
const std::string& tilesetId,
|
||||
const std::string& key,
|
||||
uint32_t zoom,
|
||||
const Rectangle& rectangleDegrees) {
|
||||
std::vector<std::string> bounds(4);
|
||||
bounds[0] = std::to_string(rectangleDegrees.minimumX); // west
|
||||
bounds[1] = std::to_string(rectangleDegrees.minimumY); // south
|
||||
bounds[2] = std::to_string(rectangleDegrees.maximumX); // east
|
||||
bounds[3] = std::to_string(rectangleDegrees.maximumY); // north
|
||||
|
||||
Uri attributionUri(apiBaseUrl, "map/attribution", true);
|
||||
|
||||
UriQuery query(attributionUri);
|
||||
query.setValue("api-version", apiVersion);
|
||||
query.setValue("subscription-key", key);
|
||||
query.setValue("tilesetId", tilesetId);
|
||||
query.setValue("zoom", std::to_string(zoom));
|
||||
query.setValue("bounds", joinToString(bounds, ","));
|
||||
attributionUri.setQuery(query.toQueryString());
|
||||
|
||||
return pAssetAccessor
|
||||
->get(asyncSystem, std::string(attributionUri.toString()))
|
||||
.thenInMainThread(
|
||||
[pLogger](const std::shared_ptr<IAssetRequest>& pRequest)
|
||||
-> rapidjson::Document {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
rapidjson::Document document;
|
||||
|
||||
if (!pResponse) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
pLogger,
|
||||
"No response received from Azure Maps API attribution "
|
||||
"service.");
|
||||
return document;
|
||||
}
|
||||
|
||||
if (pResponse->statusCode() < 200 ||
|
||||
pResponse->statusCode() >= 300) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
pLogger,
|
||||
"Error response {} received from Azure Maps API attribution "
|
||||
"service URL {}.",
|
||||
pResponse->statusCode(),
|
||||
pRequest->url());
|
||||
return document;
|
||||
}
|
||||
|
||||
document.Parse(
|
||||
reinterpret_cast<const char*>(pResponse->data().data()),
|
||||
pResponse->data().size());
|
||||
|
||||
if (document.HasParseError()) {
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
pLogger,
|
||||
"Error when parsing Azure Maps API attribution service JSON "
|
||||
"from URL {}, error code {} at byte offset {}.",
|
||||
pRequest->url(),
|
||||
document.GetParseError(),
|
||||
document.GetErrorOffset());
|
||||
}
|
||||
|
||||
return document;
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AzureMapsRasterOverlayTileProvider::AzureMapsRasterOverlayTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const std::string& credit,
|
||||
const std::string& baseUrl,
|
||||
const std::string& apiVersion,
|
||||
const std::string& tilesetId,
|
||||
const std::string& key,
|
||||
const std::string& tileEndpoint,
|
||||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel,
|
||||
uint32_t imageSize,
|
||||
bool showLogo)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pCreator,
|
||||
parameters,
|
||||
WebMercatorProjection(pCreator->getOptions().ellipsoid),
|
||||
createTilingScheme(pCreator),
|
||||
createRectangle(pCreator),
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
imageSize,
|
||||
imageSize),
|
||||
_baseUrl(baseUrl),
|
||||
_apiVersion(apiVersion),
|
||||
_tilesetId(tilesetId),
|
||||
_key(key),
|
||||
_tileEndpoint(tileEndpoint) {
|
||||
if (parameters.externals.pCreditSystem) {
|
||||
if (!credit.empty()) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
credit,
|
||||
pCreator->getOptions().showCreditsOnScreen));
|
||||
}
|
||||
|
||||
if (showLogo) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
AZURE_MAPS_LOGO_HTML,
|
||||
true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CesiumAsync::Future<LoadedRasterOverlayImage>
|
||||
AzureMapsRasterOverlayTileProvider::loadQuadtreeTileImage(
|
||||
const CesiumGeometry::QuadtreeTileID& tileID) const {
|
||||
Uri uri(CesiumUtility::Uri::substituteTemplateParameters(
|
||||
this->_tileEndpoint,
|
||||
[this, &tileID](const std::string& key) {
|
||||
if (key == "z") {
|
||||
return std::to_string(tileID.level);
|
||||
}
|
||||
if (key == "x") {
|
||||
return std::to_string(tileID.x);
|
||||
}
|
||||
if (key == "y") {
|
||||
return std::to_string(
|
||||
tileID.computeInvertedY(this->getTilingScheme()));
|
||||
}
|
||||
return key;
|
||||
}));
|
||||
|
||||
UriQuery query(uri);
|
||||
query.setValue("subscription-key", this->_key);
|
||||
uri.setQuery(query.toQueryString());
|
||||
|
||||
std::string url = std::string(uri.toString());
|
||||
|
||||
LoadTileImageFromUrlOptions options;
|
||||
options.allowEmptyImages = true;
|
||||
options.moreDetailAvailable = tileID.level < this->getMaximumLevel();
|
||||
options.rectangle = this->getTilingScheme().tileToRectangle(tileID);
|
||||
|
||||
return this->loadTileImageFromUrl(url, {}, std::move(options));
|
||||
}
|
||||
|
||||
Future<void> AzureMapsRasterOverlayTileProvider::loadCredits() {
|
||||
const uint32_t maximumZoomLevel = this->getMaximumLevel();
|
||||
|
||||
IntrusivePointer thiz = this;
|
||||
|
||||
std::vector<Future<std::vector<std::string>>> creditFutures;
|
||||
creditFutures.reserve(maximumZoomLevel + 1);
|
||||
|
||||
for (size_t i = 0; i <= maximumZoomLevel; ++i) {
|
||||
creditFutures.emplace_back(
|
||||
fetchAttributionData(
|
||||
this->getAssetAccessor(),
|
||||
this->getAsyncSystem(),
|
||||
this->getLogger(),
|
||||
this->_baseUrl,
|
||||
this->_apiVersion,
|
||||
this->_tilesetId,
|
||||
this->_key,
|
||||
uint32_t(i),
|
||||
Rectangle(-180.0, -90.0, 180.0, 90.0))
|
||||
.thenInMainThread([](rapidjson::Document&& document) {
|
||||
if (document.HasParseError() || !document.IsObject()) {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
return JsonHelpers::getStrings(document, "copyrights");
|
||||
}));
|
||||
}
|
||||
|
||||
return this->getAsyncSystem()
|
||||
.all(std::move(creditFutures))
|
||||
.thenInMainThread([thiz](
|
||||
std::vector<std::vector<std::string>>&& results) {
|
||||
std::set<std::string> uniqueCredits;
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
const std::vector<std::string>& credits = results[i];
|
||||
for (size_t j = 0; j < credits.size(); j++) {
|
||||
if (!credits[j].empty()) {
|
||||
uniqueCredits.insert(credits[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& credit : uniqueCredits) {
|
||||
thiz->getCredits().emplace_back(thiz->getCreditSystem()->createCredit(
|
||||
thiz->getCreditSource(),
|
||||
credit,
|
||||
thiz->getOwner().getOptions().showCreditsOnScreen));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
@ -2,11 +2,12 @@
|
|||
#include <CesiumAsync/IAssetAccessor.h>
|
||||
#include <CesiumAsync/IAssetResponse.h>
|
||||
#include <CesiumGeometry/QuadtreeTileID.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumGeometry/Rectangle.h>
|
||||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
#include <CesiumRasterOverlays/BingMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
|
|
@ -21,8 +22,6 @@
|
|||
#include <nonstd/expected.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/pointer.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
|
@ -46,6 +45,11 @@ struct CoverageArea {
|
|||
uint32_t zoomMax;
|
||||
};
|
||||
|
||||
struct CreditStringAndCoverageAreas {
|
||||
std::string credit;
|
||||
std::vector<CoverageArea> coverageAreas;
|
||||
};
|
||||
|
||||
struct CreditAndCoverageAreas {
|
||||
Credit credit;
|
||||
std::vector<CoverageArea> coverageAreas;
|
||||
|
|
@ -68,7 +72,9 @@ const std::string BingMapsStyle::CANVAS_GRAY = "CanvasGray";
|
|||
const std::string BingMapsStyle::ORDNANCE_SURVEY = "OrdnanceSurvey";
|
||||
const std::string BingMapsStyle::COLLINS_BART = "CollinsBart";
|
||||
|
||||
const std::string BingMapsRasterOverlay::BING_LOGO_HTML =
|
||||
namespace {
|
||||
|
||||
const std::string BING_LOGO_HTML =
|
||||
"<a href=\"http://www.bing.com\"><img "
|
||||
"src=\"data:image/"
|
||||
"png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAAATCAMAAAAj1DqpAAAAq1BMVEUAAAD////"
|
||||
|
|
@ -94,18 +100,24 @@ const std::string BingMapsRasterOverlay::BING_LOGO_HTML =
|
|||
"OXfbBoeDOo8wHpy8lKpvoafRoG6YgXFYKP4GSj63gtwWfhHzl7Skq9JTshAAAAAElFTkSuQmCC"
|
||||
"\" title=\"Bing Imagery\"/></a>";
|
||||
|
||||
Rectangle createRectangle(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
pOwner->getOptions().ellipsoid);
|
||||
}
|
||||
|
||||
QuadtreeTilingScheme createTilingScheme(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
return QuadtreeTilingScheme(createRectangle(pOwner), 2, 2);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class BingMapsTileProvider final : public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
BingMapsTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
Credit bingCredit,
|
||||
const std::vector<CreditAndCoverageAreas>& perTileCredits,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const std::vector<CreditStringAndCoverageAreas>& perTileCredits,
|
||||
const std::string& baseUrl,
|
||||
const std::string& urlTemplate,
|
||||
const std::vector<std::string>& subdomains,
|
||||
|
|
@ -113,32 +125,41 @@ public:
|
|||
uint32_t height,
|
||||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel,
|
||||
const std::string& culture,
|
||||
const CesiumGeospatial::Ellipsoid& ellipsoid)
|
||||
const std::string& culture)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
bingCredit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
WebMercatorProjection(ellipsoid),
|
||||
QuadtreeTilingScheme(
|
||||
WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
ellipsoid),
|
||||
2,
|
||||
2),
|
||||
WebMercatorProjection::computeMaximumProjectedRectangle(ellipsoid),
|
||||
pCreator,
|
||||
parameters,
|
||||
WebMercatorProjection(pCreator->getOptions().ellipsoid),
|
||||
createTilingScheme(pCreator),
|
||||
createRectangle(pCreator),
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
width,
|
||||
height),
|
||||
_credits(perTileCredits),
|
||||
_credits(),
|
||||
_baseUrl(baseUrl),
|
||||
_urlTemplate(urlTemplate),
|
||||
_culture(culture),
|
||||
_subdomains(subdomains) {}
|
||||
_subdomains(subdomains) {
|
||||
if (parameters.externals.pCreditSystem) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
BING_LOGO_HTML,
|
||||
pCreator->getOptions().showCreditsOnScreen));
|
||||
|
||||
this->_credits.reserve(perTileCredits.size());
|
||||
for (const CreditStringAndCoverageAreas& creditStringAndCoverageAreas :
|
||||
perTileCredits) {
|
||||
this->_credits.emplace_back(CreditAndCoverageAreas{
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
creditStringAndCoverageAreas.credit,
|
||||
pCreator->getOptions().showCreditsOnScreen),
|
||||
creditStringAndCoverageAreas.coverageAreas});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~BingMapsTileProvider() = default;
|
||||
|
||||
|
|
@ -280,19 +301,11 @@ namespace {
|
|||
* \endcode
|
||||
*
|
||||
* @param pResource The JSON value for the resource
|
||||
* @param pCreditSystem The `CreditSystem` that will create one credit for
|
||||
* each attribution
|
||||
* @return The `CreditAndCoverageAreas` objects that have been parsed, or an
|
||||
* empty vector if pCreditSystem is nullptr.
|
||||
* @return The `CreditStringAndCoverageAreas` objects that have been parsed.
|
||||
*/
|
||||
std::vector<CreditAndCoverageAreas> collectCredits(
|
||||
const rapidjson::Value* pResource,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
bool showCreditsOnScreen) {
|
||||
std::vector<CreditAndCoverageAreas> credits;
|
||||
if (!pCreditSystem) {
|
||||
return credits;
|
||||
}
|
||||
std::vector<CreditStringAndCoverageAreas>
|
||||
collectCredits(const rapidjson::Value* pResource) {
|
||||
std::vector<CreditStringAndCoverageAreas> credits;
|
||||
|
||||
const auto attributionsIt = pResource->FindMember("imageryProviders");
|
||||
if (attributionsIt != pResource->MemberEnd() &&
|
||||
|
|
@ -339,11 +352,9 @@ std::vector<CreditAndCoverageAreas> collectCredits(
|
|||
const auto creditString = attribution.FindMember("attribution");
|
||||
if (creditString != attribution.MemberEnd() &&
|
||||
creditString->value.IsString()) {
|
||||
credits.push_back(
|
||||
{pCreditSystem->createCredit(
|
||||
creditString->value.GetString(),
|
||||
showCreditsOnScreen),
|
||||
coverageAreas});
|
||||
credits.emplace_back(CreditStringAndCoverageAreas{
|
||||
creditString->value.GetString(),
|
||||
coverageAreas});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,13 +365,7 @@ std::vector<CreditAndCoverageAreas> collectCredits(
|
|||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
BingMapsRasterOverlay::createTileProvider(
|
||||
const AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
Uri metadataUri(
|
||||
this->_url,
|
||||
"REST/v1/Imagery/Metadata/" + this->_mapStyle,
|
||||
|
|
@ -377,20 +382,10 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
|
||||
std::string metadataUrl = std::string(metadataUri.toString());
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
const CesiumGeospatial::Ellipsoid& ellipsoid = this->getOptions().ellipsoid;
|
||||
IntrusivePointer<const BingMapsRasterOverlay> thiz = this;
|
||||
|
||||
auto handleResponse =
|
||||
[pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
ellipsoid,
|
||||
baseUrl = this->_url,
|
||||
culture = this->_culture](
|
||||
[thiz, parameters](
|
||||
const std::shared_ptr<IAssetRequest>& pRequest,
|
||||
const std::span<const std::byte>& data) -> CreateTileProviderResult {
|
||||
rapidjson::Document response;
|
||||
|
|
@ -448,39 +443,31 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
"Bing Maps tile imageUrl is missing or empty."});
|
||||
}
|
||||
|
||||
bool showCredits = pOwner->getOptions().showCreditsOnScreen;
|
||||
std::vector<CreditAndCoverageAreas> credits =
|
||||
collectCredits(pResource, pCreditSystem, showCredits);
|
||||
Credit bingCredit =
|
||||
pCreditSystem->createCredit(BING_LOGO_HTML, showCredits);
|
||||
std::vector<CreditStringAndCoverageAreas> credits =
|
||||
collectCredits(pResource);
|
||||
|
||||
return new BingMapsTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
bingCredit,
|
||||
thiz,
|
||||
parameters,
|
||||
credits,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
baseUrl,
|
||||
thiz->_url,
|
||||
urlTemplate,
|
||||
subdomains,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
maximumLevel,
|
||||
culture,
|
||||
ellipsoid);
|
||||
thiz->_culture);
|
||||
};
|
||||
|
||||
auto cacheResultIt = sessionCache.find(metadataUrl);
|
||||
if (cacheResultIt != sessionCache.end()) {
|
||||
return asyncSystem.createResolvedFuture(
|
||||
return parameters.externals.asyncSystem.createResolvedFuture(
|
||||
handleResponse(nullptr, std::span<std::byte>(cacheResultIt->second)));
|
||||
}
|
||||
|
||||
return pAssetAccessor->get(asyncSystem, metadataUrl)
|
||||
return parameters.externals.pAssetAccessor
|
||||
->get(parameters.externals.asyncSystem, metadataUrl)
|
||||
.thenInMainThread(
|
||||
[metadataUrl,
|
||||
handleResponse](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
|
|
@ -509,55 +496,4 @@ BingMapsRasterOverlay::createTileProvider(
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> BingMapsRasterOverlay::refreshTileProviderWithNewKey(
|
||||
const IntrusivePointer<RasterOverlayTileProvider>& pProvider,
|
||||
const std::string& newKey) {
|
||||
this->_key = newKey;
|
||||
|
||||
return this
|
||||
->createTileProvider(
|
||||
pProvider->getAsyncSystem(),
|
||||
pProvider->getAssetAccessor(),
|
||||
pProvider->getCreditSystem(),
|
||||
pProvider->getPrepareRendererResources(),
|
||||
pProvider->getLogger(),
|
||||
&pProvider->getOwner())
|
||||
.thenInMainThread([pProvider](CreateTileProviderResult&& result) {
|
||||
if (!result) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Bing Maps raster overlay with a new key: {}.",
|
||||
result.error().message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use static_cast instead of dynamic_cast here to avoid the need for
|
||||
// RTTI, and because we are certain of the type.
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
BingMapsTileProvider* pOldBing =
|
||||
static_cast<BingMapsTileProvider*>(pProvider.get());
|
||||
BingMapsTileProvider* pNewBing =
|
||||
static_cast<BingMapsTileProvider*>(result->get());
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
if (pOldBing->getCoverageRectangle().getLowerLeft() !=
|
||||
pNewBing->getCoverageRectangle().getLowerLeft() ||
|
||||
pOldBing->getCoverageRectangle().getUpperRight() !=
|
||||
pNewBing->getCoverageRectangle().getUpperRight() ||
|
||||
pOldBing->getHeight() != pNewBing->getHeight() ||
|
||||
pOldBing->getWidth() != pNewBing->getWidth() ||
|
||||
pOldBing->getMinimumLevel() != pNewBing->getMinimumLevel() ||
|
||||
pOldBing->getMaximumLevel() != pNewBing->getMaximumLevel() ||
|
||||
pOldBing->getProjection() != pNewBing->getProjection()) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Bing Maps raster overlay with a new key "
|
||||
"because some metadata properties changed unexpectedly upon "
|
||||
"refresh.");
|
||||
return;
|
||||
}
|
||||
|
||||
pOldBing->update(*pNewBing);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -1,23 +1,18 @@
|
|||
#include <CesiumAsync/AsyncSystem.h>
|
||||
#include <CesiumAsync/Future.h>
|
||||
#include <CesiumAsync/IAssetAccessor.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumGeospatial/GeographicProjection.h>
|
||||
#include <CesiumGltf/ImageAsset.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/DebugColorizeTilesRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/SpanHelper.h>
|
||||
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
|
@ -32,24 +27,14 @@ namespace {
|
|||
class DebugTileProvider : public RasterOverlayTileProvider {
|
||||
public:
|
||||
DebugTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const Ellipsoid& ellipsoid)
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
nullptr,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
GeographicProjection(ellipsoid),
|
||||
GeographicProjection::computeMaximumProjectedRectangle(ellipsoid)) {
|
||||
}
|
||||
pCreator,
|
||||
parameters,
|
||||
GeographicProjection(pCreator->getOptions().ellipsoid),
|
||||
GeographicProjection::computeMaximumProjectedRectangle(
|
||||
pCreator->getOptions().ellipsoid)) {}
|
||||
|
||||
virtual CesiumAsync::Future<LoadedRasterOverlayImage>
|
||||
loadTileImage(const RasterOverlayTile& overlayTile) override {
|
||||
|
|
@ -91,21 +76,9 @@ DebugColorizeTilesRasterOverlay::DebugColorizeTilesRasterOverlay(
|
|||
|
||||
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult>
|
||||
DebugColorizeTilesRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& /* pCreditSystem */,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
IntrusivePointer<RasterOverlayTileProvider>(new DebugTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this->getOptions().ellipsoid)));
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
IntrusivePointer<RasterOverlayTileProvider>(
|
||||
new DebugTileProvider(this, parameters)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,21 +5,14 @@
|
|||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
|
||||
EmptyRasterOverlayTileProvider::EmptyRasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem) noexcept
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) noexcept
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::nullopt,
|
||||
nullptr,
|
||||
nullptr,
|
||||
pCreator,
|
||||
parameters,
|
||||
CesiumGeospatial::GeographicProjection(),
|
||||
CesiumGeometry::Rectangle()) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ class EmptyRasterOverlayTileProvider
|
|||
public:
|
||||
EmptyRasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<
|
||||
const CesiumRasterOverlays::RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem) noexcept;
|
||||
const CesiumRasterOverlays::RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) noexcept;
|
||||
|
||||
protected:
|
||||
virtual CesiumAsync::Future<CesiumRasterOverlays::LoadedRasterOverlayImage>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
#include "CesiumGeometry/Rectangle.h"
|
||||
|
||||
#include <CesiumAsync/AsyncSystem.h>
|
||||
#include <CesiumAsync/Future.h>
|
||||
#include <CesiumAsync/IAssetAccessor.h>
|
||||
#include <CesiumGeometry/QuadtreeTileID.h>
|
||||
#include <CesiumGeometry/QuadtreeTilingScheme.h>
|
||||
#include <CesiumGeometry/Rectangle.h>
|
||||
#include <CesiumGeospatial/BoundingRegionBuilder.h>
|
||||
#include <CesiumGeospatial/Cartographic.h>
|
||||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
|
|
@ -12,6 +11,7 @@
|
|||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGltf/ImageAsset.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/GeoJsonDocumentRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
|
@ -19,7 +19,6 @@
|
|||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/Assert.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumVectorData/GeoJsonDocument.h>
|
||||
#include <CesiumVectorData/GeoJsonObject.h>
|
||||
|
|
@ -30,7 +29,6 @@
|
|||
#include <glm/common.hpp>
|
||||
#include <glm/ext/vector_int2.hpp>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
|
@ -514,32 +512,22 @@ private:
|
|||
|
||||
public:
|
||||
GeoJsonDocumentRasterOverlayTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const GeoJsonDocumentRasterOverlayOptions& options,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const GeoJsonDocumentRasterOverlayOptions& geoJsonOptions,
|
||||
std::shared_ptr<CesiumVectorData::GeoJsonDocument>&& pDocument)
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
GeographicProjection(options.ellipsoid),
|
||||
pCreator,
|
||||
parameters,
|
||||
GeographicProjection(geoJsonOptions.ellipsoid),
|
||||
projectRectangleSimple(
|
||||
GeographicProjection(options.ellipsoid),
|
||||
GeographicProjection(geoJsonOptions.ellipsoid),
|
||||
GlobeRectangle::MAXIMUM)),
|
||||
_pDocument(std::move(pDocument)),
|
||||
_defaultStyle(options.defaultStyle),
|
||||
_defaultStyle(geoJsonOptions.defaultStyle),
|
||||
_tree(),
|
||||
_ellipsoid(options.ellipsoid),
|
||||
_mipLevels(options.mipLevels) {
|
||||
_ellipsoid(geoJsonOptions.ellipsoid),
|
||||
_mipLevels(geoJsonOptions.mipLevels) {
|
||||
CESIUM_ASSERT(this->_pDocument);
|
||||
this->_tree = buildQuadtree(this->_pDocument, this->_defaultStyle);
|
||||
}
|
||||
|
|
@ -643,27 +631,14 @@ GeoJsonDocumentRasterOverlay::~GeoJsonDocumentRasterOverlay() = default;
|
|||
|
||||
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult>
|
||||
GeoJsonDocumentRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
IntrusivePointer<const GeoJsonDocumentRasterOverlay> thiz = this;
|
||||
|
||||
return std::move(
|
||||
const_cast<GeoJsonDocumentRasterOverlay*>(this)->_documentFuture)
|
||||
.thenInMainThread(
|
||||
[pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
options =
|
||||
this->_options](std::shared_ptr<GeoJsonDocument>&& pDocument)
|
||||
[thiz, parameters](std::shared_ptr<GeoJsonDocument>&& pDocument)
|
||||
-> CreateTileProviderResult {
|
||||
if (!pDocument) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
|
|
@ -674,13 +649,9 @@ GeoJsonDocumentRasterOverlay::createTileProvider(
|
|||
|
||||
return IntrusivePointer<RasterOverlayTileProvider>(
|
||||
new GeoJsonDocumentRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
options,
|
||||
thiz,
|
||||
parameters,
|
||||
thiz->_options,
|
||||
std::move(pDocument)));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,13 @@
|
|||
#include <CesiumJsonReader/JsonReader.h>
|
||||
#include <CesiumJsonWriter/JsonObjectWriter.h>
|
||||
#include <CesiumJsonWriter/PrettyJsonWriter.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/GoogleMapTilesRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/Assert.h>
|
||||
#include <CesiumUtility/CreditReferencer.h>
|
||||
#include <CesiumUtility/ErrorList.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/JsonHelpers.h>
|
||||
|
|
@ -140,14 +139,8 @@ class GoogleMapTilesRasterOverlayTileProvider
|
|||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
GoogleMapTilesRasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const std::string& apiBaseUrl,
|
||||
const std::string& session,
|
||||
const std::string& key,
|
||||
|
|
@ -161,9 +154,6 @@ public:
|
|||
|
||||
CesiumAsync::Future<void> loadCredits();
|
||||
|
||||
virtual void addCredits(
|
||||
CesiumUtility::CreditReferencer& creditReferencer) noexcept override;
|
||||
|
||||
protected:
|
||||
virtual CesiumAsync::Future<LoadedRasterOverlayImage> loadQuadtreeTileImage(
|
||||
const CesiumGeometry::QuadtreeTileID& tileID) const override;
|
||||
|
|
@ -175,21 +165,11 @@ private:
|
|||
std::string _apiBaseUrl;
|
||||
std::string _session;
|
||||
std::string _key;
|
||||
std::optional<Credit> _googleCredit;
|
||||
std::optional<Credit> _credits;
|
||||
|
||||
mutable QuadtreeRectangleAvailability _availableTiles;
|
||||
mutable QuadtreeRectangleAvailability _availableAvailability;
|
||||
};
|
||||
|
||||
void ensureTrailingSlash(std::string& url) {
|
||||
Uri uri(url);
|
||||
std::string_view path = uri.getPath();
|
||||
if (path.empty() || path.back() != '/') {
|
||||
uri.setPath(std::string(path) + '/');
|
||||
url = uri.toString();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace CesiumRasterOverlays {
|
||||
|
|
@ -201,7 +181,9 @@ GoogleMapTilesRasterOverlay::GoogleMapTilesRasterOverlay(
|
|||
: RasterOverlay(name, overlayOptions),
|
||||
_newSessionParameters(newSessionParameters),
|
||||
_existingSession(std::nullopt) {
|
||||
ensureTrailingSlash(this->_newSessionParameters->apiBaseUrl);
|
||||
Uri baseUrl(this->_newSessionParameters->apiBaseUrl);
|
||||
baseUrl.ensureTrailingSlash();
|
||||
this->_newSessionParameters->apiBaseUrl = baseUrl.toString();
|
||||
}
|
||||
|
||||
GoogleMapTilesRasterOverlay::GoogleMapTilesRasterOverlay(
|
||||
|
|
@ -211,40 +193,23 @@ GoogleMapTilesRasterOverlay::GoogleMapTilesRasterOverlay(
|
|||
: RasterOverlay(name, overlayOptions),
|
||||
_newSessionParameters(std::nullopt),
|
||||
_existingSession(existingSession) {
|
||||
ensureTrailingSlash(this->_existingSession->apiBaseUrl);
|
||||
Uri baseUrl(this->_existingSession->apiBaseUrl);
|
||||
baseUrl.ensureTrailingSlash();
|
||||
this->_existingSession->apiBaseUrl = baseUrl.toString();
|
||||
}
|
||||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
GoogleMapTilesRasterOverlay::createTileProvider(
|
||||
const AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
if (this->_newSessionParameters) {
|
||||
return this->createNewSession(
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pOwner);
|
||||
return this->createNewSession(parameters);
|
||||
} else if (this->_existingSession) {
|
||||
const GoogleMapTilesExistingSession& session = *this->_existingSession;
|
||||
|
||||
IntrusivePointer pTileProvider =
|
||||
new GoogleMapTilesRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this,
|
||||
parameters,
|
||||
session.apiBaseUrl,
|
||||
session.session,
|
||||
session.key,
|
||||
|
|
@ -264,25 +229,20 @@ GoogleMapTilesRasterOverlay::createTileProvider(
|
|||
return CreateTileProviderResult(pTileProvider);
|
||||
});
|
||||
} else {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = nullptr,
|
||||
.message =
|
||||
"GoogleMapTilesRasterOverlay is not configured with either "
|
||||
"new session parameters or an existing session."}));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = nullptr,
|
||||
.message =
|
||||
"GoogleMapTilesRasterOverlay is not configured with either "
|
||||
"new session parameters or an existing session."}));
|
||||
}
|
||||
}
|
||||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
GoogleMapTilesRasterOverlay::createNewSession(
|
||||
const AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
CESIUM_ASSERT(this->_newSessionParameters);
|
||||
|
||||
Uri createSessionUri(
|
||||
|
|
@ -334,36 +294,34 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
writeJsonValue(requestPayload, writer);
|
||||
std::vector<std::byte> requestPayloadBytes = writer.toBytes();
|
||||
|
||||
return pAssetAccessor
|
||||
IntrusivePointer<const GoogleMapTilesRasterOverlay> thiz = this;
|
||||
|
||||
return parameters.externals.pAssetAccessor
|
||||
->request(
|
||||
asyncSystem,
|
||||
parameters.externals.asyncSystem,
|
||||
"POST",
|
||||
std::string(createSessionUri.toString()),
|
||||
{{"Content-Type", "application/json"}},
|
||||
requestPayloadBytes)
|
||||
.thenInMainThread(
|
||||
[this,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pOwner](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
[thiz, parameters](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
-> Future<CreateTileProviderResult> {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
if (!pResponse) {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"No response received from Google Map Tiles API "
|
||||
"createSession service."}));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"No response received from Google Map Tiles API "
|
||||
"createSession service."}));
|
||||
}
|
||||
|
||||
if (pResponse->statusCode() < 200 ||
|
||||
pResponse->statusCode() >= 300) {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
return parameters.externals.asyncSystem.createResolvedFuture<
|
||||
CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
|
|
@ -382,7 +340,8 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
errorList.errors = std::move(response.errors);
|
||||
errorList.warnings = std::move(response.warnings);
|
||||
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
return parameters.externals.asyncSystem.createResolvedFuture<
|
||||
CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
|
|
@ -392,13 +351,14 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
}
|
||||
|
||||
if (!response.value->isObject()) {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service was not a JSON object."}));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service was not a JSON object."}));
|
||||
}
|
||||
|
||||
const JsonValue::Object& responseObject =
|
||||
|
|
@ -406,42 +366,45 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
|
||||
auto it = responseObject.find("session");
|
||||
if (it == responseObject.end() || !it->second.isString()) {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service did not contain a valid "
|
||||
"'session' property."}));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service did not contain a valid "
|
||||
"'session' property."}));
|
||||
}
|
||||
|
||||
std::string session = it->second.getString();
|
||||
|
||||
it = responseObject.find("tileWidth");
|
||||
if (it == responseObject.end() || !it->second.isNumber()) {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service did not contain a valid "
|
||||
"'tileWidth' property."}));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service did not contain a valid "
|
||||
"'tileWidth' property."}));
|
||||
}
|
||||
|
||||
int32_t tileWidth = it->second.getSafeNumberOrDefault<int32_t>(256);
|
||||
|
||||
it = responseObject.find("tileHeight");
|
||||
if (it == responseObject.end() || !it->second.isNumber()) {
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service did not contain a valid "
|
||||
"'tileHeight' property."}));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
.type = RasterOverlayLoadType::TileProvider,
|
||||
.pRequest = pRequest,
|
||||
.message =
|
||||
"Response from Google Map Tiles API "
|
||||
"createSession service did not contain a valid "
|
||||
"'tileHeight' property."}));
|
||||
}
|
||||
|
||||
int32_t tileHeight =
|
||||
|
|
@ -449,16 +412,11 @@ GoogleMapTilesRasterOverlay::createNewSession(
|
|||
|
||||
IntrusivePointer pTileProvider =
|
||||
new GoogleMapTilesRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this->_newSessionParameters->apiBaseUrl,
|
||||
thiz,
|
||||
parameters,
|
||||
thiz->_newSessionParameters->apiBaseUrl,
|
||||
session,
|
||||
this->_newSessionParameters->key,
|
||||
thiz->_newSessionParameters->key,
|
||||
maximumZoomLevel,
|
||||
static_cast<uint32_t>(tileWidth),
|
||||
static_cast<uint32_t>(tileHeight),
|
||||
|
|
@ -494,14 +452,8 @@ QuadtreeTilingScheme createTilingScheme(
|
|||
|
||||
GoogleMapTilesRasterOverlayTileProvider::
|
||||
GoogleMapTilesRasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<CesiumUtility::Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const std::string& apiBaseUrl,
|
||||
const std::string& session,
|
||||
const std::string& key,
|
||||
|
|
@ -510,16 +462,11 @@ GoogleMapTilesRasterOverlayTileProvider::
|
|||
uint32_t imageHeight,
|
||||
bool showLogo)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
WebMercatorProjection(pOwner->getOptions().ellipsoid),
|
||||
createTilingScheme(pOwner),
|
||||
createRectangle(pOwner),
|
||||
pCreator,
|
||||
parameters,
|
||||
WebMercatorProjection(pCreator->getOptions().ellipsoid),
|
||||
createTilingScheme(pCreator),
|
||||
createRectangle(pCreator),
|
||||
0,
|
||||
maximumLevel,
|
||||
imageWidth,
|
||||
|
|
@ -527,26 +474,14 @@ GoogleMapTilesRasterOverlayTileProvider::
|
|||
_apiBaseUrl(apiBaseUrl),
|
||||
_session(session),
|
||||
_key(key),
|
||||
_googleCredit(),
|
||||
_credits(),
|
||||
_availableTiles(createTilingScheme(pOwner), maximumLevel),
|
||||
_availableAvailability(createTilingScheme(pOwner), maximumLevel) {
|
||||
if (pCreditSystem && showLogo) {
|
||||
this->_googleCredit =
|
||||
pCreditSystem->createCredit(GOOGLE_MAPS_LOGO_HTML, true);
|
||||
}
|
||||
}
|
||||
|
||||
void GoogleMapTilesRasterOverlayTileProvider::addCredits(
|
||||
CesiumUtility::CreditReferencer& creditReferencer) noexcept {
|
||||
QuadtreeRasterOverlayTileProvider::addCredits(creditReferencer);
|
||||
|
||||
if (this->_googleCredit) {
|
||||
creditReferencer.addCreditReference(*this->_googleCredit);
|
||||
}
|
||||
|
||||
if (this->_credits) {
|
||||
creditReferencer.addCreditReference(*this->_credits);
|
||||
_availableTiles(createTilingScheme(pCreator), maximumLevel),
|
||||
_availableAvailability(createTilingScheme(pCreator), maximumLevel) {
|
||||
if (parameters.externals.pCreditSystem && showLogo) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
GOOGLE_MAPS_LOGO_HTML,
|
||||
true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -711,7 +646,6 @@ CesiumAsync::Future<rapidjson::Document> fetchViewportData(
|
|||
pRequest->url(),
|
||||
document.GetParseError(),
|
||||
document.GetErrorOffset());
|
||||
return document;
|
||||
}
|
||||
|
||||
return document;
|
||||
|
|
@ -889,7 +823,7 @@ Future<void> GoogleMapTilesRasterOverlayTileProvider::loadCredits() {
|
|||
uint32_t(i),
|
||||
Rectangle(-180.0, -90.0, 180.0, 90.0))
|
||||
.thenInMainThread([](rapidjson::Document&& document) {
|
||||
if (document.HasParseError()) {
|
||||
if (document.HasParseError() || !document.IsObject()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
|
@ -978,7 +912,10 @@ Future<void> GoogleMapTilesRasterOverlayTileProvider::loadCredits() {
|
|||
}
|
||||
|
||||
// Create a single credit from this giant string.
|
||||
thiz->_credits = thiz->getCreditSystem()->createCredit(joined, false);
|
||||
thiz->getCredits().emplace_back(thiz->getCreditSystem()->createCredit(
|
||||
thiz->getCreditSource(),
|
||||
joined,
|
||||
thiz->getOwner().getOptions().showCreditsOnScreen));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
#include <CesiumAsync/IAssetResponse.h>
|
||||
#include <CesiumAsync/NetworkAssetDescriptor.h>
|
||||
#include <CesiumAsync/SharedAssetDepot.h>
|
||||
#include <CesiumRasterOverlays/AzureMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/BingMapsRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/GoogleMapTilesRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/IonRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
|
|
@ -23,7 +25,6 @@
|
|||
#include <fmt/format.h>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <chrono>
|
||||
|
|
@ -63,8 +64,8 @@ public:
|
|||
expected<AggregatedTileProviderSuccess, RasterOverlayLoadFailureDetails>;
|
||||
|
||||
struct CreateTileProvider {
|
||||
IntrusivePointer<const RasterOverlay> pOwner;
|
||||
RasterOverlayExternals externals;
|
||||
IntrusivePointer<const IonRasterOverlay> pCreator;
|
||||
CreateRasterOverlayTileProviderParameters parameters;
|
||||
|
||||
SharedFuture<AggregatedTileProviderResult>
|
||||
operator()(const IntrusivePointer<ExternalAssetEndpoint>& pEndpoint);
|
||||
|
|
@ -74,12 +75,14 @@ public:
|
|||
DerivedValue<IntrusivePointer<ExternalAssetEndpoint>, CreateTileProvider>;
|
||||
|
||||
TileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const IntrusivePointer<RasterOverlayTileProvider>& pInitialProvider,
|
||||
const NetworkAssetDescriptor& descriptor,
|
||||
TileProviderFactoryType&& tileProviderFactory)
|
||||
: RasterOverlayTileProvider(
|
||||
&pInitialProvider->getOwner(),
|
||||
pInitialProvider->getExternals(),
|
||||
pCreator,
|
||||
parameters,
|
||||
pInitialProvider->getProjection(),
|
||||
pInitialProvider->getCoverageRectangle()),
|
||||
_descriptor(descriptor),
|
||||
|
|
@ -87,20 +90,26 @@ public:
|
|||
_credits() {}
|
||||
|
||||
static CesiumAsync::Future<RasterOverlay::CreateTileProviderResult> create(
|
||||
const RasterOverlayExternals& externals,
|
||||
const NetworkAssetDescriptor& descriptor,
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner) {
|
||||
const IntrusivePointer<const IonRasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const NetworkAssetDescriptor& descriptor) {
|
||||
auto pFactory = std::make_unique<TileProvider::TileProviderFactoryType>(
|
||||
TileProvider::TileProviderFactoryType(TileProvider::CreateTileProvider{
|
||||
.pOwner = pOwner,
|
||||
.externals = externals}));
|
||||
return TileProvider::getTileProvider(externals, descriptor, *pFactory)
|
||||
.pCreator = pCreator,
|
||||
.parameters = parameters}));
|
||||
|
||||
return TileProvider::getTileProvider(
|
||||
parameters.externals,
|
||||
descriptor,
|
||||
*pFactory)
|
||||
.thenInMainThread(
|
||||
[descriptor, pFactory = std::move(pFactory)](
|
||||
[descriptor, pFactory = std::move(pFactory), pCreator, parameters](
|
||||
AggregatedTileProviderResult&& result) mutable
|
||||
-> CreateTileProviderResult {
|
||||
if (result) {
|
||||
IntrusivePointer p = new TileProvider(
|
||||
pCreator,
|
||||
parameters,
|
||||
result.value().pAggregated,
|
||||
descriptor,
|
||||
std::move(*pFactory));
|
||||
|
|
@ -278,15 +287,7 @@ void IonRasterOverlay::setAssetOptions(
|
|||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
IonRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
NetworkAssetDescriptor descriptor;
|
||||
descriptor.url = this->_overlayUrl;
|
||||
|
||||
|
|
@ -304,15 +305,87 @@ IonRasterOverlay::createTileProvider(
|
|||
descriptor.url = uri.toString();
|
||||
}
|
||||
|
||||
RasterOverlayExternals externals{
|
||||
.pAssetAccessor = pAssetAccessor,
|
||||
.pPrepareRendererResources = pPrepareRendererResources,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pCreditSystem = pCreditSystem,
|
||||
.pLogger = pLogger,
|
||||
};
|
||||
// The aggregated tile provider should be owned by this overlay and use a
|
||||
// common credit source. But the conditions account for the possibility that
|
||||
// the IonRasterOverlay itself is aggregated by some other overlay.
|
||||
CreateRasterOverlayTileProviderParameters parametersCopy = parameters;
|
||||
if (parametersCopy.pOwner == nullptr) {
|
||||
parametersCopy.pOwner = this;
|
||||
}
|
||||
if (parametersCopy.pCreditSource == nullptr) {
|
||||
parametersCopy.pCreditSource =
|
||||
std::make_shared<CreditSource>(parameters.externals.pCreditSystem);
|
||||
}
|
||||
|
||||
return TileProvider::create(externals, descriptor, pOwner);
|
||||
return TileProvider::create(this, parametersCopy, descriptor);
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseAzure2DOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
const auto optionsIt = ionResponse.FindMember("options");
|
||||
if (optionsIt == ionResponse.MemberEnd() || !optionsIt->value.IsObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ionOptions = optionsIt->value;
|
||||
ExternalAssetEndpoint::Azure2D& azure2D =
|
||||
this->options.emplace<ExternalAssetEndpoint::Azure2D>();
|
||||
azure2D.url = JsonHelpers::getStringOrDefault(ionOptions, "url", "");
|
||||
azure2D.tilesetId =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "tilesetId", "");
|
||||
azure2D.key =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "subscription-key", "");
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseGoogle2DOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
const auto optionsIt = ionResponse.FindMember("options");
|
||||
if (optionsIt == ionResponse.MemberEnd() || !optionsIt->value.IsObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ionOptions = optionsIt->value;
|
||||
ExternalAssetEndpoint::Google2D& google2D =
|
||||
this->options.emplace<ExternalAssetEndpoint::Google2D>();
|
||||
google2D.url =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "url", google2D.url);
|
||||
google2D.key = JsonHelpers::getStringOrDefault(ionOptions, "key", "");
|
||||
google2D.session = JsonHelpers::getStringOrDefault(ionOptions, "session", "");
|
||||
google2D.expiry = JsonHelpers::getStringOrDefault(ionOptions, "expiry", "");
|
||||
google2D.tileWidth =
|
||||
JsonHelpers::getUint32OrDefault(ionOptions, "tileWidth", 256);
|
||||
google2D.tileHeight =
|
||||
JsonHelpers::getUint32OrDefault(ionOptions, "tileHeight", 256);
|
||||
google2D.imageFormat = JsonHelpers::getStringOrDefault(
|
||||
ionOptions,
|
||||
"imageFormat",
|
||||
GoogleMapTilesImageFormat::jpeg);
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseBingOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
const auto optionsIt = ionResponse.FindMember("options");
|
||||
if (optionsIt == ionResponse.MemberEnd() || !optionsIt->value.IsObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ionOptions = optionsIt->value;
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
this->options.emplace<ExternalAssetEndpoint::Bing>();
|
||||
bing.url = JsonHelpers::getStringOrDefault(ionOptions, "url", "");
|
||||
bing.key = JsonHelpers::getStringOrDefault(ionOptions, "key", "");
|
||||
bing.mapStyle =
|
||||
JsonHelpers::getStringOrDefault(ionOptions, "mapStyle", "AERIAL");
|
||||
bing.culture = JsonHelpers::getStringOrDefault(ionOptions, "culture", "");
|
||||
}
|
||||
|
||||
void IonRasterOverlay::ExternalAssetEndpoint::parseTileMapServiceOptions(
|
||||
const rapidjson::Document& ionResponse) {
|
||||
ExternalAssetEndpoint::TileMapService& tileMapService =
|
||||
this->options.emplace<ExternalAssetEndpoint::TileMapService>();
|
||||
tileMapService.url = JsonHelpers::getStringOrDefault(ionResponse, "url", "");
|
||||
tileMapService.accessToken =
|
||||
JsonHelpers::getStringOrDefault(ionResponse, "accessToken", "");
|
||||
}
|
||||
|
||||
/* static */ CesiumUtility::IntrusivePointer<IonRasterOverlay::EndpointDepot>
|
||||
|
|
@ -393,36 +466,25 @@ IonRasterOverlay::getEndpointCache() {
|
|||
"externalType",
|
||||
"unknown");
|
||||
|
||||
if (endpoint.externalType == "BING") {
|
||||
const auto optionsIt = response.FindMember("options");
|
||||
if (optionsIt == response.MemberEnd() ||
|
||||
!optionsIt->value.IsObject()) {
|
||||
if (endpoint.externalType == "AZURE_MAPS") {
|
||||
endpoint.parseAzure2DOptions(response);
|
||||
|
||||
if (!std::holds_alternative<ExternalAssetEndpoint::Azure2D>(
|
||||
endpoint.options)) {
|
||||
endpoint.pRequestThatFailed = std::move(pRequest);
|
||||
return ResultPointer<ExternalAssetEndpoint>(
|
||||
new ExternalAssetEndpoint(std::move(endpoint)),
|
||||
ErrorList::error(fmt::format(
|
||||
"Cesium ion Bing Maps raster overlay metadata "
|
||||
"Cesium ion Azure Maps raster overlay metadata "
|
||||
"response does not contain 'options' or it is "
|
||||
"not an object.")));
|
||||
}
|
||||
|
||||
const auto& options = optionsIt->value;
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
endpoint.options.emplace<ExternalAssetEndpoint::Bing>();
|
||||
bing.url =
|
||||
JsonHelpers::getStringOrDefault(options, "url", "");
|
||||
bing.key =
|
||||
JsonHelpers::getStringOrDefault(options, "key", "");
|
||||
bing.mapStyle = JsonHelpers::getStringOrDefault(
|
||||
options,
|
||||
"mapStyle",
|
||||
"AERIAL");
|
||||
bing.culture =
|
||||
JsonHelpers::getStringOrDefault(options, "culture", "");
|
||||
} else if (endpoint.externalType == "GOOGLE_2D_MAPS") {
|
||||
const auto optionsIt = response.FindMember("options");
|
||||
if (optionsIt == response.MemberEnd() ||
|
||||
!optionsIt->value.IsObject()) {
|
||||
endpoint.parseGoogle2DOptions(response);
|
||||
|
||||
if (!std::holds_alternative<
|
||||
ExternalAssetEndpoint::Google2D>(
|
||||
endpoint.options)) {
|
||||
endpoint.pRequestThatFailed = std::move(pRequest);
|
||||
return ResultPointer<ExternalAssetEndpoint>(
|
||||
new ExternalAssetEndpoint(std::move(endpoint)),
|
||||
|
|
@ -431,45 +493,21 @@ IonRasterOverlay::getEndpointCache() {
|
|||
"metadata response does not contain 'options' or "
|
||||
"it is not an object.")));
|
||||
}
|
||||
} else if (endpoint.externalType == "BING") {
|
||||
endpoint.parseBingOptions(response);
|
||||
|
||||
const auto& options = optionsIt->value;
|
||||
ExternalAssetEndpoint::Google2D& google2D =
|
||||
endpoint.options
|
||||
.emplace<ExternalAssetEndpoint::Google2D>();
|
||||
google2D.url = JsonHelpers::getStringOrDefault(
|
||||
options,
|
||||
"url",
|
||||
google2D.url);
|
||||
google2D.key =
|
||||
JsonHelpers::getStringOrDefault(options, "key", "");
|
||||
google2D.session =
|
||||
JsonHelpers::getStringOrDefault(options, "session", "");
|
||||
google2D.expiry =
|
||||
JsonHelpers::getStringOrDefault(options, "expiry", "");
|
||||
google2D.tileWidth = JsonHelpers::getUint32OrDefault(
|
||||
options,
|
||||
"tileWidth",
|
||||
256);
|
||||
google2D.tileHeight = JsonHelpers::getUint32OrDefault(
|
||||
options,
|
||||
"tileHeight",
|
||||
256);
|
||||
google2D.imageFormat = JsonHelpers::getStringOrDefault(
|
||||
options,
|
||||
"imageFormat",
|
||||
GoogleMapTilesImageFormat::jpeg);
|
||||
|
||||
if (!std::holds_alternative<ExternalAssetEndpoint::Bing>(
|
||||
endpoint.options)) {
|
||||
endpoint.pRequestThatFailed = std::move(pRequest);
|
||||
return ResultPointer<ExternalAssetEndpoint>(
|
||||
new ExternalAssetEndpoint(std::move(endpoint)),
|
||||
ErrorList::error(fmt::format(
|
||||
"Cesium ion Bing Maps raster overlay metadata "
|
||||
"response does not contain 'options' or it is "
|
||||
"not an object.")));
|
||||
}
|
||||
} else {
|
||||
ExternalAssetEndpoint::TileMapService& tileMapService =
|
||||
endpoint.options
|
||||
.emplace<ExternalAssetEndpoint::TileMapService>();
|
||||
tileMapService.url =
|
||||
JsonHelpers::getStringOrDefault(response, "url", "");
|
||||
tileMapService.accessToken =
|
||||
JsonHelpers::getStringOrDefault(
|
||||
response,
|
||||
"accessToken",
|
||||
"");
|
||||
endpoint.parseTileMapServiceOptions(response);
|
||||
}
|
||||
|
||||
const auto attributionsIt =
|
||||
|
|
@ -539,7 +577,7 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
const IntrusivePointer<ExternalAssetEndpoint>& pEndpoint) {
|
||||
if (pEndpoint == nullptr ||
|
||||
std::holds_alternative<std::monostate>(pEndpoint->options)) {
|
||||
return this->externals.asyncSystem
|
||||
return this->parameters.externals.asyncSystem
|
||||
.createResolvedFuture<AggregatedTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::CesiumIon,
|
||||
|
|
@ -549,25 +587,27 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
}
|
||||
|
||||
IntrusivePointer<RasterOverlay> pOverlay = nullptr;
|
||||
if (pEndpoint->externalType == "BING") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Bing>(
|
||||
if (pEndpoint->externalType == "AZURE_MAPS") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Azure2D>(
|
||||
pEndpoint->options));
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
std::get<ExternalAssetEndpoint::Bing>(pEndpoint->options);
|
||||
pOverlay = new BingMapsRasterOverlay(
|
||||
this->pOwner->getName(),
|
||||
bing.url,
|
||||
bing.key,
|
||||
bing.mapStyle,
|
||||
bing.culture,
|
||||
this->pOwner->getOptions());
|
||||
ExternalAssetEndpoint::Azure2D& azure2D =
|
||||
std::get<ExternalAssetEndpoint::Azure2D>(pEndpoint->options);
|
||||
pOverlay = new AzureMapsRasterOverlay(
|
||||
this->pCreator->getName(),
|
||||
AzureMapsSessionParameters{
|
||||
.key = azure2D.key,
|
||||
.tilesetId = azure2D.tilesetId,
|
||||
.showLogo = false,
|
||||
.apiBaseUrl = azure2D.url,
|
||||
},
|
||||
this->pCreator->getOptions());
|
||||
} else if (pEndpoint->externalType == "GOOGLE_2D_MAPS") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Google2D>(
|
||||
pEndpoint->options));
|
||||
ExternalAssetEndpoint::Google2D& google2D =
|
||||
std::get<ExternalAssetEndpoint::Google2D>(pEndpoint->options);
|
||||
pOverlay = new GoogleMapTilesRasterOverlay(
|
||||
this->pOwner->getName(),
|
||||
this->pCreator->getName(),
|
||||
GoogleMapTilesExistingSession{
|
||||
.key = google2D.key,
|
||||
.session = google2D.session,
|
||||
|
|
@ -578,43 +618,49 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
.showLogo = false,
|
||||
.apiBaseUrl = google2D.url,
|
||||
},
|
||||
this->pOwner->getOptions());
|
||||
this->pCreator->getOptions());
|
||||
} else if (pEndpoint->externalType == "BING") {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::Bing>(
|
||||
pEndpoint->options));
|
||||
ExternalAssetEndpoint::Bing& bing =
|
||||
std::get<ExternalAssetEndpoint::Bing>(pEndpoint->options);
|
||||
pOverlay = new BingMapsRasterOverlay(
|
||||
this->pCreator->getName(),
|
||||
bing.url,
|
||||
bing.key,
|
||||
bing.mapStyle,
|
||||
bing.culture,
|
||||
this->pCreator->getOptions());
|
||||
} else {
|
||||
CESIUM_ASSERT(std::holds_alternative<ExternalAssetEndpoint::TileMapService>(
|
||||
pEndpoint->options));
|
||||
ExternalAssetEndpoint::TileMapService& tileMapService =
|
||||
std::get<ExternalAssetEndpoint::TileMapService>(pEndpoint->options);
|
||||
pOverlay = new TileMapServiceRasterOverlay(
|
||||
this->pOwner->getName(),
|
||||
this->pCreator->getName(),
|
||||
tileMapService.url,
|
||||
std::vector<CesiumAsync::IAssetAccessor::THeader>{std::make_pair(
|
||||
"Authorization",
|
||||
"Bearer " + tileMapService.accessToken)},
|
||||
TileMapServiceRasterOverlayOptions(),
|
||||
this->pOwner->getOptions());
|
||||
this->pCreator->getOptions());
|
||||
}
|
||||
|
||||
std::vector<Credit> credits;
|
||||
|
||||
if (this->externals.pCreditSystem) {
|
||||
if (this->parameters.externals.pCreditSystem) {
|
||||
credits.reserve(pEndpoint->attributions.size());
|
||||
for (const AssetEndpointAttribution& attribution :
|
||||
pEndpoint->attributions) {
|
||||
credits.emplace_back(this->externals.pCreditSystem->createCredit(
|
||||
attribution.html,
|
||||
!attribution.collapsible ||
|
||||
this->pOwner->getOptions().showCreditsOnScreen));
|
||||
credits.emplace_back(
|
||||
this->parameters.externals.pCreditSystem->createCredit(
|
||||
attribution.html,
|
||||
!attribution.collapsible ||
|
||||
this->pCreator->getOptions().showCreditsOnScreen));
|
||||
}
|
||||
}
|
||||
|
||||
return pOverlay
|
||||
->createTileProvider(
|
||||
this->externals.asyncSystem,
|
||||
this->externals.pAssetAccessor,
|
||||
this->externals.pCreditSystem,
|
||||
this->externals.pPrepareRendererResources,
|
||||
this->externals.pLogger,
|
||||
this->pOwner)
|
||||
return pOverlay->createTileProvider(parameters)
|
||||
.thenImmediately([credits = std::move(credits)](
|
||||
CreateTileProviderResult&& result) mutable {
|
||||
if (result) {
|
||||
|
|
@ -629,5 +675,4 @@ IonRasterOverlay::TileProvider::CreateTileProvider::operator()(
|
|||
})
|
||||
.share();
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <glm/common.hpp>
|
||||
#include <glm/exponential.hpp>
|
||||
#include <glm/ext/vector_double2.hpp>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
|
@ -52,14 +51,8 @@ constexpr double pixelTolerance = 0.01;
|
|||
namespace CesiumRasterOverlays {
|
||||
|
||||
QuadtreeRasterOverlayTileProvider::QuadtreeRasterOverlayTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
@ -68,13 +61,8 @@ QuadtreeRasterOverlayTileProvider::QuadtreeRasterOverlayTileProvider(
|
|||
uint32_t imageWidth,
|
||||
uint32_t imageHeight) noexcept
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
coverageRectangle),
|
||||
_minimumLevel(minimumLevel),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <CesiumGeospatial/Ellipsoid.h>
|
||||
#include <CesiumGeospatial/GeographicProjection.h>
|
||||
#include <CesiumRasterOverlays/ActivatedRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayExternals.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
|
|
@ -19,7 +20,6 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
|
@ -32,19 +32,12 @@ namespace {
|
|||
class PlaceholderTileProvider : public RasterOverlayTileProvider {
|
||||
public:
|
||||
PlaceholderTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Ellipsoid& ellipsoid) noexcept
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
std::nullopt,
|
||||
nullptr,
|
||||
spdlog::default_logger(),
|
||||
pCreator,
|
||||
parameters,
|
||||
CesiumGeospatial::GeographicProjection(ellipsoid),
|
||||
CesiumGeometry::Rectangle()) {}
|
||||
|
||||
|
|
@ -93,14 +86,13 @@ CesiumUtility::IntrusivePointer<ActivatedRasterOverlay> RasterOverlay::activate(
|
|||
IntrusivePointer<ActivatedRasterOverlay> pResult =
|
||||
new ActivatedRasterOverlay(externals, this, ellipsoid);
|
||||
|
||||
CreateRasterOverlayTileProviderParameters parameters{
|
||||
.externals = externals,
|
||||
.pOwner = nullptr,
|
||||
.pCreditSource = nullptr};
|
||||
|
||||
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult> future =
|
||||
this->createTileProvider(
|
||||
externals.asyncSystem,
|
||||
externals.pAssetAccessor,
|
||||
externals.pCreditSystem,
|
||||
externals.pPrepareRendererResources,
|
||||
externals.pLogger,
|
||||
this);
|
||||
this->createTileProvider(parameters);
|
||||
|
||||
// This continuation, by capturing pResult, keeps the instance from being
|
||||
// destroyed. But it does not keep the RasterOverlayCollection itself alive.
|
||||
|
|
@ -115,7 +107,7 @@ CesiumUtility::IntrusivePointer<ActivatedRasterOverlay> RasterOverlay::activate(
|
|||
"Error while creating tile provider: {0}",
|
||||
e.what())});
|
||||
})
|
||||
.thenInMainThread([pResult, externals](
|
||||
.thenInMainThread([pResult, parameters](
|
||||
RasterOverlay::CreateTileProviderResult&& result) {
|
||||
IntrusivePointer<RasterOverlayTileProvider> pProvider = nullptr;
|
||||
if (result) {
|
||||
|
|
@ -124,7 +116,9 @@ CesiumUtility::IntrusivePointer<ActivatedRasterOverlay> RasterOverlay::activate(
|
|||
// Report error creating the tile provider.
|
||||
const RasterOverlayLoadFailureDetails& failureDetails =
|
||||
result.error();
|
||||
SPDLOG_LOGGER_ERROR(externals.pLogger, failureDetails.message);
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
parameters.externals.pLogger,
|
||||
failureDetails.message);
|
||||
if (pResult->getOverlay().getOptions().loadErrorCallback) {
|
||||
pResult->getOverlay().getOptions().loadErrorCallback(
|
||||
failureDetails);
|
||||
|
|
@ -134,7 +128,7 @@ CesiumUtility::IntrusivePointer<ActivatedRasterOverlay> RasterOverlay::activate(
|
|||
// all.
|
||||
pProvider = new EmptyRasterOverlayTileProvider(
|
||||
&pResult->getOverlay(),
|
||||
externals.asyncSystem);
|
||||
parameters);
|
||||
}
|
||||
|
||||
pResult->setTileProvider(pProvider);
|
||||
|
|
@ -149,8 +143,9 @@ RasterOverlay::createPlaceholder(
|
|||
const CesiumGeospatial::Ellipsoid& ellipsoid) const {
|
||||
return new PlaceholderTileProvider(
|
||||
this,
|
||||
externals.asyncSystem,
|
||||
externals.pAssetAccessor,
|
||||
nullptr,
|
||||
CreateRasterOverlayTileProviderParameters{
|
||||
.externals = externals,
|
||||
.pOwner = nullptr,
|
||||
.pCreditSource = nullptr},
|
||||
ellipsoid);
|
||||
}
|
||||
|
|
@ -37,11 +37,14 @@ RasterOverlayTile::RasterOverlayTile(
|
|||
RasterOverlayTile::~RasterOverlayTile() {
|
||||
this->_pActivatedOverlay->removeTile(this);
|
||||
|
||||
RasterOverlayTileProvider& tileProvider =
|
||||
*this->_pActivatedOverlay->getTileProvider();
|
||||
RasterOverlayTileProvider* pTileProvider =
|
||||
this->_pActivatedOverlay->getTileProvider();
|
||||
|
||||
if (!pTileProvider)
|
||||
return;
|
||||
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources = tileProvider.getPrepareRendererResources();
|
||||
pPrepareRendererResources = pTileProvider->getPrepareRendererResources();
|
||||
|
||||
if (pPrepareRendererResources) {
|
||||
void* pLoadThreadResult =
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@
|
|||
#include <CesiumGeometry/Rectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGltfReader/ImageDecoder.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayExternals.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumUtility/Assert.h>
|
||||
#include <CesiumUtility/CreditReferencer.h>
|
||||
#include <CesiumUtility/ErrorList.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
|
|
@ -37,39 +39,24 @@ using namespace CesiumUtility;
|
|||
namespace CesiumRasterOverlays {
|
||||
|
||||
RasterOverlayTileProvider::RasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const RasterOverlayExternals& externals,
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle) noexcept
|
||||
: _pOwner(const_intrusive_cast<RasterOverlay>(pOwner)),
|
||||
_externals(externals),
|
||||
_credit(),
|
||||
: _pOwner(const_intrusive_cast<RasterOverlay>(
|
||||
parameters.pOwner ? parameters.pOwner : pCreator)),
|
||||
_externals(parameters.externals),
|
||||
_credits(),
|
||||
_projection(projection),
|
||||
_coverageRectangle(coverageRectangle),
|
||||
_destructionCompleteDetails() {}
|
||||
|
||||
RasterOverlayTileProvider::RasterOverlayTileProvider(
|
||||
const CesiumUtility::IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const Rectangle& coverageRectangle) noexcept
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
RasterOverlayExternals{
|
||||
.pAssetAccessor = pAssetAccessor,
|
||||
.pPrepareRendererResources = pPrepareRendererResources,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pCreditSystem = pCreditSystem,
|
||||
.pLogger = pLogger},
|
||||
projection,
|
||||
coverageRectangle) {
|
||||
this->_credit = credit;
|
||||
_destructionCompleteDetails(),
|
||||
_pCreditSource(
|
||||
parameters.pCreditSource ? parameters.pCreditSource
|
||||
: std::make_shared<CreditSource>(
|
||||
parameters.externals.pCreditSystem)) {
|
||||
CESIUM_ASSERT(
|
||||
this->_pCreditSource->getCreditSystem() ==
|
||||
parameters.externals.pCreditSystem.get());
|
||||
}
|
||||
|
||||
RasterOverlayTileProvider::~RasterOverlayTileProvider() noexcept {
|
||||
|
|
@ -139,15 +126,31 @@ RasterOverlayTileProvider::getCoverageRectangle() const noexcept {
|
|||
return this->_coverageRectangle;
|
||||
}
|
||||
|
||||
const std::optional<CesiumUtility::Credit>&
|
||||
RasterOverlayTileProvider::getCredit() const noexcept {
|
||||
return _credit;
|
||||
const CesiumUtility::CreditSource&
|
||||
RasterOverlayTileProvider::getCreditSource() const noexcept {
|
||||
return *this->_pCreditSource;
|
||||
}
|
||||
|
||||
std::vector<CesiumUtility::Credit>&
|
||||
RasterOverlayTileProvider::getCredits() noexcept {
|
||||
return this->_credits;
|
||||
}
|
||||
|
||||
const std::vector<CesiumUtility::Credit>&
|
||||
RasterOverlayTileProvider::getCredits() const noexcept {
|
||||
return this->_credits;
|
||||
}
|
||||
|
||||
void RasterOverlayTileProvider::addCredits(
|
||||
CreditReferencer& creditReferencer) noexcept {
|
||||
if (this->_credit) {
|
||||
creditReferencer.addCreditReference(*this->_credit);
|
||||
CESIUM_ASSERT(
|
||||
creditReferencer.getCreditSystem().get() ==
|
||||
this->_pCreditSource->getCreditSystem());
|
||||
for (const CesiumUtility::Credit& credit : this->_credits) {
|
||||
CESIUM_ASSERT(
|
||||
this->getCreditSystem()->getCreditSource(credit) ==
|
||||
this->_pCreditSource.get());
|
||||
creditReferencer.addCreditReference(credit);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ RasterOverlayUtilities::upsampleGltfForRasterOverlays(
|
|||
// We're assuming here that nothing references primitives by index, so we
|
||||
// can remove them without any drama.
|
||||
if (!keep) {
|
||||
mesh.primitives.erase(mesh.primitives.begin() + int64_t(i));
|
||||
mesh.primitives.erase(mesh.primitives.begin() + ptrdiff_t(i));
|
||||
--i;
|
||||
}
|
||||
containsPrimitives |= !mesh.primitives.empty();
|
||||
|
|
|
|||
|
|
@ -5,22 +5,20 @@
|
|||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGltf/ImageAsset.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/Library.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterizedPolygonsOverlay.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
|
||||
#include <glm/common.hpp>
|
||||
#include <glm/ext/vector_double2.hpp>
|
||||
#include <glm/geometric.hpp>
|
||||
#include <spdlog/fwd.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -177,23 +175,14 @@ private:
|
|||
|
||||
public:
|
||||
RasterizedPolygonsTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const std::vector<CartographicPolygon>& polygons,
|
||||
bool invertSelection)
|
||||
: RasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
nullptr,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
// computeCoverageRectangle(projection, polygons)),
|
||||
projectRectangleSimple(
|
||||
|
|
@ -252,27 +241,17 @@ RasterizedPolygonsOverlay::~RasterizedPolygonsOverlay() = default;
|
|||
|
||||
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult>
|
||||
RasterizedPolygonsOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& /*pCreditSystem*/,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
IntrusivePointer<RasterOverlayTileProvider>(
|
||||
new RasterizedPolygonsTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this->_projection,
|
||||
this->_polygons,
|
||||
this->_invertSelection)));
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(
|
||||
IntrusivePointer<RasterOverlayTileProvider>(
|
||||
new RasterizedPolygonsTileProvider(
|
||||
this,
|
||||
parameters,
|
||||
this->_projection,
|
||||
this->_polygons,
|
||||
this->_invertSelection)));
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -9,22 +9,19 @@
|
|||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/TileMapServiceRasterOverlay.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/ErrorList.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/Uri.h>
|
||||
|
||||
#include <glm/common.hpp>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
|
@ -88,14 +85,9 @@ class TileMapServiceTileProvider final
|
|||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
TileMapServiceTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
std::optional<std::string> credit,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
@ -108,13 +100,8 @@ public:
|
|||
uint32_t maximumLevel,
|
||||
const std::vector<TileMapServiceTileset>& tileSets)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
|
|
@ -125,7 +112,15 @@ public:
|
|||
_url(url),
|
||||
_headers(headers),
|
||||
_fileExtension(fileExtension),
|
||||
_tileSets(tileSets) {}
|
||||
_tileSets(tileSets) {
|
||||
if (parameters.externals.pCreditSystem && credit) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
*credit,
|
||||
pCreator->getOptions().showCreditsOnScreen));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~TileMapServiceTileProvider() = default;
|
||||
|
||||
|
|
@ -301,37 +296,19 @@ Future<GetXmlDocumentResult> getXmlDocument(
|
|||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
TileMapServiceRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
std::string xmlUrl = this->_url;
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
IntrusivePointer<const TileMapServiceRasterOverlay> thiz = this;
|
||||
|
||||
std::optional<Credit> credit = std::nullopt;
|
||||
if (pCreditSystem && this->_options.credit) {
|
||||
credit = pCreditSystem->createCredit(
|
||||
*this->_options.credit,
|
||||
pOwner->getOptions().showCreditsOnScreen);
|
||||
}
|
||||
|
||||
return getXmlDocument(asyncSystem, pAssetAccessor, xmlUrl, this->_headers)
|
||||
return getXmlDocument(
|
||||
parameters.externals.asyncSystem,
|
||||
parameters.externals.pAssetAccessor,
|
||||
xmlUrl,
|
||||
this->_headers)
|
||||
.thenInMainThread(
|
||||
[pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
options = this->_options,
|
||||
url = this->_url,
|
||||
headers = this->_headers](
|
||||
GetXmlDocumentResult&& xml) -> CreateTileProviderResult {
|
||||
[thiz,
|
||||
parameters](GetXmlDocumentResult&& xml) -> CreateTileProviderResult {
|
||||
if (!xml) {
|
||||
return nonstd::make_unexpected(std::move(xml).error());
|
||||
}
|
||||
|
|
@ -341,11 +318,11 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
|
||||
tinyxml2::XMLElement* pTileFormat =
|
||||
pRoot->FirstChildElement("TileFormat");
|
||||
std::string fileExtension = options.fileExtension.value_or(
|
||||
std::string fileExtension = thiz->_options.fileExtension.value_or(
|
||||
getAttributeString(pTileFormat, "extension").value_or("png"));
|
||||
uint32_t tileWidth = options.tileWidth.value_or(
|
||||
uint32_t tileWidth = thiz->_options.tileWidth.value_or(
|
||||
getAttributeUint32(pTileFormat, "width").value_or(256));
|
||||
uint32_t tileHeight = options.tileHeight.value_or(
|
||||
uint32_t tileHeight = thiz->_options.tileHeight.value_or(
|
||||
getAttributeUint32(pTileFormat, "height").value_or(256));
|
||||
|
||||
uint32_t minimumLevel = std::numeric_limits<uint32_t>::max();
|
||||
|
|
@ -377,7 +354,7 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
}
|
||||
|
||||
const CesiumGeospatial::Ellipsoid& ellipsoid =
|
||||
pOwner->getOptions().ellipsoid;
|
||||
thiz->getOptions().ellipsoid;
|
||||
|
||||
CesiumGeospatial::GlobeRectangle tilingSchemeRectangle =
|
||||
CesiumGeospatial::GeographicProjection::MAXIMUM_GLOBE_RECTANGLE;
|
||||
|
|
@ -386,8 +363,8 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
uint32_t rootTilesX = 1;
|
||||
bool isRectangleInDegrees = false;
|
||||
|
||||
if (options.projection) {
|
||||
projection = options.projection.value();
|
||||
if (thiz->_options.projection) {
|
||||
projection = thiz->_options.projection.value();
|
||||
} else {
|
||||
std::string projectionName =
|
||||
getAttributeString(pTilesets, "profile").value_or("mercator");
|
||||
|
|
@ -441,14 +418,14 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
|
||||
minimumLevel = glm::min(minimumLevel, maximumLevel);
|
||||
|
||||
minimumLevel = options.minimumLevel.value_or(minimumLevel);
|
||||
maximumLevel = options.maximumLevel.value_or(maximumLevel);
|
||||
minimumLevel = thiz->_options.minimumLevel.value_or(minimumLevel);
|
||||
maximumLevel = thiz->_options.maximumLevel.value_or(maximumLevel);
|
||||
|
||||
CesiumGeometry::Rectangle coverageRectangle =
|
||||
projectRectangleSimple(projection, tilingSchemeRectangle);
|
||||
|
||||
if (options.coverageRectangle) {
|
||||
coverageRectangle = options.coverageRectangle.value();
|
||||
if (thiz->_options.coverageRectangle) {
|
||||
coverageRectangle = thiz->_options.coverageRectangle.value();
|
||||
} else {
|
||||
tinyxml2::XMLElement* pBoundingBox =
|
||||
pRoot->FirstChildElement("BoundingBox");
|
||||
|
|
@ -486,31 +463,27 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
rootTilesX,
|
||||
1);
|
||||
|
||||
std::string updatedUrl = url;
|
||||
std::string updatedUrl = thiz->_url;
|
||||
|
||||
std::string urlPath = Uri::getPath(url);
|
||||
std::string urlPath = Uri::getPath(thiz->_url);
|
||||
if (!(urlPath.size() < 4)) {
|
||||
if (urlPath.substr(urlPath.size() - 4, 4) != ".xml") {
|
||||
if (urlPath[urlPath.size() - 1] != '/') {
|
||||
urlPath += "/";
|
||||
updatedUrl = Uri::setPath(url, urlPath);
|
||||
updatedUrl = Uri::setPath(thiz->_url, urlPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TileMapServiceTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
thiz,
|
||||
parameters,
|
||||
thiz->_options.credit,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
updatedUrl,
|
||||
headers,
|
||||
thiz->_headers,
|
||||
!fileExtension.empty() ? "." + fileExtension : fileExtension,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
|
|
@ -520,63 +493,4 @@ TileMapServiceRasterOverlay::createTileProvider(
|
|||
});
|
||||
}
|
||||
|
||||
Future<void>
|
||||
TileMapServiceRasterOverlay::refreshTileProviderWithNewUrlAndHeaders(
|
||||
const IntrusivePointer<RasterOverlayTileProvider>& pProvider,
|
||||
const std::optional<std::string>& newUrl,
|
||||
const std::optional<std::vector<CesiumAsync::IAssetAccessor::THeader>>&
|
||||
newHeaders) {
|
||||
if (newUrl) {
|
||||
this->_url = *newUrl;
|
||||
}
|
||||
if (newHeaders) {
|
||||
this->_headers = *newHeaders;
|
||||
}
|
||||
|
||||
return this
|
||||
->createTileProvider(
|
||||
pProvider->getAsyncSystem(),
|
||||
pProvider->getAssetAccessor(),
|
||||
pProvider->getCreditSystem(),
|
||||
pProvider->getPrepareRendererResources(),
|
||||
pProvider->getLogger(),
|
||||
&pProvider->getOwner())
|
||||
.thenInMainThread([pProvider](CreateTileProviderResult&& result) {
|
||||
if (!result) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Bing Maps raster overlay with a new key: {}.",
|
||||
result.error().message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use static_cast instead of dynamic_cast here to avoid the need for
|
||||
// RTTI, and because we are certain of the type.
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
TileMapServiceTileProvider* pOld =
|
||||
static_cast<TileMapServiceTileProvider*>(pProvider.get());
|
||||
TileMapServiceTileProvider* pNew =
|
||||
static_cast<TileMapServiceTileProvider*>(result->get());
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
if (pOld->getCoverageRectangle().getLowerLeft() !=
|
||||
pNew->getCoverageRectangle().getLowerLeft() ||
|
||||
pOld->getCoverageRectangle().getUpperRight() !=
|
||||
pNew->getCoverageRectangle().getUpperRight() ||
|
||||
pOld->getHeight() != pNew->getHeight() ||
|
||||
pOld->getWidth() != pNew->getWidth() ||
|
||||
pOld->getMinimumLevel() != pNew->getMinimumLevel() ||
|
||||
pOld->getMaximumLevel() != pNew->getMaximumLevel() ||
|
||||
pOld->getProjection() != pNew->getProjection()) {
|
||||
SPDLOG_LOGGER_WARN(
|
||||
pProvider->getLogger(),
|
||||
"Could not refresh Tile Map Service raster overlay with a new "
|
||||
"URL and request headers because some metadata properties "
|
||||
"changed unexpectedly upon refresh.");
|
||||
return;
|
||||
}
|
||||
|
||||
pOld->update(*pNew);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -8,20 +8,16 @@
|
|||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/UrlTemplateRasterOverlay.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/Math.h>
|
||||
#include <CesiumUtility/Uri.h>
|
||||
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
|
@ -39,14 +35,9 @@ class UrlTemplateRasterOverlayTileProvider final
|
|||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
UrlTemplateRasterOverlayTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
std::optional<std::string> credit,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
@ -57,13 +48,8 @@ public:
|
|||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
|
|
@ -72,7 +58,15 @@ public:
|
|||
width,
|
||||
height),
|
||||
_url(url),
|
||||
_headers(headers) {}
|
||||
_headers(headers) {
|
||||
if (parameters.externals.pCreditSystem && credit) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
*credit,
|
||||
pCreator->getOptions().showCreditsOnScreen));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~UrlTemplateRasterOverlayTileProvider() = default;
|
||||
|
||||
|
|
@ -137,24 +131,9 @@ private:
|
|||
|
||||
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult>
|
||||
UrlTemplateRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
std::optional<Credit> credit = std::nullopt;
|
||||
if (pCreditSystem && this->_options.credit) {
|
||||
credit = pCreditSystem->createCredit(
|
||||
*this->_options.credit,
|
||||
pOwner->getOptions().showCreditsOnScreen);
|
||||
}
|
||||
|
||||
CesiumGeospatial::Projection projection = _options.projection.value_or(
|
||||
CesiumGeospatial::WebMercatorProjection(pOwner->getOptions().ellipsoid));
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
CesiumGeospatial::Projection projection = this->_options.projection.value_or(
|
||||
CesiumGeospatial::WebMercatorProjection(this->getOptions().ellipsoid));
|
||||
CesiumGeospatial::GlobeRectangle tilingSchemeRectangle =
|
||||
CesiumGeospatial::WebMercatorProjection::MAXIMUM_GLOBE_RECTANGLE;
|
||||
|
||||
|
|
@ -165,34 +144,30 @@ UrlTemplateRasterOverlay::createTileProvider(
|
|||
rootTilesX = 2;
|
||||
}
|
||||
CesiumGeometry::Rectangle coverageRectangle =
|
||||
_options.coverageRectangle.value_or(
|
||||
this->_options.coverageRectangle.value_or(
|
||||
projectRectangleSimple(projection, tilingSchemeRectangle));
|
||||
|
||||
CesiumGeometry::QuadtreeTilingScheme tilingScheme =
|
||||
_options.tilingScheme.value_or(CesiumGeometry::QuadtreeTilingScheme(
|
||||
this->_options.tilingScheme.value_or(CesiumGeometry::QuadtreeTilingScheme(
|
||||
coverageRectangle,
|
||||
rootTilesX,
|
||||
1));
|
||||
|
||||
return asyncSystem
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<RasterOverlay::CreateTileProviderResult>(
|
||||
new UrlTemplateRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this,
|
||||
parameters,
|
||||
this->_options.credit,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
_url,
|
||||
_headers,
|
||||
_options.tileWidth,
|
||||
_options.tileHeight,
|
||||
_options.minimumLevel,
|
||||
_options.maximumLevel));
|
||||
this->_url,
|
||||
this->_headers,
|
||||
this->_options.tileWidth,
|
||||
this->_options.tileHeight,
|
||||
this->_options.minimumLevel,
|
||||
this->_options.maximumLevel));
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -8,21 +8,19 @@
|
|||
#include <CesiumGeospatial/GeographicProjection.h>
|
||||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/WebMapServiceRasterOverlay.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/Math.h>
|
||||
#include <CesiumUtility/Uri.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <spdlog/logger.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
|
@ -149,14 +147,9 @@ class WebMapServiceTileProvider final
|
|||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
WebMapServiceTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
std::optional<std::string> credit,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
@ -170,13 +163,8 @@ public:
|
|||
uint32_t minimumLevel,
|
||||
uint32_t maximumLevel)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
|
|
@ -188,7 +176,15 @@ public:
|
|||
_headers(headers),
|
||||
_version(version),
|
||||
_layers(layers),
|
||||
_format(format) {}
|
||||
_format(format) {
|
||||
if (parameters.externals.pCreditSystem && credit) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
*credit,
|
||||
pCreator->getOptions().showCreditsOnScreen));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~WebMapServiceTileProvider() = default;
|
||||
|
||||
|
|
@ -268,13 +264,7 @@ WebMapServiceRasterOverlay::~WebMapServiceRasterOverlay() = default;
|
|||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
WebMapServiceRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
|
||||
std::string xmlUrlGetcapabilities =
|
||||
CesiumUtility::Uri::substituteTemplateParameters(
|
||||
|
|
@ -295,27 +285,15 @@ WebMapServiceRasterOverlay::createTileProvider(
|
|||
return "{" + placeholder + "}";
|
||||
});
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
IntrusivePointer<const WebMapServiceRasterOverlay> thiz = this;
|
||||
|
||||
std::optional<Credit> credit = std::nullopt;
|
||||
if (pCreditSystem && this->_options.credit) {
|
||||
credit = pCreditSystem->createCredit(
|
||||
*this->_options.credit,
|
||||
pOwner->getOptions().showCreditsOnScreen);
|
||||
}
|
||||
|
||||
return pAssetAccessor->get(asyncSystem, xmlUrlGetcapabilities, this->_headers)
|
||||
return parameters.externals.pAssetAccessor
|
||||
->get(
|
||||
parameters.externals.asyncSystem,
|
||||
xmlUrlGetcapabilities,
|
||||
this->_headers)
|
||||
.thenInMainThread(
|
||||
[pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
options = this->_options,
|
||||
url = this->_baseUrl,
|
||||
headers = this->_headers](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
[thiz, parameters](std::shared_ptr<IAssetRequest>&& pRequest)
|
||||
-> CreateTileProviderResult {
|
||||
const IAssetResponse* pResponse = pRequest->response();
|
||||
if (!pResponse) {
|
||||
|
|
@ -347,15 +325,18 @@ WebMapServiceRasterOverlay::createTileProvider(
|
|||
"element."});
|
||||
}
|
||||
|
||||
const WebMapServiceRasterOverlayOptions& wmsOptions =
|
||||
thiz->_options;
|
||||
|
||||
std::string validationError;
|
||||
if (!validateCapabilities(pRoot, options, validationError)) {
|
||||
if (!validateCapabilities(pRoot, wmsOptions, validationError)) {
|
||||
return nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::TileProvider,
|
||||
std::move(pRequest),
|
||||
validationError});
|
||||
}
|
||||
|
||||
const Ellipsoid& ellipsoid = pOwner->getOptions().ellipsoid;
|
||||
const Ellipsoid& ellipsoid = thiz->getOptions().ellipsoid;
|
||||
|
||||
const auto projection =
|
||||
CesiumGeospatial::GeographicProjection(ellipsoid);
|
||||
|
|
@ -374,25 +355,24 @@ WebMapServiceRasterOverlay::createTileProvider(
|
|||
rootTilesY);
|
||||
|
||||
return new WebMapServiceTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
thiz,
|
||||
parameters,
|
||||
wmsOptions.credit,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
url,
|
||||
headers,
|
||||
options.version,
|
||||
options.layers,
|
||||
options.format,
|
||||
options.tileWidth < 1 ? 1 : uint32_t(options.tileWidth),
|
||||
options.tileHeight < 1 ? 1 : uint32_t(options.tileHeight),
|
||||
options.minimumLevel < 0 ? 0 : uint32_t(options.minimumLevel),
|
||||
options.maximumLevel < 0 ? 0 : uint32_t(options.maximumLevel));
|
||||
thiz->_baseUrl,
|
||||
thiz->_headers,
|
||||
wmsOptions.version,
|
||||
wmsOptions.layers,
|
||||
wmsOptions.format,
|
||||
wmsOptions.tileWidth < 1 ? 1 : uint32_t(wmsOptions.tileWidth),
|
||||
wmsOptions.tileHeight < 1 ? 1 : uint32_t(wmsOptions.tileHeight),
|
||||
wmsOptions.minimumLevel < 0 ? 0
|
||||
: uint32_t(wmsOptions.minimumLevel),
|
||||
wmsOptions.maximumLevel < 0
|
||||
? 0
|
||||
: uint32_t(wmsOptions.maximumLevel));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,24 +7,21 @@
|
|||
#include <CesiumGeospatial/GlobeRectangle.h>
|
||||
#include <CesiumGeospatial/Projection.h>
|
||||
#include <CesiumGeospatial/WebMercatorProjection.h>
|
||||
#include <CesiumRasterOverlays/IPrepareRasterOverlayRendererResources.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayLoadFailureDetails.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/WebMapTileServiceRasterOverlay.h>
|
||||
#include <CesiumUtility/CreditSystem.h>
|
||||
#include <CesiumUtility/IntrusivePointer.h>
|
||||
#include <CesiumUtility/Uri.h>
|
||||
|
||||
#include <nonstd/expected.hpp>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
|
@ -40,14 +37,9 @@ class WebMapTileServiceTileProvider final
|
|||
: public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
WebMapTileServiceTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
std::optional<std::string> credit,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
@ -66,13 +58,8 @@ public:
|
|||
const std::optional<std::map<std::string, std::string>>& dimensions,
|
||||
const std::vector<std::string>& subdomains)
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
|
|
@ -89,7 +76,15 @@ public:
|
|||
_tileMatrixSetID(std::move(_tileMatrixSetID)),
|
||||
_labels(tileMatrixLabels),
|
||||
_staticDimensions(dimensions),
|
||||
_subdomains(subdomains) {}
|
||||
_subdomains(subdomains) {
|
||||
if (parameters.externals.pCreditSystem && credit) {
|
||||
this->getCredits().emplace_back(
|
||||
parameters.externals.pCreditSystem->createCredit(
|
||||
this->getCreditSource(),
|
||||
*credit,
|
||||
pCreator->getOptions().showCreditsOnScreen));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~WebMapTileServiceTileProvider() = default;
|
||||
|
||||
|
|
@ -204,22 +199,7 @@ WebMapTileServiceRasterOverlay::~WebMapTileServiceRasterOverlay() = default;
|
|||
|
||||
Future<RasterOverlay::CreateTileProviderResult>
|
||||
WebMapTileServiceRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
|
||||
pOwner = pOwner ? pOwner : this;
|
||||
|
||||
std::optional<Credit> credit = std::nullopt;
|
||||
if (pCreditSystem && this->_options.credit) {
|
||||
credit = pCreditSystem->createCredit(
|
||||
*this->_options.credit,
|
||||
pOwner->getOptions().showCreditsOnScreen);
|
||||
}
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
|
||||
bool hasError = false;
|
||||
std::string errorMessage;
|
||||
|
|
@ -245,7 +225,7 @@ WebMapTileServiceRasterOverlay::createTileProvider(
|
|||
}
|
||||
|
||||
CesiumGeospatial::Projection projection = _options.projection.value_or(
|
||||
CesiumGeospatial::WebMercatorProjection(pOwner->getOptions().ellipsoid));
|
||||
CesiumGeospatial::WebMercatorProjection(this->getOptions().ellipsoid));
|
||||
CesiumGeospatial::GlobeRectangle tilingSchemeRectangle =
|
||||
CesiumGeospatial::WebMercatorProjection::MAXIMUM_GLOBE_RECTANGLE;
|
||||
uint32_t rootTilesX = 1;
|
||||
|
|
@ -265,40 +245,36 @@ WebMapTileServiceRasterOverlay::createTileProvider(
|
|||
1));
|
||||
|
||||
if (hasError) {
|
||||
return asyncSystem
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<RasterOverlay::CreateTileProviderResult>(
|
||||
nonstd::make_unexpected(RasterOverlayLoadFailureDetails{
|
||||
RasterOverlayLoadType::TileProvider,
|
||||
nullptr,
|
||||
errorMessage}));
|
||||
}
|
||||
return asyncSystem
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<RasterOverlay::CreateTileProviderResult>(
|
||||
new WebMapTileServiceTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
this,
|
||||
parameters,
|
||||
this->_options.credit,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
_url,
|
||||
_headers,
|
||||
this->_url,
|
||||
this->_headers,
|
||||
useKVP,
|
||||
format,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
minimumLevel,
|
||||
maximumLevel,
|
||||
_options.layer,
|
||||
_options.style,
|
||||
_options.tileMatrixSetID,
|
||||
_options.tileMatrixLabels,
|
||||
_options.dimensions,
|
||||
_options.subdomains));
|
||||
this->_options.layer,
|
||||
this->_options.style,
|
||||
this->_options.tileMatrixSetID,
|
||||
this->_options.tileMatrixLabels,
|
||||
this->_options.dimensions,
|
||||
this->_options.subdomains));
|
||||
}
|
||||
|
||||
} // namespace CesiumRasterOverlays
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/UrlTemplateRasterOverlay.h>
|
||||
|
||||
|
|
@ -12,31 +13,19 @@ public:
|
|||
MyRasterOverlay() : RasterOverlay("name", {}) {}
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override;
|
||||
};
|
||||
|
||||
//! [use-url-template]
|
||||
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult>
|
||||
MyRasterOverlay::createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
||||
const CreateRasterOverlayTileProviderParameters& parameters) const {
|
||||
// Create a new raster overlay with a URL template.
|
||||
CesiumGeometry::Rectangle coverageRectangle = CesiumGeospatial::
|
||||
WebMercatorProjection::computeMaximumProjectedRectangle();
|
||||
|
||||
UrlTemplateRasterOverlayOptions options{
|
||||
UrlTemplateRasterOverlayOptions urlTemplateOptions{
|
||||
.credit = "Copyright (c) Some Amazing Source",
|
||||
.projection = CesiumGeospatial::WebMercatorProjection(),
|
||||
.tilingScheme =
|
||||
|
|
@ -53,16 +42,15 @@ MyRasterOverlay::createTileProvider(
|
|||
this->getName(),
|
||||
"https://example.com/level-{z}/column-{x}/row-{y}.png",
|
||||
{},
|
||||
options);
|
||||
urlTemplateOptions);
|
||||
|
||||
CreateRasterOverlayTileProviderParameters parametersCopy = parameters;
|
||||
if (!parametersCopy.pOwner) {
|
||||
parametersCopy.pOwner = this;
|
||||
}
|
||||
|
||||
// Get that raster overlay's tile provider.
|
||||
return pUrlTemplate->createTileProvider(
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pOwner != nullptr ? pOwner : this);
|
||||
return pUrlTemplate->createTileProvider(parametersCopy);
|
||||
}
|
||||
//! [use-url-template]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <CesiumNativeTests/SimpleAssetAccessor.h>
|
||||
#include <CesiumNativeTests/SimpleAssetRequest.h>
|
||||
#include <CesiumRasterOverlays/ActivatedRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/QuadtreeRasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
|
|
@ -47,14 +48,8 @@ namespace {
|
|||
class TestTileProvider : public QuadtreeRasterOverlayTileProvider {
|
||||
public:
|
||||
TestTileProvider(
|
||||
const IntrusivePointer<const RasterOverlay>& pOwner,
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CesiumUtility::CreditSystem>& pCreditSystem,
|
||||
std::optional<Credit> credit,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
const IntrusivePointer<const RasterOverlay>& pCreator,
|
||||
const CreateRasterOverlayTileProviderParameters& parameters,
|
||||
const CesiumGeospatial::Projection& projection,
|
||||
const CesiumGeometry::QuadtreeTilingScheme& tilingScheme,
|
||||
const CesiumGeometry::Rectangle& coverageRectangle,
|
||||
|
|
@ -63,13 +58,8 @@ public:
|
|||
uint32_t imageWidth,
|
||||
uint32_t imageHeight) noexcept
|
||||
: QuadtreeRasterOverlayTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
pCreditSystem,
|
||||
credit,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
pCreator,
|
||||
parameters,
|
||||
projection,
|
||||
tilingScheme,
|
||||
coverageRectangle,
|
||||
|
|
@ -114,27 +104,12 @@ public:
|
|||
: RasterOverlay(name, options) {}
|
||||
|
||||
virtual CesiumAsync::Future<CreateTileProviderResult> createTileProvider(
|
||||
const CesiumAsync::AsyncSystem& asyncSystem,
|
||||
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
||||
const std::shared_ptr<CreditSystem>& /* pCreditSystem */,
|
||||
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
||||
pPrepareRendererResources,
|
||||
const std::shared_ptr<spdlog::logger>& pLogger,
|
||||
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner)
|
||||
const CreateRasterOverlayTileProviderParameters& parameters)
|
||||
const override {
|
||||
if (!pOwner) {
|
||||
pOwner = this;
|
||||
}
|
||||
|
||||
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
||||
new TestTileProvider(
|
||||
pOwner,
|
||||
asyncSystem,
|
||||
pAssetAccessor,
|
||||
nullptr,
|
||||
std::nullopt,
|
||||
pPrepareRendererResources,
|
||||
pLogger,
|
||||
return parameters.externals.asyncSystem
|
||||
.createResolvedFuture<CreateTileProviderResult>(new TestTileProvider(
|
||||
this,
|
||||
parameters,
|
||||
WebMercatorProjection(Ellipsoid::WGS84),
|
||||
QuadtreeTilingScheme(
|
||||
WebMercatorProjection::computeMaximumProjectedRectangle(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <CesiumNativeTests/readFile.h>
|
||||
#include <CesiumNativeTests/waitForFuture.h>
|
||||
#include <CesiumRasterOverlays/ActivatedRasterOverlay.h>
|
||||
#include <CesiumRasterOverlays/CreateRasterOverlayTileProviderParameters.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
||||
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
||||
#include <CesiumRasterOverlays/TileMapServiceRasterOverlay.h>
|
||||
|
|
@ -125,12 +126,12 @@ TEST_CASE("TileMapServiceRasterOverlay") {
|
|||
RasterOverlay::CreateTileProviderResult result = waitForFuture(
|
||||
asyncSystem,
|
||||
pRasterOverlay->createTileProvider(
|
||||
asyncSystem,
|
||||
pMockAssetAccessor,
|
||||
nullptr,
|
||||
nullptr,
|
||||
spdlog::default_logger(),
|
||||
nullptr));
|
||||
CreateRasterOverlayTileProviderParameters{
|
||||
.externals =
|
||||
{.pAssetAccessor = pMockAssetAccessor,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pLogger = spdlog::default_logger()},
|
||||
}));
|
||||
|
||||
REQUIRE(result);
|
||||
}
|
||||
|
|
@ -160,12 +161,12 @@ TEST_CASE("TileMapServiceRasterOverlay") {
|
|||
RasterOverlay::CreateTileProviderResult result = waitForFuture(
|
||||
asyncSystem,
|
||||
pRasterOverlay->createTileProvider(
|
||||
asyncSystem,
|
||||
pMockAssetAccessor,
|
||||
nullptr,
|
||||
nullptr,
|
||||
spdlog::default_logger(),
|
||||
nullptr));
|
||||
CreateRasterOverlayTileProviderParameters{
|
||||
.externals =
|
||||
{.pAssetAccessor = pMockAssetAccessor,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pLogger = spdlog::default_logger()},
|
||||
}));
|
||||
|
||||
REQUIRE(result);
|
||||
}
|
||||
|
|
@ -215,12 +216,12 @@ TEST_CASE("TileMapServiceRasterOverlay") {
|
|||
RasterOverlay::CreateTileProviderResult result = waitForFuture(
|
||||
asyncSystem,
|
||||
pRasterOverlay->createTileProvider(
|
||||
asyncSystem,
|
||||
pMockAssetAccessor,
|
||||
nullptr,
|
||||
nullptr,
|
||||
spdlog::default_logger(),
|
||||
nullptr));
|
||||
CreateRasterOverlayTileProviderParameters{
|
||||
.externals =
|
||||
{.pAssetAccessor = pMockAssetAccessor,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pLogger = spdlog::default_logger()},
|
||||
}));
|
||||
|
||||
REQUIRE(result);
|
||||
}
|
||||
|
|
@ -237,12 +238,13 @@ TEST_CASE("TileMapServiceRasterOverlay") {
|
|||
RasterOverlay::CreateTileProviderResult result = waitForFuture(
|
||||
asyncSystem,
|
||||
pRasterOverlayWithCredit->createTileProvider(
|
||||
asyncSystem,
|
||||
pMockAssetAccessor,
|
||||
pCreditSystem,
|
||||
nullptr,
|
||||
spdlog::default_logger(),
|
||||
nullptr));
|
||||
CreateRasterOverlayTileProviderParameters{
|
||||
.externals =
|
||||
{.pAssetAccessor = pMockAssetAccessor,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pCreditSystem = pCreditSystem,
|
||||
.pLogger = spdlog::default_logger()},
|
||||
}));
|
||||
|
||||
REQUIRE(result);
|
||||
|
||||
|
|
@ -266,12 +268,12 @@ TEST_CASE("TileMapServiceRasterOverlay") {
|
|||
RasterOverlay::CreateTileProviderResult result = waitForFuture(
|
||||
asyncSystem,
|
||||
pRasterOverlayWithCredit->createTileProvider(
|
||||
asyncSystem,
|
||||
pMockAssetAccessor,
|
||||
nullptr,
|
||||
nullptr,
|
||||
spdlog::default_logger(),
|
||||
nullptr));
|
||||
CreateRasterOverlayTileProviderParameters{
|
||||
.externals =
|
||||
{.pAssetAccessor = pMockAssetAccessor,
|
||||
.asyncSystem = asyncSystem,
|
||||
.pLogger = spdlog::default_logger()},
|
||||
}));
|
||||
|
||||
REQUIRE(result);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ cesium_target_include_directories(
|
|||
target_link_libraries(
|
||||
CesiumUtility
|
||||
PUBLIC
|
||||
zlib-ng::zlib-ng
|
||||
zlib-ng::zlib
|
||||
spdlog::spdlog
|
||||
glm::glm
|
||||
ada::ada
|
||||
|
|
|
|||
|
|
@ -106,9 +106,17 @@ public:
|
|||
*/
|
||||
void releaseAllReferences() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Tests if a credit is referenced by this referencer.
|
||||
*
|
||||
* @param credit The credit to test if it is referenced.
|
||||
*/
|
||||
bool isCreditReferenced(Credit credit) const noexcept;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CreditSystem> _pCreditSystem;
|
||||
std::vector<int32_t> _references;
|
||||
std::vector<uint32_t> _generations;
|
||||
};
|
||||
|
||||
} // namespace CesiumUtility
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include <CesiumUtility/Library.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
|
@ -10,6 +12,45 @@
|
|||
|
||||
namespace CesiumUtility {
|
||||
|
||||
class CreditSystem;
|
||||
|
||||
/**
|
||||
* @brief Specifies how credit system snapshots should handle multiple
|
||||
* credits with the same HTML string.
|
||||
*/
|
||||
enum class CreditFilteringMode : uint8_t {
|
||||
/**
|
||||
* @brief No filtering is performed. Each unique @ref Credit is reported.
|
||||
*/
|
||||
None = 0,
|
||||
|
||||
/**
|
||||
* @brief Credits are filtered so that each reported credit has a combination
|
||||
* of HTML string and @ref CreditSystem::shouldBeShownOnScreen value that is
|
||||
* unique from all the other reported credits.
|
||||
*
|
||||
* If multiple credits have the same HTML string but different
|
||||
* @ref CreditSystem::shouldBeShownOnScreen values, they will be reported as
|
||||
* separate credits.
|
||||
*
|
||||
* It is unspecified which of the multiple credits with the same properties
|
||||
* will be reported.
|
||||
*/
|
||||
UniqueHtmlAndShowOnScreen = 1,
|
||||
|
||||
/**
|
||||
* @brief Credits with identical HTML strings are reported as one Credit even
|
||||
* if they have a different @ref CreditSource or @ref
|
||||
* CreditSystem::shouldBeShownOnScreen value.
|
||||
*
|
||||
* It is unspecified which of the multiple credits with the same source will
|
||||
* be reported. However, it is guaranteed that if any of the multiple credits
|
||||
* has @ref CreditSystem::shouldBeShownOnScreen set to `true`, the reported
|
||||
* credit will also have it set to `true`.
|
||||
*/
|
||||
UniqueHtml = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents an HTML string that should be shown on screen to attribute
|
||||
* third parties for used data, imagery, etc. Acts as a handle into a
|
||||
|
|
@ -21,18 +62,75 @@ public:
|
|||
* @brief Returns `true` if two credit objects have the same ID.
|
||||
*/
|
||||
bool operator==(const Credit& rhs) const noexcept {
|
||||
return this->id == rhs.id;
|
||||
return this->_id == rhs._id && this->_generation == rhs._generation;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t id;
|
||||
uint32_t _id;
|
||||
uint32_t _generation;
|
||||
|
||||
Credit(size_t id_) noexcept : id(id_) {}
|
||||
Credit(uint32_t id, uint32_t generation) noexcept
|
||||
: _id(id), _generation(generation) {}
|
||||
|
||||
friend class CreditSystem;
|
||||
friend class CreditReferencer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a source of credits, such as a tileset or raster overlay,
|
||||
* provided to a @ref CreditSystem.
|
||||
*
|
||||
* While the @ref CreditSystem does not directly map credit source instances to
|
||||
* tilesets or raster overlays (or vice-versa), a tileset or raster overlay can
|
||||
* be queried for its credit source instance and that instance can be compared
|
||||
* against one known to the credit system.
|
||||
*
|
||||
* When the last reference to a credit source is released, all credits
|
||||
* associated with that source are invalidated as well.
|
||||
*/
|
||||
class CESIUMUTILITY_API CreditSource {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a new credit source associated with a given credit
|
||||
* system.
|
||||
*
|
||||
* @param creditSystem The credit system to associate with this source.
|
||||
*/
|
||||
CreditSource(CreditSystem& creditSystem) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Constructs a new credit source associated with a given credit
|
||||
* system.
|
||||
*
|
||||
* @param pCreditSystem The credit system to associate with this source. This
|
||||
* is allowed to be nullptr in order to enable simpler client code when
|
||||
* working with an optional credit system.
|
||||
*/
|
||||
CreditSource(const std::shared_ptr<CreditSystem>& pCreditSystem) noexcept;
|
||||
|
||||
~CreditSource() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the @ref CreditSystem associated with this source.
|
||||
*
|
||||
* This may be nullptr if this source was never associated with a credit
|
||||
* system, or if the credit system has been destroyed.
|
||||
*/
|
||||
CreditSystem* getCreditSystem() noexcept;
|
||||
|
||||
/**
|
||||
* @copydoc getCreditSystem
|
||||
*/
|
||||
const CreditSystem* getCreditSystem() const noexcept;
|
||||
|
||||
private:
|
||||
void notifyCreditSystemDestroyed() noexcept;
|
||||
|
||||
CreditSystem* _pCreditSystem;
|
||||
|
||||
friend class CreditSystem;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A snapshot of the credits currently active in a {@link CreditSystem}.
|
||||
*/
|
||||
|
|
@ -57,18 +155,56 @@ struct CreditsSnapshot {
|
|||
class CESIUMUTILITY_API CreditSystem final {
|
||||
public:
|
||||
/**
|
||||
* @brief Inserts a credit string
|
||||
* @brief Constructs a new instance.
|
||||
*/
|
||||
CreditSystem() noexcept = default;
|
||||
~CreditSystem() noexcept;
|
||||
|
||||
CreditSystem(const CreditSystem&) = delete;
|
||||
CreditSystem& operator=(const CreditSystem&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Inserts a credit string.
|
||||
*
|
||||
* @param source The source of the credit. This should be an instance created
|
||||
* and owned by a tileset, raster overlay, or other data source.
|
||||
* @param html The HTML string for the credit.
|
||||
* @param showOnScreen Whether or not the credit should be shown on screen.
|
||||
* Credits not shown on the screen should be shown in a separate popup window.
|
||||
* @return If this string already exists from the same source, returns a
|
||||
* Credit handle to the existing entry. Otherwise returns a Credit handle to a
|
||||
* new entry.
|
||||
*/
|
||||
Credit createCredit(
|
||||
const CreditSource& source,
|
||||
std::string&& html,
|
||||
bool showOnScreen = false);
|
||||
|
||||
/** @copydoc createCredit */
|
||||
Credit createCredit(
|
||||
const CreditSource& source,
|
||||
const std::string& html,
|
||||
bool showOnScreen = false);
|
||||
|
||||
/**
|
||||
* @brief Inserts a credit string associated with the @ref
|
||||
* getDefaultCreditSource.
|
||||
*
|
||||
* @return If this string already exists, returns a Credit handle to the
|
||||
* existing entry. Otherwise returns a Credit handle to a new entry.
|
||||
*
|
||||
* @deprecated Use the overload that takes a @ref CreditSource.
|
||||
*/
|
||||
Credit createCredit(std::string&& html, bool showOnScreen = false);
|
||||
|
||||
/**
|
||||
* @brief Inserts a credit string
|
||||
* @brief Inserts a credit string associated with the @ref
|
||||
* getDefaultCreditSource.
|
||||
*
|
||||
* @return If this string already exists, returns a Credit handle to the
|
||||
* existing entry. Otherwise returns a Credit handle to a new entry.
|
||||
*
|
||||
* @deprecated Use the overload that takes a @ref CreditSource.
|
||||
*/
|
||||
Credit createCredit(const std::string& html, bool showOnScreen = false);
|
||||
|
||||
|
|
@ -83,26 +219,40 @@ public:
|
|||
void setShowOnScreen(Credit credit, bool showOnScreen) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the HTML string for this credit
|
||||
* @brief Get the HTML string for this credit.
|
||||
*/
|
||||
const std::string& getHtml(Credit credit) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the source of this credit.
|
||||
*
|
||||
* @return The source of this credit, or nullptr if the credit is invalid or
|
||||
* was created by a \ref CreditSource that has been destroyed.
|
||||
*/
|
||||
const CreditSource* getCreditSource(Credit credit) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Adds a reference to a credit, incrementing its reference count. The
|
||||
* referenced credit will be shown until its reference count goes back down to
|
||||
* zero.
|
||||
*
|
||||
* @param credit The credit to reference.
|
||||
* @returns `true` if the credit was valid and the reference was added.
|
||||
* `false` if the credit was created by a @ref CreditSource that has been
|
||||
* destroyed and so the reference could not be added.
|
||||
*/
|
||||
void addCreditReference(Credit credit);
|
||||
bool addCreditReference(Credit credit);
|
||||
|
||||
/**
|
||||
* @brief Removes a reference from a credit, decrementing its reference count.
|
||||
* When the reference count goes to zero, this credit will no longer be shown.
|
||||
*
|
||||
* @param credit The credit from which to remove a reference.
|
||||
* @returns `true` if the credit was valid and the reference was removed.
|
||||
* `false` if the credit was created by a @ref CreditSource that has been
|
||||
* destroyed and so the reference could not be removed.
|
||||
*/
|
||||
void removeCreditReference(Credit credit);
|
||||
bool removeCreditReference(Credit credit);
|
||||
|
||||
/**
|
||||
* @brief Gets a snapshot of the credits. The returned instance is only valid
|
||||
|
|
@ -111,27 +261,72 @@ public:
|
|||
* The snapshot will include a sorted list of credits that are currently
|
||||
* active, as well as a list of credits that have been removed since the last
|
||||
* snapshot.
|
||||
*
|
||||
* @param filteringMode Specifies how multiple credits with the same HTML
|
||||
* string should be reported in the snapshot.
|
||||
*/
|
||||
const CreditsSnapshot& getSnapshot() noexcept;
|
||||
const CreditsSnapshot& getSnapshot(
|
||||
CreditFilteringMode filteringMode =
|
||||
CreditFilteringMode::UniqueHtml) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the default credit source used when no other source is
|
||||
* specified.
|
||||
*
|
||||
* @deprecated Instead of using the default, create a CreditSource instance
|
||||
* for each tileset, raster overlay, or other data source.
|
||||
*/
|
||||
const CreditSource& getDefaultCreditSource() const noexcept;
|
||||
|
||||
private:
|
||||
void addBulkReferences(const std::vector<int32_t>& references) noexcept;
|
||||
void releaseBulkReferences(const std::vector<int32_t>& references) noexcept;
|
||||
struct CreditRecord {
|
||||
std::string html{};
|
||||
bool showOnScreen{false};
|
||||
int32_t referenceCount{0};
|
||||
bool shownLastSnapshot{0};
|
||||
uint32_t generation{0};
|
||||
const CreditSource* pSource{nullptr};
|
||||
uint32_t previousCreditWithSameHtml{INVALID_CREDIT_INDEX};
|
||||
uint32_t nextCreditWithSameHtml{INVALID_CREDIT_INDEX};
|
||||
};
|
||||
|
||||
void addBulkReferences(
|
||||
const std::vector<int32_t>& references,
|
||||
const std::vector<uint32_t>& generations) noexcept;
|
||||
void releaseBulkReferences(
|
||||
const std::vector<int32_t>& references,
|
||||
const std::vector<uint32_t>& generations) noexcept;
|
||||
|
||||
void createCreditSource(CreditSource& creditSource) noexcept;
|
||||
void destroyCreditSource(CreditSource& creditSource) noexcept;
|
||||
|
||||
uint32_t filterCreditForSnapshot(
|
||||
CreditFilteringMode filteringMode,
|
||||
const CreditRecord& record) noexcept;
|
||||
|
||||
const std::string INVALID_CREDIT_MESSAGE =
|
||||
"Error: Invalid Credit, cannot get HTML string.";
|
||||
|
||||
struct CreditRecord {
|
||||
std::string html;
|
||||
bool showOnScreen;
|
||||
int32_t referenceCount;
|
||||
bool shownLastSnapshot;
|
||||
};
|
||||
static const uint32_t INVALID_CREDIT_INDEX{
|
||||
std::numeric_limits<uint32_t>::max()};
|
||||
|
||||
std::vector<CreditSource*> _creditSources;
|
||||
std::vector<CreditRecord> _credits;
|
||||
std::vector<Credit> _creditsToNoLongerShowThisSnapshot;
|
||||
CreditsSnapshot _snapshot;
|
||||
std::vector<int32_t> _referenceCountScratch;
|
||||
|
||||
// These are credits that were shown in the last snapshot but whose
|
||||
// CreditSources have since been destroyed. They need to be reported in
|
||||
// removedCredits in the next snapshot.
|
||||
std::vector<Credit> _shownCreditsDestroyed;
|
||||
|
||||
// Each entry in this vector is an index into _credits that is unused and can
|
||||
// be reused for a new credit.
|
||||
std::vector<size_t> _unusedCreditRecords;
|
||||
|
||||
CreditSource _defaultCreditSource{*this};
|
||||
|
||||
friend class CreditReferencer;
|
||||
friend class CreditSource;
|
||||
};
|
||||
} // namespace CesiumUtility
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace CesiumUtility {
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ struct Hash {
|
|||
* @param second The second hash value.
|
||||
* @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
|
||||
|
|
|
|||
|
|
@ -356,6 +356,12 @@ public:
|
|||
static std::string
|
||||
setPath(const std::string& uri, const std::string& newPath);
|
||||
|
||||
/**
|
||||
* @brief Ensures that the Uri's path ends with a slash, modifying itself if
|
||||
* necessary. Useful when the Uri is used as a base URL.
|
||||
*/
|
||||
void ensureTrailingSlash();
|
||||
|
||||
private:
|
||||
std::optional<ada::url_aggregator> _url = std::nullopt;
|
||||
bool _hasScheme = false;
|
||||
|
|
|
|||
|
|
@ -10,12 +10,16 @@ CreditReferencer::CreditReferencer() noexcept : CreditReferencer(nullptr) {}
|
|||
|
||||
CreditReferencer::CreditReferencer(
|
||||
const std::shared_ptr<CreditSystem>& pCreditSystem) noexcept
|
||||
: _pCreditSystem(pCreditSystem) {}
|
||||
: _pCreditSystem(pCreditSystem), _references(), _generations() {}
|
||||
|
||||
CreditReferencer::CreditReferencer(const CreditReferencer& rhs) noexcept
|
||||
: _pCreditSystem(rhs._pCreditSystem), _references(rhs._references) {
|
||||
: _pCreditSystem(rhs._pCreditSystem),
|
||||
_references(rhs._references),
|
||||
_generations(rhs._generations) {
|
||||
if (this->_pCreditSystem) {
|
||||
this->_pCreditSystem->addBulkReferences(this->_references);
|
||||
this->_pCreditSystem->addBulkReferences(
|
||||
this->_references,
|
||||
this->_generations);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,12 +27,15 @@ CreditReferencer&
|
|||
CreditReferencer::operator=(const CreditReferencer& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
if (this->_pCreditSystem) {
|
||||
this->_pCreditSystem->addBulkReferences(rhs._references);
|
||||
this->_pCreditSystem->addBulkReferences(
|
||||
rhs._references,
|
||||
rhs._generations);
|
||||
}
|
||||
|
||||
this->releaseAllReferences();
|
||||
this->_pCreditSystem = rhs._pCreditSystem;
|
||||
this->_references = rhs._references;
|
||||
this->_generations = rhs._generations;
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
|
@ -43,6 +50,7 @@ CreditReferencer& CreditReferencer::operator=(CreditReferencer&& rhs) noexcept {
|
|||
this->releaseAllReferences();
|
||||
this->_pCreditSystem = std::move(rhs._pCreditSystem);
|
||||
this->_references = std::move(rhs._references);
|
||||
this->_generations = std::move(rhs._generations);
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
|
@ -65,21 +73,50 @@ void CreditReferencer::addCreditReference(Credit credit) noexcept {
|
|||
if (!this->_pCreditSystem)
|
||||
return;
|
||||
|
||||
if (this->_references.size() <= credit.id) {
|
||||
this->_references.resize(credit.id + 1);
|
||||
if (!this->_pCreditSystem->addCreditReference(credit)) {
|
||||
// This credit was created by a CreditSource that has been destroyed. Ignore
|
||||
// it.
|
||||
return;
|
||||
}
|
||||
|
||||
++this->_references[credit.id];
|
||||
this->_pCreditSystem->addCreditReference(credit);
|
||||
if (this->_references.size() <= credit._id) {
|
||||
this->_references.resize(credit._id + 1);
|
||||
this->_generations.resize(credit._id + 1);
|
||||
}
|
||||
|
||||
if (this->_generations[credit._id] != credit._generation) {
|
||||
// The existing references (if any) refer to an older generation of this
|
||||
// credit (i.e., from a previous CreditSource that has been destroyed). So
|
||||
// reset the reference count to zero.
|
||||
this->_references[credit._id] = 0;
|
||||
this->_generations[credit._id] = credit._generation;
|
||||
}
|
||||
|
||||
++this->_references[credit._id];
|
||||
}
|
||||
|
||||
void CreditReferencer::releaseAllReferences() noexcept {
|
||||
if (!this->_pCreditSystem)
|
||||
return;
|
||||
|
||||
this->_pCreditSystem->releaseBulkReferences(this->_references);
|
||||
this->_pCreditSystem->releaseBulkReferences(
|
||||
this->_references,
|
||||
this->_generations);
|
||||
|
||||
this->_references.clear();
|
||||
this->_generations.clear();
|
||||
}
|
||||
|
||||
bool CreditReferencer::isCreditReferenced(Credit credit) const noexcept {
|
||||
if (!this->_pCreditSystem)
|
||||
return false;
|
||||
|
||||
if (this->_references.size() <= credit._id ||
|
||||
this->_generations[credit._id] != credit._generation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->_references[credit._id] > 0;
|
||||
}
|
||||
|
||||
} // namespace CesiumUtility
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue