Skip to content

v0.2.1

Latest
Compare
Choose a tag to compare
@STREGA STREGA released this 01 Jul 17:39
· 2 commits to Release-0.2 since this release

This release adds support for Swift 5.10

What's New?

New Blending Modes

Two new blending modes are available for DrawCommand.
.add Will do an addition of the color to the render target
.subtract Will do a subtraction of the color from the render target
Screenshot_2023-10-18_at_9 15 51_PM

Object Animations

A new cached resource is available: ObjectAnimation3D
This resource stores Transform3 keyframes loaded from a file.

In combination with ObjectAnimation3DComponent and ObjectAnimation3DSystem you can now load and play object animations from files.

The animation will cause the objects Transform3Component to be updated, moving the whole object.

ObjectAnimation3DComponent works similarly to Rig3DComponent.
It can hold multiple animations and you can switch between them as desired.

entity.insert(ObjectAnimation3DComponent.self) { component in
    component.animationSet = [
        ObjectAnimation3D(
            path: "Assets/MyAnimation.glb", 
            options: .named("AnimationTrack")
         )
    ]
    component.setAnimation(at: 0)
}

Billboarding

BillboardSystem and BillboardComponent are now available.
Adding BillboardComponent to a 3D entity will cause the entity to always face toward the camera.

SpriteComponent Animation Queue

SpriteComponent now uses a queue for animations.
By using queueAnimation(_) along with the various playbackState options you can now easily create animations that seamlessly transition to one another.

Sprites in Scenes

You can now insert Sprite into a Scene, placing them in the 3D world.

Resource Loading Meta

You can now check to see which resources are still loading.
You can use this to find bugs and performance issues, as well as create a loading bar using the count against your known count.

print(game.resourceManager.currentlyLoading)
["Assets/Stages/test01/diffuse.png", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/Characters/Protagonist/Protagonist.glb", "Assets/UI/HUD.png"]

Shaders

Branch
Branch allows you to conditionally return one of two provided values.

fsh.output.color = myCompareValue.branch(
    success: Vec4(color.rgb, 0), 
    failure: Vec4(color.rgb, 1)
)
fsh.output.color = fsh.branch(
    if: myCompareValue,
    success: Vec4(color.rgb, 0), 
    failure: Vec4(color.rgb, 1)
)

Switch
Switch allows you to conditionally return one of many provided values.

fsh.output.color = myEnumValue.switch([
    .case(0, result: Vec4(.red),
    .case(1, result: Vec4(.green),
    .case(2, result: Vec4(.blue),
])

Discard
Discard allows you to insert a fragment discard inline anywhere you can pass a value.
The operation will cancel the entire fragment resulting in no color, depth, or stencil writes.

let color: Vec4 = ...

fsh.output.color = color.discard(if: myBoolValue)

Texture Size
Returns the size of the texture.

let size = fsh.channel(0).texture.size

DrawCommand

DrawCommand is the API utilized by Scene and Canvas. Every insert(...) call on those containers will ultimately create a DrawCommand.

You can now create your own 1DrawCommand and add them directly to Scene and Canvas.
This means if Canvas or Scene can't do what you want or the available implementation is too inefficient, you can make your own.

DrawCommand also gives access to standard renderer functionality in flags, like winding direction, cull modes, depth test modes, etc...

let command = DrawCommand(
    resource: .geometry(.rectOriginTopLeft),
    // An instance will be drawn for each transform
    transforms: [someTransform], 
    material: someMaterial,
    flags: .default
)
canvas.insert(command)

Resource Cache Change

The .whileReferenced cache hint will now destroy resources as soon as their reference count reaches zero.
Previously they would all be garbage collected every 1 minute.
If you experience a change in your project you can change the affected resource to work the old way by changing the cache hint.

let myResource = Geometry(path: "MyModel.obj")
myResource.cacheHint = .until(minutes: 1)

More resources have been migrated to the standard cache system.
Skeleton
Contains animatable joint information for a skinned character.

let skeleton = Skeleton(path: "MyCharacter.gltf")

SkeletalAnimation
Contains the transforms for joints that together form an animation for a skeleton

let animation = SkeletalAnimation(path: "MyCharacter.gltf", options: .named("Running"))

Together they eliminate the need to use async functions to load skinned characters.

entity.insert(Rig3DComponent.self) { component in
    component.skeleton = Skeleton(path: "Cat.glb")
    component.animationSet = [SkeletalAnimation(path: "Cat.glb")]
    component.activeAnimation = Rig3DAnimation(component.animationSet![0], repeats: true)
}

ResourceConstrainedComponent

An alternative Component protocol is available.
This protocol gives components the ability to declare their Resources.

component(ofType:_) will now return nil if any resource it uses is not .ready.

if let component = entity.component(ofType: Rig3DComponent.self) {
  // Skeleton and all SkeletalAnimations are ready
}else{
  // A resource was not ready
}

This will eliminate boilerplate since these components can't be used without their resources.
Note:
For now, using the subscript entity[Rig3DComponent.self] will still return the component no matter the state.

PerformanceRenderingSystem

The PerformanceRenderingSystem will now show some additional information.

  • Count of all resources currently loading
  • Count of Skeletons in cache
  • Count of SkeletalAnimations in cache
  • Count of TileSets in cache
  • Count of TileMaps in cache

Mutable Geometry Variants

MutableGeometry has been available for a while, and is useful for changing geometry dynamically.
New variants are now available as MutablePoints and MutableLines.

Entity Cleanup

System subclasses can now override a function that is called when an entity is removed from the game.
This gives you an opportunity to preform System specific cleanup.

override func gameDidRemove(entity: Entity, game: Game, input: HID) async {
    // Do entity cleanup
}

Immediate Geometry

GateEngine currently caches all geometry, a process that requires at least 1 game tick to complete.
So the geometry would not draw until the next frame.

This works great for file loaded geometry.
However sometimes you just want to draw a few primitives directly to a RenderTarget immediately.

You can now create a Geometry object from RawGeometry and have it block until its state is .ready.
For simple geometry there would be no significant delay.

// geometry.state is instantly .ready and it will 
// be drawable during the frame it was created in
let geometry = Geometry(rawGeometry, immediate: true)

This method is helpful for generating content once, such as building a UI element off screen and then rendering it as a texture every frame.

Quality Of Life (macOS)

The main window will now be restored to the display that it was on when it was last open.
This means if you have multiple displays you will no longer need to drag the game back to display 2 every launch.
This change will only effect Debug builds.

Bug Fixes

Metal Renderer

  • Fixed an issue where geometry could be drawn with incorrect layout and shaders

Skinning

  • Fixed a bug in the included skinning vertex shader

macOS/iOS/tvOS

  • Fixed an issue where playing spatial sounds before starting music would cause a crash.

Linux/HTML5

  • Fixed an issue where textures in channel(1) or greater would use the texture in channel(0).
  • Fixed an issue where renderTarget textures used in Sprites would draw upside down.
  • Fixed an issue where UVs could snap to an incorrect pixel on low res textures.

General

  • Fixed an issue where a previously modified cacheHint would revert back to default when creating a new reference to the same resource.
  • Cache log output now shows additional details on the specifics of the cached resource.
[GateEngine] Removing cache (unused for 5 min), Texture: Assets/Weapons/Handgun1_Black_Diffuse.png, MipMapping: none
[GateEngine] Removing cache (unused for 5 min), Geometry: Assets/Weapons/Handgun1.glb, Named: Handgun1
[GateEngine] Removing cache (unused for 5 min), Geometry: Assets/Weapons/Handgun1.glb, Named: Handgun1_MuzzleFlash1