~exelotl/natu-examples

cb096b6ecd90ad6f7ebf3b38bc00a082fb2e6ab7 — Jeremy Clarke 1 year, 10 months ago
init
A  => .gitignore +13 -0
@@ 1,13 @@
.vscode/
.sync/
wip/
output/
build/
nimcache/
*.elf
*.elf.map
*.gba
*.sav
*.DS_Store
*.out
*.exe

A  => LICENSE +17 -0
@@ 1,17 @@
Copyright (C) 2020-2022 Jeremy Clarke

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

A  => README.md +13 -0
@@ 1,13 @@
These are the examples for the [Natu](https://natu.exelo.tl/) Game Boy Advance development toolkit.

## Building

To build these examples, first install Natu by following the instructions on the website.

Then:

```sh
$ git clone https://git.sr.ht/~exelotl/natu-examples
$ cd natu-examples
$ nim build_examples
```

A  => anim_coins/anim_coins.nim +124 -0
@@ 1,124 @@
## Animated Coins Example
## ======================
## This example demonstrates another technique for animated sprites.
## - All frames of animation are copied into VRAM.
## - Each object's tile ID is set to the appropriate tile in VRAM for its current frame of animation.
##
## This can be great when you have many sprites of the same kind onscreen at once,
## provided your spritesheet has relatively few frames.
##
## It's also light on CPU usage compared to the streaming approach from the `anim_sprite` example.
##
## Coin sprite by GrafxKid: https://opengameart.org/users/grafxkid
## Image data produced via grit:
## ::
##   grit coin.png -gB4 -pn16
##

import natu/[video, bios, irq, math, utils]

{.compile: "coin.s".}
var coinTiles {.importc: "coinTiles".}: array[128, uint32]
var coinPal {.importc: "coinPal".}: array[16, uint16]

const coinAnimFrames = 0..3
const coinNumTiles = 2*2

# Memory locations used by coin sprites:
# (in a real project these should come from allocators of some kind)
const tid = 0  # base tile in object VRAM
const pal = 0  # palette slot

type
  Coin = object
    ## Each coin has a position, speed, and some animation counters.
    ## To give the coins a variety of speeds, we use fixed-point arithmetic.
    pos: Vec2f
    fallSpeed: Fixed
    animFrame: int
    animTimer: int
    animSpeed: int

proc init(c: var Coin) =
  ## Set up a coin object. All properties are randomized.
  c.pos = vec2f(
    fp(rand(0, 224)),
    fp(rand(0, 160))
  )
  c.fallSpeed = rand(200, 300).Fixed
  c.animFrame = rand(coinAnimFrames.a, coinAnimFrames.b+1)
  c.animSpeed = rand(4, 8)
  c.animTimer = rand(1, c.animSpeed+1)

proc update(c: var Coin) =
  
  # advance coin animation timer/frame
  dec c.animTimer
  if c.animTimer <= 0:
    c.animTimer = c.animSpeed
    inc c.animFrame
    if c.animFrame > coinAnimFrames.b:
      c.animFrame = coinAnimFrames.a
  
  # move coin vertically, wrap at bottom of screen
  c.pos.y += c.fallSpeed
  if c.pos.y > fp(160):
    c.pos.y = fp(-16)
    c.pos.x = fp(rand(0, 224))


proc draw(c: var Coin, oid: int) =
  # apply attributes to sprite in OAM
  # note that we point to a different tile in VRAM depending on which anim frame we are on.
  objMem[oid].init:
    pos = vec2i(c.pos)
    size = s16x16
    tid = tid + c.animFrame * coinNumTiles
    pal = pal


var coins {.noinit.}: array[40, Coin]


proc main() =
  
  irq.enable(iiVBlank)
  
  # enable sprites with 1d mapping
  dispcnt.init:
    obj = true
    obj1d = true
  
  # copy palette into object PAL RAM
  memcpy16(addr objPalMem[pal], addr coinPal, coinPal.len)
  
  # copy all frames into object VRAM
  memcpy32(addr objTileMem[tid], addr coinTiles, coinTiles.len)
  
  # initialize coins
  for coin in mitems(coins):
    coin.init()
  
  while true:
    
    # update the positions and frames of all coins
    for coin in mitems(coins):
      coin.update()
    
    VBlankIntrWait()
    
    # sprite counter (object id)
    var oid = 0
    
    # draw all coins, each call to draw also increments the sprite counter
    for coin in mitems(coins):
      coin.draw(oid)
      inc oid
    
    # hide remaining sprites
    while oid < objMem.len:
      objMem[oid].hide()
      inc oid
  

main()

A  => anim_coins/coin.png +0 -0
A  => anim_coins/coin.s +48 -0
@@ 1,48 @@

@{{BLOCK(coin)

@=======================================================================
@
@	coin, 16x64@4, 
@	+ palette 16 entries, not compressed
@	+ 16 tiles not compressed
@	Total size: 32 + 512 = 544
@
@	Time-stamp: 2020-01-14, 12:34:26
@	Exported by Cearn's GBA Image Transmogrifier, v0.8.15
@	( http://www.coranac.com/projects/#grit )
@
@=======================================================================

	.section .rodata
	.align	2
	.global coinTiles		@ 512 unsigned chars
	.hidden coinTiles
coinTiles:
	.word 0x11100000,0x22211000,0x22222100,0x33322210,0x44434210,0x44443441,0x44443441,0x44443441
	.word 0x00000111,0x00011222,0x00122222,0x01222333,0x01243444,0x14434444,0x14434444,0x14434444
	.word 0x44443441,0x44443441,0x44444431,0x44423310,0x22233310,0x33333100,0x33311000,0x11100000
	.word 0x14434444,0x14434444,0x13444444,0x01332444,0x01333222,0x00133333,0x00011333,0x00000111
	.word 0x11000000,0x22100000,0x22210000,0x44210000,0x24421000,0x22421000,0x22421000,0x22421000
	.word 0x00000011,0x00000122,0x00001222,0x00001242,0x00014442,0x00014442,0x00013442,0x00013442
	.word 0x22421000,0x22421000,0x22421000,0x24241000,0x22410000,0x33310000,0x33100000,0x11000000
	.word 0x00013442,0x00013342,0x00013342,0x00013342,0x00001334,0x00001333,0x00000133,0x00000011

	.word 0x10000000,0x21000000,0x21000000,0x21000000,0x41000000,0x41000000,0x41000000,0x41000000
	.word 0x00000001,0x00000012,0x00000012,0x00000012,0x00000014,0x00000014,0x00000013,0x00000013
	.word 0x41000000,0x31000000,0x31000000,0x31000000,0x31000000,0x31000000,0x31000000,0x10000000
	.word 0x00000013,0x00000013,0x00000013,0x00000013,0x00000013,0x00000013,0x00000013,0x00000001
	.word 0x11000000,0x22100000,0x22210000,0x42210000,0x34221000,0x34221000,0x34221000,0x34421000
	.word 0x00000011,0x00000142,0x00001444,0x00001333,0x00013333,0x00013333,0x00013433,0x00013433
	.word 0x34421000,0x34421000,0x34441000,0x34441000,0x33410000,0x33310000,0x33100000,0x11000000
	.word 0x00013433,0x00013433,0x00013433,0x00013343,0x00001333,0x00001333,0x00000133,0x00000011

	.section .rodata
	.align	2
	.global coinPal		@ 32 unsigned chars
	.hidden coinPal
coinPal:
	.hword 0x0000,0x0842,0x77BE,0x0DBD,0x1EFE,0x0000,0x0000,0x0000
	.hword 0x0421,0x0421,0x0421,0x0421,0x0421,0x0421,0x0421,0x0421

@}}BLOCK(coin)

A  => anim_coins/config.nims +31 -0
@@ 1,31 @@
import os, strutils
import natu/config

const main = "anim_coins.nim"         # path to project file
const name = splitFile(main).name      # name of ROM

put "natu.gameTitle", "ANIMCOINS"     # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"

A  => anim_sprite/anim_sprite.nim +154 -0
@@ 1,154 @@
## Animated Sprite Example
## =======================
## This example demonstrates a technique for animated sprites on the GBA:
## Make sure you're comfortable with the `move_sprite` example before tackling this!
##
## How it works:
## - In VRAM, we allocate enough space for 1 frame of animation.
## - Each VBlank, we copy the current frame into this space, replacing the previous contents.
## 
## This is ideal for sprites like the player character, who may have hundreds of frames of animation,
##  which would not all fit into VRAM at once.
##
## For a more thorough breakdown of this approach, see:
## https://pineight.com/gba/managing-sprite-vram.txt
##
## Twiggy spritesheet by GrafxKid: https://opengameart.org/users/grafxkid
## Image data (twiggy.s) is produced using `grit` in the terminal:
## ::
##    grit twiggy.png -gB4 -pn16
## 

import natu/[video, bios, irq, math, utils]

# Include the spritesheet in the build, make the data available to Nim
{.compile: "twiggy.s".}
var twiggyTiles {.importc: "twiggyTiles".}: array[3328, uint32]
var twiggyPal {.importc: "twiggyPal".}: array[16, uint16]


# Animation data
# --------------
# An animation is a list of frames in the spritesheet.
# Nim doesn't have good support for addressable constant data, so if we want
#  to put our animation data in ROM, we must use C as a work around.

type
  AnimDataPtr = ptr AnimData
  AnimData {.bycopy, exportc.} = object
    frames: ptr UncheckedArray[uint16]
    len: int
    speed: int

# Use emit to produce C code.
{.emit:"""
static const AnimData animIdleData = {
  .frames = (const NU16[]){1,3,4,5},
  .len = 4,
  .speed = 7,
};
static const AnimData animWalkData = {
  .frames = (const u16[]){13,14,15,16,17,18},
  .len = 6,
  .speed = 4,
};
static const AnimData *animIdle = &animIdleData;
static const AnimData *animWalk = &animWalkData;
""".}

# Bring the variables from C back into Nim
var animIdle {.importc, nodecl.}: AnimDataPtr
var animWalk {.importc, nodecl.}: AnimDataPtr


# Animation state
# ---------------

type Anim = object
  ## Holds the current state of an animation.
  data: AnimDataPtr
  pos: int
  timer: int

proc initAnim(data: AnimDataPtr): Anim {.noinit.} =
  result.data = data
  result.timer = data.speed + 1
  result.pos = 0

proc frame(a: Anim): int {.inline.} =
  ## Get the current frame number within the sprite sheet.
  a.data.frames[a.pos].int

proc update(a: var Anim) =
  ## Progress anim timer, advance to the next frame if necessary.
  if a.timer > 0:
    dec a.timer
  else:
    inc a.pos
    if a.pos >= a.data.len:
      a.pos = 0
    a.timer = a.data.speed


# Current animation state of the player:
var anim = initAnim(animWalk)
var cooldown = 180

proc updatePlayerAnim() =
  # Toggle between walking and idling every 3 seconds
  dec cooldown
  if cooldown <= 0:
    if anim.data == animIdle:
      anim = initAnim(animWalk)
    else:
      anim = initAnim(animIdle)
    cooldown = 180
  # Progress the animation
  anim.update()


# Memory locations used by our sprite:
# (in a real project these should come from allocators of some kind)
const tid = 0  # base tile in object VRAM
const oid = 0  # OAM entry number
const pal = 0  # palette slot

# amount of memory taken up by 1 frame of animation
const framePixels = 32*32
const frameBytes = framePixels div 2
const frameWords = frameBytes div sizeof(uint32)


proc main() =
  
  irq.enable(iiVBlank)
  
  # enable sprites with 1d mapping
  dispcnt.init:
    obj = true
    obj1d = true
  
  # copy palette into Object PAL RAM
  memcpy16(addr objPalMem[pal], addr twiggyPal, twiggyPal.len)
  
  # copy an initial frame into Object VRAM
  memcpy32(addr objTileMem[tid], addr twiggyTiles, frameWords)
  
  # hide all sprites
  for obj in mitems(objMem):
    obj.hide()
  
  # set up sprite
  objMem[oid].init:
    pos = vec2i(100, 60)
    size = s32x32
    tid = tid
    pal = pal
  
  while true:
    updatePlayerAnim()
    VBlankIntrWait()
    # Copy current frame of animation into Object VRAM (replacing the old frame)
    memcpy32(addr objTileMem[tid], addr twiggyTiles[anim.frame * frameWords], frameWords)

main()

A  => anim_sprite/config.nims +31 -0
@@ 1,31 @@
import os, strutils
import natu/config

const main = "anim_sprite.nim"         # path to project file
const name = splitFile(main).name      # name of ROM

put "natu.gameTitle", "ANIMSPRITE"     # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"

A  => anim_sprite/twiggy.png +0 -0
A  => anim_sprite/twiggy.s +498 -0
@@ 1,498 @@

@{{BLOCK(twiggy)

@=======================================================================
@
@	twiggy, 32x832@4, 
@	+ palette 16 entries, not compressed
@	+ 416 tiles not compressed
@	Total size: 32 + 13312 = 13344
@
@	Time-stamp: 2020-01-14, 12:05:21
@	Exported by Cearn's GBA Image Transmogrifier, v0.8.15
@	( http://www.coranac.com/projects/#grit )
@
@=======================================================================

	.section .rodata
	.align	2
	.global twiggyTiles		@ 13312 unsigned chars
	.hidden twiggyTiles
twiggyTiles:
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000111
	.word 0x32210000,0x22210000,0x22310000,0x22100000,0x23100000,0x31000000,0x10000000,0x00000000
	.word 0x00000001,0x00000012,0x11110132,0x22221322,0x52222432,0x22222463,0x22222261,0x32222221
	.word 0x10000000,0x21000000,0x23101111,0x22312222,0x23422225,0x36422222,0x16222222,0x12222223
	.word 0x00001223,0x00001222,0x00001322,0x00000122,0x00000132,0x00000013,0x00000001,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222321,0x55173221,0x55155231,0x55155210,0x15557310,0x55573100,0x77111000,0x54461000
	.word 0x12322237,0x12237155,0x13255155,0x01255155,0x01375551,0x00137555,0x00011177,0x00016445
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44446100,0x44655100,0x44647510,0x99875510,0x18911100,0x01710000,0x01441000,0x01111000
	.word 0x00164444,0x00155644,0x01574644,0x01557899,0x00111981,0x00001710,0x00014410,0x00011110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x21000000,0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00000132,0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x33310000,0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000
	.word 0x32234732,0x17715551,0x15515551,0x15515551,0x17555115,0x01755555,0x00111177,0x00001655
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44461000,0x46551000,0x46755100,0x98555100,0x99111000,0x17100000,0x14410000,0x11110000
	.word 0x00016444,0x00017444,0x00177444,0x00177899,0x00011881,0x00001410,0x00016610,0x00011110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00001110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00013331,0x00133331,0x11133331,0x22266310,0x25522610,0x22222210,0x22222221,0x22222221
	.word 0x23100000,0x22210000,0x22231111,0x22224322,0x32234422,0x16364422,0x13644222,0x13322222
	.word 0x00000012,0x00000012,0x00000013,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22222221,0x22222221,0x22222231,0x32223210,0x33333310,0x33331100,0x71110000,0x46100000
	.word 0x13222222,0x01222222,0x01222222,0x01222222,0x01223333,0x00133333,0x00011177,0x00001644
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44610000,0x44710000,0x44710000,0x98710000,0x88100000,0x14100000,0x16610000,0x11110000
	.word 0x00016444,0x00015564,0x00155764,0x00155589,0x00011991,0x00001710,0x00014410,0x00011110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x21000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000132
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000,0x33310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001
	.word 0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310,0x22322210
	.word 0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000,0x44461000
	.word 0x17715551,0x15515551,0x15515551,0x17555115,0x01755555,0x00111177,0x00001655,0x00016444
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x46441000,0x46551000,0x98755100,0x99555100,0x17111000,0x14100000,0x01410000,0x00110000
	.word 0x00016444,0x00017444,0x00177899,0x00177881,0x00011410,0x00001610,0x00016100,0x00011000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x21000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000132
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000,0x33310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001
	.word 0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310,0x22322210
	.word 0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000,0x44461000
	.word 0x17715551,0x15515551,0x15515551,0x17555115,0x01755555,0x00111177,0x00001655,0x00016444
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x46551000,0x46755100,0x98555100,0x99111000,0x17100000,0x14100000,0x01410000,0x00110000
	.word 0x00017444,0x00177444,0x00177899,0x00011881,0x00001410,0x00001610,0x00016100,0x00011000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000122
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01100000,0x13310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x00013222,0x11112222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x13331000,0x13333100,0x13333111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44461000
	.word 0x32234732,0x17715551,0x15515551,0x15515551,0x17555115,0x01755555,0x00111177,0x00016455
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44551000,0x46755100,0x46555100,0x98111000,0x99100000,0x17100000,0x14410000,0x11110000
	.word 0x00017444,0x00177444,0x00177444,0x00011899,0x00001881,0x00001410,0x00016610,0x00011110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01110000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22100000,0x22100000,0x23100000,0x21000000,0x31000000,0x10000000,0x00000000,0x00000000
	.word 0x00000013,0x11000122,0x22111322,0x22234222,0x22224322,0x22224633,0x22322461,0x73222210
	.word 0x13331000,0x13333111,0x13325522,0x12222222,0x22222222,0x22223222,0x32234732,0x17715551
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x57222210,0x55222100,0x55233100,0x55331000,0x57711100,0x71115510,0x44445510,0x44655510
	.word 0x15515551,0x15515551,0x17551115,0x01755145,0x01117555,0x01771177,0x11776455,0x17776444
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x46111100,0x46100000,0x98100000,0x88811000,0x11461000,0x00161000,0x00011000,0x00000000
	.word 0x01111444,0x00001444,0x00019999,0x00144781,0x00016410,0x00001100,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000122,0x00001222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01100000,0x13310000,0x13331000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x10000000,0x10000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00013222,0x11112222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310,0x22322210
	.word 0x13333100,0x13333111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222210,0x57222310,0x15222100,0x55233100,0x57331000,0x71110000,0x44610000,0x55510000
	.word 0x17755555,0x15555555,0x15115551,0x17555155,0x01755555,0x00111177,0x00011455,0x00177444
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x55710000,0x46100000,0x98100000,0x88110000,0x14610000,0x01610000,0x00110000,0x00000000
	.word 0x00177444,0x00011444,0x00001999,0x00019981,0x00144710,0x00016410,0x00001100,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x00000000
	.word 0x00000011,0x00000122,0x00001222,0x00013222,0x11112222,0x22342222,0x22443223,0x22446331
	.word 0x01100000,0x13310000,0x13331000,0x13333100,0x13333111,0x13662222,0x16225522,0x12222222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22244610,0x22222310,0x22322210,0x73222210,0x57222310,0x15222100,0x55233100,0x57331000
	.word 0x22222222,0x22223222,0x32234732,0x17755555,0x15555555,0x15115551,0x17555115,0x01755555
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x71110000,0x55510000,0x55710000,0x46100000,0x46100000,0x98100000,0x44100000,0x11100000
	.word 0x00111177,0x00177457,0x00177444,0x00011444,0x00001444,0x00001999,0x00001664,0x00001111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x10000000,0x21000000,0x21000000,0x31000000,0x10000000,0x10000000,0x00000000
	.word 0x00000000,0x00000011,0x00000132,0x00001222,0x11113222,0x22342222,0x22443223,0x22446331
	.word 0x00000000,0x11100000,0x33310000,0x33331000,0x33331111,0x13662222,0x16225522,0x12222222
	.word 0x00000000,0x00000000,0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22244610,0x22222310,0x22322210,0x73222210,0x57222310,0x15222100,0x55233100,0x57331000
	.word 0x22222222,0x22223222,0x32234732,0x17755555,0x15555555,0x15115551,0x17555115,0x01755555
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x71110000,0x44610000,0x55510000,0x55710000,0x46100000,0x98100000,0x44100000,0x11100000
	.word 0x00111177,0x00011455,0x00177444,0x00177444,0x00011444,0x00001999,0x00001664,0x00001111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000122,0x00001222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01100000,0x13310000,0x13331000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x10000000,0x10000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00013222,0x11112222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310,0x22322210
	.word 0x13333100,0x13333111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x13222210,0x57222310,0x11222100,0x55233100,0x57331000,0x71110000,0x55610000,0x55751000
	.word 0x17155555,0x15515551,0x11115551,0x17555155,0x01755555,0x00111177,0x01551457,0x01556444
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x55771000,0x46110000,0x98100000,0x99100000,0x71000000,0x41000000,0x10000000,0x00000000
	.word 0x01555445,0x00111444,0x00001899,0x00018889,0x00144744,0x00016616,0x00001101,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x00000000
	.word 0x00000011,0x00000122,0x00001222,0x00013222,0x11112222,0x22342222,0x22443223,0x22446331
	.word 0x01100000,0x13310000,0x13331000,0x13333100,0x13333111,0x13662222,0x16225522,0x12222222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22244610,0x22222310,0x22322210,0x73222210,0x57222310,0x15222100,0x55233100,0x57331000
	.word 0x22222222,0x22223222,0x32234732,0x17755555,0x15555555,0x15115551,0x17555115,0x01755555
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x71110000,0x44610000,0x44410000,0x46461000,0x66751000,0x88551000,0x88755100,0x11111100
	.word 0x00111177,0x00001655,0x00017644,0x00155744,0x00179986,0x00017499,0x00144111,0x00111100
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x10000000,0x21000000,0x21000000,0x31000000,0x10000000,0x10000000,0x00000000
	.word 0x00000000,0x00000011,0x00000132,0x00001222,0x11113222,0x22342222,0x22443223,0x22446331
	.word 0x00000000,0x11100000,0x33310000,0x33331000,0x33331111,0x13662222,0x16225522,0x12222222
	.word 0x00000000,0x00000000,0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22244610,0x22222310,0x22322210,0x73222210,0x57222310,0x15222100,0x55233100,0x57331000
	.word 0x22222222,0x22223222,0x32234732,0x17755555,0x15555555,0x15115551,0x17555115,0x01755555
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x71110000,0x44610000,0x44410000,0x46461000,0x66751000,0x88551000,0x88755100,0x11111100
	.word 0x00111177,0x00001655,0x00017644,0x00155744,0x00179986,0x00017499,0x00144111,0x00111100
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x21000000,0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00000132,0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x33310000,0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x46100000
	.word 0x32234732,0x17715551,0x15515551,0x15515551,0x17555155,0x01755555,0x00111177,0x00001655
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44610000,0x66710000,0x55510000,0x55710000,0x91100000,0x41000000,0x11000000,0x10000000
	.word 0x00001444,0x00001444,0x00017444,0x00017899,0x00001189,0x00000014,0x00000166,0x00000111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x21000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000132
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000,0x33310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001
	.word 0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310,0x22322210
	.word 0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000,0x44471000
	.word 0x17715551,0x15515551,0x15515551,0x17555155,0x01755555,0x00111177,0x00011455,0x00157444
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x46751000,0x46551000,0x98110000,0x81000000,0x10000000,0x10000000,0x00000000,0x00000000
	.word 0x00157444,0x00011444,0x00001899,0x00001899,0x00001447,0x00000164,0x00000011,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000122
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01100000,0x13310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x00013222,0x11112222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x13331000,0x13333100,0x13333111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000
	.word 0x32234732,0x17715551,0x15515551,0x15515551,0x17555155,0x01755555,0x00111177,0x00001655
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44710000,0x55510000,0x55710000,0x98100000,0x81000000,0x61000000,0x11000000,0x10000000
	.word 0x00011444,0x00157444,0x00157444,0x00011899,0x00000199,0x00000017,0x00000144,0x00000111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x21000000,0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00000132,0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x33310000,0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000
	.word 0x32234732,0x17715551,0x15515551,0x15515551,0x17555155,0x01755555,0x00111177,0x00001655
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x55510000,0x55710000,0x46100000,0x98100000,0x99100000,0x17100000,0x44100000,0x11100000
	.word 0x00001444,0x00001444,0x00017444,0x00017899,0x00001188,0x00000166,0x00000111,0x00000001
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x21000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000132
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000,0x33310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001
	.word 0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310,0x22322210
	.word 0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x44610000,0x55710000
	.word 0x17715551,0x15515551,0x15515551,0x17555155,0x01755555,0x00111177,0x00001657,0x00001445
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x57100000,0x66100000,0x98100000,0x88811000,0x11461000,0x00161000,0x00011000,0x00000000
	.word 0x00001445,0x00001444,0x00001999,0x00019981,0x00144710,0x00016410,0x00001100,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011,0x00000122
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01100000,0x13310000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00001222,0x00013222,0x11112222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x13331000,0x13333100,0x13333111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x55222100,0x55233100,0x57331000,0x71110000,0x46100000
	.word 0x32234732,0x17715551,0x15515551,0x15515551,0x17555155,0x01755555,0x00111177,0x00001655
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44610000,0x55710000,0x57100000,0x98110000,0x88610000,0x11610000,0x00110000,0x00000000
	.word 0x00001444,0x00001445,0x00001445,0x00001999,0x00001991,0x00001710,0x00014410,0x00011110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00001110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00013331,0x00133331,0x11133331,0x22266310,0x25522610,0x22222210,0x22222221,0x22322221
	.word 0x31000000,0x22100000,0x22311111,0x22243222,0x22344222,0x33644222,0x16442222,0x13222222
	.word 0x00000122,0x00000122,0x00000132,0x00000012,0x00000013,0x00000001,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x37432231,0x55517710,0x55515510,0x55515510,0x51555710,0x55557100,0x71111000,0x44610000
	.word 0x12223222,0x12222371,0x13222751,0x01222551,0x01332555,0x00133755,0x00011177,0x00001657
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x55710000,0x57100000,0x66100000,0x98100000,0x88100000,0x14410000,0x01661000,0x01111000
	.word 0x00016445,0x11156445,0x15557444,0x01178999,0x00019911,0x00017100,0x00144100,0x00111100
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00111100,0x01222210,0x13222210,0x42222310,0x43222100,0x46331000
	.word 0x00000000,0x00000000,0x00000000,0x10000000,0x31111111,0x22222223,0x22222224,0x55222224
	.word 0x00000000,0x00000000,0x00001111,0x00013333,0x00013333,0x00013336,0x00001362,0x00001622
	.word 0x00000000,0x00000000,0x11000000,0x89111000,0x69874100,0x49954410,0x68977610,0x11111110
	.word 0x44610000,0x22310000,0x22211111,0x22344446,0x22677644,0x33557764,0x35555764,0x11111111
	.word 0x22222222,0x23222222,0x34432223,0x77777732,0x17771172,0x55555552,0x55555573,0x11111111
	.word 0x00001222,0x00001222,0x00001322,0x00000147,0x00000171,0x00000175,0x00000017,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x10000000,0x21000000,0x21000000,0x21000000,0x21000000,0x21000000,0x31000000
	.word 0x00000000,0x00000001,0x00000012,0x00000122,0x00001322,0x11111222,0x22234222,0x22244322
	.word 0x00000000,0x00110000,0x01331000,0x01333100,0x01333310,0x01333311,0x01366222,0x01622552
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x10000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22244633,0x22224461,0x22222231,0x22232221,0x17322221,0x15722231,0x15522210,0x55523310
	.word 0x01222222,0x12222222,0x12222322,0x13223473,0x01771555,0x01551555,0x01551555,0x01755515
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x55733100,0x77111000,0x54461000,0x44646100,0x66675100,0x49855100,0x67875510,0x11111110
	.word 0x00175555,0x00011117,0x00001645,0x00116664,0x01446644,0x01668866,0x00164886,0x00011111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x11000000,0x22100000,0x22100000,0x23100000,0x21000000,0x31000000
	.word 0x00000000,0x00000000,0x00000001,0x00000013,0x00000122,0x11111322,0x22234222,0x22244322
	.word 0x00000000,0x00000000,0x01110000,0x13331000,0x13333100,0x13333111,0x01366222,0x01622552
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x10000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22244633,0x22224461,0x22222231,0x22232221,0x17322221,0x15722231,0x15522210,0x55523310
	.word 0x01222222,0x12222222,0x12222322,0x13223473,0x01771555,0x01551555,0x01551555,0x01755515
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x55733100,0x77111000,0x54461000,0x44646100,0x66675100,0x49855100,0x67875510,0x11111110
	.word 0x00175555,0x00011117,0x00001645,0x00116664,0x01446644,0x01668866,0x00164886,0x00011111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01110000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011
	.word 0x13221000,0x22221000,0x22231000,0x22210000,0x22310000,0x33100000,0x11000000,0x10000000
	.word 0x00000000,0x00000001,0x11111013,0x22222132,0x55222243,0x22222246,0x22222226,0x33222222
	.word 0x31000000,0x22100000,0x22310111,0x22231222,0x22342222,0x33642222,0x11622222,0x01222222
	.word 0x00000122,0x00000122,0x00000132,0x00000012,0x00000013,0x00000001,0x00000000,0x00000000

	.word 0x10000000,0x10000000,0x10000000,0x00000000,0x00000000,0x10000000,0x51000000,0x71000000
	.word 0x77322232,0x55557322,0x55717523,0x55151521,0x11555731,0x15557351,0x77711157,0x55444657
	.word 0x01232223,0x01223715,0x01325515,0x00125515,0x00137555,0x00013755,0x00001111,0x00000016
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x51000000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44446775,0x44461111,0x44461000,0x99981000,0x81991000,0x10171000,0x00144100,0x00111100
	.word 0x00000164,0x00111564,0x00155574,0x00011718,0x00000118,0x00000144,0x00001661,0x00001111
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x11000000,0x22100000,0x22100000,0x23100000,0x21000000,0x31000000,0x10000000,0x00000000
	.word 0x00000001,0x00000013,0x11000122,0x22111322,0x22234222,0x22224322,0x22224633,0x22322461
	.word 0x01110000,0x13331000,0x13333111,0x13325522,0x12222222,0x22222222,0x22223222,0x32234732
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x73222210,0x57222210,0x55222100,0x55233100,0x55331000,0x57710000,0x71100000,0x44610000
	.word 0x17715551,0x15515551,0x15515551,0x17555115,0x01755555,0x00117555,0x00001177,0x00001655
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44461000,0x46551000,0x46755100,0x98555100,0x99111000,0x17100000,0x14410000,0x11110000
	.word 0x00016444,0x00017444,0x00177444,0x00177899,0x00011881,0x00001410,0x00016610,0x00011110
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000011
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x11100000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x21000000,0x21000000,0x31000000,0x10000000,0x10000000,0x00000000,0x00000000,0x00000000
	.word 0x00000132,0x00001222,0x11113222,0x22342222,0x22443223,0x22446331,0x22244610,0x22222310
	.word 0x33310000,0x33331000,0x33331111,0x13662222,0x16225522,0x12222222,0x22222222,0x22223222
	.word 0x00000001,0x00000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000001

	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x22322210,0x73222210,0x57222310,0x15222100,0x55233100,0x57331000,0x71110000,0x44610000
	.word 0x32234732,0x17755555,0x15555555,0x15115551,0x17555115,0x01755555,0x00111177,0x00001655
	.word 0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
	.word 0x44461000,0x46551000,0x46755100,0x98555100,0x99111000,0x17100000,0x14410000,0x11110000
	.word 0x00016444,0x00017444,0x00177444,0x00177899,0x00011881,0x0000141A,0x0001661A,0x0001111A
	.word 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000

	.section .rodata
	.align	2
	.global twiggyPal		@ 32 unsigned chars
	.hidden twiggyPal
twiggyPal:
	.hword 0x0000,0x0842,0x2B96,0x1AA8,0x2D7E,0x77BE,0x1894,0x56DE
	.hword 0x1CE7,0x2D8C,0x2DD2,0x0421,0x0421,0x0421,0x0421,0x0421

@}}BLOCK(twiggy)

A  => config.nims +14 -0
@@ 1,14 @@
task build_examples, "build all examples":
  for dir in listDirs(thisDir()):
    withDir dir:
      echo dir
      selfExec "build"

task clean_examples, "remove build files for all examples":
  for dir in listDirs(thisDir()):
    withDir dir:
      selfExec "clean"

task examples, "build all examples":
  # shorthand
  buildExamplesTask()

A  => goodboy_gallery/audio.nims +8 -0
@@ 1,8 @@
# Sound effects and songs don't require any options, so
# we can build the lists automatically if desired:

for s in listFiles("samples").sorted:
  sample s

for m in listFiles("modules").sorted:
  module m

A  => goodboy_gallery/backgrounds.nims +3 -0
@@ 1,3 @@
cd "backgrounds"

background "dark_clouds.png", bkReg4bpp, flags = {bfAutoPal}

A  => goodboy_gallery/backgrounds/dark_clouds.png +0 -0
A  => goodboy_gallery/config.nims +45 -0
@@ 1,45 @@
import os, strutils, algorithm
import natu/config

const main = "source/goodboy_gallery.nim"  # path to project file
const name = splitFile(main).name          # name of ROM

put "natu.gameTitle", "GALLERY"        # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task graphics, "convert spritesheets":
  gfxConvert "graphics.nims"

task audio, "convert music and sounds":
  mmConvert "audio.nims"

task backgrounds, "convert background tilemaps":
  bgConvert "backgrounds.nims"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  graphicsTask()
  audioTask()
  backgroundsTask()
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmDir "output"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"
  
\ No newline at end of file

A  => goodboy_gallery/graphics.nims +17 -0
@@ 1,17 @@
# Config file for sprite graphics to be converted
# as part of the build process.

cd "graphics"

graphic "barrier.png", size=s32x64
graphic "gem.png", size=s32x32
graphic "player.png", size=s32x32
graphic "sacrificed_items.png", size=s32x32

sharePal:
  graphic "bullet.png", size=s8x8
  graphic "muzzle.png", size=s32x32

sharePal:
  graphic "breakable.png", size=s32x32
  graphic "shield.png", size=s64x64

A  => goodboy_gallery/graphics/barrier.png +0 -0
A  => goodboy_gallery/graphics/breakable.png +0 -0
A  => goodboy_gallery/graphics/bullet.png +0 -0
A  => goodboy_gallery/graphics/gem.png +0 -0
A  => goodboy_gallery/graphics/muzzle.png +0 -0
A  => goodboy_gallery/graphics/player.png +0 -0
A  => goodboy_gallery/graphics/sacrificed_items.png +0 -0
A  => goodboy_gallery/graphics/shield.png +0 -0
A  => goodboy_gallery/modules/subway.xm +0 -0
A  => goodboy_gallery/samples/blocked.wav +0 -0
A  => goodboy_gallery/samples/changed.wav +0 -0
A  => goodboy_gallery/source/audio.nim +34 -0
@@ 1,34 @@
import natu/[maxmod, memory]

export vblank, frame, Sample, Module

const
  channels = 16
  waveMemSize = channels * (mmSizeofModCh + mmSizeofActCh + mmSizeofMixCh) + mmMixLen31kHz 

var
  waveMem {.codegenDecl:EWRAM_DATA.}: array[waveMemSize, uint8]
  mixMem {.align:4.}: array[mmMixLen31kHz, uint8]

proc init* =
  var config = MmGbaSystem(
    mixingMode: mmMix31kHz,
    modChannelCount: channels,
    mixChannelCount: channels,
    moduleChannels: addr waveMem[0],
    activeChannels: addr waveMem[channels * mmSizeofModCh],
    mixingChannels: addr waveMem[channels * (mmSizeofModCh + mmSizeofActCh)],
    mixingMemory: addr mixMem[0],
    waveMemory: addr waveMem[channels * (mmSizeofModCh + mmSizeofActCh + mmSizeofMixCh)],
    soundbank: soundbankBin,
  )
  maxmod.init(addr config)

proc playSound*(sampleId: Sample) {.inline.} =
  maxmod.effect(sampleId)

proc playSong*(moduleId: Module) {.inline.} =
  maxmod.start(moduleId, mmPlayLoop)

proc stopSong* {.inline.} =
  maxmod.stop()

A  => goodboy_gallery/source/goodboy_gallery.nim +121 -0
@@ 1,121 @@
## Gallery Demo
## ------------
## This example demonstrates the use of Natu's asset system.
## 
## A `Graphic` enum is generated based on the "graphics.nims" config file.
## Graphics can be used at compile time and at runtime.
## 
## Similarly, enums are generated for backgrounds, music modules and samples.
## 
## While this example is still rather direct and low-level, it uses allocators
## to make managing sprite tiles and palettes easier. The Graphic enum is set
## up to work with these allocators directly.

import natu/[video, bios, irq, input, math]
import natu/[graphics, backgrounds]
import audio, simple_anim

const anims: array[Graphic, AnimData] = [
  gfxBarrier:   AnimData(first: 0, len: 10, speed: 3),
  gfxGem:       AnimData(first: 0, len: 8, speed: 4),
  gfxPlayer:    AnimData(first: 0, len: 8, speed: 5),
  gfxSacrificedItems: AnimData(first: 0, len: 8, speed: 3),
  gfxBullet:    AnimData(first: 0, len: 4, speed: 3),
  gfxMuzzle:    AnimData(first: 0, len: 8, speed: 2),
  gfxBreakable: AnimData(first: 7, len: 7, speed: 3),
  gfxShield:    AnimData(first: 0, len: 4, speed: 2),
]

var graphic: Graphic     # Current image to show
var anim: Anim           # Animation state
var obj: ObjAttr         # Sprite fields

proc initCurrentSprite(g: Graphic) =
  graphic = g
  anim = initAnim(anims[g])
  obj.init(
    pos = vec2i(120, 80) - vec2i(g.width, g.height) / 2,
    size = g.size,
    tid = allocObjTiles(g),  # Reserve enough tiles in VRAM for 1 frame of animation.
    pal = acquireObjPal(g),  # Load the palette into a slot in the PAL RAM buffer
  )

proc destroyCurrentSprite() =
  freeObjTiles(obj.tid)    # Free the tiles.
  releaseObjPal(graphic)   # Palette will also be freed only if nobody else is using it.


proc update =
  ## Run game logic
  
  if keyHit(kiLeft):
    if graphic > Graphic.low:
      playSound(sfxChanged)
      destroyCurrentSprite()
      initCurrentSprite(graphic.pred)
    else:
      playSound(sfxBlocked)
  
  if keyHit(kiRight):
    if graphic < Graphic.high:
      playSound(sfxChanged)
      destroyCurrentSprite()
      initCurrentSprite(graphic.succ)
    else:
      playSound(sfxBlocked)
  
  anim.update()


proc draw =
  ## Do graphical updates
  
  # update OAM entry
  # note: unlike in C, we can do this assignment without clobbering the affine data.
  objMem[0] = obj
  
  if anim.dirty:
    # copy a new frame into VRAM only if we're on a different
    # frame of animation than previously.
    copyFrame(addr objTileMem[obj.tid], graphic, anim.frame)
  
  # Copy palette buffers into PAL RAM.
  flushPals()


proc onVBlank =
  audio.vblank()
  draw()
  audio.frame()


proc main =
  
  # setup
  
  irq.put(iiVBlank, onVBlank)
  
  audio.init()
  
  dispcnt.init(layers = { lBg0, lObj }, obj1d = true)
  
  # Init BG0
  bgcnt[0].init(cbb = 0, sbb = 31)
  
  # Copy the tiles, map and palette
  bgcnt[0].load(bgDarkClouds)
  
  # Hide all sprites
  for obj in mitems(objMem):
    obj.hide()
  
  playSong(modSubway)
  initCurrentSprite(gfxPlayer)
  
  while true:
    keyPoll()
    update()
    VBlankIntrWait()


main()

A  => goodboy_gallery/source/simple_anim.nim +24 -0
@@ 1,24 @@

# Simple looping animation
type
  AnimData* = object
    first*, len*, speed*: int
  Anim* = object
    data*: AnimData
    frame*, timer*: int

proc initAnim*(data: AnimData): Anim =
  result.data = data
  result.frame = 0
  result.timer = data.speed + 1

proc update*(a: var Anim) =
  dec a.timer
  if a.timer < 0:
    a.timer = a.data.speed
    inc a.frame
    if a.frame >= a.data.first + a.data.len:
      a.frame = 0

proc dirty*(a: Anim): bool =
  a.timer == a.data.speed

A  => hello_world/config.nims +31 -0
@@ 1,31 @@
import os, strutils
import natu/config

const main = "hello_world.nim"         # path to project file
const name = splitFile(main).name      # name of ROM

put "natu.gameTitle", "HELLO"          # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"

A  => hello_world/hello_world.nim +12 -0
@@ 1,12 @@
import natu/[video, tte]

# show background 0
dispcnt = initDispCnt(bg0 = true)

# initialise text
tte.initChr4c(bgnr = 0, initBgCnt(cbb = 0, sbb = 31))
tte.setPos(92, 68)
tte.write("Hello World!")

while true:
  discard

A  => move_sprite/config.nims +31 -0
@@ 1,31 @@
import os, strutils
import natu/config

const main = "move_sprite.nim"         # path to project file
const name = splitFile(main).name      # name of ROM

put "natu.gameTitle", "MOVESPRITE"     # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"

A  => move_sprite/move_sprite.nim +69 -0
@@ 1,69 @@
## Sprite Example
## ==============
## This example demonstrates:
## - using the VBlank interrupt to update at 60fps without burning CPU cycles
## - loading graphics into memory
## - setting sprite attributes
## - using key functions to move the sprite around
## 
## Ship graphics by Stephen Challener (Redshrike), hosted by OpenGameArt.org
## 
## The `grit` command line tool can be used to convert an image to a representation that the hardware understands.
## i.e. 4bpp paletted, broken into 8x8px tiles which are arranged sequentially (1d mapping)
## ::
##   grit ship.png -gB4 -pn16 -ftb
##
## This produces some raw binary files that we can embed into our project using `readBin` from the utils module.

import natu/[video, bios, irq, input, math, utils]

let shipTiles = readBin("ship.img.bin")
let shipPal = readBin("ship.pal.bin")

# Memory locations used by our sprite:
const tid = 0  # base tile in object VRAM
const oid = 0  # OAM entry number
const pal = 0  # palette slot

# ship position vector
var pos = vec2i(50, 30)

# enable VBlank interrupt so we can wait for the end of the frame without burning CPU cycles
irq.enable(iiVBlank)

# enable sprites with 1d mapping
dispcnt.init(obj = true, obj1d = true)

# copy palette into Object PAL RAM
memcpy16(addr objPalMem[pal], unsafeAddr shipPal, shipPal.len div sizeof(uint16))

# copy image into Object VRAM
memcpy32(addr objTileMem[tid], unsafeAddr shipTiles, shipTiles.len div sizeof(uint32))

# hide all sprites
for obj in mitems(objMem):
  obj.hide()

# set up a sprite
let s = addr objMem[oid]
s[].init:
  pos = pos
  size = s64x64
  tid = tid
  pal = pal

while true:
  # update key states
  keyPoll()
  
  # move the ship
  if keyIsDown(kiLeft): pos.x -= 1
  if keyIsDown(kiRight): pos.x += 1
  if keyIsDown(kiUp): pos.y -= 1
  if keyIsDown(kiDown): pos.y += 1
  
  # wait for the end of the frame
  VBlankIntrWait()
  
  # update sprite position
  s[].pos = pos

A  => move_sprite/ship.img.bin +0 -0
A  => move_sprite/ship.pal.bin +0 -0
A  => move_sprite/ship.png +0 -0
A  => mystify/config.nims +31 -0
@@ 1,31 @@
import os, strutils
import natu/config

const main = "mystify.nim"             # path to project file
const name = splitFile(main).name      # name of ROM

put "natu.gameTitle", "MYSTIFY"        # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"

A  => mystify/mystify.nim +66 -0
@@ 1,66 @@
## Mode 4 Example
## ==============
## This demonstrates bitmap drawing in mode 4 with page-flipping.
## 
## Based on the 'Mystify' screensaver, we have a bunch of points
## that move around the screen and we draw lines between them.
## 
## Cool motion blur is left as an exercise to the reader :^)

import natu/[video, math, utils, bios, irq]

# set up points with random position and velocity:
var vertices: array[6, tuple[pos, vel: Vec2f]]
for v in mitems(vertices):
  v.pos = vec2f(rand(2..237), rand(2..157))
  v.vel = vec2f(rand(fp(-2)..fp(2)), rand(fp(-2)..fp(2)))

# assign palette
bgColorMem[0] = rgb5(2,4,6)      # use dark blue for backdrop color
bgColorMem[1] = rgb5(20,28,31)   # use light blue for ink color

# enable VBlank interrupt
irq.enable(iiVBlank)

# clear VRAM - only necessary to avoid visual junk when quick-launching the game
# from a flashcart, or after restarting the game via soft-reset.
RegisterRamReset({rsVram})

# enable background 2, use display mode 4 (i.e. 8bpp bitmap with page-flipping)
dispcnt.init(bg2 = true, mode = dm4)

while true:
  
  # obtain a pointer to whichever page is not currently being displayed.
  let buf: ptr M4Mem =
    if dispcnt.page: addr m4MemBack
    else: addr m4Mem
  
  buf[].clear()
  
  # begin with the final vertex.
  var prev = vertices[^1].pos
  
  # update and draw all vertices
  for v in mitems(vertices):
    
    # move by velocity
    v.pos += v.vel
    
    # bounce off screen edge
    if v.pos.x.toInt() notin 2..237: v.vel.x *= -1
    if v.pos.y.toInt() notin 2..157: v.vel.y *= -1
    
    # draw line from last point to current point.
    buf[].line(
      prev.x.toInt(), prev.y.toInt(),
      v.pos.x.toInt(), v.pos.y.toInt(),
      clrid = 1,
    )
    prev = v.pos
  
  # wait until the end of the frame
  VBlankIntrWait()
  
  # page flip:
  dispcnt.page = not dispcnt.page

A  => play_music/audio.nims +7 -0
@@ 1,7 @@
# Add all music and sounds from the audio directory.

for f in listFiles("audio").sorted:
  if f.endsWith(".wav"):
    sample f
  else:
    module f

A  => play_music/audio/shoot.wav +0 -0
A  => play_music/audio/spacecat.xm +0 -0
A  => play_music/config.nims +36 -0
@@ 1,36 @@
import os, strutils, algorithm
import natu/config

const main = "play_music.nim"         # path to project file
const name = splitFile(main).name     # name of ROM

put "natu.gameTitle", "PLAYMUSIC"     # max 12 chars, uppercase
put "natu.gameCode", "2NTP"           # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task audio, "convert music and sounds":
  mmConvert "audio.nims"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  audioTask()
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmDir "output"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"

A  => play_music/play_music.nim +42 -0
@@ 1,42 @@
## Maxmod Example
## ==============
## This example demonstrates playing music and sfx with maxmod.

import natu/[video, bios, irq, tte, input, maxmod]

proc main() =
  
  # show text on background 0
  dispcnt.init(bg0 = true)
  tte.initChr4c(bgnr = 0, initBgCnt(cbb = 0, sbb = 31))
  
  tte.write """
    Maxmod Demo
    Press A for sfx
"""
  
  # register maxmod VBlank handler
  irq.put(iiVBlank, maxmod.vblank)
  
  # init with 8 channels
  maxmod.init(soundbankBin, 8)
  
  # play music
  maxmod.start(modSpacecat, mmPlayLoop)
  
  while true:
    keyPoll()
    
    if keyHit(kiA):
      # play sound effect
      let handle = maxmod.effect(sfxShoot)
      
      # invalidate handle (allow effect to be interrupted)
      handle.release()
    
    # update maxmod
    maxmod.frame()
    
    VBlankIntrWait()

main()

A  => test_sram/config.nims +33 -0
@@ 1,33 @@
import os, strutils
import natu/config

const main = "test_sram.nim"           # path to project file
const name = splitFile(main).name      # name of ROM

put "natu.gameTitle", "TEST_SRAM"      # max 12 chars, uppercase
put "natu.gameCode", "2NTP"            # 4 chars, see GBATEK for info

if projectPath() == thisDir() / main:
  # This runs only when compiling the project file:
  gbaCfg()                             # set C compiler + linker options for GBA target
  switch "os", "standalone"
  switch "gc", "none"
  switch "checks", "off"               # toggle assertions, bounds checking, etc.
  switch "path", projectDir()          # allow imports relative to the main file
  switch "header"                      # output "{project}.h"
  switch "nimcache", "nimcache"        # output C sources to local directory
  switch "cincludes", nimcacheDir()    # allow external C files to include "{project}.h"

task build, "builds the GBA rom":
  let args = commandLineParams()[1..^1].join(" ")
  selfExec "c " & args & " -o:" & name & ".elf " & thisDir() / main
  gbaStrip name & ".elf", name & ".gba"
  gbaFix name & ".gba"

task clean, "removes build files":
  rmDir "nimcache"
  rmDir "output"
  rmFile name & ".gba"
  rmFile name & ".elf"
  rmFile name & ".elf.map"
  
\ No newline at end of file

A  => test_sram/test_sram.nim +116 -0
@@ 1,116 @@
## Save Data Example
## =================
## This example demonstrates reading and writing to cart storage.
## - Move the sprite with the D-Pad
## - Press START to save the position of the sprite
## - Power off the console
## - Next time you launch the game, the sprite should be where you left it

import natu/[bios, tte, video, irq, input, math, utils, memory]

# position of the sprite on the screen
var pos = vec2i(0, 0)

# Note: Some emulators and flashcarts try to guess what kind of storage a game uses by
#  searching for a magic string inside the ROM image.
# See http://problemkaputt.de/gbatek.htm#gbacartbackupids for more info.
# The string should begin on a word boundary.
# Inline ASM appears to be a good way to achieve this:
asm """
.balign 4
.string "SRAM_V111"
"""

# Validation:
# If the start of SRAM doesn't match the header below, we can assume the game
#  is being run for the first time, or the save file is corrupt.
const saveHeader:cstring = "test_sram"

# Note: Code that reads save data needs to be put in Work RAM.
# To do this, we can use the codegenDecl pragma to annotate the generated C function.

proc validateSave(): bool {.codegenDecl:EWRAM_CODE.} =
  for i,c in saveHeader:
    if sramMem[i].char != c:
      return false
  return true

proc newSave() =
  # Copy the header
  for i,c in saveHeader:
    sramMem[i] = c.uint8
  
  # Set the starting position for the sprite
  sramMem[0x10] = SCREEN_WIDTH div 2
  sramMem[0x11] = SCREEN_HEIGHT div 2
    
proc readSave() {.codegenDecl:EWRAM_CODE.} =
  pos.x = sramMem[0x10].int
  pos.y = sramMem[0x11].int

proc writeSave() =
  sramMem[0x10] = pos.x.uint8
  sramMem[0x11] = pos.y.uint8

proc main() =
  
  # Initialise save
  if not validateSave():
    newSave()
  readSave()
  
  # Enable VBlank interrupt so we can wait for the next frame
  irq.enable(iiVBlank)
  
  # Show background 0 and sprites
  dispcnt.init(bg0 = true, obj = true, obj1d = true)
  
  # Initialise text
  tte.initChr4c(bgnr = 0, initBgCnt(cbb = 0, sbb = 31))
  tte.write("""
  Natu Save Example
  ---------------------
  Arrows to move.
  Press START to save
  Press SELECT to load
  Saved data should persist after power off.
  """)
  
  # Hide all sprites
  for obj in mitems(objMem):
    obj.hide()
  
  # Fill a tile with white
  objPalMem[0][1] = rgb5(31,31,31)
  const numBytes = (8*8) div 2
  memset32(addr objTileMem[0], octup(1), numBytes div sizeof(uint32))
  
  # Initialise a sprite to display our white tile
  objMem[0].init(
    pos = pos,
    size = s8x8,
    tid = 0,
    pal = 0,
  )
  
  while true:
    # Update key states
    keyPoll()
    
    # Move the sprite
    if keyIsDown(kiLeft): pos.x -= 1
    if keyIsDown(kiRight): pos.x += 1
    if keyIsDown(kiUp): pos.y -= 1
    if keyIsDown(kiDown): pos.y += 1
    
    # Save/load on button press
    if keyHit(kiStart): writeSave()
    if keyHit(kiSelect): readSave()
    
    # Wait for next frame
    VBlankIntrWait()
    
    # Update sprite position
    objMem[0].pos = pos

main()