0

How does one print NSValue bytes? When using print it doesn't print all the bytes and puts '...'. E.g. {length = 128, bytes = 0x00000000 0000f03f 00000000 00000000 ... 00000000 0000f03f }

import Cocoa
import SceneKit

var identityMatrix = SCNMatrix4()

identityMatrix.m11 = 1
identityMatrix.m12 = 0
identityMatrix.m13 = 0
identityMatrix.m14 = 0
identityMatrix.m21 = 0
identityMatrix.m22 = 1
identityMatrix.m23 = 0
identityMatrix.m24 = 0
identityMatrix.m31 = 0
identityMatrix.m32 = 0
identityMatrix.m33 = 1
identityMatrix.m34 = 0
identityMatrix.m41 = 0
identityMatrix.m42 = 0
identityMatrix.m43 = 0
identityMatrix.m44 = 1

var a = [NSValue]()

a.append(NSValue(scnMatrix4:identityMatrix))

identityMatrix.m11 = 1
identityMatrix.m12 = 0
identityMatrix.m13 = 0
identityMatrix.m14 = 0
identityMatrix.m21 = 0
identityMatrix.m22 = 1
identityMatrix.m23 = 0
identityMatrix.m24 = 0
identityMatrix.m31 = 0
identityMatrix.m32 = 0
identityMatrix.m33 = 1
identityMatrix.m34 = 0
identityMatrix.m41 = 0
identityMatrix.m42 = -1.0
identityMatrix.m43 = 0
identityMatrix.m44 = 1

a.append(NSValue(scnMatrix4:identityMatrix))

print(a[0])
bhartsb
  • 1,316
  • 14
  • 39
  • 2
    This is just using the default implementation of `NSValue.description`. If you want to print it a different way, you’ll have to implement that yourself. What are you trying to do? To be clear, printing the bytes of an NSValue isn’t a particularly sensible goal in the first place, because SCNMatrix4 ,ales no guarantees about its storage layout. – Alexander Dec 28 '21 at 04:21
  • @Alexander I have a reference that provides a byte layout that I want to compare against. And if as you say that it is not sensible then have the print implementation print any of the internal bytes. – bhartsb Dec 28 '21 at 08:46
  • 1
    "I have a reference that provides a byte layout" And what do you expect from your first two matrix? You need to print yourself m11, m12, etc, be make sense of your matrix, be it float, hex bytes, etc. – Larme Dec 28 '21 at 16:09

1 Answers1

1

First of all, we can tidy this up by using an array literal, and the SCNMatrix4 initializer to get rid of all the mutability:

import Cocoa
import SceneKit

let a = [
    SCNMatrix4(
        m11: 1, m12: 0, m13: 0, m14: 0,
        m21: 0, m22: 0, m23: 0, m24: 0,
        m31: 0, m32: 0, m33: 1, m34: 0,
        m41: 0, m42: 0, m43: 0, m44: 1
    ),
    SCNMatrix4(
        m11: 1, m12:  0, m13: 0, m14: 0,
        m21: 0, m22:  1, m23: 0, m24: 0,
        m31: 0, m32:  0, m33: 1, m34: 0,
        m41: 0, m42: -1, m43: 0, m44: 1
    ),
].map(NSValue.init(scnMatrix4:))

print(a[0])

That makes the code much more sensible. We can also notice from the documentation that there's already a constant that we can use to get an identity matrix:

import Cocoa
import SceneKit

let a = [
    SCNMatrix4Identity,
    SCNMatrix4(
        m11: 1, m12:  0, m13: 0, m14: 0,
        m21: 0, m22:  1, m23: 0, m24: 0,
        m31: 0, m32:  0, m33: 1, m34: 0,
        m41: 0, m42: -1, m43: 0, m44: 1
    ),
].map(NSValue.init(scnMatrix4:))

print(a[0])

It's not clear why these matrices are wrapped in NSValue, but to display details about them (and call other methods on them), you'll need to fish the matrix back out of the NSValue box using the scnMatrix4Value API:

let sampleMatrix = a[0].scnMatrix4Value
print(sampleMatrix)

If you want to print the byte layout of these, (although it's still really not clear why you would want this, since AFAICT, NSValue and SCNMatrix4 make no promises about their memory layout), you can use the usual pointer APIs, in combination with some hex printing logic such as this:

withUnsafeBytes(of: &sampleMatrix) { sampleMatrixPointer in
    print(sampleMatrixPointer.map { String(format: "%02x", $0) }.joined(separator: ""))
}

prints:

000000000000f03f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f03f0000000000000000000000000000000000000000000000000000000000000000000000000000f03f
Alexander
  • 59,041
  • 12
  • 98
  • 151
  • Thanks for your answer. Since you asked, the main issue I'm facing involves use of class SCNSkinner and its boneInverseBindTransforms:[NSValue]? init parameter. I have a Maya plugin that transfers skinCluster data to a MacOS app and so far can't get SCNSkinner to work. I found a simple example that provides the byte layout: https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/SimpleSkin that I'm referencing while trying to figure out what is not working. The reason for the mutability is that I'm changing the matrix values and what is posted is simply copy pasted test code. – bhartsb Dec 28 '21 at 20:47
  • That seems like a different system entirely, I don't think there's any reason to expect the byte layout will be the same. – Alexander Dec 29 '21 at 02:08
  • I don't expect. I'm simply exploring and looking at differences. Printing might not be useful in this instance but it may be useful in other instances. – bhartsb Dec 29 '21 at 03:03
  • I'm passing what I think are correct parameters to the SCNSkinner initializer and it is mangling the geometry. If I don't attach the skinner to the SCNNode with the geometry the geometry renders correctly. Thought I would use the simple example from the link above as reference sample data, but still not getting results. – bhartsb Dec 29 '21 at 03:17