Skip to content

Commit

Permalink
Merge pull request #11 from lukewilliamboswell/subsprite
Browse files Browse the repository at this point in the history
Make sub-sprites first class
  • Loading branch information
lukewilliamboswell committed Jan 13, 2024
2 parents c344c76 + bf6f06f commit c315556
Showing 1 changed file with 59 additions and 32 deletions.
91 changes: 59 additions & 32 deletions platform/Sprite.roc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
interface Sprite
exposes [Sprite, new, blit, blitSub]
exposes [Sprite, SubRegion, new, blit, sub, subOrCrash]
imports [InternalTask, Task.{ Task }, Effect.{ Effect }]

## Represents a [sprite](https://en.wikipedia.org/wiki/Sprite_(computer_graphics)) for drawing to the screen.
Expand All @@ -10,10 +10,13 @@ interface Sprite
Sprite := {
data : List U8,
bpp : [BPP1, BPP2],
width : U32,
height : U32,
stride : U32,
region : SubRegion,
}

## A subregion of a [Sprite]
SubRegion : { srcX : U32, srcY : U32, width : U32, height : U32 }

## Create a [Sprite] to be drawn or [blit](https://en.wikipedia.org/wiki/Bit_blit) to the screen.
##
## ```
Expand All @@ -32,7 +35,18 @@ new :
height : U32,
}
-> Sprite
new = @Sprite
new = \{ data, bpp, width, height } ->
@Sprite {
data,
bpp,
stride: width,
region: {
srcX: 0,
srcY: 0,
width,
height,
},
}

## Draw a [Sprite] to the framebuffer.
##
Expand All @@ -42,7 +56,8 @@ new = @Sprite
##
## [Refer w4 docs for more information](https://wasm4.org/docs/reference/functions#blit-spriteptr-x-y-width-height-flags)
blit : Sprite, { x : I32, y : I32, flags ? List [FlipX, FlipY, Rotate] } -> Task {} []
blit = \@Sprite { data, bpp, width, height }, { x, y, flags ? [] } ->
blit = \@Sprite { data, bpp, stride, region }, { x, y, flags ? [] } ->
{ srcX, srcY, width, height } = region

format =
when bpp is
Expand All @@ -56,40 +71,52 @@ blit = \@Sprite { data, bpp, width, height }, { x, y, flags ? [] } ->
FlipY -> Num.bitwiseOr state 4
Rotate -> Num.bitwiseOr state 8

Effect.blit data x y width height combined
Effect.blitSub data x y width height srcX srcY stride combined
|> Effect.map Ok
|> InternalTask.fromEffect

## Draw a sub-region of a larger [Sprite] to the framebuffer. Similar to [blit] but with additional parameters.
## Creates a [Sprite] referencing a subregion of the current [Sprite].
## This will return an error if the subregion does not fit in the current [Sprite].
##
## ```
## {} <- Sprite.blitSub {
## x: 0,
## y: 0,
## srcX: 0,
## srcY: 0,
## width: 8,
## height: 8,
## flags: [FlipX, Rotate],
## } |> Task.await
## subSpriteResult = Sprite.sub sprite { srcX: 20, srcY: 0, width: 20, height: 20 }
## ```
##
## [Refer w4 docs for more information](https://wasm4.org/docs/reference/functions#blitsub-spriteptr-x-y-width-height-srcx-srcy-stride-flags)
blitSub : Sprite, { x : I32, y : I32, srcX : U32, srcY : U32, width : U32, height : U32, flags ? List [FlipX, FlipY, Rotate] } -> Task {} []
blitSub = \@Sprite { data, bpp, width: stride }, { x, y, srcX, srcY, width, height, flags ? [] } ->
## Note: If your program should never generate an invalid subregion,
## [subOrCrash] enables avoiding the result and simpler code.
##
sub : Sprite, SubRegion -> Result Sprite [OutOfBounds]
sub = \@Sprite sprite, subRegion ->
currentRegion = sprite.region

format =
when bpp is
BPP1 -> 0
BPP2 -> 1
outOfBoundX = subRegion.srcX + subRegion.width > currentRegion.width
outOfBoundY = subRegion.srcY + subRegion.height > currentRegion.height

combined =
List.walk flags format \state, flag ->
when flag is
FlipX -> Num.bitwiseOr state 2
FlipY -> Num.bitwiseOr state 4
Rotate -> Num.bitwiseOr state 8
if outOfBoundX || outOfBoundY then
Err OutOfBounds
else
newRegion = {
srcX: currentRegion.srcX + subRegion.srcX,
srcY: currentRegion.srcY + subRegion.srcY,
width: subRegion.width,
height: subRegion.height,
}
Ok (@Sprite { sprite & region: newRegion })

Effect.blitSub data x y width height srcX srcY stride combined
|> Effect.map Ok
|> InternalTask.fromEffect
## Equivalent to the [sub] function, but will crash on error.
## This is really useful for static sprite sheet data that needs subSprites extracted.
##
## ```
## subSprite = Sprite.subOrCrash sprite { srcX: 20, srcY: 0, width: 20, height: 20 }
## ```
##
## Warning: Will crash if the subregion is not contained within the sprite.
##
subOrCrash : Sprite, SubRegion -> Sprite
subOrCrash = \sprite, subRegion ->
when sub sprite subRegion is
Ok x ->
x

Err OutOfBounds ->
crash "Out of bounds subregion when generating subsprite"

0 comments on commit c315556

Please sign in to comment.