Skip to content

Commit e876c13

Browse files
authored
Merge pull request #1267 from brendan-duncan/experiment_wasm
Add support for building cesium-native with Unity Web
2 parents ab8de59 + e9a9415 commit e876c13

File tree

44 files changed

+637
-119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+637
-119
lines changed

.github/workflows/build.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,70 @@ jobs:
217217
run: |
218218
cd build
219219
ctest -V
220+
EmscriptenBuild:
221+
strategy:
222+
fail-fast: false
223+
matrix:
224+
version: [ "3.1.39", "4.0.13" ]
225+
memory: [ "32", "64" ]
226+
exclude:
227+
- version: "3.1.39"
228+
memory: "64"
229+
name: Emscripten v${{matrix.version}} ${{matrix.memory}}bit memory
230+
env:
231+
CACHE_KEY: "emscripten-${{matrix.version}}-${{matrix.memory}}"
232+
runs-on: windows-2022
233+
steps:
234+
- name: Check out repository code
235+
uses: actions/checkout@v4
236+
with:
237+
submodules: recursive
238+
- name: Use NodeJS 24 for WebAssembly 64-bit memory support
239+
if: ${{ matrix.memory == '64' }}
240+
uses: actions/setup-node@v6
241+
with:
242+
node-version: '>=24'
243+
- name: Checkout vcpkg 2025.02.14 packages for use with Emscripten 3.1.39
244+
if: ${{ matrix.version == '3.1.39' }}
245+
uses: actions/checkout@v4
246+
with:
247+
repository: microsoft/vcpkg
248+
clean: false
249+
ref: 2025.02.14
250+
path: extern/vcpkg/temp
251+
sparse-checkout-cone-mode: false
252+
sparse-checkout: |
253+
ports/ada-url
254+
- name: Move overlay ports to the correct location
255+
if: ${{ matrix.version == '3.1.39' }}
256+
run: |
257+
mv extern/vcpkg/temp/ports/* extern/vcpkg/ports/
258+
- name: Add OpenSSL "no-dso" option on older Emscripten versions
259+
if: ${{ matrix.version == '3.1.39' }}
260+
run: |
261+
echo "
262+
if(PORT MATCHES "openssl")
263+
set(VCPKG_CONFIGURE_MAKE_OPTIONS "no-dso")
264+
endif()
265+
" >> extern/vcpkg/triplets/wasm32-emscripten-cesium.cmake
266+
- name: Install latest CMake 3 and Ninja
267+
uses: lukka/get-cmake@latest
268+
with:
269+
cmakeVersion: "3.31.6"
270+
- name: Install nasm
271+
uses: ilammy/setup-nasm@v1
272+
- name: Setup emsdk
273+
uses: mymindstorm/setup-emsdk@v14
274+
with:
275+
version: ${{matrix.version}}
276+
- name: Verify
277+
run: emcc -v
278+
- name: Compile Debug Configuration
279+
run: |
280+
$env:VCPKG_ROOT="$env:VCPKG_INSTALLATION_ROOT"
281+
$MEMORYPROPERTY="${{matrix.memory}}" -eq "64" ? "-DCESIUM_WASM64=ON" : ""
282+
emcmake cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug $MEMORYPROPERTY
283+
cmake --build build --config Debug --parallel
284+
- name: Test Debug Configuration
285+
run: |
286+
node build/CesiumNativeTests/cesium-native-tests.js

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
build
2+
build-*
23
doxygen
34
Testing
45
node_modules
@@ -8,7 +9,5 @@ CMakeSettings.json
89
.cache
910
*.DS_Store
1011
test.db
11-
build-wsl
1212
.idea
13-
build-debug
1413
clang-tidy.log

CMakeLists.txt

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ if (NOT VCPKG_LIBRARY_LINKAGE)
44
set(VCPKG_LIBRARY_LINKAGE static)
55
endif()
66

7+
get_filename_component(toolchainFile "${CMAKE_TOOLCHAIN_FILE}" NAME)
8+
if(toolchainFile STREQUAL "Emscripten.cmake")
9+
set(CESIUM_TARGET_WASM ON)
10+
# Include the toolchain directly as ezvcpkg will overwrite the
11+
# toolchain before it's loaded
12+
include(${CMAKE_TOOLCHAIN_FILE})
13+
endif()
14+
715
# By default, Use ezvcpkg to install dependencies. But don't use
816
# ezvcpkg if it appears that this configuration is using vcpkg
917
# manifest mode already, either by building cesium-native directly,
@@ -24,6 +32,13 @@ endif()
2432

2533
option(CESIUM_USE_EZVCPKG "use ezvcpkg helper" ${CESIUM_USE_EZVCPKG_DEFAULT})
2634
option(CESIUM_DISABLE_CURL "Disable cesium-native's use of libcurl" OFF)
35+
option(CESIUM_DISABLE_LIBJPEG_TURBO "Disable cesium-native's use of libjpeg-turbo. JPEG images will be decoded with STB instead." OFF)
36+
option(CESIUM_WASM64 "Enable 64-bit WebAssembly target" OFF)
37+
38+
if (CESIUM_TARGET_WASM)
39+
# Make sure curl is disabled on wasm builds, as it is not supported.
40+
set(CESIUM_DISABLE_CURL ON)
41+
endif()
2742

2843
if(CESIUM_USE_EZVCPKG)
2944
# Keep vcpkg from running in manifset mode. It will try to because
@@ -50,6 +65,15 @@ if (NOT VCPKG_TRIPLET)
5065
elseif(DETECTED_VCPKG_TRIPLET STREQUAL "x64-windows")
5166
# cesium-native requires static linking on Windows
5267
set(VCPKG_TRIPLET "x64-windows-static-md")
68+
elseif(DETECTED_VCPKG_TRIPLET STREQUAL "wasm32-emscripten")
69+
# Use our custom triplet for wasm builds. Most importantly, this
70+
# enables multithreading support. Also switch to 64-bit wasm if
71+
# requested.
72+
if (CESIUM_WASM64)
73+
set(VCPKG_TRIPLET "wasm64-emscripten-cesium")
74+
else()
75+
set(VCPKG_TRIPLET "wasm32-emscripten-cesium")
76+
endif()
5377
else()
5478
set(VCPKG_TRIPLET "${DETECTED_VCPKG_TRIPLET}")
5579
endif()
@@ -87,6 +111,10 @@ if (NOT VCPKG_OVERLAY_TRIPLETS)
87111
endif()
88112
endif()
89113

114+
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/triplets")
115+
list(APPEND VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/triplets")
116+
endif()
117+
90118
message(STATUS "VCPKG_OVERLAY_TRIPLETS ${VCPKG_OVERLAY_TRIPLETS}")
91119

92120
# These packages are used in the public headers of Cesium libraries, so we need to distribute the headers and binaries
@@ -98,13 +126,13 @@ set(PACKAGES_PUBLIC asyncplusplus expected-lite fmt glm rapidjson spdlog stb ada
98126
# to distribute the binaries for linking, but not the headers, as downstream consumers don't need them
99127
# OpenSSL and abseil are both dependencies of s2geometry
100128
set(PACKAGES_PRIVATE
101-
abseil draco ktx modp-base64 meshoptimizer openssl s2geometry
102-
libjpeg-turbo sqlite3 tinyxml2 libwebp zlib-ng picosha2
103-
earcut-hpp cpp-httplib[core] libmorton zstd
129+
abseil draco ktx[core] modp-base64 meshoptimizer openssl s2geometry
130+
sqlite3 tinyxml2 libwebp zlib-ng picosha2
131+
earcut-hpp libmorton zstd
104132
)
105133

106-
# asmjit needed by blend2d on non-iOS platforms (iOS doesn't support JIT)
107-
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
134+
# asmjit needed by blend2d on non-iOS platforms (iOS and Wasm don't support JIT)
135+
if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
108136
list(APPEND PACKAGES_PRIVATE blend2d asmjit)
109137
else()
110138
# Use [core] feature to disable default jit feature.
@@ -115,16 +143,37 @@ if(NOT CESIUM_DISABLE_CURL)
115143
list(APPEND PACKAGES_PRIVATE curl)
116144
endif()
117145

146+
if(NOT CESIUM_DISABLE_LIBJPEG_TURBO)
147+
list(APPEND PACKAGES_PRIVATE libjpeg-turbo)
148+
endif()
149+
150+
# We use cpp-httplib to host a local web server for OAuth2 authorization. That's not
151+
# going to work at all on the web, and the latest versions of cpp-httplib only support
152+
# 64-bit platforms anyway, so skip it entirely for WebAssembly builds.
153+
if(NOT CESIUM_TARGET_WASM)
154+
list(APPEND PACKAGES_PRIVATE "cpp-httplib[core]")
155+
endif()
156+
118157
# Packages only used for testing
119158
set(PACKAGES_TEST doctest)
120159

160+
if(CESIUM_TARGET_WASM)
161+
# vcpkg will attempt to second-guess our CMAKE_C_COMPILER setting, choosing to go with the value of CC instead.
162+
# While normally this is the correct value to go with, for wasm we need to be using emcc and em++.
163+
# So we set CC and CXX to emcc and em++ here so vcpkg will pick them up properly.
164+
# Does this make sense? No. Does it work? Somehow. ¯\_(ツ)_/¯
165+
set(ENV{CC} ${CMAKE_C_COMPILER})
166+
set(ENV{CXX} ${CMAKE_CXX_COMPILER})
167+
endif()
168+
121169
if(CESIUM_USE_EZVCPKG)
122170
set(PACKAGES_ALL ${PACKAGES_PUBLIC})
123171
list(APPEND PACKAGES_ALL ${PACKAGES_PRIVATE})
124172
list(APPEND PACKAGES_ALL ${PACKAGES_TEST})
125173

126174
ezvcpkg_fetch(
127-
COMMIT 2025.09.17
175+
COMMIT afc0a2e01ae104a2474216a2df0e8d78516fd5af
176+
REPO microsoft/vcpkg
128177
PACKAGES ${PACKAGES_ALL}
129178
# Clean the build trees after building, so that we don't use a ton a disk space on the CI cache
130179
CLEAN_BUILDTREES
@@ -149,6 +198,16 @@ project(cesium-native
149198
LANGUAGES CXX C
150199
)
151200

201+
if(CESIUM_TARGET_WASM)
202+
if(CESIUM_WASM64)
203+
set(CMAKE_SIZEOF_VOID_P 8)
204+
else()
205+
set(CMAKE_SIZEOF_VOID_P 4)
206+
endif()
207+
# Tells emscripten to output an HTML harness for the generated WASM
208+
set(CMAKE_EXECUTABLE_SUFFIX ".html")
209+
endif()
210+
152211
include(GNUInstallDirs)
153212
include(CMakeDependentOption)
154213

@@ -318,9 +377,7 @@ find_package(doctest CONFIG REQUIRED)
318377
find_package(draco CONFIG REQUIRED)
319378
find_package(expected-lite CONFIG REQUIRED)
320379
find_package(glm CONFIG REQUIRED)
321-
find_package(httplib CONFIG REQUIRED)
322380
find_package(Ktx CONFIG REQUIRED)
323-
find_package(libjpeg-turbo CONFIG REQUIRED)
324381
find_package(libmorton CONFIG REQUIRED)
325382
find_package(meshoptimizer CONFIG REQUIRED)
326383
find_package(OpenSSL REQUIRED)
@@ -331,15 +388,23 @@ find_package(unofficial-sqlite3 CONFIG REQUIRED)
331388
find_package(WebP CONFIG REQUIRED)
332389
find_package(zlib-ng CONFIG REQUIRED)
333390

334-
# asmjit should not be included with iOS builds as iOS doesn't support JIT compilation.
335-
if(NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
391+
# asmjit should not be included with iOS or Wasm builds as they don't support JIT compilation.
392+
if(NOT CESIUM_TARGET_WASM AND NOT IOS AND NOT VCPKG_CMAKE_SYSTEM_NAME MATCHES "iOS")
336393
find_package(asmjit CONFIG REQUIRED)
337394
endif()
338395

339396
if(NOT CESIUM_DISABLE_CURL)
340397
find_package(CURL REQUIRED)
341398
endif()
342399

400+
if(NOT CESIUM_DISABLE_LIBJPEG_TURBO)
401+
find_package(libjpeg-turbo CONFIG REQUIRED)
402+
endif()
403+
404+
if(NOT CESIUM_TARGET_WASM)
405+
find_package(httplib CONFIG REQUIRED)
406+
endif()
407+
343408
# Private Library (s2geometry)
344409
add_subdirectory(extern EXCLUDE_FROM_ALL)
345410

Cesium3DTilesContent/include/Cesium3DTilesContent/SubtreeAvailability.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ class SubtreeAvailability {
234234
bool isContentAvailable(
235235
const CesiumGeometry::QuadtreeTileID& subtreeId,
236236
const CesiumGeometry::QuadtreeTileID& tileId,
237-
uint64_t contentId) const noexcept;
237+
size_t contentId) const noexcept;
238238

239239
/**
240240
* @brief Determines if content for a given tile in the octree is available.
@@ -247,7 +247,7 @@ class SubtreeAvailability {
247247
bool isContentAvailable(
248248
const CesiumGeometry::OctreeTileID& subtreeId,
249249
const CesiumGeometry::OctreeTileID& tileId,
250-
uint64_t contentId) const noexcept;
250+
size_t contentId) const noexcept;
251251

252252
/**
253253
* @brief Determines if content for a given tile in the subtree is available.
@@ -262,7 +262,7 @@ class SubtreeAvailability {
262262
bool isContentAvailable(
263263
uint32_t relativeTileLevel,
264264
uint64_t relativeTileMortonId,
265-
uint64_t contentId) const noexcept;
265+
size_t contentId) const noexcept;
266266

267267
/**
268268
* @brief Sets the availability state of the content for a given tile in the
@@ -276,7 +276,7 @@ class SubtreeAvailability {
276276
void setContentAvailable(
277277
const CesiumGeometry::QuadtreeTileID& subtreeId,
278278
const CesiumGeometry::QuadtreeTileID& tileId,
279-
uint64_t contentId,
279+
size_t contentId,
280280
bool isAvailable) noexcept;
281281

282282
/**
@@ -291,7 +291,7 @@ class SubtreeAvailability {
291291
void setContentAvailable(
292292
const CesiumGeometry::OctreeTileID& subtreeId,
293293
const CesiumGeometry::OctreeTileID& tileId,
294-
uint64_t contentId,
294+
size_t contentId,
295295
bool isAvailable) noexcept;
296296

297297
/**
@@ -309,7 +309,7 @@ class SubtreeAvailability {
309309
void setContentAvailable(
310310
uint32_t relativeTileLevel,
311311
uint64_t relativeTileMortonId,
312-
uint64_t contentId,
312+
size_t contentId,
313313
bool isAvailable) noexcept;
314314

315315
/**

Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,10 @@ void copyStringsToBuffers(
10141014
for (const auto& str : arrayMember.GetArray()) {
10151015
OffsetType byteLength = static_cast<OffsetType>(
10161016
str.GetStringLength() * sizeof(rapidjson::Value::Ch));
1017-
std::memcpy(valueBuffer.data() + offset, str.GetString(), byteLength);
1017+
std::memcpy(
1018+
valueBuffer.data() + offset,
1019+
str.GetString(),
1020+
size_t(byteLength));
10181021
std::memcpy(
10191022
offsetBuffer.data() + offsetIndex * sizeof(OffsetType),
10201023
&offset,
@@ -1075,8 +1078,7 @@ void updateStringArrayProperty(
10751078
++it;
10761079
}
10771080

1078-
const uint64_t totalByteLength =
1079-
totalCharCount * sizeof(rapidjson::Value::Ch);
1081+
const size_t totalByteLength = totalCharCount * sizeof(rapidjson::Value::Ch);
10801082
std::vector<std::byte> valueBuffer;
10811083
std::vector<std::byte> stringOffsetBuffer;
10821084
PropertyComponentType stringOffsetType = PropertyComponentType::None;

Cesium3DTilesContent/src/PntsToGltfConverter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ void decodeDracoMetadata(
823823
const std::unique_ptr<draco::PointCloud>& pPointCloud,
824824
rapidjson::Document& batchTableJson,
825825
PntsContent& parsedContent) {
826-
const uint64_t pointsLength = parsedContent.pointsLength;
826+
const size_t pointsLength = parsedContent.pointsLength;
827827
std::vector<std::byte>& data = parsedContent.dracoBatchTableBinary;
828828

829829
const auto& dracoMetadataSemantics = parsedContent.dracoMetadataSemantics;

0 commit comments

Comments
 (0)