mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
For every struct type for which the frameworks provides an NSValue category for boxing and unboxing values of that type, provide an _ObjectiveCBridgeable conformance in the Swift overlay that bridges that struct to NSValue, allowing the structs to be used naturally with id-as-Any APIs and Cocoa container classes. This is mostly a matter of gyb-ing out boilerplate using `NSValue.init(bytes:objCType:)` to construct the instance, `NSValue.objCType` to check its type when casting, and `NSValue.getValue(_:)` to extract the unboxed value, though there are a number of special snowflake cases that need special accommodation: - To maintain proper layering, CoreGraphics structs need to be bridged in the Foundation overlay. - AVFoundation provides the NSValue boxing categories for structs owned by CoreMedia, but it does so using its own internal subclasses of NSValue, and these subclasses do not interop properly with the standard `NSValue` subclasses instantiated by Foundation. To do the right thing, we therefore have to let AVFoundation provide the bridging implementation for the CoreMedia types, and we have to use its category methods to do so. - SceneKit provides NSValue categories to box and unbox SCNVector3, SCNVector4, and SCNMatrix4; however, the methods it provides do so in an unusual way. SCNVector3 and SCNVector4 are packaged into `CGRect`s and then the CGRect is boxed using `valueWithCGRect:`. SCNMatrix4 is copied into a CATransform3D, which is then boxed using `valueWithCATransform3D:` from CoreAnimation. To be consistent with what SceneKit does, use its category methods for these types as well, and when casting, check the type against the type encoding SceneKit uses rather than the type encoding of the expected type.
244 lines
7.6 KiB
Swift
244 lines
7.6 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
// REQUIRES: objc_interop
|
|
// UNSUPPORTED: OS=watchos
|
|
|
|
import StdlibUnittest
|
|
import StdlibUnittestFoundationExtras
|
|
|
|
|
|
import SceneKit
|
|
|
|
// SceneKit is only available on iOS 8.0 and above and on OS X 10.8 and above.
|
|
// That said SCNMatrix4Scale &co are only available on OS X 10.10 and above.
|
|
|
|
var SceneKitTests = TestSuite("SceneKit")
|
|
|
|
if #available(iOS 8.0, OSX 10.10, *) {
|
|
let scn_vec3_ref = SCNVector3Make(1, 2, 3)
|
|
let scn_vec4_ref = SCNVector4Make(1, 2, 3, 4)
|
|
let scn_mat4_ref = SCNMatrix4Scale(SCNMatrix4Translate(SCNMatrix4MakeRotation(SCNFloat(M_PI), 1, 0, 0), 1, 2, 3), 10, 20, 30)
|
|
|
|
// MARK: Exposing SCNFloat
|
|
|
|
SceneKitTests.test("SCNFloat") {
|
|
let f = Float(1.0)
|
|
let scn_float_from_f = SCNFloat(f)
|
|
expectEqual(scn_float_from_f, 1.0)
|
|
|
|
let d = Double(2.0)
|
|
let scn_float_from_d = SCNFloat(d)
|
|
expectEqual(scn_float_from_d, 2.0)
|
|
|
|
let cg = CGFloat(3.0)
|
|
let scn_float_from_cg = SCNFloat(cg as NSNumber)
|
|
expectEqual(scn_float_from_cg, 3.0)
|
|
|
|
let node = SCNNode()
|
|
node.position.x = scn_float_from_f
|
|
node.position.y = scn_float_from_d
|
|
node.position.z = scn_float_from_cg
|
|
expectTrue(SCNVector3EqualToVector3(node.position, scn_vec3_ref))
|
|
|
|
let f1: SCNFloat = scn_vec3_ref.x
|
|
let f2: SCNFloat = scn_vec4_ref.y
|
|
expectEqual(f1, 1.0);
|
|
expectEqual(f2, 2.0);
|
|
}
|
|
|
|
// MARK: Working with SCNVector3
|
|
|
|
SceneKitTests.test("SCNVector3.init()/Literal") {
|
|
let scn_vec3_from_lit = SCNVector3(1, 2, 3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_lit, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/Float") {
|
|
let f1: Float = 1.0
|
|
let f2: Float = 2.0
|
|
let f3: Float = 3.0
|
|
let scn_vec3_from_f = SCNVector3(f1, f2, f3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_f, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/CGFloat") {
|
|
let d1: CGFloat = 1.0
|
|
let d2: CGFloat = 2.0
|
|
let d3: CGFloat = 3.0
|
|
let scn_vec3_from_cg = SCNVector3(d1, d2, d3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_cg, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/Double") {
|
|
let d1: Double = 1.0
|
|
let d2: Double = 2.0
|
|
let d3: Double = 3.0
|
|
let scn_vec3_from_d = SCNVector3(d1, d2, d3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_d, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/Int") {
|
|
let i1: Int = 1
|
|
let i2: Int = 2
|
|
let i3: Int = 3
|
|
let scn_vec3_from_i = SCNVector3(i1, i2, i3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_i, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/float3") {
|
|
let v3 = float3(1, 2, 3)
|
|
let scn_vec3_from_float3 = SCNVector3(v3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_float3, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/double3") {
|
|
let v3 = double3(1, 2, 3)
|
|
let scn_vec3_from_double3 = SCNVector3(v3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_double3, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector3.init()/mix") {
|
|
let f1: Float = 1.0
|
|
let d2: CGFloat = 2.0
|
|
let scn_vec3_from_mixed = SCNVector3(f1, Float(d2), 3)
|
|
expectTrue(SCNVector3EqualToVector3(scn_vec3_from_mixed, scn_vec3_ref))
|
|
}
|
|
|
|
SceneKitTests.test("float3.init()/SCNVector3") {
|
|
let v3 = float3(scn_vec3_ref)
|
|
expectEqual(v3.x, 1.0)
|
|
expectEqual(v3.y, 2.0)
|
|
expectEqual(v3.z, 3.0)
|
|
}
|
|
|
|
SceneKitTests.test("double3.init()/SCNVector3") {
|
|
let v3 = double3(scn_vec3_ref)
|
|
expectEqual(v3.x, 1.0)
|
|
expectEqual(v3.y, 2.0)
|
|
expectEqual(v3.z, 3.0)
|
|
}
|
|
|
|
// MARK: Working with SCNVector4
|
|
|
|
SceneKitTests.test("SCNVector4.init()/Literal") {
|
|
let scn_vec4_from_lit = SCNVector4(1, 2, 3, 4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_lit, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/Float") {
|
|
let f1: Float = 1.0
|
|
let f2: Float = 2.0
|
|
let f3: Float = 3.0
|
|
let f4: Float = 4.0
|
|
let scn_vec4_from_f = SCNVector4(f1, f2, f3, f4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_f, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/CGFloat") {
|
|
let d1: CGFloat = 1.0
|
|
let d2: CGFloat = 2.0
|
|
let d3: CGFloat = 3.0
|
|
let d4: CGFloat = 4.0
|
|
let scn_vec4_from_cg = SCNVector4(d1, d2, d3, d4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_cg, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/Double") {
|
|
let d1: Double = 1.0
|
|
let d2: Double = 2.0
|
|
let d3: Double = 3.0
|
|
let d4: Double = 4.0
|
|
let scn_vec4_from_d = SCNVector4(d1, d2, d3, d4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_d, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/Int") {
|
|
let i1: Int = 1
|
|
let i2: Int = 2
|
|
let i3: Int = 3
|
|
let i4: Int = 4
|
|
let scn_vec4_from_i = SCNVector4(i1, i2, i3, i4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_i, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/float4") {
|
|
let v4 = float4(1, 2, 3, 4)
|
|
let scn_vec4_from_float4 = SCNVector4(v4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_float4, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/double4") {
|
|
let v4 = double4(1, 2, 3, 4)
|
|
let scn_vec4_from_double4 = SCNVector4(v4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_double4, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNVector4.init()/mix") {
|
|
let f1: Float = 1.0
|
|
let d2: CGFloat = 2.0
|
|
let f4: Float = 4.0
|
|
let scn_vec4_from_mixed = SCNVector4(f1, Float(d2), 3, f4)
|
|
expectTrue(SCNVector4EqualToVector4(scn_vec4_from_mixed, scn_vec4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("float4.init()/SCNVector4") {
|
|
let v4 = float4(scn_vec4_ref)
|
|
expectEqual(v4.x, 1.0)
|
|
expectEqual(v4.y, 2.0)
|
|
expectEqual(v4.z, 3.0)
|
|
expectEqual(v4.w, 4.0)
|
|
}
|
|
|
|
SceneKitTests.test("double4.init()/SCNVector4") {
|
|
let v4 = double4(scn_vec4_ref)
|
|
expectEqual(v4.x, 1.0)
|
|
expectEqual(v4.y, 2.0)
|
|
expectEqual(v4.z, 3.0)
|
|
expectEqual(v4.w, 4.0)
|
|
}
|
|
|
|
// MARK: Working with SCNMatrix4
|
|
|
|
SceneKitTests.test("SCNMatrix4.init()/float4x4 + float4x4.init()/SCNMatrix4") {
|
|
let mat4_from_scn_mat4 = float4x4(scn_mat4_ref)
|
|
let scn_vec4_from_mat4 = SCNMatrix4(mat4_from_scn_mat4)
|
|
expectTrue(SCNMatrix4EqualToMatrix4(scn_vec4_from_mat4, scn_mat4_ref))
|
|
}
|
|
|
|
SceneKitTests.test("SCNMatrix4.init()/double4x4 + double4x4.init()/SCNMatrix4") {
|
|
let mat4_from_scn_mat4 = double4x4(scn_mat4_ref)
|
|
let scn_vec4_from_mat4 = SCNMatrix4(mat4_from_scn_mat4)
|
|
expectTrue(SCNMatrix4EqualToMatrix4(scn_vec4_from_mat4, scn_mat4_ref))
|
|
}
|
|
|
|
func equalVector3s(_ x: SCNVector3, _ y: SCNVector3) -> Bool {
|
|
return x.x == y.x && x.y == y.y && x.z == y.z
|
|
}
|
|
func equalVector4s(_ x: SCNVector4, _ y: SCNVector4) -> Bool {
|
|
return x.x == y.x && x.y == y.y && x.z == y.z && x.w == y.w
|
|
}
|
|
func equalMatrix4s(_ x: SCNMatrix4, _ y: SCNMatrix4) -> Bool {
|
|
var xx = x, yy = y
|
|
return memcmp(&xx, &yy, MemoryLayout<SCNMatrix4>.size) == 0
|
|
}
|
|
|
|
SceneKitTests.test("NSValue bridging") {
|
|
expectBridgeToNSValue(scn_vec3_ref,
|
|
nsValueInitializer: { NSValue(scnVector3: $0) },
|
|
nsValueGetter: { $0.scnVector3Value },
|
|
equal: equalVector3s)
|
|
expectBridgeToNSValue(scn_vec4_ref,
|
|
nsValueInitializer: { NSValue(scnVector4: $0) },
|
|
nsValueGetter: { $0.scnVector4Value },
|
|
equal: equalVector4s)
|
|
expectBridgeToNSValue(scn_mat4_ref,
|
|
nsValueInitializer: { NSValue(scnMatrix4: $0) },
|
|
nsValueGetter: { $0.scnMatrix4Value },
|
|
equal: equalMatrix4s)
|
|
}
|
|
}
|
|
|
|
runAllTests()
|
|
|