react-native-cesium 1.0.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -11
- package/ReactNativeCesium.podspec +1 -1
- package/android/CMakeLists.txt +5 -3
- package/android/src/main/cpp/CesiumBridgeAndroid.cpp +197 -227
- package/android/src/main/cpp/CesiumBridgeAndroid.h +48 -49
- package/android/src/main/cpp/cpp-adapter.cpp +2 -2
- package/android/src/main/cpp/vulkan/VulkanBackend.cpp +1010 -569
- package/android/src/main/cpp/vulkan/VulkanBackend.h +121 -12
- package/android/src/main/cpp/vulkan/shaders/sky.frag +20 -10
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +28 -0
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +295 -58
- package/cpp/engine/CameraSmoother.cpp +99 -0
- package/cpp/engine/CameraSmoother.hpp +29 -0
- package/cpp/engine/CameraTargetState.cpp +49 -0
- package/cpp/engine/CameraTargetState.hpp +121 -0
- package/cpp/engine/CesiumEngine.cpp +206 -60
- package/cpp/engine/CesiumEngine.hpp +77 -10
- package/cpp/engine/EngineTunables.hpp +79 -0
- package/cpp/engine/GeoidConverter.cpp +36 -0
- package/cpp/engine/GeoidConverter.hpp +10 -0
- package/cpp/engine/GlobeCamera.cpp +7 -2
- package/cpp/engine/MetricsAggregator.cpp +71 -0
- package/cpp/engine/MetricsAggregator.hpp +54 -0
- package/cpp/engine/TileLifecycleManager.cpp +0 -12
- package/cpp/engine/TileLifecycleManager.hpp +0 -3
- package/cpp/third_party/egm96/EGM96.c +289 -0
- package/cpp/third_party/egm96/EGM96.h +45 -0
- package/cpp/third_party/egm96/EGM96_data.h +65372 -0
- package/ios/CesiumBridge.h +24 -5
- package/ios/CesiumBridge.mm +149 -271
- package/ios/HybridCesiumView.swift +197 -40
- package/ios/metal/MetalBackend.mm +72 -23
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts +26 -0
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JCesiumMetrics.hpp +5 -1
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.cpp +109 -1
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.hpp +24 -0
- package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.cpp +48 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CameraState.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CesiumMetrics.kt +32 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/HybridCesiumViewSpec.kt +72 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/Quaternion.kt +19 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.hpp +30 -0
- package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.hpp +85 -1
- package/nitrogen/generated/ios/c++/views/HybridCesiumViewComponent.mm +60 -0
- package/nitrogen/generated/ios/swift/CesiumMetrics.swift +7 -2
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec.swift +12 -0
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec_cxx.swift +288 -0
- package/nitrogen/generated/shared/c++/CesiumMetrics.hpp +5 -1
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.hpp +25 -1
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.cpp +132 -0
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.hpp +13 -1
- package/nitrogen/generated/shared/json/CesiumViewConfig.json +12 -0
- package/package.json +4 -4
- package/scripts/cesium/clone.mjs +1 -1
- package/src/specs/cesium-view.nitro.ts +29 -0
- package/cpp/engine/DeletionQueue.cpp +0 -28
- package/cpp/engine/DeletionQueue.hpp +0 -28
package/ios/CesiumBridge.h
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
NS_ASSUME_NONNULL_BEGIN
|
|
5
5
|
|
|
6
|
+
// Thin Obj-C++ shell for the iOS side. All cross-platform logic (camera
|
|
7
|
+
// demand state + smoothing, FPS / metrics aggregation, credit-HTML stripping)
|
|
8
|
+
// lives in shared C++ next to CesiumEngine.
|
|
6
9
|
@interface CesiumBridge : NSObject
|
|
7
10
|
|
|
8
11
|
- (instancetype)initWithMetalLayer:(CAMetalLayer *)layer
|
|
@@ -18,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
18
21
|
heading:(double)heading
|
|
19
22
|
pitch:(double)pitch
|
|
20
23
|
roll:(double)roll;
|
|
21
|
-
/// Same as `updateCameraLatitude:...` plus camera-space view correction (w,x,y,z)
|
|
24
|
+
/// Same as `updateCameraLatitude:...` plus a camera-space view correction (w,x,y,z) applied after HPR.
|
|
22
25
|
- (void)updateCameraQuaternionLatitude:(double)lat
|
|
23
26
|
longitude:(double)lon
|
|
24
27
|
altitude:(double)alt
|
|
@@ -38,13 +41,27 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
38
41
|
// Camera / globe
|
|
39
42
|
- (void)setVerticalFovDeg:(double)degrees;
|
|
40
43
|
|
|
41
|
-
// Tileset tuning (
|
|
44
|
+
// Tileset tuning (runtime-mutable; no full rebuild)
|
|
42
45
|
- (void)setMaximumScreenSpaceError:(double)v;
|
|
43
|
-
- (void)setMaximumSimultaneousTileLoads:(
|
|
44
|
-
- (void)setLoadingDescendantLimit:(
|
|
46
|
+
- (void)setMaximumSimultaneousTileLoads:(int32_t)v;
|
|
47
|
+
- (void)setLoadingDescendantLimit:(int32_t)v;
|
|
45
48
|
|
|
46
49
|
- (void)setMsaaSampleCount:(int)samples;
|
|
47
50
|
|
|
51
|
+
// Optional perf / quality knobs (defaults match EngineConfig).
|
|
52
|
+
- (void)setMaximumCachedMiB:(int32_t)v;
|
|
53
|
+
- (void)setPreloadAncestors:(BOOL)v;
|
|
54
|
+
- (void)setPreloadSiblings:(BOOL)v;
|
|
55
|
+
- (void)setForbidHoles:(BOOL)v;
|
|
56
|
+
- (void)setEnableWaterMask:(BOOL)v;
|
|
57
|
+
- (void)setEnableFogCulling:(BOOL)v;
|
|
58
|
+
- (void)setEnforceCulledScreenSpaceError:(BOOL)v;
|
|
59
|
+
- (void)setCulledScreenSpaceError:(double)v;
|
|
60
|
+
- (void)setEnableLodTransitionPeriod:(BOOL)v;
|
|
61
|
+
- (void)setLodTransitionLength:(double)v;
|
|
62
|
+
- (void)setSqliteCacheMaxRows:(int32_t)v;
|
|
63
|
+
- (void)setTaskProcessorThreads:(int32_t)v;
|
|
64
|
+
|
|
48
65
|
/// Throttled metrics consumed by the Swift hybrid view.
|
|
49
66
|
@property (nonatomic, readonly) double metricsFps;
|
|
50
67
|
@property (nonatomic, readonly) NSInteger metricsTilesRendered;
|
|
@@ -52,7 +69,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
52
69
|
@property (nonatomic, readonly) NSInteger metricsTilesVisited;
|
|
53
70
|
@property (nonatomic, readonly) BOOL metricsIonTokenConfigured;
|
|
54
71
|
@property (nonatomic, readonly) BOOL metricsTilesetReady;
|
|
55
|
-
@property (nonatomic, readonly)
|
|
72
|
+
@property (nonatomic, readonly) BOOL metricsTlsConfigured;
|
|
73
|
+
@property (nonatomic, readonly, copy) NSString *metricsCreditsPlainText;
|
|
74
|
+
|
|
56
75
|
- (double)readCameraLatitude;
|
|
57
76
|
- (double)readCameraLongitude;
|
|
58
77
|
- (double)readCameraAltitude;
|
package/ios/CesiumBridge.mm
CHANGED
|
@@ -1,117 +1,36 @@
|
|
|
1
1
|
#import "CesiumBridge.h"
|
|
2
2
|
#import <CoreFoundation/CoreFoundation.h>
|
|
3
3
|
|
|
4
|
+
#include "engine/CameraSmoother.hpp"
|
|
5
|
+
#include "engine/CameraTargetState.hpp"
|
|
4
6
|
#include "engine/CesiumEngine.hpp"
|
|
7
|
+
#include "engine/EngineTunables.hpp"
|
|
8
|
+
#include "engine/MetricsAggregator.hpp"
|
|
5
9
|
#include "metal/MetalBackend.h"
|
|
6
10
|
|
|
7
11
|
#include <glm/gtc/quaternion.hpp>
|
|
8
12
|
|
|
13
|
+
#include <algorithm>
|
|
9
14
|
#include <atomic>
|
|
10
15
|
#include <cmath>
|
|
11
16
|
#include <memory>
|
|
12
17
|
#include <string>
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (html.length == 0) return @"";
|
|
19
|
-
NSError* err = nil;
|
|
20
|
-
NSRegularExpression* tagRx =
|
|
21
|
-
[NSRegularExpression regularExpressionWithPattern:@"<[^>]+>" options:0 error:&err];
|
|
22
|
-
NSString* plain = [tagRx stringByReplacingMatchesInString:html
|
|
23
|
-
options:0
|
|
24
|
-
range:NSMakeRange(0, html.length)
|
|
25
|
-
withTemplate:@" "];
|
|
26
|
-
NSRegularExpression* wsRx =
|
|
27
|
-
[NSRegularExpression regularExpressionWithPattern:@"\\s+" options:0 error:&err];
|
|
28
|
-
plain = [wsRx stringByReplacingMatchesInString:plain
|
|
29
|
-
options:0
|
|
30
|
-
range:NSMakeRange(0, plain.length)
|
|
31
|
-
withTemplate:@" "];
|
|
32
|
-
return [plain stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
double lerpAngleDeg(double a, double b, double t) {
|
|
36
|
-
double diff = std::fmod(b - a + 540.0, 360.0) - 180.0;
|
|
37
|
-
return a + diff * t;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
double angleDeltaAbsDeg(double a, double b) {
|
|
41
|
-
return std::abs(std::fmod(b - a + 540.0, 360.0) - 180.0);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
} // namespace
|
|
45
|
-
|
|
46
|
-
// ── Per-DOF smoothing. ────────────────────────────────────────────────────────
|
|
47
|
-
static const double kSmoothAlt = 25.0;
|
|
48
|
-
static const double kSmoothHdg = 30.0;
|
|
49
|
-
static const double kSmoothRoll = 50.0;
|
|
50
|
-
static const double kSmoothPitch = 50.0;
|
|
51
|
-
static const double kSmoothViewCorr = 50.0;
|
|
52
|
-
static const double kEpsLatLon = 1e-7;
|
|
53
|
-
static const double kEpsAlt = 0.1;
|
|
54
|
-
static const double kEpsAngleDeg = 0.05;
|
|
55
|
-
static const double kEpsQuatDot = 1e-8;
|
|
19
|
+
@implementation CesiumBridge {
|
|
20
|
+
std::unique_ptr<reactnativecesium::MetalBackend> _metalBackend;
|
|
21
|
+
std::unique_ptr<reactnativecesium::CesiumEngine> _engine;
|
|
22
|
+
reactnativecesium::FrameResult _frameResult;
|
|
56
23
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
24
|
+
reactnativecesium::EngineConfig _config;
|
|
25
|
+
reactnativecesium::CameraTargetState _target;
|
|
26
|
+
reactnativecesium::MetricsAggregator _metrics;
|
|
60
27
|
|
|
61
|
-
@implementation CesiumBridge {
|
|
62
|
-
std::unique_ptr<reactnativecesium::MetalBackend> _metalBackend;
|
|
63
|
-
std::unique_ptr<reactnativecesium::CesiumEngine> _engine;
|
|
64
|
-
reactnativecesium::FrameResult _frameResult;
|
|
65
28
|
int _viewportWidth;
|
|
66
29
|
int _viewportHeight;
|
|
67
30
|
BOOL _initialized;
|
|
31
|
+
BOOL _suspended;
|
|
68
32
|
|
|
69
33
|
NSString* _cacheDir;
|
|
70
|
-
NSString* _ionAccessToken;
|
|
71
|
-
int64_t _ionTilesetAssetId;
|
|
72
|
-
|
|
73
|
-
double _maxSSE;
|
|
74
|
-
double _maxSimLoads;
|
|
75
|
-
double _loadDescLim;
|
|
76
|
-
|
|
77
|
-
// Demand target — incoming props/calls write here; render loop smooths toward it.
|
|
78
|
-
reactnativecesium::CameraParams _camTarget;
|
|
79
|
-
BOOL _forceRenderNextFrame;
|
|
80
|
-
|
|
81
|
-
BOOL _suspended;
|
|
82
|
-
|
|
83
|
-
double _fpsEma;
|
|
84
|
-
int _metricsTick;
|
|
85
|
-
|
|
86
|
-
double _metricsFps;
|
|
87
|
-
NSInteger _metricsTilesRendered;
|
|
88
|
-
NSInteger _metricsTilesLoading;
|
|
89
|
-
NSInteger _metricsTilesVisited;
|
|
90
|
-
BOOL _metricsIonTokenConfigured;
|
|
91
|
-
BOOL _metricsTilesetReady;
|
|
92
|
-
NSString* _metricsCreditsPlainText;
|
|
93
|
-
|
|
94
|
-
NSString* _lastCreditHtmlJoined;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
- (reactnativecesium::EngineConfig)makeEngineConfig {
|
|
98
|
-
reactnativecesium::EngineConfig config;
|
|
99
|
-
if (_ionAccessToken) {
|
|
100
|
-
config.ionAccessToken = std::string([_ionAccessToken UTF8String]);
|
|
101
|
-
}
|
|
102
|
-
config.ionAssetId = _ionTilesetAssetId;
|
|
103
|
-
config.cacheDatabasePath =
|
|
104
|
-
_cacheDir ? std::string([_cacheDir UTF8String]) + "/cesium_cache.db" : "";
|
|
105
|
-
NSString* caPem = [[NSBundle mainBundle] pathForResource:@"cacert" ofType:@"pem"];
|
|
106
|
-
if (caPem.length > 0) {
|
|
107
|
-
config.tlsCaBundlePath = std::string([caPem fileSystemRepresentation]);
|
|
108
|
-
}
|
|
109
|
-
config.maximumScreenSpaceError = std::max(1.0, _maxSSE);
|
|
110
|
-
config.maximumSimultaneousTileLoads =
|
|
111
|
-
static_cast<int32_t>(std::max(0.0, std::round(_maxSimLoads)));
|
|
112
|
-
config.loadingDescendantLimit =
|
|
113
|
-
static_cast<int32_t>(std::max(1.0, std::round(_loadDescLim)));
|
|
114
|
-
return config;
|
|
115
34
|
}
|
|
116
35
|
|
|
117
36
|
- (instancetype)initWithMetalLayer:(CAMetalLayer *)layer
|
|
@@ -123,24 +42,22 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
123
42
|
_viewportWidth = width;
|
|
124
43
|
_viewportHeight = height;
|
|
125
44
|
_initialized = NO;
|
|
126
|
-
_cacheDir = [cacheDir copy];
|
|
127
|
-
_ionAccessToken = nil;
|
|
128
|
-
_ionTilesetAssetId = 1;
|
|
129
|
-
_maxSSE = 32.0;
|
|
130
|
-
_maxSimLoads = 12.0;
|
|
131
|
-
_loadDescLim = 20.0;
|
|
132
|
-
_forceRenderNextFrame = YES;
|
|
133
45
|
_suspended = NO;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
46
|
+
_cacheDir = [cacheDir copy];
|
|
47
|
+
|
|
48
|
+
_config.cacheDatabasePath =
|
|
49
|
+
cacheDir ? std::string([cacheDir UTF8String]) + "/cesium_cache.db" : "";
|
|
50
|
+
|
|
51
|
+
NSString* caPem = [[NSBundle mainBundle] pathForResource:@"cacert" ofType:@"pem"];
|
|
52
|
+
if (caPem.length > 0) {
|
|
53
|
+
_config.tlsCaBundlePath = std::string([caPem fileSystemRepresentation]);
|
|
54
|
+
}
|
|
55
|
+
static std::atomic<int> caWarned{0};
|
|
56
|
+
if (_config.tlsCaBundlePath.empty() && caWarned.fetch_add(1) == 0) {
|
|
57
|
+
NSLog(@"[ReactNativeCesium] cacert.pem not in main bundle — libcurl may "
|
|
58
|
+
@"fail TLS to api.cesium.com on device. Ensure the pod includes "
|
|
59
|
+
@"ios/cacert.pem (run pod install).");
|
|
60
|
+
}
|
|
144
61
|
|
|
145
62
|
_metalBackend = std::make_unique<reactnativecesium::MetalBackend>();
|
|
146
63
|
_metalBackend->initialize((__bridge void*)layer, width, height);
|
|
@@ -161,22 +78,17 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
161
78
|
- (void)appWillResignActive:(NSNotification *)note { _suspended = YES; }
|
|
162
79
|
- (void)appDidBecomeActive:(NSNotification *)note {
|
|
163
80
|
_suspended = NO;
|
|
164
|
-
|
|
81
|
+
_target.requestForceRender();
|
|
165
82
|
}
|
|
166
83
|
|
|
167
84
|
- (void)buildEngine {
|
|
168
|
-
reactnativecesium::EngineConfig cfg = [self makeEngineConfig];
|
|
169
|
-
static std::atomic<int> caWarned{0};
|
|
170
|
-
if (cfg.tlsCaBundlePath.empty() && caWarned.fetch_add(1) == 0) {
|
|
171
|
-
NSLog(@"[ReactNativeCesium] cacert.pem not in main bundle — libcurl may fail TLS to "
|
|
172
|
-
@"api.cesium.com on device. Ensure the pod includes ios/cacert.pem (run pod install).");
|
|
173
|
-
}
|
|
174
85
|
_engine.reset();
|
|
175
86
|
_engine = std::make_unique<reactnativecesium::CesiumEngine>();
|
|
176
|
-
_engine->initialize(
|
|
87
|
+
_engine->initialize(_config);
|
|
177
88
|
|
|
178
|
-
//
|
|
179
|
-
|
|
89
|
+
// Seed the demand target from the engine's initial camera so the first
|
|
90
|
+
// frame is not a "snap from default" jump.
|
|
91
|
+
_target.setAll(_engine->camera().getParams());
|
|
180
92
|
|
|
181
93
|
auto* backendPtr = _metalBackend.get();
|
|
182
94
|
_engine->getResourcePreparer()->setGPUTextureCreator(
|
|
@@ -187,9 +99,8 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
187
99
|
[](void* tex) {
|
|
188
100
|
if (tex) CFRelease(tex);
|
|
189
101
|
});
|
|
190
|
-
// Water mask textures
|
|
191
|
-
//
|
|
192
|
-
// time so no separate factory is needed.
|
|
102
|
+
// Water mask textures reuse the same MTLTexture creator; the binding slot is
|
|
103
|
+
// set at draw time on Metal so no separate factory is needed.
|
|
193
104
|
_engine->getResourcePreparer()->setWaterMaskTextureCreator(
|
|
194
105
|
[backendPtr](const uint8_t* pixels, int32_t w, int32_t h) -> void* {
|
|
195
106
|
return backendPtr->createRasterTexture(pixels, w, h);
|
|
@@ -200,18 +111,24 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
200
111
|
});
|
|
201
112
|
}
|
|
202
113
|
|
|
114
|
+
- (void)applyEngineConfig {
|
|
115
|
+
if (!_engine) return;
|
|
116
|
+
_engine->updateConfig(_config);
|
|
117
|
+
_target.requestForceRender();
|
|
118
|
+
}
|
|
119
|
+
|
|
203
120
|
- (void)updateIonAccessToken:(NSString *)token assetId:(int64_t)assetId {
|
|
204
121
|
if (!_initialized) return;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
_forceRenderNextFrame = YES;
|
|
122
|
+
_config.ionAccessToken = token ? std::string([token UTF8String]) : std::string();
|
|
123
|
+
_config.ionAssetId = assetId;
|
|
124
|
+
[self applyEngineConfig];
|
|
209
125
|
}
|
|
210
126
|
|
|
211
127
|
- (void)updateImageryAssetId:(int64_t)assetId {
|
|
212
128
|
if (!_initialized) return;
|
|
213
|
-
|
|
214
|
-
|
|
129
|
+
_config.ionImageryAssetId = (assetId <= 0) ? 1 : assetId;
|
|
130
|
+
_engine->setImageryAssetId(_config.ionImageryAssetId);
|
|
131
|
+
_target.requestForceRender();
|
|
215
132
|
}
|
|
216
133
|
|
|
217
134
|
- (void)updateCameraLatitude:(double)lat
|
|
@@ -221,14 +138,7 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
221
138
|
pitch:(double)pitch
|
|
222
139
|
roll:(double)roll {
|
|
223
140
|
if (!_initialized) return;
|
|
224
|
-
|
|
225
|
-
_camTarget.longitude = lon;
|
|
226
|
-
_camTarget.altitude = alt;
|
|
227
|
-
_camTarget.heading = heading;
|
|
228
|
-
_camTarget.pitch = pitch;
|
|
229
|
-
_camTarget.roll = roll;
|
|
230
|
-
// Intentionally does not modify `_camTarget.viewCorrection`.
|
|
231
|
-
_forceRenderNextFrame = YES;
|
|
141
|
+
_target.setHpr(lat, lon, alt, heading, pitch, roll);
|
|
232
142
|
}
|
|
233
143
|
|
|
234
144
|
- (void)updateCameraQuaternionLatitude:(double)lat
|
|
@@ -242,182 +152,153 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
242
152
|
y:(double)qy
|
|
243
153
|
z:(double)qz {
|
|
244
154
|
if (!_initialized) return;
|
|
245
|
-
|
|
246
|
-
_camTarget.longitude = lon;
|
|
247
|
-
_camTarget.altitude = alt;
|
|
248
|
-
_camTarget.heading = heading;
|
|
249
|
-
_camTarget.pitch = pitch;
|
|
250
|
-
_camTarget.roll = roll;
|
|
155
|
+
_target.setHpr(lat, lon, alt, heading, pitch, roll);
|
|
251
156
|
const double ql2 = qw * qw + qx * qx + qy * qy + qz * qz;
|
|
252
|
-
glm::dquat
|
|
157
|
+
glm::dquat q;
|
|
253
158
|
if (ql2 < 1e-20) {
|
|
254
159
|
q = glm::dquat(1.0, 0.0, 0.0, 0.0);
|
|
255
160
|
} else {
|
|
256
161
|
const double inv = 1.0 / std::sqrt(ql2);
|
|
257
162
|
q = glm::dquat(qw * inv, qx * inv, qy * inv, qz * inv);
|
|
258
163
|
}
|
|
259
|
-
|
|
260
|
-
_forceRenderNextFrame = YES;
|
|
164
|
+
_target.setViewCorrection(q);
|
|
261
165
|
}
|
|
262
166
|
|
|
263
167
|
- (void)resize:(int)width height:(int)height {
|
|
264
168
|
_viewportWidth = width;
|
|
265
169
|
_viewportHeight = height;
|
|
266
170
|
if (_metalBackend) _metalBackend->resize(width, height);
|
|
267
|
-
|
|
171
|
+
_target.requestForceRender();
|
|
268
172
|
}
|
|
269
173
|
|
|
270
174
|
- (void)setVerticalFovDeg:(double)degrees {
|
|
271
175
|
if (!_initialized) return;
|
|
272
176
|
_engine->camera().setVerticalFovDegrees(degrees);
|
|
273
|
-
|
|
177
|
+
_target.requestForceRender();
|
|
274
178
|
}
|
|
275
179
|
|
|
276
180
|
- (void)setMaximumScreenSpaceError:(double)v {
|
|
277
|
-
|
|
278
|
-
if (
|
|
279
|
-
_engine->updateConfig([self makeEngineConfig]);
|
|
280
|
-
_forceRenderNextFrame = YES;
|
|
181
|
+
_config.maximumScreenSpaceError = v;
|
|
182
|
+
if (_initialized) [self applyEngineConfig];
|
|
281
183
|
}
|
|
282
|
-
- (void)setMaximumSimultaneousTileLoads:(
|
|
283
|
-
|
|
284
|
-
if (
|
|
285
|
-
_engine->updateConfig([self makeEngineConfig]);
|
|
286
|
-
_forceRenderNextFrame = YES;
|
|
184
|
+
- (void)setMaximumSimultaneousTileLoads:(int32_t)v {
|
|
185
|
+
_config.maximumSimultaneousTileLoads = v;
|
|
186
|
+
if (_initialized) [self applyEngineConfig];
|
|
287
187
|
}
|
|
288
|
-
- (void)setLoadingDescendantLimit:(
|
|
289
|
-
|
|
290
|
-
if (
|
|
291
|
-
|
|
292
|
-
|
|
188
|
+
- (void)setLoadingDescendantLimit:(int32_t)v {
|
|
189
|
+
_config.loadingDescendantLimit = v;
|
|
190
|
+
if (_initialized) [self applyEngineConfig];
|
|
191
|
+
}
|
|
192
|
+
- (void)setMaximumCachedMiB:(int32_t)v {
|
|
193
|
+
_config.maximumCachedBytes =
|
|
194
|
+
static_cast<int64_t>(std::max<int32_t>(16, v)) * 1024LL * 1024LL;
|
|
195
|
+
if (_initialized) [self applyEngineConfig];
|
|
196
|
+
}
|
|
197
|
+
- (void)setPreloadAncestors:(BOOL)v {
|
|
198
|
+
_config.preloadAncestors = (v == YES);
|
|
199
|
+
if (_initialized) [self applyEngineConfig];
|
|
200
|
+
}
|
|
201
|
+
- (void)setPreloadSiblings:(BOOL)v {
|
|
202
|
+
_config.preloadSiblings = (v == YES);
|
|
203
|
+
if (_initialized) [self applyEngineConfig];
|
|
204
|
+
}
|
|
205
|
+
- (void)setForbidHoles:(BOOL)v {
|
|
206
|
+
_config.forbidHoles = (v == YES);
|
|
207
|
+
if (_initialized) [self applyEngineConfig];
|
|
208
|
+
}
|
|
209
|
+
- (void)setEnableWaterMask:(BOOL)v {
|
|
210
|
+
_config.enableWaterMask = (v == YES);
|
|
211
|
+
if (_initialized) [self applyEngineConfig];
|
|
212
|
+
}
|
|
213
|
+
- (void)setEnableFogCulling:(BOOL)v {
|
|
214
|
+
_config.enableFogCulling = (v == YES);
|
|
215
|
+
if (_initialized) [self applyEngineConfig];
|
|
216
|
+
}
|
|
217
|
+
- (void)setEnforceCulledScreenSpaceError:(BOOL)v {
|
|
218
|
+
_config.enforceCulledScreenSpaceError = (v == YES);
|
|
219
|
+
if (_initialized) [self applyEngineConfig];
|
|
220
|
+
}
|
|
221
|
+
- (void)setCulledScreenSpaceError:(double)v {
|
|
222
|
+
_config.culledScreenSpaceError = v;
|
|
223
|
+
if (_initialized) [self applyEngineConfig];
|
|
224
|
+
}
|
|
225
|
+
- (void)setEnableLodTransitionPeriod:(BOOL)v {
|
|
226
|
+
_config.enableLodTransitionPeriod = (v == YES);
|
|
227
|
+
if (_initialized) [self applyEngineConfig];
|
|
228
|
+
}
|
|
229
|
+
- (void)setLodTransitionLength:(double)v {
|
|
230
|
+
_config.lodTransitionLength = v;
|
|
231
|
+
if (_initialized) [self applyEngineConfig];
|
|
232
|
+
}
|
|
233
|
+
- (void)setSqliteCacheMaxRows:(int32_t)v {
|
|
234
|
+
// Cache rows are taken into account on the next initialize().
|
|
235
|
+
_config.sqliteCacheMaxRows = std::max<int32_t>(64, v);
|
|
236
|
+
}
|
|
237
|
+
- (void)setTaskProcessorThreads:(int32_t)v {
|
|
238
|
+
_config.taskProcessorThreads = std::max<int32_t>(0, v);
|
|
293
239
|
}
|
|
294
240
|
|
|
295
241
|
- (void)setMsaaSampleCount:(int)samples {
|
|
296
242
|
if (_metalBackend) _metalBackend->setMsaaSampleCount(samples);
|
|
297
|
-
|
|
243
|
+
_target.requestForceRender();
|
|
298
244
|
}
|
|
299
245
|
|
|
300
|
-
- (void)markNeedsRender {
|
|
301
|
-
_forceRenderNextFrame = YES;
|
|
302
|
-
}
|
|
246
|
+
- (void)markNeedsRender { _target.requestForceRender(); }
|
|
303
247
|
|
|
304
248
|
- (BOOL)shouldRenderNextFrame {
|
|
305
|
-
if (!_initialized || _suspended || !_engine)
|
|
306
|
-
|
|
249
|
+
if (!_initialized || _suspended || !_engine) return NO;
|
|
250
|
+
if (_target.consumeForceRender()) {
|
|
251
|
+
_target.requestForceRender(); // sticky for one frame so we make it through
|
|
252
|
+
return YES;
|
|
307
253
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return _forceRenderNextFrame ||
|
|
320
|
-
_frameResult.tilesLoading > 0 ||
|
|
321
|
-
!_frameResult.tilesetActive ||
|
|
322
|
-
cameraDirty;
|
|
254
|
+
if (_frameResult.tilesLoading > 0 || !_frameResult.tilesetActive) return YES;
|
|
255
|
+
if (_target.isDirty()) {
|
|
256
|
+
const auto cur = _engine->camera().getParams();
|
|
257
|
+
const auto tgt = _target.snapshot();
|
|
258
|
+
if (reactnativecesium::CameraTargetState::deltaExceedsEpsilon(cur, tgt)) {
|
|
259
|
+
return YES;
|
|
260
|
+
}
|
|
261
|
+
_target.clearDirty();
|
|
262
|
+
}
|
|
263
|
+
return NO;
|
|
323
264
|
}
|
|
324
265
|
|
|
325
266
|
- (void)renderFrameWithDt:(double)dt {
|
|
326
267
|
if (!_initialized || _suspended) return;
|
|
327
268
|
|
|
328
269
|
@autoreleasepool {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
// ── Smooth follower: track _camTarget per DOF ────────────────────────────
|
|
332
|
-
// lat/lon: direct copy — pan gestures must feel instant.
|
|
333
|
-
cur.latitude = _camTarget.latitude;
|
|
334
|
-
cur.longitude = _camTarget.longitude;
|
|
335
|
-
// alt/hdg/roll/pitch: exponential decay toward target.
|
|
336
|
-
const double aAlt = 1.0 - std::exp(-kSmoothAlt * dt);
|
|
337
|
-
const double aHdg = 1.0 - std::exp(-kSmoothHdg * dt);
|
|
338
|
-
const double aPitch = 1.0 - std::exp(-kSmoothPitch * dt);
|
|
339
|
-
const double aRoll = 1.0 - std::exp(-kSmoothRoll * dt);
|
|
340
|
-
const double aViewQ = 1.0 - std::exp(-kSmoothViewCorr * dt);
|
|
341
|
-
cur.altitude = cur.altitude + aAlt * (_camTarget.altitude - cur.altitude);
|
|
342
|
-
cur.heading = lerpAngleDeg(cur.heading, _camTarget.heading, aHdg);
|
|
343
|
-
cur.pitch = lerpAngleDeg(cur.pitch, _camTarget.pitch, aPitch);
|
|
344
|
-
cur.roll = lerpAngleDeg(cur.roll, _camTarget.roll, aRoll);
|
|
345
|
-
|
|
346
|
-
glm::dquat cq = glm::normalize(cur.viewCorrection);
|
|
347
|
-
glm::dquat tq = glm::normalize(_camTarget.viewCorrection);
|
|
348
|
-
if (glm::dot(cq, tq) < 0.0)
|
|
349
|
-
tq = -tq;
|
|
350
|
-
cur.viewCorrection = glm::normalize(glm::slerp(cq, tq, aViewQ));
|
|
351
|
-
|
|
352
|
-
if (std::abs(_camTarget.altitude - cur.altitude) <= kEpsAlt) {
|
|
353
|
-
cur.altitude = _camTarget.altitude;
|
|
354
|
-
}
|
|
355
|
-
if (angleDeltaAbsDeg(cur.heading, _camTarget.heading) <= kEpsAngleDeg) {
|
|
356
|
-
cur.heading = _camTarget.heading;
|
|
357
|
-
}
|
|
358
|
-
if (angleDeltaAbsDeg(cur.pitch, _camTarget.pitch) <= kEpsAngleDeg) {
|
|
359
|
-
cur.pitch = _camTarget.pitch;
|
|
360
|
-
}
|
|
361
|
-
if (angleDeltaAbsDeg(cur.roll, _camTarget.roll) <= kEpsAngleDeg) {
|
|
362
|
-
cur.roll = _camTarget.roll;
|
|
363
|
-
}
|
|
364
|
-
if ((1.0 - quatDotAbs(cur.viewCorrection, _camTarget.viewCorrection)) <= kEpsQuatDot) {
|
|
365
|
-
cur.viewCorrection = _camTarget.viewCorrection;
|
|
366
|
-
}
|
|
367
|
-
_engine->camera().setParams(cur);
|
|
270
|
+
(void)_target.consumeForceRender();
|
|
368
271
|
|
|
369
|
-
_engine->
|
|
272
|
+
const auto cur = _engine->camera().getParams();
|
|
273
|
+
const auto tgt = _target.snapshot();
|
|
274
|
+
const auto smooth = reactnativecesium::CameraSmoother::step(
|
|
275
|
+
cur, tgt, dt, _target.recentIntervalSec());
|
|
276
|
+
_engine->camera().setParams(smooth);
|
|
370
277
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (++_metricsTick >= 20) {
|
|
375
|
-
_metricsTick = 0;
|
|
376
|
-
_metricsFps = _fpsEma;
|
|
377
|
-
_metricsTilesRendered = _frameResult.tilesRendered;
|
|
378
|
-
_metricsTilesLoading = _frameResult.tilesLoading;
|
|
379
|
-
_metricsTilesVisited = _frameResult.tilesVisited;
|
|
380
|
-
_metricsIonTokenConfigured = _frameResult.ionTokenConfigured;
|
|
381
|
-
_metricsTilesetReady = _frameResult.tilesetActive;
|
|
382
|
-
if (!_frameResult.creditHtmlLines.empty()) {
|
|
383
|
-
NSMutableString* joined = [NSMutableString string];
|
|
384
|
-
for (const auto& html : _frameResult.creditHtmlLines) {
|
|
385
|
-
if (joined.length > 0) [joined appendString:@"|"];
|
|
386
|
-
[joined appendString:[NSString stringWithUTF8String:html.c_str()]];
|
|
387
|
-
}
|
|
388
|
-
if (![_lastCreditHtmlJoined isEqualToString:joined]) {
|
|
389
|
-
_lastCreditHtmlJoined = [joined copy];
|
|
390
|
-
NSMutableString* credits = [NSMutableString string];
|
|
391
|
-
for (const auto& html : _frameResult.creditHtmlLines) {
|
|
392
|
-
NSString* chunk = stripHtmlToPlain(
|
|
393
|
-
[NSString stringWithUTF8String:html.c_str()]);
|
|
394
|
-
if (chunk.length == 0) continue;
|
|
395
|
-
if (credits.length > 0) [credits appendString:@" · "];
|
|
396
|
-
[credits appendString:chunk];
|
|
397
|
-
}
|
|
398
|
-
_metricsCreditsPlainText = [credits copy];
|
|
399
|
-
}
|
|
400
|
-
} else {
|
|
401
|
-
_lastCreditHtmlJoined = @"";
|
|
402
|
-
_metricsCreditsPlainText = @"";
|
|
403
|
-
}
|
|
278
|
+
if (!reactnativecesium::CameraTargetState::deltaExceedsEpsilon(smooth, tgt)) {
|
|
279
|
+
_target.clearDirty();
|
|
404
280
|
}
|
|
405
281
|
|
|
282
|
+
_engine->updateFrame(_viewportWidth, _viewportHeight, _frameResult);
|
|
283
|
+
_metrics.tick(dt, _frameResult, !_config.tlsCaBundlePath.empty());
|
|
284
|
+
|
|
406
285
|
reactnativecesium::FrameParams params;
|
|
407
286
|
_metalBackend->beginFrame(params);
|
|
408
287
|
_metalBackend->drawScene(_frameResult);
|
|
409
288
|
_metalBackend->endFrame();
|
|
410
|
-
_forceRenderNextFrame = NO;
|
|
411
289
|
}
|
|
412
290
|
}
|
|
413
291
|
|
|
414
|
-
- (double)metricsFps { return
|
|
415
|
-
- (NSInteger)metricsTilesRendered { return
|
|
416
|
-
- (NSInteger)metricsTilesLoading { return
|
|
417
|
-
- (NSInteger)metricsTilesVisited { return
|
|
418
|
-
- (BOOL)metricsIonTokenConfigured { return
|
|
419
|
-
- (BOOL)metricsTilesetReady { return
|
|
420
|
-
- (
|
|
292
|
+
- (double)metricsFps { return _metrics.latest().fps; }
|
|
293
|
+
- (NSInteger)metricsTilesRendered { return _metrics.latest().tilesRendered; }
|
|
294
|
+
- (NSInteger)metricsTilesLoading { return _metrics.latest().tilesLoading; }
|
|
295
|
+
- (NSInteger)metricsTilesVisited { return _metrics.latest().tilesVisited; }
|
|
296
|
+
- (BOOL)metricsIonTokenConfigured { return _metrics.latest().ionTokenConfigured; }
|
|
297
|
+
- (BOOL)metricsTilesetReady { return _metrics.latest().tilesetReady; }
|
|
298
|
+
- (BOOL)metricsTlsConfigured { return _metrics.latest().tlsConfigured; }
|
|
299
|
+
- (NSString*)metricsCreditsPlainText {
|
|
300
|
+
return [NSString stringWithUTF8String:_metrics.latest().creditsPlainText.c_str()];
|
|
301
|
+
}
|
|
421
302
|
|
|
422
303
|
- (double)readCameraLatitude { return _engine ? _engine->camera().getParams().latitude : 0.0; }
|
|
423
304
|
- (double)readCameraLongitude { return _engine ? _engine->camera().getParams().longitude : 0.0; }
|
|
@@ -432,16 +313,13 @@ static double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
|
432
313
|
return _engine->camera().getParams().viewCorrection.w;
|
|
433
314
|
}
|
|
434
315
|
- (double)readViewCorrectionX {
|
|
435
|
-
|
|
436
|
-
return _engine->camera().getParams().viewCorrection.x;
|
|
316
|
+
return _engine ? _engine->camera().getParams().viewCorrection.x : 0.0;
|
|
437
317
|
}
|
|
438
318
|
- (double)readViewCorrectionY {
|
|
439
|
-
|
|
440
|
-
return _engine->camera().getParams().viewCorrection.y;
|
|
319
|
+
return _engine ? _engine->camera().getParams().viewCorrection.y : 0.0;
|
|
441
320
|
}
|
|
442
321
|
- (double)readViewCorrectionZ {
|
|
443
|
-
|
|
444
|
-
return _engine->camera().getParams().viewCorrection.z;
|
|
322
|
+
return _engine ? _engine->camera().getParams().viewCorrection.z : 0.0;
|
|
445
323
|
}
|
|
446
324
|
|
|
447
325
|
- (void)shutdown {
|