@aguacerowx/react-native 0.0.37 → 0.0.39

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 (402) hide show
  1. package/README.md +126 -126
  2. package/aguacerowx-react-native.podspec +38 -38
  3. package/android/.gradle/buildOutputCleanup/cache.properties +2 -2
  4. package/android/build.gradle +107 -107
  5. package/android/src/main/AndroidManifest.xml +6 -6
  6. package/android/src/main/java/com/aguacerowx/reactnative/AguaceroPackage.java +33 -33
  7. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +688 -688
  8. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayerView.java +304 -304
  9. package/android/src/main/java/com/aguacerowx/reactnative/GridRenderManager.java +125 -125
  10. package/android/src/main/java/com/aguacerowx/reactnative/InspectorModule.java +71 -71
  11. package/android/src/main/java/com/aguacerowx/reactnative/ShaderUtils.java +106 -106
  12. package/android/src/main/java/com/aguacerowx/reactnative/WeatherFrameProcessorModule.java +151 -151
  13. package/android/src/main/res/raw/debug_fragment_shader.glsl +12 -12
  14. package/android/src/main/res/raw/debug_vertex_shader.glsl +12 -12
  15. package/android/src/main/res/raw/fragment_shader.glsl +180 -180
  16. package/android/src/main/res/raw/vertex_shader.glsl +19 -19
  17. package/index.js +2 -2
  18. package/ios/AguaceroPackage.m +18 -18
  19. package/ios/FragmentUniforms.swift +15 -15
  20. package/ios/GridRenderLayer.swift +1115 -1137
  21. package/ios/GridRenderLayerBridge.swift +44 -44
  22. package/ios/GridRenderLayerManager.mm +171 -157
  23. package/ios/GridRenderLayerView.h +30 -30
  24. package/ios/GridRenderLayerView.m +200 -200
  25. package/ios/InspectorDataCache.swift +63 -65
  26. package/ios/InspectorModule.m +9 -9
  27. package/ios/InspectorModule.swift +112 -63
  28. package/ios/Shaders.metal +319 -319
  29. package/ios/WeatherFrameProcessorModule.m +15 -15
  30. package/ios/WeatherFrameProcessorModule.swift +152 -103
  31. package/lib/commonjs/README.md +126 -126
  32. package/lib/commonjs/aguacerowx-react-native.podspec +38 -38
  33. package/lib/commonjs/android/build.gradle +107 -107
  34. package/lib/commonjs/android/src/main/AndroidManifest.xml +6 -6
  35. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/AguaceroPackage.java +33 -33
  36. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +688 -688
  37. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayerView.java +304 -304
  38. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/GridRenderManager.java +125 -125
  39. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/InspectorModule.java +71 -71
  40. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/ShaderUtils.java +106 -106
  41. package/lib/commonjs/android/src/main/java/com/aguacerowx/reactnative/WeatherFrameProcessorModule.java +151 -151
  42. package/lib/commonjs/android/src/main/res/raw/debug_fragment_shader.glsl +12 -12
  43. package/lib/commonjs/android/src/main/res/raw/debug_vertex_shader.glsl +12 -12
  44. package/lib/commonjs/android/src/main/res/raw/fragment_shader.glsl +180 -180
  45. package/lib/commonjs/android/src/main/res/raw/vertex_shader.glsl +19 -19
  46. package/lib/commonjs/babel.config.js.map +1 -1
  47. package/lib/commonjs/index.js.map +1 -1
  48. package/lib/commonjs/ios/AguaceroPackage.m +18 -18
  49. package/lib/commonjs/ios/FragmentUniforms.swift +15 -15
  50. package/lib/commonjs/ios/GridRenderLayer.swift +1115 -1137
  51. package/lib/commonjs/ios/GridRenderLayerBridge.swift +44 -44
  52. package/lib/commonjs/ios/GridRenderLayerManager.mm +171 -157
  53. package/lib/commonjs/ios/GridRenderLayerView.h +30 -30
  54. package/lib/commonjs/ios/GridRenderLayerView.m +200 -200
  55. package/lib/commonjs/ios/InspectorDataCache.swift +63 -65
  56. package/lib/commonjs/ios/InspectorModule.m +9 -9
  57. package/lib/commonjs/ios/InspectorModule.swift +112 -63
  58. package/lib/commonjs/ios/Shaders.metal +319 -319
  59. package/lib/commonjs/ios/WeatherFrameProcessorModule.m +15 -15
  60. package/lib/commonjs/ios/WeatherFrameProcessorModule.swift +152 -103
  61. package/lib/commonjs/package.json +72 -72
  62. package/lib/commonjs/react-native-builder-bob.config.js.map +1 -1
  63. package/lib/commonjs/scripts/compile-shaders.js.map +1 -1
  64. package/lib/commonjs/scripts/compile-shaders.sh +38 -38
  65. package/lib/commonjs/src/AguaceroContext.js.map +1 -1
  66. package/lib/commonjs/src/GridRenderLayer.js.map +1 -1
  67. package/lib/commonjs/src/GridRenderLayerNativeComponent.js.map +1 -1
  68. package/lib/commonjs/src/MapManager.js.map +1 -1
  69. package/lib/commonjs/src/MapRegistry.js.map +1 -1
  70. package/lib/commonjs/src/StyleApplicator.js +6 -6
  71. package/lib/commonjs/src/StyleApplicator.js.map +1 -1
  72. package/lib/commonjs/src/WeatherLayerManager.js +38 -3
  73. package/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  74. package/lib/commonjs/tsconfig.json +23 -23
  75. package/lib/module/README.md +126 -126
  76. package/lib/module/aguacerowx-react-native.podspec +38 -38
  77. package/lib/module/android/build.gradle +107 -107
  78. package/lib/module/android/src/main/AndroidManifest.xml +6 -6
  79. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/AguaceroPackage.java +33 -33
  80. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayer.java +688 -688
  81. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderLayerView.java +304 -304
  82. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/GridRenderManager.java +125 -125
  83. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/InspectorModule.java +71 -71
  84. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/ShaderUtils.java +106 -106
  85. package/lib/module/android/src/main/java/com/aguacerowx/reactnative/WeatherFrameProcessorModule.java +151 -151
  86. package/lib/module/android/src/main/res/raw/debug_fragment_shader.glsl +12 -12
  87. package/lib/module/android/src/main/res/raw/debug_vertex_shader.glsl +12 -12
  88. package/lib/module/android/src/main/res/raw/fragment_shader.glsl +180 -180
  89. package/lib/module/android/src/main/res/raw/vertex_shader.glsl +19 -19
  90. package/lib/module/babel.config.js.map +1 -1
  91. package/lib/module/index.js.map +1 -1
  92. package/lib/module/ios/AguaceroPackage.m +18 -18
  93. package/lib/module/ios/FragmentUniforms.swift +15 -15
  94. package/lib/module/ios/GridRenderLayer.swift +1115 -1137
  95. package/lib/module/ios/GridRenderLayerBridge.swift +44 -44
  96. package/lib/module/ios/GridRenderLayerManager.mm +171 -157
  97. package/lib/module/ios/GridRenderLayerView.h +30 -30
  98. package/lib/module/ios/GridRenderLayerView.m +200 -200
  99. package/lib/module/ios/InspectorDataCache.swift +63 -65
  100. package/lib/module/ios/InspectorModule.m +9 -9
  101. package/lib/module/ios/InspectorModule.swift +112 -63
  102. package/lib/module/ios/Shaders.metal +319 -319
  103. package/lib/module/ios/WeatherFrameProcessorModule.m +15 -15
  104. package/lib/module/ios/WeatherFrameProcessorModule.swift +152 -103
  105. package/lib/module/lib/commonjs/README.md +126 -126
  106. package/lib/module/lib/commonjs/aguacerowx-react-native.podspec +38 -38
  107. package/lib/module/lib/commonjs/babel.config.js.map +1 -1
  108. package/lib/module/lib/commonjs/index.js.map +1 -1
  109. package/lib/module/lib/commonjs/ios/GridRenderLayerBridge.swift +44 -44
  110. package/lib/module/lib/commonjs/ios/GridRenderLayerManager.mm +171 -157
  111. package/lib/module/lib/commonjs/ios/GridRenderLayerView.h +30 -30
  112. package/lib/module/lib/commonjs/ios/GridRenderLayerView.m +200 -200
  113. package/lib/module/lib/commonjs/ios/InspectorDataCache.swift +63 -65
  114. package/lib/module/lib/commonjs/ios/InspectorModule.m +9 -9
  115. package/lib/module/lib/commonjs/ios/InspectorModule.swift +112 -63
  116. package/lib/module/lib/commonjs/ios/Shaders.metal +319 -319
  117. package/lib/module/lib/commonjs/ios/WeatherFrameProcessorModule.m +15 -15
  118. package/lib/module/lib/commonjs/ios/WeatherFrameProcessorModule.swift +152 -103
  119. package/lib/module/lib/commonjs/package.json +72 -72
  120. package/lib/module/lib/commonjs/react-native-builder-bob.config.js.map +1 -1
  121. package/lib/module/lib/commonjs/scripts/compile-shaders.js.map +1 -1
  122. package/lib/module/lib/commonjs/scripts/compile-shaders.sh +38 -38
  123. package/lib/module/lib/commonjs/src/AguaceroContext.js.map +1 -1
  124. package/lib/module/lib/commonjs/src/GridRenderLayer.js.map +1 -1
  125. package/lib/module/lib/commonjs/src/GridRenderLayerNativeComponent.js.map +1 -1
  126. package/lib/module/lib/commonjs/src/MapManager.js.map +1 -1
  127. package/lib/module/lib/commonjs/src/MapRegistry.js.map +1 -1
  128. package/lib/module/lib/commonjs/src/StyleApplicator.js +6 -6
  129. package/lib/module/lib/commonjs/src/StyleApplicator.js.map +1 -1
  130. package/lib/module/lib/commonjs/src/WeatherLayerManager.js +38 -3
  131. package/lib/module/lib/commonjs/src/WeatherLayerManager.js.map +1 -1
  132. package/lib/module/lib/commonjs/tsconfig.json +23 -23
  133. package/lib/module/package.json +72 -72
  134. package/lib/module/react-native-builder-bob.config.js.map +1 -1
  135. package/lib/module/scripts/compile-shaders.js.map +1 -1
  136. package/lib/module/scripts/compile-shaders.sh +38 -38
  137. package/lib/module/src/AguaceroContext.js.map +1 -1
  138. package/lib/module/src/GridRenderLayer.js.map +1 -1
  139. package/lib/module/src/GridRenderLayerNativeComponent.js.map +1 -1
  140. package/lib/module/src/MapManager.js.map +1 -1
  141. package/lib/module/src/MapRegistry.js.map +1 -1
  142. package/lib/module/src/StyleApplicator.js +6 -6
  143. package/lib/module/src/StyleApplicator.js.map +1 -1
  144. package/lib/module/src/WeatherLayerManager.js +39 -3
  145. package/lib/module/src/WeatherLayerManager.js.map +1 -1
  146. package/lib/module/tsconfig.json +23 -23
  147. package/lib/typescript/src/WeatherLayerManager.d.ts.map +1 -1
  148. package/package.json +72 -72
  149. package/src/AguaceroContext.js +3 -3
  150. package/src/GridRenderLayer.js +215 -215
  151. package/src/GridRenderLayerNativeComponent.ts +15 -15
  152. package/src/MapManager.js +218 -218
  153. package/src/MapRegistry.js +34 -34
  154. package/src/StyleApplicator.js +240 -240
  155. package/src/WeatherLayerManager.js +1207 -1167
  156. package/android/build/.transforms/42e9b8fa82d77a1c205db5bf0d0ed519/results.bin +0 -1
  157. package/android/build/.transforms/42e9b8fa82d77a1c205db5bf0d0ed519/transformed/classes/classes_dex/classes.dex +0 -0
  158. package/android/build/.transforms/8f329a9571a96a1c1c0869d49784e448/results.bin +0 -1
  159. package/android/build/.transforms/8f329a9571a96a1c1c0869d49784e448/transformed/classes/classes_dex/classes.dex +0 -0
  160. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/results.bin +0 -1
  161. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/AguaceroPackage.dex +0 -0
  162. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/BuildConfig.dex +0 -0
  163. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.dex +0 -0
  164. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayer.dex +0 -0
  165. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderLayerView.dex +0 -0
  166. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/GridRenderManager.dex +0 -0
  167. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/InspectorModule.dex +0 -0
  168. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/ShaderUtils.dex +0 -0
  169. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/aguacerowx/reactnative/WeatherFrameProcessorModule.dex +0 -0
  170. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.dex +0 -0
  171. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.dex +0 -0
  172. package/android/build/.transforms/c8ab78b63f2cc835ac936d58e29a17ab/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  173. package/android/build/.transforms/f95abdfc98a7a06fc247f75cdd74def9/results.bin +0 -1
  174. package/android/build/.transforms/f95abdfc98a7a06fc247f75cdd74def9/transformed/classes/classes_dex/classes.dex +0 -0
  175. package/android/build/generated/source/buildConfig/debug/com/aguacerowx/reactnative/BuildConfig.java +0 -10
  176. package/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.java +0 -43
  177. package/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.java +0 -22
  178. package/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec-generated.cpp +0 -22
  179. package/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec.h +0 -24
  180. package/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  181. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI-generated.cpp +0 -17
  182. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI.h +0 -19
  183. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.cpp +0 -22
  184. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.h +0 -24
  185. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.cpp +0 -16
  186. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.h +0 -23
  187. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.cpp +0 -62
  188. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.h +0 -40
  189. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.cpp +0 -17
  190. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.h +0 -32
  191. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.cpp +0 -16
  192. package/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.h +0 -20
  193. package/android/build/generated/source/codegen/schema.json +0 -1
  194. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -8
  195. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  196. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  197. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  198. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  199. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  200. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -4
  201. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_fragment_shader.glsl.flat +0 -0
  202. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_vertex_shader.glsl.flat +0 -0
  203. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  204. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_vertex_shader.glsl.flat +0 -0
  205. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -5
  206. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  207. package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  208. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  209. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  210. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  211. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  212. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  213. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  214. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  215. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  216. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  217. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  218. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  219. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  220. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  221. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -6
  222. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -8
  223. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -8
  224. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  225. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  226. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_fragment_shader.glsl +0 -13
  227. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_vertex_shader.glsl +0 -13
  228. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +0 -181
  229. package/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/vertex_shader.glsl +0 -20
  230. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  231. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  232. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  233. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  234. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  235. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  236. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  237. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  238. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  239. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  240. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  241. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  242. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -5
  243. package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  244. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  245. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  246. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayerView.class.uniqueId2 +0 -0
  247. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  248. package/lib/commonjs/android/build/generated/source/buildConfig/debug/com/aguacerowx/reactnative/BuildConfig.java +0 -10
  249. package/lib/commonjs/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.java +0 -43
  250. package/lib/commonjs/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.java +0 -22
  251. package/lib/commonjs/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec-generated.cpp +0 -22
  252. package/lib/commonjs/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec.h +0 -24
  253. package/lib/commonjs/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  254. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI-generated.cpp +0 -17
  255. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI.h +0 -19
  256. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.cpp +0 -22
  257. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.h +0 -24
  258. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.cpp +0 -16
  259. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.h +0 -23
  260. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.cpp +0 -62
  261. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.h +0 -40
  262. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.cpp +0 -17
  263. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.h +0 -32
  264. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.cpp +0 -16
  265. package/lib/commonjs/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.h +0 -20
  266. package/lib/commonjs/android/build/generated/source/codegen/schema.json +0 -1
  267. package/lib/commonjs/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -8
  268. package/lib/commonjs/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  269. package/lib/commonjs/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  270. package/lib/commonjs/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  271. package/lib/commonjs/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  272. package/lib/commonjs/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  273. package/lib/commonjs/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -4
  274. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_fragment_shader.glsl.flat +0 -0
  275. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_vertex_shader.glsl.flat +0 -0
  276. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  277. package/lib/commonjs/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_vertex_shader.glsl.flat +0 -0
  278. package/lib/commonjs/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -5
  279. package/lib/commonjs/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  280. package/lib/commonjs/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  281. package/lib/commonjs/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  282. package/lib/commonjs/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  283. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  284. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  285. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  286. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  287. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  288. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  289. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  290. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  291. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  292. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  293. package/lib/commonjs/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  294. package/lib/commonjs/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -6
  295. package/lib/commonjs/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -8
  296. package/lib/commonjs/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -8
  297. package/lib/commonjs/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  298. package/lib/commonjs/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  299. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_fragment_shader.glsl +0 -13
  300. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_vertex_shader.glsl +0 -13
  301. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +0 -181
  302. package/lib/commonjs/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/vertex_shader.glsl +0 -20
  303. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  304. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  305. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  306. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  307. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  308. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  309. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  310. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  311. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  312. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  313. package/lib/commonjs/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  314. package/lib/commonjs/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  315. package/lib/commonjs/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -5
  316. package/lib/commonjs/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  317. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  318. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  319. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayerView.class.uniqueId2 +0 -0
  320. package/lib/commonjs/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  321. package/lib/module/android/build/generated/source/buildConfig/debug/com/aguacerowx/reactnative/BuildConfig.java +0 -10
  322. package/lib/module/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.java +0 -43
  323. package/lib/module/android/build/generated/source/codegen/java/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.java +0 -22
  324. package/lib/module/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec-generated.cpp +0 -22
  325. package/lib/module/android/build/generated/source/codegen/jni/AguaceroWxReactNativeSpec.h +0 -24
  326. package/lib/module/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  327. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI-generated.cpp +0 -17
  328. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/AguaceroWxReactNativeSpecJSI.h +0 -19
  329. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.cpp +0 -22
  330. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ComponentDescriptors.h +0 -24
  331. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.cpp +0 -16
  332. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/EventEmitters.h +0 -23
  333. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.cpp +0 -62
  334. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/Props.h +0 -40
  335. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.cpp +0 -17
  336. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/ShadowNodes.h +0 -32
  337. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.cpp +0 -16
  338. package/lib/module/android/build/generated/source/codegen/jni/react/renderer/components/AguaceroWxReactNativeSpec/States.h +0 -20
  339. package/lib/module/android/build/generated/source/codegen/schema.json +0 -1
  340. package/lib/module/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -8
  341. package/lib/module/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  342. package/lib/module/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  343. package/lib/module/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  344. package/lib/module/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  345. package/lib/module/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  346. package/lib/module/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -4
  347. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_fragment_shader.glsl.flat +0 -0
  348. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_debug_vertex_shader.glsl.flat +0 -0
  349. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_fragment_shader.glsl.flat +0 -0
  350. package/lib/module/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/raw_vertex_shader.glsl.flat +0 -0
  351. package/lib/module/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -5
  352. package/lib/module/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  353. package/lib/module/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  354. package/lib/module/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  355. package/lib/module/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  356. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  357. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  358. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  359. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  360. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  361. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  362. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  363. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  364. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  365. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  366. package/lib/module/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  367. package/lib/module/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -6
  368. package/lib/module/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -8
  369. package/lib/module/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -8
  370. package/lib/module/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  371. package/lib/module/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  372. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_fragment_shader.glsl +0 -13
  373. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/debug_vertex_shader.glsl +0 -13
  374. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/fragment_shader.glsl +0 -181
  375. package/lib/module/android/build/intermediates/packaged_res/debug/packageDebugResources/raw/vertex_shader.glsl +0 -20
  376. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/AguaceroPackage.class +0 -0
  377. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/BuildConfig.class +0 -0
  378. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer$VertexInfo.class +0 -0
  379. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayer.class +0 -0
  380. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderLayerView.class +0 -0
  381. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/GridRenderManager.class +0 -0
  382. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/InspectorModule.class +0 -0
  383. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/ShaderUtils.class +0 -0
  384. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/aguacerowx/reactnative/WeatherFrameProcessorModule.class +0 -0
  385. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerDelegate.class +0 -0
  386. package/lib/module/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/facebook/react/viewmanagers/GridRenderLayerManagerInterface.class +0 -0
  387. package/lib/module/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  388. package/lib/module/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -5
  389. package/lib/module/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  390. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer$VertexInfo.class.uniqueId0 +0 -0
  391. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayer.class.uniqueId1 +0 -0
  392. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/GridRenderLayerView.class.uniqueId2 +0 -0
  393. package/lib/module/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  394. package/lib/module/lib/commonjs/android/build.gradle +0 -108
  395. package/lib/module/lib/commonjs/android/src/main/AndroidManifest.xml +0 -7
  396. package/lib/module/lib/commonjs/ios/AguaceroPackage.m +0 -19
  397. package/lib/module/lib/commonjs/ios/FragmentUniforms.swift +0 -16
  398. package/lib/module/lib/commonjs/ios/GridRenderLayer.swift +0 -1137
  399. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-device.metallib +0 -0
  400. package/lib/module/lib/commonjs/ios/compiled-shaders/Shaders-simulator.metallib +0 -0
  401. package/lib/module/lib/commonjs/ios/generated/AguaceroWxReactNativeSpec-generated.mm +0 -0
  402. package/lib/module/lib/commonjs/ios/generated/AguaceroWxReactNativeSpec.h +0 -0
