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