Dereference UnsafeMutablePointer

2019-07-26 22:24发布

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;
                  }
              }
          }];

2条回答
再贱就再见
2楼-- · 2019-07-26 22:44

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.

查看更多
冷血范
3楼-- · 2019-07-26 22:47

You can actually subscript the typed UnsafeMutablePointer without having to create an UnsafeMutableBufferPointer, as in:

let colorsPointer:UnsafeMutableRawPointer = data[0] + dataStride[0] * i
let rgbaBuffer = colorsPointer.bindMemory(to: Float.self, capacity: dataStride[0])
if(arc4random_uniform(2) == 1) {
    rgbaBuffer[0] = rgbaBuffer[1]
    rgbaBuffer[1] = 0
}

Were you ever able to get your solution to work? It appears only a handful of SCNParticleProperties can be used within an SCNParticleEventBlock block.

查看更多
登录 后发表回答