diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a17f62441..d9bc50ae7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,114 +7,6 @@ env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true jobs: - # === Windows XP === - winxp: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - name: Build - shell: cmd - run: | - COPY /Y build\janet\janetconf.h vendor\janet\src\conf\janetconf.h - cd build - cmake -G "Visual Studio 16 2019" -A Win32 -T v141_xp -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - - name: Deploy - uses: actions/upload-artifact@v4 - with: - name: "tic80-winxp" - path: | - build/bin/tic80.exe - build/bin/*.dll - - - name: Build Pro - shell: cmd - run: | - COPY /Y build\janet\janetconf.h vendor\janet\src\conf\janetconf.h - cd build - cmake -G "Visual Studio 16 2019" -A Win32 -T v141_xp -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - # === Windows === - windows: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - name: Build - shell: cmd - run: | - cd build - cmake -G "Visual Studio 16 2019" -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - - name: Deploy - uses: actions/upload-artifact@v4 - with: - name: "tic80-windows" - path: | - build/bin/tic80.exe - build/bin/*.dll - - - name: Build Pro - shell: cmd - run: | - cd build - cmake -G "Visual Studio 16 2019" -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - # === Windows MinGW-64 === - windows-mingw: - runs-on: windows-latest - defaults: - run: - shell: msys2 {0} - - steps: - - name: Setup Mingw - uses: msys2/setup-msys2@v2 - with: - msystem: UCRT64 - update: true - install: >- - base-devel - git - gcc - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - name: Build - shell: bash - run: | - cd build - cmake -G "MSYS Makefiles" -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON -DBUILD_WITH_JANET=OFF .. - cmake --build . --config MinSizeRel --parallel - # === Ubuntu === linux: runs-on: ubuntu-20.04 @@ -137,7 +29,7 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=ON .. + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. cmake --build . --config MinSizeRel --parallel - name: Deploy @@ -148,12 +40,6 @@ jobs: build/bin/tic80 build/bin/*.so - - name: Build Pro - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - # === Raspberry PI === rpi: runs-on: ubuntu-latest @@ -173,7 +59,7 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_PRO=On -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. cmake --build . --config MinSizeRel --parallel - name: Deploy @@ -183,230 +69,7 @@ jobs: path: | build/bin/tic80 build/bin/*.so - - - name: Build Pro - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_PRO=On -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake .. - cmake --build . --config MinSizeRel --parallel - - # === Raspberry PI 1-4 Bare Metal === - rpi-baremetal: - runs-on: ubuntu-latest - container: nesbox/baremetalpi-tic80:latest - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install Host toolchain - run: | - apt-get update - apt-get install --assume-yes build-essential ruby-full - - - name: Prebuild - run: | - cd vendor - git clone --recursive https://github.com/smuehlst/circle-stdlib - cd circle-stdlib - git checkout fdb3c4a948421d47fddab8042a92f980cba43915 - git submodule update --recursive - ./configure -r 3 - make -j$(nproc) - cd libs/circle/addon/vc4/sound/ - make -j$(nproc) - cd ../vchiq - make -j$(nproc) - cd ../../linux - make -j$(nproc) - - - name: Build - run: | - git apply build/baremetalpi/circle.patch - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_TOOLCHAIN_FILE=baremetalpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. - make tic80studio -j$(nproc) - cd baremetalpi - make -j$(nproc) - cd ../../vendor/circle-stdlib/libs/circle/boot/ - make -j$(nproc) - - - name: Pack - run: | - cp build/baremetalpi/kernel8-32.img vendor/circle-stdlib/libs/circle/boot/kernel.img - cp build/baremetalpi/boot/config.txt vendor/circle-stdlib/libs/circle/boot/config.txt - - - name: Deploy - uses: actions/upload-artifact@v3 - with: - name: "tic80-rpi-baremetal" - path: | - vendor/circle-stdlib/libs/circle/boot/config.txt - vendor/circle-stdlib/libs/circle/boot/kernel.img - vendor/circle-stdlib/libs/circle/boot/bootcode.bin - vendor/circle-stdlib/libs/circle/boot/start.elf - vendor/circle-stdlib/libs/circle/boot/fixup.dat - vendor/circle-stdlib/libs/circle/boot/LICENCE.broadcom - - # === Raspberry PI 4 Bare Metal === - rpi4-baremetal: - runs-on: ubuntu-latest - container: nesbox/baremetalpi-tic80:latest - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install Host toolchain - run: | - apt-get update - apt-get install --assume-yes build-essential ruby-full - - - name: Prebuild - run: | - cd vendor - git clone --recursive https://github.com/smuehlst/circle-stdlib - cd circle-stdlib - git checkout fdb3c4a948421d47fddab8042a92f980cba43915 - git submodule update --recursive - ./configure -r 4 - make -j$(nproc) - cd libs/circle/addon/vc4/sound/ - make -j$(nproc) - cd ../vchiq - make -j$(nproc) - cd ../../linux - make -j$(nproc) - - - name: Build - run: | - git apply build/baremetalpi/circle.patch - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_TOOLCHAIN_FILE=baremetalpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. - make tic80studio -j$(nproc) - cd baremetalpi - make -j$(nproc) - cd ../../vendor/circle-stdlib/libs/circle/boot/ - make -j$(nproc) - - - name: Pack - run: | - cp build/baremetalpi/kernel7l.img vendor/circle-stdlib/libs/circle/boot/kernel.img - cp build/baremetalpi/boot/config.txt vendor/circle-stdlib/libs/circle/boot/config.txt - - - name: Deploy - uses: actions/upload-artifact@v3 - with: - name: "tic80-rpi4-baremetal" - path: | - vendor/circle-stdlib/libs/circle/boot/bcm2711-rpi-4-b.dtb - vendor/circle-stdlib/libs/circle/boot/bcm2711-rpi-cm4.dtb - vendor/circle-stdlib/libs/circle/boot/bootcode.bin - vendor/circle-stdlib/libs/circle/boot/config.txt - vendor/circle-stdlib/libs/circle/boot/COPYING.linux - vendor/circle-stdlib/libs/circle/boot/fixup4.dat - vendor/circle-stdlib/libs/circle/boot/kernel.img - vendor/circle-stdlib/libs/circle/boot/LICENCE.broadcom - vendor/circle-stdlib/libs/circle/boot/start4.elf - - # === Nintendo 3DS build === - nintendo-3ds: - runs-on: ubuntu-latest - container: nesbox/devkitpro-tic80:latest - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install Host toolchain - run: | - apt-get update - apt-get install --assume-yes build-essential ruby-full - - - name: Build - run: | - cd build - cmake -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/3ds.cmake -DN3DS=TRUE -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON .. - make -j$(nproc) - - - name: Deploy - uses: actions/upload-artifact@v3 - with: - name: "tic80-nintendo-3ds" - path: build/bin/tic80.3dsx - - # === MacOS 12 === - macos: - runs-on: macos-12 - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install - run: brew uninstall --ignore-dependencies libidn2 - - - name: Build - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - - name: Deploy - uses: actions/upload-artifact@v4 - with: - name: "tic80-macos" - path: | - build/bin/tic80 - build/bin/*.dylib - - - name: Build Pro - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - # === MacOS 14 / arm64 === - macos-arm64: - runs-on: macos-14 - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install - run: brew uninstall --ignore-dependencies libidn2 - - - name: Build - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - - - name: Deploy - uses: actions/upload-artifact@v4 - with: - name: "tic80-macos-arm64" - path: | - build/bin/tic80 - build/bin/*.dylib - - - name: Build Pro - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. - cmake --build . --config MinSizeRel --parallel - + # === Android === android: runs-on: ubuntu-latest @@ -446,99 +109,3 @@ jobs: with: name: "tic80-android" path: build/android/tic80.apk - - # === HTML === - html: - runs-on: ubuntu-latest - - steps: - - uses: mymindstorm/setup-emsdk@v14 - - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - name: Build lua - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=ON -DTIC80_TARGET=tic80lua .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build ruby - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_RUBY=ON -DTIC80_TARGET=tic80ruby .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build js - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_JS=ON -DTIC80_TARGET=tic80js .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build moon - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_MOON=ON -DTIC80_TARGET=tic80moon .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build fennel - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_FENNEL=ON -DTIC80_TARGET=tic80fennel .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build scheme - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_SCHEME=ON -DTIC80_TARGET=tic80scheme .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build squirrel - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_SQUIRREL=ON -DTIC80_TARGET=tic80squirrel .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build wren - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_WREN=ON -DTIC80_TARGET=tic80wren .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build wasm - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_WASM=ON -DTIC80_TARGET=tic80wasm .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build janet - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_JANET=ON -DTIC80_TARGET=tic80janet .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build python - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_LUA=OFF -DBUILD_WITH_PYTHON=ON -DTIC80_TARGET=tic80python .. --fresh - cmake --build . --config MinSizeRel --parallel - - - name: Build all - run: | - cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON .. --fresh - cmake --build . --config MinSizeRel --parallel - cp html/index.html bin/index.html - - - name: Deploy - uses: actions/upload-artifact@v4 - with: - name: "tic80-html" - path: | - build/bin/* diff --git a/templates/README.md b/templates/README.md index 7f5457985..c6b172178 100644 --- a/templates/README.md +++ b/templates/README.md @@ -2,6 +2,7 @@ This directory contains starter projects (and libs) for the compiled languages we support via `script: wasm`. Currently this list includes: +- Nim - Zig (low-level) - D (low-level) @@ -11,7 +12,6 @@ We could easily support these as well, with contributor help: - C++ - Go - Nelua -- Nim - Odin - Rust - Wat diff --git a/templates/nim/README.md b/templates/nim/README.md new file mode 100644 index 000000000..f6052b5d9 --- /dev/null +++ b/templates/nim/README.md @@ -0,0 +1,10 @@ +# Nim Starter Project Template + +This is a Nim / TIC-80 starter template. To build wasm binary and import it into +the 'cart.tic' file, ensure you have a Nim compiler, Wasi-SDK and Tic-80 on your system and run: + +``` +nimble buildcart +``` + +Run `nimble tasks` command to see more build options. diff --git a/templates/nim/cart.nimble b/templates/nim/cart.nimble new file mode 100644 index 000000000..f543bb6c5 --- /dev/null +++ b/templates/nim/cart.nimble @@ -0,0 +1,38 @@ +# Package + +version = "0.1.0" +author = "archargelod" +description = "tic80 wasm template for Nim language" +license = "MIT" +srcDir = "src" + + +# Dependencies + +requires "nim >= 2.0.0" + +# Tasks +import std/strformat + +let pwd = getCurrentDir() + +task wasmbuild, "Build wasm binary (debug)": + exec("nim c -o:cart.wasm src/cart") + +task wasmrelease, "Build wasm binary (release)": + exec("nim c -d:release -o:cart.wasm src/cart") + +task buildcart, "Build optimized wasm binary and import it to tic80 cart": + rmFile("cart.tic") + exec("nim c -d:release -o:cart.wasm src/cart") + exec(&"tic80 --cli --fs=\"{pwd}\" --cmd=\"load src/cart.tic & import binary cart.wasm & save cart.tic & exit\"") + +task runcart, "Build optimized wasm binary and run it with tic80": + rmFile("cart.tic") + exec("nim c -d:release -o:cart.wasm src/cart") + exec(&"tic80 --skip --fs=\"{pwd}\" --cmd=\"load src/cart.tic & import binary cart.wasm & save cart.tic & run\"") + +task debugcart, "Build wasm binary in debug mode and run it with tic80": + rmFile("cart.tic") + exec("nim c -o:cart.wasm src/cart") + exec(&"tic80 --skip --fs=\"{pwd}\" --cmd=\"load src/cart.tic & import binary cart.wasm & save cart.tic & run\"") diff --git a/templates/nim/config.nims b/templates/nim/config.nims new file mode 100644 index 000000000..b45316f72 --- /dev/null +++ b/templates/nim/config.nims @@ -0,0 +1,52 @@ +import std/os + +let wasi = getEnv("WASI_SDK_PATH") +if wasi == "" and not defined(nimsuggest): + echo "" + echo "Error:" + echo "Download the WASI SDK (https://github.com/WebAssembly/wasi-sdk) and set the $WASI_SDK_PATH environment variable!" + echo "" + quit(-1) + +switch("cpu", "wasm32") +switch("cc", "clang") +switch("threads", "off") + +# ARC is much more embedded-friendly +switch("gc", "arc") +# Treats defects as errors, results in smaller binary size +switch("panics", "on") + +# Use the common ANSI C target +switch("os", "any") +# Needed for os:any +switch("define", "posix") + +# WASM has no signal handlers +switch("define", "noSignalHandler") +# The only entrypoints are start and update +switch("noMain") +# Use malloc instead of Nim's memory allocator, makes binary size much smaller +switch("define", "useMalloc") + +switch("clang.exe", wasi / "bin" / "clang") +switch("clang.linkerexe", wasi / "bin" / "clang") + +switch("passC", "--sysroot=" & (wasi / "share" / "wasi-sysroot")) + +switch("passL", "-Wl,-zstack-size=8192,--no-entry,--import-memory -mexec-model=reactor -Wl,--initial-memory=262144,--max-memory=262144,--global-base=98304") + +when not defined(release): + switch("assertions", "off") + switch("checks", "off") + switch("stackTrace", "off") + switch("lineTrace", "off") + switch("lineDir", "off") + switch("debugger", "native") + # This is needed to remove all unused Nim functions that will in turn import + # WASI stuff that is not available in WASM-4 + switch("passL", "-Wl,--gc-sections") +else: + switch("opt", "size") + switch("passC", "-flto") + switch("passL", "-Wl,--strip-all,--gc-sections,--lto-O3") diff --git a/templates/nim/demo/bunny.tic b/templates/nim/demo/bunny.tic new file mode 100644 index 000000000..c6aeea14e Binary files /dev/null and b/templates/nim/demo/bunny.tic differ diff --git a/templates/nim/demo/bunnymark.nim b/templates/nim/demo/bunnymark.nim new file mode 100644 index 000000000..c5946717f --- /dev/null +++ b/templates/nim/demo/bunnymark.nim @@ -0,0 +1,84 @@ +import std/[random] +import ../cart/tic80 + +let ToolbarHeight = 6 + +type + Bunny = object + x, y: float32 + width: int32 = 26 + height: int32 = 32 + speedX, speedY: float32 + sprite: int32 + FPS = object + value, frames: int32 + lastTime: float32 + +proc getValue(f: var FPS): int32 = + if time() - f.lastTime <= 1000: + inc f.frames + else: + f.value = f.frames + f.frames = 0 + f.lastTime = time() + f.value + +proc newBunny: Bunny = + Bunny( + x: rand(0 .. Width).float32, + y: rand(0 .. Height).float32, + width: 26, + height: 32, + speedX: rand(-100.0 .. 100.0) / 60, + speedY: rand(-100.0 .. 100.0) / 60, + sprite: 1, + ) + +proc draw(b: Bunny) = + spr(b.sprite, b.x.int32, b.y.int32, transColor=1, w=4, h=4) + +proc update(b: var Bunny) = + b.x += b.speedX + b.y += b.speedY + + if b.x.int32 + b.width > Width: + b.x = float32(Width - b.width) + b.speedX *= -1 + if b.x < 0: + b.x = 0 + b.speedX *= -1 + + if b.y.int32 + b.height > Height: + b.y = float32(Height - b.height) + b.speedY *= -1 + if b.y < 0: + b.y = 0 + b.speedY *= -1 + +randomize(tstamp().int64) + +var fps: FPS +var bunnies: seq[Bunny] + +proc TIC {.exportWasm.} = + cls(13) + + if btn(P1_Up): + for _ in 1..5: + bunnies.add newBunny() + + if btn(P1_Down): + for _ in 1..5: + if bunnies.len > 0: + bunnies.del bunnies.high + + for bunny in bunnies.mitems: + bunny.update() + + for bunny in bunnies.mitems: + bunny.draw() + + rect(0, 0, Width, ToolbarHeight, 0) + print("Bunnies: " & $bunnies.len, 1, 0, 11, false, 1, false) + print("FPS: " & $fps.getValue(), Width div 2, 0, 11, false, 1, false) + diff --git a/templates/nim/src/cart.nim b/templates/nim/src/cart.nim new file mode 100644 index 000000000..39fddbc91 --- /dev/null +++ b/templates/nim/src/cart.nim @@ -0,0 +1,17 @@ +import cart/tic80 + +var + t = 1 + x = 96 + y = 24 + +proc TIC {.exportWasm.} = + cls(Color13) + + if btn(P1_Up): dec y + if btn(P1_Down): inc y + if btn(P1_Left): dec x + if btn(P1_Right): inc x + + spr(1 + t mod 60 div 30 * 2, x, y, transColor=Color14, scale=3, w=2, h=2) + print("Hello from Nim!", 84, 84) diff --git a/templates/nim/src/cart.tic b/templates/nim/src/cart.tic new file mode 100644 index 000000000..c5d4c3db0 Binary files /dev/null and b/templates/nim/src/cart.tic differ diff --git a/templates/nim/src/cart/internal.nim b/templates/nim/src/cart/internal.nim new file mode 100644 index 000000000..2da55f738 --- /dev/null +++ b/templates/nim/src/cart/internal.nim @@ -0,0 +1,286 @@ +const + TileSize* = 8 + Width* = 240 + Height* = 136 + WidthTiles* = Width div TileSize + HeightTiles* = Height div TileSize + Bpp* = 4 ## bits per pixel + +type + Key* = enum + Key_Null, Key_A, Key_B, Key_C, Key_D, Key_E, Key_F, Key_G, Key_H, Key_I, Key_J, + Key_K, Key_L, Key_M, Key_N, Key_O, Key_P, Key_Q, Key_R, Key_S, Key_T, Key_U, + Key_V, Key_W, Key_X, Key_Y, Key_Z, Key_0, Key_1, Key_2, Key_3, Key_4, Key_5, + Key_6, Key_7, Key_8, Key_9, Key_Minus, Key_Equals, Key_Leftbracket, + Key_Rightbracket, Key_Backslash, Key_Semicolon, Key_Apostrophe, Key_Grave, + Key_Comma, Key_Period, Key_Slash, Key_Space, Key_Tab, Key_Return, Key_Backspace, + Key_Delete, Key_Insert, Key_Pageup, Key_Pagedown, Key_Home, Key_End, Key_Up, + Key_Down, Key_Left, Key_Right, Key_Capslock, Key_Ctrl, Key_Shift, Key_Alt + + Button* = enum + P1_Up, P1_Down, P1_Left, P1_Right, P1_A, P1_B, P1_X, P1_Y, + P2_Up, P2_Down, P2_Left, P2_Right, P2_A, P2_B, P2_X, P2_Y, + P3_Up, P3_Down, P3_Left, P3_Right, P3_A, P3_B, P3_X, P3_Y, + P4_Up, P4_Down, P4_Left, P4_Right, P4_A, P4_B, P4_X, P4_Y + + Color* = enum + Null = -1'i8, Color0, Color1, Color2, Color3, Color4, Color5, Color6, Color7, + Color8, Color9, Color10, Color11, Color12, Color13, Color14, Color15, + + VRAM* {.bycopy.} = object + screen*: array[Width * Height * Bpp div 8, uint8] + palette*: array[48, uint8] ## 16 colors. + palletteMap*: array[8, uint8] ## 16 indices. + borderColorAndOvrTransparency*: uint8 ## Bank 0 is border color, bank 1 is OVR transparency. + screenOffsetX*: int8 + screenOffsetY*: int8 + mouseCursor*: int8 + blitSegment*: uint8 + reserved*: array[3, uint8] + + MousePos* {.bycopy.} = object + x*: int16 + y*: int16 + scrollx*: int8 + scrolly*: int8 + left*: bool + middle*: bool + right*: bool + + +## --------------------------- +## Pointers +## --------------------------- + +const + Framebuffer*: ptr Vram = cast[ptr Vram](0) + Tiles*: ptr uint8 = cast[ptr uint8](0x04000) + Sprites*: ptr uint8 = cast[ptr uint8](0x06000) + Map*: ptr uint8 = cast[ptr uint8](0x08000) + Gamepads*: ptr uint8 = cast[ptr uint8](0x0ff80) + Mouse*: ptr uint8 = cast[ptr uint8](0x0ff84) + Keyboard*: ptr uint8 = cast[ptr uint8](0x0ff88) + SfxState*: ptr uint8 = cast[ptr uint8](0x0ff8c) + SoundRegisters*: ptr uint8 = cast[ptr uint8](0x0ff9c) + Waveforms*: ptr uint8 = cast[ptr uint8](0x0ffe4) + Sfx*: ptr uint8 = cast[ptr uint8](0x100e4) + MusicPatterns*: ptr uint8 = cast[ptr uint8](0x11164) + MusicTracks*: ptr uint8 = cast[ptr uint8](0x13e64) + SoundState*: ptr uint8 = cast[ptr uint8](0x13ffc) + StereoVolume*: ptr uint8 = cast[ptr uint8](0x14000) + PersistentMemory*: ptr uint8 = cast[ptr uint8](0x14004) + SpriteFlags*: ptr uint8 = cast[ptr uint8](0x14404) + SystemFont*: ptr uint8 = cast[ptr uint8](0x14604) + WasmFreeRam*: ptr uint8 = cast[ptr uint8](0x18000) + +## 160kb + + +## --------------------------- +## Constants +## --------------------------- + +const + TilesSize*: uint32 = 0x2000 + SpritesSize*: uint32 = 0x2000 + MapSize*: uint32 = 32640 + GamepadsSize*: uint32 = 4 + MouseSize*: uint32 = 4 + KeyboardSize*: uint32 = 4 + SfxStateSize*: uint32 = 16 + SoundRegistersSize*: uint32 = 72 + WaveformsSize*: uint32 = 256 + SfxSize*: uint32 = 4224 + MusicPatternsSize*: uint32 = 11520 + MusicTracksSize*: uint32 = 408 + SoundStateSize*: uint32 = 4 + StereoVolumeSize*: uint32 = 4 + PersistentMemorySize*: uint32 = 1024 + SpriteFlagsSize*: uint32 = 512 + SystemFontSize*: uint32 = 2048 + WasmFreeRamSize*: uint32 = 163840 + +## 160kb + + +{.push importc, codegenDecl: "__attribute__((import_name(\"$2\"))) $1 $2$3".} + +## --------------------------- +## Drawing Procedures +## --------------------------- + +proc circ*(x, y, radius: int32; color: Color) + ## Draw a filled circle. + +proc circb*(x, y, radius: int32; color: Color) + ## Draw a circle border. + +proc elli*(x, y, a, b: int32; color: Color) + ## Draw a filled ellipse. + +proc ellib*(x, y, a, b: int32; color: Color) + ## Draw an ellipse border. + +proc clip*(x, y, width, height: int32) + ## Set the screen clipping region. + +proc cls*(color: Color = Color0) + ## Clear the screen. + +proc font*(text: cstring; x, y: int32; trans_colors: ptr uint8; trans_count: int8, + char_width, char_height: int8; fixed: bool; scale: int8; alt: bool): int8 + ## Print a string using foreground sprite data as the font. + +proc line*(x0, y0, x1, y1: cfloat; color: Color) + ## Draw a straight line. + +proc map*(x, y, w, h, sx, sy: int32; trans_colors: ptr uint8; colorCount: int8; + scale: int8; remap: int32) + ## Draw a map region. + +proc pix*(x, y: int32; color: Color): uint8 {.discardable.} + ## Get or set the color of a single pixel. + +proc print*(text: cstring; x, y: int32; color: Color = Color15; fixed = false; + scale: int32 = 1; alt = false): int32 {.discardable.} + ## Print a string using the system font. + +proc rect*(x, y, w, h: int32; color: Color) + ## Draw a filled rectangle. + +proc rectb*(x, y, w, h: int32; color: Color) + ## Draw a rectangle border. + +proc spr*(id, x, y: int32; trans_colors: ptr uint8; color_count: int8; + scale, flip, rotate, w, h: int32) + ## Draw a sprite or composite sprite. + +proc tri*(x1, y1, x2, y2, x3, y3: cfloat; color: Color) + ## Draw a filled triangle. + +proc trib*(x1, y1, x2, y2, x3, y3: cfloat; color: Color) + ## Draw a triangle border. + +proc ttri*(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3: cfloat; texsrc: int32; + trans_colors: ptr uint8; color_count: int8; z1, z2, z3: cfloat; depth: bool) + ## Draw a triangle filled with texture. + + +## --------------------------- +## Input Functions +## --------------------------- + +proc btn*(button: Button): uint32 + ## Get gamepad button state in current frame. + +proc btnp*(button: Button; hold: int32 = -1; period: int32 = -1): uint32 + ## Get gamepad button state according to previous frame. + +proc key*(key: Key): bool + ## Get keyboard button state in current frame. + +proc keyp*(key: Key; hold: int32 = -1; period: int32 = -1): bool + ## Get keyboard button state relative to previous frame. + +proc mouse*(mouse_ptr_addy: ptr MousePos) + ## Get XY and press state of mouse/touch. + + +## --------------------------- +## Sound Functions +## --------------------------- + +proc music*(track, frame, row: int32; loop, sustain: bool; tempo, speed: int32) + ## Play or stop playing music. + +proc sfx*(sfx_id, note, octave, duration, channel, volume_left, volume_right, + speed: int32) + ## Play or stop playing a given sound. + + +## --------------------------- +## Memory Functions +## --------------------------- + +proc pmem*(address: int32; value: int64): uint32 {.discardable.} + ## Access or update the persistent memory. + +proc peek*(address: int32; bits: int8 = 8): int8 + ## Read a byte from an address in RAM. + +proc peek1*(address: int32): int8 + ## Read a single bit from an address in RAM. + +proc peek2*(address: int32): int8 + ## Read two bit value from an address in RAM. + +proc peek4*(address: int32): int8 + ## Read a nibble value from an address. + +proc poke*(address: int32; value: int8; bits: int8 = 8) + ## Write a byte value to an address in RAM. + +proc poke1*(address: int32; value: int8) + ## Write a single bit to an address in RAM. + +proc poke2*(address: int32; value: int8) + ## Write a two bit value to an address in RAM. + +proc poke4*(address: int32; value: int8) + ## Write a nibble value to an address in RAM. + +proc sync*(mask: int32 = 0; bank: int8 = 0; to_cart = false) + ## Copy banks of RAM (sprites, map, etc) to and from the cartridge. + +proc vbank*(bank: int8): int8 + ## Switch the 16kb of banked video RAM. + + +## --------------------------- +## Utility Functions +## --------------------------- + +proc fget*(sprite_index: int32; flag: int8): bool + ## Retrieve a sprite flag. + +proc fset*(sprite_index: int32; flag: int8; value: bool): bool {.discardable.} + ## Update a sprite flag. + +proc mget*(x, y: int32): int32 + ## Retrieve a map tile at given coordinates. + +proc mset*(x, y, value: int32) + ## Update a map tile at given coordinates. + + +## --------------------------- +## System Functions +## --------------------------- + +proc exit*() + ## Interrupt program and return to console. + +proc tstamp*(): uint32 + ## Returns the current Unix timestamp in seconds. + +proc trace*(text: cstring; color: Color = Color15) + ## Print a string to the Console. + +{.pop.} + +# suffix fixes "unreachable code executed" error +proc time2*(): cfloat {.importc, + codegenDecl: "__attribute__((import_name(\"time\"))) $1 $2$3".} + ## Returns how many milliseconds have passed since game started. + +import std/macros + +macro exportWasm*(def: untyped): untyped = + result = def + result[^3] = nnkPragma.newTree( + ident("exportc"), + nnkExprColonExpr.newTree( + ident("codegenDecl"), + newStrLitNode("__attribute__((export_name(\"$2\"))) $1 $2$3") + ) + ) diff --git a/templates/nim/src/cart/tic80.nim b/templates/nim/src/cart/tic80.nim new file mode 100755 index 000000000..c8d5a79ca --- /dev/null +++ b/templates/nim/src/cart/tic80.nim @@ -0,0 +1,78 @@ +import internal except btn, btnp, trace +export internal except btn, btnp, trace + +proc font*(text: cstring, x, y: int32, transColor, char_width, char_height: int8, + fixed: bool, scale: int8, alt: bool): int8 {.discardable.} = + ## Print a string using foreground sprite data as the font. + if transColor >= 0: + let trans_colors = transColor.uint8 + internal.font(text, x, y, addr trans_colors, 1, char_width, char_height, fixed, + scale, alt) + else: + internal.font(text, x, y, nil, 0, char_width, char_height, fixed, scale, alt) + +proc map*(x: int32 = 0, y: int32 = 0, w: int32 = 30, h: int32 = 17, + sx: int32 = 0, sy: int32 = 0, transColor: Color = Null, scale: int8 = 1, + remap: int32 = -1) = + ## Draw a map region. + if transColor.int8 >= 0: + let trans_colors = transColor.uint8 + internal.map(x, y, w, h, sx, sy, addr trans_colors, 1, scale, remap) + else: + internal.map(x, y, w, h, sx, sy, nil, 0, scale, remap) + +proc spr*(id, x, y: int32, transColor: Color = Null, scale: int32 = 1, + flip: int32 = 0, rotate: int32 = 0, w: int32 = 1, h: int32 = 1) = + ## Draw a sprite or composite sprite. + if transColor.int8 >= 0: + let trans_colors = transColor.uint8 + internal.spr(id, x, y, addr trans_colors, 1, scale, flip, rotate, w, h) + else: + internal.spr(id, x, y, nil, 0, scale, flip, rotate, w, h) + +proc ttri*(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3: cfloat, + texsrc: int32 = 0, transColor: Color = Null, + z1: cfloat = 0, z2: cfloat = 0, z3: cfloat = 0, depth = false) = + ## Draw a triangle filled with texture. + if transColor.int8 >= 0: + let trans_colors = transColor.uint8 + internal.ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texsrc, + addr trans_colors, 1, z1, z2, z3, depth) + else: + internal.ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texsrc, + nil, 0, z1, z2, z3, depth) + +proc btn*(index: Button): bool {.inline.} = + ## Get gamepad button state in current frame. + internal.btn(index) > 0 + +proc btnp*(index: Button, hold: int32 = -1, period: int32 = -1): bool {.inline.} = + ## Get gamepad button state according to previous frame. + internal.btnp(index, hold, period) > 0 + +proc mouse*(): MousePos {.inline.} = internal.mouse(addr result) + ## Get XY and press state of mouse/touch. + +proc pmemset*(address: int32; value: int64) = pmem(address, value) + ## Update the persistent memory. +proc pmemget*(address: int32): uint32 = pmem(address, -1) + ## Access the persistent memory. + +proc pixset*(x, y: int32; color: Color) = pix(x, y, color) + ## Set the color of a single pixel. +proc pixget*(x, y: int32): uint8 = pix(x, y, Null) + ## Get the color of a single pixel. + +proc trace*(items: varargs[cstring, cstring]) = + ## Print a string to the Console. + for item in items: internal.trace(item) + +proc print*(text: string; x, y: int32; color: Color = Color15; fixed = false; + scale: int32 = 1; alt = false): int32 {.discardable.} = + ## Print a string using the system font. + print(cstring(text), x, y, color, fixed, scale, alt) + +proc NimMain() {.importc.} + +proc BOOT() {.exportWasm.} = + NimMain()