Advertisement
Guest User

Untitled

a guest
Feb 17th, 2025
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 4.59 KB | None | 0 0
  1. import Foundation
  2. import simd
  3. import Synchronization
  4. import SwiftUI
  5.  
  6. struct ReferencePointStorage {
  7.     var position: SIMD2<Float>
  8.     var orbit: [SIMD2<Float>]
  9.     var period: Int32
  10.     var maxIter: Int32
  11. }
  12.  
  13. final class ReferencePoint: Sendable {
  14.     let storage: Mutex<ReferencePointStorage>
  15.  
  16.     init(position: SIMD2<Float>, scale: Float) {
  17.         storage = .init(.init(position: position, orbit: Array(repeating: SIMD2<Float>(0, 0), count: 1024), period: 0, maxIter: 100))
  18.         Task {
  19.             await calculateOrbit(scale: scale)
  20.         }
  21.     }
  22.  
  23.     func updatePosition(position: SIMD2<Float>, scale: Float) {
  24.         storage.withLock {
  25.             $0.position = position
  26.             Task {
  27.                 await calculateOrbit(scale: scale)
  28.             }
  29.         }
  30.     }
  31.  
  32.     func calculateOrbit(scale: Float) async {
  33.         var z = SIMD2<Float>(0, 0)
  34.         storage.withLock {
  35.             $0.maxIter = Int32(min(100 + log2(Float(scale)) * 25, 1000))
  36.  
  37.             for i in 0..<1024 {
  38.                 $0.orbit[i] = z
  39.  
  40.                 let real = z.x * z.x - z.y * z.y + $0.position.x
  41.                 let imag = 2 * z.x * z.y + $0.position.y
  42.                 z = SIMD2<Float>(real, imag)
  43.  
  44.                 if (z.x * z.x + z.y * z.y) > 4 {
  45.                     $0.maxIter = Int32(i)
  46.                     break
  47.                 }
  48.  
  49.                 if i > 20 {
  50.                     for j in 1...20 {
  51.                         if abs(z.x - $0.orbit[i-j].x) < 1e-6 && abs(z.y - $0.orbit[i-j].y) < 1e-6 {
  52.                             $0.period = Int32(j)
  53.                             $0.maxIter = Int32(i)
  54.                             return
  55.                         }
  56.                     }
  57.                 }
  58.             }
  59.         }
  60.     }
  61.  
  62.     func getData() -> sending Data {
  63.         var data = Data(capacity: MemoryLayout<SIMD2<Float>>.size * 1025 + MemoryLayout<Int32>.size * 2)
  64.  
  65.         storage.withLock {
  66.             var positionCopy = $0.position
  67.             var orbitCopy = $0.orbit
  68.             var periodCopy = $0.period
  69.             var maxIterCopy = $0.maxIter
  70.             data.append(Data(bytes: &positionCopy, count: MemoryLayout<SIMD2<Float>>.size))
  71.             data.append(Data(bytes: &orbitCopy, count: MemoryLayout<SIMD2<Float>>.size * 1024))
  72.             data.append(Data(bytes: &periodCopy, count: MemoryLayout<Int32>.size))
  73.             data.append(Data(bytes: &maxIterCopy, count: MemoryLayout<Int32>.size))
  74.         }
  75.         return data
  76.     }
  77.  
  78.     func getPosition() -> SIMD2<Float> {
  79.         storage.withLock {
  80.             return $0.position
  81.         }
  82.     }
  83. }
  84.  
  85. extension View {
  86.     func mandelbrotShader(offset: CGSize, scale: CGFloat, color: Color) -> some View {
  87.         modifier(MandelbrotShader(offset: offset, scale: scale, color: color))
  88.     }
  89. }
  90.  
  91. struct MandelbrotShader: ViewModifier {
  92.     let offset: CGSize
  93.     let scale: CGFloat
  94.     let color: Color
  95.  
  96.     @State private var referencePoint: ReferencePoint
  97.  
  98.     init(offset: CGSize, scale: CGFloat, color: Color) {
  99.         self.offset = offset
  100.         self.scale = scale
  101.         self.color = color
  102.         self.referencePoint = ReferencePoint(position: SIMD2<Float>(-0.5, 0), scale: Float(scale))
  103.     }
  104.  
  105.     func body(content: Content) -> some View {
  106.         content
  107.             .visualEffect { [referencePoint] content, proxy in
  108.                 let components = color.resolve(in: EnvironmentValues())
  109.  
  110.                 let existingPos = referencePoint.getPosition()
  111.                 let currentPos = SIMD2<Float>(
  112.                     Float(-0.5 + offset.width),
  113.                     Float(offset.height)
  114.                 )
  115.                 if simd_distance(currentPos, existingPos) > 0.1 / Float(scale) {
  116.                     referencePoint.updatePosition(position: currentPos, scale: Float(scale)) // UNSURE IF THIS WILL MUTATE THE @STATE VERSION
  117.  
  118.                     // AVOID THE NEED FOR MUTATION HERE BY PASSING getData() TO .data() BELOW
  119.                     //                        self.referenceData = referencePoint?.getData() ?? Data()
  120.                     //                        print(self.referenceData)
  121.                 }
  122.  
  123.                 return content
  124.                     .colorEffect(ShaderLibrary.mandelbrot(
  125.                         .float2(proxy.size),
  126.                         .float2(Float(offset.width), Float(offset.height)),
  127.                         .float(Float(scale)),
  128.                         .float3(Float(components.red), Float(components.green), Float(components.blue)),
  129.                         .data(referencePoint.getData())
  130.                     ))
  131.             }
  132.     }
  133. }
  134.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement