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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +12 -0
  3. package/README.md +308 -0
  4. package/ReactNativeCesium.podspec +54 -0
  5. package/android/CMakeLists.txt +146 -0
  6. package/android/build.gradle +178 -0
  7. package/android/fix-prefab.gradle +51 -0
  8. package/android/gradle.properties +5 -0
  9. package/android/src/main/AndroidManifest.xml +5 -0
  10. package/android/src/main/assets/cacert.pem +3529 -0
  11. package/android/src/main/cpp/CesiumBridgeAndroid.cpp +487 -0
  12. package/android/src/main/cpp/CesiumBridgeAndroid.h +94 -0
  13. package/android/src/main/cpp/cpp-adapter.cpp +17 -0
  14. package/android/src/main/cpp/vulkan/VulkanBackend.cpp +1781 -0
  15. package/android/src/main/cpp/vulkan/VulkanBackend.h +190 -0
  16. package/android/src/main/cpp/vulkan/shaders/sky.frag +86 -0
  17. package/android/src/main/cpp/vulkan/shaders/sky.vert +9 -0
  18. package/android/src/main/cpp/vulkan/shaders/terrain.frag +144 -0
  19. package/android/src/main/cpp/vulkan/shaders/terrain.vert +25 -0
  20. package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +84 -0
  21. package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +225 -0
  22. package/android/src/main/java/com/reactnativecesium/ReactNativeCesiumPackage.kt +28 -0
  23. package/cpp/engine/CesiumEngine.cpp +413 -0
  24. package/cpp/engine/CesiumEngine.hpp +90 -0
  25. package/cpp/engine/DeletionQueue.cpp +28 -0
  26. package/cpp/engine/DeletionQueue.hpp +28 -0
  27. package/cpp/engine/GlobeCamera.cpp +181 -0
  28. package/cpp/engine/GlobeCamera.hpp +64 -0
  29. package/cpp/engine/GltfToMesh.cpp +154 -0
  30. package/cpp/engine/GltfToMesh.hpp +20 -0
  31. package/cpp/engine/ResourcePreparer.cpp +224 -0
  32. package/cpp/engine/ResourcePreparer.hpp +96 -0
  33. package/cpp/engine/TaskProcessor.cpp +61 -0
  34. package/cpp/engine/TaskProcessor.hpp +43 -0
  35. package/cpp/engine/TileLifecycleManager.cpp +30 -0
  36. package/cpp/engine/TileLifecycleManager.hpp +25 -0
  37. package/cpp/fmt/format.h +9 -0
  38. package/cpp/renderer/IGPUBackend.hpp +22 -0
  39. package/cpp/renderer/RenderTypes.hpp +112 -0
  40. package/cpp/renderer/ShaderTypes.hpp +29 -0
  41. package/example/README.md +43 -0
  42. package/example/react-native-cesium-example.jpg +0 -0
  43. package/ios/CesiumBridge.h +55 -0
  44. package/ios/CesiumBridge.mm +393 -0
  45. package/ios/HybridCesiumView.swift +299 -0
  46. package/ios/ReactNativeCesium-umbrella.h +16 -0
  47. package/ios/metal/MetalBackend.h +82 -0
  48. package/ios/metal/MetalBackend.mm +839 -0
  49. package/ios/react_native_cesium_ensure_native.rb +12 -0
  50. package/ios/react_native_cesium_post_install.rb +30 -0
  51. package/lib/commonjs/CesiumView.js +13 -0
  52. package/lib/commonjs/CesiumView.js.map +1 -0
  53. package/lib/commonjs/index.js +13 -0
  54. package/lib/commonjs/index.js.map +1 -0
  55. package/lib/commonjs/package.json +1 -0
  56. package/lib/commonjs/specs/cesium-view.nitro.js +6 -0
  57. package/lib/commonjs/specs/cesium-view.nitro.js.map +1 -0
  58. package/lib/module/CesiumView.js +9 -0
  59. package/lib/module/CesiumView.js.map +1 -0
  60. package/lib/module/index.js +4 -0
  61. package/lib/module/index.js.map +1 -0
  62. package/lib/module/specs/cesium-view.nitro.js +4 -0
  63. package/lib/module/specs/cesium-view.nitro.js.map +1 -0
  64. package/lib/typescript/src/CesiumView.d.ts +5 -0
  65. package/lib/typescript/src/CesiumView.d.ts.map +1 -0
  66. package/lib/typescript/src/index.d.ts +3 -0
  67. package/lib/typescript/src/index.d.ts.map +1 -0
  68. package/lib/typescript/src/specs/cesium-view.nitro.d.ts +43 -0
  69. package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -0
  70. package/nitro.json +30 -0
  71. package/nitrogen/generated/.gitattributes +1 -0
  72. package/nitrogen/generated/android/ReactNativeCesium+autolinking.cmake +83 -0
  73. package/nitrogen/generated/android/ReactNativeCesium+autolinking.gradle +27 -0
  74. package/nitrogen/generated/android/ReactNativeCesiumOnLoad.cpp +58 -0
  75. package/nitrogen/generated/android/ReactNativeCesiumOnLoad.hpp +34 -0
  76. package/nitrogen/generated/android/c++/JCameraState.hpp +81 -0
  77. package/nitrogen/generated/android/c++/JCesiumMetrics.hpp +81 -0
  78. package/nitrogen/generated/android/c++/JFunc_void_CesiumMetrics.hpp +78 -0
  79. package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.cpp +178 -0
  80. package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.hpp +83 -0
  81. package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.cpp +92 -0
  82. package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.hpp +49 -0
  83. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CameraState.kt +56 -0
  84. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CesiumMetrics.kt +56 -0
  85. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/Func_void_CesiumMetrics.kt +80 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/HybridCesiumViewSpec.kt +126 -0
  87. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/ReactNativeCesiumOnLoad.kt +35 -0
  88. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewManager.kt +80 -0
  89. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewStateUpdater.kt +23 -0
  90. package/nitrogen/generated/ios/ReactNativeCesium+autolinking.rb +60 -0
  91. package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.cpp +57 -0
  92. package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.hpp +164 -0
  93. package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Umbrella.hpp +53 -0
  94. package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.mm +33 -0
  95. package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.swift +26 -0
  96. package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.cpp +11 -0
  97. package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.hpp +157 -0
  98. package/nitrogen/generated/ios/c++/views/HybridCesiumViewComponent.mm +167 -0
  99. package/nitrogen/generated/ios/swift/CameraState.swift +59 -0
  100. package/nitrogen/generated/ios/swift/CesiumMetrics.swift +59 -0
  101. package/nitrogen/generated/ios/swift/Func_void_CameraState.swift +46 -0
  102. package/nitrogen/generated/ios/swift/Func_void_CesiumMetrics.swift +46 -0
  103. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  104. package/nitrogen/generated/ios/swift/HybridCesiumViewSpec.swift +65 -0
  105. package/nitrogen/generated/ios/swift/HybridCesiumViewSpec_cxx.swift +306 -0
  106. package/nitrogen/generated/shared/c++/CameraState.hpp +107 -0
  107. package/nitrogen/generated/shared/c++/CesiumMetrics.hpp +107 -0
  108. package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.cpp +42 -0
  109. package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.hpp +90 -0
  110. package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.cpp +182 -0
  111. package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.hpp +122 -0
  112. package/nitrogen/generated/shared/json/CesiumViewConfig.json +19 -0
  113. package/package.json +140 -0
  114. package/react-native.config.js +16 -0
  115. package/scripts/cesium/build.mjs +901 -0
  116. package/scripts/cesium/clean.mjs +35 -0
  117. package/scripts/cesium/clone.mjs +32 -0
  118. package/scripts/cesium/ensure-native.mjs +116 -0
  119. package/scripts/cesium/vcpkg-ports/zstd/fix-emscripten-and-clang-cl.patch +31 -0
  120. package/scripts/cesium/vcpkg-ports/zstd/fix-windows-rc-compile.patch +13 -0
  121. package/scripts/cesium/vcpkg-ports/zstd/no-static-suffix.patch +13 -0
  122. package/scripts/cesium/vcpkg-ports/zstd/portfile.cmake +77 -0
  123. package/scripts/cesium/vcpkg-ports/zstd/usage +4 -0
  124. package/scripts/cesium/vcpkg-ports/zstd/vcpkg.json +23 -0
  125. package/scripts/cesium/vcpkg-triplets/arm64-ios-simulator.cmake +10 -0
  126. package/scripts/cesium/vcpkg-triplets/arm64-ios.cmake +14 -0
  127. package/src/CesiumView.tsx +13 -0
  128. package/src/index.ts +7 -0
  129. 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