Skip to content

Commit 5e5c5e4

Browse files
authored
Merge branch 'main' into geospatial-guide-tag
2 parents 46cb506 + 0f9ecc1 commit 5e5c5e4

File tree

138 files changed

+4018
-2327
lines changed

Some content is hidden

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

138 files changed

+4018
-2327
lines changed

.clang-tidy

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ Checks:
124124
- "modernize-use-equals-delete"
125125
- "modernize-use-nullptr"
126126
- "modernize-use-starts-ends-with"
127-
- "modernize-use-std-numbers"
127+
# The <numbers> header is unfortunately not available in Android NDK r25b,
128+
# which is an important target for cesium-native via Unreal Engine.
129+
#- "modernize-use-std-numbers"
128130
#- "modernize-use-using"
129131
- "performance-*"
130132
- "-performance-enum-size"

CHANGES.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@
22

33
### v0.44.0 - 2025-02-03
44

5-
##### Fixes :wrench:
5+
##### Breaking Changes :mega:
66

7-
- Fixed a crash in `GltfWriter` that would happen when the `EXT_structural_metadata` `schema` property was null.
7+
- cesium-native no longer uses the `GLM_FORCE_SIZE_T_LENGTH` option with the `glm` library
88

99
##### Additions :tada:
1010

11+
- Added conversion of I3dm batch table metadata to `EXT_structural_metadata` and `EXT_instance_features` extensions.
12+
- Added `CesiumIonClient::Connection::geocode` method for making geocoding queries against the Cesium ion geocoder API.
13+
- Added `UrlTemplateRasterOverlay` for requesting raster tiles from services using a templated URL.
1114
- `upsampleGltfForRasterOverlays` is now compatible with meshes using TRIANGLE_STRIP, TRIANGLE_FAN, or non-indexed TRIANGLES primitives.
1215

16+
##### Fixes :wrench:
17+
18+
- Fixed a crash in `GltfWriter` that would happen when the `EXT_structural_metadata` `schema` property was null.
19+
1320
### v0.43.0 - 2025-01-02
1421

1522
##### Breaking Changes :mega:

CMakeGraphVizOptions.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ set(GRAPHVIZ_GENERATE_PER_TARGET FALSE)
22
set(GRAPHVIZ_GENERATE_DEPENDERS FALSE)
33
set(GRAPHVIZ_OBJECT_LIBS FALSE)
44
list(APPEND GRAPHVIZ_IGNORE_TARGETS cesium-native-tests)
5-
list(APPEND GRAPHVIZ_IGNORE_TARGETS "Catch2::*")
5+
list(APPEND GRAPHVIZ_IGNORE_TARGETS "doctest::*")
66
list(APPEND GRAPHVIZ_IGNORE_TARGETS "lib*.lib")
77
list(APPEND GRAPHVIZ_IGNORE_TARGETS "lib*.so")

CMakeLists.txt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ set(PACKAGES_PRIVATE
5656
)
5757

5858
# Packages only used for testing
59-
set(PACKAGES_TEST catch2)
59+
set(PACKAGES_TEST doctest)
6060

6161
if(NOT VCPKG_MANIFEST_MODE)
6262
set(PACKAGES_ALL ${PACKAGES_PUBLIC})
@@ -116,13 +116,7 @@ cmake_dependent_option(
116116
OFF
117117
)
118118

119-
cmake_dependent_option(
120-
CESIUM_CLANG_TIDY_USE_THREADS
121-
"Sets the number of threads for run-clang-tidy to use."
122-
14
123-
CESIUM_ENABLE_CLANG_TIDY
124-
1
125-
)
119+
set(CESIUM_CLANG_TIDY_USE_THREADS 14 CACHE STRING "Sets the number of threads for run-clang-tidy to use.")
126120

127121
if(CESIUM_INSTALL_STATIC_LIBS OR CESIUM_INSTALL_HEADERS)
128122
foreach(PACKAGE ${PACKAGES_PUBLIC})
@@ -247,7 +241,7 @@ list(APPEND CMAKE_PREFIX_PATH "${PACKAGE_BUILD_DIR}")
247241
# and imporeted library target ourselves. This is the case for modp_b64::modp_b64, picosha2::picosha2 and earcut. In
248242
# these cases, we *do* have the somewhat ugly and verbose details in the extern/CMakeLists.txt file.
249243
find_package(Async++ CONFIG REQUIRED)
250-
find_package(Catch2 CONFIG REQUIRED)
244+
find_package(doctest CONFIG REQUIRED)
251245
find_package(draco CONFIG REQUIRED)
252246
find_package(expected-lite CONFIG REQUIRED)
253247
find_package(glm CONFIG REQUIRED)

