react-native-cesium 1.0.1
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/LICENSE +21 -0
- package/NOTICE +12 -0
- package/README.md +308 -0
- package/ReactNativeCesium.podspec +54 -0
- package/android/CMakeLists.txt +146 -0
- package/android/build.gradle +178 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/assets/cacert.pem +3529 -0
- package/android/src/main/cpp/CesiumBridgeAndroid.cpp +487 -0
- package/android/src/main/cpp/CesiumBridgeAndroid.h +94 -0
- package/android/src/main/cpp/cpp-adapter.cpp +17 -0
- package/android/src/main/cpp/vulkan/VulkanBackend.cpp +1781 -0
- package/android/src/main/cpp/vulkan/VulkanBackend.h +190 -0
- package/android/src/main/cpp/vulkan/shaders/sky.frag +86 -0
- package/android/src/main/cpp/vulkan/shaders/sky.vert +9 -0
- package/android/src/main/cpp/vulkan/shaders/terrain.frag +144 -0
- package/android/src/main/cpp/vulkan/shaders/terrain.vert +25 -0
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +84 -0
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +225 -0
- package/android/src/main/java/com/reactnativecesium/ReactNativeCesiumPackage.kt +28 -0
- package/cpp/engine/CesiumEngine.cpp +413 -0
- package/cpp/engine/CesiumEngine.hpp +90 -0
- package/cpp/engine/DeletionQueue.cpp +28 -0
- package/cpp/engine/DeletionQueue.hpp +28 -0
- package/cpp/engine/GlobeCamera.cpp +181 -0
- package/cpp/engine/GlobeCamera.hpp +64 -0
- package/cpp/engine/GltfToMesh.cpp +154 -0
- package/cpp/engine/GltfToMesh.hpp +20 -0
- package/cpp/engine/ResourcePreparer.cpp +224 -0
- package/cpp/engine/ResourcePreparer.hpp +96 -0
- package/cpp/engine/TaskProcessor.cpp +61 -0
- package/cpp/engine/TaskProcessor.hpp +43 -0
- package/cpp/engine/TileLifecycleManager.cpp +30 -0
- package/cpp/engine/TileLifecycleManager.hpp +25 -0
- package/cpp/fmt/format.h +9 -0
- package/cpp/renderer/IGPUBackend.hpp +22 -0
- package/cpp/renderer/RenderTypes.hpp +112 -0
- package/cpp/renderer/ShaderTypes.hpp +29 -0
- package/example/README.md +43 -0
- package/example/react-native-cesium-example.jpg +0 -0
- package/ios/CesiumBridge.h +55 -0
- package/ios/CesiumBridge.mm +393 -0
- package/ios/HybridCesiumView.swift +299 -0
- package/ios/ReactNativeCesium-umbrella.h +16 -0
- package/ios/metal/MetalBackend.h +82 -0
- package/ios/metal/MetalBackend.mm +839 -0
- package/ios/react_native_cesium_ensure_native.rb +12 -0
- package/ios/react_native_cesium_post_install.rb +30 -0
- package/lib/commonjs/CesiumView.js +13 -0
- package/lib/commonjs/CesiumView.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/specs/cesium-view.nitro.js +6 -0
- package/lib/commonjs/specs/cesium-view.nitro.js.map +1 -0
- package/lib/module/CesiumView.js +9 -0
- package/lib/module/CesiumView.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/specs/cesium-view.nitro.js +4 -0
- package/lib/module/specs/cesium-view.nitro.js.map +1 -0
- package/lib/typescript/src/CesiumView.d.ts +5 -0
- package/lib/typescript/src/CesiumView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts +43 -0
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -0
- package/nitro.json +30 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/ReactNativeCesium+autolinking.cmake +83 -0
- package/nitrogen/generated/android/ReactNativeCesium+autolinking.gradle +27 -0
- package/nitrogen/generated/android/ReactNativeCesiumOnLoad.cpp +58 -0
- package/nitrogen/generated/android/ReactNativeCesiumOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JCameraState.hpp +81 -0
- package/nitrogen/generated/android/c++/JCesiumMetrics.hpp +81 -0
- package/nitrogen/generated/android/c++/JFunc_void_CesiumMetrics.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.cpp +178 -0
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.hpp +83 -0
- package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.cpp +92 -0
- package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CameraState.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CesiumMetrics.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/Func_void_CesiumMetrics.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/HybridCesiumViewSpec.kt +126 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/ReactNativeCesiumOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewStateUpdater.kt +23 -0
- package/nitrogen/generated/ios/ReactNativeCesium+autolinking.rb +60 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.cpp +57 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.hpp +164 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Umbrella.hpp +53 -0
- package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.mm +33 -0
- package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.hpp +157 -0
- package/nitrogen/generated/ios/c++/views/HybridCesiumViewComponent.mm +167 -0
- package/nitrogen/generated/ios/swift/CameraState.swift +59 -0
- package/nitrogen/generated/ios/swift/CesiumMetrics.swift +59 -0
- package/nitrogen/generated/ios/swift/Func_void_CameraState.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_CesiumMetrics.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec.swift +65 -0
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec_cxx.swift +306 -0
- package/nitrogen/generated/shared/c++/CameraState.hpp +107 -0
- package/nitrogen/generated/shared/c++/CesiumMetrics.hpp +107 -0
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.cpp +42 -0
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.hpp +90 -0
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.cpp +182 -0
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.hpp +122 -0
- package/nitrogen/generated/shared/json/CesiumViewConfig.json +19 -0
- package/package.json +140 -0
- package/react-native.config.js +16 -0
- package/scripts/cesium/build.mjs +901 -0
- package/scripts/cesium/clean.mjs +35 -0
- package/scripts/cesium/clone.mjs +32 -0
- package/scripts/cesium/ensure-native.mjs +116 -0
- package/scripts/cesium/vcpkg-ports/zstd/fix-emscripten-and-clang-cl.patch +31 -0
- package/scripts/cesium/vcpkg-ports/zstd/fix-windows-rc-compile.patch +13 -0
- package/scripts/cesium/vcpkg-ports/zstd/no-static-suffix.patch +13 -0
- package/scripts/cesium/vcpkg-ports/zstd/portfile.cmake +77 -0
- package/scripts/cesium/vcpkg-ports/zstd/usage +4 -0
- package/scripts/cesium/vcpkg-ports/zstd/vcpkg.json +23 -0
- package/scripts/cesium/vcpkg-triplets/arm64-ios-simulator.cmake +10 -0
- package/scripts/cesium/vcpkg-triplets/arm64-ios.cmake +14 -0
- package/src/CesiumView.tsx +13 -0
- package/src/index.ts +7 -0
- package/src/specs/cesium-view.nitro.ts +51 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Metal
|
|
3
|
+
import MetalKit
|
|
4
|
+
import NitroModules
|
|
5
|
+
import UIKit
|
|
6
|
+
|
|
7
|
+
class HybridCesiumView: HybridCesiumViewSpec {
|
|
8
|
+
// MARK: - Props
|
|
9
|
+
|
|
10
|
+
var ionAccessToken: String = "" {
|
|
11
|
+
didSet { bridge?.updateIonAccessToken(ionAccessToken, assetId: Int64(ionAssetId)) }
|
|
12
|
+
}
|
|
13
|
+
var ionAssetId: Double = 1 {
|
|
14
|
+
didSet { bridge?.updateIonAccessToken(ionAccessToken, assetId: Int64(ionAssetId)) }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// Construction-time seed camera. Once the bridge exists, use `setCamera(_:)`
|
|
18
|
+
/// for runtime updates; later prop writes are stored but do not drive the
|
|
19
|
+
/// active native camera.
|
|
20
|
+
var initialCamera: CameraState = CameraState(
|
|
21
|
+
latitude: 46.15,
|
|
22
|
+
longitude: 7.35,
|
|
23
|
+
altitude: 12000,
|
|
24
|
+
heading: 129,
|
|
25
|
+
pitch: -45,
|
|
26
|
+
roll: 0,
|
|
27
|
+
verticalFovDeg: 60
|
|
28
|
+
)
|
|
29
|
+
var pauseRendering: Bool = false {
|
|
30
|
+
didSet {
|
|
31
|
+
displayLink?.isPaused = pauseRendering
|
|
32
|
+
if !pauseRendering {
|
|
33
|
+
bridge?.markNeedsRender()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var maximumScreenSpaceError: Double = 32 {
|
|
39
|
+
didSet { bridge?.setMaximumScreenSpaceError(maximumScreenSpaceError) }
|
|
40
|
+
}
|
|
41
|
+
var maximumSimultaneousTileLoads: Double = 12 {
|
|
42
|
+
didSet { bridge?.setMaximumSimultaneousTileLoads(Int32(maximumSimultaneousTileLoads)) }
|
|
43
|
+
}
|
|
44
|
+
var loadingDescendantLimit: Double = 20 {
|
|
45
|
+
didSet { bridge?.setLoadingDescendantLimit(Int32(loadingDescendantLimit)) }
|
|
46
|
+
}
|
|
47
|
+
var msaaSampleCount: Double = 1 {
|
|
48
|
+
didSet {
|
|
49
|
+
let s = Int32(msaaSampleCount)
|
|
50
|
+
bridge?.setMsaaSampleCount(s)
|
|
51
|
+
applyMtkViewMsaa(Int(s))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var ionImageryAssetId: Double = 1 {
|
|
55
|
+
didSet { bridge?.updateImageryAssetId(Int64(ionImageryAssetId)) }
|
|
56
|
+
}
|
|
57
|
+
var onMetrics: ((CesiumMetrics) -> Void)?
|
|
58
|
+
|
|
59
|
+
// MARK: - Methods
|
|
60
|
+
|
|
61
|
+
func getCameraState() throws -> Promise<CameraState> {
|
|
62
|
+
guard let b = bridge else {
|
|
63
|
+
return Promise.rejected(
|
|
64
|
+
withError: NSError(
|
|
65
|
+
domain: "HybridCesiumView",
|
|
66
|
+
code: 1,
|
|
67
|
+
userInfo: [NSLocalizedDescriptionKey: "Native bridge not initialized"]
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
let s = CameraState(
|
|
72
|
+
latitude: b.readCameraLatitude(),
|
|
73
|
+
longitude: b.readCameraLongitude(),
|
|
74
|
+
altitude: b.readCameraAltitude(),
|
|
75
|
+
heading: b.readCameraHeading(),
|
|
76
|
+
pitch: b.readCameraPitch(),
|
|
77
|
+
roll: b.readCameraRoll(),
|
|
78
|
+
verticalFovDeg: b.readVerticalFovDeg()
|
|
79
|
+
)
|
|
80
|
+
return Promise.resolved(withResult: s)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func setCamera(camera: CameraState) throws {
|
|
84
|
+
// Runtime camera updates flow through this method; if the view is not ready
|
|
85
|
+
// yet we keep the latest value and apply it during initialization.
|
|
86
|
+
initialCamera = camera
|
|
87
|
+
pushCameraStateIfChanged(camera)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// MARK: - View
|
|
91
|
+
|
|
92
|
+
private let metalView: MTKView
|
|
93
|
+
private var bridge: CesiumBridge?
|
|
94
|
+
private var displayLink: CADisplayLink?
|
|
95
|
+
private var layoutPollTimer: Timer?
|
|
96
|
+
private var metricsFrameCounter: Int = 0
|
|
97
|
+
private var idleProbeAccumulator: Double = 0
|
|
98
|
+
private var usingLowRefreshRate = false
|
|
99
|
+
private var hasConfiguredFrameRate = false
|
|
100
|
+
private var lastPushedCameraState: CameraState?
|
|
101
|
+
private var lastBridgePixelSize: CGSize = .zero
|
|
102
|
+
|
|
103
|
+
var view: UIView { metalView }
|
|
104
|
+
|
|
105
|
+
override init() {
|
|
106
|
+
let device = MTLCreateSystemDefaultDevice()!
|
|
107
|
+
metalView = MTKView(frame: .zero, device: device)
|
|
108
|
+
metalView.colorPixelFormat = .bgra8Unorm_srgb
|
|
109
|
+
metalView.depthStencilPixelFormat = .depth32Float
|
|
110
|
+
metalView.autoResizeDrawable = false
|
|
111
|
+
metalView.isPaused = true
|
|
112
|
+
metalView.enableSetNeedsDisplay = false
|
|
113
|
+
metalView.isMultipleTouchEnabled = true
|
|
114
|
+
|
|
115
|
+
super.init()
|
|
116
|
+
|
|
117
|
+
metalView.layer.isOpaque = true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// MARK: - Lifecycle
|
|
121
|
+
|
|
122
|
+
func beforeUpdate() {}
|
|
123
|
+
|
|
124
|
+
func afterUpdate() {
|
|
125
|
+
if bridge == nil && layoutPollTimer == nil {
|
|
126
|
+
layoutPollTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { [weak self] _ in
|
|
127
|
+
guard let self = self else { return }
|
|
128
|
+
if self.metalView.bounds.width > 0 {
|
|
129
|
+
self.layoutPollTimer?.invalidate()
|
|
130
|
+
self.layoutPollTimer = nil
|
|
131
|
+
self.ensureInitialized()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
ensureInitialized()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private func ensureInitialized() {
|
|
139
|
+
guard bridge == nil,
|
|
140
|
+
let metalLayer = metalView.layer as? CAMetalLayer,
|
|
141
|
+
metalView.bounds.width > 0 else { return }
|
|
142
|
+
|
|
143
|
+
let scale = metalView.contentScaleFactor
|
|
144
|
+
let w = Int(metalView.bounds.width * scale)
|
|
145
|
+
let h = Int(metalView.bounds.height * scale)
|
|
146
|
+
let pixelSize = CGSize(width: w, height: h)
|
|
147
|
+
metalView.drawableSize = pixelSize
|
|
148
|
+
lastBridgePixelSize = pixelSize
|
|
149
|
+
|
|
150
|
+
let cacheDir = NSSearchPathForDirectoriesInDomains(
|
|
151
|
+
.cachesDirectory, .userDomainMask, true
|
|
152
|
+
).first ?? NSTemporaryDirectory()
|
|
153
|
+
|
|
154
|
+
bridge = CesiumBridge(
|
|
155
|
+
metalLayer: metalLayer,
|
|
156
|
+
width: Int32(w),
|
|
157
|
+
height: Int32(h),
|
|
158
|
+
cacheDir: cacheDir
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
syncBridgeOptionsFromProps()
|
|
162
|
+
|
|
163
|
+
if !ionAccessToken.isEmpty {
|
|
164
|
+
bridge?.updateIonAccessToken(ionAccessToken, assetId: Int64(ionAssetId))
|
|
165
|
+
}
|
|
166
|
+
pushCameraStateIfChanged(initialCamera)
|
|
167
|
+
if ionImageryAssetId != 1 {
|
|
168
|
+
bridge?.updateImageryAssetId(Int64(ionImageryAssetId))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let sc = Int32(msaaSampleCount)
|
|
172
|
+
bridge?.setMsaaSampleCount(sc)
|
|
173
|
+
applyMtkViewMsaa(Int(sc))
|
|
174
|
+
|
|
175
|
+
startRenderLoop()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private func applyMtkViewMsaa(_ s: Int) {
|
|
179
|
+
guard let d = metalView.device else {
|
|
180
|
+
metalView.sampleCount = 1
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
if s >= 4, d.supportsTextureSampleCount(4) {
|
|
184
|
+
metalView.sampleCount = 4
|
|
185
|
+
} else if s >= 2, d.supportsTextureSampleCount(2) {
|
|
186
|
+
metalView.sampleCount = 2
|
|
187
|
+
} else {
|
|
188
|
+
metalView.sampleCount = 1
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private func syncBridgeOptionsFromProps() {
|
|
193
|
+
bridge?.setMaximumScreenSpaceError(maximumScreenSpaceError)
|
|
194
|
+
bridge?.setMaximumSimultaneousTileLoads(Int32(maximumSimultaneousTileLoads))
|
|
195
|
+
bridge?.setLoadingDescendantLimit(Int32(loadingDescendantLimit))
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Pushes camera state into native bridge only when values changed.
|
|
199
|
+
private func pushCameraStateIfChanged(_ camera: CameraState) {
|
|
200
|
+
guard bridge != nil else { return }
|
|
201
|
+
if let last = lastPushedCameraState,
|
|
202
|
+
last.latitude == camera.latitude,
|
|
203
|
+
last.longitude == camera.longitude,
|
|
204
|
+
last.altitude == camera.altitude,
|
|
205
|
+
last.heading == camera.heading,
|
|
206
|
+
last.pitch == camera.pitch,
|
|
207
|
+
last.roll == camera.roll,
|
|
208
|
+
last.verticalFovDeg == camera.verticalFovDeg {
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
lastPushedCameraState = camera
|
|
212
|
+
bridge?.updateCameraLatitude(
|
|
213
|
+
camera.latitude,
|
|
214
|
+
longitude: camera.longitude,
|
|
215
|
+
altitude: camera.altitude,
|
|
216
|
+
heading: camera.heading,
|
|
217
|
+
pitch: camera.pitch,
|
|
218
|
+
roll: camera.roll
|
|
219
|
+
)
|
|
220
|
+
bridge?.setVerticalFovDeg(camera.verticalFovDeg)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// MARK: - Render Loop
|
|
224
|
+
|
|
225
|
+
private func startRenderLoop() {
|
|
226
|
+
displayLink = CADisplayLink(target: self, selector: #selector(renderFrame))
|
|
227
|
+
setDisplayLinkFrameRate(idle: false)
|
|
228
|
+
displayLink?.add(to: .main, forMode: .common)
|
|
229
|
+
displayLink?.isPaused = pauseRendering
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private func setDisplayLinkFrameRate(idle: Bool) {
|
|
233
|
+
guard let dl = displayLink else { return }
|
|
234
|
+
if hasConfiguredFrameRate && usingLowRefreshRate == idle { return }
|
|
235
|
+
hasConfiguredFrameRate = true
|
|
236
|
+
usingLowRefreshRate = idle
|
|
237
|
+
dl.preferredFrameRateRange = idle
|
|
238
|
+
? CAFrameRateRange(minimum: 5, maximum: 15, preferred: 10)
|
|
239
|
+
: CAFrameRateRange(minimum: 30, maximum: 60, preferred: 60)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@objc private func renderFrame() {
|
|
243
|
+
guard !pauseRendering,
|
|
244
|
+
let dl = displayLink,
|
|
245
|
+
let bridge else { return }
|
|
246
|
+
|
|
247
|
+
let dt = max(dl.targetTimestamp - dl.timestamp, 1.0 / 120.0)
|
|
248
|
+
|
|
249
|
+
let scale = metalView.contentScaleFactor
|
|
250
|
+
let w = Int(metalView.bounds.width * scale)
|
|
251
|
+
let h = Int(metalView.bounds.height * scale)
|
|
252
|
+
|
|
253
|
+
if w > 0 && h > 0 {
|
|
254
|
+
let pixelSize = CGSize(width: w, height: h)
|
|
255
|
+
if lastBridgePixelSize != pixelSize {
|
|
256
|
+
metalView.drawableSize = pixelSize
|
|
257
|
+
lastBridgePixelSize = pixelSize
|
|
258
|
+
bridge.resize(Int32(w), height: Int32(h))
|
|
259
|
+
bridge.markNeedsRender()
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
let shouldRenderNow = bridge.shouldRenderNextFrame()
|
|
264
|
+
if shouldRenderNow {
|
|
265
|
+
setDisplayLinkFrameRate(idle: false)
|
|
266
|
+
idleProbeAccumulator = 0
|
|
267
|
+
bridge.renderFrame(withDt: dt)
|
|
268
|
+
} else {
|
|
269
|
+
setDisplayLinkFrameRate(idle: true)
|
|
270
|
+
idleProbeAccumulator += dt
|
|
271
|
+
if idleProbeAccumulator >= 0.25 {
|
|
272
|
+
// Safety probe: occasionally tick engine state for late tile completions.
|
|
273
|
+
idleProbeAccumulator = 0
|
|
274
|
+
bridge.markNeedsRender()
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
metricsFrameCounter += 1
|
|
279
|
+
if metricsFrameCounter >= 20, let cb = onMetrics {
|
|
280
|
+
metricsFrameCounter = 0
|
|
281
|
+
let m = CesiumMetrics(
|
|
282
|
+
fps: bridge.metricsFps,
|
|
283
|
+
tilesRendered: Double(bridge.metricsTilesRendered),
|
|
284
|
+
tilesLoading: Double(bridge.metricsTilesLoading),
|
|
285
|
+
tilesVisited: Double(bridge.metricsTilesVisited),
|
|
286
|
+
ionTokenConfigured: bridge.metricsIonTokenConfigured,
|
|
287
|
+
tilesetReady: bridge.metricsTilesetReady,
|
|
288
|
+
creditsPlainText: bridge.metricsCreditsPlainText
|
|
289
|
+
)
|
|
290
|
+
cb(m)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
deinit {
|
|
295
|
+
layoutPollTimer?.invalidate()
|
|
296
|
+
displayLink?.invalidate()
|
|
297
|
+
bridge?.shutdown()
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#ifdef __OBJC__
|
|
2
|
+
#import <UIKit/UIKit.h>
|
|
3
|
+
#else
|
|
4
|
+
#ifndef FOUNDATION_EXPORT
|
|
5
|
+
#if defined(__cplusplus)
|
|
6
|
+
#define FOUNDATION_EXPORT extern "C"
|
|
7
|
+
#else
|
|
8
|
+
#define FOUNDATION_EXPORT extern
|
|
9
|
+
#endif
|
|
10
|
+
#endif
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
#import "CesiumBridge.h"
|
|
14
|
+
|
|
15
|
+
FOUNDATION_EXPORT double ReactNativeCesiumVersionNumber;
|
|
16
|
+
FOUNDATION_EXPORT const unsigned char ReactNativeCesiumVersionString[];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "renderer/IGPUBackend.hpp"
|
|
4
|
+
|
|
5
|
+
#ifdef __OBJC__
|
|
6
|
+
#import <Metal/Metal.h>
|
|
7
|
+
#import <QuartzCore/CAMetalLayer.h>
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
#include <cstddef> // size_t
|
|
11
|
+
|
|
12
|
+
namespace reactnativecesium {
|
|
13
|
+
|
|
14
|
+
class MetalBackend : public IGPUBackend {
|
|
15
|
+
public:
|
|
16
|
+
MetalBackend();
|
|
17
|
+
~MetalBackend() override;
|
|
18
|
+
|
|
19
|
+
void initialize(void* nativeSurface, int width, int height) override;
|
|
20
|
+
void resize(int width, int height) override;
|
|
21
|
+
void shutdown() override;
|
|
22
|
+
|
|
23
|
+
void beginFrame(const FrameParams& params) override;
|
|
24
|
+
void drawScene(const FrameResult& frame) override;
|
|
25
|
+
void endFrame() override;
|
|
26
|
+
|
|
27
|
+
// Create a retained Metal texture from raw RGBA8 pixels. Returns void*
|
|
28
|
+
// (retained id<MTLTexture>) that must be CFRelease'd when no longer needed.
|
|
29
|
+
// Both imagery overlays and water mask textures use this same function; they
|
|
30
|
+
// are distinguished only by which texture slot they are bound to at draw time.
|
|
31
|
+
void* createRasterTexture(const uint8_t* pixels, int32_t width, int32_t height);
|
|
32
|
+
|
|
33
|
+
/// 1 = off; 2 or 4 = MSAA when the device supports it. May block briefly
|
|
34
|
+
/// to drain in-flight frames before rebuilding pipelines.
|
|
35
|
+
void setMsaaSampleCount(int sampleCount);
|
|
36
|
+
|
|
37
|
+
private:
|
|
38
|
+
void buildRenderPipelines();
|
|
39
|
+
void createDepthTexture();
|
|
40
|
+
void createFallbackTexture();
|
|
41
|
+
void createWaterMaskFallback();
|
|
42
|
+
|
|
43
|
+
void* device_; // id<MTLDevice>
|
|
44
|
+
void* commandQueue_; // id<MTLCommandQueue>
|
|
45
|
+
void* metalLayer_; // CAMetalLayer* (weak — owned by the view)
|
|
46
|
+
void* terrainPipeline_; // id<MTLRenderPipelineState>
|
|
47
|
+
void* skyPipeline_; // id<MTLRenderPipelineState>
|
|
48
|
+
void* terrainDepthState_; // reversed-Z GREATER, write=YES
|
|
49
|
+
void* skyDepthState_; // Always, write=NO
|
|
50
|
+
void* depthTexture_; // id<MTLTexture>
|
|
51
|
+
void* fallbackTexture_; // 1×1 white id<MTLTexture> (imagery fallback)
|
|
52
|
+
void* fallbackWaterMaskTexture_; // 1×1 zero id<MTLTexture> (water mask fallback)
|
|
53
|
+
|
|
54
|
+
// Per-frame bookkeeping
|
|
55
|
+
void* currentDrawable_;
|
|
56
|
+
void* currentCommandBuffer_;
|
|
57
|
+
void* currentEncoder_;
|
|
58
|
+
|
|
59
|
+
int viewportWidth_ = 0;
|
|
60
|
+
int viewportHeight_ = 0;
|
|
61
|
+
int sampleCount_ = 1; // MSAA: 1, 2, or 4
|
|
62
|
+
|
|
63
|
+
// ── Triple-buffered persistent vertex / index / UV buffers ────────────────
|
|
64
|
+
// Using kMaxFramesInFlight slots avoids CPU-GPU data hazards without
|
|
65
|
+
// allocating new MTLBuffers every frame. The dispatch_semaphore limits the
|
|
66
|
+
// CPU to kMaxFramesInFlight frames ahead of the GPU.
|
|
67
|
+
static constexpr int kMaxFramesInFlight = 3;
|
|
68
|
+
|
|
69
|
+
void* frameSemaphore_; // dispatch_semaphore_t (stored as void* to keep header C++)
|
|
70
|
+
int frameIndex_ = 0;
|
|
71
|
+
|
|
72
|
+
void* vtxBufs_[kMaxFramesInFlight]; // id<MTLBuffer> — packed_float3 tile-local positions
|
|
73
|
+
void* idxBufs_[kMaxFramesInFlight]; // id<MTLBuffer> — uint32 indices
|
|
74
|
+
void* uvBufs_[kMaxFramesInFlight]; // id<MTLBuffer> — packed_float2 UVs
|
|
75
|
+
void* altBufs_[kMaxFramesInFlight]; // id<MTLBuffer> — float altitudes (metres, from double)
|
|
76
|
+
size_t vtxCaps_[kMaxFramesInFlight]; // allocated byte capacities
|
|
77
|
+
size_t idxCaps_[kMaxFramesInFlight];
|
|
78
|
+
size_t uvCaps_[kMaxFramesInFlight];
|
|
79
|
+
size_t altCaps_[kMaxFramesInFlight];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
} // namespace reactnativecesium
|