-
Notifications
You must be signed in to change notification settings - Fork 6
/
GLLModel.swift
94 lines (81 loc) · 3.73 KB
/
GLLModel.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//
// GLLModel.m
// GLLara
//
// Created by Torsten Kammer on 31.08.12.
// Copyright (c) 2012 Torsten Kammer. All rights reserved.
//
import Foundation
import UniformTypeIdentifiers
let GLLModelLoadingErrorDomain = "GLL Model loading error domain";
enum GLLModelLoadingErrorCode: Int {
case prematureEndOfFile
case indexOutOfRange
case circularReference
case fileTypeNotSupported
case parametersNotFound
}
/**
* # A renderable object.
*
* A GLLModel corresponds to one mesh file (which actually contains many meshes; this is a bit confusing) and describes its graphics contexts. It contains some default transformations, but does not store poses and the like.
*/
@objc class GLLModel: NSObject {
@objc var bones: [GLLModelBone] = []
@objc var meshes: [GLLModelMesh] = []
static let cachedModels = NSCache<NSString, GLLModel>()
/**
* # Returns a model with a given URL, returning a cached instance if one exists.
*
* Since a model is immutable here, it can be shared as much as necessary. This method uses an internal cache to share objects. Note that a model can be evicted from this cache again, if nobody is using it.
*/
@objc static func cachedModel(from file: URL, parent: GLLModel? = nil) throws -> GLLModel {
var key = file.absoluteString
if let parent {
key += "\n\(parent.baseURL.absoluteString)"
}
if let result = cachedModels.object(forKey: key as NSString) {
return result
}
if file.pathExtension == "mesh" || file.pathExtension == "xps" {
let model = try GLLModelXNALara(binaryFromFile: file, parent: parent)
cachedModels.setObject(model, forKey: key as NSString)
return model
} else if file.lastPathComponent.hasSuffix(".mesh.ascii") {
let model = try GLLModelXNALara(ASCIIFromFile: file, parent: parent)
cachedModels.setObject(model, forKey: key as NSString)
return model
} else if file.pathExtension == "obj" {
let model = try GLLModelObj(contentsOf: file)
cachedModels.setObject(model, forKey: key as NSString)
return model
} else if file.pathExtension == ".gltf" {
let model = try GLLModelGltf(url: file, isBinary: false)
cachedModels.setObject(model, forKey: key as NSString)
return model
} else if file.pathExtension == ".glb" {
let model = try GLLModelGltf(url: file, isBinary: true)
cachedModels.setObject(model, forKey: key as NSString)
return model
} else {
// Find display name for this extension
let contentType = try file.resourceValues(forKeys: [.contentTypeKey]).contentType
let fileTypeDescription = contentType?.localizedDescription ?? file.pathExtension
throw NSError(domain: GLLModelLoadingErrorDomain, code: GLLModelLoadingErrorCode.fileTypeNotSupported.rawValue, userInfo: [
NSLocalizedDescriptionKey : String(format:NSLocalizedString("Files of type %@ are not supported.", comment: "Tried to load unsupported format"), fileTypeDescription),
NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString("Only .mesh, .mesh.ascii and .obj files can be loaded.", comment: "Tried to load unsupported format")
])
}
}
@objc var baseURL: URL! = nil
@objc var parameters: GLLModelParams! = nil
var hasBones: Bool {
return bones.count > 1
}
@objc var cameraTargetNames: [GLLCameraTargetDescription] {
return parameters.cameraTargets
}
@objc func bone(name: String) -> GLLModelBone? {
return bones.first { $0.name == name }
}
}