Compare commits
50 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
3a043b41c6 | |
![]() |
8512600e7d | |
![]() |
a8916f6e60 | |
![]() |
0bef3b8633 | |
![]() |
46fd54f726 | |
![]() |
31dea75e7c | |
![]() |
8c02951c65 | |
![]() |
9a4685ba98 | |
![]() |
8e65bf0f64 | |
![]() |
8c0d86d542 | |
![]() |
956583145d | |
![]() |
bcb7294eb1 | |
![]() |
19c3089f7e | |
![]() |
f6c9d76e03 | |
![]() |
af4c4926c5 | |
![]() |
463a27bc55 | |
![]() |
6b5faed6f6 | |
![]() |
e69d2f12ff | |
![]() |
9e0a0a4dcb | |
![]() |
0aed670c0c | |
![]() |
aacc3a5ad0 | |
![]() |
f9575a721c | |
![]() |
e49ed1f3b9 | |
![]() |
ed9d49fc09 | |
![]() |
8e6f6cc233 | |
![]() |
57c2ab5239 | |
![]() |
0bd59364e3 | |
![]() |
ba138d0435 | |
![]() |
6954f1d14b | |
![]() |
400350b6cf | |
![]() |
3d64f344fc | |
![]() |
f447e8ff21 | |
![]() |
d9acd1908c | |
![]() |
b76b663998 | |
![]() |
84e08299b2 | |
![]() |
c15ba1516c | |
![]() |
78c088b0a2 | |
![]() |
8ce9159f71 | |
![]() |
6c8375673c | |
![]() |
fe182c4736 | |
![]() |
34870fb42e | |
![]() |
7eeff81550 | |
![]() |
b376d0ff86 | |
![]() |
d657965b74 | |
![]() |
e600336537 | |
![]() |
f0c359c281 | |
![]() |
c5daa186b6 | |
![]() |
a0dcfaf12c | |
![]() |
5171e72c20 | |
![]() |
28173ad725 |
|
@ -0,0 +1,15 @@
|
||||||
|
name: Swift
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: macOS-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Build
|
||||||
|
run: swift build -v
|
||||||
|
- name: Run tests
|
||||||
|
run: swift test -v
|
|
@ -1,6 +1,4 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/.build
|
/.build
|
||||||
/Packages
|
/Packages
|
||||||
gltf_scenekit.xcodeproj/project.xcworkspace/xcuserdata
|
**/xcuserdata
|
||||||
gltf_scenekit.xcodeproj/xcuserdata
|
|
||||||
glTFSceneKit.xcodeproj/xcuserdata
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[submodule "Draco"]
|
|
||||||
path = Draco
|
|
||||||
url = https://github.com/3d4medical/DracoSwiftPackage.git
|
|
1
Draco
1
Draco
|
@ -1 +0,0 @@
|
||||||
Subproject commit 10caef92253b10439b3bc560ecef4a79804f612a
|
|
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"object": {
|
|
||||||
"pins": [
|
|
||||||
{
|
|
||||||
"package": "Draco",
|
|
||||||
"repositoryURL": "https://github.com/3d4medical/DracoSwiftPackage.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "0dac933ae63d023d2ba87decb2a5485beac7f548",
|
|
||||||
"version": "0.0.9"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"version": 1
|
|
||||||
}
|
|
|
@ -1,19 +1,18 @@
|
||||||
// swift-tools-version:4.0
|
// swift-tools-version:5.0
|
||||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "glTFSceneKit",
|
name: "glTFSceneKit",
|
||||||
|
platforms: [
|
||||||
|
.macOS(.v10_12), .iOS(.v10),
|
||||||
|
],
|
||||||
products: [
|
products: [
|
||||||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||||
.library(
|
.library(
|
||||||
name: "glTFSceneKit",
|
name: "glTFSceneKit",
|
||||||
targets: ["glTFSceneKit"]),
|
targets: ["glTFSceneKit"])
|
||||||
],
|
|
||||||
dependencies: [
|
|
||||||
// Dependencies declare other packages that this package depends on.
|
|
||||||
.package(url: "https://github.com/3d4medical/DracoSwiftPackage.git", from: "0.0.9"),
|
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
|
@ -23,10 +22,8 @@ let package = Package(
|
||||||
dependencies: []),
|
dependencies: []),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "glTFSceneKitTests",
|
name: "glTFSceneKitTests",
|
||||||
dependencies: ["glTFSceneKit"]),
|
dependencies: ["glTFSceneKit"])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// swift build -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.13"
|
||||||
// swift build -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.12"
|
|
||||||
|
|
||||||
|
|
15
README.md
15
README.md
|
@ -32,13 +32,9 @@
|
||||||
|
|
||||||
|
|
||||||
#### Extensions
|
#### Extensions
|
||||||
- [X] KHR_draco_mesh_compression - Draco (supported draft version, need to fix when indices is short)
|
- [ ] KHR_draco_mesh_compression - Draco (supported draft version, need rework. temporary disabled)
|
||||||
- [X] 3D4M_compressed_texture - [Draft of unofficial extension.](https://github.com/sakrist/glTF/tree/extensions/compressed_texture/extensions/2.0/Vendor/3D4M_compressed_texture)
|
- [X] 3D4M_compressed_texture - [Draft of unofficial extension.](https://github.com/sakrist/glTF/tree/extensions/compressed_texture/extensions/2.0/Vendor/3D4M_compressed_texture)
|
||||||
|
|
||||||
## Dependecies
|
|
||||||
|
|
||||||
- [DracoSwiftPackage](https://github.com/3D4Medical/DracoSwiftPackage) - custom Draco package for decode
|
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```swift
|
```swift
|
||||||
|
@ -47,5 +43,12 @@ import glTFSceneKit
|
||||||
let directory = "..." // path to folder where is gltf file located
|
let directory = "..." // path to folder where is gltf file located
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
let glTF = try? decoder.decode(GLTF.self, from: jsonData)
|
let glTF = try? decoder.decode(GLTF.self, from: jsonData)
|
||||||
let scene = glTF?.convert(view:sceneView, directoryPath:directory)
|
if let converter = GLTFConverter(glTF: glTF) {
|
||||||
|
let scene = converter.convert(to: view.scene!, geometryCompletionHandler: {
|
||||||
|
// Geometries are loaded and textures are may still in loading process.
|
||||||
|
}) { (error) in
|
||||||
|
// Fully converted to SceneKit
|
||||||
|
// TODO: handle error.
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -8,27 +8,19 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SceneKit
|
import SceneKit
|
||||||
|
|
||||||
extension GLTF {
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
|
extension GLTFConverter {
|
||||||
var animationDuration:Double {
|
|
||||||
get { return (objc_getAssociatedObject(self, &Keys.animation_duration) as? Double ?? 0) }
|
func parseAnimations() throws {
|
||||||
set { objc_setAssociatedObject(self, &Keys.animation_duration, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
if let animations = glTF.animations {
|
||||||
}
|
for animation in animations {
|
||||||
|
|
||||||
func parseAnimations() {
|
|
||||||
if self.animations != nil {
|
|
||||||
for animation in self.animations! {
|
|
||||||
for channel in animation.channels {
|
for channel in animation.channels {
|
||||||
let sampler = animation.samplers[channel.sampler]
|
let sampler = animation.samplers[channel.sampler]
|
||||||
do {
|
try constructAnimation(sampler: sampler, target: channel.target)
|
||||||
try constructAnimation(sampler: sampler, target:channel.target)
|
|
||||||
} catch {
|
|
||||||
print(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for node in self.cache_nodes! {
|
for node in self.cache_nodes! {
|
||||||
let group = node?.value(forUndefinedKey: "group") as? CAAnimationGroup
|
let group = node?.value(forUndefinedKey: "group") as? CAAnimationGroup
|
||||||
if group != nil && self.animationDuration != 0 {
|
if group != nil && self.animationDuration != 0 {
|
||||||
|
@ -36,132 +28,141 @@ extension GLTF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func constructAnimation(sampler:GLTFAnimationSampler, target:GLTFAnimationChannelTarget ) throws {
|
func constructAnimation(sampler: GLTFAnimationSampler, target: GLTFAnimationChannelTarget ) throws {
|
||||||
|
|
||||||
let node:SCNNode = self.cache_nodes![target.node!]!
|
// let targetIndex = target.node!
|
||||||
|
// guard let node:SCNNode = self.cache_nodes?[targetIndex] else {
|
||||||
let accessorInput = self.accessors![sampler.input]
|
// throw GLTFError("constructAnimation: Can't find target node with \(targetIndex), sampler:\(sampler) target:\(target)")
|
||||||
let accessorOutput = self.accessors![sampler.output]
|
// }
|
||||||
|
//
|
||||||
var keyTimesFloat = [Float]()
|
// guard let accessorInput = glTF.accessors?[sampler.input] else {
|
||||||
if let (data, _, _) = loadAcessor(accessorInput) {
|
// throw GLTFError("Input accessor could not be found for sampler.input \(sampler.input)")
|
||||||
keyTimesFloat = dataAsArray(data, accessorInput.componentType, accessorInput.type) as! [Float]
|
// }
|
||||||
}
|
// guard let accessorOutput = glTF.accessors?[sampler.output] else {
|
||||||
let duration = Double(keyTimesFloat.last!)
|
// throw GLTFError("Output accessor could not be found for sampler.output \(sampler.output)")
|
||||||
let f_duration = Float(duration)
|
// }
|
||||||
let keyTimes: [NSNumber] = keyTimesFloat.map { NSNumber(value: $0 / f_duration ) }
|
//
|
||||||
|
// var keyTimesFloat = [Float]()
|
||||||
var values_ = [Any]()
|
// if let (bufferView, interleaved) = try determineAcessor(accessorInput),
|
||||||
if let (data, _, _) = loadAcessor(accessorOutput) {
|
// let data = try loadAcessor(accessorInput, bufferView, interleaved) {
|
||||||
values_ = dataAsArray(data, accessorOutput.componentType, accessorOutput.type)
|
// keyTimesFloat = dataAsArray(data, accessorInput.componentType, accessorInput.type) as! [Float]
|
||||||
}
|
// }
|
||||||
|
// let duration = Double(keyTimesFloat.last!)
|
||||||
var groupDuration:Double = 0
|
// let f_duration = Float(duration)
|
||||||
|
// let keyTimes: [NSNumber] = keyTimesFloat.map { NSNumber(value: $0 / f_duration ) }
|
||||||
var caanimations:[CAAnimation] = [CAAnimation]()
|
//
|
||||||
if target.path == .weights {
|
// var values_ = [Any]()
|
||||||
let weightPaths = node.value(forUndefinedKey: "weightPaths") as? [String]
|
// if let (bufferView, interleaved) = try determineAcessor(accessorOutput),
|
||||||
|
// let data = try loadAcessor(accessorInput, bufferView, interleaved) {
|
||||||
groupDuration = duration
|
// values_ = dataAsArray(data, accessorOutput.componentType, accessorOutput.type)
|
||||||
|
// }
|
||||||
var keyAnimations = [CAKeyframeAnimation]()
|
//
|
||||||
for path in weightPaths! {
|
// var groupDuration:Double = 0
|
||||||
let animation = CAKeyframeAnimation()
|
//
|
||||||
animation.keyPath = path
|
// var caanimations:[CAAnimation] = [CAAnimation]()
|
||||||
animation.keyTimes = keyTimes
|
// if target.path == .weights {
|
||||||
animation.duration = duration
|
// let weightPaths = node.value(forUndefinedKey: "weightPaths") as? [String]
|
||||||
keyAnimations.append(animation)
|
//
|
||||||
}
|
// groupDuration = duration
|
||||||
|
//
|
||||||
let step = keyAnimations.count
|
// var keyAnimations = [CAKeyframeAnimation]()
|
||||||
let dataLength = values_.count / step
|
// for path in weightPaths! {
|
||||||
guard dataLength == keyTimes.count else {
|
// let animation = CAKeyframeAnimation()
|
||||||
throw "data count mismatch: \(dataLength) != \(keyTimes.count)"
|
// animation.keyPath = path
|
||||||
}
|
// animation.keyTimes = keyTimes
|
||||||
|
// animation.duration = duration
|
||||||
for i in 0..<keyAnimations.count {
|
// keyAnimations.append(animation)
|
||||||
var valueIndex = i
|
// }
|
||||||
var v = [NSNumber]()
|
//
|
||||||
v.reserveCapacity(dataLength)
|
// let step = keyAnimations.count
|
||||||
for _ in 0..<dataLength {
|
// let dataLength = values_.count / step
|
||||||
v.append(NSNumber(value: (values_[valueIndex] as! Float) ))
|
// guard dataLength == keyTimes.count else {
|
||||||
valueIndex += step
|
// throw GLTFError("data count mismatch: \(dataLength) != \(keyTimes.count)")
|
||||||
}
|
// }
|
||||||
keyAnimations[i].values = v
|
//
|
||||||
}
|
// for i in 0..<keyAnimations.count {
|
||||||
|
// var valueIndex = i
|
||||||
caanimations = keyAnimations
|
// var v = [NSNumber]()
|
||||||
|
// v.reserveCapacity(dataLength)
|
||||||
} else {
|
// for _ in 0..<dataLength {
|
||||||
let keyFrameAnimation = CAKeyframeAnimation()
|
// v.append(NSNumber(value: (values_[valueIndex] as! Float) ))
|
||||||
|
// valueIndex += step
|
||||||
self.animationDuration = max(self.animationDuration, duration)
|
// }
|
||||||
|
// keyAnimations[i].values = v
|
||||||
keyFrameAnimation.keyPath = target.path.scn()
|
// }
|
||||||
keyFrameAnimation.keyTimes = keyTimes
|
//
|
||||||
keyFrameAnimation.values = values_
|
// caanimations = keyAnimations
|
||||||
keyFrameAnimation.repeatCount = .infinity
|
//
|
||||||
keyFrameAnimation.duration = duration
|
// } else {
|
||||||
|
// let keyFrameAnimation = CAKeyframeAnimation()
|
||||||
caanimations.append(keyFrameAnimation)
|
//
|
||||||
|
// self.animationDuration = max(self.animationDuration, duration)
|
||||||
groupDuration = self.animationDuration
|
//
|
||||||
}
|
// keyFrameAnimation.keyPath = target.path.scn()
|
||||||
|
// keyFrameAnimation.keyTimes = keyTimes
|
||||||
let group = (node.value(forUndefinedKey: "group") as? CAAnimationGroup) ?? CAAnimationGroup()
|
// keyFrameAnimation.values = values_
|
||||||
node.setValue(group, forUndefinedKey: "group")
|
// keyFrameAnimation.repeatCount = .infinity
|
||||||
var animations = group.animations ?? []
|
// keyFrameAnimation.duration = duration
|
||||||
animations.append(contentsOf: caanimations)
|
//
|
||||||
group.animations = animations
|
// caanimations.append(keyFrameAnimation)
|
||||||
group.duration = groupDuration
|
//
|
||||||
group.repeatCount = .infinity
|
// groupDuration = self.animationDuration
|
||||||
node.addAnimation(group, forKey: target.path.rawValue)
|
// }
|
||||||
|
//
|
||||||
|
// let group = (node.value(forUndefinedKey: "group") as? CAAnimationGroup) ?? CAAnimationGroup()
|
||||||
|
// node.setValue(group, forUndefinedKey: "group")
|
||||||
|
// var animations = group.animations ?? []
|
||||||
|
// animations.append(contentsOf: caanimations)
|
||||||
|
// group.animations = animations
|
||||||
|
// group.duration = groupDuration
|
||||||
|
// group.repeatCount = .infinity
|
||||||
|
// node.addAnimation(group, forKey: target.path.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSkin(_ skin:Int, _ scnNode:SCNNode) {
|
func loadSkin(_ skin: Int, _ scnNode: SCNNode) {
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataAsArray(_ data:Data, _ componentType:GLTFAccessorComponentType, _ type:GLTFAccessorType) -> [Any] {
|
func dataAsArray(_ data: Data, _ componentType: GLTFAccessorComponentType, _ type: GLTFAccessorType) -> [Any] {
|
||||||
var values = [Any]()
|
var values = [Any]()
|
||||||
switch componentType {
|
switch componentType {
|
||||||
case .BYTE:
|
case .BYTE:
|
||||||
values = data.array() as [Int8]
|
values = data.array() as [Int8]
|
||||||
break
|
|
||||||
case .UNSIGNED_BYTE:
|
case .UNSIGNED_BYTE:
|
||||||
values = data.array() as [UInt8]
|
values = data.array() as [UInt8]
|
||||||
break
|
|
||||||
case .SHORT:
|
case .SHORT:
|
||||||
values = data.array() as [Int16]
|
values = data.array() as [Int16]
|
||||||
break
|
|
||||||
case .UNSIGNED_SHORT:
|
case .UNSIGNED_SHORT:
|
||||||
values = data.array() as [UInt16]
|
values = data.array() as [UInt16]
|
||||||
break
|
|
||||||
case .UNSIGNED_INT:
|
case .UNSIGNED_INT:
|
||||||
values = data.array() as [UInt32]
|
values = data.array() as [UInt32]
|
||||||
break
|
|
||||||
case .FLOAT:
|
case .FLOAT:
|
||||||
do {
|
do {
|
||||||
switch type {
|
switch type {
|
||||||
case .SCALAR:
|
case .SCALAR:
|
||||||
values = data.array() as [Float]
|
values = data.array() as [Float]
|
||||||
break
|
|
||||||
case .VEC2:
|
case .VEC2:
|
||||||
values = data.array() as [SCNVector2]
|
values = data.array() as [SCNVector2]
|
||||||
break
|
|
||||||
case .VEC3:
|
case .VEC3:
|
||||||
values = data.array() as [GLKVector3]
|
values = data.array() as [GLKVector3]
|
||||||
for i in 0..<values.count {
|
for i in 0..<values.count {
|
||||||
values[i] = SCNVector3FromGLKVector3(values[i] as! GLKVector3)
|
values[i] = SCNVector3FromGLKVector3(values[i] as! GLKVector3)
|
||||||
}
|
}
|
||||||
break
|
|
||||||
case .VEC4:
|
case .VEC4:
|
||||||
values = data.array() as [GLKVector4]
|
values = data.array() as [GLKVector4]
|
||||||
for i in 0..<values.count {
|
for i in 0..<values.count {
|
||||||
values[i] = SCNVector4FromGLKVector4(values[i] as! GLKVector4)
|
values[i] = SCNVector4FromGLKVector4(values[i] as! GLKVector4)
|
||||||
}
|
}
|
||||||
break
|
|
||||||
case .MAT2:
|
case .MAT2:
|
||||||
break
|
break
|
||||||
case .MAT3:
|
case .MAT3:
|
||||||
|
@ -171,16 +172,15 @@ extension GLTF {
|
||||||
for i in 0..<values.count {
|
for i in 0..<values.count {
|
||||||
values[i] = SCNMatrix4FromGLKMatrix4(values[i] as! GLKMatrix4)
|
values[i] = SCNMatrix4FromGLKMatrix4(values[i] as! GLKMatrix4)
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
extension GLTFAnimationChannelTargetPath {
|
extension GLTFAnimationChannelTargetPath {
|
||||||
fileprivate func scn() -> String {
|
fileprivate func scn() -> String {
|
||||||
|
@ -196,5 +196,3 @@ extension GLTFAnimationChannelTargetPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,43 +8,45 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SceneKit
|
import SceneKit
|
||||||
|
|
||||||
enum CTLevel:Int {
|
enum CTLevel: Int {
|
||||||
case first = 0
|
case first = 0
|
||||||
case last
|
case last
|
||||||
case all
|
case all
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
extension GLTF {
|
extension GLTF {
|
||||||
|
|
||||||
func loadCompressedTexture(descriptor:GLTF_3D4MCompressedTextureExtension, loadLevel:CTLevel, completionHandler: @escaping (Any?, Error?) -> Void ) {
|
func loadCompressedTexture(descriptor: GLTF_3D4MCompressedTextureExtension, loadLevel: CTLevel, completionHandler: @escaping (Any?, Error?) -> Void ) {
|
||||||
|
|
||||||
let width = descriptor.width
|
let width = descriptor.width
|
||||||
let height = descriptor.height
|
let height = descriptor.height
|
||||||
|
|
||||||
if (width == 0 || height == 0) {
|
if width == 0 || height == 0 {
|
||||||
completionHandler(nil, "GLTF_3D4MCompressedTextureExtension: Failed to load texture, inappropriate texture size.")
|
completionHandler(nil, GLTFError("GLTF_3D4MCompressedTextureExtension: Failed to load texture, inappropriate texture size."))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let (bytesPerRow, pixelFormat) = _get_bpp_pixelFormat(descriptor.compression)
|
let (bytesPerRow, pixelFormat) = _get_bpp_pixelFormat(descriptor.compression)
|
||||||
|
|
||||||
if (pixelFormat == .invalid ) {
|
if pixelFormat == .invalid {
|
||||||
completionHandler(nil, "GLTF_3D4MCompressedTextureExtension: Failed to load texture, unsupported compression format \(descriptor.compression).")
|
completionHandler(nil, GLTFError("GLTF_3D4MCompressedTextureExtension: Failed to load texture, unsupported compression format \(descriptor.compression)."))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if loadLevel == .all {
|
if loadLevel == .all {
|
||||||
var buffers = [GLTFBuffer]()
|
var buffers = [GLTFBuffer]()
|
||||||
for bViewIndex in descriptor.sources {
|
for bViewIndex in descriptor.sources {
|
||||||
let buffer = self.buffers![self.bufferViews![bViewIndex].buffer]
|
let buffer = self.buffers![self.bufferViews![bViewIndex].buffer]
|
||||||
buffers.append(buffer)
|
buffers.append(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.loader.load(gltf:self, resources: Set(buffers)) { (error) in
|
self.loader.load(gltf: self, resources: Set(buffers), options: ResourceType.texture) { (error) in
|
||||||
var error_ = error
|
var error_ = error
|
||||||
var textureResult:Any?
|
var textureResult: Any?
|
||||||
|
|
||||||
if error == nil {
|
if error == nil {
|
||||||
var datas = [Data]()
|
var datas = [Data]()
|
||||||
for buffer in buffers {
|
for buffer in buffers {
|
||||||
if buffer.data != nil {
|
if buffer.data != nil {
|
||||||
datas.append(buffer.data!)
|
datas.append(buffer.data!)
|
||||||
|
@ -57,312 +59,305 @@ extension GLTF {
|
||||||
} catch {
|
} catch {
|
||||||
error_ = error
|
error_ = error
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
error_ = error
|
||||||
}
|
}
|
||||||
completionHandler(textureResult, error_)
|
completionHandler(textureResult, error_)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let sizeWidth = (loadLevel == .first) ? 32 : descriptor.width
|
let sizeWidth = (loadLevel == .first) ? 32 : descriptor.width
|
||||||
let sizeHeight = (loadLevel == .first) ? 32 : descriptor.height
|
let sizeHeight = (loadLevel == .first) ? 32 : descriptor.height
|
||||||
let index = (loadLevel == .first) ? descriptor.sources.last! : descriptor.sources.first!
|
let index = (loadLevel == .first) ? descriptor.sources.last! : descriptor.sources.first!
|
||||||
|
|
||||||
if let bView = self.bufferViews?[index] {
|
if let bView = self.bufferViews?[index] {
|
||||||
let buffer_ = self.buffers![bView.buffer]
|
let buffer_ = self.buffers![bView.buffer]
|
||||||
self.loader.load(gltf:self, resource: buffer_) { (buffer, error) in
|
self.loader.load(gltf: self, resource: buffer_, options: ResourceType.texture) { (buffer, error) in
|
||||||
var error_ = error
|
var error_ = error
|
||||||
var textureResult:Any?
|
var textureResult: Any?
|
||||||
var datas = [Data]()
|
var datas = [Data]()
|
||||||
if buffer.data != nil {
|
if buffer.data != nil {
|
||||||
datas.append(buffer.data!)
|
datas.append(buffer.data!)
|
||||||
do {
|
do {
|
||||||
textureResult = try self._createMetalTexture(sizeWidth, sizeHeight, pixelFormat, datas, bytesPerRow)
|
if !buffer_.uri!.contains("lacrimal")
|
||||||
|
&& !buffer_.uri!.contains("Bursa") {
|
||||||
|
textureResult = try self._createMetalTexture(sizeWidth, sizeHeight, pixelFormat, datas, bytesPerRow)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
error_ = error
|
error_ = error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error_ = "Can't load data for \(buffer.uri ?? "")"
|
error_ = GLTFError("Can't load data for \(buffer.uri ?? "")")
|
||||||
}
|
}
|
||||||
|
|
||||||
completionHandler(textureResult, error_)
|
completionHandler(textureResult, error_)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _createMetalTexture( _ width:Int, _ height:Int, _ pixelFormat:MTLPixelFormat, _ mipmaps:[Data], _ bppBlock:(Int, Int)->Int) throws -> MTLTexture {
|
fileprivate func _createMetalTexture( _ width: Int, _ height: Int, _ pixelFormat: MTLPixelFormat, _ mipmaps: [Data], _ bppBlock: (Int, Int) -> Int) throws -> MTLTexture {
|
||||||
var width = width
|
var width = width
|
||||||
var height = height
|
var height = height
|
||||||
let mipmapsCount = mipmaps.count
|
let mipmapsCount = mipmaps.count
|
||||||
|
|
||||||
if mipmapsCount == 0 {
|
if mipmapsCount == 0 {
|
||||||
throw "mipmaps array can't be empty."
|
throw GLTFError("mipmaps array can't be empty.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: pixelFormat,
|
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: pixelFormat,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
mipmapped: (mipmapsCount > 1))
|
mipmapped: (mipmapsCount > 1))
|
||||||
textureDescriptor.mipmapLevelCount = mipmapsCount
|
textureDescriptor.mipmapLevelCount = mipmapsCount
|
||||||
|
|
||||||
var device:MTLDevice?
|
guard let device = MetalDevice.device else {
|
||||||
#if os(macOS)
|
throw GLTFError("View has Metal's render APi but can't get instance of MTLDevice.")
|
||||||
device = self.renderer?.device
|
|
||||||
#endif
|
|
||||||
if (device == nil) {
|
|
||||||
device = MTLCreateSystemDefaultDevice()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device == nil) {
|
guard let texture = device.makeTexture(descriptor: textureDescriptor) else {
|
||||||
throw "View has Metal's render APi but can't get instance of MTLDevice."
|
throw GLTFError("Failed to create metal texture with descriptor \(textureDescriptor)")
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture = device?.makeTexture(descriptor: textureDescriptor)
|
|
||||||
|
|
||||||
if (texture == nil) {
|
|
||||||
throw "Failed to create metal texture with descriptor \(textureDescriptor)"
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0 ..< mipmapsCount {
|
for i in 0 ..< mipmapsCount {
|
||||||
let data = mipmaps[i]
|
let data = mipmaps[i]
|
||||||
let bPr = bppBlock(width, height)
|
let bPr = bppBlock(width, height)
|
||||||
data.withUnsafeBytes { (unsafeBufferPointer:UnsafeRawBufferPointer) in
|
data.withUnsafeBytes { (unsafeBufferPointer: UnsafeRawBufferPointer) in
|
||||||
if let unsafePointer = unsafeBufferPointer.bindMemory(to: UInt8.self).baseAddress {
|
if let unsafePointer = unsafeBufferPointer.bindMemory(to: UInt8.self).baseAddress {
|
||||||
texture?.replace(region: MTLRegionMake2D(0, 0, width, height),
|
texture.replace(region: MTLRegionMake2D(0, 0, width, height),
|
||||||
mipmapLevel: i,
|
mipmapLevel: i,
|
||||||
withBytes: unsafePointer,
|
withBytes: unsafePointer,
|
||||||
bytesPerRow: bPr)
|
bytesPerRow: bPr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width = max(width >> 1, 1);
|
width = max(width >> 1, 1)
|
||||||
height = max(height >> 1, 1);
|
height = max(height >> 1, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture!
|
return texture
|
||||||
}
|
}
|
||||||
|
|
||||||
func _compress(image:OSImage) -> Any? {
|
internal func _compress(image: OSImage) -> Any? {
|
||||||
#if (os(iOS) || os(tvOS)) && !targetEnvironment(simulator)
|
#if (os(iOS) || os(tvOS)) && !targetEnvironment(simulator)
|
||||||
if #available(iOS 11.0, tvOS 11.0, *) {
|
if #available(iOS 11.0, tvOS 11.0, *) {
|
||||||
// if let cg = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
|
// if let cg = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
|
||||||
if let cg = image.cgImage {
|
if let cg = image.cgImage {
|
||||||
let data = CFDataCreateMutable(nil, 0)!
|
let data = CFDataCreateMutable(nil, 0)!
|
||||||
let uti: CFString = "org.khronos.astc" as CFString
|
let uti: CFString = "org.khronos.astc" as CFString
|
||||||
let imageDestination = CGImageDestinationCreateWithData(data, uti, 1, nil)
|
let imageDestination = CGImageDestinationCreateWithData(data, uti, 1, nil)
|
||||||
CGImageDestinationAddImage(imageDestination!, cg, nil)
|
CGImageDestinationAddImage(imageDestination!, cg, nil)
|
||||||
CGImageDestinationFinalize(imageDestination!)
|
CGImageDestinationFinalize(imageDestination!)
|
||||||
let (bytesPerRow, pixelFormat) = _get_bpp_pixelFormat(.COMPRESSED_RGBA_ASTC_4x4)
|
let (bytesPerRow, pixelFormat) = _get_bpp_pixelFormat(.COMPRESSED_RGBA_ASTC_4x4)
|
||||||
|
|
||||||
var _data = (data as Data)
|
var _data = (data as Data)
|
||||||
// remove astc header of 16 bytes
|
// remove astc header of 16 bytes
|
||||||
_data = _data.subdata(in: 16..<_data.count)
|
_data = _data.subdata(in: 16..<_data.count)
|
||||||
|
|
||||||
return try? _createMetalTexture(cg.width, cg.height, pixelFormat, [_data as Data], bytesPerRow) as Any
|
return try? _createMetalTexture(cg.width, cg.height, pixelFormat, [_data as Data], bytesPerRow) as Any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate func _get_bpp_pixelFormat(_ compression: GLTF_3D4MCompressedTextureExtensionCompression) -> ((Int, Int) -> Int, MTLPixelFormat) {
|
||||||
fileprivate func _get_bpp_pixelFormat(_ compression:GLTF_3D4MCompressedTextureExtensionCompression) ->((Int, Int)->Int, MTLPixelFormat) {
|
var bytesPerRow: (Int, Int) -> Int = {_, _ in return 0 }
|
||||||
var bytesPerRow:(Int, Int)->Int = {_,_ in return 0 }
|
var pixelFormat: MTLPixelFormat = .invalid
|
||||||
var pixelFormat:MTLPixelFormat = .invalid;
|
|
||||||
|
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
if (compression == .COMPRESSED_RGBA_S3TC_DXT1) {
|
if compression == .COMPRESSED_RGBA_S3TC_DXT1 {
|
||||||
pixelFormat = .bc1_rgba
|
pixelFormat = .bc1_rgba
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 8 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 8 }
|
||||||
} else if (compression == .COMPRESSED_SRGB_ALPHA_S3TC_DXT1) {
|
} else if compression == .COMPRESSED_SRGB_ALPHA_S3TC_DXT1 {
|
||||||
pixelFormat = .bc1_rgba_srgb
|
pixelFormat = .bc1_rgba_srgb
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 8 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 8 }
|
||||||
} else if (compression == .COMPRESSED_RGBA_S3TC_DXT3) {
|
} else if compression == .COMPRESSED_RGBA_S3TC_DXT3 {
|
||||||
pixelFormat = .bc2_rgba
|
pixelFormat = .bc2_rgba
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 }
|
||||||
} else if (compression == .COMPRESSED_SRGB_ALPHA_S3TC_DXT3) {
|
} else if compression == .COMPRESSED_SRGB_ALPHA_S3TC_DXT3 {
|
||||||
pixelFormat = .bc2_rgba_srgb
|
pixelFormat = .bc2_rgba_srgb
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 }
|
||||||
} else if (compression == .COMPRESSED_RGBA_S3TC_DXT5) {
|
} else if compression == .COMPRESSED_RGBA_S3TC_DXT5 {
|
||||||
pixelFormat = .bc3_rgba
|
pixelFormat = .bc3_rgba
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 }
|
||||||
} else if (compression == .COMPRESSED_SRGB_ALPHA_S3TC_DXT5) {
|
} else if compression == .COMPRESSED_SRGB_ALPHA_S3TC_DXT5 {
|
||||||
pixelFormat = .bc3_rgba_srgb
|
pixelFormat = .bc3_rgba_srgb
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 }
|
||||||
} else if (compression == .COMPRESSED_RGBA_BPTC_UNORM) {
|
} else if compression == .COMPRESSED_RGBA_BPTC_UNORM {
|
||||||
pixelFormat = .bc7_rgbaUnorm
|
pixelFormat = .bc7_rgbaUnorm
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 }
|
||||||
} else if (compression == .COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
|
} else if compression == .COMPRESSED_SRGB_ALPHA_BPTC_UNORM {
|
||||||
pixelFormat = .bc7_rgbaUnorm_srgb
|
pixelFormat = .bc7_rgbaUnorm_srgb
|
||||||
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 };
|
bytesPerRow = {width, height in return ((width + 3) / 4) * 16 }
|
||||||
}
|
}
|
||||||
#elseif os(iOS) || os(tvOS)
|
#elseif os(iOS) || os(tvOS)
|
||||||
|
|
||||||
switch compression {
|
switch compression {
|
||||||
case .ETC1_RGB8_OES:
|
case .ETC1_RGB8_OES:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_RGB8_ETC2:
|
case .COMPRESSED_RGB8_ETC2:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ETC2:
|
case .COMPRESSED_SRGB8_ETC2:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
case .COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
case .COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA8_ETC2_EAC:
|
case .COMPRESSED_RGBA8_ETC2_EAC:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
|
case .COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
|
||||||
assert(false, " \(compression) not supported yet")
|
assert(false, " \(compression) not supported yet")
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB_PVRTC_2BPPV1:
|
case .COMPRESSED_SRGB_PVRTC_2BPPV1:
|
||||||
pixelFormat = .pvrtc_rgb_2bpp_srgb
|
pixelFormat = .pvrtc_rgb_2bpp_srgb
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB_PVRTC_4BPPV1:
|
case .COMPRESSED_SRGB_PVRTC_4BPPV1:
|
||||||
pixelFormat = .pvrtc_rgb_4bpp_srgb
|
pixelFormat = .pvrtc_rgb_4bpp_srgb
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1:
|
case .COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1:
|
||||||
pixelFormat = .pvrtc_rgba_2bpp_srgb
|
pixelFormat = .pvrtc_rgba_2bpp_srgb
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1:
|
case .COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1:
|
||||||
pixelFormat = .pvrtc_rgba_4bpp_srgb
|
pixelFormat = .pvrtc_rgba_4bpp_srgb
|
||||||
break
|
|
||||||
case .COMPRESSED_RGB_PVRTC_4BPPV1:
|
case .COMPRESSED_RGB_PVRTC_4BPPV1:
|
||||||
pixelFormat = .pvrtc_rgb_4bpp
|
pixelFormat = .pvrtc_rgb_4bpp
|
||||||
break
|
|
||||||
case .COMPRESSED_RGB_PVRTC_2BPPV1:
|
case .COMPRESSED_RGB_PVRTC_2BPPV1:
|
||||||
pixelFormat = .pvrtc_rgb_2bpp
|
pixelFormat = .pvrtc_rgb_2bpp
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_PVRTC_4BPPV1:
|
case .COMPRESSED_RGBA_PVRTC_4BPPV1:
|
||||||
pixelFormat = .pvrtc_rgba_4bpp
|
pixelFormat = .pvrtc_rgba_4bpp
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_PVRTC_2BPPV1:
|
case .COMPRESSED_RGBA_PVRTC_2BPPV1:
|
||||||
pixelFormat = .pvrtc_rgba_2bpp
|
pixelFormat = .pvrtc_rgba_2bpp
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_4x4:
|
case .COMPRESSED_RGBA_ASTC_4x4:
|
||||||
pixelFormat = .astc_4x4_ldr
|
pixelFormat = .astc_4x4_ldr
|
||||||
bytesPerRow = {width, height in return (width + 4 - 1) / 4 * 16 };
|
bytesPerRow = {width, height in return (width + 4 - 1) / 4 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_5x4:
|
case .COMPRESSED_RGBA_ASTC_5x4:
|
||||||
pixelFormat = .astc_5x4_ldr
|
pixelFormat = .astc_5x4_ldr
|
||||||
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 };
|
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_5x5:
|
case .COMPRESSED_RGBA_ASTC_5x5:
|
||||||
pixelFormat = .astc_5x5_ldr
|
pixelFormat = .astc_5x5_ldr
|
||||||
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 };
|
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_6x5:
|
case .COMPRESSED_RGBA_ASTC_6x5:
|
||||||
pixelFormat = .astc_6x5_ldr
|
pixelFormat = .astc_6x5_ldr
|
||||||
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 };
|
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_6x6:
|
case .COMPRESSED_RGBA_ASTC_6x6:
|
||||||
pixelFormat = .astc_6x6_ldr
|
pixelFormat = .astc_6x6_ldr
|
||||||
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 };
|
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_8x5:
|
case .COMPRESSED_RGBA_ASTC_8x5:
|
||||||
pixelFormat = .astc_8x5_ldr
|
pixelFormat = .astc_8x5_ldr
|
||||||
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 };
|
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_8x6:
|
case .COMPRESSED_RGBA_ASTC_8x6:
|
||||||
pixelFormat = .astc_8x6_ldr
|
pixelFormat = .astc_8x6_ldr
|
||||||
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 };
|
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_8x8:
|
case .COMPRESSED_RGBA_ASTC_8x8:
|
||||||
pixelFormat = .astc_8x8_ldr
|
pixelFormat = .astc_8x8_ldr
|
||||||
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 };
|
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_10x5:
|
case .COMPRESSED_RGBA_ASTC_10x5:
|
||||||
pixelFormat = .astc_10x5_ldr
|
pixelFormat = .astc_10x5_ldr
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_10x6:
|
case .COMPRESSED_RGBA_ASTC_10x6:
|
||||||
pixelFormat = .astc_10x6_ldr
|
pixelFormat = .astc_10x6_ldr
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_10x8:
|
case .COMPRESSED_RGBA_ASTC_10x8:
|
||||||
pixelFormat = .astc_10x8_ldr
|
pixelFormat = .astc_10x8_ldr
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_10x10:
|
case .COMPRESSED_RGBA_ASTC_10x10:
|
||||||
pixelFormat = .astc_10x10_ldr
|
pixelFormat = .astc_10x10_ldr
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_12x10:
|
case .COMPRESSED_RGBA_ASTC_12x10:
|
||||||
pixelFormat = .astc_12x10_ldr
|
pixelFormat = .astc_12x10_ldr
|
||||||
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 };
|
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_RGBA_ASTC_12x12:
|
case .COMPRESSED_RGBA_ASTC_12x12:
|
||||||
pixelFormat = .astc_12x12_ldr
|
pixelFormat = .astc_12x12_ldr
|
||||||
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 };
|
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_4x4:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_4x4:
|
||||||
pixelFormat = .astc_4x4_srgb
|
pixelFormat = .astc_4x4_srgb
|
||||||
bytesPerRow = {width, height in return (width + 4 - 1) / 4 * 16 };
|
bytesPerRow = {width, height in return (width + 4 - 1) / 4 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_5x4:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_5x4:
|
||||||
pixelFormat = .astc_5x4_srgb
|
pixelFormat = .astc_5x4_srgb
|
||||||
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 };
|
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_5x5:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_5x5:
|
||||||
pixelFormat = .astc_5x5_srgb
|
pixelFormat = .astc_5x5_srgb
|
||||||
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 };
|
bytesPerRow = {width, height in return (width + 5 - 1) / 5 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_6x5:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_6x5:
|
||||||
pixelFormat = .astc_6x5_srgb
|
pixelFormat = .astc_6x5_srgb
|
||||||
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 };
|
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_6x6:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_6x6:
|
||||||
pixelFormat = .astc_6x6_srgb
|
pixelFormat = .astc_6x6_srgb
|
||||||
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 };
|
bytesPerRow = {width, height in return (width + 6 - 1) / 6 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_8x5:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_8x5:
|
||||||
pixelFormat = .astc_8x5_srgb
|
pixelFormat = .astc_8x5_srgb
|
||||||
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 };
|
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_8x6:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_8x6:
|
||||||
pixelFormat = .astc_8x6_srgb
|
pixelFormat = .astc_8x6_srgb
|
||||||
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 };
|
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_8x8:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_8x8:
|
||||||
pixelFormat = .astc_8x8_srgb
|
pixelFormat = .astc_8x8_srgb
|
||||||
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 };
|
bytesPerRow = {width, height in return (width + 8 - 1) / 8 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x5:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x5:
|
||||||
pixelFormat = .astc_10x5_srgb
|
pixelFormat = .astc_10x5_srgb
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x6:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x6:
|
||||||
pixelFormat = .astc_10x6_srgb
|
pixelFormat = .astc_10x6_srgb
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x8:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x8:
|
||||||
pixelFormat = .astc_10x8_srgb
|
pixelFormat = .astc_10x8_srgb
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x10:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_10x10:
|
||||||
pixelFormat = .astc_10x10_srgb
|
pixelFormat = .astc_10x10_srgb
|
||||||
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 };
|
bytesPerRow = {width, height in return (width + 10 - 1) / 10 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_12x10:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_12x10:
|
||||||
pixelFormat = .astc_12x10_srgb
|
pixelFormat = .astc_12x10_srgb
|
||||||
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 };
|
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 }
|
||||||
break
|
|
||||||
case .COMPRESSED_SRGB8_ALPHA8_ASTC_12x12:
|
case .COMPRESSED_SRGB8_ALPHA8_ASTC_12x12:
|
||||||
pixelFormat = .astc_12x12_srgb
|
pixelFormat = .astc_12x12_srgb
|
||||||
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 };
|
bytesPerRow = {width, height in return (width + 12 - 1) / 12 * 16 }
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false, " \(compression) can't bbe supported on iOS")
|
assert(false, " \(compression) can't bbe supported on iOS")
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return (bytesPerRow, pixelFormat)
|
return (bytesPerRow, pixelFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,63 +9,98 @@ import Foundation
|
||||||
import SceneKit
|
import SceneKit
|
||||||
|
|
||||||
// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md
|
// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md
|
||||||
|
#if DRACO
|
||||||
extension GLTF {
|
extension GLTF {
|
||||||
|
|
||||||
func convertDracoMesh(_ dracoMesh:GLTFKHRDracoMeshCompressionExtension, triangleStrip:Bool = true) -> (SCNGeometryElement?, [SCNGeometrySource]?) {
|
func convertDracoMesh(_ dracoMesh: GLTFKHRDracoMeshCompressionExtension, triangleStrip: Bool = true) throws -> (SCNGeometryElement?, [SCNGeometrySource]?) {
|
||||||
if let (bufferView, data) = try? requestData(bufferView: dracoMesh.bufferView) {
|
if let (bufferView, data) = try GLTF.requestData(glTF: self, bufferView: dracoMesh.bufferView) {
|
||||||
var data = data
|
var data = data
|
||||||
let start = bufferView.byteOffset
|
let start = bufferView.byteOffset
|
||||||
let end = start + bufferView.byteLength
|
let end = start + bufferView.byteLength
|
||||||
|
|
||||||
if start != 0 || end != data.count {
|
if start != 0 || end != data.count {
|
||||||
data = data.subdata(in: start..<end)
|
data = data.subdata(in: start..<end)
|
||||||
}
|
}
|
||||||
|
|
||||||
let (indicesData, verticies, stride) = uncompressDracoData(data, triangleStrip: triangleStrip)
|
let (indicesData, verticies, stride) = uncompressDracoData(data, triangleStrip: triangleStrip)
|
||||||
|
|
||||||
let indexSize = MemoryLayout<UInt32>.size;
|
let indexSize = MemoryLayout<UInt32>.size
|
||||||
|
|
||||||
let primitiveCount = (triangleStrip) ? ((indicesData.count / indexSize) - 2) : (indicesData.count / (indexSize * 3))
|
let primitiveCount = (triangleStrip) ? ((indicesData.count / indexSize) - 2) : (indicesData.count / (indexSize * 3))
|
||||||
|
|
||||||
let element = SCNGeometryElement.init(data: indicesData,
|
let element = SCNGeometryElement.init(data: indicesData,
|
||||||
primitiveType: ((triangleStrip) ? .triangleStrip : .triangles),
|
primitiveType: ((triangleStrip) ? .triangleStrip : .triangles),
|
||||||
primitiveCount: primitiveCount,
|
primitiveCount: primitiveCount,
|
||||||
bytesPerIndex: indexSize)
|
bytesPerIndex: indexSize)
|
||||||
|
|
||||||
|
|
||||||
let byteStride = (bufferView.byteStride != nil) ? bufferView.byteStride! : (stride * 4)
|
let byteStride = (bufferView.byteStride != nil) ? bufferView.byteStride! : (stride * 4)
|
||||||
let count = verticies.count / byteStride
|
let count = verticies.count / byteStride
|
||||||
var byteOffset = 0
|
var byteOffset = 0
|
||||||
|
|
||||||
var geometrySources = [SCNGeometrySource]()
|
var geometrySources = [SCNGeometrySource]()
|
||||||
|
|
||||||
// sort attributes
|
// sort attributes
|
||||||
var sortedAttributes:[String] = [String](repeating: "", count: dracoMesh.attributes.count)
|
var sortedAttributes: [String] = [String](repeating: "", count: dracoMesh.attributes.count)
|
||||||
for pair in dracoMesh.attributes {
|
for pair in dracoMesh.attributes {
|
||||||
sortedAttributes[pair.value] = pair.key
|
sortedAttributes[pair.value] = pair.key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mtlBuffer: MTLBuffer?
|
||||||
|
let device = MetalDevice.device
|
||||||
|
verticies.withUnsafeBytes { (unsafeBufferPointer: UnsafeRawBufferPointer) in
|
||||||
|
let uint8Ptr = unsafeBufferPointer.bindMemory(to: Int8.self).baseAddress!
|
||||||
|
mtlBuffer = device?.makeBuffer(bytes: uint8Ptr, length: verticies.count, options: .storageModeShared)
|
||||||
|
}
|
||||||
|
|
||||||
|
let createGeometrySource: (SCNGeometrySource.Semantic) -> (SCNGeometrySource)
|
||||||
|
if let mtlB = mtlBuffer {
|
||||||
|
createGeometrySource = { semantic in
|
||||||
|
let vertexFormat: MTLVertexFormat
|
||||||
|
switch semantic {
|
||||||
|
case .texcoord:
|
||||||
|
vertexFormat = .float2
|
||||||
|
default:
|
||||||
|
vertexFormat = .float3
|
||||||
|
}
|
||||||
|
|
||||||
|
let geometrySource = SCNGeometrySource.init(buffer: mtlB,
|
||||||
|
vertexFormat: vertexFormat,
|
||||||
|
semantic: semantic,
|
||||||
|
vertexCount: count,
|
||||||
|
dataOffset: byteOffset,
|
||||||
|
dataStride: byteStride)
|
||||||
|
return geometrySource
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
createGeometrySource = { semantic in
|
||||||
|
let geometrySource = SCNGeometrySource.init(data: verticies,
|
||||||
|
semantic: semantic,
|
||||||
|
vectorCount: count,
|
||||||
|
usesFloatComponents: true,
|
||||||
|
componentsPerVector: ((semantic == .texcoord) ? 2 : 3) ,
|
||||||
|
bytesPerComponent: 4,
|
||||||
|
dataOffset: byteOffset,
|
||||||
|
dataStride: byteStride)
|
||||||
|
return geometrySource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for key in sortedAttributes {
|
for key in sortedAttributes {
|
||||||
// convert string semantic to SceneKit enum type
|
// convert string semantic to SceneKit enum type
|
||||||
let semantic = self.sourceSemantic(name:key)
|
let semantic = GLTF.sourceSemantic(name: key)
|
||||||
|
|
||||||
let geometrySource = SCNGeometrySource.init(data: verticies,
|
let geometrySource = createGeometrySource(semantic)
|
||||||
semantic: semantic,
|
|
||||||
vectorCount: count,
|
|
||||||
usesFloatComponents: true,
|
|
||||||
componentsPerVector: ((semantic == .texcoord) ? 2 : 3) ,
|
|
||||||
bytesPerComponent: 4,
|
|
||||||
dataOffset: byteOffset,
|
|
||||||
dataStride: byteStride)
|
|
||||||
geometrySources.append(geometrySource)
|
geometrySources.append(geometrySource)
|
||||||
|
|
||||||
byteOffset = byteOffset + ((semantic == .texcoord) ? 8 : 12)
|
byteOffset = byteOffset + ((semantic == .texcoord) ? 8 : 12)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (element, geometrySources)
|
return (element, geometrySources)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (nil, nil)
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -8,50 +8,50 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SceneKit
|
import SceneKit
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
extension GLTF {
|
extension GLTF {
|
||||||
|
|
||||||
// MARK: - Material
|
// MARK: - Material
|
||||||
|
|
||||||
// load material by index
|
// load material by index
|
||||||
func loadMaterial(index:Int, textureChangedCallback: ((Any?)-> Void)? = nil, completionHandler: @escaping (SCNMaterial) -> Void) {
|
internal func loadMaterial(index: Int, delegate: TextureLoaderDelegate, textureChangedCallback: ((Any?) -> Void)? = nil, completionHandler: @escaping (SCNMaterial) -> Void) {
|
||||||
|
|
||||||
if let material = self.materials?[index] {
|
if let material = self.materials?[index] {
|
||||||
let scnMaterial = SCNMaterial()
|
let scnMaterial = SCNMaterial()
|
||||||
scnMaterial.name = material.name
|
scnMaterial.name = material.name
|
||||||
scnMaterial.isDoubleSided = material.doubleSided
|
scnMaterial.isDoubleSided = material.doubleSided
|
||||||
|
|
||||||
if let pbr = material.pbrMetallicRoughness {
|
if let pbr = material.pbrMetallicRoughness {
|
||||||
|
|
||||||
// set PBR type
|
// set PBR type
|
||||||
scnMaterial.lightingModel = .physicallyBased
|
scnMaterial.lightingModel = .physicallyBased
|
||||||
|
|
||||||
if let baseTextureInfo = pbr.baseColorTexture {
|
if let baseTextureInfo = pbr.baseColorTexture {
|
||||||
TextureStorageManager.loadTexture(gltf:self, index:baseTextureInfo.index, property: scnMaterial.diffuse, callback: textureChangedCallback)
|
TextureStorageManager.loadTexture(gltf: self, delegate: delegate, index: baseTextureInfo.index, property: scnMaterial.diffuse)
|
||||||
} else {
|
} else {
|
||||||
let color = (pbr.baseColorFactor.count < 4) ? [1, 1, 1, 1] : (pbr.baseColorFactor)
|
let color = (pbr.baseColorFactor.count < 4) ? [1, 1, 1, 1] : (pbr.baseColorFactor)
|
||||||
scnMaterial.diffuse.contents = OSColor(red: CGFloat(color[0]), green: CGFloat(color[1]), blue: CGFloat(color[2]), alpha: CGFloat(color[3]))
|
scnMaterial.diffuse.contents = OSColor(red: CGFloat(color[0]), green: CGFloat(color[1]), blue: CGFloat(color[2]), alpha: CGFloat(color[3]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// transparency/opacity
|
// transparency/opacity
|
||||||
scnMaterial.transparency = CGFloat(pbr.baseColorFactor[3])
|
scnMaterial.transparency = CGFloat(pbr.baseColorFactor[3])
|
||||||
|
|
||||||
if let metallicRoughnessTextureInfo = pbr.metallicRoughnessTexture {
|
if let metallicRoughnessTextureInfo = pbr.metallicRoughnessTexture {
|
||||||
if #available(OSX 10.13, iOS 11.0, tvOS 11.0, *) {
|
if #available(OSX 10.13, iOS 11.0, tvOS 11.0, *) {
|
||||||
scnMaterial.metalness.textureComponents = .blue
|
scnMaterial.metalness.textureComponents = .blue
|
||||||
scnMaterial.roughness.textureComponents = .green
|
scnMaterial.roughness.textureComponents = .green
|
||||||
TextureStorageManager.loadTexture(gltf:self, index:metallicRoughnessTextureInfo.index, property: scnMaterial.metalness)
|
TextureStorageManager.loadTexture(gltf: self, delegate: delegate, index: metallicRoughnessTextureInfo.index, property: scnMaterial.metalness)
|
||||||
TextureStorageManager.loadTexture(gltf:self, index:metallicRoughnessTextureInfo.index, property: scnMaterial.roughness)
|
TextureStorageManager.loadTexture(gltf: self, delegate: delegate, index: metallicRoughnessTextureInfo.index, property: scnMaterial.roughness)
|
||||||
} else {
|
} else {
|
||||||
// Fallback on earlier versions
|
// Fallback on earlier versions
|
||||||
if let texture = self.textures?[metallicRoughnessTextureInfo.index] {
|
if let texture = self.textures?[metallicRoughnessTextureInfo.index] {
|
||||||
|
|
||||||
if texture.source != nil {
|
if texture.source != nil {
|
||||||
|
|
||||||
loadSampler(sampler:texture.sampler, property: scnMaterial.roughness)
|
loadSampler(sampler: texture.sampler, property: scnMaterial.roughness)
|
||||||
loadSampler(sampler:texture.sampler, property: scnMaterial.metalness)
|
loadSampler(sampler: texture.sampler, property: scnMaterial.metalness)
|
||||||
|
|
||||||
let image = self.image(byIndex:texture.source!)
|
let image = self.image(byIndex: texture.source!)
|
||||||
if let images = ((try? image?.channels()) as [OSImage]??) {
|
if let images = ((try? image?.channels()) as [OSImage]??) {
|
||||||
scnMaterial.roughness.contents = images?[1]
|
scnMaterial.roughness.contents = images?[1]
|
||||||
scnMaterial.metalness.contents = images?[2]
|
scnMaterial.metalness.contents = images?[2]
|
||||||
|
@ -59,47 +59,47 @@ extension GLTF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
scnMaterial.metalness.contents = pbr.metallicFactor
|
scnMaterial.metalness.contents = pbr.metallicFactor
|
||||||
scnMaterial.roughness.contents = pbr.roughnessFactor
|
scnMaterial.roughness.contents = pbr.roughnessFactor
|
||||||
scnMaterial.fresnelExponent = 0.04
|
scnMaterial.fresnelExponent = 0.04
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let normalTextureInfo = material.normalTexture {
|
if let normalTextureInfo = material.normalTexture {
|
||||||
TextureStorageManager.loadTexture(gltf:self, index: normalTextureInfo.index!, property: scnMaterial.normal)
|
TextureStorageManager.loadTexture(gltf: self, delegate: delegate, index: normalTextureInfo.index!, property: scnMaterial.normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let occlusionTextureInfo = material.occlusionTexture {
|
if let occlusionTextureInfo = material.occlusionTexture {
|
||||||
TextureStorageManager.loadTexture(gltf:self, index: occlusionTextureInfo.index!, property: scnMaterial.ambientOcclusion)
|
TextureStorageManager.loadTexture(gltf: self, delegate: delegate, index: occlusionTextureInfo.index!, property: scnMaterial.ambientOcclusion)
|
||||||
scnMaterial.ambientOcclusion.intensity = CGFloat(occlusionTextureInfo.strength)
|
scnMaterial.ambientOcclusion.intensity = CGFloat(occlusionTextureInfo.strength)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let emissiveTextureInfo = material.emissiveTexture {
|
if let emissiveTextureInfo = material.emissiveTexture {
|
||||||
TextureStorageManager.loadTexture(gltf:self, index: emissiveTextureInfo.index, property: scnMaterial.emission)
|
TextureStorageManager.loadTexture(gltf: self, delegate: delegate, index: emissiveTextureInfo.index, property: scnMaterial.emission)
|
||||||
} else {
|
} else {
|
||||||
let color = (material.emissiveFactor.count < 3) ? [1, 1, 1] : (material.emissiveFactor)
|
let color = (material.emissiveFactor.count < 3) ? [1, 1, 1] : (material.emissiveFactor)
|
||||||
scnMaterial.emission.contents = SCNVector4Make(SCNFloat(color[0]), SCNFloat(color[1]), SCNFloat(color[2]), 1.0)
|
scnMaterial.emission.contents = SCNVector4Make(SCNFloat(color[0]), SCNFloat(color[1]), SCNFloat(color[2]), 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
completionHandler(scnMaterial)
|
completionHandler(scnMaterial)
|
||||||
} else {
|
} else {
|
||||||
completionHandler(SCNMaterial())
|
completionHandler(SCNMaterial())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get image by index
|
// get image by index
|
||||||
fileprivate func image(byIndex index:Int) -> OSImage? {
|
fileprivate func image(byIndex index: Int) -> OSImage? {
|
||||||
if let gltf_image = self.images?[index] {
|
if let gltf_image = self.images?[index] {
|
||||||
if let image = ((try? self.loader.load(gltf:self, resource: gltf_image)) as OSImage??) {
|
if let image = ((try? self.loader.load(gltf: self, resource: gltf_image)) as OSImage??) {
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSampler(sampler samplerIndex:Int?, property:SCNMaterialProperty) {
|
func loadSampler(sampler samplerIndex: Int?, property: SCNMaterialProperty) {
|
||||||
if let sampler = self.samplers?[samplerIndex!] {
|
if let sampler = self.samplers?[samplerIndex!] {
|
||||||
property.wrapS = sampler.wrapS.scn()
|
property.wrapS = sampler.wrapS.scn()
|
||||||
property.wrapT = sampler.wrapT.scn()
|
property.wrapT = sampler.wrapT.scn()
|
||||||
|
@ -109,7 +109,6 @@ extension GLTF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension GLTFSampler {
|
extension GLTFSampler {
|
||||||
fileprivate func magFilterScene() -> SCNFilterMode {
|
fileprivate func magFilterScene() -> SCNFilterMode {
|
||||||
if self.magFilter != nil {
|
if self.magFilter != nil {
|
||||||
|
@ -117,7 +116,7 @@ extension GLTFSampler {
|
||||||
}
|
}
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func minFilterScene() -> (SCNFilterMode, SCNFilterMode) {
|
fileprivate func minFilterScene() -> (SCNFilterMode, SCNFilterMode) {
|
||||||
if self.minFilter != nil {
|
if self.minFilter != nil {
|
||||||
return (self.minFilter?.scn())!
|
return (self.minFilter?.scn())!
|
||||||
|
@ -181,4 +180,3 @@ extension GLTFSamplerWrapT {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,616 +10,85 @@ import Foundation
|
||||||
import SceneKit
|
import SceneKit
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
let log_scenekit = OSLog(subsystem: "org.glTFSceneKit", category: "scene")
|
let log_scenekit = OSLog(subsystem: "org.glTFSceneKit", category: "scene")
|
||||||
|
|
||||||
let dracoExtensionKey = "KHR_draco_mesh_compression"
|
|
||||||
let compressedTextureExtensionKey = "3D4M_compressed_texture"
|
let compressedTextureExtensionKey = "3D4M_compressed_texture"
|
||||||
let supportedExtensions = [dracoExtensionKey, compressedTextureExtensionKey]
|
let meshExtensionKey = "3D4M_mesh"
|
||||||
|
#if DRACO
|
||||||
|
let dracoExtensionKey = "KHR_draco_mesh_compression"
|
||||||
|
let supportedExtensions = [dracoExtensionKey, compressedTextureExtensionKey, meshExtensionKey]
|
||||||
|
#else
|
||||||
|
let supportedExtensions = [compressedTextureExtensionKey, meshExtensionKey]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ConvertionProgressMask: OptionSet {
|
||||||
struct ConvertionProgressMask : OptionSet {
|
|
||||||
let rawValue: Int
|
let rawValue: Int
|
||||||
|
|
||||||
static let nodes = ConvertionProgressMask(rawValue: 1 << 1)
|
static let nodes = ConvertionProgressMask(rawValue: 1 << 1)
|
||||||
static let textures = ConvertionProgressMask(rawValue: 1 << 2)
|
static let textures = ConvertionProgressMask(rawValue: 1 << 2)
|
||||||
static let animations = ConvertionProgressMask(rawValue: 1 << 3)
|
static let animations = ConvertionProgressMask(rawValue: 1 << 3)
|
||||||
|
|
||||||
static func all() -> ConvertionProgressMask {
|
static func all() -> ConvertionProgressMask {
|
||||||
return [.nodes, .textures, .animations]
|
return [.nodes, .textures, .animations]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc public protocol SceneLoadingDelegate {
|
||||||
|
@objc optional func scene(_ didLoadScene: SCNScene? )
|
||||||
|
@objc optional func scene(_ scene: SCNScene?, didCreate camera: SCNCamera)
|
||||||
|
@objc optional func scene(_ scene: SCNScene?, didCreate node: SCNNode)
|
||||||
|
@objc optional func scene(_ scene: SCNScene?, didCreate material: SCNMaterial, for node: SCNNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
extension GLTF {
|
extension GLTF {
|
||||||
|
|
||||||
struct Keys {
|
struct Keys {
|
||||||
static var cache_nodes = "cache_nodes"
|
|
||||||
static var animation_duration = "animation_duration"
|
|
||||||
static var resource_loader = "resource_loader"
|
static var resource_loader = "resource_loader"
|
||||||
static var load_canceled = "load_canceled"
|
static var load_canceled = "load_canceled"
|
||||||
static var completion_handler = "completion_handler"
|
|
||||||
static var scnview = "scnview"
|
|
||||||
static var nodesDispatchGroup = "nodesDispatchGroup"
|
|
||||||
static var convertionProgress = "convertionProgressMask"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Status will be true if `cancel` was call.
|
public var loader: GLTFResourceLoader {
|
||||||
@objc open private(set) var isCancelled:Bool {
|
get {
|
||||||
|
var loader_ = objc_getAssociatedObject(self, &Keys.resource_loader) as? GLTFResourceLoader
|
||||||
|
if loader_ != nil {
|
||||||
|
return loader_!
|
||||||
|
}
|
||||||
|
loader_ = GLTFResourceLoaderDefault()
|
||||||
|
self.loader = loader_!
|
||||||
|
return loader_!
|
||||||
|
}
|
||||||
|
set { objc_setAssociatedObject(self, &Keys.resource_loader, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Status set to true if `cancel` been call.
|
||||||
|
@objc open private(set) var isCancelled: Bool {
|
||||||
get { return (objc_getAssociatedObject(self, &Keys.load_canceled) as? Bool) ?? false }
|
get { return (objc_getAssociatedObject(self, &Keys.load_canceled) as? Bool) ?? false }
|
||||||
set { objc_setAssociatedObject(self, &Keys.load_canceled, newValue, .OBJC_ASSOCIATION_ASSIGN) }
|
set { objc_setAssociatedObject(self, &Keys.load_canceled, newValue, .OBJC_ASSOCIATION_ASSIGN) }
|
||||||
}
|
}
|
||||||
|
|
||||||
var cache_nodes:[SCNNode?]? {
|
|
||||||
get { return objc_getAssociatedObject(self, &Keys.cache_nodes) as? [SCNNode?] }
|
|
||||||
set { objc_setAssociatedObject(self, &Keys.cache_nodes, newValue, .OBJC_ASSOCIATION_RETAIN) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var convertionProgressMask:ConvertionProgressMask {
|
|
||||||
get {
|
|
||||||
var p = objc_getAssociatedObject(self, &Keys.convertionProgress)
|
|
||||||
if p == nil {
|
|
||||||
p = ConvertionProgressMask.init(rawValue: 0)
|
|
||||||
objc_setAssociatedObject(self, &Keys.convertionProgress, p, .OBJC_ASSOCIATION_RETAIN)
|
|
||||||
}
|
|
||||||
return p as! ConvertionProgressMask
|
|
||||||
}
|
|
||||||
set { objc_setAssociatedObject(self, &Keys.convertionProgress, newValue, .OBJC_ASSOCIATION_RETAIN) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderer:SCNSceneRenderer? {
|
|
||||||
get { return objc_getAssociatedObject(self, &Keys.scnview) as? SCNSceneRenderer }
|
|
||||||
set { objc_setAssociatedObject(self, &Keys.scnview, newValue, .OBJC_ASSOCIATION_ASSIGN) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var _completionHandler:((Error?) -> Void) {
|
|
||||||
get { return (objc_getAssociatedObject(self, &Keys.completion_handler) as? ((Error?) -> Void) ?? {_ in }) }
|
|
||||||
set { objc_setAssociatedObject(self, &Keys.completion_handler, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var nodesDispatchGroup:DispatchGroup {
|
|
||||||
get {
|
|
||||||
if let d = objc_getAssociatedObject(self, &Keys.nodesDispatchGroup) {
|
|
||||||
return d as! DispatchGroup
|
|
||||||
}
|
|
||||||
let group = DispatchGroup()
|
|
||||||
objc_setAssociatedObject(self, &Keys.nodesDispatchGroup, group, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
||||||
return group
|
|
||||||
}
|
|
||||||
set { objc_setAssociatedObject(self, &Keys.nodesDispatchGroup, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Convert glTF object to SceneKit scene.
|
|
||||||
///
|
|
||||||
/// - Parameter scene: Optional parameter. If property is set then loaded model will be add to existing objects in scene.
|
|
||||||
/// - Parameter view: Required for Metal. But optional for OpenGL rendering.
|
|
||||||
/// - Parameter directoryPath: location to others related resources of glTF.
|
|
||||||
/// - Parameter multiThread: By default model will be load in multiple threads.
|
|
||||||
/// - Parameter completionHandler: Execute completion block once model fully loaded. If multiThread parameter set to true, then scene will be returned soon as possible and completion block will be executed later, after all textures load.
|
|
||||||
/// - Returns: instance of Scene
|
|
||||||
@objc open func convert(to scene:SCNScene = SCNScene.init(),
|
|
||||||
renderer:SCNSceneRenderer? = nil,
|
|
||||||
directoryPath:String? = nil,
|
|
||||||
multiThread:Bool = true,
|
|
||||||
hidden:Bool = false,
|
|
||||||
geometryCompletionHandler: @escaping ()->Void,
|
|
||||||
completionHandler: @escaping ((Error?) -> Void) = {_ in } ) -> SCNScene? {
|
|
||||||
|
|
||||||
if (self.extensionsUsed != nil) {
|
internal func cancel() {
|
||||||
// for key in self.extensionsUsed! {
|
|
||||||
// if !supportedExtensions.contains(key) {
|
|
||||||
// completionHandler("Used `\(key)` extension is not supported!")
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.extensionsRequired != nil) {
|
|
||||||
for key in self.extensionsRequired! {
|
|
||||||
if !supportedExtensions.contains(key) {
|
|
||||||
completionHandler("Required `\(key)` extension is not supported!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.renderer = renderer
|
|
||||||
self._completionHandler = completionHandler
|
|
||||||
|
|
||||||
if directoryPath != nil {
|
|
||||||
self.loader.directoryPath = directoryPath!
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get dispatch group for current GLTF
|
|
||||||
let convertGroup = self.nodesDispatchGroup
|
|
||||||
convertGroup.enter()
|
|
||||||
|
|
||||||
if self.scenes != nil && self.scene != nil {
|
|
||||||
let sceneGlTF = self.scenes![(self.scene)!]
|
|
||||||
if let sceneName = sceneGlTF.name {
|
|
||||||
scene.setAttribute(sceneName, forKey: "name")
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cache_nodes = [SCNNode?](repeating: nil, count: (self.nodes?.count)!)
|
|
||||||
|
|
||||||
// run in multi-thread or single
|
|
||||||
if (multiThread) {
|
|
||||||
|
|
||||||
let start = Date()
|
|
||||||
|
|
||||||
// this enter is requered here in case materials has few textures
|
|
||||||
// which loaded very quickly even before all geometries submitted for load
|
|
||||||
let texturesGroup = TextureStorageManager.manager.group(gltf:self, true)
|
|
||||||
|
|
||||||
// construct nodes tree
|
|
||||||
_constructNodesTree(rootNode: scene.rootNode, nodes: sceneGlTF.nodes!, group: convertGroup, hidden: hidden)
|
|
||||||
|
|
||||||
os_log("submit data to download %d ms", log: log_scenekit, type: .debug, Int(start.timeIntervalSinceNow * -1000))
|
|
||||||
|
|
||||||
// completion
|
|
||||||
convertGroup.notify(queue: DispatchQueue.main) {
|
|
||||||
texturesGroup.leave()
|
|
||||||
|
|
||||||
geometryCompletionHandler()
|
|
||||||
os_log("geometry loaded %d ms", log: log_scenekit, type: .debug, Int(start.timeIntervalSinceNow * -1000))
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self._nodesConverted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
convertGroup.leave()
|
|
||||||
} else {
|
|
||||||
for nodeIndex in sceneGlTF.nodes! {
|
|
||||||
let scnNode = self.buildNode(nodeIndex:nodeIndex)
|
|
||||||
scnNode.isHidden = hidden
|
|
||||||
scene.rootNode.addChildNode(scnNode)
|
|
||||||
}
|
|
||||||
convertGroup.leave()
|
|
||||||
self._nodesConverted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if self.isCancelled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return scene
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
open func cancel() {
|
|
||||||
self.isCancelled = true
|
self.isCancelled = true
|
||||||
self.loader.cancelAll()
|
self.loader.cancelAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func _constructNodesTree(rootNode:SCNNode, nodes:[Int], group:DispatchGroup, hidden:Bool) {
|
|
||||||
var cache_nodes = self.cache_nodes
|
|
||||||
for nodeIndex in nodes {
|
|
||||||
group.enter()
|
|
||||||
let scnNode = SCNNode()
|
|
||||||
scnNode.isHidden = hidden
|
|
||||||
if let node = self.nodes?[nodeIndex] {
|
|
||||||
scnNode.name = node.name
|
|
||||||
|
|
||||||
if node.children != nil && node.children?.count != 0 {
|
|
||||||
_constructNodesTree(rootNode: scnNode, nodes: node.children!, group: group, hidden: hidden)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create nodes up front to avoid deadlocks in multithreading
|
|
||||||
let primitivesCount = self.meshes?[node.mesh!].primitives.count ?? 0
|
|
||||||
for _ in 0..<primitivesCount {
|
|
||||||
let scnNodePrimitiveNode = SCNNode()
|
|
||||||
scnNode.addChildNode(scnNodePrimitiveNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rootNode.addChildNode(scnNode)
|
|
||||||
cache_nodes?[nodeIndex] = scnNode
|
|
||||||
|
|
||||||
self._preloadBuffersData(nodeIndex: nodeIndex) { error in
|
|
||||||
if error != nil {
|
|
||||||
print("Failed to load geometry node with error: \(error!)")
|
|
||||||
} else {
|
|
||||||
_ = self.buildNode(nodeIndex: nodeIndex, scnNode: scnNode)
|
|
||||||
}
|
|
||||||
group.leave()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Nodes converted, start parse and create animation.
|
|
||||||
/// And in case no textures required to load, complete convertion from glTF to SceneKit.
|
|
||||||
fileprivate func _nodesConverted() {
|
|
||||||
self.convertionProgressMask.insert(.nodes)
|
|
||||||
|
|
||||||
self.parseAnimations()
|
|
||||||
// probably should be inserted some where else and call on completion of animation parse
|
|
||||||
self.convertionProgressMask.insert(.animations)
|
|
||||||
|
|
||||||
self.nodesDispatchGroup.wait()
|
|
||||||
|
|
||||||
if self.textures?.count == 0 {
|
|
||||||
self.convertionProgressMask.insert(.textures)
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.convertionProgressMask.rawValue == ConvertionProgressMask.all().rawValue {
|
|
||||||
self._converted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func _texturesLoaded() {
|
|
||||||
self.convertionProgressMask.insert(.textures)
|
|
||||||
TextureStorageManager.manager.clear(gltf: self)
|
|
||||||
|
|
||||||
if self.convertionProgressMask.rawValue == ConvertionProgressMask.all().rawValue {
|
|
||||||
self._converted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Completion function and cache cleaning.
|
|
||||||
func _converted() {
|
|
||||||
os_log("convert completed", log: log_scenekit, type: .debug)
|
|
||||||
|
|
||||||
// clear cache
|
|
||||||
_completionHandler(nil)
|
|
||||||
_completionHandler = {_ in }
|
|
||||||
|
|
||||||
self.cache_nodes?.removeAll()
|
|
||||||
|
|
||||||
self.clearCache()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Collect associated buffers for node into a Set on Decode time.
|
|
||||||
fileprivate func _preloadBuffersData(nodeIndex:Int, completionHandler: @escaping (Error?) -> Void ) {
|
|
||||||
|
|
||||||
var buffers:Set = Set<GLTFBuffer>()
|
|
||||||
|
|
||||||
if let node = self.nodes?[nodeIndex] {
|
|
||||||
if node.mesh != nil {
|
|
||||||
if let mesh = self.meshes?[node.mesh!] {
|
|
||||||
for primitive in mesh.primitives {
|
|
||||||
// check on draco extension
|
|
||||||
if let dracoMesh = primitive.extensions?[dracoExtensionKey] {
|
|
||||||
let dracoMesh = dracoMesh as! GLTFKHRDracoMeshCompressionExtension
|
|
||||||
let buffer = self.buffers![self.bufferViews![dracoMesh.bufferView].buffer]
|
|
||||||
buffers.insert(buffer)
|
|
||||||
} else {
|
|
||||||
for (_,index) in primitive.attributes {
|
|
||||||
if let accessor = self.accessors?[index] {
|
|
||||||
if let bufferView = accessor.bufferView {
|
|
||||||
let buffer = self.buffers![self.bufferViews![bufferView].buffer]
|
|
||||||
buffers.insert(buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if primitive.indices != nil {
|
|
||||||
if let accessor = self.accessors?[primitive.indices!] {
|
|
||||||
if let bufferView = accessor.bufferView {
|
|
||||||
let buffer = self.buffers![self.bufferViews![bufferView].buffer]
|
|
||||||
buffers.insert(buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.loader.load(gltf:self, resources: buffers, completionHandler:completionHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Nodes
|
|
||||||
|
|
||||||
fileprivate func buildNode(nodeIndex:Int, scnNode:SCNNode = SCNNode()) -> SCNNode {
|
|
||||||
|
|
||||||
if let node = self.nodes?[nodeIndex] {
|
|
||||||
|
|
||||||
// Get camera, if it has reference on any.
|
|
||||||
constructCamera(node, scnNode)
|
|
||||||
|
|
||||||
// convert meshes if any exists in gltf node
|
|
||||||
geometryNode(node, scnNode)
|
|
||||||
|
|
||||||
|
|
||||||
// load skin if any reference exists
|
|
||||||
if let skin = node.skin {
|
|
||||||
loadSkin(skin, scnNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// bake all transformations into one mtarix
|
|
||||||
scnNode.transform = bakeTransformationMatrix(node)
|
|
||||||
|
|
||||||
if self.isCancelled {
|
|
||||||
return scnNode
|
|
||||||
}
|
|
||||||
|
|
||||||
if let children = node.children {
|
|
||||||
for i in children {
|
|
||||||
let subSCNNode = self.buildNode(nodeIndex:i)
|
|
||||||
scnNode.addChildNode(subSCNNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return scnNode
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func bakeTransformationMatrix(_ node:GLTFNode) -> SCNMatrix4 {
|
|
||||||
let rotation = GLKMatrix4MakeWithQuaternion(GLKQuaternion.init(q: (Float(node.rotation[0]), Float(node.rotation[1]), Float(node.rotation[2]), Float(node.rotation[3]))))
|
|
||||||
var matrix = SCNMatrix4.init(array:node.matrix)
|
|
||||||
matrix = SCNMatrix4Translate(matrix, SCNFloat(node.translation[0]), SCNFloat(node.translation[1]), SCNFloat(node.translation[2]))
|
|
||||||
matrix = SCNMatrix4Mult(matrix, SCNMatrix4FromGLKMatrix4(rotation))
|
|
||||||
matrix = SCNMatrix4Scale(matrix, SCNFloat(node.scale[0]), SCNFloat(node.scale[1]), SCNFloat(node.scale[2]))
|
|
||||||
return matrix
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func constructCamera(_ node:GLTFNode, _ scnNode:SCNNode) {
|
|
||||||
if let cameraIndex = node.camera {
|
|
||||||
scnNode.camera = SCNCamera()
|
|
||||||
if self.cameras != nil {
|
|
||||||
let camera = self.cameras![cameraIndex]
|
|
||||||
scnNode.camera?.name = camera.name
|
|
||||||
switch camera.type {
|
|
||||||
case .perspective:
|
|
||||||
scnNode.camera?.zNear = (camera.perspective?.znear)!
|
|
||||||
scnNode.camera?.zFar = (camera.perspective?.zfar)!
|
|
||||||
if #available(OSX 10.13, iOS 11.0, tvOS 11.0, *) {
|
|
||||||
scnNode.camera?.fieldOfView = CGFloat((camera.perspective?.yfov)! * 180.0 / .pi)
|
|
||||||
scnNode.camera?.wantsDepthOfField = true
|
|
||||||
scnNode.camera?.motionBlurIntensity = 0.3
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case .orthographic:
|
|
||||||
scnNode.camera?.usesOrthographicProjection = true
|
|
||||||
scnNode.camera?.zNear = (camera.orthographic?.znear)!
|
|
||||||
scnNode.camera?.zFar = (camera.orthographic?.zfar)!
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
internal func clearCache() {
|
||||||
/// convert glTF mesh into SCNGeometry
|
if self.buffers != nil {
|
||||||
///
|
for buffer in self.buffers! {
|
||||||
/// - Parameters:
|
buffer.data = nil
|
||||||
/// - node: gltf node
|
}
|
||||||
/// - scnNode: SceneKit node, which is going to be parent node
|
}
|
||||||
fileprivate func geometryNode(_ node:GLTFNode, _ scnNode:SCNNode) {
|
|
||||||
|
if self.images != nil {
|
||||||
if self.isCancelled {
|
for image in self.images! {
|
||||||
return
|
image.image = nil
|
||||||
}
|
|
||||||
|
|
||||||
if let meshIndex = node.mesh {
|
|
||||||
|
|
||||||
var weightPaths = [String]()
|
|
||||||
|
|
||||||
if let mesh = self.meshes?[meshIndex] {
|
|
||||||
|
|
||||||
var primitiveIndex = 0
|
|
||||||
|
|
||||||
for primitive in mesh.primitives {
|
|
||||||
|
|
||||||
var sources:[SCNGeometrySource] = [SCNGeometrySource]()
|
|
||||||
var elements:[SCNGeometryElement] = [SCNGeometryElement]()
|
|
||||||
|
|
||||||
// get indices
|
|
||||||
if let element = self.geometryElement(primitive) {
|
|
||||||
elements.append(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get sources from attributes information
|
|
||||||
sources.append(contentsOf: self.geometrySources(primitive.attributes))
|
|
||||||
|
|
||||||
// check on draco extension
|
|
||||||
if let dracoMesh = primitive.extensions?[dracoExtensionKey] {
|
|
||||||
let (dElement, dSources) = self.convertDracoMesh(dracoMesh as! GLTFKHRDracoMeshCompressionExtension)
|
|
||||||
|
|
||||||
if (dElement != nil) {
|
|
||||||
elements.append(dElement!)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dSources != nil) {
|
|
||||||
sources.append(contentsOf: dSources!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.isCancelled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let primitiveNode:SCNNode
|
|
||||||
// create geometry
|
|
||||||
let geometry = SCNGeometry.init(sources: sources, elements: elements)
|
|
||||||
|
|
||||||
if primitiveIndex < scnNode.childNodes.count {
|
|
||||||
primitiveNode = scnNode.childNodes[primitiveIndex]
|
|
||||||
primitiveNode.geometry = geometry
|
|
||||||
} else {
|
|
||||||
primitiveNode = SCNNode.init(geometry: geometry)
|
|
||||||
scnNode.addChildNode(primitiveNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
if primitiveNode.geometry?.firstMaterial != nil {
|
|
||||||
// create empty SCNMaterial. Callbacks call later then materail will be download, so we must provide materail for selection
|
|
||||||
let emptyMaterial = SCNMaterial()
|
|
||||||
emptyMaterial.name = "empty"
|
|
||||||
emptyMaterial.isDoubleSided = true
|
|
||||||
|
|
||||||
primitiveNode.geometry!.firstMaterial = emptyMaterial
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if let materialIndex = primitive.material {
|
|
||||||
self.loadMaterial(index:materialIndex, textureChangedCallback: { _ in
|
|
||||||
if let material = primitiveNode.geometry?.firstMaterial {
|
|
||||||
if let texture = material.diffuse.contents as? MTLTexture {
|
|
||||||
if texture.pixelFormat.hasAlpha() {
|
|
||||||
primitiveNode.renderingOrder = 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}) { scnMaterial in
|
|
||||||
let emissionContent = primitiveNode.geometry?.firstMaterial?.emission.contents
|
|
||||||
scnMaterial.emission.contents = emissionContent
|
|
||||||
geometry.materials = [scnMaterial]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
primitiveNode.name = mesh.name
|
|
||||||
|
|
||||||
if let transparency = primitiveNode.geometry?.firstMaterial?.transparency,
|
|
||||||
transparency < 1.0 {
|
|
||||||
primitiveNode.renderingOrder = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if let targets = primitive.targets {
|
|
||||||
let morpher = SCNMorpher()
|
|
||||||
let targetsCount = targets.count
|
|
||||||
for targetIndex in 0..<targetsCount {
|
|
||||||
let target = targets[targetIndex]
|
|
||||||
let sourcesMorph = geometrySources(target)
|
|
||||||
let geometryMorph = SCNGeometry(sources: sourcesMorph, elements: nil)
|
|
||||||
morpher.targets.append(geometryMorph)
|
|
||||||
|
|
||||||
let path = "childNodes[\(primitiveIndex)].morpher.weights[\(targetIndex)]"
|
|
||||||
weightPaths.append(path)
|
|
||||||
}
|
|
||||||
morpher.calculationMode = .additive
|
|
||||||
primitiveNode.morpher = morpher
|
|
||||||
}
|
|
||||||
|
|
||||||
primitiveIndex += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scnNode.setValue(weightPaths, forUndefinedKey: "weightPaths")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func geometryElement(_ primitive: GLTFMeshPrimitive) -> SCNGeometryElement? {
|
|
||||||
if let indicesIndex = primitive.indices {
|
|
||||||
if let accessor = self.accessors?[indicesIndex] {
|
|
||||||
|
|
||||||
if let (indicesData, _, _) = loadAcessor(accessor) {
|
|
||||||
|
|
||||||
var count = accessor.count
|
|
||||||
|
|
||||||
let primitiveType = primitive.mode.scn()
|
|
||||||
switch primitiveType {
|
|
||||||
case .triangles:
|
|
||||||
count = count/3
|
|
||||||
break
|
|
||||||
case .triangleStrip:
|
|
||||||
count = count-2
|
|
||||||
break
|
|
||||||
case .line:
|
|
||||||
count = count/2
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return SCNGeometryElement.init(data: indicesData,
|
|
||||||
primitiveType: primitiveType,
|
|
||||||
primitiveCount: count,
|
|
||||||
bytesPerIndex: accessor.bytesPerElement())
|
|
||||||
} else {
|
|
||||||
// here is should be errors handling
|
|
||||||
print("Error load geometryElement")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert mesh/animation attributes into SCNGeometrySource
|
|
||||||
///
|
|
||||||
/// - Parameter attributes: dictionary of accessors
|
|
||||||
/// - Returns: array of SCNGeometrySource objects
|
|
||||||
fileprivate func geometrySources(_ attributes:[String:Int]) -> [SCNGeometrySource] {
|
|
||||||
var geometrySources = [SCNGeometrySource]()
|
|
||||||
for (key, accessorIndex) in attributes {
|
|
||||||
if let accessor = self.accessors?[accessorIndex] {
|
|
||||||
|
|
||||||
if let (data, byteStride, byteOffset) = loadAcessor(accessor) {
|
|
||||||
|
|
||||||
let count = accessor.count
|
|
||||||
|
|
||||||
// convert string semantic to SceneKit semantic type
|
|
||||||
let semantic = self.sourceSemantic(name:key)
|
|
||||||
|
|
||||||
let geometrySource = SCNGeometrySource.init(data: data,
|
|
||||||
semantic: semantic,
|
|
||||||
vectorCount: count,
|
|
||||||
usesFloatComponents: true,
|
|
||||||
componentsPerVector: accessor.components(),
|
|
||||||
bytesPerComponent: accessor.bytesPerElement(),
|
|
||||||
dataOffset: byteOffset,
|
|
||||||
dataStride: byteStride)
|
|
||||||
geometrySources.append(geometrySource)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return geometrySources
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func requestData(bufferView:Int) throws -> (GLTFBufferView, Data) {
|
|
||||||
if let bufferView = self.bufferViews?[bufferView] {
|
|
||||||
let buffer = self.buffers![bufferView.buffer]
|
|
||||||
|
|
||||||
if let data = try self.loader.load(gltf:self, resource: buffer) {
|
|
||||||
return (bufferView, data)
|
|
||||||
}
|
|
||||||
throw "Can't load data!"
|
|
||||||
}
|
|
||||||
throw "Can't load data! Can't find bufferView or buffer"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// get data by accessor
|
|
||||||
func loadAcessor(_ accessor:GLTFAccessor) -> (Data, Int, Int)? {
|
|
||||||
|
|
||||||
if accessor.bufferView == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if let (bufferView, data) = try? requestData(bufferView: accessor.bufferView!) {
|
|
||||||
|
|
||||||
var addAccessorOffset = false
|
|
||||||
if (bufferView.byteStride == nil || accessor.components()*accessor.bytesPerElement() == bufferView.byteStride) {
|
|
||||||
addAccessorOffset = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let count = accessor.count
|
|
||||||
let byteStride = (bufferView.byteStride == nil) ? accessor.components()*accessor.bytesPerElement() : bufferView.byteStride!
|
|
||||||
let bytesLength = byteStride*count
|
|
||||||
|
|
||||||
let start = bufferView.byteOffset+((addAccessorOffset) ? accessor.byteOffset : 0)
|
|
||||||
let end = start+bytesLength
|
|
||||||
|
|
||||||
var subdata = data
|
|
||||||
if start != 0 || end != data.count {
|
|
||||||
subdata = data.subdata(in: start..<end)
|
|
||||||
}
|
|
||||||
|
|
||||||
let byteOffset = ((!addAccessorOffset) ? accessor.byteOffset : 0)
|
|
||||||
return (subdata, byteStride, byteOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// convert attributes name to SceneKit semantic
|
// convert attributes name to SceneKit semantic
|
||||||
func sourceSemantic(name:String) -> SCNGeometrySource.Semantic {
|
internal static func sourceSemantic(name: String) -> SCNGeometrySource.Semantic {
|
||||||
switch name {
|
switch name {
|
||||||
case "POSITION":
|
case "POSITION":
|
||||||
return .vertex
|
return .vertex
|
||||||
|
@ -639,69 +108,48 @@ extension GLTF {
|
||||||
return .vertex
|
return .vertex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearCache() {
|
internal static func requestData(glTF: GLTF, bufferView: GLTFBufferView) throws -> Data? {
|
||||||
if self.buffers != nil {
|
if let buffer = glTF.buffers?[bufferView.buffer] {
|
||||||
for buffer in self.buffers! {
|
|
||||||
buffer.data = nil
|
if let data = try glTF.loader.load(gltf: glTF, resource: buffer) {
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw GLTFError("Can't load data! Can't find buffer at index \(bufferView.buffer)")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
if self.images != nil {
|
}
|
||||||
for image in self.images! {
|
|
||||||
image.image = nil
|
internal static func requestData(glTF: GLTF, bufferView: Int) throws -> (GLTFBufferView, Data)? {
|
||||||
|
if let bufferView = glTF.bufferViews?[bufferView] {
|
||||||
|
if let data = try requestData(glTF: glTF, bufferView: bufferView) {
|
||||||
|
return (bufferView, data)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw GLTFError("Can't load data! Can't find bufferView at index \(bufferView)")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension GLTFBuffer {
|
||||||
|
|
||||||
|
static var data_associate_key = "data_associate_key"
|
||||||
|
|
||||||
|
public var data: Data? {
|
||||||
|
get { return objc_getAssociatedObject(self, &GLTFBuffer.data_associate_key) as? Data }
|
||||||
|
set { objc_setAssociatedObject(self, &GLTFBuffer.data_associate_key, newValue, .OBJC_ASSOCIATION_RETAIN) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension GLTFImage {
|
||||||
|
|
||||||
extension GLTFAccessor {
|
static var image_associate_key = "image_associate_key"
|
||||||
fileprivate func components() -> Int {
|
|
||||||
switch type {
|
public var image: OSImage? {
|
||||||
case .SCALAR:
|
get { return objc_getAssociatedObject(self, &GLTFImage.image_associate_key) as? OSImage }
|
||||||
return 1
|
set { objc_setAssociatedObject(self, &GLTFImage.image_associate_key, newValue, .OBJC_ASSOCIATION_RETAIN) }
|
||||||
case .VEC2:
|
|
||||||
return 2
|
|
||||||
case .VEC3:
|
|
||||||
return 3
|
|
||||||
case .VEC4, .MAT2:
|
|
||||||
return 4
|
|
||||||
case .MAT3:
|
|
||||||
return 9
|
|
||||||
case .MAT4:
|
|
||||||
return 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func bytesPerElement() -> Int {
|
|
||||||
switch componentType {
|
|
||||||
case .UNSIGNED_BYTE, .BYTE:
|
|
||||||
return 1
|
|
||||||
case .UNSIGNED_SHORT, .SHORT:
|
|
||||||
return 2
|
|
||||||
default:
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension GLTFMeshPrimitiveMode {
|
|
||||||
fileprivate func scn() -> SCNGeometryPrimitiveType {
|
|
||||||
switch self {
|
|
||||||
case .POINTS:
|
|
||||||
return .point
|
|
||||||
case .LINES, .LINE_LOOP, .LINE_STRIP:
|
|
||||||
return .line
|
|
||||||
case .TRIANGLE_STRIP:
|
|
||||||
return .triangleStrip
|
|
||||||
case .TRIANGLES:
|
|
||||||
return .triangles
|
|
||||||
default:
|
|
||||||
return .triangles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,66 +9,65 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// The root object for a glTF asset.
|
/// The root object for a glTF asset.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTF : NSObject, Codable {
|
open class GLTF: NSObject, Codable {
|
||||||
/// An array of accessors.
|
/// An array of accessors.
|
||||||
public var accessors:[GLTFAccessor]?
|
public var accessors: [GLTFAccessor]?
|
||||||
|
|
||||||
/// An array of keyframe animations.
|
/// An array of keyframe animations.
|
||||||
public var animations:[GLTFAnimation]?
|
public var animations: [GLTFAnimation]?
|
||||||
|
|
||||||
/// Metadata about the glTF asset.
|
/// Metadata about the glTF asset.
|
||||||
public var asset:GLTFAsset
|
public var asset: GLTFAsset
|
||||||
|
|
||||||
/// An array of bufferViews.
|
/// An array of bufferViews.
|
||||||
public var bufferViews:[GLTFBufferView]?
|
public var bufferViews: [GLTFBufferView]?
|
||||||
|
|
||||||
/// An array of buffers.
|
/// An array of buffers.
|
||||||
public var buffers:[GLTFBuffer]?
|
public var buffers: [GLTFBuffer]?
|
||||||
|
|
||||||
/// An array of cameras.
|
/// An array of cameras.
|
||||||
public var cameras:[GLTFCamera]?
|
public var cameras: [GLTFCamera]?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Names of glTF extensions required to properly load this asset.
|
/// Names of glTF extensions required to properly load this asset.
|
||||||
public var extensionsRequired:[String]?
|
public var extensionsRequired: [String]?
|
||||||
|
|
||||||
/// Names of glTF extensions used somewhere in this asset.
|
/// Names of glTF extensions used somewhere in this asset.
|
||||||
public var extensionsUsed:[String]?
|
public var extensionsUsed: [String]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// An array of images.
|
/// An array of images.
|
||||||
public var images:[GLTFImage]?
|
public var images: [GLTFImage]?
|
||||||
|
|
||||||
/// An array of materials.
|
/// An array of materials.
|
||||||
public var materials:[GLTFMaterial]?
|
public var materials: [GLTFMaterial]?
|
||||||
|
|
||||||
/// An array of meshes.
|
/// An array of meshes.
|
||||||
public var meshes:[GLTFMesh]?
|
public var meshes: [GLTFMesh]?
|
||||||
|
|
||||||
/// An array of nodes.
|
/// An array of nodes.
|
||||||
public var nodes:[GLTFNode]?
|
public var nodes: [GLTFNode]?
|
||||||
|
|
||||||
/// An array of samplers.
|
/// An array of samplers.
|
||||||
public var samplers:[GLTFSampler]?
|
public var samplers: [GLTFSampler]?
|
||||||
|
|
||||||
/// The index of the default scene.
|
/// The index of the default scene.
|
||||||
public var scene:Int?
|
public var scene: Int?
|
||||||
|
|
||||||
/// An array of scenes.
|
/// An array of scenes.
|
||||||
public var scenes:[GLTFScene]?
|
public var scenes: [GLTFScene]?
|
||||||
|
|
||||||
/// An array of skins.
|
/// An array of skins.
|
||||||
public var skins:[GLTFSkin]?
|
public var skins: [GLTFSkin]?
|
||||||
|
|
||||||
/// An array of textures.
|
/// An array of textures.
|
||||||
public var textures:[GLTFTexture]?
|
public var textures: [GLTFTexture]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case accessors
|
case accessors
|
||||||
|
@ -91,8 +90,8 @@ open class GLTF : NSObject, Codable {
|
||||||
case skins
|
case skins
|
||||||
case textures
|
case textures
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(asset a:GLTFAsset) {
|
public init(asset a: GLTFAsset) {
|
||||||
asset = a
|
asset = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,25 @@ import Foundation
|
||||||
case MAT3
|
case MAT3
|
||||||
case MAT4
|
case MAT4
|
||||||
|
|
||||||
|
public var rawIntValue: Int {
|
||||||
|
switch self {
|
||||||
|
case .SCALAR:
|
||||||
|
return 0
|
||||||
|
case .VEC2:
|
||||||
|
return 1
|
||||||
|
case .VEC3:
|
||||||
|
return 2
|
||||||
|
case .VEC4:
|
||||||
|
return 3
|
||||||
|
case .MAT2:
|
||||||
|
return 4
|
||||||
|
case .MAT3:
|
||||||
|
return 5
|
||||||
|
case .MAT4:
|
||||||
|
return 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public var rawValue: String {
|
public var rawValue: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .SCALAR:
|
case .SCALAR:
|
||||||
|
@ -106,45 +125,44 @@ import Foundation
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A typed view into a bufferView. A bufferView contains raw binary data. An accessor provides a typed view into a bufferView or a subset of a bufferView similar to how WebGL's `vertexAttribPointer()` defines an attribute in a buffer.
|
/// A typed view into a bufferView. A bufferView contains raw binary data. An accessor provides a typed view into a bufferView or a subset of a bufferView similar to how WebGL's `vertexAttribPointer()` defines an attribute in a buffer.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAccessor : NSObject, Codable {
|
open class GLTFAccessor: NSObject, Codable {
|
||||||
/// The index of the bufferView.
|
/// The index of the bufferView.
|
||||||
public var bufferView:Int?
|
public var bufferView: Int?
|
||||||
|
|
||||||
/// The offset relative to the start of the bufferView in bytes.
|
/// The offset relative to the start of the bufferView in bytes.
|
||||||
public var byteOffset:Int
|
public var byteOffset: Int
|
||||||
|
|
||||||
/// The datatype of components in the attribute.
|
/// The datatype of components in the attribute.
|
||||||
public var componentType:GLTFAccessorComponentType
|
public var componentType: GLTFAccessorComponentType
|
||||||
|
|
||||||
/// The number of attributes referenced by this accessor.
|
/// The number of attributes referenced by this accessor.
|
||||||
public var count:Int
|
public var count: Int
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// Maximum value of each component in this attribute.
|
/// Maximum value of each component in this attribute.
|
||||||
public var max:[Double]?
|
public var max: [Double]?
|
||||||
|
|
||||||
/// Minimum value of each component in this attribute.
|
/// Minimum value of each component in this attribute.
|
||||||
public var min:[Double]?
|
public var min: [Double]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// Specifies whether integer data values should be normalized.
|
/// Specifies whether integer data values should be normalized.
|
||||||
public var normalized:Bool
|
public var normalized: Bool = false
|
||||||
|
|
||||||
/// Sparse storage of attributes that deviate from their initialization value.
|
/// Sparse storage of attributes that deviate from their initialization value.
|
||||||
public var sparse:GLTFAccessorSparse?
|
public var sparse: GLTFAccessorSparse?
|
||||||
|
|
||||||
/// Specifies if the attribute is a scalar, vector, or matrix.
|
/// Specifies if the attribute is a scalar, vector, or matrix.
|
||||||
public var type:GLTFAccessorType
|
public var type: GLTFAccessorType
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case bufferView
|
case bufferView
|
||||||
|
@ -161,6 +179,18 @@ open class GLTFAccessor : NSObject, Codable {
|
||||||
case type
|
case type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public init (bufferView: Int?,
|
||||||
|
byteOffset: Int,
|
||||||
|
componentType: GLTFAccessorComponentType,
|
||||||
|
count: Int,
|
||||||
|
type: GLTFAccessorType) {
|
||||||
|
self.bufferView = bufferView
|
||||||
|
self.byteOffset = byteOffset
|
||||||
|
self.componentType = componentType
|
||||||
|
self.count = count
|
||||||
|
self.type = type
|
||||||
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
bufferView = try? container.decode(Int.self, forKey: .bufferView)
|
bufferView = try? container.decode(Int.self, forKey: .bufferView)
|
||||||
|
|
|
@ -9,24 +9,23 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Sparse storage of attributes that deviate from their initialization value.
|
/// Sparse storage of attributes that deviate from their initialization value.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAccessorSparse : NSObject, Codable {
|
open class GLTFAccessorSparse: NSObject, Codable {
|
||||||
/// Number of entries stored in the sparse array.
|
/// Number of entries stored in the sparse array.
|
||||||
public var count:Int
|
public var count: Int
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// Indices of those attributes that deviate from their initialization value.
|
/// Indices of those attributes that deviate from their initialization value.
|
||||||
public var indices:GLTFAccessorSparseIndices
|
public var indices: GLTFAccessorSparseIndices
|
||||||
|
|
||||||
/// Array of size `accessor.sparse.count` times number of components storing the displaced accessor attributes pointed by `accessor.sparse.indices`.
|
/// Array of size `accessor.sparse.count` times number of components storing the displaced accessor attributes pointed by `accessor.sparse.indices`.
|
||||||
public var values:GLTFAccessorSparseValues
|
public var values: GLTFAccessorSparseValues
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case count
|
case count
|
||||||
|
|
|
@ -40,24 +40,23 @@ import Foundation
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Indices of those attributes that deviate from their initialization value.
|
/// Indices of those attributes that deviate from their initialization value.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAccessorSparseIndices : NSObject, Codable {
|
open class GLTFAccessorSparseIndices: NSObject, Codable {
|
||||||
/// The index of the bufferView with sparse indices. Referenced bufferView can't have ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target.
|
/// The index of the bufferView with sparse indices. Referenced bufferView can't have ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target.
|
||||||
public var bufferView:Int
|
public var bufferView: Int
|
||||||
|
|
||||||
/// The offset relative to the start of the bufferView in bytes. Must be aligned.
|
/// The offset relative to the start of the bufferView in bytes. Must be aligned.
|
||||||
public var byteOffset:Int
|
public var byteOffset: Int
|
||||||
|
|
||||||
/// The indices data type.
|
/// The indices data type.
|
||||||
public var componentType:GLTFAccessorSparseIndicesComponentType
|
public var componentType: GLTFAccessorSparseIndicesComponentType
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case bufferView
|
case bufferView
|
||||||
|
|
|
@ -9,21 +9,20 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Array of size `accessor.sparse.count` times number of components storing the displaced accessor attributes pointed by `accessor.sparse.indices`.
|
/// Array of size `accessor.sparse.count` times number of components storing the displaced accessor attributes pointed by `accessor.sparse.indices`.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAccessorSparseValues : NSObject, Codable {
|
open class GLTFAccessorSparseValues: NSObject, Codable {
|
||||||
/// The index of the bufferView with sparse values. Referenced bufferView can't have ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target.
|
/// The index of the bufferView with sparse values. Referenced bufferView can't have ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target.
|
||||||
public var bufferView:Int
|
public var bufferView: Int
|
||||||
|
|
||||||
/// The offset relative to the start of the bufferView in bytes. Must be aligned.
|
/// The offset relative to the start of the bufferView in bytes. Must be aligned.
|
||||||
public var byteOffset:Int
|
public var byteOffset: Int
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case bufferView
|
case bufferView
|
||||||
|
|
|
@ -9,24 +9,23 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A keyframe animation.
|
/// A keyframe animation.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAnimation : NSObject, Codable {
|
open class GLTFAnimation: NSObject, Codable {
|
||||||
/// An array of channels, each of which targets an animation's sampler at a node's property. Different channels of the same animation can't have equal targets.
|
/// An array of channels, each of which targets an animation's sampler at a node's property. Different channels of the same animation can't have equal targets.
|
||||||
public var channels:[GLTFAnimationChannel]
|
public var channels: [GLTFAnimationChannel]
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// An array of samplers that combines input and output accessors with an interpolation algorithm to define a keyframe graph (but not its target).
|
/// An array of samplers that combines input and output accessors with an interpolation algorithm to define a keyframe graph (but not its target).
|
||||||
public var samplers:[GLTFAnimationSampler]
|
public var samplers: [GLTFAnimationSampler]
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case channels
|
case channels
|
||||||
|
|
|
@ -9,21 +9,20 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Targets an animation's sampler at a node's property.
|
/// Targets an animation's sampler at a node's property.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAnimationChannel : NSObject, Codable {
|
open class GLTFAnimationChannel: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of a sampler in this animation used to compute the value for the target.
|
/// The index of a sampler in this animation used to compute the value for the target.
|
||||||
public var sampler:Int
|
public var sampler: Int
|
||||||
|
|
||||||
/// The index of the node and TRS property that an animation channel targets.
|
/// The index of the node and TRS property that an animation channel targets.
|
||||||
public var target:GLTFAnimationChannelTarget
|
public var target: GLTFAnimationChannelTarget
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -45,21 +45,20 @@ import Foundation
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The index of the node and TRS property that an animation channel targets.
|
/// The index of the node and TRS property that an animation channel targets.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAnimationChannelTarget : NSObject, Codable {
|
open class GLTFAnimationChannelTarget: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of the node to target.
|
/// The index of the node to target.
|
||||||
public var node:Int?
|
public var node: Int?
|
||||||
|
|
||||||
/// The name of the node's TRS property to modify, or the "weights" of the Morph Targets it instantiates. For the "translation" property, the values that are provided by the sampler are the translation along the x, y, and z axes. For the "rotation" property, the values are a quaternion in the order (x, y, z, w), where w is the scalar. For the "scale" property, the values are the scaling factors along the x, y, and z axes.
|
/// The name of the node's TRS property to modify, or the "weights" of the Morph Targets it instantiates. For the "translation" property, the values that are provided by the sampler are the translation along the x, y, and z axes. For the "rotation" property, the values are a quaternion in the order (x, y, z, w), where w is the scalar. For the "scale" property, the values are the scaling factors along the x, y, and z axes.
|
||||||
public var path:GLTFAnimationChannelTargetPath
|
public var path: GLTFAnimationChannelTargetPath
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -43,24 +43,23 @@ import Foundation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Combines input and output accessors with an interpolation algorithm to define a keyframe graph (but not its target).
|
/// Combines input and output accessors with an interpolation algorithm to define a keyframe graph (but not its target).
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAnimationSampler : NSObject, Codable {
|
open class GLTFAnimationSampler: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of an accessor containing keyframe input values, e.g., time.
|
/// The index of an accessor containing keyframe input values, e.g., time.
|
||||||
public var input:Int
|
public var input: Int
|
||||||
|
|
||||||
/// Interpolation algorithm.
|
/// Interpolation algorithm.
|
||||||
public var interpolation:GLTFAnimationSamplerInterpolation
|
public var interpolation: GLTFAnimationSamplerInterpolation
|
||||||
|
|
||||||
/// The index of an accessor, containing keyframe output values.
|
/// The index of an accessor, containing keyframe output values.
|
||||||
public var output:Int
|
public var output: Int
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -9,27 +9,26 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Metadata about the glTF asset.
|
/// Metadata about the glTF asset.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFAsset : NSObject, Codable {
|
open class GLTFAsset: NSObject, Codable {
|
||||||
/// A copyright message suitable for display to credit the content creator.
|
/// A copyright message suitable for display to credit the content creator.
|
||||||
public var copyright:String?
|
public var copyright: String?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// Tool that generated this glTF model. Useful for debugging.
|
/// Tool that generated this glTF model. Useful for debugging.
|
||||||
public var generator:String?
|
public var generator: String?
|
||||||
|
|
||||||
/// The minimum glTF version that this asset targets.
|
/// The minimum glTF version that this asset targets.
|
||||||
public var minVersion:String?
|
public var minVersion: String?
|
||||||
|
|
||||||
/// The glTF version that this asset targets.
|
/// The glTF version that this asset targets.
|
||||||
public var version:String
|
public var version: String
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case copyright
|
case copyright
|
||||||
|
@ -39,8 +38,8 @@ open class GLTFAsset : NSObject, Codable {
|
||||||
case minVersion
|
case minVersion
|
||||||
case version
|
case version
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(version v:String) {
|
public init(version v: String) {
|
||||||
version = v
|
version = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,25 +9,24 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A buffer points to binary geometry, animation, or skins.
|
/// A buffer points to binary geometry, animation, or skins.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFBuffer : NSObject, Codable {
|
open class GLTFBuffer: NSObject, Codable {
|
||||||
/// The length of the buffer in bytes.
|
/// The length of the buffer in bytes.
|
||||||
public var byteLength:Int
|
public var byteLength: Int
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The uri of the buffer.
|
/// The uri of the buffer.
|
||||||
public var uri:String?
|
public var uri: String?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case byteLength
|
case byteLength
|
||||||
case extensions
|
case extensions
|
||||||
|
@ -35,7 +34,7 @@ open class GLTFBuffer : NSObject, Codable {
|
||||||
case name
|
case name
|
||||||
case uri
|
case uri
|
||||||
}
|
}
|
||||||
|
|
||||||
public override init() {
|
public override init() {
|
||||||
byteLength = 0
|
byteLength = 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,33 +35,32 @@ import Foundation
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A view into a buffer generally representing a subset of the buffer.
|
/// A view into a buffer generally representing a subset of the buffer.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFBufferView : NSObject, Codable {
|
open class GLTFBufferView: NSObject, Codable {
|
||||||
/// The index of the buffer.
|
/// The index of the buffer.
|
||||||
public var buffer:Int
|
public var buffer: Int
|
||||||
|
|
||||||
/// The length of the bufferView in bytes.
|
/// The length of the bufferView in bytes.
|
||||||
public var byteLength:Int
|
public var byteLength: Int
|
||||||
|
|
||||||
/// The offset into the buffer in bytes.
|
/// The offset into the buffer in bytes.
|
||||||
public var byteOffset:Int
|
public var byteOffset: Int
|
||||||
|
|
||||||
/// The stride, in bytes.
|
/// The stride, in bytes.
|
||||||
public var byteStride:Int?
|
public var byteStride: Int?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The target that the GPU buffer should be bound to.
|
/// The target that the GPU buffer should be bound to.
|
||||||
public var target:GLTFBufferViewTarget?
|
public var target: GLTFBufferViewTarget?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case buffer
|
case buffer
|
||||||
|
@ -74,12 +73,12 @@ open class GLTFBufferView : NSObject, Codable {
|
||||||
case target
|
case target
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(buffer b:Int, byteLength bl:Int, byteOffset bo:Int) {
|
public init(buffer b: Int, byteLength bl: Int, byteOffset bo: Int) {
|
||||||
buffer = b
|
buffer = b
|
||||||
byteLength = bl
|
byteLength = bl
|
||||||
byteOffset = bo
|
byteOffset = bo
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
buffer = try container.decode(Int.self, forKey: .buffer)
|
buffer = try container.decode(Int.self, forKey: .buffer)
|
||||||
|
|
|
@ -35,27 +35,26 @@ import Foundation
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A camera's projection. A node can reference a camera to apply a transform to place the camera in the scene.
|
/// A camera's projection. A node can reference a camera to apply a transform to place the camera in the scene.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFCamera : NSObject, Codable {
|
open class GLTFCamera: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// An orthographic camera containing properties to create an orthographic projection matrix.
|
/// An orthographic camera containing properties to create an orthographic projection matrix.
|
||||||
public var orthographic:GLTFCameraOrthographic?
|
public var orthographic: GLTFCameraOrthographic?
|
||||||
|
|
||||||
/// A perspective camera containing properties to create a perspective projection matrix.
|
/// A perspective camera containing properties to create a perspective projection matrix.
|
||||||
public var perspective:GLTFCameraPerspective?
|
public var perspective: GLTFCameraPerspective?
|
||||||
|
|
||||||
/// Specifies if the camera uses a perspective or orthographic projection.
|
/// Specifies if the camera uses a perspective or orthographic projection.
|
||||||
public var type:GLTFCameraType
|
public var type: GLTFCameraType
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -9,27 +9,26 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// An orthographic camera containing properties to create an orthographic projection matrix.
|
/// An orthographic camera containing properties to create an orthographic projection matrix.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFCameraOrthographic : NSObject, Codable {
|
open class GLTFCameraOrthographic: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The floating-point horizontal magnification of the view. Must not be zero.
|
/// The floating-point horizontal magnification of the view. Must not be zero.
|
||||||
public var xmag:Double
|
public var xmag: Double
|
||||||
|
|
||||||
/// The floating-point vertical magnification of the view. Must not be zero.
|
/// The floating-point vertical magnification of the view. Must not be zero.
|
||||||
public var ymag:Double
|
public var ymag: Double
|
||||||
|
|
||||||
/// The floating-point distance to the far clipping plane. `zfar` must be greater than `znear`.
|
/// The floating-point distance to the far clipping plane. `zfar` must be greater than `znear`.
|
||||||
public var zfar:Double
|
public var zfar: Double
|
||||||
|
|
||||||
/// The floating-point distance to the near clipping plane.
|
/// The floating-point distance to the near clipping plane.
|
||||||
public var znear:Double
|
public var znear: Double
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -9,27 +9,26 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A perspective camera containing properties to create a perspective projection matrix.
|
/// A perspective camera containing properties to create a perspective projection matrix.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFCameraPerspective : NSObject, Codable {
|
open class GLTFCameraPerspective: NSObject, Codable {
|
||||||
/// The floating-point aspect ratio of the field of view.
|
/// The floating-point aspect ratio of the field of view.
|
||||||
public var aspectRatio:Double?
|
public var aspectRatio: Double?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The floating-point vertical field of view in radians.
|
/// The floating-point vertical field of view in radians.
|
||||||
public var yfov:Double
|
public var yfov: Double
|
||||||
|
|
||||||
/// The floating-point distance to the far clipping plane.
|
/// The floating-point distance to the far clipping plane.
|
||||||
public var zfar:Double?
|
public var zfar: Double?
|
||||||
|
|
||||||
/// The floating-point distance to the near clipping plane.
|
/// The floating-point distance to the near clipping plane.
|
||||||
public var znear:Double
|
public var znear: Double
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case aspectRatio
|
case aspectRatio
|
||||||
|
|
|
@ -35,28 +35,27 @@ import Foundation
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Image data used to create a texture. Image can be referenced by URI or `bufferView` index. `mimeType` is required in the latter case.
|
/// Image data used to create a texture. Image can be referenced by URI or `bufferView` index. `mimeType` is required in the latter case.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFImage : NSObject, Codable {
|
open class GLTFImage: NSObject, Codable {
|
||||||
/// The index of the bufferView that contains the image. Use this instead of the image's uri property.
|
/// The index of the bufferView that contains the image. Use this instead of the image's uri property.
|
||||||
public var bufferView:Int?
|
public var bufferView: Int?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The image's MIME type.
|
/// The image's MIME type.
|
||||||
public var mimeType:GLTFImageMimeType?
|
public var mimeType: GLTFImageMimeType?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The uri of the image.
|
/// The uri of the image.
|
||||||
public var uri:String?
|
public var uri: String?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case bufferView
|
case bufferView
|
||||||
case extensions
|
case extensions
|
||||||
|
@ -67,7 +66,7 @@ open class GLTFImage : NSObject, Codable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override init() { }
|
public override init() { }
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
bufferView = try? container.decode(Int.self, forKey: .bufferView)
|
bufferView = try? container.decode(Int.self, forKey: .bufferView)
|
||||||
|
|
|
@ -9,26 +9,25 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Class template
|
/// Class template
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFKHRDracoMeshCompressionExtension : NSObject, Codable {
|
open class GLTFKHRDracoMeshCompressionExtension: NSObject, Codable {
|
||||||
/// A dictionary object, where each key corresponds to an attribute and its unique attribute id stored in the compressed geometry.
|
/// A dictionary object, where each key corresponds to an attribute and its unique attribute id stored in the compressed geometry.
|
||||||
public var attributes:[String: Int]
|
public var attributes: [String: Int]
|
||||||
|
|
||||||
/// The index of the bufferView.
|
/// The index of the bufferView.
|
||||||
public var bufferView:Int
|
public var bufferView: Int
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case attributes
|
case attributes
|
||||||
case bufferView
|
case bufferView
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(attributes a:[String: Int], bufferView bv:Int) {
|
public init(attributes a: [String: Int], bufferView bv: Int) {
|
||||||
attributes = a
|
attributes = a
|
||||||
bufferView = bv
|
bufferView = bv
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
attributes = try container.decode([String: Int].self, forKey: .attributes)
|
attributes = try container.decode([String: Int].self, forKey: .attributes)
|
||||||
|
|
|
@ -43,43 +43,42 @@ import Foundation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The material appearance of a primitive.
|
/// The material appearance of a primitive.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFMaterial : NSObject, Codable {
|
open class GLTFMaterial: NSObject, Codable {
|
||||||
/// The alpha cutoff value of the material.
|
/// The alpha cutoff value of the material.
|
||||||
public var alphaCutoff:Double
|
public var alphaCutoff: Double
|
||||||
|
|
||||||
/// The alpha rendering mode of the material.
|
/// The alpha rendering mode of the material.
|
||||||
public var alphaMode:GLTFMaterialAlphaMode
|
public var alphaMode: GLTFMaterialAlphaMode
|
||||||
|
|
||||||
/// Specifies whether the material is double sided.
|
/// Specifies whether the material is double sided.
|
||||||
public var doubleSided:Bool
|
public var doubleSided: Bool
|
||||||
|
|
||||||
/// The emissive color of the material.
|
/// The emissive color of the material.
|
||||||
public var emissiveFactor:[Double]
|
public var emissiveFactor: [Double]
|
||||||
|
|
||||||
/// Reference to a texture.
|
/// Reference to a texture.
|
||||||
public var emissiveTexture:GLTFTextureInfo?
|
public var emissiveTexture: GLTFTextureInfo?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The normal map texture.
|
/// The normal map texture.
|
||||||
public var normalTexture:GLTFMaterialNormalTextureInfo?
|
public var normalTexture: GLTFMaterialNormalTextureInfo?
|
||||||
|
|
||||||
/// The occlusion map texture.
|
/// The occlusion map texture.
|
||||||
public var occlusionTexture:GLTFMaterialOcclusionTextureInfo?
|
public var occlusionTexture: GLTFMaterialOcclusionTextureInfo?
|
||||||
|
|
||||||
/// A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology.
|
/// A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology.
|
||||||
public var pbrMetallicRoughness:GLTFMaterialPBRMetallicRoughness?
|
public var pbrMetallicRoughness: GLTFMaterialPBRMetallicRoughness?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case alphaCutoff
|
case alphaCutoff
|
||||||
case alphaMode
|
case alphaMode
|
||||||
|
@ -100,7 +99,7 @@ open class GLTFMaterial : NSObject, Codable {
|
||||||
doubleSided = false
|
doubleSided = false
|
||||||
emissiveFactor = [0, 0, 0]
|
emissiveFactor = [0, 0, 0]
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -9,24 +9,23 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// The normal map texture.
|
/// The normal map texture.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFMaterialNormalTextureInfo : NSObject, Codable {
|
open class GLTFMaterialNormalTextureInfo: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of the texture.
|
/// The index of the texture.
|
||||||
public var index:Int?
|
public var index: Int?
|
||||||
|
|
||||||
/// The scalar multiplier applied to each normal vector of the normal texture.
|
/// The scalar multiplier applied to each normal vector of the normal texture.
|
||||||
public var scale:Double
|
public var scale: Double
|
||||||
|
|
||||||
/// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
/// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
||||||
public var texCoord:Int
|
public var texCoord: Int
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
@ -40,7 +39,7 @@ open class GLTFMaterialNormalTextureInfo : NSObject, Codable {
|
||||||
scale = 1
|
scale = 1
|
||||||
texCoord = 0
|
texCoord = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
extensions = try? container.decode([String: Any].self, forKey: .extensions)
|
extensions = try? container.decode([String: Any].self, forKey: .extensions)
|
||||||
|
|
|
@ -9,24 +9,23 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// The occlusion map texture.
|
/// The occlusion map texture.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFMaterialOcclusionTextureInfo : NSObject, Codable {
|
open class GLTFMaterialOcclusionTextureInfo: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of the texture.
|
/// The index of the texture.
|
||||||
public var index:Int?
|
public var index: Int?
|
||||||
|
|
||||||
/// A scalar multiplier controlling the amount of occlusion applied.
|
/// A scalar multiplier controlling the amount of occlusion applied.
|
||||||
public var strength:Double
|
public var strength: Double
|
||||||
|
|
||||||
/// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
/// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
||||||
public var texCoord:Int
|
public var texCoord: Int
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -9,30 +9,29 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology.
|
/// A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFMaterialPBRMetallicRoughness : NSObject, Codable {
|
open class GLTFMaterialPBRMetallicRoughness: NSObject, Codable {
|
||||||
/// The material's base color factor.
|
/// The material's base color factor.
|
||||||
public var baseColorFactor:[Double]
|
public var baseColorFactor: [Double]
|
||||||
|
|
||||||
/// Reference to a texture.
|
/// Reference to a texture.
|
||||||
public var baseColorTexture:GLTFTextureInfo?
|
public var baseColorTexture: GLTFTextureInfo?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The metalness of the material.
|
/// The metalness of the material.
|
||||||
public var metallicFactor:Double
|
public var metallicFactor: Double
|
||||||
|
|
||||||
/// Reference to a texture.
|
/// Reference to a texture.
|
||||||
public var metallicRoughnessTexture:GLTFTextureInfo?
|
public var metallicRoughnessTexture: GLTFTextureInfo?
|
||||||
|
|
||||||
/// The roughness of the material.
|
/// The roughness of the material.
|
||||||
public var roughnessFactor:Double
|
public var roughnessFactor: Double
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case baseColorFactor
|
case baseColorFactor
|
||||||
|
@ -49,7 +48,7 @@ open class GLTFMaterialPBRMetallicRoughness : NSObject, Codable {
|
||||||
metallicFactor = 1
|
metallicFactor = 1
|
||||||
roughnessFactor = 1
|
roughnessFactor = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -9,24 +9,23 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A set of primitives to be rendered. A node can contain one mesh. A node's transform places the mesh in the scene.
|
/// A set of primitives to be rendered. A node can contain one mesh. A node's transform places the mesh in the scene.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFMesh : NSObject, Codable {
|
open class GLTFMesh: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// An array of primitives, each defining geometry to be rendered with a material.
|
/// An array of primitives, each defining geometry to be rendered with a material.
|
||||||
public var primitives:[GLTFMeshPrimitive]
|
public var primitives: [GLTFMeshPrimitive]
|
||||||
|
|
||||||
/// Array of weights to be applied to the Morph Targets.
|
/// Array of weights to be applied to the Morph Targets.
|
||||||
public var weights:[Double]?
|
public var weights: [Double]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
@ -39,7 +38,7 @@ open class GLTFMesh : NSObject, Codable {
|
||||||
public override init() {
|
public override init() {
|
||||||
primitives = [GLTFMeshPrimitive]()
|
primitives = [GLTFMeshPrimitive]()
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
extensions = try? container.decode([String: Any].self, forKey: .extensions)
|
extensions = try? container.decode([String: Any].self, forKey: .extensions)
|
||||||
|
|
|
@ -63,30 +63,29 @@ import Foundation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Geometry to be rendered with the given material.
|
/// Geometry to be rendered with the given material.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFMeshPrimitive : NSObject, Codable {
|
open class GLTFMeshPrimitive: NSObject, Codable {
|
||||||
/// A dictionary object, where each key corresponds to mesh attribute semantic and each value is the index of the accessor containing attribute's data.
|
/// A dictionary object, where each key corresponds to mesh attribute semantic and each value is the index of the accessor containing attribute's data.
|
||||||
public var attributes:[String: Int]
|
public var attributes: [String: Int]
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of the accessor that contains the indices.
|
/// The index of the accessor that contains the indices.
|
||||||
public var indices:Int?
|
public var indices: Int?
|
||||||
|
|
||||||
/// The index of the material to apply to this primitive when rendering.
|
/// The index of the material to apply to this primitive when rendering.
|
||||||
public var material:Int?
|
public var material: Int?
|
||||||
|
|
||||||
/// The type of primitives to render.
|
/// The type of primitives to render.
|
||||||
public var mode:GLTFMeshPrimitiveMode
|
public var mode: GLTFMeshPrimitiveMode
|
||||||
|
|
||||||
/// An array of Morph Targets, each Morph Target is a dictionary mapping attributes (only `POSITION`, `NORMAL`, and `TANGENT` supported) to their deviations in the Morph Target.
|
/// An array of Morph Targets, each Morph Target is a dictionary mapping attributes (only `POSITION`, `NORMAL`, and `TANGENT` supported) to their deviations in the Morph Target.
|
||||||
public var targets:[[String: Int]]?
|
public var targets: [[String: Int]]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case attributes
|
case attributes
|
||||||
|
@ -97,16 +96,18 @@ open class GLTFMeshPrimitive : NSObject, Codable {
|
||||||
case mode
|
case mode
|
||||||
case targets
|
case targets
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(attributes a:[String: Int], mode m:GLTFMeshPrimitiveMode) {
|
public init(attributes a: [String: Int], mode m: GLTFMeshPrimitiveMode) {
|
||||||
attributes = a
|
attributes = a
|
||||||
mode = m
|
mode = m
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
attributes = (try? container.decode([String: Int].self, forKey: .attributes)) ?? [String: Int]()
|
attributes = (try? container.decode([String: Int].self, forKey: .attributes)) ?? [String: Int]()
|
||||||
|
#if DRACO
|
||||||
extensions = try? container.decode([String: GLTFKHRDracoMeshCompressionExtension].self, forKey: .extensions)
|
extensions = try? container.decode([String: GLTFKHRDracoMeshCompressionExtension].self, forKey: .extensions)
|
||||||
|
#endif
|
||||||
extras = try? container.decode([String: Any].self, forKey: .extras)
|
extras = try? container.decode([String: Any].self, forKey: .extras)
|
||||||
indices = try? container.decode(Int.self, forKey: .indices)
|
indices = try? container.decode(Int.self, forKey: .indices)
|
||||||
material = try? container.decode(Int.self, forKey: .material)
|
material = try? container.decode(Int.self, forKey: .material)
|
||||||
|
@ -121,16 +122,19 @@ open class GLTFMeshPrimitive : NSObject, Codable {
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(attributes, forKey: .attributes)
|
try container.encode(attributes, forKey: .attributes)
|
||||||
|
#if DRACO
|
||||||
try? container.encode(extensions as? [String: GLTFKHRDracoMeshCompressionExtension], forKey: .extensions)
|
try? container.encode(extensions as? [String: GLTFKHRDracoMeshCompressionExtension], forKey: .extensions)
|
||||||
|
#endif
|
||||||
try container.encode(extras, forKey: .extras)
|
try container.encode(extras, forKey: .extras)
|
||||||
try container.encode(indices, forKey: .indices)
|
try container.encode(indices, forKey: .indices)
|
||||||
try container.encode(material, forKey: .material)
|
try container.encode(material, forKey: .material)
|
||||||
try container.encode(mode, forKey: .mode)
|
try container.encode(mode, forKey: .mode)
|
||||||
try container.encode(targets, forKey: .targets)
|
try container.encode(targets, forKey: .targets)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DRACO
|
||||||
extension KeyedEncodingContainerProtocol {
|
extension KeyedEncodingContainerProtocol {
|
||||||
mutating func encode(_ value: [String: GLTFKHRDracoMeshCompressionExtension]?, forKey key: Key) throws {
|
mutating func encode(_ value: [String: GLTFKHRDracoMeshCompressionExtension]?, forKey key: Key) throws {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
|
@ -139,4 +143,4 @@ extension KeyedEncodingContainerProtocol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -9,45 +9,44 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A node in the node hierarchy. When the node contains `skin`, all `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes. A node can have either a `matrix` or any combination of `translation`/`rotation`/`scale` (TRS) properties. TRS properties are converted to matrices and postmultiplied in the `T * R * S` order to compose the transformation matrix; first the scale is applied to the vertices, then the rotation, and then the translation. If none are provided, the transform is the identity. When a node is targeted for animation (referenced by an animation.channel.target), only TRS properties may be present; `matrix` will not be present.
|
/// A node in the node hierarchy. When the node contains `skin`, all `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes. A node can have either a `matrix` or any combination of `translation`/`rotation`/`scale` (TRS) properties. TRS properties are converted to matrices and postmultiplied in the `T * R * S` order to compose the transformation matrix; first the scale is applied to the vertices, then the rotation, and then the translation. If none are provided, the transform is the identity. When a node is targeted for animation (referenced by an animation.channel.target), only TRS properties may be present; `matrix` will not be present.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFNode : NSObject, Codable {
|
open class GLTFNode: NSObject, Codable {
|
||||||
/// The index of the camera referenced by this node.
|
/// The index of the camera referenced by this node.
|
||||||
public var camera:Int?
|
public var camera: Int?
|
||||||
|
|
||||||
/// The indices of this node's children.
|
/// The indices of this node's children.
|
||||||
public var children:[Int]?
|
public var children: [Int]?
|
||||||
|
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// A floating-point 4x4 transformation matrix stored in column-major order.
|
/// A floating-point 4x4 transformation matrix stored in column-major order.
|
||||||
public var matrix:[Double]
|
public var matrix: [Double]
|
||||||
|
|
||||||
/// The index of the mesh in this node.
|
/// The index of the mesh in this node.
|
||||||
public var mesh:Int?
|
public var mesh: Int?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The node's unit quaternion rotation in the order (x, y, z, w), where w is the scalar.
|
/// The node's unit quaternion rotation in the order (x, y, z, w), where w is the scalar.
|
||||||
public var rotation:[Double]
|
public var rotation: [Double]
|
||||||
|
|
||||||
/// The node's non-uniform scale, given as the scaling factors along the x, y, and z axes.
|
/// The node's non-uniform scale, given as the scaling factors along the x, y, and z axes.
|
||||||
public var scale:[Double]
|
public var scale: [Double]
|
||||||
|
|
||||||
/// The index of the skin referenced by this node.
|
/// The index of the skin referenced by this node.
|
||||||
public var skin:Int?
|
public var skin: Int?
|
||||||
|
|
||||||
/// The node's translation along the x, y, and z axes.
|
/// The node's translation along the x, y, and z axes.
|
||||||
public var translation:[Double]
|
public var translation: [Double]
|
||||||
|
|
||||||
/// The weights of the instantiated Morph Target. Number of elements must match number of Morph Targets of used mesh.
|
/// The weights of the instantiated Morph Target. Number of elements must match number of Morph Targets of used mesh.
|
||||||
public var weights:[Double]?
|
public var weights: [Double]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case camera
|
case camera
|
||||||
|
@ -63,7 +62,7 @@ open class GLTFNode : NSObject, Codable {
|
||||||
case translation
|
case translation
|
||||||
case weights
|
case weights
|
||||||
}
|
}
|
||||||
|
|
||||||
public override init() {
|
public override init() {
|
||||||
matrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
matrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
||||||
rotation = [0, 0, 0, 1]
|
rotation = [0, 0, 0, 1]
|
||||||
|
|
|
@ -149,30 +149,29 @@ import Foundation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Texture sampler properties for filtering and wrapping modes.
|
/// Texture sampler properties for filtering and wrapping modes.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFSampler : NSObject, Codable {
|
open class GLTFSampler: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// Magnification filter.
|
/// Magnification filter.
|
||||||
public var magFilter:GLTFSamplerMagFilter?
|
public var magFilter: GLTFSamplerMagFilter?
|
||||||
|
|
||||||
/// Minification filter.
|
/// Minification filter.
|
||||||
public var minFilter:GLTFSamplerMinFilter?
|
public var minFilter: GLTFSamplerMinFilter?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// s wrapping mode.
|
/// s wrapping mode.
|
||||||
public var wrapS:GLTFSamplerWrapS
|
public var wrapS: GLTFSamplerWrapS
|
||||||
|
|
||||||
/// t wrapping mode.
|
/// t wrapping mode.
|
||||||
public var wrapT:GLTFSamplerWrapT
|
public var wrapT: GLTFSamplerWrapT
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
@ -184,11 +183,11 @@ open class GLTFSampler : NSObject, Codable {
|
||||||
case wrapT
|
case wrapT
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(wrapS s:GLTFSamplerWrapS, wrapT t:GLTFSamplerWrapT) {
|
public init(wrapS s: GLTFSamplerWrapS, wrapT t: GLTFSamplerWrapT) {
|
||||||
wrapS = s
|
wrapS = s
|
||||||
wrapT = t
|
wrapT = t
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
extensions = try? container.decode([String: Any].self, forKey: .extensions)
|
extensions = try? container.decode([String: Any].self, forKey: .extensions)
|
||||||
|
|
|
@ -9,21 +9,20 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// The root nodes of a scene.
|
/// The root nodes of a scene.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFScene : NSObject, Codable {
|
open class GLTFScene: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The indices of each root node.
|
/// The indices of each root node.
|
||||||
public var nodes:[Int]?
|
public var nodes: [Int]?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
@ -31,7 +30,7 @@ open class GLTFScene : NSObject, Codable {
|
||||||
case name
|
case name
|
||||||
case nodes
|
case nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
public override init() {}
|
public override init() {}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
|
|
|
@ -9,27 +9,26 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Joints and matrices defining a skin.
|
/// Joints and matrices defining a skin.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFSkin : NSObject, Codable {
|
open class GLTFSkin: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of the accessor containing the floating-point 4x4 inverse-bind matrices. The default is that each matrix is a 4x4 identity matrix, which implies that inverse-bind matrices were pre-applied.
|
/// The index of the accessor containing the floating-point 4x4 inverse-bind matrices. The default is that each matrix is a 4x4 identity matrix, which implies that inverse-bind matrices were pre-applied.
|
||||||
public var inverseBindMatrices:Int?
|
public var inverseBindMatrices: Int?
|
||||||
|
|
||||||
/// Indices of skeleton nodes, used as joints in this skin.
|
/// Indices of skeleton nodes, used as joints in this skin.
|
||||||
public var joints:[Int]
|
public var joints: [Int]
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The index of the node used as a skeleton root. When undefined, joints transforms resolve to scene root.
|
/// The index of the node used as a skeleton root. When undefined, joints transforms resolve to scene root.
|
||||||
public var skeleton:Int?
|
public var skeleton: Int?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
|
|
|
@ -9,25 +9,24 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// A texture and its sampler.
|
/// A texture and its sampler.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFTexture : NSObject, Codable {
|
open class GLTFTexture: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The user-defined name of this object.
|
/// The user-defined name of this object.
|
||||||
public var name:String?
|
public var name: String?
|
||||||
|
|
||||||
/// The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used.
|
/// The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used.
|
||||||
public var sampler:Int?
|
public var sampler: Int?
|
||||||
|
|
||||||
/// The index of the image used by this texture.
|
/// The index of the image used by this texture.
|
||||||
public var source:Int?
|
public var source: Int?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
case extras
|
case extras
|
||||||
|
@ -37,10 +36,10 @@ open class GLTFTexture : NSObject, Codable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override init() { }
|
public override init() { }
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
extensions = try? container.decode([String: GLTF_3D4MCompressedTextureExtension].self, forKey: .extensions)
|
extensions = try? container.decode([String: GLTF_3D4MCompressedTextureExtension].self, forKey: .extensions)
|
||||||
extras = try? container.decode([String: Any].self, forKey: .extras)
|
extras = try? container.decode([String: Any].self, forKey: .extras)
|
||||||
name = try? container.decode(String.self, forKey: .name)
|
name = try? container.decode(String.self, forKey: .name)
|
||||||
sampler = try? container.decode(Int.self, forKey: .sampler)
|
sampler = try? container.decode(Int.self, forKey: .sampler)
|
||||||
|
@ -57,7 +56,6 @@ open class GLTFTexture : NSObject, Codable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension KeyedEncodingContainerProtocol {
|
extension KeyedEncodingContainerProtocol {
|
||||||
mutating func encode(_ value: [String: GLTF_3D4MCompressedTextureExtension]?, forKey key: Key) throws {
|
mutating func encode(_ value: [String: GLTF_3D4MCompressedTextureExtension]?, forKey key: Key) throws {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
|
@ -66,4 +64,3 @@ extension KeyedEncodingContainerProtocol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,27 +9,26 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
/// Reference to a texture.
|
/// Reference to a texture.
|
||||||
@objcMembers
|
@objcMembers
|
||||||
open class GLTFTextureInfo : NSObject, Codable {
|
open class GLTFTextureInfo: NSObject, Codable {
|
||||||
/// Dictionary object with extension-specific objects.
|
/// Dictionary object with extension-specific objects.
|
||||||
public var extensions:[String: Any]?
|
public var extensions: [String: Any]?
|
||||||
|
|
||||||
/// Application-specific data.
|
/// Application-specific data.
|
||||||
public var extras:[String: Any]?
|
public var extras: [String: Any]?
|
||||||
|
|
||||||
/// The index of the texture.
|
/// The index of the texture.
|
||||||
public var index:Int
|
public var index: Int
|
||||||
|
|
||||||
/// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
/// The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
||||||
public var texCoord:Int
|
public var texCoord: Int
|
||||||
|
|
||||||
public init(index i:Int) {
|
public init(index i: Int) {
|
||||||
index = i
|
index = i
|
||||||
texCoord = 0
|
texCoord = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case extensions
|
case extensions
|
||||||
case extras
|
case extras
|
||||||
|
|
|
@ -7,36 +7,34 @@ import CoreGraphics
|
||||||
|
|
||||||
public struct JSONCodingKeys: CodingKey {
|
public struct JSONCodingKeys: CodingKey {
|
||||||
public var stringValue: String
|
public var stringValue: String
|
||||||
|
|
||||||
public init(stringValue: String) {
|
public init(stringValue: String) {
|
||||||
self.stringValue = stringValue
|
self.stringValue = stringValue
|
||||||
}
|
}
|
||||||
|
|
||||||
public var intValue: Int?
|
public var intValue: Int?
|
||||||
|
|
||||||
public init?(intValue: Int) {
|
public init?(intValue: Int) {
|
||||||
self.init(stringValue: "\(intValue)")
|
self.init(stringValue: "\(intValue)")
|
||||||
self.intValue = intValue
|
self.intValue = intValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public extension KeyedDecodingContainer {
|
public extension KeyedDecodingContainer {
|
||||||
|
|
||||||
func decode(_ type: Dictionary<String, Any>.Type, forKey key: K) throws -> Dictionary<String, Any> {
|
func decode(_ type: [String: Any].Type, forKey key: K) throws -> [String: Any] {
|
||||||
let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
|
let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
|
||||||
return try container.decode(type)
|
return try container.decode(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode(_ type: Array<Any>.Type, forKey key: K) throws -> Array<Any> {
|
func decode(_ type: [Any].Type, forKey key: K) throws -> [Any] {
|
||||||
var container = try self.nestedUnkeyedContainer(forKey: key)
|
var container = try self.nestedUnkeyedContainer(forKey: key)
|
||||||
return try container.decode(type)
|
return try container.decode(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decode(_ type: [String: Any].Type) throws -> [String: Any] {
|
||||||
func decode(_ type: Dictionary<String, Any>.Type) throws -> Dictionary<String, Any> {
|
var dictionary = [String: Any]()
|
||||||
var dictionary = Dictionary<String, Any>()
|
|
||||||
|
|
||||||
for key in allKeys {
|
for key in allKeys {
|
||||||
if let boolValue = try? decode(Bool.self, forKey: key) {
|
if let boolValue = try? decode(Bool.self, forKey: key) {
|
||||||
dictionary[key.stringValue] = boolValue
|
dictionary[key.stringValue] = boolValue
|
||||||
|
@ -57,8 +55,8 @@ public extension KeyedDecodingContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension UnkeyedDecodingContainer {
|
public extension UnkeyedDecodingContainer {
|
||||||
|
|
||||||
mutating func decode(_ type: Array<Any>.Type) throws -> Array<Any> {
|
mutating func decode(_ type: [Any].Type) throws -> [Any] {
|
||||||
var array: [Any] = []
|
var array: [Any] = []
|
||||||
while isAtEnd == false {
|
while isAtEnd == false {
|
||||||
if let value = try? decode(Bool.self) {
|
if let value = try? decode(Bool.self) {
|
||||||
|
@ -69,22 +67,22 @@ public extension UnkeyedDecodingContainer {
|
||||||
array.append(value)
|
array.append(value)
|
||||||
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self) {
|
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self) {
|
||||||
array.append(nestedDictionary)
|
array.append(nestedDictionary)
|
||||||
} else if let nestedArray = try? decode(Array<Any>.self) {
|
} else if var nestedContainer = try? nestedUnkeyedContainer(),
|
||||||
|
let nestedArray = try? nestedContainer.decode(Array<Any>.self) {
|
||||||
array.append(nestedArray)
|
array.append(nestedArray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func decode(_ type: Dictionary<String, Any>.Type) throws -> Dictionary<String, Any> {
|
mutating func decode(_ type: [String: Any].Type) throws -> [String: Any] {
|
||||||
let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
|
let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
|
||||||
return try nestedContainer.decode(type)
|
return try nestedContainer.decode(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
|
public extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
|
||||||
mutating func encode(_ value: Dictionary<String, Any>) throws {
|
mutating func encode(_ value: [String: Any]) throws {
|
||||||
try value.forEach({ (key, value) in
|
try value.forEach({ (key, value) in
|
||||||
let key = JSONCodingKeys(stringValue: key)
|
let key = JSONCodingKeys(stringValue: key)
|
||||||
switch value {
|
switch value {
|
||||||
|
@ -98,9 +96,9 @@ public extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
|
||||||
try encode(value, forKey: key)
|
try encode(value, forKey: key)
|
||||||
case let value as CGFloat:
|
case let value as CGFloat:
|
||||||
try encode(value, forKey: key)
|
try encode(value, forKey: key)
|
||||||
case let value as Dictionary<String, Any>:
|
case let value as [String: Any]:
|
||||||
try encode(value, forKey: key)
|
try encode(value, forKey: key)
|
||||||
case let value as Array<Any>:
|
case let value as [Any]:
|
||||||
try encode(value, forKey: key)
|
try encode(value, forKey: key)
|
||||||
case Optional<Any>.none:
|
case Optional<Any>.none:
|
||||||
try encodeNil(forKey: key)
|
try encodeNil(forKey: key)
|
||||||
|
@ -112,14 +110,14 @@ public extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension KeyedEncodingContainerProtocol {
|
public extension KeyedEncodingContainerProtocol {
|
||||||
mutating func encode(_ value: Dictionary<String, Any>?, forKey key: Key) throws {
|
mutating func encode(_ value: [String: Any]?, forKey key: Key) throws {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
var container = self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
|
var container = self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
|
||||||
try container.encode(value!)
|
try container.encode(value!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func encode(_ value: Array<Any>?, forKey key: Key) throws {
|
mutating func encode(_ value: [Any]?, forKey key: Key) throws {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
var container = self.nestedUnkeyedContainer(forKey: key)
|
var container = self.nestedUnkeyedContainer(forKey: key)
|
||||||
try container.encode(value!)
|
try container.encode(value!)
|
||||||
|
@ -128,7 +126,7 @@ public extension KeyedEncodingContainerProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension UnkeyedEncodingContainer {
|
public extension UnkeyedEncodingContainer {
|
||||||
mutating func encode(_ value: Array<Any>) throws {
|
mutating func encode(_ value: [Any]) throws {
|
||||||
try value.enumerated().forEach({ (index, value) in
|
try value.enumerated().forEach({ (index, value) in
|
||||||
switch value {
|
switch value {
|
||||||
case let value as Bool:
|
case let value as Bool:
|
||||||
|
@ -141,9 +139,9 @@ public extension UnkeyedEncodingContainer {
|
||||||
try encode(value)
|
try encode(value)
|
||||||
case let value as CGFloat:
|
case let value as CGFloat:
|
||||||
try encode(value)
|
try encode(value)
|
||||||
case let value as Dictionary<String, Any>:
|
case let value as [String: Any]:
|
||||||
try encode(value)
|
try encode(value)
|
||||||
case let value as Array<Any>:
|
case let value as [Any]:
|
||||||
try encode(value)
|
try encode(value)
|
||||||
case Optional<Any>.none:
|
case Optional<Any>.none:
|
||||||
try encodeNil()
|
try encodeNil()
|
||||||
|
@ -153,10 +151,9 @@ public extension UnkeyedEncodingContainer {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func encode(_ value: Dictionary<String, Any>) throws {
|
mutating func encode(_ value: [String: Any]) throws {
|
||||||
var nestedContainer = self.nestedContainer(keyedBy: JSONCodingKeys.self)
|
var nestedContainer = self.nestedContainer(keyedBy: JSONCodingKeys.self)
|
||||||
try nestedContainer.encode(value)
|
try nestedContainer.encode(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,468 @@
|
||||||
|
//
|
||||||
|
// GLTF+Geometry.swift
|
||||||
|
// glTFSceneKit
|
||||||
|
//
|
||||||
|
// Created by sergey.novikov on 03/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SceneKit
|
||||||
|
|
||||||
|
extension GLTFMeshPrimitiveMode {
|
||||||
|
public func scn() -> SCNGeometryPrimitiveType {
|
||||||
|
switch self {
|
||||||
|
case .POINTS:
|
||||||
|
return .point
|
||||||
|
case .LINES, .LINE_LOOP, .LINE_STRIP:
|
||||||
|
return .line
|
||||||
|
case .TRIANGLE_STRIP:
|
||||||
|
return .triangleStrip
|
||||||
|
case .TRIANGLES:
|
||||||
|
return .triangles
|
||||||
|
default:
|
||||||
|
return .triangles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
|
extension GLTFAccessor {
|
||||||
|
public func components() -> Int {
|
||||||
|
switch type {
|
||||||
|
case .SCALAR:
|
||||||
|
return 1
|
||||||
|
case .VEC2:
|
||||||
|
return 2
|
||||||
|
case .VEC3:
|
||||||
|
return 3
|
||||||
|
case .VEC4, .MAT2:
|
||||||
|
return 4
|
||||||
|
case .MAT3:
|
||||||
|
return 9
|
||||||
|
case .MAT4:
|
||||||
|
return 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func bytesPerElement() -> Int {
|
||||||
|
switch componentType {
|
||||||
|
case .UNSIGNED_BYTE, .BYTE:
|
||||||
|
return 1
|
||||||
|
case .UNSIGNED_SHORT, .SHORT:
|
||||||
|
return 2
|
||||||
|
default:
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func vertexFormat() -> MTLVertexFormat {
|
||||||
|
switch type {
|
||||||
|
case .SCALAR:
|
||||||
|
switch componentType {
|
||||||
|
case .UNSIGNED_SHORT, .SHORT, .UNSIGNED_BYTE, .BYTE:
|
||||||
|
fatalError("Unsupported")
|
||||||
|
|
||||||
|
case .UNSIGNED_INT:
|
||||||
|
return .uint
|
||||||
|
case .FLOAT:
|
||||||
|
return .float
|
||||||
|
}
|
||||||
|
|
||||||
|
case .VEC2:
|
||||||
|
switch componentType {
|
||||||
|
case .UNSIGNED_SHORT:
|
||||||
|
return .ushort2
|
||||||
|
case .SHORT:
|
||||||
|
return .short2
|
||||||
|
case .UNSIGNED_BYTE:
|
||||||
|
return .uchar2
|
||||||
|
case .BYTE:
|
||||||
|
return .char2
|
||||||
|
case .UNSIGNED_INT:
|
||||||
|
return .uint2
|
||||||
|
case .FLOAT:
|
||||||
|
return .float2
|
||||||
|
}
|
||||||
|
|
||||||
|
case .VEC3:
|
||||||
|
switch componentType {
|
||||||
|
case .UNSIGNED_SHORT:
|
||||||
|
return .ushort3
|
||||||
|
case .SHORT:
|
||||||
|
return .short3
|
||||||
|
case .UNSIGNED_BYTE:
|
||||||
|
return .uchar3
|
||||||
|
case .BYTE:
|
||||||
|
return .char3
|
||||||
|
case .UNSIGNED_INT:
|
||||||
|
return .uint3
|
||||||
|
case .FLOAT:
|
||||||
|
return .float3
|
||||||
|
}
|
||||||
|
|
||||||
|
case .VEC4:
|
||||||
|
switch componentType {
|
||||||
|
case .UNSIGNED_SHORT:
|
||||||
|
return .ushort4
|
||||||
|
case .SHORT:
|
||||||
|
return .short4
|
||||||
|
case .UNSIGNED_BYTE:
|
||||||
|
return .uchar4
|
||||||
|
case .BYTE:
|
||||||
|
return .char4
|
||||||
|
case .UNSIGNED_INT:
|
||||||
|
return .uint4
|
||||||
|
case .FLOAT:
|
||||||
|
return .float4
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatalError("Unsupported")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate extension GLTF {
|
||||||
|
//let buffer = glTF.buffers![glTF.bufferViews![bufferView].buffer]
|
||||||
|
func buffer(for bufferView: Int) -> GLTFBuffer? {
|
||||||
|
if let bufferIndex = self.bufferViews?[bufferView].buffer {
|
||||||
|
return self.buffers?[bufferIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
|
extension GLTFConverter {
|
||||||
|
|
||||||
|
/// convert glTF mesh into SCNGeometry
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - node: gltf node
|
||||||
|
/// - scnNode: SceneKit node, which is going to be parent node
|
||||||
|
internal func geometryNode(_ node: GLTFNode, _ scnNode: SCNNode) throws {
|
||||||
|
|
||||||
|
if glTF.isCancelled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let meshIndex = node.mesh {
|
||||||
|
var weightPaths = [String]()
|
||||||
|
|
||||||
|
if let mesh = glTF.meshes?[meshIndex] {
|
||||||
|
|
||||||
|
var primitiveIndex = 0
|
||||||
|
|
||||||
|
for primitive in mesh.primitives {
|
||||||
|
|
||||||
|
var sources: [SCNGeometrySource] = [SCNGeometrySource]()
|
||||||
|
var elements: [SCNGeometryElement] = [SCNGeometryElement]()
|
||||||
|
|
||||||
|
// get indices
|
||||||
|
if let element = try self.geometryElement(primitive) {
|
||||||
|
elements.append(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get sources from attributes information
|
||||||
|
if let geometrySources = try self.geometrySources(primitive.attributes) {
|
||||||
|
sources.append(contentsOf: geometrySources)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DRACO
|
||||||
|
// check on draco extension
|
||||||
|
if let dracoMesh = primitive.extensions?[dracoExtensionKey] {
|
||||||
|
let (dElement, dSources) = try glTF.convertDracoMesh(dracoMesh as! GLTFKHRDracoMeshCompressionExtension)
|
||||||
|
|
||||||
|
if dElement != nil {
|
||||||
|
elements.append(dElement!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dSources != nil {
|
||||||
|
sources.append(contentsOf: dSources!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if glTF.isCancelled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let primitiveNode: SCNNode
|
||||||
|
// create geometry
|
||||||
|
let geometry = SCNGeometry.init(sources: sources, elements: elements)
|
||||||
|
|
||||||
|
if primitiveIndex < scnNode.childNodes.count {
|
||||||
|
primitiveNode = scnNode.childNodes[primitiveIndex]
|
||||||
|
primitiveNode.geometry = geometry
|
||||||
|
} else {
|
||||||
|
primitiveNode = SCNNode.init(geometry: geometry)
|
||||||
|
scnNode.addChildNode(primitiveNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
primitiveNode.name = mesh.name
|
||||||
|
|
||||||
|
delegate?.scene?(loadingScene!, didCreate: primitiveNode)
|
||||||
|
|
||||||
|
if primitiveNode.geometry?.firstMaterial != nil {
|
||||||
|
// create empty SCNMaterial. Callbacks call later then materail will be download, so we must provide materail for selection
|
||||||
|
let emptyMaterial = SCNMaterial()
|
||||||
|
emptyMaterial.name = "empty"
|
||||||
|
emptyMaterial.isDoubleSided = true
|
||||||
|
|
||||||
|
primitiveNode.geometry!.firstMaterial = emptyMaterial
|
||||||
|
}
|
||||||
|
|
||||||
|
if let materialIndex = primitive.material {
|
||||||
|
self.glTF.loadMaterial(index: materialIndex, delegate: self, textureChangedCallback: { _ in
|
||||||
|
if let material = primitiveNode.geometry?.firstMaterial {
|
||||||
|
if let texture = material.diffuse.contents as? MTLTexture {
|
||||||
|
if texture.pixelFormat.hasAlpha() {
|
||||||
|
primitiveNode.renderingOrder = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, completionHandler: { [unowned self] scnMaterial in
|
||||||
|
self.delegate?.scene?(self.loadingScene!, didCreate: scnMaterial, for: primitiveNode)
|
||||||
|
|
||||||
|
let emissionContent = primitiveNode.geometry?.firstMaterial?.emission.contents
|
||||||
|
scnMaterial.emission.contents = emissionContent
|
||||||
|
|
||||||
|
geometry.materials = [scnMaterial]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if let transparency = primitiveNode.geometry?.firstMaterial?.transparency,
|
||||||
|
transparency < 1.0 {
|
||||||
|
primitiveNode.renderingOrder = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
if glTF.isCancelled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let targets = primitive.targets {
|
||||||
|
let morpher = SCNMorpher()
|
||||||
|
let targetsCount = targets.count
|
||||||
|
for targetIndex in 0..<targetsCount {
|
||||||
|
let target = targets[targetIndex]
|
||||||
|
if let sourcesMorph = try geometrySources(target) {
|
||||||
|
let geometryMorph = SCNGeometry(sources: sourcesMorph, elements: nil)
|
||||||
|
morpher.targets.append(geometryMorph)
|
||||||
|
|
||||||
|
let path = "childNodes[\(primitiveIndex)].morpher.weights[\(targetIndex)]"
|
||||||
|
weightPaths.append(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
morpher.calculationMode = .additive
|
||||||
|
primitiveNode.morpher = morpher
|
||||||
|
}
|
||||||
|
|
||||||
|
primitiveIndex += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scnNode.setValue(weightPaths, forUndefinedKey: "weightPaths")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func geometryElement(_ primitive: GLTFMeshPrimitive) throws -> SCNGeometryElement? {
|
||||||
|
if let indicesIndex = primitive.indices {
|
||||||
|
if let accessor = glTF.accessors?[indicesIndex],
|
||||||
|
let bufferViewIndex = accessor.bufferView,
|
||||||
|
let bufferView = glTF.bufferViews?[bufferViewIndex] {
|
||||||
|
|
||||||
|
if let indicesData = try loadAcessor(accessor, bufferView, false) {
|
||||||
|
|
||||||
|
var count = accessor.count
|
||||||
|
|
||||||
|
let primitiveType = primitive.mode.scn()
|
||||||
|
switch primitiveType {
|
||||||
|
case .triangles:
|
||||||
|
count /= 3
|
||||||
|
case .triangleStrip:
|
||||||
|
count -= 2
|
||||||
|
case .line:
|
||||||
|
count /= 2
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCNGeometryElement.init(data: indicesData,
|
||||||
|
primitiveType: primitiveType,
|
||||||
|
primitiveCount: count,
|
||||||
|
bytesPerIndex: accessor.bytesPerElement())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw GLTFError("Can't find indices acessor with index \(indicesIndex)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert mesh/animation attributes into SCNGeometrySource
|
||||||
|
///
|
||||||
|
/// - Parameter attributes: dictionary of accessors
|
||||||
|
/// - Returns: array of SCNGeometrySource objects
|
||||||
|
fileprivate func geometrySources(_ attributes: [String: Int]) throws -> [SCNGeometrySource]? {
|
||||||
|
var geometrySources = [SCNGeometrySource]()
|
||||||
|
|
||||||
|
// accessors can point to different buffers. We cache last one.
|
||||||
|
var previousBufferView = -1
|
||||||
|
var mtlBuffer: MTLBuffer?
|
||||||
|
|
||||||
|
var byteOffset = 0
|
||||||
|
var byteStride = 0
|
||||||
|
|
||||||
|
for (key, accessorIndex) in attributes {
|
||||||
|
if let accessor = glTF.accessors?[accessorIndex],
|
||||||
|
let (bufferView, interleaved) = try determineAcessor(accessor) {
|
||||||
|
|
||||||
|
byteOffset = (interleaved) ? accessor.byteOffset : 0
|
||||||
|
byteStride = bufferView.byteStride ?? 0
|
||||||
|
|
||||||
|
if mtlBuffer == nil || previousBufferView != accessor.bufferView! {
|
||||||
|
if let data = try loadAcessor(accessor, bufferView, interleaved) {
|
||||||
|
|
||||||
|
let device = self.device()
|
||||||
|
data.withUnsafeBytes { (unsafeBufferPointer: UnsafeRawBufferPointer) in
|
||||||
|
let uint8Ptr = unsafeBufferPointer.bindMemory(to: Int8.self).baseAddress!
|
||||||
|
mtlBuffer = device?.makeBuffer(bytes: uint8Ptr, length: data.count, options: .storageModeShared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousBufferView = accessor.bufferView!
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = accessor.count
|
||||||
|
|
||||||
|
let vertexFormat: MTLVertexFormat = accessor.vertexFormat()
|
||||||
|
|
||||||
|
// convert string semantic to SceneKit semantic type
|
||||||
|
let semantic = GLTF.sourceSemantic(name: key)
|
||||||
|
|
||||||
|
if let mtlB = mtlBuffer {
|
||||||
|
let geometrySource = SCNGeometrySource.init(buffer: mtlB,
|
||||||
|
vertexFormat: vertexFormat,
|
||||||
|
semantic: semantic,
|
||||||
|
vertexCount: count,
|
||||||
|
dataOffset: byteOffset,
|
||||||
|
dataStride: byteStride)
|
||||||
|
geometrySources.append(geometrySource)
|
||||||
|
} else {
|
||||||
|
// TODO: implement fallback on init with data, which was deleted
|
||||||
|
|
||||||
|
throw GLTFError("Metal device failed to allocate MTLBuffer with accessor.bufferView = \(accessor.bufferView!)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw GLTFError("Can't locate accessor at \(accessorIndex) index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return geometrySources
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Collect associated buffers for node into a Set on Decode time.
|
||||||
|
internal func _preloadBuffersData(nodeIndex: Int, completionHandler: @escaping (Error?) -> Void ) {
|
||||||
|
|
||||||
|
var buffers: Set = Set<GLTFBuffer>()
|
||||||
|
|
||||||
|
let insertBuffer: ( (Int?) -> Void ) = { [weak self] index in
|
||||||
|
guard let index = index else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let accessor = self?.glTF.accessors?[index] {
|
||||||
|
if let bufferView = accessor.bufferView,
|
||||||
|
let buffer = self?.glTF.buffer(for: bufferView) {
|
||||||
|
buffers.insert(buffer)
|
||||||
|
} else {
|
||||||
|
self?.errorMessage = GLTFError("Can't locate buffer with accessor at \(index) index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let node = glTF.nodes?[nodeIndex],
|
||||||
|
let meshIndex = node.mesh,
|
||||||
|
let mesh = glTF.meshes?[meshIndex] {
|
||||||
|
|
||||||
|
for primitive in mesh.primitives {
|
||||||
|
// check on draco extension
|
||||||
|
#if DRACO
|
||||||
|
if let dracoMesh = primitive.extensions?[dracoExtensionKey] {
|
||||||
|
if let dracoMesh = dracoMesh as? GLTFKHRDracoMeshCompressionExtension {
|
||||||
|
if let buffer = glTF.buffer(for: dracoMesh.bufferView) {
|
||||||
|
buffers.insert(buffer)
|
||||||
|
} else {
|
||||||
|
errorMessage = GLTFError("Can't locate draco buffer with bufferView at \(dracoMesh.bufferView) index")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
errorMessage = GLTFError("Draco extension not compatible for mesh at \(meshIndex) index")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
primitive.attributes.forEach { (_, index) in
|
||||||
|
insertBuffer(index)
|
||||||
|
}
|
||||||
|
insertBuffer(primitive.indices)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
primitive.attributes.forEach { (_, index) in
|
||||||
|
insertBuffer(index)
|
||||||
|
}
|
||||||
|
insertBuffer(primitive.indices)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glTF.loader.load(gltf: glTF, resources: buffers, options: ResourceType.buffer, completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine where an accessor and a bufferView link are interleaved or not
|
||||||
|
internal func determineAcessor(_ accessor: GLTFAccessor) throws -> (GLTFBufferView, Bool)? {
|
||||||
|
|
||||||
|
guard let index = accessor.bufferView else {
|
||||||
|
throw GLTFError("Missing 'bufferView' for \(accessor.name ?? "") acessor")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let bufferView = glTF.bufferViews?[index] {
|
||||||
|
|
||||||
|
// Interleaved data usualy has bytesStride as correct value.
|
||||||
|
// Some times non-interleaved data also has bytesStride, and in some cases don't. It's up to exporter
|
||||||
|
// We do calculate bytesStride for accessor manualy and compare it later to determine if our data is interleaved or not.
|
||||||
|
let byteStride: Int = bufferView.byteStride ?? 0
|
||||||
|
let accessorByteStride = accessor.components()*accessor.bytesPerElement()
|
||||||
|
|
||||||
|
let interleaved = (byteStride != accessorByteStride)
|
||||||
|
return (bufferView, interleaved)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get data by accessor
|
||||||
|
internal func loadAcessor(_ accessor: GLTFAccessor, _ bufferView: GLTFBufferView, _ interleaved: Bool) throws -> Data? {
|
||||||
|
|
||||||
|
if let data = try GLTF.requestData(glTF: glTF, bufferView: bufferView) {
|
||||||
|
|
||||||
|
var byteStride: Int = bufferView.byteStride ?? 0
|
||||||
|
if byteStride == 0 {
|
||||||
|
byteStride = accessor.components()*accessor.bytesPerElement()
|
||||||
|
}
|
||||||
|
// calculate length
|
||||||
|
let bytesLength = byteStride * accessor.count
|
||||||
|
|
||||||
|
// calculate range
|
||||||
|
let start = bufferView.byteOffset + ((!interleaved) ? accessor.byteOffset : 0)
|
||||||
|
let end = start + bytesLength
|
||||||
|
|
||||||
|
var subdata = data
|
||||||
|
if start != 0 || end != data.count {
|
||||||
|
subdata = data.subdata(in: start..<end)
|
||||||
|
}
|
||||||
|
|
||||||
|
return subdata
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,339 @@
|
||||||
|
//
|
||||||
|
// GLTFConverter.swift
|
||||||
|
// glTFSceneKit
|
||||||
|
//
|
||||||
|
// Created by sergey.novikov on 03/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SceneKit
|
||||||
|
import os
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
|
public class GLTFConverter: TextureLoaderDelegate {
|
||||||
|
|
||||||
|
/// Status will be true if `cancel` was call.
|
||||||
|
@objc internal var errorMessage: Error?
|
||||||
|
|
||||||
|
internal private(set) var cache_nodes: [SCNNode?]?
|
||||||
|
|
||||||
|
internal var _completionHandler: ((Error?) -> Void) = { _ in }
|
||||||
|
internal var nodesDispatchGroup: DispatchGroup = DispatchGroup()
|
||||||
|
internal var convertionProgressMask: ConvertionProgressMask = ConvertionProgressMask(rawValue: 0)
|
||||||
|
|
||||||
|
public weak var renderer: SCNSceneRenderer?
|
||||||
|
internal var loadingScene: SCNScene?
|
||||||
|
public weak var delegate: SceneLoadingDelegate?
|
||||||
|
|
||||||
|
var animationDuration: Double = 0.0
|
||||||
|
|
||||||
|
internal var glTF: GLTF
|
||||||
|
|
||||||
|
public init(glTF: GLTF) {
|
||||||
|
self.glTF = glTF
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert glTF object to SceneKit scene.
|
||||||
|
///
|
||||||
|
/// - Parameter scene: Optional parameter. If property is set then loaded model will be add to existing objects in scene.
|
||||||
|
/// - Parameter view: Required for Metal. But optional for OpenGL rendering.
|
||||||
|
/// - Parameter directoryPath: location to others related resources of glTF.
|
||||||
|
/// - Parameter multiThread: By default model will be load in multiple threads.
|
||||||
|
/// - Parameter completionHandler: Execute completion block once model fully loaded. If multiThread parameter set to true, then scene will be returned soon as possible and completion block will be executed later, after all textures load.
|
||||||
|
/// - Returns: instance of Scene
|
||||||
|
@objc open func convert(to scene: SCNScene = SCNScene.init(),
|
||||||
|
rootNode: SCNNode? = nil,
|
||||||
|
directoryPath: String? = nil,
|
||||||
|
multiThread: Bool = true,
|
||||||
|
hidden: Bool = false,
|
||||||
|
geometryCompletionHandler: @escaping () -> Void = { },
|
||||||
|
completionHandler: @escaping ((Error?) -> Void) = {_ in }) -> SCNScene? {
|
||||||
|
|
||||||
|
if glTF.extensionsUsed != nil {
|
||||||
|
// for key in self.extensionsUsed! {
|
||||||
|
// if !supportedExtensions.contains(key) {
|
||||||
|
// completionHandler("Used `\(key)` extension is not supported!")
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if glTF.extensionsRequired != nil {
|
||||||
|
for key in glTF.extensionsRequired! {
|
||||||
|
if !supportedExtensions.contains(key) {
|
||||||
|
completionHandler(GLTFError("Required `\(key)` extension is not supported!"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(delegate != nil)
|
||||||
|
|
||||||
|
self.loadingScene = scene
|
||||||
|
self._completionHandler = completionHandler
|
||||||
|
|
||||||
|
if directoryPath != nil {
|
||||||
|
glTF.loader.directoryPath = directoryPath!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get dispatch group for current GLTF
|
||||||
|
let convertGroup = self.nodesDispatchGroup
|
||||||
|
convertGroup.enter()
|
||||||
|
|
||||||
|
if glTF.scenes != nil && glTF.scene != nil {
|
||||||
|
let sceneGlTF = glTF.scenes![(glTF.scene)!]
|
||||||
|
if let sceneName = sceneGlTF.name {
|
||||||
|
scene.setAttribute(sceneName, forKey: "name")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cache_nodes = [SCNNode?](repeating: nil, count: glTF.nodes!.count)
|
||||||
|
|
||||||
|
// run in multi-thread or single
|
||||||
|
if multiThread {
|
||||||
|
|
||||||
|
let start = Date()
|
||||||
|
|
||||||
|
// this enter is requered here in case materials has few textures
|
||||||
|
// which loaded very quickly even before all geometries submitted for load
|
||||||
|
let texturesGroup = TextureStorageManager.manager.group(gltf: glTF, delegate: self, true)
|
||||||
|
|
||||||
|
// construct nodes tree
|
||||||
|
|
||||||
|
_constructNodesTree(rootNode: rootNode ?? scene.rootNode, nodes: sceneGlTF.nodes!, group: convertGroup, hidden: hidden)
|
||||||
|
|
||||||
|
os_log("submit data to download %d ms", log: log_scenekit, type: .debug, Int(start.timeIntervalSinceNow * -1000))
|
||||||
|
|
||||||
|
// completion
|
||||||
|
convertGroup.notify(queue: DispatchQueue.main) {
|
||||||
|
texturesGroup.leave()
|
||||||
|
|
||||||
|
geometryCompletionHandler()
|
||||||
|
os_log("geometry loaded %d ms", log: log_scenekit, type: .debug, Int(start.timeIntervalSinceNow * -1000))
|
||||||
|
|
||||||
|
self._nodesConverted(self.errorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
convertGroup.leave()
|
||||||
|
} else {
|
||||||
|
var err: Error?
|
||||||
|
do {
|
||||||
|
for nodeIndex in sceneGlTF.nodes! {
|
||||||
|
if let scnNode = try self.buildNode(nodeIndex: nodeIndex) {
|
||||||
|
scnNode.isHidden = hidden
|
||||||
|
|
||||||
|
scene.rootNode.addChildNode(scnNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
err = error
|
||||||
|
}
|
||||||
|
convertGroup.leave()
|
||||||
|
geometryCompletionHandler()
|
||||||
|
self._nodesConverted(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if glTF.isCancelled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return scene
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
open func cancel() {
|
||||||
|
glTF.cancel()
|
||||||
|
TextureStorageManager.manager.clear(gltf: glTF)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func _constructNodesTree(rootNode: SCNNode, nodes: [Int], group: DispatchGroup, hidden: Bool) {
|
||||||
|
var cache_nodes = self.cache_nodes
|
||||||
|
for nodeIndex in nodes {
|
||||||
|
|
||||||
|
if glTF.isCancelled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let node = glTF.nodes?[nodeIndex] {
|
||||||
|
|
||||||
|
group.enter() // <=== enter group
|
||||||
|
|
||||||
|
let scnNode: SCNNode
|
||||||
|
if let name = node.name,
|
||||||
|
let existedNode = rootNode.childNode(withName: name, recursively: false) {
|
||||||
|
scnNode = existedNode
|
||||||
|
} else {
|
||||||
|
scnNode = SCNNode()
|
||||||
|
}
|
||||||
|
scnNode.isHidden = hidden
|
||||||
|
scnNode.name = node.name
|
||||||
|
|
||||||
|
let haveChilds = node.children != nil && node.children?.count != 0
|
||||||
|
if haveChilds {
|
||||||
|
_constructNodesTree(rootNode: scnNode, nodes: node.children!, group: group, hidden: hidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create nodes up front to avoid deadlocks in multithreading
|
||||||
|
if let meshIndex = node.mesh {
|
||||||
|
let primitivesCount = glTF.meshes?[meshIndex].primitives.count ?? 0
|
||||||
|
for _ in 0..<primitivesCount {
|
||||||
|
let scnNodePrimitiveNode = SCNNode()
|
||||||
|
scnNode.addChildNode(scnNodePrimitiveNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rootNode.addChildNode(scnNode)
|
||||||
|
cache_nodes?[nodeIndex] = scnNode
|
||||||
|
|
||||||
|
self._preloadBuffersData(nodeIndex: nodeIndex) { error in
|
||||||
|
if error != nil {
|
||||||
|
print("Failed to load geometry node with error: \(error!)")
|
||||||
|
self.errorMessage = error
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
_ = try self.buildNode(nodeIndex: nodeIndex, scnNode: scnNode)
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
self.errorMessage = error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group.leave() // <=== leave group
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Nodes converted, start parse and create animation.
|
||||||
|
/// And in case no textures required to load, complete convertion from glTF to SceneKit.
|
||||||
|
fileprivate func _nodesConverted(_ error: Error?) {
|
||||||
|
self.convertionProgressMask.insert(.nodes)
|
||||||
|
|
||||||
|
if let e = error {
|
||||||
|
self.errorMessage = e
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try self.parseAnimations()
|
||||||
|
} catch {
|
||||||
|
self.errorMessage = error
|
||||||
|
}
|
||||||
|
// probably should be inserted some where else and call on completion of animation parse
|
||||||
|
self.convertionProgressMask.insert(.animations)
|
||||||
|
|
||||||
|
self.nodesDispatchGroup.wait()
|
||||||
|
|
||||||
|
if glTF.textures?.count == 0 {
|
||||||
|
self.convertionProgressMask.insert(.textures)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.convertionProgressMask.rawValue == ConvertionProgressMask.all().rawValue {
|
||||||
|
self._converted(self.errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func texturesLoaded() {
|
||||||
|
self.convertionProgressMask.insert(.textures)
|
||||||
|
TextureStorageManager.manager.clear(gltf: glTF)
|
||||||
|
|
||||||
|
if self.convertionProgressMask.rawValue == ConvertionProgressMask.all().rawValue {
|
||||||
|
self._converted(self.errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Completion function and cache cleaning.
|
||||||
|
internal func _converted(_ error: Error?) {
|
||||||
|
os_log("convert completed", log: log_scenekit, type: .debug)
|
||||||
|
|
||||||
|
delegate?.scene?(loadingScene!)
|
||||||
|
delegate = nil
|
||||||
|
loadingScene = nil
|
||||||
|
|
||||||
|
// clear cache
|
||||||
|
_completionHandler(error)
|
||||||
|
_completionHandler = {_ in }
|
||||||
|
|
||||||
|
self.cache_nodes?.removeAll()
|
||||||
|
|
||||||
|
self.clearCache()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Nodes
|
||||||
|
|
||||||
|
fileprivate func buildNode(nodeIndex: Int, scnNode: SCNNode = SCNNode()) throws -> SCNNode? {
|
||||||
|
|
||||||
|
if let node = glTF.nodes?[nodeIndex] {
|
||||||
|
|
||||||
|
// Get camera, if it has reference on any.
|
||||||
|
constructCamera(node, scnNode)
|
||||||
|
|
||||||
|
// convert meshes if any exists in gltf node
|
||||||
|
try self.geometryNode(node, scnNode)
|
||||||
|
|
||||||
|
// load skin if any reference exists
|
||||||
|
if let skin = node.skin {
|
||||||
|
self.loadSkin(skin, scnNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bake all transformations into one mtarix
|
||||||
|
scnNode.transform = bakeTransformationMatrix(node)
|
||||||
|
|
||||||
|
if glTF.isCancelled {
|
||||||
|
return scnNode
|
||||||
|
}
|
||||||
|
|
||||||
|
if let children = node.children {
|
||||||
|
for i in children {
|
||||||
|
if let subSCNNode = try self.buildNode(nodeIndex: i) {
|
||||||
|
scnNode.addChildNode(subSCNNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scnNode
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func bakeTransformationMatrix(_ node: GLTFNode) -> SCNMatrix4 {
|
||||||
|
let rotation = GLKMatrix4MakeWithQuaternion(GLKQuaternion.init(q: (Float(node.rotation[0]), Float(node.rotation[1]), Float(node.rotation[2]), Float(node.rotation[3]))))
|
||||||
|
var matrix = SCNMatrix4.init(array: node.matrix)
|
||||||
|
matrix = SCNMatrix4Translate(matrix, SCNFloat(node.translation[0]), SCNFloat(node.translation[1]), SCNFloat(node.translation[2]))
|
||||||
|
matrix = SCNMatrix4Mult(matrix, SCNMatrix4FromGLKMatrix4(rotation))
|
||||||
|
matrix = SCNMatrix4Scale(matrix, SCNFloat(node.scale[0]), SCNFloat(node.scale[1]), SCNFloat(node.scale[2]))
|
||||||
|
return matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func constructCamera(_ node: GLTFNode, _ scnNode: SCNNode) {
|
||||||
|
if let cameraIndex = node.camera {
|
||||||
|
scnNode.camera = SCNCamera()
|
||||||
|
if glTF.cameras != nil {
|
||||||
|
let camera = glTF.cameras![cameraIndex]
|
||||||
|
scnNode.camera?.name = camera.name
|
||||||
|
switch camera.type {
|
||||||
|
case .perspective:
|
||||||
|
scnNode.camera?.zNear = (camera.perspective?.znear)!
|
||||||
|
scnNode.camera?.zFar = (camera.perspective?.zfar)!
|
||||||
|
if #available(OSX 10.13, iOS 11.0, tvOS 11.0, *) {
|
||||||
|
scnNode.camera?.fieldOfView = CGFloat((camera.perspective?.yfov)! * 180.0 / .pi)
|
||||||
|
scnNode.camera?.wantsDepthOfField = true
|
||||||
|
scnNode.camera?.motionBlurIntensity = 0.3
|
||||||
|
}
|
||||||
|
case .orthographic:
|
||||||
|
scnNode.camera?.usesOrthographicProjection = true
|
||||||
|
scnNode.camera?.zNear = (camera.orthographic?.znear)!
|
||||||
|
scnNode.camera?.zFar = (camera.orthographic?.zfar)!
|
||||||
|
}
|
||||||
|
if let camera = scnNode.camera {
|
||||||
|
delegate?.scene?(loadingScene!, didCreate: camera)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func clearCache() {
|
||||||
|
glTF.clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func device() -> MTLDevice? {
|
||||||
|
return MetalDevice.device
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,63 +7,52 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
public enum ResourceType {
|
||||||
|
case buffer
|
||||||
|
case texture
|
||||||
|
case image
|
||||||
|
}
|
||||||
|
|
||||||
/// Description for resources delivery by request from general GLTF converter.
|
/// Description for resources delivery by request from general GLTF converter.
|
||||||
/// - Simple implementation is GLTFResourceLoaderDefault and utilised as default resource delivery instrument.
|
/// - Simple implementation is GLTFResourceLoaderDefault and utilised as default resource delivery instrument.
|
||||||
/// - Optionaly can be implemented own resource loader, for example if requered to deliver content from remote server.
|
/// - Optionaly can be implemented own resource loader, for example if requered to deliver content from remote server.
|
||||||
/// - All functionas with completion handler considered as possible delayed delivery, i.e. multi-thread or work with network.
|
/// - All functionas with completion handler considered as possible delayed delivery, i.e. multi-thread or work with network.
|
||||||
public protocol GLTFResourceLoader {
|
public protocol GLTFResourceLoader {
|
||||||
|
|
||||||
/// Set location where is gltf file is located.
|
/// Set location where is gltf file is located.
|
||||||
var directoryPath: String { get set }
|
var directoryPath: String { get set }
|
||||||
|
|
||||||
func load(gltf: GLTF, resource: GLTFBuffer) throws -> Data?
|
func load(gltf: GLTF, resource: GLTFBuffer) throws -> Data?
|
||||||
func load(gltf: GLTF, resource: GLTFBuffer, completionHandler: @escaping (GLTFBuffer, Error?) -> Void )
|
func load(gltf: GLTF, resource: GLTFBuffer, options: Any?, completionHandler: @escaping (GLTFBuffer, Error?) -> Void )
|
||||||
func load(gltf: GLTF, resources: Set<GLTFBuffer>, completionHandler: @escaping (Error?) -> Void )
|
func load(gltf: GLTF, resources: Set<GLTFBuffer>, options: Any?, completionHandler: @escaping (Error?) -> Void )
|
||||||
|
|
||||||
func load(gltf: GLTF, resource: GLTFImage) throws -> OSImage?
|
func load(gltf: GLTF, resource: GLTFImage) throws -> OSImage?
|
||||||
func load(gltf: GLTF, resource: GLTFImage, completionHandler: @escaping (GLTFImage, Error?) -> Void )
|
func load(gltf: GLTF, resource: GLTFImage, completionHandler: @escaping (GLTFImage, Error?) -> Void )
|
||||||
|
|
||||||
/// This function going to be call if `cancel` was occured on GLTF convert.
|
/// This function going to be call if `cancel` was occured on GLTF convert.
|
||||||
func cancelAll()
|
func cancelAll()
|
||||||
}
|
|
||||||
|
|
||||||
extension GLTF {
|
|
||||||
public var loader:GLTFResourceLoader {
|
|
||||||
get {
|
|
||||||
var loader_ = objc_getAssociatedObject(self, &Keys.resource_loader) as? GLTFResourceLoader
|
|
||||||
if loader_ != nil {
|
|
||||||
return loader_!
|
|
||||||
}
|
|
||||||
loader_ = GLTFResourceLoaderDefault()
|
|
||||||
self.loader = loader_!
|
|
||||||
return loader_!
|
|
||||||
}
|
|
||||||
set { objc_setAssociatedObject(self, &Keys.resource_loader, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Default resource delivery instrument.
|
/// Default resource delivery instrument.
|
||||||
open class GLTFResourceLoaderDefault : GLTFResourceLoader {
|
open class GLTFResourceLoaderDefault: GLTFResourceLoader {
|
||||||
|
|
||||||
public var directoryPath: String = ""
|
public var directoryPath: String = ""
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
|
||||||
open func load(gltf: GLTF, resource: GLTFBuffer) throws -> Data? {
|
open func load(gltf: GLTF, resource: GLTFBuffer) throws -> Data? {
|
||||||
if resource.data == nil && resource.uri != nil {
|
if resource.data == nil && resource.uri != nil {
|
||||||
resource.data = try loadUri(uri: resource.uri!)
|
resource.data = try loadUri(uri: resource.uri!)
|
||||||
}
|
}
|
||||||
return resource.data
|
return resource.data
|
||||||
}
|
}
|
||||||
|
|
||||||
open func load(gltf: GLTF, resource: GLTFBuffer, completionHandler: @escaping (GLTFBuffer, Error?) -> Void) {
|
open func load(gltf: GLTF, resource: GLTFBuffer, options: Any?, completionHandler: @escaping (GLTFBuffer, Error?) -> Void) {
|
||||||
var error_:Error?
|
var error_: Error?
|
||||||
do {
|
do {
|
||||||
if resource.data == nil && resource.uri != nil {
|
if resource.data == nil && resource.uri != nil {
|
||||||
if let data = try loadUri(uri: resource.uri!) {
|
if let data = try loadUri(uri: resource.uri!) {
|
||||||
resource.data = data
|
resource.data = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -71,26 +60,26 @@ open class GLTFResourceLoaderDefault : GLTFResourceLoader {
|
||||||
}
|
}
|
||||||
completionHandler(resource, error_)
|
completionHandler(resource, error_)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func load(gltf: GLTF, resources: Set<GLTFBuffer>, completionHandler: @escaping (Error?) -> Void) {
|
open func load(gltf: GLTF, resources: Set<GLTFBuffer>, options: Any?, completionHandler: @escaping (Error?) -> Void) {
|
||||||
var error_:Error?
|
var error_: Error?
|
||||||
do {
|
do {
|
||||||
for resource in resources {
|
for resource in resources {
|
||||||
if resource.data == nil && resource.uri != nil {
|
if resource.data == nil && resource.uri != nil {
|
||||||
if let data = try loadUri(uri: resource.uri!) {
|
if let data = try loadUri(uri: resource.uri!) {
|
||||||
resource.data = data
|
resource.data = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
error_ = error
|
error_ = error
|
||||||
}
|
}
|
||||||
DispatchQueue.global().async {
|
DispatchQueue.global(qos: .userInteractive).async {
|
||||||
completionHandler(error_)
|
completionHandler(error_)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open func load(gltf: GLTF, resource: GLTFImage) throws -> OSImage? {
|
open func load(gltf: GLTF, resource: GLTFImage) throws -> OSImage? {
|
||||||
if resource.image == nil && resource.uri != nil {
|
if resource.image == nil && resource.uri != nil {
|
||||||
if let imageData = try loadUri(uri: resource.uri!) {
|
if let imageData = try loadUri(uri: resource.uri!) {
|
||||||
|
@ -99,13 +88,13 @@ open class GLTFResourceLoaderDefault : GLTFResourceLoader {
|
||||||
}
|
}
|
||||||
return resource.image
|
return resource.image
|
||||||
}
|
}
|
||||||
|
|
||||||
open func load(gltf: GLTF, resource: GLTFImage, completionHandler: @escaping (GLTFImage, Error?) -> Void) {
|
open func load(gltf: GLTF, resource: GLTFImage, completionHandler: @escaping (GLTFImage, Error?) -> Void) {
|
||||||
var error_:Error?
|
var error_: Error?
|
||||||
do {
|
do {
|
||||||
if resource.image == nil && resource.uri != nil {
|
if resource.image == nil && resource.uri != nil {
|
||||||
if let imageData = try loadUri(uri: resource.uri!) {
|
if let imageData = try loadUri(uri: resource.uri!) {
|
||||||
resource.image = OSImage.init(data: imageData)
|
resource.image = OSImage.init(data: imageData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -113,55 +102,27 @@ open class GLTFResourceLoaderDefault : GLTFResourceLoader {
|
||||||
}
|
}
|
||||||
completionHandler(resource, error_)
|
completionHandler(resource, error_)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func cancelAll() {
|
open func cancelAll() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func loadUri(uri: String) throws -> Data? {
|
fileprivate func loadUri(uri: String) throws -> Data? {
|
||||||
var data = uri.base64Decoded()
|
var data = uri.base64Decoded()
|
||||||
if data == nil {
|
if data == nil {
|
||||||
|
if uri.hasPrefix("http") {
|
||||||
if (uri.hasPrefix("http")) {
|
|
||||||
if let url = URL.init(string: uri) {
|
if let url = URL.init(string: uri) {
|
||||||
data = try Data.init(contentsOf: url)
|
data = try Data.init(contentsOf: url)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let filepath = [self.directoryPath, uri].joined(separator: "/")
|
let filepath = [self.directoryPath, uri].joined(separator: "/")
|
||||||
if FileManager.default.fileExists(atPath: filepath) {
|
let url = URL(fileURLWithPath: filepath)
|
||||||
let url = URL(fileURLWithPath: filepath)
|
data = try Data.init(contentsOf: url)
|
||||||
data = try Data.init(contentsOf: url)
|
|
||||||
} else {
|
|
||||||
throw "Can't find file at \(filepath)"
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return (data == nil) ? nil : Data([UInt8](data!))
|
return (data == nil) ? nil : Data([UInt8](data!))
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extension GLTFBuffer {
|
|
||||||
|
|
||||||
static var data_associate_key = "data_associate_key"
|
|
||||||
|
|
||||||
public var data:Data? {
|
|
||||||
get { return objc_getAssociatedObject(self, &GLTFBuffer.data_associate_key) as? Data }
|
|
||||||
set { objc_setAssociatedObject(self, &GLTFBuffer.data_associate_key, newValue, .OBJC_ASSOCIATION_RETAIN) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension GLTFImage {
|
|
||||||
|
|
||||||
static var image_associate_key = "image_associate_key"
|
|
||||||
|
|
||||||
public var image:OSImage? {
|
|
||||||
get { return objc_getAssociatedObject(self, &GLTFImage.image_associate_key) as? OSImage }
|
|
||||||
set { objc_setAssociatedObject(self, &GLTFImage.image_associate_key, newValue, .OBJC_ASSOCIATION_RETAIN) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -344,23 +344,22 @@ public enum GLTF_3D4MCompressedTextureExtensionTarget: Int, RawRepresentable, Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Class template
|
/// Class template
|
||||||
open class GLTF_3D4MCompressedTextureExtension : Codable {
|
open class GLTF_3D4MCompressedTextureExtension: Codable {
|
||||||
/// Compression type.
|
/// Compression type.
|
||||||
public var compression:GLTF_3D4MCompressedTextureExtensionCompression
|
public var compression: GLTF_3D4MCompressedTextureExtensionCompression
|
||||||
|
|
||||||
/// Texture width size in pixels.
|
/// Texture width size in pixels.
|
||||||
public var width:Int
|
public var width: Int
|
||||||
|
|
||||||
/// Texture height size in pixels.
|
/// Texture height size in pixels.
|
||||||
public var height:Int
|
public var height: Int
|
||||||
|
|
||||||
/// Texture index of bufferView used for each level of texture. First source representing level 0. Each next is divide by 2 of previous texture size. For example 0 level is 1024, next is 512 and next 256 ans so on.
|
/// Texture index of bufferView used for each level of texture. First source representing level 0. Each next is divide by 2 of previous texture size. For example 0 level is 1024, next is 512 and next 256 ans so on.
|
||||||
public var sources:[Int]
|
public var sources: [Int]
|
||||||
|
|
||||||
/// Texture 2D target.
|
/// Texture 2D target.
|
||||||
public var target:GLTF_3D4MCompressedTextureExtensionTarget
|
public var target: GLTF_3D4MCompressedTextureExtensionTarget
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case compression
|
case compression
|
||||||
|
@ -370,18 +369,18 @@ open class GLTF_3D4MCompressedTextureExtension : Codable {
|
||||||
case width
|
case width
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(compression c:GLTF_3D4MCompressedTextureExtensionCompression,
|
public init(compression c: GLTF_3D4MCompressedTextureExtensionCompression,
|
||||||
width w:Int,
|
width w: Int,
|
||||||
height h:Int,
|
height h: Int,
|
||||||
sources s:[Int],
|
sources s: [Int],
|
||||||
target t:GLTF_3D4MCompressedTextureExtensionTarget) {
|
target t: GLTF_3D4MCompressedTextureExtensionTarget) {
|
||||||
compression = c
|
compression = c
|
||||||
width = w
|
width = w
|
||||||
height = h
|
height = h
|
||||||
sources = s
|
sources = s
|
||||||
target = t
|
target = t
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
compression = try container.decode(GLTF_3D4MCompressedTextureExtensionCompression.self, forKey: .compression)
|
compression = try container.decode(GLTF_3D4MCompressedTextureExtensionCompression.self, forKey: .compression)
|
||||||
|
|
|
@ -19,7 +19,6 @@ import SceneKit
|
||||||
typealias SCNFloat = CGFloat
|
typealias SCNFloat = CGFloat
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct SCNVector2 {
|
struct SCNVector2 {
|
||||||
public var x: SCNFloat
|
public var x: SCNFloat
|
||||||
public var y: SCNFloat
|
public var y: SCNFloat
|
||||||
|
@ -29,15 +28,31 @@ struct SCNVector2 {
|
||||||
}
|
}
|
||||||
public init(x: SCNFloat, y: SCNFloat) {
|
public init(x: SCNFloat, y: SCNFloat) {
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GLTFError: LocalizedError, CustomDebugStringConvertible {
|
||||||
|
var title: String?
|
||||||
|
var code: Int
|
||||||
|
var errorDescription: String? { return _description }
|
||||||
|
var failureReason: String? { return _description }
|
||||||
|
|
||||||
extension String: Error {}
|
private var _description: String
|
||||||
|
|
||||||
|
init(_ description: String) {
|
||||||
|
self.title = "GLTF Error"
|
||||||
|
self._description = description
|
||||||
|
self.code = -1000000
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugDescription: String {
|
||||||
|
return self.title! + ": " + self._description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension SCNMatrix4 {
|
extension SCNMatrix4 {
|
||||||
init(array:[Double]) {
|
init(array: [Double]) {
|
||||||
self.init()
|
self.init()
|
||||||
self.m11 = SCNFloat(array[0])
|
self.m11 = SCNFloat(array[0])
|
||||||
self.m12 = SCNFloat(array[1])
|
self.m12 = SCNFloat(array[1])
|
||||||
|
@ -66,7 +81,7 @@ extension String {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//: ### Base64 decoding a string
|
//: ### Base64 decoding a string
|
||||||
func base64Decoded() -> Data? {
|
func base64Decoded() -> Data? {
|
||||||
if self.contains("base64") {
|
if self.contains("base64") {
|
||||||
|
@ -81,7 +96,7 @@ extension String {
|
||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
func array<Type>() -> [Type] {
|
func array<Type>() -> [Type] {
|
||||||
return withUnsafeBytes { (unsafeBufferPointer:UnsafeRawBufferPointer) -> [Type] in
|
return withUnsafeBytes { (unsafeBufferPointer: UnsafeRawBufferPointer) -> [Type] in
|
||||||
Array(UnsafeBufferPointer<Type>(start: unsafeBufferPointer.bindMemory(to: Type.self).baseAddress, count: self.count/MemoryLayout<Type>.size))
|
Array(UnsafeBufferPointer<Type>(start: unsafeBufferPointer.bindMemory(to: Type.self).baseAddress, count: self.count/MemoryLayout<Type>.size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,22 +106,21 @@ extension Data {
|
||||||
// https://github.com/magicien/GLTFSceneKit/blob/master/Source/Common/GLTFFunctions.swift
|
// https://github.com/magicien/GLTFSceneKit/blob/master/Source/Common/GLTFFunctions.swift
|
||||||
|
|
||||||
extension OSImage {
|
extension OSImage {
|
||||||
|
|
||||||
func channels() throws -> [OSImage] {
|
func channels() throws -> [OSImage] {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
var rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
|
var rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
|
||||||
guard let cgImage = self.cgImage(forProposedRect: &rect, context: nil, hints: nil) else {
|
guard let cgImage = self.cgImage(forProposedRect: &rect, context: nil, hints: nil) else {
|
||||||
throw "Failed to create CGImage"
|
throw GLTFError("Failed to create CGImage")
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
guard let cgImage = self.cgImage else {
|
guard let cgImage = self.cgImage else {
|
||||||
throw "failed to create CGImage"
|
throw GLTFError("failed to create CGImage")
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return try channels(from: cgImage)
|
return try channels(from: cgImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func channels(from image: CGImage) throws -> [OSImage] {
|
func channels(from image: CGImage) throws -> [OSImage] {
|
||||||
let w = image.width
|
let w = image.width
|
||||||
let h = image.height
|
let h = image.height
|
||||||
|
@ -118,29 +132,28 @@ extension OSImage {
|
||||||
let srcDataSize = w * h * srcBytesPerPixel
|
let srcDataSize = w * h * srcBytesPerPixel
|
||||||
let rawPtr: UnsafeMutableRawPointer = malloc(srcDataSize)
|
let rawPtr: UnsafeMutableRawPointer = malloc(srcDataSize)
|
||||||
defer { free(rawPtr) }
|
defer { free(rawPtr) }
|
||||||
|
|
||||||
|
|
||||||
guard let context = CGContext(data: rawPtr, width: w, height: h, bitsPerComponent: bitsPerComponent, bytesPerRow: srcBytesPerPixel * w, space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) else {
|
guard let context = CGContext(data: rawPtr, width: w, height: h, bitsPerComponent: bitsPerComponent, bytesPerRow: srcBytesPerPixel * w, space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) else {
|
||||||
throw "Failed to make textures"
|
throw GLTFError("Failed to make textures")
|
||||||
}
|
}
|
||||||
context.draw(image, in: rect)
|
context.draw(image, in: rect)
|
||||||
|
|
||||||
let ptr = rawPtr.bindMemory(to: UInt8.self, capacity: srcDataSize)
|
let ptr = rawPtr.bindMemory(to: UInt8.self, capacity: srcDataSize)
|
||||||
|
|
||||||
/// create data for each component
|
/// create data for each component
|
||||||
let dstBytesPerPixel = bitsPerComponent / 8
|
let dstBytesPerPixel = bitsPerComponent / 8
|
||||||
let dstDataSize = w * h * dstBytesPerPixel
|
let dstDataSize = w * h * dstBytesPerPixel
|
||||||
|
|
||||||
var componentsRaw:[UnsafeMutableRawPointer] = [UnsafeMutableRawPointer]()
|
var componentsRaw: [UnsafeMutableRawPointer] = [UnsafeMutableRawPointer]()
|
||||||
var componentsPtr = [Any]()
|
var componentsPtr = [Any]()
|
||||||
|
|
||||||
for _ in 0..<componentsPerPixel {
|
for _ in 0..<componentsPerPixel {
|
||||||
let componentRawPtr: UnsafeMutableRawPointer = malloc(dstDataSize)
|
let componentRawPtr: UnsafeMutableRawPointer = malloc(dstDataSize)
|
||||||
let componentPtr = componentRawPtr.bindMemory(to: UInt8.self, capacity: dstDataSize)
|
let componentPtr = componentRawPtr.bindMemory(to: UInt8.self, capacity: dstDataSize)
|
||||||
componentsRaw.append(componentRawPtr)
|
componentsRaw.append(componentRawPtr)
|
||||||
componentsPtr.append(componentPtr)
|
componentsPtr.append(componentPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
var srcPos = 0
|
var srcPos = 0
|
||||||
var dstPos = 0
|
var dstPos = 0
|
||||||
for _ in 0..<(w * h) {
|
for _ in 0..<(w * h) {
|
||||||
|
@ -154,18 +167,18 @@ extension OSImage {
|
||||||
dstPos += dstBytesPerPixel
|
dstPos += dstBytesPerPixel
|
||||||
}
|
}
|
||||||
let dstColorSpace = CGColorSpaceCreateDeviceGray()
|
let dstColorSpace = CGColorSpaceCreateDeviceGray()
|
||||||
|
|
||||||
var images = [OSImage]()
|
var images = [OSImage]()
|
||||||
|
|
||||||
for i in 0..<componentsPerPixel {
|
for i in 0..<componentsPerPixel {
|
||||||
let componentPtr = componentsPtr[i] as! UnsafeMutablePointer<UInt8>
|
let componentPtr = componentsPtr[i] as! UnsafeMutablePointer<UInt8>
|
||||||
|
|
||||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
|
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
|
||||||
guard let imageData = CFDataCreate(nil, componentPtr, dstDataSize) else {
|
guard let imageData = CFDataCreate(nil, componentPtr, dstDataSize) else {
|
||||||
throw "Failed to create Data"
|
throw GLTFError("Failed to create Data")
|
||||||
}
|
}
|
||||||
guard let provider = CGDataProvider(data: imageData) else {
|
guard let provider = CGDataProvider(data: imageData) else {
|
||||||
throw "Failed to create Provider"
|
throw GLTFError("Failed to create Provider")
|
||||||
}
|
}
|
||||||
guard let imageChannel = CGImage(
|
guard let imageChannel = CGImage(
|
||||||
width: w, height: h,
|
width: w, height: h,
|
||||||
|
@ -178,7 +191,7 @@ extension OSImage {
|
||||||
decode: nil,
|
decode: nil,
|
||||||
shouldInterpolate: false,
|
shouldInterpolate: false,
|
||||||
intent: CGColorRenderingIntent.defaultIntent) else {
|
intent: CGColorRenderingIntent.defaultIntent) else {
|
||||||
throw "Failed to create CGImage"
|
throw GLTFError("Failed to create CGImage")
|
||||||
}
|
}
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
let image_ = OSImage(cgImage: imageChannel, size: NSSize.init(width: w, height: h))
|
let image_ = OSImage(cgImage: imageChannel, size: NSSize.init(width: w, height: h))
|
||||||
|
@ -192,13 +205,13 @@ extension OSImage {
|
||||||
}
|
}
|
||||||
componentsRaw.removeAll()
|
componentsRaw.removeAll()
|
||||||
componentsPtr.removeAll()
|
componentsPtr.removeAll()
|
||||||
|
|
||||||
return images
|
return images
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
extension MTLPixelFormat {
|
extension MTLPixelFormat {
|
||||||
public func hasAlpha() -> Bool {
|
public func hasAlpha() -> Bool {
|
||||||
switch self {
|
switch self {
|
||||||
|
@ -214,11 +227,16 @@ extension MTLPixelFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
extension SCNMaterial {
|
extension SCNMaterial {
|
||||||
public func hasAlpha() -> Bool {
|
public func hasAlpha() -> Bool {
|
||||||
return (diffuse.contents as? MTLTexture)?.pixelFormat.hasAlpha() ?? false
|
return (diffuse.contents as? MTLTexture)?.pixelFormat.hasAlpha() ?? false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
|
class MetalDevice {
|
||||||
|
static var device = {
|
||||||
|
return MTLCreateSystemDefaultDevice()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
|
@ -10,22 +10,27 @@ import SceneKit
|
||||||
import os
|
import os
|
||||||
|
|
||||||
// Texture load status
|
// Texture load status
|
||||||
enum TextureStatus:Int {
|
enum TextureStatus: Int {
|
||||||
case no = 0
|
case no = 0
|
||||||
case loading
|
case loading
|
||||||
case loaded
|
case loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protocol TextureLoaderDelegate: class {
|
||||||
|
var renderer: SCNSceneRenderer? { get }
|
||||||
|
func texturesLoaded()
|
||||||
|
}
|
||||||
|
|
||||||
class TextureAssociator {
|
class TextureAssociator {
|
||||||
var status:TextureStatus = .no
|
var status: TextureStatus = .no
|
||||||
|
|
||||||
private var content_:Any?
|
private var content_: Any? = OSColor.white
|
||||||
var content:Any? {
|
var content: Any? {
|
||||||
set {
|
set {
|
||||||
content_ = newValue
|
content_ = newValue
|
||||||
if (newValue != nil) {
|
if newValue != nil {
|
||||||
self.status = .loaded
|
self.status = .loaded
|
||||||
|
|
||||||
for property in associatedProperties {
|
for property in associatedProperties {
|
||||||
property.contents = self.content_
|
property.contents = self.content_
|
||||||
}
|
}
|
||||||
|
@ -35,166 +40,166 @@ class TextureAssociator {
|
||||||
return content_
|
return content_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var associatedProperties = Set<SCNMaterialProperty>()
|
lazy var associatedProperties = Set<SCNMaterialProperty>()
|
||||||
|
|
||||||
func associate(property:SCNMaterialProperty) {
|
func associate(property: SCNMaterialProperty) {
|
||||||
associatedProperties.insert(property)
|
associatedProperties.insert(property)
|
||||||
property.contents = self.content
|
property.contents = self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
associatedProperties.removeAll()
|
associatedProperties.removeAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(OSX 10.12, iOS 10.0, *)
|
||||||
class TextureStorageManager {
|
class TextureStorageManager {
|
||||||
|
|
||||||
static let manager = TextureStorageManager()
|
static let manager = TextureStorageManager()
|
||||||
|
|
||||||
private var worker = DispatchQueue(label: "textures_loader")
|
private var worker = DispatchQueue(label: "textures_loader")
|
||||||
private var groups:[Int : DispatchGroup] = [Int : DispatchGroup]()
|
private var groups: [Int: DispatchGroup] = [Int: DispatchGroup]()
|
||||||
|
|
||||||
lazy private var _associators:[Int : [Int : TextureAssociator]] = [Int : [Int : TextureAssociator]]()
|
lazy private var _associators: [Int: [Int: TextureAssociator]] = [Int: [Int: TextureAssociator]]()
|
||||||
|
|
||||||
func clear(gltf: GLTF) {
|
func clear(gltf: GLTF) {
|
||||||
let hash = gltf.hashValue
|
let hash = gltf.hashValue
|
||||||
self.groups[hash] = nil
|
self.groups[hash] = nil
|
||||||
self._associators[hash] = nil
|
self._associators[hash] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func textureAssociator(gltf: GLTF, at index: Int) -> TextureAssociator {
|
func textureAssociator(gltf: GLTF, at index: Int) -> TextureAssociator {
|
||||||
let hash = gltf.hashValue
|
let hash = gltf.hashValue
|
||||||
|
|
||||||
if self._associators[hash] == nil {
|
if self._associators[hash] == nil {
|
||||||
self._associators[hash] = [Int : TextureAssociator]()
|
self._associators[hash] = [Int: TextureAssociator]()
|
||||||
}
|
}
|
||||||
var tStatus = (self._associators[hash])![index]
|
var tStatus = (self._associators[hash])![index]
|
||||||
if tStatus == nil {
|
if tStatus == nil {
|
||||||
tStatus = TextureAssociator()
|
tStatus = TextureAssociator()
|
||||||
self._associators[hash]![index] = tStatus
|
self._associators[hash]![index] = tStatus
|
||||||
}
|
}
|
||||||
return tStatus!
|
return tStatus!
|
||||||
}
|
}
|
||||||
|
|
||||||
func group(gltf: GLTF, _ enter:Bool = false) -> DispatchGroup {
|
|
||||||
let index = gltf.hashValue
|
|
||||||
var group:DispatchGroup?
|
|
||||||
|
|
||||||
group = groups[index]
|
func group(gltf: GLTF, delegate: TextureLoaderDelegate, _ enter: Bool = false) -> DispatchGroup {
|
||||||
|
let index = gltf.hashValue
|
||||||
|
var group: DispatchGroup? = groups[index]
|
||||||
|
|
||||||
if group == nil {
|
if group == nil {
|
||||||
groups[index] = DispatchGroup()
|
groups[index] = DispatchGroup()
|
||||||
group = groups[index]
|
group = groups[index]
|
||||||
group?.enter()
|
group?.enter()
|
||||||
|
|
||||||
let startLoadTextures = Date()
|
let startLoadTextures = Date()
|
||||||
|
|
||||||
// notify when all textures are loaded
|
// notify when all textures are loaded
|
||||||
// this is last operation.
|
// this is last operation.
|
||||||
group?.notify(queue: DispatchQueue.main) {
|
group?.notify(queue: DispatchQueue.global(qos: .userInteractive)) {
|
||||||
|
|
||||||
os_log("textures loaded %d ms", log: log_scenekit, type: .debug, Int(startLoadTextures.timeIntervalSinceNow * -1000))
|
os_log("textures loaded %d ms", log: log_scenekit, type: .debug, Int(startLoadTextures.timeIntervalSinceNow * -1000))
|
||||||
|
|
||||||
gltf._texturesLoaded()
|
delegate.texturesLoaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if enter {
|
} else if enter {
|
||||||
group?.enter()
|
group?.enter()
|
||||||
}
|
}
|
||||||
return group!
|
return group!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Load texture by index.
|
/// Load texture by index.
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - index: index of GLTFTexture in textures
|
/// - index: index of GLTFTexture in textures
|
||||||
/// - property: material's property
|
/// - property: material's property
|
||||||
static func loadTexture(gltf: GLTF, index: Int, property: SCNMaterialProperty, callback: ((Any?)-> Void)? = nil) {
|
static func loadTexture(gltf: GLTF, delegate: TextureLoaderDelegate, index: Int, property: SCNMaterialProperty) {
|
||||||
self.manager._loadTexture(gltf: gltf, index: index, property: property, callback: callback)
|
self.manager._loadTexture(gltf: gltf, delegate: delegate, index: index, property: property)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _loadTexture(gltf: GLTF, index: Int, property: SCNMaterialProperty, callback: ((Any?)-> Void)? = nil) {
|
fileprivate func _loadTexture(gltf: GLTF, delegate: TextureLoaderDelegate, index: Int, property: SCNMaterialProperty) {
|
||||||
guard let texture = gltf.textures?[index] else {
|
guard let texture = gltf.textures?[index] else {
|
||||||
print("Failed to find texture")
|
print("Failed to find texture")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let group = self.group(gltf: gltf, delegate: delegate, true)
|
||||||
|
|
||||||
worker.async {
|
worker.async {
|
||||||
let tStatus = self.textureAssociator(gltf:gltf, at:index)
|
let tStatus = self.textureAssociator(gltf: gltf, at: index)
|
||||||
|
|
||||||
if tStatus.status == .no {
|
if tStatus.status == .no {
|
||||||
tStatus.status = .loading
|
tStatus.status = .loading
|
||||||
tStatus.associate(property: property)
|
tStatus.associate(property: property)
|
||||||
|
|
||||||
gltf.loadSampler(sampler:texture.sampler, property: property)
|
gltf.loadSampler(sampler: texture.sampler, property: property)
|
||||||
|
|
||||||
let device = MTLCreateSystemDefaultDevice()
|
let device = MetalDevice.device
|
||||||
let metalOn = (gltf.renderer?.renderingAPI == .metal || device != nil)
|
let metalOn = (delegate.renderer?.renderingAPI == .metal || device != nil)
|
||||||
|
|
||||||
if let descriptor = texture.extensions?[compressedTextureExtensionKey] as? GLTF_3D4MCompressedTextureExtension, metalOn {
|
if let descriptor = texture.extensions?[compressedTextureExtensionKey] as? GLTF_3D4MCompressedTextureExtension, metalOn {
|
||||||
|
|
||||||
let group = self.group(gltf:gltf, true)
|
|
||||||
|
|
||||||
// load first level mipmap as texture
|
// load first level mipmap as texture
|
||||||
gltf.loadCompressedTexture(descriptor:descriptor, loadLevel: .first) { cTexture, error in
|
gltf.loadCompressedTexture(descriptor: descriptor, loadLevel: .first) { cTexture, error in
|
||||||
|
tStatus.content = cTexture
|
||||||
|
|
||||||
if gltf.isCancelled {
|
if gltf.isCancelled {
|
||||||
group.leave()
|
group.leave()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != nil) {
|
if error != nil {
|
||||||
print("Failed to load comressed texture \(error.debugDescription). Fallback on image source.")
|
print("Failed to load comressed texture \(error.debugDescription). Fallback on image source.")
|
||||||
self._loadImageTexture(gltf, texture, tStatus, callback)
|
self._loadImageTexture(gltf, delegate, texture, tStatus)
|
||||||
group.leave()
|
group.leave()
|
||||||
} else {
|
} else {
|
||||||
tStatus.content = cTexture as Any?
|
tStatus.content = cTexture
|
||||||
callback?(cTexture)
|
|
||||||
|
|
||||||
// load all levels
|
// load all levels
|
||||||
gltf.loadCompressedTexture(descriptor:descriptor, loadLevel: .last) { (cTexture2, error) in
|
gltf.loadCompressedTexture(descriptor: descriptor, loadLevel: .last) { (cTexture2, error) in
|
||||||
|
|
||||||
if gltf.isCancelled {
|
if gltf.isCancelled {
|
||||||
group.leave()
|
group.leave()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != nil) {
|
if error != nil {
|
||||||
print("Failed to load comressed texture \(error.debugDescription). Fallback on image source.")
|
print("Failed to load comressed texture \(error.debugDescription). Fallback on image source.")
|
||||||
self._loadImageTexture(gltf, texture, tStatus, callback)
|
self._loadImageTexture(gltf, delegate, texture, tStatus)
|
||||||
} else {
|
} else {
|
||||||
tStatus.content = cTexture2 as Any?
|
tStatus.content = cTexture2
|
||||||
callback?(cTexture2)
|
|
||||||
}
|
}
|
||||||
group.leave()
|
group.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self._loadImageTexture(gltf, texture, tStatus, callback)
|
|
||||||
|
self._loadImageTexture(gltf, delegate, texture, tStatus)
|
||||||
|
group.leave()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
tStatus.associate(property: property)
|
tStatus.associate(property: property)
|
||||||
|
group.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// load original image source png or jpg
|
/// load original image source png or jpg
|
||||||
fileprivate func _loadImageTexture(_ gltf: GLTF, _ texture: GLTFTexture, _ tStatus: TextureAssociator, _ callback: ((Any?)-> Void)? = nil) {
|
fileprivate func _loadImageTexture(_ gltf: GLTF, _ delegate: TextureLoaderDelegate, _ texture: GLTFTexture, _ tStatus: TextureAssociator) {
|
||||||
self.worker.async {
|
self.worker.async {
|
||||||
if gltf.isCancelled {
|
if gltf.isCancelled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let group = self.group(gltf:gltf, true)
|
let group = self.group(gltf: gltf, delegate: delegate, true)
|
||||||
|
|
||||||
if let imageSourceIndex = texture.source {
|
if let imageSourceIndex = texture.source {
|
||||||
if let gltf_image = gltf.images?[imageSourceIndex] {
|
if let gltf_image = gltf.images?[imageSourceIndex] {
|
||||||
|
|
||||||
gltf.loader.load(gltf:gltf, resource: gltf_image) { resource, error in
|
gltf.loader.load(gltf: gltf, resource: gltf_image) { resource, _ in
|
||||||
if resource.image != nil {
|
if resource.image != nil {
|
||||||
tStatus.content = gltf._compress(image:resource.image!)
|
tStatus.content = gltf._compress(image: resource.image!)
|
||||||
callback?(tStatus.content)
|
|
||||||
}
|
}
|
||||||
group.leave()
|
group.leave()
|
||||||
}
|
}
|
||||||
|
@ -203,4 +208,3 @@ class TextureStorageManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,5 @@ import XCTest
|
||||||
@testable import gltf_scenekitTests
|
@testable import gltf_scenekitTests
|
||||||
|
|
||||||
XCTMain([
|
XCTMain([
|
||||||
testCase(gltf_scenekitTests.allTests),
|
testCase(gltf_scenekitTests.allTests)
|
||||||
])
|
])
|
||||||
|
|
|
@ -2,37 +2,109 @@ import XCTest
|
||||||
import SceneKit
|
import SceneKit
|
||||||
@testable import glTFSceneKit
|
@testable import glTFSceneKit
|
||||||
|
|
||||||
let jsonString = """
|
class LoadingDelegate : SceneLoadingDelegate {
|
||||||
{ "accessors": [ ], "asset": { "copyright": "3D4Medical LLC", "generator": "Comanche", "version": "2.0" }, "bufferViews": [ { "buffer": 0, "byteLength": 118766, "byteStride": 44, "target": 34962 }], "buffers": [ { "byteLength": 118766, "uri": "draco/file.bin" }], "extensionsRequired": [ "KHR_draco_mesh_compression"], "extensionsUsed": [ "KHR_draco_mesh_compression"], "images": [ { "mimeType": "image/png", "uri": "png/texture.png" }, { "mimeType": "image/png", "uri": "png/texture.png" }], "materials": [ { "alphaMode": "OPAQUE", "name": "", "normalTexture": { "index": 1 }, "pbrMetallicRoughness": { "baseColorFactor": [ 0.725279, 0.700000, 0.734000, 1.000000], "baseColorTexture": { "index": 0 }, "metallicFactor": 0.000000, "roughnessFactor": 0.800000 } }], "meshes": [ { "primitives": [ { "attributes": { }, "extensions": { "KHR_draco_mesh_compression" : { "attributes": { "TEXCOORD_0" : 2, "NORMAL" : 1, "TANGENT" : 3, "POSITION" : 0}, "bufferView": 0 }}, "material": 0, "mode": 5 }] }], "nodes": [ { "mesh": 0 }], "samplers": [ { "magFilter": 9729, "minFilter": 9729, "wrapS": 10497, "wrapT": 10497 }], "scene": 0, "scenes": [ { "nodes": [ 0] }], "textures": [ { "sampler": 0, "source": 0 }, { "sampler": 0, "source": 1 }] }
|
|
||||||
"""
|
}
|
||||||
|
|
||||||
|
|
||||||
class gltf_scenekitTests: XCTestCase {
|
class gltf_scenekitTests: XCTestCase {
|
||||||
func testGLTFinit() {
|
|
||||||
|
let view = SCNView()
|
||||||
let view = SCNView()
|
let scene = SCNScene()
|
||||||
|
let loadingDelegate = LoadingDelegate()
|
||||||
|
let decoder = JSONDecoder()
|
||||||
let jsonData = jsonString.data(using: .utf8)
|
|
||||||
let decoder = JSONDecoder()
|
override func setUp() {
|
||||||
|
view.scene = scene
|
||||||
self.measure {
|
|
||||||
let glTF = try? decoder.decode(GLTF.self, from: jsonData!)
|
|
||||||
|
|
||||||
_ = glTF?.convert(renderer:view, directoryPath:nil, multiThread:false, geometryCompletionHandler: {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let jsonDataArray = jsonData!.array() as [UInt8]
|
|
||||||
|
|
||||||
// XCTAssert(glTF != nil)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let jsonStringSimple = """
|
||||||
|
{ "accessors": [ ], "asset": { "copyright": "3D4Medical LLC", "generator": "Comanche", "version": "2.0" }, "bufferViews": [ { "buffer": 0, "byteLength": 118766, "byteStride": 44, "target": 34962 }], "buffers": [ { "byteLength": 118766, "uri": "draco/file.bin" }], "extensionsRequired": [ ], "extensionsUsed": [], "images": [ { "mimeType": "image/png", "uri": "png/texture.png" }, { "mimeType": "image/png", "uri": "png/texture.png" }], "materials": [ { "alphaMode": "OPAQUE", "name": "", "normalTexture": { "index": 1 }, "pbrMetallicRoughness": { "baseColorFactor": [ 0.725279, 0.700000, 0.734000, 1.000000], "baseColorTexture": { "index": 0 }, "metallicFactor": 0.000000, "roughnessFactor": 0.800000 } }], "meshes": [ { "primitives": [ { "attributes": { }, "extensions": { "KHR_draco_mesh_compression" : { "attributes": { "TEXCOORD_0" : 2, "NORMAL" : 1, "TANGENT" : 3, "POSITION" : 0}, "bufferView": 0 }}, "material": 0, "mode": 5 }] }], "nodes": [ { "mesh": 0 }], "samplers": [ { "magFilter": 9729, "minFilter": 9729, "wrapS": 10497, "wrapT": 10497 }], "scene": 0, "scenes": [ { "nodes": [ 0] }], "textures": [ { "sampler": 0, "source": 0 }, { "sampler": 0, "source": 1 }] }
|
||||||
|
"""
|
||||||
|
func testSimpleGLTFinit() {
|
||||||
|
|
||||||
|
let jsonData = jsonStringSimple.data(using: .utf8)
|
||||||
|
|
||||||
static var allTests = [
|
let expectationGeometry = self.expectation(description: "Geometry")
|
||||||
("testGLTFinit", testGLTFinit),
|
let expectationCompleted = self.expectation(description: "Completed")
|
||||||
]
|
|
||||||
|
if let glTF = try? decoder.decode(GLTF.self, from: jsonData!) {
|
||||||
|
let converter = GLTFConverter(glTF: glTF)
|
||||||
|
converter.delegate = loadingDelegate
|
||||||
|
let scene = converter.convert(to: view.scene!, geometryCompletionHandler: {
|
||||||
|
print("Geometry loaded")
|
||||||
|
expectationGeometry.fulfill()
|
||||||
|
}) { (error) in
|
||||||
|
print("Completed with \((error != nil) ? "\(error.debugDescription)" : "no errors")")
|
||||||
|
expectationCompleted.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForExpectations(timeout: 5, handler: nil)
|
||||||
|
|
||||||
|
XCTAssert(scene != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test where it's failed on extension
|
||||||
|
let jsonStringExt = """
|
||||||
|
{ "accessors": [ ], "asset": { "copyright": "3D4Medical LLC", "generator": "Comanche", "version": "2.0" }, "bufferViews": [ { "buffer": 0, "byteLength": 118766, "byteStride": 44, "target": 34962 }], "buffers": [ { "byteLength": 118766, "uri": "draco/file.bin" }], "extensionsRequired": [ "KHR_draco_mesh_compression"], "extensionsUsed": [ "KHR_draco_mesh_compression"], "images": [ { "mimeType": "image/png", "uri": "png/texture.png" }, { "mimeType": "image/png", "uri": "png/texture.png" }], "materials": [ { "alphaMode": "OPAQUE", "name": "", "normalTexture": { "index": 1 }, "pbrMetallicRoughness": { "baseColorFactor": [ 0.725279, 0.700000, 0.734000, 1.000000], "baseColorTexture": { "index": 0 }, "metallicFactor": 0.000000, "roughnessFactor": 0.800000 } }], "meshes": [ { "primitives": [ { "attributes": { }, "extensions": { "KHR_draco_mesh_compression" : { "attributes": { "TEXCOORD_0" : 2, "NORMAL" : 1, "TANGENT" : 3, "POSITION" : 0}, "bufferView": 0 }}, "material": 0, "mode": 5 }] }], "nodes": [ { "mesh": 0 }], "samplers": [ { "magFilter": 9729, "minFilter": 9729, "wrapS": 10497, "wrapT": 10497 }], "scene": 0, "scenes": [ { "nodes": [ 0] }], "textures": [ { "sampler": 0, "source": 0 }, { "sampler": 0, "source": 1 }] }
|
||||||
|
"""
|
||||||
|
func testGLTFfailure() {
|
||||||
|
|
||||||
|
let expectationGeometry = self.expectation(description: "Geometry")
|
||||||
|
let expectationCompleted = self.expectation(description: "Completed")
|
||||||
|
|
||||||
|
let jsonData = jsonStringExt.data(using: .utf8)
|
||||||
|
|
||||||
|
if let glTF = try? decoder.decode(GLTF.self, from: jsonData!) {
|
||||||
|
let converter = GLTFConverter(glTF: glTF)
|
||||||
|
converter.delegate = loadingDelegate
|
||||||
|
let scene = converter.convert(to: view.scene!, geometryCompletionHandler: {
|
||||||
|
print("Geometry loaded")
|
||||||
|
expectationGeometry.fulfill()
|
||||||
|
}) { (error) in
|
||||||
|
print("Completed with \((error != nil) ? "\(error.debugDescription)" : "no errors")")
|
||||||
|
XCTAssert(error != nil) // expecting error here
|
||||||
|
expectationGeometry.fulfill()
|
||||||
|
expectationCompleted.fulfill()
|
||||||
|
}
|
||||||
|
waitForExpectations(timeout: 5, handler: nil)
|
||||||
|
// expecting no scene here
|
||||||
|
XCTAssert(scene == nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let box_gltf = """
|
||||||
|
{"asset":{"generator":"COLLADA2GLTF","version":"2.0"},"scene":0,"scenes":[{"nodes":[0]}],"nodes":[{"children":[1],"matrix":[1,0,0,0,0,0,-1,0,0,1,0,0,0,0,0,1]},{"mesh":0}],"meshes":[{"primitives":[{"attributes":{"NORMAL":1,"POSITION":2},"indices":0,"mode":4,"material":0}],"name":"Mesh"}],"accessors":[{"bufferView":0,"byteOffset":0,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":1,"byteOffset":288,"componentType":5126,"count":24,"max":[0.5,0.5,0.5],"min":[-0.5,-0.5,-0.5],"type":"VEC3"}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[0.800000011920929,0,0,1],"metallicFactor":0},"name":"Red"}],"bufferViews":[{"buffer":0,"byteOffset":576,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":0,"byteLength":576,"byteStride":12,"target":34962}],"buffers":[{"byteLength":648,"uri":"data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA"}]}
|
||||||
|
"""
|
||||||
|
func testGLTFBox() {
|
||||||
|
|
||||||
|
let expectationGeometry = self.expectation(description: "Geometry")
|
||||||
|
let expectationCompleted = self.expectation(description: "Completed")
|
||||||
|
|
||||||
|
let jsonData = box_gltf.data(using: .utf8)
|
||||||
|
|
||||||
|
if let glTF = try? decoder.decode(GLTF.self, from: jsonData!) {
|
||||||
|
let converter = GLTFConverter(glTF: glTF)
|
||||||
|
converter.delegate = loadingDelegate
|
||||||
|
let scene = converter.convert(to: view.scene!, geometryCompletionHandler: {
|
||||||
|
print("Geometry loaded")
|
||||||
|
expectationGeometry.fulfill()
|
||||||
|
}) { (error) in
|
||||||
|
print("Completed with \((error != nil) ? "\(error.debugDescription)" : "no errors")")
|
||||||
|
XCTAssert(error == nil)
|
||||||
|
expectationCompleted.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForExpectations(timeout: 5, handler: nil)
|
||||||
|
|
||||||
|
XCTAssert(scene != nil)
|
||||||
|
let node = scene?.rootNode.childNodes.first?.childNodes.first?.childNodes.first!
|
||||||
|
let geometry = node?.geometry
|
||||||
|
|
||||||
|
XCTAssert(geometry != nil)
|
||||||
|
|
||||||
|
// expecting 24 elements
|
||||||
|
XCTAssert(geometry!.sources.first!.vectorCount == 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
49A51D192345E8BB002B5D24 /* GLTFConverter+Geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A51D182345E8BB002B5D24 /* GLTFConverter+Geometry.swift */; };
|
||||||
|
49A51D1A2345E8BB002B5D24 /* GLTFConverter+Geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A51D182345E8BB002B5D24 /* GLTFConverter+Geometry.swift */; };
|
||||||
|
49A51D1B2345E8BB002B5D24 /* GLTFConverter+Geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A51D182345E8BB002B5D24 /* GLTFConverter+Geometry.swift */; };
|
||||||
D2157142204035E3009E9D16 /* JSONCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D215713A20402611009E9D16 /* JSONCodingKeys.swift */; };
|
D2157142204035E3009E9D16 /* JSONCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D215713A20402611009E9D16 /* JSONCodingKeys.swift */; };
|
||||||
D2180CDF208745A6005353CF /* GLTF+Draco.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2180CDD2087457D005353CF /* GLTF+Draco.swift */; };
|
|
||||||
D2180CE0208745A7005353CF /* GLTF+Draco.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2180CDD2087457D005353CF /* GLTF+Draco.swift */; };
|
|
||||||
D256CD0620B2B9F1002E841E /* glTFSceneKit-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */; };
|
D256CD0620B2B9F1002E841E /* glTFSceneKit-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */; };
|
||||||
D256CD0720B2B9F2002E841E /* glTFSceneKit-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */; };
|
D256CD0720B2B9F2002E841E /* glTFSceneKit-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */; };
|
||||||
D2750CED2077B7AC00F6198D /* GLTF+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* GLTF+SceneKit.swift */; };
|
D2750CED2077B7AC00F6198D /* GLTF+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* GLTF+SceneKit.swift */; };
|
||||||
|
@ -35,7 +36,6 @@
|
||||||
D2750D012077B7AC00F6198D /* GLTFMaterialOcclusionTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* GLTFMaterialOcclusionTextureInfo.swift */; };
|
D2750D012077B7AC00F6198D /* GLTFMaterialOcclusionTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* GLTFMaterialOcclusionTextureInfo.swift */; };
|
||||||
D2750D022077B7AC00F6198D /* GLTFMaterialPBRMetallicRoughness.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* GLTFMaterialPBRMetallicRoughness.swift */; };
|
D2750D022077B7AC00F6198D /* GLTFMaterialPBRMetallicRoughness.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* GLTFMaterialPBRMetallicRoughness.swift */; };
|
||||||
D2750D032077B7AC00F6198D /* GLTFMesh.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* GLTFMesh.swift */; };
|
D2750D032077B7AC00F6198D /* GLTFMesh.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* GLTFMesh.swift */; };
|
||||||
D2750D042077B7AC00F6198D /* GLTFKHRDracoMeshCompressionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27BDF82203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift */; };
|
|
||||||
D2750D052077B7AC00F6198D /* GLTFMeshPrimitive.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* GLTFMeshPrimitive.swift */; };
|
D2750D052077B7AC00F6198D /* GLTFMeshPrimitive.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* GLTFMeshPrimitive.swift */; };
|
||||||
D2750D062077B7AC00F6198D /* GLTFNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* GLTFNode.swift */; };
|
D2750D062077B7AC00F6198D /* GLTFNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* GLTFNode.swift */; };
|
||||||
D2750D072077B7AC00F6198D /* JSONCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D215713A20402611009E9D16 /* JSONCodingKeys.swift */; };
|
D2750D072077B7AC00F6198D /* JSONCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D215713A20402611009E9D16 /* JSONCodingKeys.swift */; };
|
||||||
|
@ -45,22 +45,17 @@
|
||||||
D2750D0B2077B7AC00F6198D /* GLTFTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_37 /* GLTFTexture.swift */; };
|
D2750D0B2077B7AC00F6198D /* GLTFTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_37 /* GLTFTexture.swift */; };
|
||||||
D2750D0C2077B7AC00F6198D /* GLTFTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* GLTFTextureInfo.swift */; };
|
D2750D0C2077B7AC00F6198D /* GLTFTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* GLTFTextureInfo.swift */; };
|
||||||
D2750D0D2077B7AC00F6198D /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_39 /* Helper.swift */; };
|
D2750D0D2077B7AC00F6198D /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_39 /* Helper.swift */; };
|
||||||
D27BDF83203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27BDF82203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift */; };
|
|
||||||
D287556D2077CB16009B7FA9 /* GLTF+CompressedTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */; };
|
D287556D2077CB16009B7FA9 /* GLTF+CompressedTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */; };
|
||||||
D287556E2077CB1B009B7FA9 /* GLTF+CompressedTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */; };
|
D287556E2077CB1B009B7FA9 /* GLTF+CompressedTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */; };
|
||||||
D287E3F5209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */; };
|
D287E3F5209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */; };
|
||||||
D287E3F6209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */; };
|
D287E3F6209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */; };
|
||||||
D2A67C0020ADB91B007523AF /* Draco.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A67BFF20ADB91B007523AF /* Draco.swift */; };
|
|
||||||
D2A67C0120ADB91B007523AF /* Draco.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A67BFF20ADB91B007523AF /* Draco.swift */; };
|
|
||||||
D2A67C0320ADB92F007523AF /* libdraco.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2A67C0220ADB92F007523AF /* libdraco.a */; };
|
|
||||||
D2A67C0520ADB93E007523AF /* libdraco_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2A67C0420ADB93E007523AF /* libdraco_ios.a */; };
|
|
||||||
D2AC651E205D578B0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AC651D205D578A0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift */; };
|
D2AC651E205D578B0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AC651D205D578A0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift */; };
|
||||||
D2AFCFC0208F1DE00048A9DA /* GLTF+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */; };
|
D2AFCFC0208F1DE00048A9DA /* GLTF+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */; };
|
||||||
D2AFCFC1208F1DE00048A9DA /* GLTF+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */; };
|
D2AFCFC1208F1DE00048A9DA /* GLTF+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */; };
|
||||||
D2AFCFC3208F2A010048A9DA /* GLTF+Material.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */; };
|
D2AFCFC3208F2A010048A9DA /* GLTF+Material.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */; };
|
||||||
D2AFCFC4208F2A010048A9DA /* GLTF+Material.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */; };
|
D2AFCFC4208F2A010048A9DA /* GLTF+Material.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */; };
|
||||||
D2AFCFD2208F6F010048A9DA /* GLTF+Resources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFD1208F6F010048A9DA /* GLTF+Resources.swift */; };
|
D2AFCFD2208F6F010048A9DA /* GLTFResourceLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFD1208F6F010048A9DA /* GLTFResourceLoader.swift */; };
|
||||||
D2AFCFD3208F6F010048A9DA /* GLTF+Resources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFD1208F6F010048A9DA /* GLTF+Resources.swift */; };
|
D2AFCFD3208F6F010048A9DA /* GLTFResourceLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFD1208F6F010048A9DA /* GLTFResourceLoader.swift */; };
|
||||||
D2B064DD214FE0CC00309D6F /* GLTF+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* GLTF+SceneKit.swift */; };
|
D2B064DD214FE0CC00309D6F /* GLTF+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* GLTF+SceneKit.swift */; };
|
||||||
D2B064DE214FE0CC00309D6F /* GLTF.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* GLTF.swift */; };
|
D2B064DE214FE0CC00309D6F /* GLTF.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* GLTF.swift */; };
|
||||||
D2B064DF214FE0CC00309D6F /* GLTFAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* GLTFAccessor.swift */; };
|
D2B064DF214FE0CC00309D6F /* GLTFAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* GLTFAccessor.swift */; };
|
||||||
|
@ -76,10 +71,9 @@
|
||||||
D2B064E9214FE0CC00309D6F /* GLTF+Material.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */; };
|
D2B064E9214FE0CC00309D6F /* GLTF+Material.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */; };
|
||||||
D2B064EA214FE0CC00309D6F /* GLTFAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* GLTFAsset.swift */; };
|
D2B064EA214FE0CC00309D6F /* GLTFAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* GLTFAsset.swift */; };
|
||||||
D2B064EB214FE0CC00309D6F /* GLTFBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* GLTFBuffer.swift */; };
|
D2B064EB214FE0CC00309D6F /* GLTFBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* GLTFBuffer.swift */; };
|
||||||
D2B064EC214FE0CC00309D6F /* Draco.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A67BFF20ADB91B007523AF /* Draco.swift */; };
|
|
||||||
D2B064ED214FE0CC00309D6F /* GLTFBufferView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* GLTFBufferView.swift */; };
|
D2B064ED214FE0CC00309D6F /* GLTFBufferView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* GLTFBufferView.swift */; };
|
||||||
D2B064EE214FE0CC00309D6F /* GLTFCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* GLTFCamera.swift */; };
|
D2B064EE214FE0CC00309D6F /* GLTFCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* GLTFCamera.swift */; };
|
||||||
D2B064EF214FE0CC00309D6F /* GLTF+Resources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFD1208F6F010048A9DA /* GLTF+Resources.swift */; };
|
D2B064EF214FE0CC00309D6F /* GLTFResourceLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2AFCFD1208F6F010048A9DA /* GLTFResourceLoader.swift */; };
|
||||||
D2B064F0214FE0CC00309D6F /* GLTFCameraOrthographic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* GLTFCameraOrthographic.swift */; };
|
D2B064F0214FE0CC00309D6F /* GLTFCameraOrthographic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* GLTFCameraOrthographic.swift */; };
|
||||||
D2B064F1214FE0CC00309D6F /* GLTFCameraPerspective.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* GLTFCameraPerspective.swift */; };
|
D2B064F1214FE0CC00309D6F /* GLTFCameraPerspective.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* GLTFCameraPerspective.swift */; };
|
||||||
D2B064F2214FE0CC00309D6F /* GLTFImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* GLTFImage.swift */; };
|
D2B064F2214FE0CC00309D6F /* GLTFImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* GLTFImage.swift */; };
|
||||||
|
@ -88,21 +82,21 @@
|
||||||
D2B064F5214FE0CC00309D6F /* GLTFMaterialOcclusionTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* GLTFMaterialOcclusionTextureInfo.swift */; };
|
D2B064F5214FE0CC00309D6F /* GLTFMaterialOcclusionTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* GLTFMaterialOcclusionTextureInfo.swift */; };
|
||||||
D2B064F6214FE0CC00309D6F /* GLTFMaterialPBRMetallicRoughness.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* GLTFMaterialPBRMetallicRoughness.swift */; };
|
D2B064F6214FE0CC00309D6F /* GLTFMaterialPBRMetallicRoughness.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* GLTFMaterialPBRMetallicRoughness.swift */; };
|
||||||
D2B064F7214FE0CC00309D6F /* GLTFMesh.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* GLTFMesh.swift */; };
|
D2B064F7214FE0CC00309D6F /* GLTFMesh.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* GLTFMesh.swift */; };
|
||||||
D2B064F8214FE0CC00309D6F /* GLTFKHRDracoMeshCompressionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27BDF82203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift */; };
|
|
||||||
D2B064F9214FE0CC00309D6F /* GLTFMeshPrimitive.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* GLTFMeshPrimitive.swift */; };
|
D2B064F9214FE0CC00309D6F /* GLTFMeshPrimitive.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* GLTFMeshPrimitive.swift */; };
|
||||||
D2B064FA214FE0CC00309D6F /* GLTFNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* GLTFNode.swift */; };
|
D2B064FA214FE0CC00309D6F /* GLTFNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* GLTFNode.swift */; };
|
||||||
D2B064FB214FE0CC00309D6F /* GLTF+CompressedTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */; };
|
D2B064FB214FE0CC00309D6F /* GLTF+CompressedTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */; };
|
||||||
D2B064FC214FE0CC00309D6F /* JSONCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D215713A20402611009E9D16 /* JSONCodingKeys.swift */; };
|
D2B064FC214FE0CC00309D6F /* JSONCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D215713A20402611009E9D16 /* JSONCodingKeys.swift */; };
|
||||||
D2B064FD214FE0CC00309D6F /* GLTFSampler.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* GLTFSampler.swift */; };
|
D2B064FD214FE0CC00309D6F /* GLTFSampler.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* GLTFSampler.swift */; };
|
||||||
D2B064FE214FE0CC00309D6F /* GLTFScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_35 /* GLTFScene.swift */; };
|
D2B064FE214FE0CC00309D6F /* GLTFScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_35 /* GLTFScene.swift */; };
|
||||||
D2B064FF214FE0CC00309D6F /* GLTF+Draco.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2180CDD2087457D005353CF /* GLTF+Draco.swift */; };
|
|
||||||
D2B06500214FE0CC00309D6F /* GLTFSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_36 /* GLTFSkin.swift */; };
|
D2B06500214FE0CC00309D6F /* GLTFSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_36 /* GLTFSkin.swift */; };
|
||||||
D2B06501214FE0CC00309D6F /* TextureStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */; };
|
D2B06501214FE0CC00309D6F /* TextureStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */; };
|
||||||
D2B06502214FE0CC00309D6F /* GLTFTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_37 /* GLTFTexture.swift */; };
|
D2B06502214FE0CC00309D6F /* GLTFTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_37 /* GLTFTexture.swift */; };
|
||||||
D2B06503214FE0CC00309D6F /* GLTFTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* GLTFTextureInfo.swift */; };
|
D2B06503214FE0CC00309D6F /* GLTFTextureInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* GLTFTextureInfo.swift */; };
|
||||||
D2B06504214FE0CC00309D6F /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_39 /* Helper.swift */; };
|
D2B06504214FE0CC00309D6F /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_39 /* Helper.swift */; };
|
||||||
D2B06509214FE0CC00309D6F /* glTFSceneKit-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */; };
|
D2B06509214FE0CC00309D6F /* glTFSceneKit-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */; };
|
||||||
D2B0651F214FEC7200309D6F /* libdraco_tvos.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2B0651E214FEC7200309D6F /* libdraco_tvos.a */; };
|
D2C6215623B4F77E00EA739E /* GLTFConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A51D22234601B7002B5D24 /* GLTFConverter.swift */; };
|
||||||
|
D2C6215723B4F77F00EA739E /* GLTFConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A51D22234601B7002B5D24 /* GLTFConverter.swift */; };
|
||||||
|
D2C6215823B4F78000EA739E /* GLTFConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A51D22234601B7002B5D24 /* GLTFConverter.swift */; };
|
||||||
OBJ_58 /* gltf_scenekitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_42 /* gltf_scenekitTests.swift */; };
|
OBJ_58 /* gltf_scenekitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_42 /* gltf_scenekitTests.swift */; };
|
||||||
OBJ_60 /* glTFSceneKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "gltf_scenekit::gltf_scenekit::Product" /* glTFSceneKit.framework */; };
|
OBJ_60 /* glTFSceneKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "gltf_scenekit::gltf_scenekit::Product" /* glTFSceneKit.framework */; };
|
||||||
OBJ_67 /* GLTF+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* GLTF+SceneKit.swift */; };
|
OBJ_67 /* GLTF+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* GLTF+SceneKit.swift */; };
|
||||||
|
@ -178,22 +172,20 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
49A51D182345E8BB002B5D24 /* GLTFConverter+Geometry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTFConverter+Geometry.swift"; sourceTree = "<group>"; };
|
||||||
|
49A51D22234601B7002B5D24 /* GLTFConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTFConverter.swift; sourceTree = "<group>"; };
|
||||||
D215713A20402611009E9D16 /* JSONCodingKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCodingKeys.swift; sourceTree = "<group>"; };
|
D215713A20402611009E9D16 /* JSONCodingKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCodingKeys.swift; sourceTree = "<group>"; };
|
||||||
D2180CDD2087457D005353CF /* GLTF+Draco.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Draco.swift"; sourceTree = "<group>"; };
|
D2180CDD2087457D005353CF /* GLTF+Draco.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Draco.swift"; sourceTree = "<group>"; };
|
||||||
D2750D132077B7AC00F6198D /* glTFSceneKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = glTFSceneKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D2750D132077B7AC00F6198D /* glTFSceneKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = glTFSceneKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D27BDF82203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GLTFKHRDracoMeshCompressionExtension.swift; sourceTree = "<group>"; };
|
D27BDF82203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GLTFKHRDracoMeshCompressionExtension.swift; sourceTree = "<group>"; };
|
||||||
D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+CompressedTexture.swift"; sourceTree = "<group>"; };
|
D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+CompressedTexture.swift"; sourceTree = "<group>"; };
|
||||||
D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextureStorageManager.swift; sourceTree = "<group>"; };
|
D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextureStorageManager.swift; sourceTree = "<group>"; };
|
||||||
D2A67BFF20ADB91B007523AF /* Draco.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Draco.swift; path = Draco/Draco/Draco.swift; sourceTree = "<group>"; };
|
|
||||||
D2A67C0220ADB92F007523AF /* libdraco.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdraco.a; path = Draco/libdraco.a; sourceTree = "<group>"; };
|
|
||||||
D2A67C0420ADB93E007523AF /* libdraco_ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdraco_ios.a; path = Draco/libdraco_ios.a; sourceTree = "<group>"; };
|
|
||||||
D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "glTFSceneKit-Bridging-Header.h"; sourceTree = "<group>"; };
|
D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "glTFSceneKit-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
D2AC651D205D578A0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GLTF_3D4MCompressedTextureExtension.swift; sourceTree = "<group>"; };
|
D2AC651D205D578A0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GLTF_3D4MCompressedTextureExtension.swift; sourceTree = "<group>"; };
|
||||||
D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Animation.swift"; sourceTree = "<group>"; };
|
D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Animation.swift"; sourceTree = "<group>"; };
|
||||||
D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Material.swift"; sourceTree = "<group>"; };
|
D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Material.swift"; sourceTree = "<group>"; };
|
||||||
D2AFCFD1208F6F010048A9DA /* GLTF+Resources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GLTF+Resources.swift"; sourceTree = "<group>"; };
|
D2AFCFD1208F6F010048A9DA /* GLTFResourceLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTFResourceLoader.swift; sourceTree = "<group>"; };
|
||||||
D2B0650D214FE0CC00309D6F /* glTFSceneKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = glTFSceneKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D2B0650D214FE0CC00309D6F /* glTFSceneKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = glTFSceneKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D2B0651E214FEC7200309D6F /* libdraco_tvos.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdraco_tvos.a; path = Draco/libdraco_tvos.a; sourceTree = "<group>"; };
|
|
||||||
OBJ_11 /* GLTF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTF.swift; sourceTree = "<group>"; };
|
OBJ_11 /* GLTF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTF.swift; sourceTree = "<group>"; };
|
||||||
OBJ_12 /* GLTFAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTFAccessor.swift; sourceTree = "<group>"; };
|
OBJ_12 /* GLTFAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTFAccessor.swift; sourceTree = "<group>"; };
|
||||||
OBJ_13 /* GLTFAccessorSparse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTFAccessorSparse.swift; sourceTree = "<group>"; };
|
OBJ_13 /* GLTFAccessorSparse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLTFAccessorSparse.swift; sourceTree = "<group>"; };
|
||||||
|
@ -235,7 +227,6 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 0;
|
buildActionMask = 0;
|
||||||
files = (
|
files = (
|
||||||
D2A67C0520ADB93E007523AF /* libdraco_ios.a in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -243,7 +234,6 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 0;
|
buildActionMask = 0;
|
||||||
files = (
|
files = (
|
||||||
D2B0651F214FEC7200309D6F /* libdraco_tvos.a in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -259,7 +249,6 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 0;
|
buildActionMask = 0;
|
||||||
files = (
|
files = (
|
||||||
D2A67C0320ADB92F007523AF /* libdraco.a in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -269,9 +258,6 @@
|
||||||
D27BDF7B203DCE6E0036F3A7 /* Frameworks */ = {
|
D27BDF7B203DCE6E0036F3A7 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D2B0651E214FEC7200309D6F /* libdraco_tvos.a */,
|
|
||||||
D2A67C0420ADB93E007523AF /* libdraco_ios.a */,
|
|
||||||
D2A67C0220ADB92F007523AF /* libdraco.a */,
|
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -353,7 +339,6 @@
|
||||||
children = (
|
children = (
|
||||||
OBJ_6 /* Package.swift */,
|
OBJ_6 /* Package.swift */,
|
||||||
D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */,
|
D2A67C0B20ADB9D0007523AF /* glTFSceneKit-Bridging-Header.h */,
|
||||||
D2A67BFF20ADB91B007523AF /* Draco.swift */,
|
|
||||||
OBJ_7 /* Sources */,
|
OBJ_7 /* Sources */,
|
||||||
OBJ_40 /* Tests */,
|
OBJ_40 /* Tests */,
|
||||||
OBJ_43 /* Dependencies */,
|
OBJ_43 /* Dependencies */,
|
||||||
|
@ -373,15 +358,17 @@
|
||||||
OBJ_8 /* glTFSceneKit */ = {
|
OBJ_8 /* glTFSceneKit */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
49A51D22234601B7002B5D24 /* GLTFConverter.swift */,
|
||||||
|
49A51D182345E8BB002B5D24 /* GLTFConverter+Geometry.swift */,
|
||||||
OBJ_9 /* GLTF+SceneKit.swift */,
|
OBJ_9 /* GLTF+SceneKit.swift */,
|
||||||
D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */,
|
|
||||||
D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */,
|
D2AFCFC2208F2A010048A9DA /* GLTF+Material.swift */,
|
||||||
D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */,
|
D287556B2077CABB009B7FA9 /* GLTF+CompressedTexture.swift */,
|
||||||
D2180CDD2087457D005353CF /* GLTF+Draco.swift */,
|
D2180CDD2087457D005353CF /* GLTF+Draco.swift */,
|
||||||
D2AFCFD1208F6F010048A9DA /* GLTF+Resources.swift */,
|
D2AFCFD1208F6F010048A9DA /* GLTFResourceLoader.swift */,
|
||||||
D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */,
|
D2AFCFBF208F1DE00048A9DA /* GLTF+Animation.swift */,
|
||||||
OBJ_10 /* GLTF */,
|
OBJ_10 /* GLTF */,
|
||||||
D2AC651D205D578A0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift */,
|
D2AC651D205D578A0091D5E0 /* GLTF_3D4MCompressedTextureExtension.swift */,
|
||||||
|
D287E3F4209602EB00EBCFD1 /* TextureStorageManager.swift */,
|
||||||
OBJ_39 /* Helper.swift */,
|
OBJ_39 /* Helper.swift */,
|
||||||
);
|
);
|
||||||
name = glTFSceneKit;
|
name = glTFSceneKit;
|
||||||
|
@ -501,6 +488,7 @@
|
||||||
LastUpgradeCheck = 1020;
|
LastUpgradeCheck = 1020;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
D2750CEA2077B7AC00F6198D = {
|
D2750CEA2077B7AC00F6198D = {
|
||||||
|
LastSwiftMigration = 1130;
|
||||||
ProvisioningStyle = Manual;
|
ProvisioningStyle = Manual;
|
||||||
};
|
};
|
||||||
D2B064DA214FE0CC00309D6F = {
|
D2B064DA214FE0CC00309D6F = {
|
||||||
|
@ -583,6 +571,7 @@
|
||||||
files = (
|
files = (
|
||||||
D2750CED2077B7AC00F6198D /* GLTF+SceneKit.swift in Sources */,
|
D2750CED2077B7AC00F6198D /* GLTF+SceneKit.swift in Sources */,
|
||||||
D2750CEE2077B7AC00F6198D /* GLTF.swift in Sources */,
|
D2750CEE2077B7AC00F6198D /* GLTF.swift in Sources */,
|
||||||
|
49A51D1A2345E8BB002B5D24 /* GLTFConverter+Geometry.swift in Sources */,
|
||||||
D2750CEF2077B7AC00F6198D /* GLTFAccessor.swift in Sources */,
|
D2750CEF2077B7AC00F6198D /* GLTFAccessor.swift in Sources */,
|
||||||
D2750CF02077B7AC00F6198D /* GLTFAccessorSparse.swift in Sources */,
|
D2750CF02077B7AC00F6198D /* GLTFAccessorSparse.swift in Sources */,
|
||||||
D2750CF12077B7AC00F6198D /* GLTFAccessorSparseIndices.swift in Sources */,
|
D2750CF12077B7AC00F6198D /* GLTFAccessorSparseIndices.swift in Sources */,
|
||||||
|
@ -596,10 +585,9 @@
|
||||||
D2AFCFC4208F2A010048A9DA /* GLTF+Material.swift in Sources */,
|
D2AFCFC4208F2A010048A9DA /* GLTF+Material.swift in Sources */,
|
||||||
D2750CF82077B7AC00F6198D /* GLTFAsset.swift in Sources */,
|
D2750CF82077B7AC00F6198D /* GLTFAsset.swift in Sources */,
|
||||||
D2750CF92077B7AC00F6198D /* GLTFBuffer.swift in Sources */,
|
D2750CF92077B7AC00F6198D /* GLTFBuffer.swift in Sources */,
|
||||||
D2A67C0120ADB91B007523AF /* Draco.swift in Sources */,
|
|
||||||
D2750CFA2077B7AC00F6198D /* GLTFBufferView.swift in Sources */,
|
D2750CFA2077B7AC00F6198D /* GLTFBufferView.swift in Sources */,
|
||||||
D2750CFB2077B7AC00F6198D /* GLTFCamera.swift in Sources */,
|
D2750CFB2077B7AC00F6198D /* GLTFCamera.swift in Sources */,
|
||||||
D2AFCFD3208F6F010048A9DA /* GLTF+Resources.swift in Sources */,
|
D2AFCFD3208F6F010048A9DA /* GLTFResourceLoader.swift in Sources */,
|
||||||
D2750CFC2077B7AC00F6198D /* GLTFCameraOrthographic.swift in Sources */,
|
D2750CFC2077B7AC00F6198D /* GLTFCameraOrthographic.swift in Sources */,
|
||||||
D2750CFD2077B7AC00F6198D /* GLTFCameraPerspective.swift in Sources */,
|
D2750CFD2077B7AC00F6198D /* GLTFCameraPerspective.swift in Sources */,
|
||||||
D2750CFE2077B7AC00F6198D /* GLTFImage.swift in Sources */,
|
D2750CFE2077B7AC00F6198D /* GLTFImage.swift in Sources */,
|
||||||
|
@ -608,14 +596,13 @@
|
||||||
D2750D012077B7AC00F6198D /* GLTFMaterialOcclusionTextureInfo.swift in Sources */,
|
D2750D012077B7AC00F6198D /* GLTFMaterialOcclusionTextureInfo.swift in Sources */,
|
||||||
D2750D022077B7AC00F6198D /* GLTFMaterialPBRMetallicRoughness.swift in Sources */,
|
D2750D022077B7AC00F6198D /* GLTFMaterialPBRMetallicRoughness.swift in Sources */,
|
||||||
D2750D032077B7AC00F6198D /* GLTFMesh.swift in Sources */,
|
D2750D032077B7AC00F6198D /* GLTFMesh.swift in Sources */,
|
||||||
D2750D042077B7AC00F6198D /* GLTFKHRDracoMeshCompressionExtension.swift in Sources */,
|
D2C6215723B4F77F00EA739E /* GLTFConverter.swift in Sources */,
|
||||||
D2750D052077B7AC00F6198D /* GLTFMeshPrimitive.swift in Sources */,
|
D2750D052077B7AC00F6198D /* GLTFMeshPrimitive.swift in Sources */,
|
||||||
D2750D062077B7AC00F6198D /* GLTFNode.swift in Sources */,
|
D2750D062077B7AC00F6198D /* GLTFNode.swift in Sources */,
|
||||||
D287556E2077CB1B009B7FA9 /* GLTF+CompressedTexture.swift in Sources */,
|
D287556E2077CB1B009B7FA9 /* GLTF+CompressedTexture.swift in Sources */,
|
||||||
D2750D072077B7AC00F6198D /* JSONCodingKeys.swift in Sources */,
|
D2750D072077B7AC00F6198D /* JSONCodingKeys.swift in Sources */,
|
||||||
D2750D082077B7AC00F6198D /* GLTFSampler.swift in Sources */,
|
D2750D082077B7AC00F6198D /* GLTFSampler.swift in Sources */,
|
||||||
D2750D092077B7AC00F6198D /* GLTFScene.swift in Sources */,
|
D2750D092077B7AC00F6198D /* GLTFScene.swift in Sources */,
|
||||||
D2180CE0208745A7005353CF /* GLTF+Draco.swift in Sources */,
|
|
||||||
D2750D0A2077B7AC00F6198D /* GLTFSkin.swift in Sources */,
|
D2750D0A2077B7AC00F6198D /* GLTFSkin.swift in Sources */,
|
||||||
D287E3F6209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */,
|
D287E3F6209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */,
|
||||||
D2750D0B2077B7AC00F6198D /* GLTFTexture.swift in Sources */,
|
D2750D0B2077B7AC00F6198D /* GLTFTexture.swift in Sources */,
|
||||||
|
@ -630,6 +617,7 @@
|
||||||
files = (
|
files = (
|
||||||
D2B064DD214FE0CC00309D6F /* GLTF+SceneKit.swift in Sources */,
|
D2B064DD214FE0CC00309D6F /* GLTF+SceneKit.swift in Sources */,
|
||||||
D2B064DE214FE0CC00309D6F /* GLTF.swift in Sources */,
|
D2B064DE214FE0CC00309D6F /* GLTF.swift in Sources */,
|
||||||
|
49A51D1B2345E8BB002B5D24 /* GLTFConverter+Geometry.swift in Sources */,
|
||||||
D2B064DF214FE0CC00309D6F /* GLTFAccessor.swift in Sources */,
|
D2B064DF214FE0CC00309D6F /* GLTFAccessor.swift in Sources */,
|
||||||
D2B064E0214FE0CC00309D6F /* GLTFAccessorSparse.swift in Sources */,
|
D2B064E0214FE0CC00309D6F /* GLTFAccessorSparse.swift in Sources */,
|
||||||
D2B064E1214FE0CC00309D6F /* GLTFAccessorSparseIndices.swift in Sources */,
|
D2B064E1214FE0CC00309D6F /* GLTFAccessorSparseIndices.swift in Sources */,
|
||||||
|
@ -643,10 +631,9 @@
|
||||||
D2B064E9214FE0CC00309D6F /* GLTF+Material.swift in Sources */,
|
D2B064E9214FE0CC00309D6F /* GLTF+Material.swift in Sources */,
|
||||||
D2B064EA214FE0CC00309D6F /* GLTFAsset.swift in Sources */,
|
D2B064EA214FE0CC00309D6F /* GLTFAsset.swift in Sources */,
|
||||||
D2B064EB214FE0CC00309D6F /* GLTFBuffer.swift in Sources */,
|
D2B064EB214FE0CC00309D6F /* GLTFBuffer.swift in Sources */,
|
||||||
D2B064EC214FE0CC00309D6F /* Draco.swift in Sources */,
|
|
||||||
D2B064ED214FE0CC00309D6F /* GLTFBufferView.swift in Sources */,
|
D2B064ED214FE0CC00309D6F /* GLTFBufferView.swift in Sources */,
|
||||||
D2B064EE214FE0CC00309D6F /* GLTFCamera.swift in Sources */,
|
D2B064EE214FE0CC00309D6F /* GLTFCamera.swift in Sources */,
|
||||||
D2B064EF214FE0CC00309D6F /* GLTF+Resources.swift in Sources */,
|
D2B064EF214FE0CC00309D6F /* GLTFResourceLoader.swift in Sources */,
|
||||||
D2B064F0214FE0CC00309D6F /* GLTFCameraOrthographic.swift in Sources */,
|
D2B064F0214FE0CC00309D6F /* GLTFCameraOrthographic.swift in Sources */,
|
||||||
D2B064F1214FE0CC00309D6F /* GLTFCameraPerspective.swift in Sources */,
|
D2B064F1214FE0CC00309D6F /* GLTFCameraPerspective.swift in Sources */,
|
||||||
D2B064F2214FE0CC00309D6F /* GLTFImage.swift in Sources */,
|
D2B064F2214FE0CC00309D6F /* GLTFImage.swift in Sources */,
|
||||||
|
@ -655,14 +642,13 @@
|
||||||
D2B064F5214FE0CC00309D6F /* GLTFMaterialOcclusionTextureInfo.swift in Sources */,
|
D2B064F5214FE0CC00309D6F /* GLTFMaterialOcclusionTextureInfo.swift in Sources */,
|
||||||
D2B064F6214FE0CC00309D6F /* GLTFMaterialPBRMetallicRoughness.swift in Sources */,
|
D2B064F6214FE0CC00309D6F /* GLTFMaterialPBRMetallicRoughness.swift in Sources */,
|
||||||
D2B064F7214FE0CC00309D6F /* GLTFMesh.swift in Sources */,
|
D2B064F7214FE0CC00309D6F /* GLTFMesh.swift in Sources */,
|
||||||
D2B064F8214FE0CC00309D6F /* GLTFKHRDracoMeshCompressionExtension.swift in Sources */,
|
D2C6215823B4F78000EA739E /* GLTFConverter.swift in Sources */,
|
||||||
D2B064F9214FE0CC00309D6F /* GLTFMeshPrimitive.swift in Sources */,
|
D2B064F9214FE0CC00309D6F /* GLTFMeshPrimitive.swift in Sources */,
|
||||||
D2B064FA214FE0CC00309D6F /* GLTFNode.swift in Sources */,
|
D2B064FA214FE0CC00309D6F /* GLTFNode.swift in Sources */,
|
||||||
D2B064FB214FE0CC00309D6F /* GLTF+CompressedTexture.swift in Sources */,
|
D2B064FB214FE0CC00309D6F /* GLTF+CompressedTexture.swift in Sources */,
|
||||||
D2B064FC214FE0CC00309D6F /* JSONCodingKeys.swift in Sources */,
|
D2B064FC214FE0CC00309D6F /* JSONCodingKeys.swift in Sources */,
|
||||||
D2B064FD214FE0CC00309D6F /* GLTFSampler.swift in Sources */,
|
D2B064FD214FE0CC00309D6F /* GLTFSampler.swift in Sources */,
|
||||||
D2B064FE214FE0CC00309D6F /* GLTFScene.swift in Sources */,
|
D2B064FE214FE0CC00309D6F /* GLTFScene.swift in Sources */,
|
||||||
D2B064FF214FE0CC00309D6F /* GLTF+Draco.swift in Sources */,
|
|
||||||
D2B06500214FE0CC00309D6F /* GLTFSkin.swift in Sources */,
|
D2B06500214FE0CC00309D6F /* GLTFSkin.swift in Sources */,
|
||||||
D2B06501214FE0CC00309D6F /* TextureStorageManager.swift in Sources */,
|
D2B06501214FE0CC00309D6F /* TextureStorageManager.swift in Sources */,
|
||||||
D2B06502214FE0CC00309D6F /* GLTFTexture.swift in Sources */,
|
D2B06502214FE0CC00309D6F /* GLTFTexture.swift in Sources */,
|
||||||
|
@ -685,6 +671,7 @@
|
||||||
files = (
|
files = (
|
||||||
OBJ_67 /* GLTF+SceneKit.swift in Sources */,
|
OBJ_67 /* GLTF+SceneKit.swift in Sources */,
|
||||||
OBJ_68 /* GLTF.swift in Sources */,
|
OBJ_68 /* GLTF.swift in Sources */,
|
||||||
|
49A51D192345E8BB002B5D24 /* GLTFConverter+Geometry.swift in Sources */,
|
||||||
OBJ_69 /* GLTFAccessor.swift in Sources */,
|
OBJ_69 /* GLTFAccessor.swift in Sources */,
|
||||||
OBJ_70 /* GLTFAccessorSparse.swift in Sources */,
|
OBJ_70 /* GLTFAccessorSparse.swift in Sources */,
|
||||||
OBJ_71 /* GLTFAccessorSparseIndices.swift in Sources */,
|
OBJ_71 /* GLTFAccessorSparseIndices.swift in Sources */,
|
||||||
|
@ -698,10 +685,9 @@
|
||||||
D2AFCFC3208F2A010048A9DA /* GLTF+Material.swift in Sources */,
|
D2AFCFC3208F2A010048A9DA /* GLTF+Material.swift in Sources */,
|
||||||
OBJ_77 /* GLTFAsset.swift in Sources */,
|
OBJ_77 /* GLTFAsset.swift in Sources */,
|
||||||
OBJ_78 /* GLTFBuffer.swift in Sources */,
|
OBJ_78 /* GLTFBuffer.swift in Sources */,
|
||||||
D2A67C0020ADB91B007523AF /* Draco.swift in Sources */,
|
|
||||||
OBJ_79 /* GLTFBufferView.swift in Sources */,
|
OBJ_79 /* GLTFBufferView.swift in Sources */,
|
||||||
OBJ_80 /* GLTFCamera.swift in Sources */,
|
OBJ_80 /* GLTFCamera.swift in Sources */,
|
||||||
D2AFCFD2208F6F010048A9DA /* GLTF+Resources.swift in Sources */,
|
D2AFCFD2208F6F010048A9DA /* GLTFResourceLoader.swift in Sources */,
|
||||||
OBJ_81 /* GLTFCameraOrthographic.swift in Sources */,
|
OBJ_81 /* GLTFCameraOrthographic.swift in Sources */,
|
||||||
OBJ_82 /* GLTFCameraPerspective.swift in Sources */,
|
OBJ_82 /* GLTFCameraPerspective.swift in Sources */,
|
||||||
OBJ_83 /* GLTFImage.swift in Sources */,
|
OBJ_83 /* GLTFImage.swift in Sources */,
|
||||||
|
@ -710,14 +696,13 @@
|
||||||
OBJ_86 /* GLTFMaterialOcclusionTextureInfo.swift in Sources */,
|
OBJ_86 /* GLTFMaterialOcclusionTextureInfo.swift in Sources */,
|
||||||
OBJ_87 /* GLTFMaterialPBRMetallicRoughness.swift in Sources */,
|
OBJ_87 /* GLTFMaterialPBRMetallicRoughness.swift in Sources */,
|
||||||
OBJ_88 /* GLTFMesh.swift in Sources */,
|
OBJ_88 /* GLTFMesh.swift in Sources */,
|
||||||
D27BDF83203F0BEF0036F3A7 /* GLTFKHRDracoMeshCompressionExtension.swift in Sources */,
|
D2C6215623B4F77E00EA739E /* GLTFConverter.swift in Sources */,
|
||||||
OBJ_89 /* GLTFMeshPrimitive.swift in Sources */,
|
OBJ_89 /* GLTFMeshPrimitive.swift in Sources */,
|
||||||
OBJ_90 /* GLTFNode.swift in Sources */,
|
OBJ_90 /* GLTFNode.swift in Sources */,
|
||||||
D287556D2077CB16009B7FA9 /* GLTF+CompressedTexture.swift in Sources */,
|
D287556D2077CB16009B7FA9 /* GLTF+CompressedTexture.swift in Sources */,
|
||||||
D2157142204035E3009E9D16 /* JSONCodingKeys.swift in Sources */,
|
D2157142204035E3009E9D16 /* JSONCodingKeys.swift in Sources */,
|
||||||
OBJ_91 /* GLTFSampler.swift in Sources */,
|
OBJ_91 /* GLTFSampler.swift in Sources */,
|
||||||
OBJ_92 /* GLTFScene.swift in Sources */,
|
OBJ_92 /* GLTFScene.swift in Sources */,
|
||||||
D2180CDF208745A6005353CF /* GLTF+Draco.swift in Sources */,
|
|
||||||
OBJ_93 /* GLTFSkin.swift in Sources */,
|
OBJ_93 /* GLTFSkin.swift in Sources */,
|
||||||
D287E3F5209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */,
|
D287E3F5209602EB00EBCFD1 /* TextureStorageManager.swift in Sources */,
|
||||||
OBJ_94 /* GLTFTexture.swift in Sources */,
|
OBJ_94 /* GLTFTexture.swift in Sources */,
|
||||||
|
@ -740,7 +725,6 @@
|
||||||
D2750D112077B7AC00F6198D /* Debug */ = {
|
D2750D112077B7AC00F6198D /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
|
||||||
BITCODE_GENERATION_MODE = bitcode;
|
BITCODE_GENERATION_MODE = bitcode;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
@ -748,19 +732,9 @@
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_ios_Info.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_ios_Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
|
||||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Draco";
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -775,7 +749,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
TARGET_NAME = glTFSceneKit;
|
TARGET_NAME = glTFSceneKit;
|
||||||
VALID_ARCHS = arm64;
|
VALID_ARCHS = arm64;
|
||||||
|
@ -785,26 +759,15 @@
|
||||||
D2750D122077B7AC00F6198D /* Release */ = {
|
D2750D122077B7AC00F6198D /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_ios_Info.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_ios_Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
|
||||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Draco";
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -819,7 +782,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
TARGET_NAME = glTFSceneKit;
|
TARGET_NAME = glTFSceneKit;
|
||||||
VALID_ARCHS = arm64;
|
VALID_ARCHS = arm64;
|
||||||
|
@ -835,19 +798,9 @@
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/glTFSceneKit_tvos.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/glTFSceneKit_tvos.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||||
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
|
||||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Draco";
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -879,19 +832,9 @@
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Draco",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/glTFSceneKit_tvos.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/glTFSceneKit_tvos.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||||
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
|
||||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Draco";
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -1016,27 +959,12 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(SRCROOT)/.build/checkouts/**",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekitTests_Info.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekitTests_Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = "$(SRCROOT)/.build/checkouts/**";
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"-lc++",
|
|
||||||
"-ldraco",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||||
PRODUCT_NAME = glTFSceneKitTests;
|
PRODUCT_NAME = glTFSceneKitTests;
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGET_NAME = gltf_scenekitTests;
|
TARGET_NAME = gltf_scenekitTests;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
@ -1045,27 +973,12 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
|
||||||
);
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(SRCROOT)/.build/checkouts/**",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekitTests_Info.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekitTests_Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = "$(SRCROOT)/.build/checkouts/**";
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"-lc++",
|
|
||||||
"-ldraco",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||||
PRODUCT_NAME = glTFSceneKitTests;
|
PRODUCT_NAME = glTFSceneKitTests;
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "glTFSceneKit-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGET_NAME = gltf_scenekitTests;
|
TARGET_NAME = gltf_scenekitTests;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
@ -1073,7 +986,6 @@
|
||||||
OBJ_64 /* Debug */ = {
|
OBJ_64 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
@ -1083,8 +995,7 @@
|
||||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_Info.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
LIBRARY_SEARCH_PATHS = "";
|
||||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Draco";
|
|
||||||
MACH_O_TYPE = mh_dylib;
|
MACH_O_TYPE = mh_dylib;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
|
@ -1108,7 +1019,6 @@
|
||||||
OBJ_65 /* Release */ = {
|
OBJ_65 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
@ -1118,8 +1028,7 @@
|
||||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||||
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_Info.plist;
|
INFOPLIST_FILE = glTFSceneKit.xcodeproj/gltf_scenekit_Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
LIBRARY_SEARCH_PATHS = "";
|
||||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Draco";
|
|
||||||
MACH_O_TYPE = mh_dylib;
|
MACH_O_TYPE = mh_dylib;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
|
|
Binary file not shown.
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1020"
|
LastUpgradeVersion = "1100"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -29,8 +29,6 @@
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
@ -51,8 +49,6 @@
|
||||||
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1020"
|
LastUpgradeVersion = "1100"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -29,8 +29,6 @@
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
@ -51,8 +49,6 @@
|
||||||
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1020"
|
LastUpgradeVersion = "1100"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -27,6 +27,15 @@
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "gltf_scenekit::gltf_scenekit"
|
||||||
|
BuildableName = "glTFSceneKit.framework"
|
||||||
|
BlueprintName = "glTFSceneKit"
|
||||||
|
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO">
|
skipped = "NO">
|
||||||
|
@ -39,17 +48,6 @@
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "gltf_scenekit::gltf_scenekit"
|
|
||||||
BuildableName = "glTFSceneKit.framework"
|
|
||||||
BlueprintName = "glTFSceneKit"
|
|
||||||
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
@ -70,8 +68,6 @@
|
||||||
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
ReferencedContainer = "container:glTFSceneKit.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|
Loading…
Reference in New Issue