Search code examples
arraysswift3unsafemutablepointer

Dereference UnsafeMutablePointer<UnsafeMutableRawPointer>


I have a block that is passing data in that I'd like to convert to an array of array of floats -- e.g. [[0.1,0.2,0.3, 1.0], [0.3, 0.4, 0.5, 1.0], [0.5, 0.6, 0.7, 1.0]]. This data is passed to me in the form of data:UnsafeMutablePointer<UnsafeMutableRawPointer> (The inner arrays are RGBA values)

fwiw -- the block parameters are from SCNParticleEventBlock

How can I dereference data into a [[Float]]? Once I have the array containing the inner arrays, I can reference the inner array (colorArray) data with:

let rgba: UnsafeMutablePointer<Float> = UnsafeMutablePointer(mutating: colorArray)
let count = 4
for i in 0..<count {
    print((rgba+i).pointee)
}

fwiw -- this is Apple's example Objective-C code for referencing the data (from SCNParticleSystem handle(_:forProperties:handler:) )

[system handleEvent:SCNParticleEventBirth
      forProperties:@[SCNParticlePropertyColor]
          withBlock:^(void **data, size_t *dataStride, uint32_t *indices , NSInteger count) {
              for (NSInteger i = 0; i < count; ++i) {
                  float *color = (float *)((char *)data[0] + dataStride[0] * i);
                  if (rand() & 0x1) { // Switch the green and red color components.
                      color[0] = color[1];
                      color[1] = 0;
                  }
              }
          }];

Solution

  • Based on this answer, I've written the particle system handler function in swift as:

        ps.handle(SCNParticleEvent.birth, forProperties [SCNParticleSystem.ParticleProperty.color]) {
        (data:UnsafeMutablePointer<UnsafeMutableRawPointer>, dataStride:UnsafeMutablePointer<Int>, indicies:UnsafeMutablePointer<UInt32>?, count:Int) in
    
        for i in 0..<count {
    
            // get an UnsafeMutableRawPointer to the i-th rgba element in the data
            let colorsPointer:UnsafeMutableRawPointer = data[0] + dataStride[0] * i
    
            //  convert the UnsafeMutableRawPointer to a typed pointer by binding it to a type:
            let floatPtr = colorsPointer.bindMemory(to: Float.self, capacity: dataStride[0])
            // convert that to a an  UnsafeMutableBufferPointer
            var rgbaBuffer = UnsafeMutableBufferPointer(start: floatPtr, count: dataStride[0])
            // At this point, I could convert the buffer to an Array, but doing so copies the data into the array and any changes made in the array are not reflected in the original data.  UnsafeMutableBufferPointer are subscriptable, nice.
            //var rgbaArray = Array(rgbaBuffer)
    
            // about half the time, mess with the red and green components
            if(arc4random_uniform(2) == 1) {
                rgbaBuffer[0] = rgbaBuffer[1]
                rgbaBuffer[1] = 0
            }
        }
     }
    

    I'm really not certain if this is the most direct way to go about this and seems rather cumbersome compared to the objective-C code (see above question). I'm certainly open to other solutions and/or comments on this solution.