Cesium3DTiles/test/TestMetadataQuery.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
#include <Cesium3DTiles/Schema.h>
66
#include <CesiumUtility/JsonValue.h>
77

8-
#include <catch2/catch_test_macros.hpp>
8+
#include <doctest/doctest.h>
99

1010
#include <optional>
1111

1212
using namespace Cesium3DTiles;
1313
using namespace CesiumUtility;
1414

1515
TEST_CASE("MetadataQuery") {
16-
SECTION("findFirstPropertyWithSemantic") {
16+
SUBCASE("findFirstPropertyWithSemantic") {
1717
Schema schema{};
1818
Class& classDefinition =
1919
schema.classes.emplace("someClass", Class()).first->second;

Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.cpp

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
#include "BatchTableToGltfStructuralMetadata.h"
22

33
#include "BatchTableHierarchyPropertyValues.h"
4+
#include "MetadataProperty.h"
45

6+
#include <Cesium3DTilesContent/GltfConverterUtility.h>
7+
#include <CesiumGltf/Accessor.h>
58
#include <CesiumGltf/Buffer.h>
69
#include <CesiumGltf/BufferView.h>
710
#include <CesiumGltf/Class.h>
811
#include <CesiumGltf/ClassProperty.h>
12+
#include <CesiumGltf/ExtensionExtInstanceFeatures.h>
913
#include <CesiumGltf/ExtensionExtMeshFeatures.h>
14+
#include <CesiumGltf/ExtensionExtMeshGpuInstancing.h>
1015
#include <CesiumGltf/ExtensionKhrDracoMeshCompression.h>
1116
#include <CesiumGltf/ExtensionModelExtStructuralMetadata.h>
1217
#include <CesiumGltf/FeatureId.h>
1318
#include <CesiumGltf/Mesh.h>
1419
#include <CesiumGltf/MeshPrimitive.h>
1520
#include <CesiumGltf/Model.h>
21+
#include <CesiumGltf/Node.h>
1622
#include <CesiumGltf/PropertyTable.h>
1723
#include <CesiumGltf/PropertyTableProperty.h>
1824
#include <CesiumGltf/PropertyType.h>
@@ -29,6 +35,7 @@
2935
#include <rapidjson/stringbuffer.h>
3036
#include <rapidjson/writer.h>
3137

38+
#include <algorithm>
3239
#include <cstddef>
3340
#include <cstdint>
3441
#include <cstring>
@@ -2008,4 +2015,215 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromPnts(
20082015

20092016
return result;
20102017
}
2018+
2019+
namespace {
2020+
2021+
// Does something like this already exist?
2022+
2023+
template <typename T> int32_t componentTypeFromCpp();
2024+
2025+
template <> int32_t componentTypeFromCpp<uint8_t>() {
2026+
return Accessor::ComponentType::UNSIGNED_BYTE;
2027+
}
2028+
2029+
template <> int32_t componentTypeFromCpp<uint16_t>() {
2030+
return Accessor::ComponentType::UNSIGNED_SHORT;
2031+
}
2032+
2033+
template <> int32_t componentTypeFromCpp<uint32_t>() {
2034+
return Accessor::ComponentType::UNSIGNED_INT;
2035+
}
2036+
2037+
// encapsulation of the binary batch id data in an I3dm
2038+
struct BatchIdSemantic {
2039+
std::variant<
2040+
std::span<const uint8_t>,
2041+
std::span<const uint16_t>,
2042+
std::span<const uint32_t>>
2043+
batchSpan;
2044+
const std::byte* rawData;
2045+
uint32_t numElements;
2046+
uint32_t byteSize;
2047+
2048+
template <typename UintType>
2049+
static std::span<const UintType>
2050+
makeSpan(const std::byte* byteData, uint32_t offset, uint32_t numElements) {
2051+
return std::span<const UintType>(
2052+
reinterpret_cast<const UintType*>(byteData + offset),
2053+
numElements);
2054+
}
2055+
2056+
BatchIdSemantic(
2057+
const rapidjson::Document& featureTableJson,
2058+
uint32_t numInstances,
2059+
const std::span<const std::byte>& featureTableJsonData)
2060+
: rawData(nullptr), numElements(0), byteSize(0) {
2061+
const auto batchIdIt = featureTableJson.FindMember("BATCH_ID");
2062+
if (batchIdIt == featureTableJson.MemberEnd() ||
2063+
!batchIdIt->value.IsObject()) {
2064+
return;
2065+
}
2066+
const auto byteOffsetIt = batchIdIt->value.FindMember("byteOffset");
2067+
if (byteOffsetIt == batchIdIt->value.MemberEnd() ||
2068+
!byteOffsetIt->value.IsUint()) {
2069+
// Warning
2070+
}
2071+
uint32_t byteOffset = byteOffsetIt->value.GetUint();
2072+
const auto componentTypeIt = batchIdIt->value.FindMember("componentType");
2073+
if (componentTypeIt != featureTableJson.MemberEnd() &&
2074+
componentTypeIt->value.IsString()) {
2075+
const std::string& componentTypeString =
2076+
componentTypeIt->value.GetString();
2077+
if (MetadataProperty::stringToMetadataComponentType.find(
2078+
componentTypeString) ==
2079+
MetadataProperty::stringToMetadataComponentType.end()) {
2080+
// Warning
2081+
}
2082+
MetadataProperty::ComponentType componentType =
2083+
MetadataProperty::stringToMetadataComponentType.at(
2084+
componentTypeString);
2085+
rawData = featureTableJsonData.data();
2086+
if (componentType == MetadataProperty::ComponentType::UNSIGNED_BYTE) {
2087+
batchSpan = makeSpan<uint8_t>(rawData, byteOffset, numInstances);
2088+
numElements = numInstances;
2089+
byteSize = numElements * sizeof(uint8_t);
2090+
} else if (
2091+
componentType == MetadataProperty::ComponentType::UNSIGNED_SHORT) {
2092+
batchSpan = makeSpan<uint8_t>(rawData, byteOffset, numInstances);
2093+
numElements = numInstances;
2094+
byteSize = numElements * sizeof(uint16_t);
2095+
} else if (
2096+
componentType == MetadataProperty::ComponentType::UNSIGNED_INT) {
2097+
batchSpan = makeSpan<uint32_t>(rawData, byteOffset, numInstances);
2098+
numElements = numInstances;
2099+
byteSize = numElements * sizeof(uint32_t);
2100+
}
2101+
}
2102+
}
2103+
2104+
size_t idSize() const {
2105+
return std::visit(
2106+
[](auto&& batchIds) { return sizeof(batchIds[0]); },
2107+
batchSpan);
2108+
}
2109+
2110+
uint32_t maxBatchId() const {
2111+
return std::visit(
2112+
[](auto&& batchIds) {
2113+
auto itr = std::max_element(batchIds.begin(), batchIds.end());
2114+
return static_cast<uint32_t>(*itr);
2115+
},
2116+
batchSpan);
2117+
}
2118+
2119+
int32_t componentType() const {
2120+
return std::visit(
2121+
[](auto&& batchIds) {
2122+
using span_type = std::remove_reference_t<decltype(batchIds)>;
2123+
return componentTypeFromCpp<typename span_type::value_type>();
2124+
},
2125+
batchSpan);
2126+
}
2127+
};
2128+
2129+
// returns an accessor ID for the added feature IDs
2130+
int32_t
2131+
addFeatureIdsToGltf(CesiumGltf::Model& gltf, const BatchIdSemantic& batchIds) {
2132+
int32_t featuresBufferId = GltfConverterUtility::createBufferInGltf(gltf);
2133+
auto& featuresBuffer = gltf.buffers[static_cast<uint32_t>(featuresBufferId)];
2134+
featuresBuffer.cesium.data.resize(batchIds.byteSize);
2135+
std::memcpy(
2136+
&featuresBuffer.cesium.data[0],
2137+
batchIds.rawData,
2138+
batchIds.byteSize);
2139+
int32_t featuresBufferViewId = GltfConverterUtility::createBufferViewInGltf(
2140+
gltf,
2141+
featuresBufferId,
2142+
0,
2143+
static_cast<int64_t>(batchIds.idSize()));
2144+
gltf.bufferViews[static_cast<uint32_t>(featuresBufferViewId)].byteLength =
2145+
batchIds.byteSize;
2146+
2147+
int32_t accessorId = GltfConverterUtility::createAccessorInGltf(
2148+
gltf,
2149+
featuresBufferViewId,
2150+
batchIds.componentType(),
2151+
batchIds.numElements,
2152+
Accessor::Type::SCALAR);
2153+
return accessorId;
2154+
}
2155+
2156+
} // namespace
2157+
2158+
ErrorList BatchTableToGltfStructuralMetadata::convertFromI3dm(
2159+
const rapidjson::Document& featureTableJson,
2160+
const rapidjson::Document& batchTableJson,
2161+
const std::span<const std::byte>& featureTableJsonData,
2162+
const std::span<const std::byte>& batchTableBinaryData,
2163+
CesiumGltf::Model& gltf) {
2164+
// Check to make sure a char of rapidjson is 1 byte
2165+
static_assert(
2166+
sizeof(rapidjson::Value::Ch) == 1,
2167+
"RapidJson::Value::Ch is not 1 byte");
2168+
2169+
ErrorList result;
2170+
2171+
// Parse the batch table and convert it to the EXT_structural_metadata
2172+
// extension.
2173+
2174+
// Batch table length is either the max batch ID + 1 or, if there are no batch
2175+
// IDs, the number of instances.
2176+
int64_t featureCount = 0;
2177+
std::optional<BatchIdSemantic> optBatchIds;
2178+
const auto batchIdIt = featureTableJson.FindMember("BATCH_ID");
2179+
std::optional<uint32_t> optInstancesLength =
2180+
GltfConverterUtility::getValue<uint32_t>(
2181+
featureTableJson,
2182+
"INSTANCES_LENGTH");
2183+
if (!optInstancesLength) {
2184+
result.emplaceError("Required INSTANCES_LENGTH semantic is missing");
2185+
return result;
2186+
}
2187+
if (batchIdIt == featureTableJson.MemberEnd()) {
2188+
featureCount = *optInstancesLength;
2189+
} else {
2190+
optBatchIds = BatchIdSemantic(
2191+
featureTableJson,
2192+
*optInstancesLength,
2193+
featureTableJsonData);
2194+
uint32_t maxBatchId = optBatchIds->maxBatchId();
2195+
featureCount = maxBatchId + 1;
2196+
}
2197+
2198+
convertBatchTableToGltfStructuralMetadataExtension(
2199+
batchTableJson,
2200+
batchTableBinaryData,
2201+
gltf,
2202+
featureCount,
2203+
result);
2204+
2205+
int32_t featureIdAccessor = -1;
2206+
if (optBatchIds.has_value()) {
2207+
featureIdAccessor = addFeatureIdsToGltf(gltf, *optBatchIds);
2208+
}
2209+
2210+
// Create an EXT_instance_features extension for node that has an
2211+
// EXT_mesh_gpu_instancing extension
2212+
for (Node& node : gltf.nodes) {
2213+
if (auto* pGpuInstancing =
2214+
node.getExtension<ExtensionExtMeshGpuInstancing>()) {
2215+
auto& instanceFeatureExt =
2216+
node.addExtension<ExtensionExtInstanceFeatures>();
2217+
gltf.addExtensionUsed(ExtensionExtInstanceFeatures::ExtensionName);
2218+
instanceFeatureExt.featureIds.resize(1);
2219+
instanceFeatureExt.featureIds[0].featureCount = featureCount;
2220+
instanceFeatureExt.featureIds[0].propertyTable = 0;
2221+
if (featureIdAccessor >= 0) {
2222+
pGpuInstancing->attributes["_FEATURE_ID_0"] = featureIdAccessor;
2223+
instanceFeatureExt.featureIds[0].attribute = 0;
2224+
}
2225+
}
2226+
}
2227+
return result;
2228+
}
20112229
} // namespace Cesium3DTilesContent

Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,12 @@ struct BatchTableToGltfStructuralMetadata {
2121
const rapidjson::Document& batchTableJson,
2222
const std::span<const std::byte>& batchTableBinaryData,
2323
CesiumGltf::Model& gltf);
24+
25+
static CesiumUtility::ErrorList convertFromI3dm(
26+
const rapidjson::Document& featureTableJson,
27+
const rapidjson::Document& batchTableJson,
28+
const std::span<const std::byte>& featureTableJsonData,
29+
const std::span<const std::byte>& batchTableBinaryData,
30+
CesiumGltf::Model& gltf);
2431
};
2532
} // namespace Cesium3DTilesContent

0 commit comments

Comments
 (0)