@@ -1,1137 +1,1115 @@
1
- import Foundation
2
- import MapboxMaps
3
- import Metal
4
- import libzstd
5
- import simd
6
-
7
- // MARK: - Swift-only wrapper for CustomLayerHost conformance
8
- @objc internal final class GridRenderLayerHost: NSObject, CustomLayerHost {
9
- weak var layer: GridRenderLayer?
10
-
11
- init(layer: GridRenderLayer) {
12
- self.layer = layer
13
- super.init()
14
- }
15
-
16
- func renderingWillStart(_ metalDevice: MTLDevice, colorPixelFormat: UInt, depthStencilPixelFormat: UInt) {
17
- layer?.internalRenderingWillStart(metalDevice, colorPixelFormat: colorPixelFormat, depthStencilPixelFormat: depthStencilPixelFormat)
18
- }
19
-
20
- func render(_ parameters: CustomLayerRenderParameters, mtlCommandBuffer: MTLCommandBuffer, mtlRenderPassDescriptor: MTLRenderPassDescriptor) {
21
- layer?.internalRender(parameters, mtlCommandBuffer: mtlCommandBuffer, mtlRenderPassDescriptor: mtlRenderPassDescriptor)
22
- }
23
-
24
- func renderingWillEnd() {
25
- layer?.internalRenderingWillEnd()
26
- }
27
- }
28
-
29
- @objc(GridRenderLayer)
30
- public class GridRenderLayer: NSObject {
31
-
32
- // MARK: - Properties
33
-
34
- public var id: String
35
- @objc internal var hostWrapper: GridRenderLayerHost!
36
-
37
- // Metal objects
38
- private var device: MTLDevice!
39
- private var commandQueue: MTLCommandQueue!
40
- private var pipelineState: MTLRenderPipelineState!
41
- private var vertexBuffer: MTLBuffer?
42
- private var indexBuffer: MTLBuffer?
43
- private var dataTexture: MTLTexture?
44
- private var colormapTexture: MTLTexture?
45
- private var dataSamplerState: MTLSamplerState!
46
- private var colormapSamplerState: MTLSamplerState!
47
- private var isDataSamplerLinear: Bool = false
48
-
49
- private var pendingColormapUpdate: String?
50
- private var pendingDataUpdate: (data: String, nx: NSNumber, ny: NSNumber, scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: String)?
51
- private var pendingGeometryUpdate: (corners: [String: Any], gridDef: [String: Any])?
52
-
53
- // Layer state
54
- private var indexCount: Int = 0
55
- private var uniforms = FragmentUniforms(
56
- opacity: 1.0,
57
- dataRange: SIMD2<Float>(0.0, 1.0),
58
- scale: 1.0,
59
- offset: 0.0,
60
- missingQuantized: 127.0,
61
- textureSize: SIMD2<Float>(0.0, 0.0),
62
- smoothing: 1,
63
- scaleType: 0,
64
- isPtype: 0,
65
- isMRMS: 0
66
- )
67
- private var isVisible = false
68
- private var pendingActiveFrameKey: String?
69
- private var lastRequestedCacheKey: String?
70
- private let inspectorCache = InspectorDataCache.shared
71
- private struct FrameMetadata {
72
- let scale: Float
73
- let offset: Float
74
- let missing: Float
75
- let scaleType: Int
76
- let nx: Float
77
- let ny: Float
78
- let filePath: String
79
- let originalScale: Float
80
- let originalOffset: Float
81
- var processedData: Data? // Cache the final transformed bytes
82
- }
83
- private var frameCache: [String: FrameMetadata] = [:]
84
- private let frameCacheQueue = DispatchQueue(label: "com.aguacero.frame-cache-queue")
85
- private let frameProcessingQueue = DispatchQueue(label: "com.aguacero.frame-processing", qos: .userInitiated, attributes: .concurrent)
86
- private let semaphore = DispatchSemaphore(value: 8)
87
-
88
- private struct VertexInfo {
89
- var mercX: Float
90
- var mercY: Float
91
- var texU: Float
92
- var texV: Float
93
- var index: UInt16
94
- }
95
- @objc
96
- public init(id: String) {
97
- self.id = id
98
- super.init()
99
- self.hostWrapper = GridRenderLayerHost(layer: self)
100
- }
101
-
102
- @objc public func getHostWrapper() -> Any {
103
- return self.hostWrapper as Any
104
- }
105
-
106
- // MARK: - Public Methods (called from Manager)
107
-
108
- @objc public func setOpacity(value: Float) {
109
- self.uniforms.opacity = value
110
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
111
- }
112
-
113
- @objc public func setDataRange(value: [NSNumber]) {
114
- self.uniforms.dataRange = SIMD2<Float>(value[0].floatValue, value[1].floatValue)
115
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
116
- }
117
-
118
- @objc public func setSmoothing(value: Bool) {
119
- self.uniforms.smoothing = value ? 1 : 0
120
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
121
- }
122
-
123
- @objc(setIsMRMSWithIsMRMS:)
124
- public func setIsMRMS(isMRMS: Bool) {
125
- self.uniforms.isMRMS = isMRMS ? 1 : 0
126
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
127
- }
128
-
129
- // ADD THIS METHOD
130
- @objc(setVariableWithVariable:)
131
- public func setVariable(variable: String) {
132
- let isPtypeVar = (variable == "ptypeRefl" || variable == "ptypeRate")
133
- self.uniforms.isPtype = isPtypeVar ? 1 : 0
134
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
135
- }
136
-
137
- @objc public func clear() {
138
- self.isVisible = false
139
- self.inspectorCache.clear()
140
- }
141
-
142
- @objc public func updateDataParameters(scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: NSNumber) { // ADD scaleType parameter
143
- // Update both the inspector cache AND the rendering uniforms
144
- self.uniforms.scale = scale.floatValue
145
- self.uniforms.offset = offset.floatValue
146
- self.uniforms.missingQuantized = missing.floatValue
147
- self.uniforms.scaleType = Int32(scaleType.intValue) // ADD THIS
148
-
149
- inspectorCache.update(
150
- data: inspectorCache.lastDecompressedData,
151
- nx: inspectorCache.nx,
152
- ny: inspectorCache.ny,
153
- scale: scale.floatValue,
154
- offset: offset.floatValue,
155
- missing: missing.floatValue,
156
- scaleType: scaleType.intValue // ADD THIS
157
- )
158
- }
159
-
160
- @objc public func updateColormapTexture(colormapAsBase64: String) {
161
- guard let device = self.device else {
162
- pendingColormapUpdate = colormapAsBase64
163
- return
164
- }
165
- guard let data = Data(base64Encoded: colormapAsBase64) else { return }
166
- let textureDescriptor = MTLTextureDescriptor()
167
- textureDescriptor.pixelFormat = .rgba8Unorm
168
- textureDescriptor.width = 256
169
- textureDescriptor.height = 1
170
- textureDescriptor.usage = .shaderRead
171
- guard let texture = device.makeTexture(descriptor: textureDescriptor) else { return }
172
- texture.replace(
173
- region: MTLRegionMake2D(0, 0, 256, 1),
174
- mipmapLevel: 0,
175
- withBytes: (data as NSData).bytes,
176
- bytesPerRow: 256 * 4
177
- )
178
- self.colormapTexture = texture
179
- }
180
-
181
- @objc(clearGpuCache)
182
- public func clearGpuCache() {
183
- print("ℹ️ [GridRenderLayer] clearGpuCache called")
184
- frameProcessingQueue.async { [weak self] in
185
- guard let self = self else { return }
186
- self.frameCacheQueue.async {
187
- self.frameCache.removeAll()
188
- }
189
- }
190
- }
191
-
192
- private func processRawData(fileData: Data) -> Data? {
193
- guard let decompressedDeltas = self.decompressZstd(data: fileData) else {
194
- print("❌ [GridRenderLayer] Failed to decompress zstd data")
195
- return nil
196
- }
197
- let reconstructedData = self.reconstructData(decompressedDeltas: decompressedDeltas)
198
- let finalTextureBytes = self.transformData(finalData: reconstructedData)
199
- return finalTextureBytes
200
- }
201
-
202
- private func createTextureFromBytes(bytes: Data, nx: Int, ny: Int) -> MTLTexture? {
203
- guard let device = self.device else { return nil }
204
- let textureDescriptor = MTLTextureDescriptor()
205
- textureDescriptor.pixelFormat = .r8Unorm
206
- textureDescriptor.width = nx
207
- textureDescriptor.height = ny
208
- textureDescriptor.usage = .shaderRead
209
-
210
- guard let texture = device.makeTexture(descriptor: textureDescriptor) else { return nil }
211
- texture.replace(
212
- region: MTLRegionMake2D(0, 0, nx, ny),
213
- mipmapLevel: 0,
214
- withBytes: (bytes as NSData).bytes,
215
- bytesPerRow: nx
216
- )
217
- return texture
218
- }
219
-
220
- private func updateInspectorCache(filePath: String, reconstructedData: Data?, nx: Int, ny: Int, scale: Float, offset: Float, missing: Float, scaleType: Int) {
221
- // This is now called from frameProcessingQueue, so we can do the work synchronously
222
-
223
- let finalReconstructedData: Data
224
- if let data = reconstructedData {
225
- finalReconstructedData = data
226
- } else {
227
- guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else {
228
- print("❌ [Inspector] FATAL: Failed to read file data from path.")
229
- self.inspectorCache.clear()
230
- return
231
- }
232
-
233
- guard let decompressedDeltas = self.decompressZstd(data: fileData) else {
234
- print("❌ [Inspector] FATAL: Failed to decompress Zstd data.")
235
- self.inspectorCache.clear()
236
- return
237
- }
238
- finalReconstructedData = self.reconstructData(decompressedDeltas: decompressedDeltas)
239
- }
240
-
241
- self.inspectorCache.update(
242
- data: finalReconstructedData,
243
- nx: nx,
244
- ny: ny,
245
- scale: scale,
246
- offset: offset,
247
- missing: missing,
248
- scaleType: scaleType
249
- )
250
- }
251
-
252
- @objc(setActiveFrameWithCacheKey:)
253
- public func setActiveFrame(cacheKey: String) {
254
- setActiveFrameInternal(cacheKey: cacheKey, isExternalRequest: true)
255
- }
256
-
257
- private func setActiveFrameInternal(cacheKey: String, isExternalRequest: Bool) {
258
- if isExternalRequest {
259
- lastRequestedCacheKey = cacheKey
260
- } else {
261
- // If it's an internal retry (from primeGpuCache),
262
- // only proceed if it's still the frame the user wants.
263
- if lastRequestedCacheKey != cacheKey {
264
- return
265
- }
266
- }
267
-
268
- var frameResult: FrameMetadata?
269
- frameCacheQueue.sync {
270
- frameResult = frameCache[cacheKey]
271
- }
272
-
273
- if let frame = frameResult {
274
- frameProcessingQueue.async { [weak self] in
275
- guard let self = self else { return }
276
-
277
- // Check if this frame is still the one we want
278
- if self.lastRequestedCacheKey != cacheKey { return }
279
-
280
- let finalTextureBytes: Data
281
- if let cachedData = frame.processedData {
282
- finalTextureBytes = cachedData
283
- } else {
284
- guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: frame.filePath)),
285
- let processed = self.processRawData(fileData: fileData)
286
- else {
287
- print("❌ [GridRenderLayer] Failed to load/process data for: \(cacheKey)")
288
- return
289
- }
290
- finalTextureBytes = processed
291
- self.frameCacheQueue.async {
292
- self.frameCache[cacheKey]?.processedData = finalTextureBytes
293
- }
294
- }
295
-
296
- // Final check before jumping to main thread
297
- if self.lastRequestedCacheKey != cacheKey { return }
298
-
299
- DispatchQueue.main.async { [weak self] in
300
- guard let self = self else { return }
301
-
302
- // Final check on main thread
303
- if self.lastRequestedCacheKey != cacheKey {
304
- return
305
- }
306
-
307
- let nx = Int(frame.nx)
308
- let ny = Int(frame.ny)
309
-
310
- if let existingTexture = self.dataTexture,
311
- existingTexture.width == nx,
312
- existingTexture.height == ny {
313
- existingTexture.replace(
314
- region: MTLRegionMake2D(0, 0, nx, ny),
315
- mipmapLevel: 0,
316
- withBytes: (finalTextureBytes as NSData).bytes,
317
- bytesPerRow: nx
318
- )
319
- } else {
320
- guard let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nx, ny: ny) else {
321
- return
322
- }
323
- self.dataTexture = texture
324
- }
325
-
326
- self.uniforms.scale = frame.scale
327
- self.uniforms.offset = frame.offset
328
- self.uniforms.missingQuantized = frame.missing
329
- self.uniforms.textureSize = SIMD2<Float>(frame.nx, frame.ny)
330
- self.uniforms.scaleType = Int32(frame.scaleType)
331
-
332
- self.isVisible = true
333
- self.pendingActiveFrameKey = nil
334
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
335
-
336
- self.frameProcessingQueue.async { [weak self] in
337
- self?.updateInspectorCache(
338
- filePath: frame.filePath,
339
- reconstructedData: nil,
340
- nx: nx,
341
- ny: ny,
342
- scale: frame.scale,
343
- offset: frame.offset,
344
- missing: frame.missing,
345
- scaleType: frame.scaleType
346
- )
347
- }
348
- }
349
- }
350
- } else {
351
- if isExternalRequest {
352
- self.pendingActiveFrameKey = cacheKey
353
- }
354
- }
355
- }
356
-
357
- @objc(primeGpuCacheWithFrameInfo:)
358
- public func primeGpuCache(frameInfo: [String: [String: Any]]) {
359
- print("ℹ️ [GridRenderLayer] primeGpuCache called with \(frameInfo.count) items")
360
- let group = DispatchGroup()
361
-
362
- for (cacheKey, info) in frameInfo {
363
- group.enter()
364
-
365
- frameProcessingQueue.async { [weak self] in
366
- guard let self = self else {
367
- group.leave()
368
- return
369
- }
370
-
371
- self.semaphore.wait()
372
- defer {
373
- self.semaphore.signal()
374
- group.leave()
375
- }
376
-
377
- let alreadyExists: Bool = self.frameCacheQueue.sync {
378
- return self.frameCache[cacheKey] != nil
379
- }
380
- if alreadyExists {
381
- print("ℹ️ [GridRenderLayer] Frame already cached: \(cacheKey)")
382
- return
383
- }
384
-
385
- guard let filePath = info["filePath"] as? String,
386
- let nx = info["nx"] as? NSNumber,
387
- let ny = info["ny"] as? NSNumber,
388
- let scale = info["scale"] as? NSNumber,
389
- let offset = info["offset"] as? NSNumber,
390
- let missing = info["missing"] as? NSNumber,
391
- let scaleTypeStr = info["scaleType"] as? String,
392
- let originalScale = info["originalScale"] as? NSNumber,
393
- let originalOffset = info["originalOffset"] as? NSNumber
394
- else {
395
- print("❌ [GridRenderLayer] Skipping prime for \(cacheKey), missing data. Info keys: \(info.keys)")
396
- return
397
- }
398
-
399
- let metadata = FrameMetadata(
400
- scale: scale.floatValue,
401
- offset: offset.floatValue,
402
- missing: missing.floatValue,
403
- scaleType: (scaleTypeStr == "sqrt") ? 1 : 0,
404
- nx: nx.floatValue,
405
- ny: ny.floatValue,
406
- filePath: filePath,
407
- originalScale: originalScale.floatValue,
408
- originalOffset: originalOffset.floatValue,
409
- processedData: nil
410
- )
411
-
412
- // Add to cache immediately so setActiveFrame can see it
413
- self.frameCacheQueue.async {
414
- self.frameCache[cacheKey] = metadata
415
- print("ℹ️ [GridRenderLayer] Primed cache key: \(cacheKey)")
416
- }
417
-
418
- // PERFORMANCE: Pre-process the data in the background
419
- if let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) {
420
- if let processedData = self.processRawData(fileData: fileData) {
421
- self.frameCacheQueue.async {
422
- self.frameCache[cacheKey]?.processedData = processedData
423
- }
424
- }
425
- }
426
-
427
- DispatchQueue.main.async {
428
- if let pendingKey = self.pendingActiveFrameKey, pendingKey == cacheKey {
429
- if self.lastRequestedCacheKey == cacheKey {
430
- print("ℹ️ [GridRenderLayer] Applying pending frame: \(cacheKey)")
431
- self.setActiveFrameInternal(cacheKey: pendingKey, isExternalRequest: false)
432
- }
433
- // Clear pending key if it matches what we just processed
434
- if self.pendingActiveFrameKey == cacheKey {
435
- self.pendingActiveFrameKey = nil
436
- }
437
- }
438
- }
439
- }
440
- }
441
- }
442
-
443
- @objc public func updateDataTexture(data: String, nx: NSNumber, ny: NSNumber, scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: String) {
444
- let filePath = data
445
-
446
- frameProcessingQueue.async { [weak self] in
447
- guard let self = self else { return }
448
-
449
- guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
450
- let finalTextureBytes = self.processRawData(fileData: fileData)
451
- else {
452
- print("❌ [GridRenderLayer] FAST LANE: Failed to process initial frame data.")
453
- return
454
- }
455
-
456
- DispatchQueue.main.async { [weak self] in
457
- guard let self = self else { return }
458
-
459
- let nxInt = nx.intValue
460
- let nyInt = ny.intValue
461
-
462
- // REUSE TEXTURE if dimensions match
463
- if let existingTexture = self.dataTexture,
464
- existingTexture.width == nxInt,
465
- existingTexture.height == nyInt {
466
- existingTexture.replace(
467
- region: MTLRegionMake2D(0, 0, nxInt, nyInt),
468
- mipmapLevel: 0,
469
- withBytes: (finalTextureBytes as NSData).bytes,
470
- bytesPerRow: nxInt
471
- )
472
- } else {
473
- // Create new texture only if needed
474
- guard let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nxInt, ny: nyInt) else {
475
- print("❌ [GridRenderLayer] FAST LANE: Failed to create texture")
476
- return
477
- }
478
- self.dataTexture = texture
479
- }
480
-
481
- self.uniforms.scale = scale.floatValue
482
- self.uniforms.offset = offset.floatValue
483
- self.uniforms.missingQuantized = missing.floatValue
484
- self.uniforms.scaleType = Int32((scaleType == "sqrt") ? 1 : 0)
485
- self.uniforms.textureSize = SIMD2<Float>(nx.floatValue, ny.floatValue)
486
-
487
- self.isVisible = true
488
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
489
-
490
- self.updateInspectorCache(
491
- filePath: filePath,
492
- reconstructedData: nil,
493
- nx: nx.intValue,
494
- ny: ny.intValue,
495
- scale: scale.floatValue,
496
- offset: offset.floatValue,
497
- missing: missing.floatValue,
498
- scaleType: (scaleType == "sqrt") ? 1 : 0
499
- )
500
- }
501
- }
502
- }
503
-
504
- @objc public func updateGeometry(corners: [String: Any], gridDef: [String: Any]) {
505
- guard self.device != nil else {
506
- print("⚠️ [GridRenderLayer] Device not ready yet, storing geometry for later")
507
- pendingGeometryUpdate = (corners: corners, gridDef: gridDef)
508
- return
509
- }
510
-
511
- DispatchQueue.global(qos: .userInitiated).async {
512
-
513
- var vertices: [Float] = []
514
- var indices: [UInt16] = []
515
-
516
- self.generateGeometryData(gridDef: gridDef, vertices: &vertices, indices: &indices)
517
-
518
- if vertices.isEmpty || indices.isEmpty {
519
- print("❌ [GridRenderLayer] No geometry generated")
520
- return
521
- }
522
-
523
- self.indexCount = indices.count
524
-
525
- DispatchQueue.main.async {
526
- self.vertexBuffer = self.device.makeBuffer(bytes: vertices, length: vertices.count * MemoryLayout<Float>.size, options: [])
527
- self.indexBuffer = self.device.makeBuffer(bytes: indices, length: indices.count * MemoryLayout<UInt16>.size, options: [])
528
-
529
- NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
530
- }
531
- }
532
- }
533
-
534
- private func decompressZstd(data: Data) -> Data? {
535
- let decompressedSize = data.withUnsafeBytes { ptr in
536
- ZSTD_getFrameContentSize(ptr.baseAddress, data.count)
537
- }
538
-
539
- guard Int64(bitPattern: decompressedSize) > 0 else {
540
- print("❌ [GridRenderLayer] Could not determine decompressed size")
541
- return nil
542
- }
543
-
544
- var decompressedData = Data(count: Int(decompressedSize))
545
-
546
- let result = decompressedData.withUnsafeMutableBytes { decompressedPtr -> Int in
547
- data.withUnsafeBytes { compressedPtr -> Int in
548
- let returnValue = ZSTD_decompress(
549
- decompressedPtr.baseAddress,
550
- Int(decompressedSize),
551
- compressedPtr.baseAddress,
552
- data.count
553
- )
554
- return Int(returnValue)
555
- }
556
- }
557
-
558
- guard result > 0 && result == decompressedData.count else {
559
- if result > 0 {
560
- let size_t_result = size_t(result)
561
- if let errorName = ZSTD_getErrorName(size_t_result) {
562
- let errorString = String(cString: errorName)
563
- print("❌ [GridRenderLayer] Zstd decompression failed: \(errorString)")
564
- }
565
- }
566
- return nil
567
- }
568
- return decompressedData
569
- }
570
-
571
- // MARK: - Private Helper Methods
572
-
573
- private func reconstructData(decompressedDeltas: Data) -> Data {
574
- guard !decompressedDeltas.isEmpty else { return Data() }
575
- var reconstructedData = Data(count: decompressedDeltas.count)
576
- reconstructedData[0] = decompressedDeltas[0]
577
- for i in 1..<decompressedDeltas.count {
578
- reconstructedData[i] = UInt8(Int8(bitPattern: reconstructedData[i-1]) &+ Int8(bitPattern: decompressedDeltas[i]))
579
- }
580
- return reconstructedData
581
- }
582
-
583
- private func transformData(finalData: Data) -> Data {
584
- var transformedData = Data(count: finalData.count)
585
- for i in 0..<finalData.count {
586
- transformedData[i] = UInt8(Int16(Int8(bitPattern: finalData[i])) + 128)
587
- }
588
- return transformedData
589
- }
590
-
591
- private func isLCCType(gridDef: [String: Any]) -> Bool {
592
- if let type = gridDef["type"] as? String {
593
- return type == "lambert_conformal_conic"
594
- }
595
- return false
596
- }
597
-
598
- private func generateLCCGeometry(gridDef: [String: Any], vertices: inout [Float], indices: inout [UInt16]) {
599
- guard let gridParams = gridDef["grid_params"] as? [String: Any],
600
- let projParams = gridDef["proj_params"] as? [String: Any],
601
- let nx = gridParams["nx"] as? Int,
602
- let ny = gridParams["ny"] as? Int,
603
- let dx = gridParams["dx"] as? Double,
604
- let dy = gridParams["dy"] as? Double,
605
- let x_origin = gridParams["x_origin"] as? Double,
606
- let y_origin = gridParams["y_origin"] as? Double else {
607
- return
608
- }
609
-
610
- let subdivisions = 60
611
- let TILE_SIZE: Double = 512.0
612
-
613
- let x_min = x_origin
614
- let y_max = y_origin
615
- let x_max = x_origin + Double(nx - 1) * dx
616
- let y_min = y_origin + Double(ny - 1) * dy
617
-
618
- var vertexGrid: [[VertexInfo?]] = Array(repeating: Array(repeating: nil, count: subdivisions + 1), count: subdivisions + 1)
619
- var validVertexCount: UInt16 = 0
620
-
621
- // Generate vertices
622
- for row in 0...subdivisions {
623
- for col in 0...subdivisions {
624
- let t_x = Double(col) / Double(subdivisions)
625
- let t_y = Double(row) / Double(subdivisions)
626
-
627
- let proj_x = x_min + t_x * (x_max - x_min)
628
- let proj_y = y_max + t_y * (y_min - y_max)
629
-
630
- // Convert LCC projection coordinates to lat/lon
631
- if let (lon, lat) = lccToLonLat(i: proj_x, j: proj_y, gridDef: gridDef) {
632
- // Convert lat/lon to Mercator
633
- let mercX_normalized = (lon + 180.0) / 360.0
634
- let clampedLat = max(-85.05112878, min(85.05112878, lat))
635
- let sinLatitude = sin(clampedLat * .pi / 180.0)
636
- let mercY_normalized = 0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * .pi)
637
-
638
- let mercX = mercX_normalized * TILE_SIZE
639
- let mercY = mercY_normalized * TILE_SIZE
640
-
641
- // Check for invalid values
642
- if !mercX.isFinite || !mercY.isFinite {
643
- vertexGrid[row][col] = nil
644
- continue
645
- }
646
-
647
- let tex_u = Float(t_x)
648
- let tex_v = Float(t_y)
649
-
650
- let vInfo = VertexInfo(
651
- mercX: Float(mercX),
652
- mercY: Float(mercY),
653
- texU: tex_u,
654
- texV: tex_v,
655
- index: validVertexCount
656
- )
657
-
658
- vertexGrid[row][col] = vInfo
659
-
660
- vertices.append(Float(mercX))
661
- vertices.append(Float(mercY))
662
- vertices.append(tex_u)
663
- vertices.append(tex_v)
664
-
665
- validVertexCount += 1
666
- } else {
667
- vertexGrid[row][col] = nil
668
- }
669
- }
670
- }
671
-
672
- if vertices.isEmpty {
673
- print("❌ [LCC Geometry] No valid vertices generated")
674
- return
675
- }
676
-
677
- // Generate indices
678
- for row in 0..<subdivisions {
679
- for col in 0..<subdivisions {
680
- guard let topLeft = vertexGrid[row][col],
681
- let topRight = vertexGrid[row][col + 1],
682
- let bottomLeft = vertexGrid[row + 1][col],
683
- let bottomRight = vertexGrid[row + 1][col + 1] else {
684
- continue
685
- }
686
-
687
- indices.append(topLeft.index)
688
- indices.append(bottomLeft.index)
689
- indices.append(topRight.index)
690
-
691
- indices.append(topRight.index)
692
- indices.append(bottomLeft.index)
693
- indices.append(bottomRight.index)
694
- }
695
- }
696
- }
697
-
698
- private func lccToLonLat(i: Double, j: Double, gridDef: [String: Any]) -> (lon: Double, lat: Double)? {
699
- guard let projParams = gridDef["proj_params"] as? [String: Any],
700
- let lat_0 = (projParams["lat_0"] as? NSNumber)?.doubleValue,
701
- let lon_0 = (projParams["lon_0"] as? NSNumber)?.doubleValue,
702
- let lat_1 = (projParams["lat_1"] as? NSNumber)?.doubleValue,
703
- let lat_2 = (projParams["lat_2"] as? NSNumber)?.doubleValue,
704
- let r_earth = (projParams["R"] as? NSNumber)?.doubleValue else {
705
- print("❌ [LCC Geometry] Failed to extract LCC parameters.")
706
- return nil
707
- }
708
-
709
- let π = Double.pi
710
- let toRad = π / 180.0
711
- let toDeg = 180.0 / π
712
-
713
- let lat1_rad = lat_1 * toRad
714
- let lat2_rad = lat_2 * toRad
715
- let lat0_rad = lat_0 * toRad
716
- let lon0_rad = lon_0 * toRad
717
-
718
- let n: Double
719
- if abs(lat_1 - lat_2) < 1e-10 {
720
- n = sin(lat1_rad)
721
- } else {
722
- n = log(cos(lat1_rad) / cos(lat2_rad)) / log(tan(π/4.0 + lat2_rad/2.0) / tan(π/4.0 + lat1_rad/2.0))
723
- }
724
-
725
- let F = cos(lat1_rad) * pow(tan(π/4.0 + lat1_rad/2.0), n) / n
726
- let rho_0 = r_earth * F * pow(tan(π/4.0 + lat0_rad/2.0), -n)
727
-
728
- let x = i
729
- let y = j
730
-
731
- let rho = sqrt(x * x + (rho_0 - y) * (rho_0 - y))
732
- if rho < 1e-10 {
733
- return (lon: lon_0, lat: lat_0)
734
- }
735
-
736
- let theta = atan2(x, rho_0 - y)
737
-
738
- let lon = lon0_rad + theta / n
739
- let lat = 2.0 * atan(pow(r_earth * F / rho, 1.0 / n)) - π/2.0
740
-
741
- let lonDeg = lon * toDeg
742
- let latDeg = lat * toDeg
743
-
744
- if !lonDeg.isFinite || !latDeg.isFinite {
745
- return nil
746
- }
747
-
748
- return (lon: lonDeg, lat: latDeg)
749
- }
750
-
751
- private func generateGeometryData(gridDef: [String: Any], vertices: inout [Float], indices: inout [UInt16]) {
752
- guard let gridParams = gridDef["grid_params"] as? [String: Any] else {
753
- print("❌ [generateGeometryData] No grid_params found")
754
- return
755
- }
756
-
757
- // Check grid type
758
- let isGFS = isGFSType(gridParams: gridParams)
759
- let isLCC = isLCCType(gridDef: gridDef)
760
-
761
- if isGFS {
762
- // GFS path remains unchanged
763
- let subdivisions = 120
764
- let verticesPerRow = (subdivisions * 3) + 1
765
- let TILE_SIZE: Double = 512.0
766
-
767
- for row in 0...subdivisions {
768
- for col in 0...(subdivisions * 3) {
769
- let v_interp = Float(row) / Float(subdivisions)
770
- let u_interp = Float(col) / Float(subdivisions)
771
- let lon = -540.0 + Double(u_interp) * 1080.0
772
- let lat = -90.0 + Double(v_interp) * 180.0
773
-
774
- let merc = lonLatToMercator(lon: lon, lat: lat, tileSize: TILE_SIZE)
775
- vertices.append(contentsOf: [merc.x, merc.y])
776
-
777
- let tex_u = Float((lon + 180.0) / 360.0)
778
- let tex_v = 1.0 - v_interp
779
- vertices.append(contentsOf: [tex_u, tex_v])
780
- }
781
- }
782
-
783
- for row in 0..<subdivisions {
784
- for col in 0..<(subdivisions * 3) {
785
- let tl = UInt16(row * verticesPerRow + col)
786
- let tr = tl + 1
787
- let bl = UInt16((row + 1) * verticesPerRow + col)
788
- let br = bl + 1
789
- indices.append(contentsOf: [tl, bl, tr, tr, bl, br])
790
- }
791
- }
792
- return
793
- }
794
-
795
- if isLCC {
796
- generateLCCGeometry(gridDef: gridDef, vertices: &vertices, indices: &indices)
797
- return
798
- }
799
-
800
- let nx = gridParams["nx"] as? Int ?? 0
801
- let ny = gridParams["ny"] as? Int ?? 0
802
- let lon_first = gridParams["lon_first"] as? Double ?? 0.0
803
- let lat_first = gridParams["lat_first"] as? Double ?? 90.0
804
- let dx = gridParams["dx_degrees"] as? Double ?? 0.0
805
- let dy = gridParams["dy_degrees"] as? Double ?? 0.0
806
- let lon_last = gridParams["lon_last"] as? Double ?? (lon_first + Double(nx - 1) * dx)
807
- let lat_last = gridParams["lat_last"] as? Double ?? (lat_first + Double(ny - 1) * dy)
808
-
809
- let lat_span = lat_last - lat_first
810
- let isSouthToNorth = lat_span > 0
811
-
812
- // Check if this is ECMWF and normalize longitudes
813
- let isECMWF = isECMWFType(gridParams: gridParams)
814
- var data_lon_first_180 = lon_first
815
- var data_lon_last_180 = lon_last
816
-
817
- if isECMWF {
818
- // Convert ECMWF's 180 to -180 range to -180 to 180
819
- data_lon_first_180 = lon_first >= 180 ? lon_first - 360 : lon_first
820
- data_lon_last_180 = lon_last >= 180 ? lon_last - 360 : lon_last
821
- } else {
822
- // For GFS and other models
823
- data_lon_first_180 = lon_first > 180 ? lon_first - 360 : lon_first
824
- data_lon_last_180 = lon_last > 180 ? lon_last - 360 : lon_last
825
- }
826
-
827
- let data_lon_range = data_lon_last_180 - data_lon_first_180
828
-
829
- let subdivisions_x = 120
830
- let subdivisions_y = 60
831
- let verticesPerRow = subdivisions_x + 1
832
- let TILE_SIZE: Double = 512.0
833
-
834
- let worldCopies = (data_lon_range > 300) ? [-1, 0, 1] : [0]
835
-
836
- for world_copy in worldCopies {
837
- let vertexStartIndex = UInt16(vertices.count / 4)
838
- let lon_offset = Double(world_copy) * 360.0
839
-
840
- for row in 0...subdivisions_y {
841
- for col in 0...subdivisions_x {
842
- let v_interp = Float(row) / Float(subdivisions_y)
843
- let u_interp = Float(col) / Float(subdivisions_x)
844
-
845
- let vertex_lon = data_lon_first_180 + (Double(u_interp) * data_lon_range)
846
- let vertex_lat = lat_first + (Double(v_interp) * lat_span)
847
-
848
- let mercX_normalized = ((vertex_lon + lon_offset) + 180.0) / 360.0
849
- let clampedLat = max(-85.05112878, min(85.05112878, vertex_lat))
850
- let sinLatitude = sin(clampedLat * .pi / 180.0)
851
- let mercY_normalized = 0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * .pi)
852
- let mercX = mercX_normalized * TILE_SIZE
853
- let mercY = mercY_normalized * TILE_SIZE
854
-
855
- vertices.append(contentsOf: [Float(mercX), Float(mercY)])
856
-
857
- let tex_u = u_interp
858
- let tex_v = isSouthToNorth ? (1.0 - v_interp) : v_interp
859
-
860
- vertices.append(contentsOf: [tex_u, tex_v])
861
- }
862
- }
863
-
864
- for row in 0..<UInt16(subdivisions_y) {
865
- for col in 0..<UInt16(subdivisions_x) {
866
- let tl = vertexStartIndex + row * UInt16(verticesPerRow) + col
867
- let tr = tl + 1
868
- let bl = vertexStartIndex + (row + 1) * UInt16(verticesPerRow) + col
869
- let br = bl + 1
870
-
871
- if isSouthToNorth {
872
- indices.append(contentsOf: [tl, bl, tr, tr, bl, br])
873
- } else {
874
- indices.append(contentsOf: [tl, tr, bl, bl, tr, br])
875
- }
876
- }
877
- }
878
- }
879
- }
880
-
881
- private func isGFSType(gridParams: [String: Any]) -> Bool {
882
- return (gridParams["lon_first"] as? Double) == 0.0 &&
883
- abs((gridParams["lat_first"] as? Double) ?? -1) == 90.0
884
- }
885
-
886
- private func isECMWFType(gridParams: [String: Any]) -> Bool {
887
- return (gridParams["lon_first"] as? Double) == 180.0 &&
888
- (gridParams["lat_first"] as? Double) == 90.0
889
- }
890
-
891
- private func lonLatToMercator(lon: Double, lat: Double, tileSize: Double) -> (x: Float, y: Float) {
892
- let mercX_normalized = (lon + 180.0) / 360.0
893
- let clampedLat = max(-85.05112878, min(85.05112878, lat))
894
- let sinLatitude = sin(clampedLat * .pi / 180.0)
895
- let mercY_normalized = 0.5 - log((1.0 + sinLatitude) / (1.0 - sinLatitude)) / (4.0 * .pi)
896
-
897
- return (x: Float(mercX_normalized * tileSize), y: Float(mercY_normalized * tileSize))
898
- }
899
-
900
- // MARK: - Internal methods for CustomLayerHost (called by wrapper)
901
-
902
- internal func internalRenderingWillStart(_ metalDevice: MTLDevice, colorPixelFormat: UInt, depthStencilPixelFormat: UInt) {
903
- self.device = metalDevice
904
- self.commandQueue = metalDevice.makeCommandQueue()
905
-
906
- let bundle = Bundle(for: GridRenderLayer.self)
907
-
908
- // Determine if we're running on simulator or device
909
- #if targetEnvironment(simulator)
910
- let metallibName = "Shaders-simulator"
911
- #else
912
- let metallibName = "Shaders-device"
913
- #endif
914
-
915
- // Try to load pre-compiled metallib for the current platform
916
- var defaultLibrary: MTLLibrary?
917
-
918
- // 1. Look in the main bundle level
919
- if let metallibUrl = bundle.url(forResource: metallibName, withExtension: "metallib") {
920
- print("ℹ️ [GridRenderLayer] Found pre-compiled shaders at: \(metallibUrl.lastPathComponent)")
921
- defaultLibrary = try? metalDevice.makeLibrary(URL: metallibUrl)
922
- }
923
-
924
- // 2. Fall back to compiled-shaders subdirectory
925
- if defaultLibrary == nil {
926
- if let metallibUrl = bundle.url(forResource: metallibName, withExtension: "metallib", subdirectory: "compiled-shaders") {
927
- print("ℹ️ [GridRenderLayer] Found pre-compiled shaders in subdirectory: \(metallibUrl.lastPathComponent)")
928
- defaultLibrary = try? metalDevice.makeLibrary(URL: metallibUrl)
929
- }
930
- }
931
-
932
- // 3. Fall back to compiling from .metal source (for development with npm link)
933
- if defaultLibrary == nil {
934
- if let metalUrl = bundle.url(forResource: "Shaders", withExtension: "metal") {
935
- print("⚠️ [GridRenderLayer] Pre-compiled shaders not found. Compiling from source: \(metalUrl.lastPathComponent)")
936
- if let source = try? String(contentsOf: metalUrl),
937
- let library = try? metalDevice.makeLibrary(source: source, options: nil) {
938
- defaultLibrary = library
939
- }
940
- }
941
- }
942
-
943
- // Neither worked
944
- if defaultLibrary == nil {
945
- print("❌ [GridRenderLayer] Could not find or compile Metal shaders")
946
- print(" Bundle path: \(bundle.bundlePath)")
947
- return
948
- }
949
-
950
- guard let library = defaultLibrary else {
951
- print("❌ [GridRenderLayer] Failed to create Metal library")
952
- return
953
- }
954
-
955
- let vertexFunction = library.makeFunction(name: "vertex_main")
956
- let fragmentFunction = library.makeFunction(name: "fragment_main")
957
-
958
- // Set up vertex descriptor
959
- let vertexDescriptor = MTLVertexDescriptor()
960
- vertexDescriptor.attributes[0].format = .float2 // position (x, y)
961
- vertexDescriptor.attributes[0].offset = 0
962
- vertexDescriptor.attributes[0].bufferIndex = 0
963
-
964
- vertexDescriptor.attributes[1].format = .float2 // texCoord (u, v)
965
- vertexDescriptor.attributes[1].offset = MemoryLayout<Float>.size * 2
966
- vertexDescriptor.attributes[1].bufferIndex = 0
967
-
968
- vertexDescriptor.layouts[0].stride = MemoryLayout<Float>.size * 4 // 2 floats for pos + 2 for texCoord
969
- vertexDescriptor.layouts[0].stepFunction = .perVertex
970
-
971
- let pipelineDescriptor = MTLRenderPipelineDescriptor()
972
- pipelineDescriptor.vertexDescriptor = vertexDescriptor
973
- pipelineDescriptor.vertexFunction = vertexFunction
974
- pipelineDescriptor.fragmentFunction = fragmentFunction
975
-
976
- pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat(rawValue: colorPixelFormat) ?? .bgra8Unorm
977
- pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormat(rawValue: depthStencilPixelFormat) ?? .depth32Float_stencil8
978
- pipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormat(rawValue: depthStencilPixelFormat) ?? .depth32Float_stencil8
979
-
980
- pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
981
- pipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
982
- pipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
983
- pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
984
- pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
985
- pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
986
- pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
987
-
988
- do {
989
- self.pipelineState = try metalDevice.makeRenderPipelineState(descriptor: pipelineDescriptor)
990
- } catch {
991
- print("❌ [GridRenderLayer] Failed to create pipeline state: \(error)")
992
- return
993
- }
994
-
995
- let dataSamplerDesc = MTLSamplerDescriptor()
996
- dataSamplerDesc.minFilter = .nearest
997
- dataSamplerDesc.magFilter = .nearest
998
- self.dataSamplerState = metalDevice.makeSamplerState(descriptor: dataSamplerDesc)
999
-
1000
- let colormapSamplerDesc = MTLSamplerDescriptor()
1001
- colormapSamplerDesc.minFilter = .nearest
1002
- colormapSamplerDesc.magFilter = .nearest
1003
- colormapSamplerDesc.sAddressMode = .clampToEdge
1004
- self.colormapSamplerState = metalDevice.makeSamplerState(descriptor: colormapSamplerDesc)
1005
-
1006
- // Process any pending updates that came in before Metal was ready
1007
- if let pendingGeometry = pendingGeometryUpdate {
1008
- updateGeometry(corners: pendingGeometry.corners, gridDef: pendingGeometry.gridDef)
1009
- pendingGeometryUpdate = nil
1010
- }
1011
-
1012
- if let pendingColormap = pendingColormapUpdate {
1013
- updateColormapTexture(colormapAsBase64: pendingColormap)
1014
- pendingColormapUpdate = nil
1015
- }
1016
-
1017
- if let pendingData = pendingDataUpdate {
1018
- updateDataTexture(data: pendingData.data, nx: pendingData.nx, ny: pendingData.ny,
1019
- scale: pendingData.scale, offset: pendingData.offset,
1020
- missing: pendingData.missing, scaleType: pendingData.scaleType)
1021
- pendingDataUpdate = nil
1022
- }
1023
- }
1024
- internal func internalRender(_ parameters: CustomLayerRenderParameters, mtlCommandBuffer: MTLCommandBuffer, mtlRenderPassDescriptor: MTLRenderPassDescriptor) {
1025
- guard isVisible,
1026
- let pipeline = pipelineState,
1027
- let vertices = vertexBuffer,
1028
- let indices = indexBuffer,
1029
- let dataTex = dataTexture,
1030
- let colormapTex = colormapTexture,
1031
- indexCount > 0,
1032
- let encoder = mtlCommandBuffer.makeRenderCommandEncoder(descriptor: mtlRenderPassDescriptor) else {
1033
-
1034
- return
1035
- }
1036
-
1037
- let needsLinear = (uniforms.smoothing != 0)
1038
- if isDataSamplerLinear != needsLinear {
1039
- let samplerDesc = MTLSamplerDescriptor()
1040
- samplerDesc.minFilter = needsLinear ? .linear : .nearest
1041
- samplerDesc.magFilter = needsLinear ? .linear : .nearest
1042
- dataSamplerState = device.makeSamplerState(descriptor: samplerDesc)
1043
- isDataSamplerLinear = needsLinear
1044
- }
1045
-
1046
- // Apply zoom scale transformation
1047
- let zoom = parameters.zoom
1048
- let scale = Float(pow(2.0, zoom))
1049
-
1050
- let matrixArray = parameters.projectionMatrix
1051
- var floatArray = matrixArray.map { $0.floatValue }
1052
-
1053
- floatArray[0] *= scale // X scale
1054
- floatArray[1] *= scale // X rotation
1055
- floatArray[2] *= scale // X Z-component
1056
- floatArray[3] *= scale // X translation
1057
- floatArray[4] *= scale // Y rotation
1058
- floatArray[5] *= scale // Y scale
1059
- floatArray[6] *= scale // Y Z-component
1060
- floatArray[7] *= scale // Y translation
1061
- floatArray[8] *= scale // Z X-component
1062
- floatArray[9] *= scale // Z Y-component
1063
- floatArray[10] *= scale // Z scale
1064
- floatArray[11] *= scale // Z translation
1065
-
1066
- let mvp = matrix_float4x4(
1067
- SIMD4<Float>(floatArray[0], floatArray[1], floatArray[2], floatArray[3]),
1068
- SIMD4<Float>(floatArray[4], floatArray[5], floatArray[6], floatArray[7]),
1069
- SIMD4<Float>(floatArray[8], floatArray[9], floatArray[10], floatArray[11]),
1070
- SIMD4<Float>(floatArray[12], floatArray[13], floatArray[14], floatArray[15])
1071
- )
1072
-
1073
- // Add depth state
1074
- let depthStencilDescriptor = MTLDepthStencilDescriptor()
1075
- depthStencilDescriptor.depthCompareFunction = .always
1076
- depthStencilDescriptor.isDepthWriteEnabled = false
1077
- let depthStencilState = device.makeDepthStencilState(descriptor: depthStencilDescriptor)
1078
-
1079
- encoder.setRenderPipelineState(pipeline)
1080
- encoder.setDepthStencilState(depthStencilState!)
1081
- encoder.setVertexBuffer(vertices, offset: 0, index: 0)
1082
- encoder.setVertexBytes([mvp], length: MemoryLayout<matrix_float4x4>.size, index: 1)
1083
-
1084
- var mutableUniforms = uniforms
1085
- encoder.setFragmentBytes(&mutableUniforms, length: MemoryLayout<FragmentUniforms>.stride, index: 0)
1086
- encoder.setFragmentTexture(dataTex, index: 0)
1087
- encoder.setFragmentTexture(colormapTex, index: 1)
1088
- encoder.setFragmentSamplerState(dataSamplerState, index: 0)
1089
- encoder.setFragmentSamplerState(colormapSamplerState, index: 1)
1090
-
1091
- encoder.drawIndexedPrimitives(type: .triangle, indexCount: indexCount, indexType: .uint16, indexBuffer: indices, indexBufferOffset: 0)
1092
-
1093
- encoder.endEncoding()
1094
- }
1095
-
1096
- deinit {
1097
- print("🔴 [GridRenderLayer] deinit called for layer: \(id)")
1098
-
1099
- // Clean up all resources
1100
- frameCacheQueue.sync {
1101
- frameCache.removeAll()
1102
- }
1103
- vertexBuffer = nil
1104
- indexBuffer = nil
1105
- dataTexture = nil
1106
- colormapTexture = nil
1107
- device = nil
1108
- commandQueue = nil
1109
- pipelineState = nil
1110
- dataSamplerState = nil
1111
- colormapSamplerState = nil
1112
-
1113
- // Break the reference cycle
1114
- hostWrapper = nil
1115
- }
1116
-
1117
- internal func internalRenderingWillEnd() {
1118
- // DO NOT clear these here, otherwise the layer disappears during map transitions/resizing
1119
- // vertexBuffer = nil
1120
- // indexBuffer = nil
1121
- // dataTexture = nil
1122
- // colormapTexture = nil
1123
- }
1124
- }
1125
-
1126
- extension GridRenderLayer {
1127
- // Override to prevent KVC crashes during cleanup
1128
- open override func value(forUndefinedKey key: String) -> Any? {
1129
- print("⚠️ [GridRenderLayer] Attempted to access undefined key: \(key)")
1130
- return nil
1131
- }
1132
-
1133
- open override func setValue(_ value: Any?, forUndefinedKey key: String) {
1134
- print("⚠️ [GridRenderLayer] Attempted to set undefined key: \(key)")
1135
- // Silently ignore instead of crashing
1136
- }
1137
- }
1
+ import Foundation
2
+ import MapboxMaps
3
+ import Metal
4
+ import libzstd
5
+ import simd
6
+
7
+ // MARK: - Swift-only wrapper for CustomLayerHost conformance
8
+ @objc internal final class GridRenderLayerHost: NSObject, CustomLayerHost {
9
+ weak var layer: GridRenderLayer?
10
+
11
+ init(layer: GridRenderLayer) {
12
+ self.layer = layer
13
+ super.init()
14
+ }
15
+
16
+ func renderingWillStart(_ metalDevice: MTLDevice, colorPixelFormat: UInt, depthStencilPixelFormat: UInt) {
17
+ layer?.internalRenderingWillStart(metalDevice, colorPixelFormat: colorPixelFormat, depthStencilPixelFormat: depthStencilPixelFormat)
18
+ }
19
+
20
+ func render(_ parameters: CustomLayerRenderParameters, mtlCommandBuffer: MTLCommandBuffer, mtlRenderPassDescriptor: MTLRenderPassDescriptor) {
21
+ layer?.internalRender(parameters, mtlCommandBuffer: mtlCommandBuffer, mtlRenderPassDescriptor: mtlRenderPassDescriptor)
22
+ }
23
+
24
+ func renderingWillEnd() {
25
+ layer?.internalRenderingWillEnd()
26
+ }
27
+ }
28
+
29
+ @objc(GridRenderLayer)
30
+ public class GridRenderLayer: NSObject {
31
+
32
+ // MARK: - Properties
33
+
34
+ public var id: String
35
+ @objc internal var hostWrapper: GridRenderLayerHost!
36
+
37
+ // Metal objects
38
+ private var device: MTLDevice!
39
+ private var commandQueue: MTLCommandQueue!
40
+ private var pipelineState: MTLRenderPipelineState!
41
+ private var vertexBuffer: MTLBuffer?
42
+ private var indexBuffer: MTLBuffer?
43
+ private var dataTexture: MTLTexture?
44
+ private var colormapTexture: MTLTexture?
45
+ private var dataSamplerState: MTLSamplerState!
46
+ private var colormapSamplerState: MTLSamplerState!
47
+ private var isDataSamplerLinear: Bool = false
48
+
49
+ private var pendingColormapUpdate: String?
50
+ private var pendingDataUpdate: (data: String, nx: NSNumber, ny: NSNumber, scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: String)?
51
+ private var pendingGeometryUpdate: (corners: [String: Any], gridDef: [String: Any])?
52
+
53
+ // Layer state
54
+ private var indexCount: Int = 0
55
+ private var uniforms = FragmentUniforms(
56
+ opacity: 1.0,
57
+ dataRange: SIMD2<Float>(0.0, 1.0),
58
+ scale: 1.0,
59
+ offset: 0.0,
60
+ missingQuantized: 127.0,
61
+ textureSize: SIMD2<Float>(0.0, 0.0),
62
+ smoothing: 1,
63
+ scaleType: 0,
64
+ isPtype: 0,
65
+ isMRMS: 0
66
+ )
67
+ private var isVisible = false
68
+ private var pendingActiveFrameKey: String?
69
+ private var lastRequestedCacheKey: String?
70
+ private let inspectorCache = InspectorDataCache.shared
71
+ private struct FrameMetadata {
72
+ let scale: Float
73
+ let offset: Float
74
+ let missing: Float
75
+ let scaleType: Int
76
+ let nx: Float
77
+ let ny: Float
78
+ let filePath: String
79
+ let originalScale: Float
80
+ let originalOffset: Float
81
+ }
82
+ private var frameCache: [String: FrameMetadata] = [:]
83
+ private let frameCacheQueue = DispatchQueue(label: "com.aguacero.frame-cache-queue")
84
+ private let frameProcessingQueue = DispatchQueue(label: "com.aguacero.frame-processing", qos: .userInitiated, attributes: .concurrent)
85
+ private let semaphore = DispatchSemaphore(value: 8)
86
+
87
+ private struct VertexInfo {
88
+ var mercX: Float
89
+ var mercY: Float
90
+ var texU: Float
91
+ var texV: Float
92
+ var index: UInt16
93
+ }
94
+
95
+ // MARK: - Performance Helper
96
+ private func logPerf(_ msg: String) {
97
+ var taskInfo = mach_task_basic_info()
98
+ var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
99
+ let kerr: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
100
+ $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
101
+ task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
102
+ }
103
+ }
104
+ let mem = (kerr == KERN_SUCCESS) ? Float(taskInfo.resident_size) / 1024.0 / 1024.0 : 0
105
+ print("⚡️ [PERF] [GridRenderLayer] \(msg) | RAM: \(String(format: "%.2f", mem)) MB")
106
+ }
107
+
108
+ @objc
109
+ public init(id: String) {
110
+ self.id = id
111
+ super.init()
112
+ self.hostWrapper = GridRenderLayerHost(layer: self)
113
+ }
114
+
115
+ @objc public func getHostWrapper() -> Any {
116
+ return self.hostWrapper as Any
117
+ }
118
+
119
+ // MARK: - Public Methods (called from Manager)
120
+
121
+ @objc public func setOpacity(value: Float) {
122
+ self.uniforms.opacity = value
123
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
124
+ }
125
+
126
+ @objc public func setDataRange(value: [NSNumber]) {
127
+ self.uniforms.dataRange = SIMD2<Float>(value[0].floatValue, value[1].floatValue)
128
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
129
+ }
130
+
131
+ @objc public func setSmoothing(value: Bool) {
132
+ self.uniforms.smoothing = value ? 1 : 0
133
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
134
+ }
135
+
136
+ @objc(setIsMRMSWithIsMRMS:)
137
+ public func setIsMRMS(isMRMS: Bool) {
138
+ self.uniforms.isMRMS = isMRMS ? 1 : 0
139
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
140
+ }
141
+
142
+ // ADD THIS METHOD
143
+ @objc(setVariableWithVariable:)
144
+ public func setVariable(variable: String) {
145
+ let isPtypeVar = (variable == "ptypeRefl" || variable == "ptypeRate")
146
+ self.uniforms.isPtype = isPtypeVar ? 1 : 0
147
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
148
+ }
149
+
150
+ @objc public func clear() {
151
+ self.isVisible = false
152
+ self.inspectorCache.clear()
153
+ }
154
+
155
+ @objc public func updateDataParameters(scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: NSNumber) { // ADD scaleType parameter
156
+ // Update both the inspector cache AND the rendering uniforms
157
+ self.uniforms.scale = scale.floatValue
158
+ self.uniforms.offset = offset.floatValue
159
+ self.uniforms.missingQuantized = missing.floatValue
160
+ self.uniforms.scaleType = Int32(scaleType.intValue) // ADD THIS
161
+
162
+ inspectorCache.update(
163
+ data: nil,
164
+ nx: inspectorCache.nx,
165
+ ny: inspectorCache.ny,
166
+ scale: scale.floatValue,
167
+ offset: offset.floatValue,
168
+ missing: missing.floatValue,
169
+ scaleType: scaleType.intValue
170
+ )
171
+ }
172
+
173
+ @objc public func updateColormapTexture(colormapAsBase64: String) {
174
+ guard let device = self.device else {
175
+ pendingColormapUpdate = colormapAsBase64
176
+ return
177
+ }
178
+ guard let data = Data(base64Encoded: colormapAsBase64) else { return }
179
+ let textureDescriptor = MTLTextureDescriptor()
180
+ textureDescriptor.pixelFormat = .rgba8Unorm
181
+ textureDescriptor.width = 256
182
+ textureDescriptor.height = 1
183
+ textureDescriptor.usage = .shaderRead
184
+ guard let texture = device.makeTexture(descriptor: textureDescriptor) else { return }
185
+ texture.replace(
186
+ region: MTLRegionMake2D(0, 0, 256, 1),
187
+ mipmapLevel: 0,
188
+ withBytes: (data as NSData).bytes,
189
+ bytesPerRow: 256 * 4
190
+ )
191
+ self.colormapTexture = texture
192
+ }
193
+
194
+ @objc(clearGpuCache)
195
+ public func clearGpuCache() {
196
+ print("ℹ️ [GridRenderLayer] clearGpuCache called")
197
+ frameProcessingQueue.async { [weak self] in
198
+ guard let self = self else { return }
199
+ self.frameCacheQueue.async {
200
+ self.frameCache.removeAll()
201
+ }
202
+ }
203
+ }
204
+
205
+ private func reconstructAndTransformInPlace(data: inout Data) {
206
+ let count = data.count
207
+ if count == 0 { return }
208
+
209
+ // Get raw pointer to memory (Bypasses Swift Array bounds checking)
210
+ data.withUnsafeMutableBytes { rawBuffer in
211
+ guard let ptr = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return }
212
+
213
+ // 1. Setup first byte
214
+ // Cast to Int8 to handle the delta logic, then back to UInt8 for storage
215
+ var runningValue: Int8 = Int8(bitPattern: ptr[0])
216
+
217
+ // Transform first byte immediately: runningValue + 128
218
+ // We use &+ to allow overflow wrapping (which is exactly what we want for -128->0 mapping)
219
+ ptr[0] = UInt8(bitPattern: runningValue) &+ 128
220
+
221
+ // 2. Optimized Loop (One pass for everything)
222
+ for i in 1..<count {
223
+ let delta = Int8(bitPattern: ptr[i])
224
+
225
+ // Reconstruction: Add delta to previous value
226
+ runningValue = runningValue &+ delta
227
+
228
+ // Transformation: Add 128 to shift into UInt8 range for Texture
229
+ ptr[i] = UInt8(bitPattern: runningValue) &+ 128
230
+ }
231
+ }
232
+ }
233
+
234
+ private func processRawData(fileData: Data) -> Data? {
235
+ let start = CFAbsoluteTimeGetCurrent()
236
+
237
+ // 1. Decompress
238
+ // This allocates the only buffer we will use.
239
+ let t1 = CFAbsoluteTimeGetCurrent()
240
+ guard var workingData = self.decompressZstd(data: fileData) else {
241
+ print("❌ [GridRenderLayer] Failed to decompress zstd data")
242
+ return nil
243
+ }
244
+ let t1_diff = (CFAbsoluteTimeGetCurrent() - t1) * 1000
245
+
246
+ // 2. Reconstruct AND Transform (In-Place)
247
+ // No new memory allocation here.
248
+ let t2 = CFAbsoluteTimeGetCurrent()
249
+ self.reconstructAndTransformInPlace(data: &workingData)
250
+ let t2_diff = (CFAbsoluteTimeGetCurrent() - t2) * 1000
251
+
252
+ // 3. (Legacy Timer Placeholder to match logs)
253
+ // Since we combined them, this is effectively instant now
254
+ let t3_diff = 0.0
255
+
256
+ let total = (CFAbsoluteTimeGetCurrent() - start) * 1000
257
+
258
+ // Log CPU transformation metrics
259
+ // Expect Recon+Trans to drop from ~1000ms to ~10-20ms
260
+ logPerf("PROCESS RAW: Total \(String(format: "%.1f", total))ms (Zstd: \(String(format: "%.1f", t1_diff))ms, Recon+Trans: \(String(format: "%.1f", t2_diff))ms)")
261
+
262
+ return workingData
263
+ }
264
+
265
+ private func createTextureFromBytes(bytes: Data, nx: Int, ny: Int) -> MTLTexture? {
266
+ guard let device = self.device else { return nil }
267
+ let textureDescriptor = MTLTextureDescriptor()
268
+ textureDescriptor.pixelFormat = .r8Unorm
269
+ textureDescriptor.width = nx
270
+ textureDescriptor.height = ny
271
+ textureDescriptor.usage = .shaderRead
272
+
273
+ guard let texture = device.makeTexture(descriptor: textureDescriptor) else { return nil }
274
+ texture.replace(
275
+ region: MTLRegionMake2D(0, 0, nx, ny),
276
+ mipmapLevel: 0,
277
+ withBytes: (bytes as NSData).bytes,
278
+ bytesPerRow: nx
279
+ )
280
+ return texture
281
+ }
282
+
283
+ private func updateInspectorCache(filePath: String, reconstructedData: Data?, nx: Int, ny: Int, scale: Float, offset: Float, missing: Float, scaleType: Int) {
284
+ self.inspectorCache.updateWithFilePath(
285
+ filePath: filePath,
286
+ nx: nx,
287
+ ny: ny,
288
+ scale: scale,
289
+ offset: offset,
290
+ missing: missing,
291
+ scaleType: scaleType
292
+ )
293
+ }
294
+
295
+ @objc(setActiveFrameWithCacheKey:)
296
+ public func setActiveFrame(cacheKey: String) {
297
+ logPerf("setActiveFrame requested: \(cacheKey)")
298
+ setActiveFrameInternal(cacheKey: cacheKey, isExternalRequest: true)
299
+ }
300
+
301
+ private func setActiveFrameInternal(cacheKey: String, isExternalRequest: Bool) {
302
+ if isExternalRequest {
303
+ lastRequestedCacheKey = cacheKey
304
+ } else {
305
+ if lastRequestedCacheKey != cacheKey { return }
306
+ }
307
+
308
+ var frameResult: FrameMetadata?
309
+ frameCacheQueue.sync {
310
+ frameResult = frameCache[cacheKey]
311
+ }
312
+
313
+ if let frame = frameResult {
314
+ frameProcessingQueue.async { [weak self] in
315
+ guard let self = self else { return }
316
+ if self.lastRequestedCacheKey != cacheKey { return }
317
+
318
+ // ALWAYS load from disk. It is fast enough now (20ms).
319
+ // No caching needed.
320
+ let diskStart = CFAbsoluteTimeGetCurrent()
321
+ guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: frame.filePath)) else {
322
+ print("❌ [GridRenderLayer] Failed to load file: \(frame.filePath)")
323
+ return
324
+ }
325
+
326
+ // processRawData is now optimized (in-place) and takes ~20ms
327
+ guard let finalTextureBytes = self.processRawData(fileData: fileData) else {
328
+ print("❌ [GridRenderLayer] Failed to process data for: \(cacheKey)")
329
+ return
330
+ }
331
+
332
+ // Final check before jumping to main thread
333
+ if self.lastRequestedCacheKey != cacheKey { return }
334
+
335
+ DispatchQueue.main.async { [weak self] in
336
+ // ... (Keep existing Main Thread texture upload logic) ...
337
+ guard let self = self else { return }
338
+
339
+ if self.lastRequestedCacheKey != cacheKey { return }
340
+
341
+ let nx = Int(frame.nx)
342
+ let ny = Int(frame.ny)
343
+
344
+ if let existingTexture = self.dataTexture,
345
+ existingTexture.width == nx,
346
+ existingTexture.height == ny {
347
+ existingTexture.replace(
348
+ region: MTLRegionMake2D(0, 0, nx, ny),
349
+ mipmapLevel: 0,
350
+ withBytes: (finalTextureBytes as NSData).bytes,
351
+ bytesPerRow: nx
352
+ )
353
+ } else {
354
+ guard let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nx, ny: ny) else { return }
355
+ self.dataTexture = texture
356
+ }
357
+
358
+ self.uniforms.scale = frame.scale
359
+ self.uniforms.offset = frame.offset
360
+ self.uniforms.missingQuantized = frame.missing
361
+ self.uniforms.textureSize = SIMD2<Float>(frame.nx, frame.ny)
362
+ self.uniforms.scaleType = Int32(frame.scaleType)
363
+
364
+ self.isVisible = true
365
+ self.pendingActiveFrameKey = nil
366
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
367
+
368
+ // Update inspector in background
369
+ self.frameProcessingQueue.async { [weak self] in
370
+ self?.updateInspectorCache(
371
+ filePath: frame.filePath,
372
+ reconstructedData: finalTextureBytes, // Pass the data we already processed!
373
+ nx: nx,
374
+ ny: ny,
375
+ scale: frame.scale,
376
+ offset: frame.offset,
377
+ missing: frame.missing,
378
+ scaleType: frame.scaleType
379
+ )
380
+ }
381
+ }
382
+ }
383
+ } else {
384
+ if isExternalRequest {
385
+ self.pendingActiveFrameKey = cacheKey
386
+ }
387
+ }
388
+ }
389
+
390
+ @objc(primeGpuCacheWithFrameInfo:)
391
+ public func primeGpuCache(frameInfo: [String: [String: Any]]) {
392
+ // logPerf("primeGpuCache called with \(frameInfo.count) items")
393
+
394
+ // We do NOT need the frameProcessingQueue here anymore because we are just storing metadata.
395
+ // Doing this synchronously on the caller thread (which is a background thread from Manager) is fine and much faster.
396
+
397
+ self.frameCacheQueue.async { [weak self] in
398
+ guard let self = self else { return }
399
+
400
+ for (cacheKey, info) in frameInfo {
401
+ if self.frameCache[cacheKey] != nil { continue }
402
+
403
+ guard let filePath = info["filePath"] as? String,
404
+ let nx = info["nx"] as? NSNumber,
405
+ let ny = info["ny"] as? NSNumber,
406
+ let scale = info["scale"] as? NSNumber,
407
+ let offset = info["offset"] as? NSNumber,
408
+ let missing = info["missing"] as? NSNumber,
409
+ let scaleTypeStr = info["scaleType"] as? String,
410
+ let originalScale = info["originalScale"] as? NSNumber,
411
+ let originalOffset = info["originalOffset"] as? NSNumber
412
+ else { continue }
413
+
414
+ let metadata = FrameMetadata(
415
+ scale: scale.floatValue,
416
+ offset: offset.floatValue,
417
+ missing: missing.floatValue,
418
+ scaleType: (scaleTypeStr == "sqrt") ? 1 : 0,
419
+ nx: nx.floatValue,
420
+ ny: ny.floatValue,
421
+ filePath: filePath,
422
+ originalScale: originalScale.floatValue,
423
+ originalOffset: originalOffset.floatValue
424
+ // processedData: nil <--- REMOVED
425
+ )
426
+
427
+ self.frameCache[cacheKey] = metadata
428
+
429
+ // Check if this was a pending active frame
430
+ DispatchQueue.main.async { [weak self] in
431
+ guard let self = self else { return }
432
+ if self.pendingActiveFrameKey == cacheKey {
433
+ self.setActiveFrameInternal(cacheKey: cacheKey, isExternalRequest: false)
434
+ }
435
+ }
436
+ }
437
+ }
438
+ }
439
+
440
+ @objc public func updateDataTexture(data: String, nx: NSNumber, ny: NSNumber, scale: NSNumber, offset: NSNumber, missing: NSNumber, scaleType: String) {
441
+ let filePath = data
442
+ logPerf("updateDataTexture called for \(filePath)")
443
+
444
+ frameProcessingQueue.async { [weak self] in
445
+ guard let self = self else { return }
446
+
447
+ guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
448
+ let finalTextureBytes = self.processRawData(fileData: fileData)
449
+ else {
450
+ print("❌ [GridRenderLayer] FAST LANE: Failed to process initial frame data.")
451
+ return
452
+ }
453
+
454
+ DispatchQueue.main.async { [weak self] in
455
+ guard let self = self else { return }
456
+
457
+ let nxInt = nx.intValue
458
+ let nyInt = ny.intValue
459
+
460
+ // REUSE TEXTURE if dimensions match
461
+ if let existingTexture = self.dataTexture,
462
+ existingTexture.width == nxInt,
463
+ existingTexture.height == nyInt {
464
+ existingTexture.replace(
465
+ region: MTLRegionMake2D(0, 0, nxInt, nyInt),
466
+ mipmapLevel: 0,
467
+ withBytes: (finalTextureBytes as NSData).bytes,
468
+ bytesPerRow: nxInt
469
+ )
470
+ } else {
471
+ // Create new texture only if needed
472
+ guard let texture = self.createTextureFromBytes(bytes: finalTextureBytes, nx: nxInt, ny: nyInt) else {
473
+ print("❌ [GridRenderLayer] FAST LANE: Failed to create texture")
474
+ return
475
+ }
476
+ self.dataTexture = texture
477
+ }
478
+
479
+ self.uniforms.scale = scale.floatValue
480
+ self.uniforms.offset = offset.floatValue
481
+ self.uniforms.missingQuantized = missing.floatValue
482
+ self.uniforms.scaleType = Int32((scaleType == "sqrt") ? 1 : 0)
483
+ self.uniforms.textureSize = SIMD2<Float>(nx.floatValue, ny.floatValue)
484
+
485
+ self.isVisible = true
486
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
487
+
488
+ self.updateInspectorCache(
489
+ filePath: filePath,
490
+ reconstructedData: nil,
491
+ nx: nx.intValue,
492
+ ny: ny.intValue,
493
+ scale: scale.floatValue,
494
+ offset: offset.floatValue,
495
+ missing: missing.floatValue,
496
+ scaleType: (scaleType == "sqrt") ? 1 : 0
497
+ )
498
+ }
499
+ }
500
+ }
501
+
502
+ @objc public func updateGeometry(corners: [String: Any], gridDef: [String: Any]) {
503
+ guard self.device != nil else {
504
+ print("⚠️ [GridRenderLayer] Device not ready yet, storing geometry for later")
505
+ pendingGeometryUpdate = (corners: corners, gridDef: gridDef)
506
+ return
507
+ }
508
+
509
+ DispatchQueue.global(qos: .userInitiated).async {
510
+
511
+ var vertices: [Float] = []
512
+ var indices: [UInt16] = []
513
+
514
+ self.generateGeometryData(gridDef: gridDef, vertices: &vertices, indices: &indices)
515
+
516
+ if vertices.isEmpty || indices.isEmpty {
517
+ print("❌ [GridRenderLayer] No geometry generated")
518
+ return
519
+ }
520
+
521
+ self.indexCount = indices.count
522
+
523
+ DispatchQueue.main.async {
524
+ self.vertexBuffer = self.device.makeBuffer(bytes: vertices, length: vertices.count * MemoryLayout<Float>.size, options: [])
525
+ self.indexBuffer = self.device.makeBuffer(bytes: indices, length: indices.count * MemoryLayout<UInt16>.size, options: [])
526
+
527
+ NotificationCenter.default.post(name: NSNotification.Name("TriggerMapRepaint"), object: nil)
528
+ }
529
+ }
530
+ }
531
+
532
+ private func decompressZstd(data: Data) -> Data? {
533
+ let decompressedSize = data.withUnsafeBytes { ptr in
534
+ ZSTD_getFrameContentSize(ptr.baseAddress, data.count)
535
+ }
536
+
537
+ guard Int64(bitPattern: decompressedSize) > 0 else {
538
+ print("❌ [GridRenderLayer] Could not determine decompressed size")
539
+ return nil
540
+ }
541
+
542
+ var decompressedData = Data(count: Int(decompressedSize))
543
+
544
+ let result = decompressedData.withUnsafeMutableBytes { decompressedPtr -> Int in
545
+ data.withUnsafeBytes { compressedPtr -> Int in
546
+ let returnValue = ZSTD_decompress(
547
+ decompressedPtr.baseAddress,
548
+ Int(decompressedSize),
549
+ compressedPtr.baseAddress,
550
+ data.count
551
+ )
552
+ return Int(returnValue)
553
+ }
554
+ }
555
+
556
+ guard result > 0 && result == decompressedData.count else {
557
+ if result > 0 {
558
+ let size_t_result = size_t(result)
559
+ if let errorName = ZSTD_getErrorName(size_t_result) {
560
+ let errorString = String(cString: errorName)
561
+ print("❌ [GridRenderLayer] Zstd decompression failed: \(errorString)")
562
+ }
563
+ }
564
+ return nil
565
+ }
566
+ return decompressedData
567
+ }
568
+
569
+ private func isLCCType(gridDef: [String: Any]) -> Bool {
570
+ if let type = gridDef["type"] as? String {
571
+ return type == "lambert_conformal_conic"
572
+ }
573
+ return false
574
+ }
575
+
576
+ private func generateLCCGeometry(gridDef: [String: Any], vertices: inout [Float], indices: inout [UInt16]) {
577
+ guard let gridParams = gridDef["grid_params"] as? [String: Any],
578
+ let projParams = gridDef["proj_params"] as? [String: Any],
579
+ let nx = gridParams["nx"] as? Int,
580
+ let ny = gridParams["ny"] as? Int,
581
+ let dx = gridParams["dx"] as? Double,
582
+ let dy = gridParams["dy"] as? Double,
583
+ let x_origin = gridParams["x_origin"] as? Double,
584
+ let y_origin = gridParams["y_origin"] as? Double else {
585
+ return
586
+ }
587
+
588
+ let subdivisions = 60
589
+ let TILE_SIZE: Double = 512.0
590
+
591
+ let x_min = x_origin
592
+ let y_max = y_origin
593
+ let x_max = x_origin + Double(nx - 1) * dx
594
+ let y_min = y_origin + Double(ny - 1) * dy
595
+
596
+ var vertexGrid: [[VertexInfo?]] = Array(repeating: Array(repeating: nil, count: subdivisions + 1), count: subdivisions + 1)
597
+ var validVertexCount: UInt16 = 0
598
+
599
+ // Generate vertices
600
+ for row in 0...subdivisions {
601
+ for col in 0...subdivisions {
602
+ let t_x = Double(col) / Double(subdivisions)
603
+ let t_y = Double(row) / Double(subdivisions)
604
+
605
+ let proj_x = x_min + t_x * (x_max - x_min)
606
+ let proj_y = y_max + t_y * (y_min - y_max)
607
+
608
+ // Convert LCC projection coordinates to lat/lon
609
+ if let (lon, lat) = lccToLonLat(i: proj_x, j: proj_y, gridDef: gridDef) {
610
+ // Convert lat/lon to Mercator
611
+ let mercX_normalized = (lon + 180.0) / 360.0
612
+ let clampedLat = max(-85.05112878, min(85.05112878, lat))
613
+ let sinLatitude = sin(clampedLat * .pi / 180.0)
614
+ let mercY_normalized = 0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * .pi)
615
+
616
+ let mercX = mercX_normalized * TILE_SIZE
617
+ let mercY = mercY_normalized * TILE_SIZE
618
+
619
+ // Check for invalid values
620
+ if !mercX.isFinite || !mercY.isFinite {
621
+ vertexGrid[row][col] = nil
622
+ continue
623
+ }
624
+
625
+ let tex_u = Float(t_x)
626
+ let tex_v = Float(t_y)
627
+
628
+ let vInfo = VertexInfo(
629
+ mercX: Float(mercX),
630
+ mercY: Float(mercY),
631
+ texU: tex_u,
632
+ texV: tex_v,
633
+ index: validVertexCount
634
+ )
635
+
636
+ vertexGrid[row][col] = vInfo
637
+
638
+ vertices.append(Float(mercX))
639
+ vertices.append(Float(mercY))
640
+ vertices.append(tex_u)
641
+ vertices.append(tex_v)
642
+
643
+ validVertexCount += 1
644
+ } else {
645
+ vertexGrid[row][col] = nil
646
+ }
647
+ }
648
+ }
649
+
650
+ if vertices.isEmpty {
651
+ print("❌ [LCC Geometry] No valid vertices generated")
652
+ return
653
+ }
654
+
655
+ // Generate indices
656
+ for row in 0..<subdivisions {
657
+ for col in 0..<subdivisions {
658
+ guard let topLeft = vertexGrid[row][col],
659
+ let topRight = vertexGrid[row][col + 1],
660
+ let bottomLeft = vertexGrid[row + 1][col],
661
+ let bottomRight = vertexGrid[row + 1][col + 1] else {
662
+ continue
663
+ }
664
+
665
+ indices.append(topLeft.index)
666
+ indices.append(bottomLeft.index)
667
+ indices.append(topRight.index)
668
+
669
+ indices.append(topRight.index)
670
+ indices.append(bottomLeft.index)
671
+ indices.append(bottomRight.index)
672
+ }
673
+ }
674
+ }
675
+
676
+ private func lccToLonLat(i: Double, j: Double, gridDef: [String: Any]) -> (lon: Double, lat: Double)? {
677
+ guard let projParams = gridDef["proj_params"] as? [String: Any],
678
+ let lat_0 = (projParams["lat_0"] as? NSNumber)?.doubleValue,
679
+ let lon_0 = (projParams["lon_0"] as? NSNumber)?.doubleValue,
680
+ let lat_1 = (projParams["lat_1"] as? NSNumber)?.doubleValue,
681
+ let lat_2 = (projParams["lat_2"] as? NSNumber)?.doubleValue,
682
+ let r_earth = (projParams["R"] as? NSNumber)?.doubleValue else {
683
+ print("❌ [LCC Geometry] Failed to extract LCC parameters.")
684
+ return nil
685
+ }
686
+
687
+ let π = Double.pi
688
+ let toRad = π / 180.0
689
+ let toDeg = 180.0 / π
690
+
691
+ let lat1_rad = lat_1 * toRad
692
+ let lat2_rad = lat_2 * toRad
693
+ let lat0_rad = lat_0 * toRad
694
+ let lon0_rad = lon_0 * toRad
695
+
696
+ let n: Double
697
+ if abs(lat_1 - lat_2) < 1e-10 {
698
+ n = sin(lat1_rad)
699
+ } else {
700
+ n = log(cos(lat1_rad) / cos(lat2_rad)) / log(tan(π/4.0 + lat2_rad/2.0) / tan(π/4.0 + lat1_rad/2.0))
701
+ }
702
+
703
+ let F = cos(lat1_rad) * pow(tan(π/4.0 + lat1_rad/2.0), n) / n
704
+ let rho_0 = r_earth * F * pow(tan(π/4.0 + lat0_rad/2.0), -n)
705
+
706
+ let x = i
707
+ let y = j
708
+
709
+ let rho = sqrt(x * x + (rho_0 - y) * (rho_0 - y))
710
+ if rho < 1e-10 {
711
+ return (lon: lon_0, lat: lat_0)
712
+ }
713
+
714
+ let theta = atan2(x, rho_0 - y)
715
+
716
+ let lon = lon0_rad + theta / n
717
+ let lat = 2.0 * atan(pow(r_earth * F / rho, 1.0 / n)) - π/2.0
718
+
719
+ let lonDeg = lon * toDeg
720
+ let latDeg = lat * toDeg
721
+
722
+ if !lonDeg.isFinite || !latDeg.isFinite {
723
+ return nil
724
+ }
725
+
726
+ return (lon: lonDeg, lat: latDeg)
727
+ }
728
+
729
+ private func generateGeometryData(gridDef: [String: Any], vertices: inout [Float], indices: inout [UInt16]) {
730
+ guard let gridParams = gridDef["grid_params"] as? [String: Any] else {
731
+ print("❌ [generateGeometryData] No grid_params found")
732
+ return
733
+ }
734
+
735
+ // Check grid type
736
+ let isGFS = isGFSType(gridParams: gridParams)
737
+ let isLCC = isLCCType(gridDef: gridDef)
738
+
739
+ if isGFS {
740
+ // GFS path remains unchanged
741
+ let subdivisions = 120
742
+ let verticesPerRow = (subdivisions * 3) + 1
743
+ let TILE_SIZE: Double = 512.0
744
+
745
+ for row in 0...subdivisions {
746
+ for col in 0...(subdivisions * 3) {
747
+ let v_interp = Float(row) / Float(subdivisions)
748
+ let u_interp = Float(col) / Float(subdivisions)
749
+ let lon = -540.0 + Double(u_interp) * 1080.0
750
+ let lat = -90.0 + Double(v_interp) * 180.0
751
+
752
+ let merc = lonLatToMercator(lon: lon, lat: lat, tileSize: TILE_SIZE)
753
+ vertices.append(contentsOf: [merc.x, merc.y])
754
+
755
+ let tex_u = Float((lon + 180.0) / 360.0)
756
+ let tex_v = 1.0 - v_interp
757
+ vertices.append(contentsOf: [tex_u, tex_v])
758
+ }
759
+ }
760
+
761
+ for row in 0..<subdivisions {
762
+ for col in 0..<(subdivisions * 3) {
763
+ let tl = UInt16(row * verticesPerRow + col)
764
+ let tr = tl + 1
765
+ let bl = UInt16((row + 1) * verticesPerRow + col)
766
+ let br = bl + 1
767
+ indices.append(contentsOf: [tl, bl, tr, tr, bl, br])
768
+ }
769
+ }
770
+ return
771
+ }
772
+
773
+ if isLCC {
774
+ generateLCCGeometry(gridDef: gridDef, vertices: &vertices, indices: &indices)
775
+ return
776
+ }
777
+
778
+ let nx = gridParams["nx"] as? Int ?? 0
779
+ let ny = gridParams["ny"] as? Int ?? 0
780
+ let lon_first = gridParams["lon_first"] as? Double ?? 0.0
781
+ let lat_first = gridParams["lat_first"] as? Double ?? 90.0
782
+ let dx = gridParams["dx_degrees"] as? Double ?? 0.0
783
+ let dy = gridParams["dy_degrees"] as? Double ?? 0.0
784
+ let lon_last = gridParams["lon_last"] as? Double ?? (lon_first + Double(nx - 1) * dx)
785
+ let lat_last = gridParams["lat_last"] as? Double ?? (lat_first + Double(ny - 1) * dy)
786
+
787
+ let lat_span = lat_last - lat_first
788
+ let isSouthToNorth = lat_span > 0
789
+
790
+ // Check if this is ECMWF and normalize longitudes
791
+ let isECMWF = isECMWFType(gridParams: gridParams)
792
+ var data_lon_first_180 = lon_first
793
+ var data_lon_last_180 = lon_last
794
+
795
+ if isECMWF {
796
+ // Convert ECMWF's 180 to -180 range to -180 to 180
797
+ data_lon_first_180 = lon_first >= 180 ? lon_first - 360 : lon_first
798
+ data_lon_last_180 = lon_last >= 180 ? lon_last - 360 : lon_last
799
+ } else {
800
+ // For GFS and other models
801
+ data_lon_first_180 = lon_first > 180 ? lon_first - 360 : lon_first
802
+ data_lon_last_180 = lon_last > 180 ? lon_last - 360 : lon_last
803
+ }
804
+
805
+ let data_lon_range = data_lon_last_180 - data_lon_first_180
806
+
807
+ let subdivisions_x = 120
808
+ let subdivisions_y = 60
809
+ let verticesPerRow = subdivisions_x + 1
810
+ let TILE_SIZE: Double = 512.0
811
+
812
+ let worldCopies = (data_lon_range > 300) ? [-1, 0, 1] : [0]
813
+
814
+ for world_copy in worldCopies {
815
+ let vertexStartIndex = UInt16(vertices.count / 4)
816
+ let lon_offset = Double(world_copy) * 360.0
817
+
818
+ for row in 0...subdivisions_y {
819
+ for col in 0...subdivisions_x {
820
+ let v_interp = Float(row) / Float(subdivisions_y)
821
+ let u_interp = Float(col) / Float(subdivisions_x)
822
+
823
+ let vertex_lon = data_lon_first_180 + (Double(u_interp) * data_lon_range)
824
+ let vertex_lat = lat_first + (Double(v_interp) * lat_span)
825
+
826
+ let mercX_normalized = ((vertex_lon + lon_offset) + 180.0) / 360.0
827
+ let clampedLat = max(-85.05112878, min(85.05112878, vertex_lat))
828
+ let sinLatitude = sin(clampedLat * .pi / 180.0)
829
+ let mercY_normalized = 0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * .pi)
830
+ let mercX = mercX_normalized * TILE_SIZE
831
+ let mercY = mercY_normalized * TILE_SIZE
832
+
833
+ vertices.append(contentsOf: [Float(mercX), Float(mercY)])
834
+
835
+ let tex_u = u_interp
836
+ let tex_v = isSouthToNorth ? (1.0 - v_interp) : v_interp
837
+
838
+ vertices.append(contentsOf: [tex_u, tex_v])
839
+ }
840
+ }
841
+
842
+ for row in 0..<UInt16(subdivisions_y) {
843
+ for col in 0..<UInt16(subdivisions_x) {
844
+ let tl = vertexStartIndex + row * UInt16(verticesPerRow) + col
845
+ let tr = tl + 1
846
+ let bl = vertexStartIndex + (row + 1) * UInt16(verticesPerRow) + col
847
+ let br = bl + 1
848
+
849
+ if isSouthToNorth {
850
+ indices.append(contentsOf: [tl, bl, tr, tr, bl, br])
851
+ } else {
852
+ indices.append(contentsOf: [tl, tr, bl, bl, tr, br])
853
+ }
854
+ }
855
+ }
856
+ }
857
+ }
858
+
859
+ private func isGFSType(gridParams: [String: Any]) -> Bool {
860
+ return (gridParams["lon_first"] as? Double) == 0.0 &&
861
+ abs((gridParams["lat_first"] as? Double) ?? -1) == 90.0
862
+ }
863
+
864
+ private func isECMWFType(gridParams: [String: Any]) -> Bool {
865
+ return (gridParams["lon_first"] as? Double) == 180.0 &&
866
+ (gridParams["lat_first"] as? Double) == 90.0
867
+ }
868
+
869
+ private func lonLatToMercator(lon: Double, lat: Double, tileSize: Double) -> (x: Float, y: Float) {
870
+ let mercX_normalized = (lon + 180.0) / 360.0
871
+ let clampedLat = max(-85.05112878, min(85.05112878, lat))
872
+ let sinLatitude = sin(clampedLat * .pi / 180.0)
873
+ let mercY_normalized = 0.5 - log((1.0 + sinLatitude) / (1.0 - sinLatitude)) / (4.0 * .pi)
874
+
875
+ return (x: Float(mercX_normalized * tileSize), y: Float(mercY_normalized * tileSize))
876
+ }
877
+
878
+ // MARK: - Internal methods for CustomLayerHost (called by wrapper)
879
+
880
+ internal func internalRenderingWillStart(_ metalDevice: MTLDevice, colorPixelFormat: UInt, depthStencilPixelFormat: UInt) {
881
+ self.device = metalDevice
882
+ self.commandQueue = metalDevice.makeCommandQueue()
883
+
884
+ let bundle = Bundle(for: GridRenderLayer.self)
885
+
886
+ // Determine if we're running on simulator or device
887
+ #if targetEnvironment(simulator)
888
+ let metallibName = "Shaders-simulator"
889
+ #else
890
+ let metallibName = "Shaders-device"
891
+ #endif
892
+
893
+ // Try to load pre-compiled metallib for the current platform
894
+ var defaultLibrary: MTLLibrary?
895
+
896
+ // 1. Look in the main bundle level
897
+ if let metallibUrl = bundle.url(forResource: metallibName, withExtension: "metallib") {
898
+ print("ℹ️ [GridRenderLayer] Found pre-compiled shaders at: \(metallibUrl.lastPathComponent)")
899
+ defaultLibrary = try? metalDevice.makeLibrary(URL: metallibUrl)
900
+ }
901
+
902
+ // 2. Fall back to compiled-shaders subdirectory
903
+ if defaultLibrary == nil {
904
+ if let metallibUrl = bundle.url(forResource: metallibName, withExtension: "metallib", subdirectory: "compiled-shaders") {
905
+ print("ℹ️ [GridRenderLayer] Found pre-compiled shaders in subdirectory: \(metallibUrl.lastPathComponent)")
906
+ defaultLibrary = try? metalDevice.makeLibrary(URL: metallibUrl)
907
+ }
908
+ }
909
+
910
+ // 3. Fall back to compiling from .metal source (for development with npm link)
911
+ if defaultLibrary == nil {
912
+ if let metalUrl = bundle.url(forResource: "Shaders", withExtension: "metal") {
913
+ print("⚠️ [GridRenderLayer] Pre-compiled shaders not found. Compiling from source: \(metalUrl.lastPathComponent)")
914
+ if let source = try? String(contentsOf: metalUrl),
915
+ let library = try? metalDevice.makeLibrary(source: source, options: nil) {
916
+ defaultLibrary = library
917
+ }
918
+ }
919
+ }
920
+
921
+ // Neither worked
922
+ if defaultLibrary == nil {
923
+ print("❌ [GridRenderLayer] Could not find or compile Metal shaders")
924
+ print(" Bundle path: \(bundle.bundlePath)")
925
+ return
926
+ }
927
+
928
+ guard let library = defaultLibrary else {
929
+ print("❌ [GridRenderLayer] Failed to create Metal library")
930
+ return
931
+ }
932
+
933
+ let vertexFunction = library.makeFunction(name: "vertex_main")
934
+ let fragmentFunction = library.makeFunction(name: "fragment_main")
935
+
936
+ // Set up vertex descriptor
937
+ let vertexDescriptor = MTLVertexDescriptor()
938
+ vertexDescriptor.attributes[0].format = .float2 // position (x, y)
939
+ vertexDescriptor.attributes[0].offset = 0
940
+ vertexDescriptor.attributes[0].bufferIndex = 0
941
+
942
+ vertexDescriptor.attributes[1].format = .float2 // texCoord (u, v)
943
+ vertexDescriptor.attributes[1].offset = MemoryLayout<Float>.size * 2
944
+ vertexDescriptor.attributes[1].bufferIndex = 0
945
+
946
+ vertexDescriptor.layouts[0].stride = MemoryLayout<Float>.size * 4 // 2 floats for pos + 2 for texCoord
947
+ vertexDescriptor.layouts[0].stepFunction = .perVertex
948
+
949
+ let pipelineDescriptor = MTLRenderPipelineDescriptor()
950
+ pipelineDescriptor.vertexDescriptor = vertexDescriptor
951
+ pipelineDescriptor.vertexFunction = vertexFunction
952
+ pipelineDescriptor.fragmentFunction = fragmentFunction
953
+
954
+ pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat(rawValue: colorPixelFormat) ?? .bgra8Unorm
955
+ pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormat(rawValue: depthStencilPixelFormat) ?? .depth32Float_stencil8
956
+ pipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormat(rawValue: depthStencilPixelFormat) ?? .depth32Float_stencil8
957
+
958
+ pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
959
+ pipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
960
+ pipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
961
+ pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
962
+ pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
963
+ pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
964
+ pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
965
+
966
+ do {
967
+ self.pipelineState = try metalDevice.makeRenderPipelineState(descriptor: pipelineDescriptor)
968
+ } catch {
969
+ print("❌ [GridRenderLayer] Failed to create pipeline state: \(error)")
970
+ return
971
+ }
972
+
973
+ let dataSamplerDesc = MTLSamplerDescriptor()
974
+ dataSamplerDesc.minFilter = .nearest
975
+ dataSamplerDesc.magFilter = .nearest
976
+ self.dataSamplerState = metalDevice.makeSamplerState(descriptor: dataSamplerDesc)
977
+
978
+ let colormapSamplerDesc = MTLSamplerDescriptor()
979
+ colormapSamplerDesc.minFilter = .nearest
980
+ colormapSamplerDesc.magFilter = .nearest
981
+ colormapSamplerDesc.sAddressMode = .clampToEdge
982
+ self.colormapSamplerState = metalDevice.makeSamplerState(descriptor: colormapSamplerDesc)
983
+
984
+ // Process any pending updates that came in before Metal was ready
985
+ if let pendingGeometry = pendingGeometryUpdate {
986
+ updateGeometry(corners: pendingGeometry.corners, gridDef: pendingGeometry.gridDef)
987
+ pendingGeometryUpdate = nil
988
+ }
989
+
990
+ if let pendingColormap = pendingColormapUpdate {
991
+ updateColormapTexture(colormapAsBase64: pendingColormap)
992
+ pendingColormapUpdate = nil
993
+ }
994
+
995
+ if let pendingData = pendingDataUpdate {
996
+ updateDataTexture(data: pendingData.data, nx: pendingData.nx, ny: pendingData.ny,
997
+ scale: pendingData.scale, offset: pendingData.offset,
998
+ missing: pendingData.missing, scaleType: pendingData.scaleType)
999
+ pendingDataUpdate = nil
1000
+ }
1001
+ }
1002
+ internal func internalRender(_ parameters: CustomLayerRenderParameters, mtlCommandBuffer: MTLCommandBuffer, mtlRenderPassDescriptor: MTLRenderPassDescriptor) {
1003
+ guard isVisible,
1004
+ let pipeline = pipelineState,
1005
+ let vertices = vertexBuffer,
1006
+ let indices = indexBuffer,
1007
+ let dataTex = dataTexture,
1008
+ let colormapTex = colormapTexture,
1009
+ indexCount > 0,
1010
+ let encoder = mtlCommandBuffer.makeRenderCommandEncoder(descriptor: mtlRenderPassDescriptor) else {
1011
+
1012
+ return
1013
+ }
1014
+
1015
+ let needsLinear = (uniforms.smoothing != 0)
1016
+ if isDataSamplerLinear != needsLinear {
1017
+ let samplerDesc = MTLSamplerDescriptor()
1018
+ samplerDesc.minFilter = needsLinear ? .linear : .nearest
1019
+ samplerDesc.magFilter = needsLinear ? .linear : .nearest
1020
+ dataSamplerState = device.makeSamplerState(descriptor: samplerDesc)
1021
+ isDataSamplerLinear = needsLinear
1022
+ }
1023
+
1024
+ // Apply zoom scale transformation
1025
+ let zoom = parameters.zoom
1026
+ let scale = Float(pow(2.0, zoom))
1027
+
1028
+ let matrixArray = parameters.projectionMatrix
1029
+ var floatArray = matrixArray.map { $0.floatValue }
1030
+
1031
+ floatArray[0] *= scale // X scale
1032
+ floatArray[1] *= scale // X rotation
1033
+ floatArray[2] *= scale // X Z-component
1034
+ floatArray[3] *= scale // X translation
1035
+ floatArray[4] *= scale // Y rotation
1036
+ floatArray[5] *= scale // Y scale
1037
+ floatArray[6] *= scale // Y Z-component
1038
+ floatArray[7] *= scale // Y translation
1039
+ floatArray[8] *= scale // Z X-component
1040
+ floatArray[9] *= scale // Z Y-component
1041
+ floatArray[10] *= scale // Z scale
1042
+ floatArray[11] *= scale // Z translation
1043
+
1044
+ let mvp = matrix_float4x4(
1045
+ SIMD4<Float>(floatArray[0], floatArray[1], floatArray[2], floatArray[3]),
1046
+ SIMD4<Float>(floatArray[4], floatArray[5], floatArray[6], floatArray[7]),
1047
+ SIMD4<Float>(floatArray[8], floatArray[9], floatArray[10], floatArray[11]),
1048
+ SIMD4<Float>(floatArray[12], floatArray[13], floatArray[14], floatArray[15])
1049
+ )
1050
+
1051
+ // Add depth state
1052
+ let depthStencilDescriptor = MTLDepthStencilDescriptor()
1053
+ depthStencilDescriptor.depthCompareFunction = .always
1054
+ depthStencilDescriptor.isDepthWriteEnabled = false
1055
+ let depthStencilState = device.makeDepthStencilState(descriptor: depthStencilDescriptor)
1056
+
1057
+ encoder.setRenderPipelineState(pipeline)
1058
+ encoder.setDepthStencilState(depthStencilState!)
1059
+ encoder.setVertexBuffer(vertices, offset: 0, index: 0)
1060
+ encoder.setVertexBytes([mvp], length: MemoryLayout<matrix_float4x4>.size, index: 1)
1061
+
1062
+ var mutableUniforms = uniforms
1063
+ encoder.setFragmentBytes(&mutableUniforms, length: MemoryLayout<FragmentUniforms>.stride, index: 0)
1064
+ encoder.setFragmentTexture(dataTex, index: 0)
1065
+ encoder.setFragmentTexture(colormapTex, index: 1)
1066
+ encoder.setFragmentSamplerState(dataSamplerState, index: 0)
1067
+ encoder.setFragmentSamplerState(colormapSamplerState, index: 1)
1068
+
1069
+ encoder.drawIndexedPrimitives(type: .triangle, indexCount: indexCount, indexType: .uint16, indexBuffer: indices, indexBufferOffset: 0)
1070
+
1071
+ encoder.endEncoding()
1072
+ }
1073
+
1074
+ deinit {
1075
+ print("🔴 [GridRenderLayer] deinit called for layer: \(id)")
1076
+
1077
+ // Clean up all resources
1078
+ frameCacheQueue.sync {
1079
+ frameCache.removeAll()
1080
+ }
1081
+ vertexBuffer = nil
1082
+ indexBuffer = nil
1083
+ dataTexture = nil
1084
+ colormapTexture = nil
1085
+ device = nil
1086
+ commandQueue = nil
1087
+ pipelineState = nil
1088
+ dataSamplerState = nil
1089
+ colormapSamplerState = nil
1090
+
1091
+ // Break the reference cycle
1092
+ hostWrapper = nil
1093
+ }
1094
+
1095
+ internal func internalRenderingWillEnd() {
1096
+ // DO NOT clear these here, otherwise the layer disappears during map transitions/resizing
1097
+ // vertexBuffer = nil
1098
+ // indexBuffer = nil
1099
+ // dataTexture = nil
1100
+ // colormapTexture = nil
1101
+ }
1102
+ }
1103
+
1104
+ extension GridRenderLayer {
1105
+ // Override to prevent KVC crashes during cleanup
1106
+ open override func value(forUndefinedKey key: String) -> Any? {
1107
+ print("⚠️ [GridRenderLayer] Attempted to access undefined key: \(key)")
1108
+ return nil
1109
+ }
1110
+
1111
+ open override func setValue(_ value: Any?, forUndefinedKey key: String) {
1112
+ print("⚠️ [GridRenderLayer] Attempted to set undefined key: \(key)")
1113
+ // Silently ignore instead of crashing
1114
+ }
1115
+ }