From 0ce535daaeb2bd6eea882b89d134ad7b464dded7 Mon Sep 17 00:00:00 2001 From: Archar Gelod <60652075+Archargelod@users.noreply.github.com> Date: Fri, 14 Jun 2024 05:08:00 +0000 Subject: [PATCH 1/2] Update build.yml --- .github/workflows/build.yml | 439 +----------------------------------- 1 file changed, 3 insertions(+), 436 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0436951cd..6f7e28b86 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,114 +3,6 @@ name: Build on: [push, pull_request] 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 @@ -133,7 +25,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 @@ -144,12 +36,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 @@ -169,7 +55,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 @@ -179,230 +65,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 @@ -442,99 +105,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/* From 561758bbd0429165b77594c88c8c9e4daa6f8ea8 Mon Sep 17 00:00:00 2001 From: archargelod Date: Wed, 31 Jul 2024 18:45:48 +0800 Subject: [PATCH 2/2] add Nim Wasm template --- templates/README.md | 2 +- templates/nim/README.md | 10 + templates/nim/cart.nimble | 38 ++++ templates/nim/config.nims | 52 +++++ templates/nim/demo/bunny.tic | Bin 0 -> 18560 bytes templates/nim/demo/bunnymark.nim | 84 ++++++++ templates/nim/src/cart.nim | 17 ++ templates/nim/src/cart.tic | Bin 0 -> 102861 bytes templates/nim/src/cart/internal.nim | 286 ++++++++++++++++++++++++++++ templates/nim/src/cart/tic80.nim | 78 ++++++++ 10 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 templates/nim/README.md create mode 100644 templates/nim/cart.nimble create mode 100644 templates/nim/config.nims create mode 100644 templates/nim/demo/bunny.tic create mode 100644 templates/nim/demo/bunnymark.nim create mode 100644 templates/nim/src/cart.nim create mode 100644 templates/nim/src/cart.tic create mode 100644 templates/nim/src/cart/internal.nim create mode 100755 templates/nim/src/cart/tic80.nim 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 0000000000000000000000000000000000000000..c6aeea14e588cd38de30558621155a570ba2e5be GIT binary patch literal 18560 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c5d4c3db01a8c873835ed19cf53958a1245a17e0 GIT binary patch literal 102861 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 literal 0 HcmV?d00001 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()