Skip to content

Commit

Permalink
Make Skeleton & SkeletalAnimation a cached resource
Browse files Browse the repository at this point in the history
  • Loading branch information
STREGA committed Oct 14, 2023
1 parent b7b65a8 commit 58476a6
Show file tree
Hide file tree
Showing 12 changed files with 626 additions and 145 deletions.
23 changes: 17 additions & 6 deletions Sources/GateEngine/ECS/3D Specific/Rig/Rig3DComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* http://stregasgate.com
*/

public class Rig3DComponent: Component {
@MainActor public final class Rig3DComponent: Component {
public var disabled: Bool = false
internal var deltaAccumulator: Float = 0
public var slowAnimationsPastDistance: Float = 20
Expand Down Expand Up @@ -37,15 +37,26 @@ public class Rig3DComponent: Component {
public var updateColliderFromBoneNamed: String? = nil

func update(deltaTime: Float, objectScale: Size3) {
activeAnimation?.update(deltaTime: deltaTime, objectScale: objectScale)
deltaAccumulator += deltaTime
blendingAccumulator += deltaTime
if let activeAnimation, activeAnimation.isReady {
activeAnimation.update(deltaTime: deltaTime, objectScale: objectScale)
deltaAccumulator += deltaTime
blendingAccumulator += deltaTime
}
}

public class Animation {
@MainActor public final class Animation {
public var subAnimations: [SubAnimation]
var primaryIndex: Int = 0

public var isReady: Bool {
for animation in subAnimations {
if animation.skeletalAnimation.state != .ready {
return false
}
}
return true
}

@inline(__always)
public var progress: Float {
get {
Expand Down Expand Up @@ -146,7 +157,7 @@ public class Rig3DComponent: Component {
self.subAnimations.append(a)
}

public struct SubAnimation {
@MainActor public struct SubAnimation {
public var skeletalAnimation: SkeletalAnimation
public var skipJoints: [Skeleton.SkipJoint]

Expand Down
4 changes: 2 additions & 2 deletions Sources/GateEngine/ECS/3D Specific/Rig/Rig3DSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public final class Rig3DSystem: System {
if let component = entity.component(ofType: Rig3DComponent.self),
component.disabled == false
{
if let animation = component.activeAnimation {
if let animation = component.activeAnimation, animation.isReady {
if let scale = entity.component(ofType: Transform3Component.self)?.scale {
component.update(
deltaTime: deltaTime + component.deltaAccumulator,
Expand All @@ -66,7 +66,7 @@ public final class Rig3DSystem: System {
for animation in animation.subAnimations {
component.skeleton.applyAnimation(
animation.skeletalAnimation,
withTime: animation.accumulatedTime,
atTime: animation.accumulatedTime,
duration: animation.duration,
repeating: animation.repeats,
skipJoints: animation.skipJoints,
Expand Down
16 changes: 9 additions & 7 deletions Sources/GateEngine/ECS/StandardRenderingSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ public final class StandardRenderingSystem: RenderingSystem {

if let rigComponent = entity.component(ofType: Rig3DComponent.self) {
for skinnedGeometry in renderingGeometry.skinnedGeometries {
scene.insert(
skinnedGeometry,
withPose: rigComponent.skeleton.getPose(),
material: material,
at: transform,
flags: renderingGeometry.flags
)
if let pose = rigComponent.skeleton.getPose() {
scene.insert(
skinnedGeometry,
withPose: pose,
material: material,
at: transform,
flags: renderingGeometry.flags
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ public class GLTransmissionFormat {
}
return false
}

public static func supportedFileExtensions() -> [String] {
return ["gltf", "glb"]
}
}

extension GLTransmissionFormat: GeometryImporter {
Expand Down Expand Up @@ -657,7 +661,7 @@ extension GLTransmissionFormat: SkinImporter {
}
}

extension GLTransmissionFormat: SkeletonImporter {
extension GLTransmissionFormat: SkeletonImporter {
private func skeletonNode(named name: String?, in gltf: GLTF) -> Int? {
func findIn(_ parent: Int) -> Int? {
let node = gltf.nodes[parent]
Expand Down Expand Up @@ -687,9 +691,7 @@ extension GLTransmissionFormat: SkeletonImporter {
return gltf.scenes[gltf.scene].nodes.first
}

public func loadData(path: String, options: SkeletonImporterOptions) async throws -> Skeleton.Joint {
let baseURL = URL(string: path)!.deletingLastPathComponent()
let data = try await Game.shared.platform.loadResource(from: path)
public func process(data: Data, baseURL: URL, options: SkeletonImporterOptions) async throws -> Skeleton.Joint {
let gltf = try gltf(from: data, baseURL: baseURL)
guard let rootNode = skeletonNode(named: options.subobjectName, in: gltf) else {
throw GateEngineError.failedToDecode("Couldn't find skeleton root.")
Expand Down Expand Up @@ -721,9 +723,7 @@ extension GLTransmissionFormat: SkeletalAnimationImporter {
return gltf.animations?.first
}

public func loadData(path: String, options: SkeletalAnimationImporterOptions) async throws -> SkeletalAnimation {
let data = try await Game.shared.platform.loadResource(from: path)
let baseURL = URL(string: path)!.deletingLastPathComponent()
public func process(data: Data, baseURL: URL, options: SkeletalAnimationImporterOptions) async throws -> SkeletalAnimationBackend {
let gltf = try gltf(from: data, baseURL: baseURL)

guard let animation = animation(named: options.subobjectName, from: gltf) else {
Expand Down Expand Up @@ -835,6 +835,6 @@ extension GLTransmissionFormat: SkeletalAnimationImporter {
timeMax = .maximum(times.max()!, timeMax)
}

return SkeletalAnimation(name: animation.name, duration: timeMax, animations: animations)
return SkeletalAnimationBackend(name: animation.name, duration: timeMax, animations: animations)
}
}
6 changes: 6 additions & 0 deletions Sources/GateEngine/Resources/Resource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ public protocol Resource: Equatable, Hashable {
It is a programming error to use a resource or access it's properties while it's state is anything other then `ready`.
*/
@MainActor var state: ResourceState { get }
@MainActor var isReady: Bool {get}

@MainActor var cacheHint: CacheHint {get}
}

public extension Resource {
@_transparent
@MainActor var isReady: Bool {self.state == .ready}
}

public enum ResourceState: Equatable {
/// The resource isn't ready for use but may eventually become `ready` or `failed`.
case pending
Expand Down
10 changes: 1 addition & 9 deletions Sources/GateEngine/Resources/ResourceManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,14 @@ extension ResourceManager {
var geometries: [GeometryKey: GeometryCache] = [:]
var skinnedGeometries: [SkinnedGeometryKey: SkinnedGeometryCache] = [:]

var skeletons: [SkeletonKey: SkeletonCache] = [:]
var skeletalAnimations: [SkeletalAnimationKey: SkeletalAnimationCache] = [:]

var tileSets: [TileSetKey: TileSetCache] = [:]
var tileMaps: [TileMapKey: TileMapCache] = [:]

var audioBuffers: [AudioBufferKey: AudioBufferCache] = [:]

// Skeleton
struct SkeletalAnimationKey: Hashable, Sendable {
let path: String
let options: SkeletalAnimationImporterOptions
}
struct SkeletalAnimationCache {
weak var skeletalAnimation: SkeletalAnimation? = nil
}

// AudioBuffer
struct AudioBufferKey: Hashable, Sendable {
let path: String
Expand Down
Loading

0 comments on commit 58476a6

Please sign in to comment.