@@ -123,6 +123,26 @@ final class SkeletonBackend {
123123 self . rootJoint = joint
124124 self . bindPose = Skeleton . Pose ( joint)
125125 }
126+
127+ init ( rawSkeleton: RawSkeleton ) {
128+ func createJoint( from rawJoint: RawSkeleton . RawJoint ) -> Skeleton . Joint {
129+ var joint = Skeleton . Joint ( rawJoint: rawJoint)
130+ joint. localTransform = rawJoint. localTransform
131+ for rawJoint in rawSkeleton. joints {
132+ if rawJoint. parent == joint. id {
133+ let child = createJoint ( from: rawJoint)
134+ child. parent = joint
135+ }
136+ }
137+ return joint
138+ }
139+ let rootJoint = createJoint ( from: rawSkeleton. joints. first ( where: { $0. parent == nil } ) !)
140+ self . rootJoint = rootJoint
141+ self . bindPose = Skeleton . Pose ( rootJoint)
142+ }
143+ }
144+ fileprivate extension Skeleton . Joint {
145+
126146}
127147
128148extension Skeleton {
@@ -328,6 +348,12 @@ extension Skeleton {
328348 self . id = id
329349 self . name = name
330350 }
351+
352+ /// Convenince for constructing a Skeleton from a RawSkeleton
353+ fileprivate convenience init ( rawJoint: RawSkeleton . RawJoint ) {
354+ self . init ( id: rawJoint. id, name: rawJoint. name)
355+ self . localTransform = rawJoint. localTransform
356+ }
331357 }
332358}
333359
@@ -473,12 +499,8 @@ extension Skeleton.Pose.Joint: Hashable {
473499
474500// MARK: - Resource Manager
475501
476- public protocol SkeletonImporter : AnyObject {
477- init ( )
478-
479- func process( data: Data , baseURL: URL , options: SkeletonImporterOptions ) async throws -> Skeleton . Joint
480-
481- static func supportedFileExtensions( ) -> [ String ]
502+ public protocol SkeletonImporter : ResourceImporter {
503+ func loadSkeleton( options: SkeletonImporterOptions ) async throws ( GateEngineError) -> RawSkeleton
482504}
483505
484506public struct SkeletonImporterOptions : Equatable , Hashable , Sendable {
@@ -498,13 +520,11 @@ extension ResourceManager {
498520 guard importers. skeletonImporters. contains ( where: { $0 == type } ) == false else { return }
499521 importers. skeletonImporters. insert ( type, at: 0 )
500522 }
501-
502- fileprivate func importerForFileType ( _ file : String ) -> ( any SkeletonImporter ) ? {
523+
524+ func skeletonImporterForPath ( _ path : String ) async throws -> ( any SkeletonImporter ) ? {
503525 for type in self . importers. skeletonImporters {
504- if type. supportedFileExtensions ( ) . contains ( where: {
505- $0. caseInsensitiveCompare ( file) == . orderedSame
506- } ) {
507- return type. init ( )
526+ if type. canProcessFile ( path) {
527+ return try await self . importers. getImporter ( path: path, type: type)
508528 }
509529 }
510530 return nil
@@ -556,6 +576,22 @@ extension ResourceManager.Cache {
556576 }
557577}
558578
579+ extension RawSkeleton {
580+ public init ( path: String , options: SkeletonImporterOptions = . none) async throws {
581+ guard
582+ let importer: any SkeletonImporter = try await Game . unsafeShared. resourceManager. skeletonImporterForPath ( path)
583+ else {
584+ throw GateEngineError . failedToLoad ( " No importer for \( URL ( fileURLWithPath: path) . pathExtension) . " )
585+ }
586+
587+ do {
588+ self = try await importer. loadSkeleton ( options: options)
589+ } catch {
590+ throw GateEngineError ( error)
591+ }
592+ }
593+ }
594+
559595@MainActor
560596extension ResourceManager {
561597 func changeCacheHint( _ cacheHint: CacheHint , for key: Cache . SkeletonKey ) {
@@ -626,23 +662,13 @@ extension ResourceManager {
626662 let path = key. requestedPath
627663
628664 do {
629- guard let fileExtension = path. components ( separatedBy: " . " ) . last else {
630- throw GateEngineError . failedToLoad ( " Unknown file type. " )
631- }
632- guard let importer: any SkeletonImporter = Game . unsafeShared. resourceManager. importerForFileType ( fileExtension) else {
633- throw GateEngineError . failedToLoad ( " No importer for \( fileExtension) . " )
634- }
635-
636- let data = try await Platform . current. loadResource ( from: path)
637- let rootJoint : Skeleton . Joint = try await importer. process (
638- data: data,
639- baseURL: URL ( string: path) !. deletingLastPathComponent ( ) ,
665+ let rawSkeleton = try await RawSkeleton (
666+ path: key. requestedPath,
640667 options: key. options
641668 )
642-
643669 Task { @MainActor in
644670 if let cache = cache. skeletons [ key] {
645- cache. skeletonBackend = SkeletonBackend ( rootJoint : rootJoint )
671+ cache. skeletonBackend = SkeletonBackend ( rawSkeleton : rawSkeleton )
646672 cache. state = . ready
647673 } else {
648674 Log . warn ( " Resource \" \( path) \" was deallocated before being " + ( isFirstLoad ? " loaded. " : " re-loaded. " ) )
0 commit comments