this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add Nim Wasm template (#2645)

authored by

Archar Gelod and committed by
GitHub
55ee0b30 3c52c46c

+565
+10
templates/nim/README.md
··· 1 + # Nim Starter Project Template 2 + 3 + This is a Nim / TIC-80 starter template. To build wasm binary and import it into 4 + the 'cart.tic' file, ensure you have a Nim compiler, Wasi-SDK and Tic-80 on your system and run: 5 + 6 + ``` 7 + nimble buildcart 8 + ``` 9 + 10 + Run `nimble tasks` command to see more build options.
+38
templates/nim/cart.nimble
··· 1 + # Package 2 + 3 + version = "0.1.0" 4 + author = "archargelod" 5 + description = "tic80 wasm template for Nim language" 6 + license = "MIT" 7 + srcDir = "src" 8 + 9 + 10 + # Dependencies 11 + 12 + requires "nim >= 2.0.0" 13 + 14 + # Tasks 15 + import std/strformat 16 + 17 + let pwd = getCurrentDir() 18 + 19 + task wasmbuild, "Build wasm binary (debug)": 20 + exec("nim c -o:cart.wasm src/cart") 21 + 22 + task wasmrelease, "Build wasm binary (release)": 23 + exec("nim c -d:release -o:cart.wasm src/cart") 24 + 25 + task buildcart, "Build optimized wasm binary and import it to tic80 cart": 26 + rmFile("cart.tic") 27 + exec("nim c -d:release -o:cart.wasm src/cart") 28 + exec(&"tic80 --cli --fs=\"{pwd}\" --cmd=\"load src/cart.tic & import binary cart.wasm & save cart.tic & exit\"") 29 + 30 + task runcart, "Build optimized wasm binary and run it with tic80": 31 + rmFile("cart.tic") 32 + exec("nim c -d:release -o:cart.wasm src/cart") 33 + exec(&"tic80 --skip --fs=\"{pwd}\" --cmd=\"load src/cart.tic & import binary cart.wasm & save cart.tic & run\"") 34 + 35 + task debugcart, "Build wasm binary in debug mode and run it with tic80": 36 + rmFile("cart.tic") 37 + exec("nim c -o:cart.wasm src/cart") 38 + exec(&"tic80 --skip --fs=\"{pwd}\" --cmd=\"load src/cart.tic & import binary cart.wasm & save cart.tic & run\"")
+52
templates/nim/config.nims
··· 1 + import std/os 2 + 3 + let wasi = getEnv("WASI_SDK_PATH") 4 + if wasi == "" and not defined(nimsuggest): 5 + echo "" 6 + echo "Error:" 7 + echo "Download the WASI SDK (https://github.com/WebAssembly/wasi-sdk) and set the $WASI_SDK_PATH environment variable!" 8 + echo "" 9 + quit(-1) 10 + 11 + switch("cpu", "wasm32") 12 + switch("cc", "clang") 13 + switch("threads", "off") 14 + 15 + # ARC is much more embedded-friendly 16 + switch("gc", "arc") 17 + # Treats defects as errors, results in smaller binary size 18 + switch("panics", "on") 19 + 20 + # Use the common ANSI C target 21 + switch("os", "any") 22 + # Needed for os:any 23 + switch("define", "posix") 24 + 25 + # WASM has no signal handlers 26 + switch("define", "noSignalHandler") 27 + # The only entrypoints are start and update 28 + switch("noMain") 29 + # Use malloc instead of Nim's memory allocator, makes binary size much smaller 30 + switch("define", "useMalloc") 31 + 32 + switch("clang.exe", wasi / "bin" / "clang") 33 + switch("clang.linkerexe", wasi / "bin" / "clang") 34 + 35 + switch("passC", "--sysroot=" & (wasi / "share" / "wasi-sysroot")) 36 + 37 + switch("passL", "-Wl,-zstack-size=8192,--no-entry,--import-memory -mexec-model=reactor -Wl,--initial-memory=262144,--max-memory=262144,--global-base=98304") 38 + 39 + when not defined(release): 40 + switch("assertions", "off") 41 + switch("checks", "off") 42 + switch("stackTrace", "off") 43 + switch("lineTrace", "off") 44 + switch("lineDir", "off") 45 + switch("debugger", "native") 46 + # This is needed to remove all unused Nim functions that will in turn import 47 + # WASI stuff that is not available in WASM-4 48 + switch("passL", "-Wl,--gc-sections") 49 + else: 50 + switch("opt", "size") 51 + switch("passC", "-flto") 52 + switch("passL", "-Wl,--strip-all,--gc-sections,--lto-O3")
templates/nim/demo/bunny.tic

This is a binary file and will not be displayed.

+84
templates/nim/demo/bunnymark.nim
··· 1 + import std/[random] 2 + import ../cart/tic80 3 + 4 + let ToolbarHeight = 6 5 + 6 + type 7 + Bunny = object 8 + x, y: float32 9 + width: int32 = 26 10 + height: int32 = 32 11 + speedX, speedY: float32 12 + sprite: int32 13 + FPS = object 14 + value, frames: int32 15 + lastTime: float32 16 + 17 + proc getValue(f: var FPS): int32 = 18 + if time() - f.lastTime <= 1000: 19 + inc f.frames 20 + else: 21 + f.value = f.frames 22 + f.frames = 0 23 + f.lastTime = time() 24 + f.value 25 + 26 + proc newBunny: Bunny = 27 + Bunny( 28 + x: rand(0 .. Width).float32, 29 + y: rand(0 .. Height).float32, 30 + width: 26, 31 + height: 32, 32 + speedX: rand(-100.0 .. 100.0) / 60, 33 + speedY: rand(-100.0 .. 100.0) / 60, 34 + sprite: 1, 35 + ) 36 + 37 + proc draw(b: Bunny) = 38 + spr(b.sprite, b.x.int32, b.y.int32, transColor=1, w=4, h=4) 39 + 40 + proc update(b: var Bunny) = 41 + b.x += b.speedX 42 + b.y += b.speedY 43 + 44 + if b.x.int32 + b.width > Width: 45 + b.x = float32(Width - b.width) 46 + b.speedX *= -1 47 + if b.x < 0: 48 + b.x = 0 49 + b.speedX *= -1 50 + 51 + if b.y.int32 + b.height > Height: 52 + b.y = float32(Height - b.height) 53 + b.speedY *= -1 54 + if b.y < 0: 55 + b.y = 0 56 + b.speedY *= -1 57 + 58 + randomize(tstamp().int64) 59 + 60 + var fps: FPS 61 + var bunnies: seq[Bunny] 62 + 63 + proc TIC {.exportWasm.} = 64 + cls(13) 65 + 66 + if btn(P1_Up): 67 + for _ in 1..5: 68 + bunnies.add newBunny() 69 + 70 + if btn(P1_Down): 71 + for _ in 1..5: 72 + if bunnies.len > 0: 73 + bunnies.del bunnies.high 74 + 75 + for bunny in bunnies.mitems: 76 + bunny.update() 77 + 78 + for bunny in bunnies.mitems: 79 + bunny.draw() 80 + 81 + rect(0, 0, Width, ToolbarHeight, 0) 82 + print("Bunnies: " & $bunnies.len, 1, 0, 11, false, 1, false) 83 + print("FPS: " & $fps.getValue(), Width div 2, 0, 11, false, 1, false) 84 +
+17
templates/nim/src/cart.nim
··· 1 + import cart/tic80 2 + 3 + var 4 + t = 1 5 + x = 96 6 + y = 24 7 + 8 + proc TIC {.exportWasm.} = 9 + cls(Color13) 10 + 11 + if btn(P1_Up): dec y 12 + if btn(P1_Down): inc y 13 + if btn(P1_Left): dec x 14 + if btn(P1_Right): inc x 15 + 16 + spr(1 + t mod 60 div 30 * 2, x, y, transColor=Color14, scale=3, w=2, h=2) 17 + print("Hello from Nim!", 84, 84)
templates/nim/src/cart.tic

This is a binary file and will not be displayed.

+286
templates/nim/src/cart/internal.nim
··· 1 + const 2 + TileSize* = 8 3 + Width* = 240 4 + Height* = 136 5 + WidthTiles* = Width div TileSize 6 + HeightTiles* = Height div TileSize 7 + Bpp* = 4 ## bits per pixel 8 + 9 + type 10 + Key* = enum 11 + Key_Null, Key_A, Key_B, Key_C, Key_D, Key_E, Key_F, Key_G, Key_H, Key_I, Key_J, 12 + Key_K, Key_L, Key_M, Key_N, Key_O, Key_P, Key_Q, Key_R, Key_S, Key_T, Key_U, 13 + Key_V, Key_W, Key_X, Key_Y, Key_Z, Key_0, Key_1, Key_2, Key_3, Key_4, Key_5, 14 + Key_6, Key_7, Key_8, Key_9, Key_Minus, Key_Equals, Key_Leftbracket, 15 + Key_Rightbracket, Key_Backslash, Key_Semicolon, Key_Apostrophe, Key_Grave, 16 + Key_Comma, Key_Period, Key_Slash, Key_Space, Key_Tab, Key_Return, Key_Backspace, 17 + Key_Delete, Key_Insert, Key_Pageup, Key_Pagedown, Key_Home, Key_End, Key_Up, 18 + Key_Down, Key_Left, Key_Right, Key_Capslock, Key_Ctrl, Key_Shift, Key_Alt 19 + 20 + Button* = enum 21 + P1_Up, P1_Down, P1_Left, P1_Right, P1_A, P1_B, P1_X, P1_Y, 22 + P2_Up, P2_Down, P2_Left, P2_Right, P2_A, P2_B, P2_X, P2_Y, 23 + P3_Up, P3_Down, P3_Left, P3_Right, P3_A, P3_B, P3_X, P3_Y, 24 + P4_Up, P4_Down, P4_Left, P4_Right, P4_A, P4_B, P4_X, P4_Y 25 + 26 + Color* = enum 27 + Null = -1'i8, Color0, Color1, Color2, Color3, Color4, Color5, Color6, Color7, 28 + Color8, Color9, Color10, Color11, Color12, Color13, Color14, Color15, 29 + 30 + VRAM* {.bycopy.} = object 31 + screen*: array[Width * Height * Bpp div 8, uint8] 32 + palette*: array[48, uint8] ## 16 colors. 33 + palletteMap*: array[8, uint8] ## 16 indices. 34 + borderColorAndOvrTransparency*: uint8 ## Bank 0 is border color, bank 1 is OVR transparency. 35 + screenOffsetX*: int8 36 + screenOffsetY*: int8 37 + mouseCursor*: int8 38 + blitSegment*: uint8 39 + reserved*: array[3, uint8] 40 + 41 + MousePos* {.bycopy.} = object 42 + x*: int16 43 + y*: int16 44 + scrollx*: int8 45 + scrolly*: int8 46 + left*: bool 47 + middle*: bool 48 + right*: bool 49 + 50 + 51 + ## --------------------------- 52 + ## Pointers 53 + ## --------------------------- 54 + 55 + const 56 + Framebuffer*: ptr Vram = cast[ptr Vram](0) 57 + Tiles*: ptr uint8 = cast[ptr uint8](0x04000) 58 + Sprites*: ptr uint8 = cast[ptr uint8](0x06000) 59 + Map*: ptr uint8 = cast[ptr uint8](0x08000) 60 + Gamepads*: ptr uint8 = cast[ptr uint8](0x0ff80) 61 + Mouse*: ptr uint8 = cast[ptr uint8](0x0ff84) 62 + Keyboard*: ptr uint8 = cast[ptr uint8](0x0ff88) 63 + SfxState*: ptr uint8 = cast[ptr uint8](0x0ff8c) 64 + SoundRegisters*: ptr uint8 = cast[ptr uint8](0x0ff9c) 65 + Waveforms*: ptr uint8 = cast[ptr uint8](0x0ffe4) 66 + Sfx*: ptr uint8 = cast[ptr uint8](0x100e4) 67 + MusicPatterns*: ptr uint8 = cast[ptr uint8](0x11164) 68 + MusicTracks*: ptr uint8 = cast[ptr uint8](0x13e64) 69 + SoundState*: ptr uint8 = cast[ptr uint8](0x13ffc) 70 + StereoVolume*: ptr uint8 = cast[ptr uint8](0x14000) 71 + PersistentMemory*: ptr uint8 = cast[ptr uint8](0x14004) 72 + SpriteFlags*: ptr uint8 = cast[ptr uint8](0x14404) 73 + SystemFont*: ptr uint8 = cast[ptr uint8](0x14604) 74 + WasmFreeRam*: ptr uint8 = cast[ptr uint8](0x18000) 75 + 76 + ## 160kb 77 + 78 + 79 + ## --------------------------- 80 + ## Constants 81 + ## --------------------------- 82 + 83 + const 84 + TilesSize*: uint32 = 0x2000 85 + SpritesSize*: uint32 = 0x2000 86 + MapSize*: uint32 = 32640 87 + GamepadsSize*: uint32 = 4 88 + MouseSize*: uint32 = 4 89 + KeyboardSize*: uint32 = 4 90 + SfxStateSize*: uint32 = 16 91 + SoundRegistersSize*: uint32 = 72 92 + WaveformsSize*: uint32 = 256 93 + SfxSize*: uint32 = 4224 94 + MusicPatternsSize*: uint32 = 11520 95 + MusicTracksSize*: uint32 = 408 96 + SoundStateSize*: uint32 = 4 97 + StereoVolumeSize*: uint32 = 4 98 + PersistentMemorySize*: uint32 = 1024 99 + SpriteFlagsSize*: uint32 = 512 100 + SystemFontSize*: uint32 = 2048 101 + WasmFreeRamSize*: uint32 = 163840 102 + 103 + ## 160kb 104 + 105 + 106 + {.push importc, codegenDecl: "__attribute__((import_name(\"$2\"))) $1 $2$3".} 107 + 108 + ## --------------------------- 109 + ## Drawing Procedures 110 + ## --------------------------- 111 + 112 + proc circ*(x, y, radius: int32; color: Color) 113 + ## Draw a filled circle. 114 + 115 + proc circb*(x, y, radius: int32; color: Color) 116 + ## Draw a circle border. 117 + 118 + proc elli*(x, y, a, b: int32; color: Color) 119 + ## Draw a filled ellipse. 120 + 121 + proc ellib*(x, y, a, b: int32; color: Color) 122 + ## Draw an ellipse border. 123 + 124 + proc clip*(x, y, width, height: int32) 125 + ## Set the screen clipping region. 126 + 127 + proc cls*(color: Color = Color0) 128 + ## Clear the screen. 129 + 130 + proc font*(text: cstring; x, y: int32; trans_colors: ptr uint8; trans_count: int8, 131 + char_width, char_height: int8; fixed: bool; scale: int8; alt: bool): int8 132 + ## Print a string using foreground sprite data as the font. 133 + 134 + proc line*(x0, y0, x1, y1: cfloat; color: Color) 135 + ## Draw a straight line. 136 + 137 + proc map*(x, y, w, h, sx, sy: int32; trans_colors: ptr uint8; colorCount: int8; 138 + scale: int8; remap: int32) 139 + ## Draw a map region. 140 + 141 + proc pix*(x, y: int32; color: Color): uint8 {.discardable.} 142 + ## Get or set the color of a single pixel. 143 + 144 + proc print*(text: cstring; x, y: int32; color: Color = Color15; fixed = false; 145 + scale: int32 = 1; alt = false): int32 {.discardable.} 146 + ## Print a string using the system font. 147 + 148 + proc rect*(x, y, w, h: int32; color: Color) 149 + ## Draw a filled rectangle. 150 + 151 + proc rectb*(x, y, w, h: int32; color: Color) 152 + ## Draw a rectangle border. 153 + 154 + proc spr*(id, x, y: int32; trans_colors: ptr uint8; color_count: int8; 155 + scale, flip, rotate, w, h: int32) 156 + ## Draw a sprite or composite sprite. 157 + 158 + proc tri*(x1, y1, x2, y2, x3, y3: cfloat; color: Color) 159 + ## Draw a filled triangle. 160 + 161 + proc trib*(x1, y1, x2, y2, x3, y3: cfloat; color: Color) 162 + ## Draw a triangle border. 163 + 164 + proc ttri*(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3: cfloat; texsrc: int32; 165 + trans_colors: ptr uint8; color_count: int8; z1, z2, z3: cfloat; depth: bool) 166 + ## Draw a triangle filled with texture. 167 + 168 + 169 + ## --------------------------- 170 + ## Input Functions 171 + ## --------------------------- 172 + 173 + proc btn*(button: Button): uint32 174 + ## Get gamepad button state in current frame. 175 + 176 + proc btnp*(button: Button; hold: int32 = -1; period: int32 = -1): uint32 177 + ## Get gamepad button state according to previous frame. 178 + 179 + proc key*(key: Key): bool 180 + ## Get keyboard button state in current frame. 181 + 182 + proc keyp*(key: Key; hold: int32 = -1; period: int32 = -1): bool 183 + ## Get keyboard button state relative to previous frame. 184 + 185 + proc mouse*(mouse_ptr_addy: ptr MousePos) 186 + ## Get XY and press state of mouse/touch. 187 + 188 + 189 + ## --------------------------- 190 + ## Sound Functions 191 + ## --------------------------- 192 + 193 + proc music*(track, frame, row: int32; loop, sustain: bool; tempo, speed: int32) 194 + ## Play or stop playing music. 195 + 196 + proc sfx*(sfx_id, note, octave, duration, channel, volume_left, volume_right, 197 + speed: int32) 198 + ## Play or stop playing a given sound. 199 + 200 + 201 + ## --------------------------- 202 + ## Memory Functions 203 + ## --------------------------- 204 + 205 + proc pmem*(address: int32; value: int64): uint32 {.discardable.} 206 + ## Access or update the persistent memory. 207 + 208 + proc peek*(address: int32; bits: int8 = 8): int8 209 + ## Read a byte from an address in RAM. 210 + 211 + proc peek1*(address: int32): int8 212 + ## Read a single bit from an address in RAM. 213 + 214 + proc peek2*(address: int32): int8 215 + ## Read two bit value from an address in RAM. 216 + 217 + proc peek4*(address: int32): int8 218 + ## Read a nibble value from an address. 219 + 220 + proc poke*(address: int32; value: int8; bits: int8 = 8) 221 + ## Write a byte value to an address in RAM. 222 + 223 + proc poke1*(address: int32; value: int8) 224 + ## Write a single bit to an address in RAM. 225 + 226 + proc poke2*(address: int32; value: int8) 227 + ## Write a two bit value to an address in RAM. 228 + 229 + proc poke4*(address: int32; value: int8) 230 + ## Write a nibble value to an address in RAM. 231 + 232 + proc sync*(mask: int32 = 0; bank: int8 = 0; to_cart = false) 233 + ## Copy banks of RAM (sprites, map, etc) to and from the cartridge. 234 + 235 + proc vbank*(bank: int8): int8 236 + ## Switch the 16kb of banked video RAM. 237 + 238 + 239 + ## --------------------------- 240 + ## Utility Functions 241 + ## --------------------------- 242 + 243 + proc fget*(sprite_index: int32; flag: int8): bool 244 + ## Retrieve a sprite flag. 245 + 246 + proc fset*(sprite_index: int32; flag: int8; value: bool): bool {.discardable.} 247 + ## Update a sprite flag. 248 + 249 + proc mget*(x, y: int32): int32 250 + ## Retrieve a map tile at given coordinates. 251 + 252 + proc mset*(x, y, value: int32) 253 + ## Update a map tile at given coordinates. 254 + 255 + 256 + ## --------------------------- 257 + ## System Functions 258 + ## --------------------------- 259 + 260 + proc exit*() 261 + ## Interrupt program and return to console. 262 + 263 + proc tstamp*(): uint32 264 + ## Returns the current Unix timestamp in seconds. 265 + 266 + proc trace*(text: cstring; color: Color = Color15) 267 + ## Print a string to the Console. 268 + 269 + {.pop.} 270 + 271 + # suffix fixes "unreachable code executed" error 272 + proc time2*(): cfloat {.importc, 273 + codegenDecl: "__attribute__((import_name(\"time\"))) $1 $2$3".} 274 + ## Returns how many milliseconds have passed since game started. 275 + 276 + import std/macros 277 + 278 + macro exportWasm*(def: untyped): untyped = 279 + result = def 280 + result[^3] = nnkPragma.newTree( 281 + ident("exportc"), 282 + nnkExprColonExpr.newTree( 283 + ident("codegenDecl"), 284 + newStrLitNode("__attribute__((export_name(\"$2\"))) $1 $2$3") 285 + ) 286 + )
+78
templates/nim/src/cart/tic80.nim
··· 1 + import internal except btn, btnp, trace 2 + export internal except btn, btnp, trace 3 + 4 + proc font*(text: cstring, x, y: int32, transColor, char_width, char_height: int8, 5 + fixed: bool, scale: int8, alt: bool): int8 {.discardable.} = 6 + ## Print a string using foreground sprite data as the font. 7 + if transColor >= 0: 8 + let trans_colors = transColor.uint8 9 + internal.font(text, x, y, addr trans_colors, 1, char_width, char_height, fixed, 10 + scale, alt) 11 + else: 12 + internal.font(text, x, y, nil, 0, char_width, char_height, fixed, scale, alt) 13 + 14 + proc map*(x: int32 = 0, y: int32 = 0, w: int32 = 30, h: int32 = 17, 15 + sx: int32 = 0, sy: int32 = 0, transColor: Color = Null, scale: int8 = 1, 16 + remap: int32 = -1) = 17 + ## Draw a map region. 18 + if transColor.int8 >= 0: 19 + let trans_colors = transColor.uint8 20 + internal.map(x, y, w, h, sx, sy, addr trans_colors, 1, scale, remap) 21 + else: 22 + internal.map(x, y, w, h, sx, sy, nil, 0, scale, remap) 23 + 24 + proc spr*(id, x, y: int32, transColor: Color = Null, scale: int32 = 1, 25 + flip: int32 = 0, rotate: int32 = 0, w: int32 = 1, h: int32 = 1) = 26 + ## Draw a sprite or composite sprite. 27 + if transColor.int8 >= 0: 28 + let trans_colors = transColor.uint8 29 + internal.spr(id, x, y, addr trans_colors, 1, scale, flip, rotate, w, h) 30 + else: 31 + internal.spr(id, x, y, nil, 0, scale, flip, rotate, w, h) 32 + 33 + proc ttri*(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3: cfloat, 34 + texsrc: int32 = 0, transColor: Color = Null, 35 + z1: cfloat = 0, z2: cfloat = 0, z3: cfloat = 0, depth = false) = 36 + ## Draw a triangle filled with texture. 37 + if transColor.int8 >= 0: 38 + let trans_colors = transColor.uint8 39 + internal.ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texsrc, 40 + addr trans_colors, 1, z1, z2, z3, depth) 41 + else: 42 + internal.ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texsrc, 43 + nil, 0, z1, z2, z3, depth) 44 + 45 + proc btn*(index: Button): bool {.inline.} = 46 + ## Get gamepad button state in current frame. 47 + internal.btn(index) > 0 48 + 49 + proc btnp*(index: Button, hold: int32 = -1, period: int32 = -1): bool {.inline.} = 50 + ## Get gamepad button state according to previous frame. 51 + internal.btnp(index, hold, period) > 0 52 + 53 + proc mouse*(): MousePos {.inline.} = internal.mouse(addr result) 54 + ## Get XY and press state of mouse/touch. 55 + 56 + proc pmemset*(address: int32; value: int64) = pmem(address, value) 57 + ## Update the persistent memory. 58 + proc pmemget*(address: int32): uint32 = pmem(address, -1) 59 + ## Access the persistent memory. 60 + 61 + proc pixset*(x, y: int32; color: Color) = pix(x, y, color) 62 + ## Set the color of a single pixel. 63 + proc pixget*(x, y: int32): uint8 = pix(x, y, Null) 64 + ## Get the color of a single pixel. 65 + 66 + proc trace*(items: varargs[cstring, cstring]) = 67 + ## Print a string to the Console. 68 + for item in items: internal.trace(item) 69 + 70 + proc print*(text: string; x, y: int32; color: Color = Color15; fixed = false; 71 + scale: int32 = 1; alt = false): int32 {.discardable.} = 72 + ## Print a string using the system font. 73 + print(cstring(text), x, y, color, fixed, scale, alt) 74 + 75 + proc NimMain() {.importc.} 76 + 77 + proc BOOT() {.exportWasm.} = 78 + NimMain()