From 3dfc2ed6388ebcb7563154bb763df0000b585cfe Mon Sep 17 00:00:00 2001 From: nesbox Date: Sun, 19 May 2024 15:37:46 +0200 Subject: [PATCH] #2257: deploy scripts as shared libs --- .github/workflows/build.yml | 359 ++----- CMakeLists.txt | 18 +- build/android/app/build.gradle | 2 +- build/baremetalpi/Makefile | 1 + cmake/core.cmake | 2 +- cmake/fennel.cmake | 5 +- cmake/janet.cmake | 4 +- cmake/lua.cmake | 38 +- cmake/moon.cmake | 5 +- cmake/mruby.cmake | 12 +- cmake/naett.cmake | 2 +- cmake/pocketpy.cmake | 4 +- cmake/quickjs.cmake | 4 +- cmake/scheme.cmake | 4 +- cmake/sdl.cmake | 24 +- cmake/squirrel.cmake | 4 +- cmake/wasm.cmake | 4 +- cmake/wren.cmake | 4 +- include/tic80_config.h | 16 +- src/api/fennel.c | 22 +- src/api/janet.c | 2 +- src/api/js.c | 2 +- src/api/lua.c | 1715 +----------------------------- src/api/luaapi.c | 1720 +++++++++++++++++++++++++++++++ src/api/{lua_api.h => luaapi.h} | 19 +- src/api/moonscript.c | 22 +- src/api/mruby.c | 2 +- src/api/python.c | 2 +- src/api/scheme.c | 2 +- src/api/squirrel.c | 2 +- src/api/wasm.c | 2 +- src/api/wren.c | 2 +- 32 files changed, 1935 insertions(+), 2091 deletions(-) create mode 100644 src/api/luaapi.c rename src/api/{lua_api.h => luaapi.h} (69%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 67dc11e0..6b407578 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,16 +2,13 @@ name: Build on: [push, pull_request] -env: - BUILD_TYPE: MinSizeRel - jobs: # === Windows XP === winxp: runs-on: windows-2019 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -25,43 +22,31 @@ jobs: 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=%BUILD_TYPE% .. - cmake --build . --config %BUILD_TYPE% --parallel + 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@v3 + uses: actions/upload-artifact@v4 with: name: "tic80-winxp" - path: build/bin/tic80.exe + path: | + build/bin/tic80.exe + build/bin/*.dll - # === Windows XP PRO === - winxp-pro: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - name: Build + - 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=%BUILD_TYPE% -DBUILD_PRO=On .. - cmake --build . --config %BUILD_TYPE% --parallel + 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@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -74,82 +59,47 @@ jobs: shell: cmd run: | cd build - cmake -G "Visual Studio 16 2019" -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. - cmake --build . --config %BUILD_TYPE% --parallel + 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@v3 + uses: actions/upload-artifact@v4 with: name: "tic80-windows" - path: build/bin/tic80.exe + path: | + build/bin/tic80.exe + build/bin/*.dll - # === Windows PRO === - windows-pro: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - name: Build + - name: Build Pro shell: cmd run: | cd build - cmake -G "Visual Studio 16 2019" -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DBUILD_PRO=On .. - cmake --build . --config %BUILD_TYPE% --parallel - - # === Windows Sokol === - windows-sokol: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v3 - 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_SDL=Off -DBUILD_SOKOL=On -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. - cmake --build . --config %BUILD_TYPE% --parallel - cp bin/tic80-sokol.exe bin/tic80.exe - - - name: Deploy - uses: actions/upload-artifact@v3 - with: - name: "tic80-windows-sokol" - path: build/bin/tic80.exe + 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-2019 + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} steps: - # https://github.com/actions/runner-images/issues/2642#issuecomment-774988591 - - name: configure Pagefile - uses: al-cheb/configure-pagefile-action@v1.2 + - name: Setup Mingw + uses: msys2/setup-msys2@v2 with: - minimum-size: 16GB - maximum-size: 16GB - disk-root: "C:" - + msystem: UCRT64 + update: true + install: >- + base-devel + git + gcc + - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -158,47 +108,15 @@ jobs: shell: bash run: | cd build - cmake -G "MSYS Makefiles" -DCMAKE_C_COMPILER=C:/msys64/mingw64/bin/gcc.exe -DCMAKE_CXX_COMPILER=C:/msys64/mingw64/bin/c++.exe -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. - cmake --build . --config %BUILD_TYPE% --parallel - - - name: Deploy - uses: actions/upload-artifact@v3 - with: - name: "tic80-mingw" - path: build/bin/tic80.exe - - # === Ubuntu PRO === - linux-pro: - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - - name: Install - run: | - sudo apt-get update - sudo apt-get install libglu1-mesa-dev libasound2-dev libpulse-dev libaudio-dev libsamplerate0-dev libcurl4-openssl-dev -y - - - name: Build - run: | - cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SDLGPU=On -DBUILD_PRO=On .. - cmake --build . --config $BUILD_TYPE --parallel - cpack + 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 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -215,21 +133,22 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SDLGPU=On .. - cmake --build . --config $BUILD_TYPE --parallel - cpack + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=ON .. + cmake --build . --config MinSizeRel --parallel - - name: Deploy DEB - uses: actions/upload-artifact@v3 - with: - name: "tic80-linux-deb" - path: build/tic80.deb - - - name: Deploy ZIP - uses: actions/upload-artifact@v3 + - name: Deploy + uses: actions/upload-artifact@v4 with: name: "tic80-linux" - path: build/bin/tic80 + path: | + 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: @@ -250,46 +169,24 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake .. - cmake --build . --config $BUILD_TYPE --parallel - cpack - - - name: Deploy DEB - uses: actions/upload-artifact@v3 - with: - name: "tic80-rpi-deb" - path: build/tic80.deb + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. + cmake --build . --config MinSizeRel --parallel - name: Deploy uses: actions/upload-artifact@v3 with: name: "tic80-rpi" - path: build/bin/tic80 + path: | + build/bin/tic80 + build/bin/*.so - # === Raspberry PI PRO === - rpi-pro: - runs-on: ubuntu-latest - container: nesbox/rpi-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 gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf - - - name: Build + - name: Build Pro run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_PRO=On -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake .. - cmake --build . --config $BUILD_TYPE --parallel - cpack + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_PRO=On -DCMAKE_TOOLCHAIN_FILE=rpi/toolchain.cmake .. + cmake --build . --config MinSizeRel --parallel - # === Raspberry PI 1-3 Bare Metal === + # === Raspberry PI 1-4 Bare Metal === rpi-baremetal: runs-on: ubuntu-latest container: nesbox/baremetalpi-tic80:latest @@ -325,7 +222,7 @@ jobs: run: | git apply build/baremetalpi/circle.patch cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=baremetalpi/toolchain.cmake .. + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_TOOLCHAIN_FILE=baremetalpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. make tic80studio -j$(nproc) cd baremetalpi make -j$(nproc) @@ -385,7 +282,7 @@ jobs: run: | git apply build/baremetalpi/circle.patch cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=baremetalpi/toolchain.cmake .. + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_TOOLCHAIN_FILE=baremetalpi/toolchain.cmake -DBUILD_WITH_ALL=ON .. make tic80studio -j$(nproc) cd baremetalpi make -j$(nproc) @@ -431,7 +328,7 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/3ds.cmake -DN3DS=TRUE -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. + cmake -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/3ds.cmake -DN3DS=TRUE -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON .. make -j$(nproc) - name: Deploy @@ -445,7 +342,7 @@ jobs: runs-on: macos-12 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -456,50 +353,29 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SDLGPU=On .. - cmake --build . --config $BUILD_TYPE --parallel - cpack - cp *.dmg tic80.dmg - - - name: Deploy DMG - uses: actions/upload-artifact@v3 - with: - name: "tic80-macos-dmg" - path: build/tic80.dmg + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=ON .. + cmake --build . --config MinSizeRel --parallel - name: Deploy - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "tic80-macos" - path: build/bin/tic80 + path: | + build/bin/tic80 + build/bin/*.dylib - # === MacOS 12 PRO === - macos-pro: - runs-on: macos-12 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install - run: brew uninstall --ignore-dependencies libidn2 - - - name: Build + - name: Build Pro run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SDLGPU=On -DBUILD_PRO=On .. - cmake --build . --config $BUILD_TYPE --parallel - cpack - cp *.dmg tic80.dmg + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_PRO=On -DBUILD_WITH_ALL=ON .. + cmake --build . --config MinSizeRel --parallel -# === MacOS 14 / arm64 === + # === MacOS 14 / arm64 === macos-arm64: runs-on: macos-14 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -510,50 +386,29 @@ jobs: - name: Build run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SDLGPU=On .. - cmake --build . --config $BUILD_TYPE --parallel - cpack - cp *.dmg tic80.dmg - - - name: Deploy DMG - uses: actions/upload-artifact@v3 - with: - name: "tic80-macos-arm64-dmg" - path: build/tic80.dmg + cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=ON .. + cmake --build . --config MinSizeRel --parallel - name: Deploy - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "tic80-macos-arm64" - path: build/bin/tic80 + path: | + build/bin/tic80 + build/bin/*.dylib - # === MacOS 14 / arm64 PRO === - macos-arm64-pro: - runs-on: macos-14 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - - - name: Install - run: brew uninstall --ignore-dependencies libidn2 - - - name: Build + - name: Build Pro run: | cd build - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SDLGPU=On -DBUILD_PRO=On .. - cmake --build . --config $BUILD_TYPE --parallel - cpack - cp *.dmg tic80.dmg + 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 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -566,7 +421,7 @@ jobs: local-cache: true - name: set up JDK 11 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin' @@ -583,7 +438,7 @@ jobs: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - name: Deploy - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "tic80-android" path: build/android/tic80.apk @@ -593,9 +448,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: mymindstorm/setup-emsdk@v11 + - uses: mymindstorm/setup-emsdk@v14 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -607,39 +462,15 @@ jobs: - name: Build run: | cd build - emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. - cmake --build . --config $BUILD_TYPE --parallel - mkdir bin/html bin/html-export - cp html/export.html bin/html-export/index.html - cp bin/tic80*.js bin/html-export/ - cp bin/tic80*.wasm bin/html-export/ - cp html/index.html bin/html/index.html - cp html/export.html bin/html/export.html - cp bin/tic80.js bin/html/tic80.js - cp bin/tic80.wasm bin/html/tic80.wasm - cp bin/tic80.js webapp/tic80.js - cp bin/tic80.wasm webapp/tic80.wasm + emcmake cmake -DBUILD_SDLGPU=On -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_WITH_ALL=ON .. + cmake --build . --config MinSizeRel --parallel + cp html/index.html bin/index.html - name: Deploy - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "tic80-html" path: | - build/bin/html/tic80.js - build/bin/html/tic80.wasm - build/bin/html/index.html - build/bin/html/export.html - - - name: Deploy WebApp - uses: actions/upload-artifact@v3 - with: - name: "tic80-webapp" - path: | - build/webapp/index.html - build/webapp/serviceworker.js - build/webapp/tic80-180.png - build/webapp/tic80-192.png - build/webapp/tic80-512.png - build/webapp/tic80.webmanifest - build/webapp/tic80.js - build/webapp/tic80.wasm + build/bin/tic80.js + build/bin/tic80.wasm + build/bin/index.html diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b382fe2..49b48710 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,19 +14,20 @@ message("VERSION_HASH: ${VERSION_HASH}") configure_file("${PROJECT_SOURCE_DIR}/version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/version.h") -if(ANDROID OR EMSCRIPTEN OR N3DS OR RPI) - set(BUILD_LIBRETRO_DEFAULT OFF) - set(BUILD_PLAYER_DEFAULT OFF) - set(BUILD_TOOLS OFF) +if(ANDROID OR EMSCRIPTEN OR N3DS OR BAREMETALPI) + set(BUILD_STATIC_DEFAULT ON) else() - set(BUILD_LIBRETRO_DEFAULT ON) - set(BUILD_PLAYER_DEFAULT ON) - set(BUILD_TOOLS ON) + set(BUILD_STATIC_DEFAULT OFF) endif() +set(BUILD_PLAYER_DEFAULT OFF) +set(BUILD_LIBRETRO_DEFAULT OFF) set(BUILD_TOUCH_INPUT_DEFAULT ${ANDROID}) +set(BUILD_TOOLS OFF) +set(BUILD_WITH_ALL_DEFAULT OFF) -option(BUILD_STATIC "Static runtime" ON) +option(BUILD_STATIC "Static runtime" ${BUILD_STATIC_DEFAULT}) +option(BUILD_WITH_ALL "Build all supported scripts" ${BUILD_WITH_ALL_DEFAULT}) option(BUILD_SDL "SDL Enabled" ON) option(BUILD_SDLGPU "SDL GPU Enabled" OFF) option(BUILD_SOKOL "Sokol Enabled" OFF) @@ -66,6 +67,7 @@ target_compile_definitions(runtime INTERFACE BUILD_DEPRECATED) message("BUILD_STATIC: ${BUILD_STATIC}") message("BUILD_SDLGPU: ${BUILD_SDLGPU}") message("BUILD_TOUCH_INPUT: ${BUILD_TOUCH_INPUT}") +message("BUILD_WITH_ALL: ${BUILD_WITH_ALL}") if (N3DS) set(BUILD_SDL OFF) diff --git a/build/android/app/build.gradle b/build/android/app/build.gradle index 85cdba2d..d73fa7c1 100644 --- a/build/android/app/build.gradle +++ b/build/android/app/build.gradle @@ -25,7 +25,7 @@ android { arguments "APP_PLATFORM=android-31" } cmake { - arguments "-DBUILD_WITH_MRUBY=Off", "-DBUILD_PRO=Off", "-DCMAKE_BUILD_TYPE=MinSizeRel" + arguments "-DBUILD_WITH_MRUBY=OFF", "-DBUILD_PRO=Off", "-DCMAKE_BUILD_TYPE=MinSizeRel", "-DBUILD_WITH_ALL=ON" } } } diff --git a/build/baremetalpi/Makefile b/build/baremetalpi/Makefile index 9143e878..6fbb3787 100644 --- a/build/baremetalpi/Makefile +++ b/build/baremetalpi/Makefile @@ -27,6 +27,7 @@ LIBS := \ $(TIC80LIB)/libtic80core.a \ $(TIC80LIB)/libgiflib.a \ $(TIC80LIB)/liblpeg.a \ + $(TIC80LIB)/libluaapi.a \ $(TIC80LIB)/liblua.a \ $(TIC80LIB)/libmoon.a \ $(TIC80LIB)/libfennel.a \ diff --git a/cmake/core.cmake b/cmake/core.cmake index 1dfabc6e..e5db8267 100644 --- a/cmake/core.cmake +++ b/cmake/core.cmake @@ -108,5 +108,5 @@ if(BUILD_DEPRECATED) endif() if(LINUX) - target_link_libraries(tic80core PRIVATE m) + target_link_libraries(tic80core PRIVATE m dl) endif() diff --git a/cmake/fennel.cmake b/cmake/fennel.cmake index 59fb38d1..13b6f24c 100644 --- a/cmake/fennel.cmake +++ b/cmake/fennel.cmake @@ -2,6 +2,9 @@ # Fennel ################################ +option(BUILD_WITH_FENNEL "Fennel Enabled" ${BUILD_WITH_ALL}) +message("BUILD_WITH_FENNEL: ${BUILD_WITH_FENNEL}") + if(BUILD_WITH_FENNEL) add_library(fennel ${TIC_RUNTIME} ${CMAKE_SOURCE_DIR}/src/api/fennel.c) @@ -10,7 +13,7 @@ if(BUILD_WITH_FENNEL) set_target_properties(fennel PROPERTIES PREFIX "") endif() - target_link_libraries(fennel PRIVATE lua runtime) + target_link_libraries(fennel PRIVATE runtime luaapi) target_include_directories(fennel PRIVATE ${THIRDPARTY_DIR}/fennel diff --git a/cmake/janet.cmake b/cmake/janet.cmake index 3915d7db..271caf8a 100644 --- a/cmake/janet.cmake +++ b/cmake/janet.cmake @@ -2,9 +2,7 @@ # Janet ################################ -set(BUILD_WITH_JANET_DEFAULT TRUE) - -option(BUILD_WITH_JANET "Janet Enabled" ${BUILD_WITH_JANET_DEFAULT}) +option(BUILD_WITH_JANET "Janet Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_JANET: ${BUILD_WITH_JANET}") if(BUILD_WITH_JANET) diff --git a/cmake/lua.cmake b/cmake/lua.cmake index 1b50762a..aa582857 100644 --- a/cmake/lua.cmake +++ b/cmake/lua.cmake @@ -2,23 +2,9 @@ # LUA ################################ -set(BUILD_WITH_LUA_DEFAULT TRUE) -set(BUILD_WITH_MOON_DEFAULT TRUE) -set(BUILD_WITH_FENNEL_DEFAULT TRUE) - -option(BUILD_WITH_LUA "Lua Enabled" ${BUILD_WITH_LUA_DEFAULT}) +option(BUILD_WITH_LUA "Lua Enabled" ON) message("BUILD_WITH_LUA: ${BUILD_WITH_LUA}") -option(BUILD_WITH_MOON "Moon Enabled" ${BUILD_WITH_MOON_DEFAULT}) -message("BUILD_WITH_MOON: ${BUILD_WITH_MOON}") - -option(BUILD_WITH_FENNEL "Fennel Enabled" ${BUILD_WITH_FENNEL_DEFAULT}) -message("BUILD_WITH_FENNEL: ${BUILD_WITH_FENNEL}") - -if(BUILD_WITH_MOON OR BUILD_WITH_FENNEL) - set(BUILD_WITH_LUA TRUE) -endif() - if(BUILD_WITH_LUA) set(LUA_DIR ${THIRDPARTY_DIR}/lua) @@ -58,18 +44,28 @@ if(BUILD_WITH_LUA) ${LUA_DIR}/lbitlib.c ) - list(APPEND LUA_SRC ${CMAKE_SOURCE_DIR}/src/api/lua.c) - list(APPEND LUA_SRC ${CMAKE_SOURCE_DIR}/src/api/parse_note.c) + add_library(luaapi STATIC + ${LUA_SRC} + ${CMAKE_SOURCE_DIR}/src/api/luaapi.c + ${CMAKE_SOURCE_DIR}/src/api/parse_note.c + ) - add_library(lua ${TIC_RUNTIME} ${LUA_SRC}) + add_library(lua ${TIC_RUNTIME} ${CMAKE_SOURCE_DIR}/src/api/lua.c) if(NOT BUILD_STATIC) set_target_properties(lua PROPERTIES PREFIX "") endif() - target_link_libraries(lua PRIVATE runtime) + target_link_libraries(lua PRIVATE runtime luaapi) + + target_compile_definitions(luaapi PRIVATE LUA_COMPAT_5_2) + + target_include_directories(luaapi + PUBLIC ${THIRDPARTY_DIR}/lua + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/src + ) - target_compile_definitions(lua PRIVATE LUA_COMPAT_5_2) target_include_directories(lua PUBLIC ${THIRDPARTY_DIR}/lua PRIVATE @@ -78,7 +74,7 @@ if(BUILD_WITH_LUA) ) if(N3DS) - target_compile_definitions(lua PUBLIC LUA_32BITS) + target_compile_definitions(luaapi PUBLIC LUA_32BITS) endif() target_compile_definitions(lua INTERFACE TIC_BUILD_WITH_LUA) diff --git a/cmake/moon.cmake b/cmake/moon.cmake index def8fcb5..8ebbfd4a 100644 --- a/cmake/moon.cmake +++ b/cmake/moon.cmake @@ -2,6 +2,9 @@ # MoonScript ################################ +option(BUILD_WITH_MOON "Moon Enabled" ${BUILD_WITH_ALL}) +message("BUILD_WITH_MOON: ${BUILD_WITH_MOON}") + if(BUILD_WITH_MOON) set(LPEG_DIR ${THIRDPARTY_DIR}/lpeg) @@ -22,7 +25,7 @@ if(BUILD_WITH_MOON) set_target_properties(moon PROPERTIES PREFIX "") endif() - target_link_libraries(moon PRIVATE lpeg lua runtime) + target_link_libraries(moon PRIVATE lpeg runtime luaapi) target_include_directories(moon PRIVATE diff --git a/cmake/mruby.cmake b/cmake/mruby.cmake index 7f846635..84ee140c 100644 --- a/cmake/mruby.cmake +++ b/cmake/mruby.cmake @@ -2,18 +2,14 @@ # MRUBY ################################ -find_program(RUBY ruby) -find_program(RAKE rake) -if(NOT RAKE) - set(BUILD_WITH_MRUBY_DEFAULT FALSE) -else() - set(BUILD_WITH_MRUBY_DEFAULT TRUE) -endif() -option(BUILD_WITH_MRUBY "mruby Enabled" ${BUILD_WITH_MRUBY_DEFAULT}) +option(BUILD_WITH_MRUBY "mruby Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_MRUBY: ${BUILD_WITH_MRUBY}") if(BUILD_WITH_MRUBY) + find_program(RUBY ruby) + find_program(RAKE rake) + list(APPEND RUBY_SRC ${CMAKE_SOURCE_DIR}/src/api/mruby.c) list(APPEND RUBY_SRC ${CMAKE_SOURCE_DIR}/src/api/parse_note.c) diff --git a/cmake/naett.cmake b/cmake/naett.cmake index e314367e..3ddf2d96 100644 --- a/cmake/naett.cmake +++ b/cmake/naett.cmake @@ -22,7 +22,7 @@ if(USE_NAETT) target_link_libraries(naett INTERFACE winhttp) elseif(LINUX) target_include_directories(naett PRIVATE ${CURL_INCLUDE_DIRS}) - target_link_libraries(naett ${CURL_LIBRARIES}) + target_link_libraries(naett ${CURL_LIBRARIES} pthread) elseif(APPLE) target_link_libraries(naett "-framework Cocoa") diff --git a/cmake/pocketpy.cmake b/cmake/pocketpy.cmake index adff8144..4356f0ab 100644 --- a/cmake/pocketpy.cmake +++ b/cmake/pocketpy.cmake @@ -2,9 +2,7 @@ # pocketpy (Python) ################################ -set(BUILD_WITH_PYTHON_DEFAULT TRUE) - -option(BUILD_WITH_PYTHON "Python Enabled" ${BUILD_WITH_PYTHON_DEFAULT}) +option(BUILD_WITH_PYTHON "Python Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_PYTHON: ${BUILD_WITH_PYTHON}") if(BUILD_WITH_PYTHON) diff --git a/cmake/quickjs.cmake b/cmake/quickjs.cmake index 92fae79e..80c87a02 100644 --- a/cmake/quickjs.cmake +++ b/cmake/quickjs.cmake @@ -2,9 +2,7 @@ # QuickJS ################################ -set(BUILD_WITH_JS_DEFAULT TRUE) - -option(BUILD_WITH_JS "JS Enabled" ${BUILD_WITH_JS_DEFAULT}) +option(BUILD_WITH_JS "JS Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_JS: ${BUILD_WITH_JS}") if(BUILD_WITH_JS) diff --git a/cmake/scheme.cmake b/cmake/scheme.cmake index a9f85198..85486750 100644 --- a/cmake/scheme.cmake +++ b/cmake/scheme.cmake @@ -2,9 +2,7 @@ # SCHEME (S7) ################################ -set(BUILD_WITH_SCHEME_DEFAULT TRUE) - -option(BUILD_WITH_SCHEME "Scheme Enabled" ${BUILD_WITH_SCHEME_DEFAULT}) +option(BUILD_WITH_SCHEME "Scheme Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_SCHEME: ${BUILD_WITH_SCHEME}") if(BUILD_WITH_SCHEME) diff --git a/cmake/sdl.cmake b/cmake/sdl.cmake index 02c1270a..2b4d8e6f 100644 --- a/cmake/sdl.cmake +++ b/cmake/sdl.cmake @@ -12,6 +12,8 @@ if(BUILD_SDL AND NOT EMSCRIPTEN AND NOT RPI) set(SDL_STATIC_PIC ON CACHE BOOL "" FORCE) endif() + set(SDL_SHARED OFF CACHE BOOL "" FORCE) + add_subdirectory(${THIRDPARTY_DIR}/sdl2) endif() @@ -39,13 +41,7 @@ if(BUILD_SDL AND BUILD_PLAYER AND NOT RPI) target_link_options(player-sdl PRIVATE -static) endif() - target_link_libraries(player-sdl PRIVATE tic80core SDL2main) - - if(BUILD_STATIC) - target_link_libraries(player-sdl PRIVATE SDL2-static) - else() - target_link_libraries(player-sdl PRIVATE SDL2) - endif() + target_link_libraries(player-sdl PRIVATE tic80core SDL2main SDL2-static) endif() ################################ @@ -117,11 +113,7 @@ if(ANDROID) endif() if(NOT EMSCRIPTEN) - if(BUILD_STATIC) - target_link_libraries(sdlgpu SDL2-static) - else() - target_link_libraries(sdlgpu SDL2) - endif() + target_link_libraries(sdlgpu SDL2-static) endif() endif() @@ -190,13 +182,9 @@ if(BUILD_SDL) else() if(EMSCRIPTEN) elseif(RPI) - target_link_libraries(tic80 libSDL2.a bcm_host) + target_link_libraries(tic80 libSDL2.a bcm_host pthread) else() - if(BUILD_STATIC) - target_link_libraries(tic80 SDL2-static) - else() - target_link_libraries(tic80 SDL2) - endif() + target_link_libraries(tic80 SDL2-static) endif() endif() diff --git a/cmake/squirrel.cmake b/cmake/squirrel.cmake index 6559e91d..b4627643 100644 --- a/cmake/squirrel.cmake +++ b/cmake/squirrel.cmake @@ -2,9 +2,7 @@ # SQUIRREL ################################ -set(BUILD_WITH_SQUIRREL_DEFAULT TRUE) - -option(BUILD_WITH_SQUIRREL "Squirrel Enabled" ${BUILD_WITH_SQUIRREL_DEFAULT}) +option(BUILD_WITH_SQUIRREL "Squirrel Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_SQUIRREL: ${BUILD_WITH_SQUIRREL}") if(BUILD_WITH_SQUIRREL) diff --git a/cmake/wasm.cmake b/cmake/wasm.cmake index acd1c88d..955c8bb5 100644 --- a/cmake/wasm.cmake +++ b/cmake/wasm.cmake @@ -2,9 +2,7 @@ # WASM ################################ -set(BUILD_WITH_WASM_DEFAULT TRUE) - -option(BUILD_WITH_WASM "Wasm Enabled" ${BUILD_WITH_WASM_DEFAULT}) +option(BUILD_WITH_WASM "Wasm Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_WASM: ${BUILD_WITH_WASM}") if(BUILD_WITH_WASM) diff --git a/cmake/wren.cmake b/cmake/wren.cmake index e261788b..37f83b06 100644 --- a/cmake/wren.cmake +++ b/cmake/wren.cmake @@ -2,9 +2,7 @@ # WREN ################################ -set(BUILD_WITH_WREN_DEFAULT TRUE) - -option(BUILD_WITH_WREN "WREN Enabled" ${BUILD_WITH_WREN_DEFAULT}) +option(BUILD_WITH_WREN "WREN Enabled" ${BUILD_WITH_ALL}) message("BUILD_WITH_WREN: ${BUILD_WITH_WREN}") if(BUILD_WITH_WREN) diff --git a/include/tic80_config.h b/include/tic80_config.h index 0ee4fd0e..80afd972 100644 --- a/include/tic80_config.h +++ b/include/tic80_config.h @@ -37,9 +37,9 @@ # undef __TIC_WINDOWS__ # define __TIC_WINDOWS__ 1 # define TIC_MODULE_EXT ".dll" -# if defined(_MSC_VER) && defined(_USING_V110_SDK71_) -# define __TIC_WIN7__ 1 -# endif +# if defined(_MSC_VER) && defined(_USING_V110_SDK71_) +# define __TIC_WIN7__ 1 +# endif #endif #if defined(ANDROID) || defined(__ANDROID__) @@ -52,6 +52,16 @@ # define TIC_MODULE_EXT ".so" #endif +#if defined(TIC_RUNTIME_STATIC) +# define TIC_EXPORT +#else +# if defined(__TIC_WINDOWS__) +# define TIC_EXPORT __declspec(dllexport) +# elif defined(__GNUC__) && __GNUC__ >= 4 +# define TIC_EXPORT __attribute__ ((visibility("default"))) +# endif +#endif + #ifndef TIC80_API # if defined(TIC80_SHARED) # if defined(__TIC_WINDOWS__) diff --git a/src/api/fennel.c b/src/api/fennel.c index bf5f9342..433c18f8 100644 --- a/src/api/fennel.c +++ b/src/api/fennel.c @@ -21,7 +21,7 @@ // SOFTWARE. #include "core/core.h" -#include "lua_api.h" +#include "luaapi.h" #include "fennel.h" @@ -41,12 +41,12 @@ static const char* execute_fennel_src = FENNEL_CODE( static bool initFennel(tic_mem* tic, const char* code) { tic_core* core = (tic_core*)tic; - closeLua(tic); + luaapi_close(tic); lua_State* lua = core->currentVM = luaL_newstate(); - lua_open_builtins(lua); + luaapi_open(lua); - initLuaAPI(core); + luaapi_init(core); { lua_State* fennel = core->currentVM; @@ -187,7 +187,7 @@ static const u8 DemoRom[] = #include "../build/assets/fenneldemo.tic.dat" }; -const tic_script EXPORT_SCRIPT(Fennel) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Fennel) = { .id = 14, .name = "fennel", @@ -195,15 +195,15 @@ const tic_script EXPORT_SCRIPT(Fennel) = .projectComment = ";;", { .init = initFennel, - .close = closeLua, - .tick = callLuaTick, - .boot = callLuaBoot, + .close = luaapi_close, + .tick = luaapi_tick, + .boot = luaapi_boot, .callback = { - .scanline = callLuaScanline, - .border = callLuaBorder, - .menu = callLuaMenu, + .scanline = luaapi_scn, + .border = luaapi_bdr, + .menu = luaapi_menu, }, }, diff --git a/src/api/janet.c b/src/api/janet.c index 77b7b43c..b693c610 100644 --- a/src/api/janet.c +++ b/src/api/janet.c @@ -1276,7 +1276,7 @@ static const u8 MarkRom[] = #include "../build/assets/janetmark.tic.dat" }; -JANET_API const tic_script EXPORT_SCRIPT(Janet) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Janet) = { .id = 18, .name = "janet", diff --git a/src/api/js.c b/src/api/js.c index cae11d4d..1c49497e 100644 --- a/src/api/js.c +++ b/src/api/js.c @@ -1264,7 +1264,7 @@ static const u8 MarkRom[] = #include "../build/assets/jsmark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Js) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Js) = { .id = 12, .name = "js", diff --git a/src/api/lua.c b/src/api/lua.c index 926b531d..0c118cdf 100644 --- a/src/api/lua.c +++ b/src/api/lua.c @@ -21,6 +21,7 @@ // SOFTWARE. #include "core/core.h" +#include "luaapi.h" #include #include @@ -28,1578 +29,16 @@ #include #include -extern bool parse_note(const char* noteStr, s32* note, s32* octave); - -static inline s32 getLuaNumber(lua_State* lua, s32 index) -{ - return (s32)lua_tonumber(lua, index); -} - -static void registerLuaFunction(tic_core* core, lua_CFunction func, const char *name) -{ - lua_pushlightuserdata(core->currentVM, core); - lua_pushcclosure(core->currentVM, func, 1); - lua_setglobal(core->currentVM, name); -} - -static tic_core* getLuaCore(lua_State* lua) -{ - tic_core* core = lua_touserdata(lua, lua_upvalueindex(1)); - return core; -} - -static s32 lua_peek(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top >= 1) - { - s32 address = getLuaNumber(lua, 1); - s32 bits = BITS_IN_BYTE; - - if(top == 2) - bits = getLuaNumber(lua, 2); - - lua_pushinteger(lua, core->api.peek(tic, address, bits)); - return 1; - } - else luaL_error(lua, "invalid parameters, peek(addr,bits)\n"); - - return 0; -} - -static s32 lua_poke(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top >= 2) - { - s32 address = getLuaNumber(lua, 1); - u8 value = getLuaNumber(lua, 2); - s32 bits = BITS_IN_BYTE; - - if(top == 3) - bits = getLuaNumber(lua, 3); - - core->api.poke(tic, address, value, bits); - } - else luaL_error(lua, "invalid parameters, poke(addr,val,bits)\n"); - - return 0; -} - -static s32 lua_peek1(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 1) - { - s32 address = getLuaNumber(lua, 1); - lua_pushinteger(lua, core->api.peek1(tic, address)); - return 1; - } - else luaL_error(lua, "invalid parameters, peek1(addr)\n"); - - return 0; -} - -static s32 lua_poke1(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 2) - { - s32 address = getLuaNumber(lua, 1); - u8 value = getLuaNumber(lua, 2); - - core->api.poke1(tic, address, value); - } - else luaL_error(lua, "invalid parameters, poke1(addr,val)\n"); - - return 0; -} - -static s32 lua_peek2(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 1) - { - s32 address = getLuaNumber(lua, 1); - lua_pushinteger(lua, core->api.peek2(tic, address)); - return 1; - } - else luaL_error(lua, "invalid parameters, peek2(addr)\n"); - - return 0; -} - -static s32 lua_poke2(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 2) - { - s32 address = getLuaNumber(lua, 1); - u8 value = getLuaNumber(lua, 2); - - core->api.poke2(tic, address, value); - } - else luaL_error(lua, "invalid parameters, poke2(addr,val)\n"); - - return 0; -} - -static s32 lua_peek4(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 1) - { - s32 address = getLuaNumber(lua, 1); - lua_pushinteger(lua, core->api.peek4(tic, address)); - return 1; - } - else luaL_error(lua, "invalid parameters, peek4(addr)\n"); - - return 0; -} - -static s32 lua_poke4(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 2) - { - s32 address = getLuaNumber(lua, 1); - u8 value = getLuaNumber(lua, 2); - - core->api.poke4(tic, address, value); - } - else luaL_error(lua, "invalid parameters, poke4(addr,val)\n"); - - return 0; -} - -static s32 lua_cls(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.cls(tic, top == 1 ? getLuaNumber(lua, 1) : 0); - - return 0; -} - -static s32 lua_pix(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top >= 2) - { - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top >= 3) - { - s32 color = getLuaNumber(lua, 3); - core->api.pix(tic, x, y, color, false); - } - else - { - lua_pushinteger(lua, core->api.pix(tic, x, y, 0, true)); - return 1; - } - - } - else luaL_error(lua, "invalid parameters, pix(x y [color])\n"); - - return 0; -} - -static s32 lua_line(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 5) - { - float x0 = lua_tonumber(lua, 1); - float y0 = lua_tonumber(lua, 2); - float x1 = lua_tonumber(lua, 3); - float y1 = lua_tonumber(lua, 4); - s32 color = getLuaNumber(lua, 5); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.line(tic, x0, y0, x1, y1, color); - } - else luaL_error(lua, "invalid parameters, line(x0,y0,x1,y1,color)\n"); - - return 0; -} - -static s32 lua_rect(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 5) - { - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 w = getLuaNumber(lua, 3); - s32 h = getLuaNumber(lua, 4); - s32 color = getLuaNumber(lua, 5); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.rect(tic, x, y, w, h, color); - } - else luaL_error(lua, "invalid parameters, rect(x,y,w,h,color)\n"); - - return 0; -} - -static s32 lua_rectb(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 5) - { - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 w = getLuaNumber(lua, 3); - s32 h = getLuaNumber(lua, 4); - s32 color = getLuaNumber(lua, 5); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.rectb(tic, x, y, w, h, color); - } - else luaL_error(lua, "invalid parameters, rectb(x,y,w,h,color)\n"); - - return 0; -} - -static s32 lua_circ(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 4) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 radius = getLuaNumber(lua, 3); - s32 color = getLuaNumber(lua, 4); - - core->api.circ(tic, x, y, radius, color); - } - else luaL_error(lua, "invalid parameters, circ(x,y,radius,color)\n"); - - return 0; -} - -static s32 lua_circb(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 4) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 radius = getLuaNumber(lua, 3); - s32 color = getLuaNumber(lua, 4); - - core->api.circb(tic, x, y, radius, color); - } - else luaL_error(lua, "invalid parameters, circb(x,y,radius,color)\n"); - - return 0; -} - -static s32 lua_elli(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 5) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 a = getLuaNumber(lua, 3); - s32 b = getLuaNumber(lua, 4); - s32 color = getLuaNumber(lua, 5); - - core->api.elli(tic, x, y, a, b, color); - } - else luaL_error(lua, "invalid parameters, elli(x,y,a,b,color)\n"); - - return 0; -} - -static s32 lua_ellib(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 5) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 a = getLuaNumber(lua, 3); - s32 b = getLuaNumber(lua, 4); - s32 color = getLuaNumber(lua, 5); - - core->api.ellib(tic, x, y, a, b, color); - } - else luaL_error(lua, "invalid parameters, ellib(x,y,a,b,color)\n"); - - return 0; -} - -static s32 lua_tri(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 7) - { - float pt[6]; - - for(s32 i = 0; i < COUNT_OF(pt); i++) - pt[i] = lua_tonumber(lua, i+1); - - s32 color = getLuaNumber(lua, 7); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); - } - else luaL_error(lua, "invalid parameters, tri(x1,y1,x2,y2,x3,y3,color)\n"); - - return 0; -} - -static s32 lua_trib(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 7) - { - float pt[6]; - - for(s32 i = 0; i < COUNT_OF(pt); i++) - pt[i] = lua_tonumber(lua, i+1); - - s32 color = getLuaNumber(lua, 7); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.trib(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); - } - else luaL_error(lua, "invalid parameters, trib(x1,y1,x2,y2,x3,y3,color)\n"); - - return 0; -} - -#if defined(BUILD_DEPRECATED) - -static s32 lua_textri(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if (top >= 12) - { - float pt[12]; - - for (s32 i = 0; i < COUNT_OF(pt); i++) - pt[i] = (float)lua_tonumber(lua, i + 1); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - static u8 colors[TIC_PALETTE_SIZE]; - s32 count = 0; - bool use_map = false; - - // check for use map - if (top >= 13) - use_map = lua_toboolean(lua, 13); - - // check for chroma - if(top >= 14) - { - if(lua_istable(lua, 14)) - { - for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) - { - lua_rawgeti(lua, 14, i); - if(lua_isnumber(lua, -1)) - { - colors[i-1] = getLuaNumber(lua, -1); - count++; - lua_pop(lua, 1); - } - else - { - lua_pop(lua, 1); - break; - } - } - } - else - { - colors[0] = getLuaNumber(lua, 14); - count = 1; - } - } - - core->api.textri(tic, - pt[0], pt[1], // xy 1 - pt[2], pt[3], // xy 2 - pt[4], pt[5], // xy 3 - pt[6], pt[7], // uv 1 - pt[8], pt[9], // uv 2 - pt[10], pt[11], // uv 3 - use_map, // use map - colors, count); // chroma - } - - return 0; -} - -#endif - -static s32 lua_ttri(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if (top >= 12) - { - float pt[12]; - - for (s32 i = 0; i < COUNT_OF(pt); i++) - pt[i] = (float)lua_tonumber(lua, i + 1); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - static u8 colors[TIC_PALETTE_SIZE]; - s32 count = 0; - tic_texture_src src = tic_tiles_texture; - - // check for texture src - if (top >= 13) - { - src = lua_isboolean(lua, 13) - ? (lua_toboolean(lua, 13) ? tic_map_texture : tic_tiles_texture) - : lua_tointeger(lua, 13); - } - // check for chroma - if(top >= 14) - { - if(lua_istable(lua, 14)) - { - for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) - { - lua_rawgeti(lua, 14, i); - if(lua_isnumber(lua, -1)) - { - colors[i-1] = getLuaNumber(lua, -1); - count++; - lua_pop(lua, 1); - } - else - { - lua_pop(lua, 1); - break; - } - } - } - else - { - colors[0] = getLuaNumber(lua, 14); - count = 1; - } - } - - float z[3]; - bool depth = false; - - if(top == 17) - { - for (s32 i = 0; i < COUNT_OF(z); i++) - z[i] = (float)lua_tonumber(lua, i + 15); - - depth = true; - } - - core->api.ttri(tic, pt[0], pt[1], // xy 1 - pt[2], pt[3], // xy 2 - pt[4], pt[5], // xy 3 - pt[6], pt[7], // uv 1 - pt[8], pt[9], // uv 2 - pt[10], pt[11], // uv 3 - src, // texture source - colors, count, // chroma - z[0], z[1], z[2], depth); // depth - } - else luaL_error(lua, "invalid parameters, ttri(x1,y1,x2,y2,x3,y3,u1,v1,u2,v2,u3,v3,[src=0],[chroma=off],[z1=0],[z2=0],[z3=0])\n"); - return 0; -} - - -static s32 lua_clip(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 0) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.clip(tic, 0, 0, TIC80_WIDTH, TIC80_HEIGHT); - } - else if(top == 4) - { - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - s32 w = getLuaNumber(lua, 3); - s32 h = getLuaNumber(lua, 4); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.clip((tic_mem*)getLuaCore(lua), x, y, w, h); - } - else luaL_error(lua, "invalid parameters, use clip(x,y,w,h) or clip()\n"); - - return 0; -} - -static s32 lua_btnp(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 top = lua_gettop(lua); - - if (top == 0) - { - lua_pushinteger(lua, core->api.btnp(tic, -1, -1, -1)); - } - else if(top == 1) - { - s32 index = getLuaNumber(lua, 1) & 0x1f; - - lua_pushboolean(lua, core->api.btnp(tic, index, -1, -1)); - } - else if (top == 3) - { - s32 index = getLuaNumber(lua, 1) & 0x1f; - u32 hold = getLuaNumber(lua, 2); - u32 period = getLuaNumber(lua, 3); - - lua_pushboolean(lua, core->api.btnp(tic, index, hold, period)); - } - else - { - luaL_error(lua, "invalid params, btnp [ id [ hold period ] ]\n"); - return 0; - } - - return 1; -} - -static s32 lua_btn(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 top = lua_gettop(lua); - - if (top == 0) - { - lua_pushinteger(lua, core->api.btn(tic, -1)); - } - else if (top == 1) - { - bool pressed = core->api.btn(tic, getLuaNumber(lua, 1) & 0x1f); - lua_pushboolean(lua, pressed); - } - else - { - luaL_error(lua, "invalid params, btn [ id ]\n"); - return 0; - } - - return 1; -} - -static s32 lua_spr(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - s32 index = 0; - s32 x = 0; - s32 y = 0; - s32 w = 1; - s32 h = 1; - s32 scale = 1; - tic_flip flip = tic_no_flip; - tic_rotate rotate = tic_no_rotate; - static u8 colors[TIC_PALETTE_SIZE]; - s32 count = 0; - - if(top >= 1) - { - index = getLuaNumber(lua, 1); - - if(top >= 3) - { - x = getLuaNumber(lua, 2); - y = getLuaNumber(lua, 3); - - if(top >= 4) - { - if(lua_istable(lua, 4)) - { - for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) - { - lua_rawgeti(lua, 4, i); - if(lua_isnumber(lua, -1)) - { - colors[i-1] = getLuaNumber(lua, -1); - count++; - lua_pop(lua, 1); - } - else - { - lua_pop(lua, 1); - break; - } - } - } - else - { - colors[0] = getLuaNumber(lua, 4); - count = 1; - } - - if(top >= 5) - { - scale = getLuaNumber(lua, 5); - - if(top >= 6) - { - flip = getLuaNumber(lua, 6); - - if(top >= 7) - { - rotate = getLuaNumber(lua, 7); - - if(top >= 9) - { - w = getLuaNumber(lua, 8); - h = getLuaNumber(lua, 9); - } - } - } - } - } - } - } - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate); - - return 0; -} - -static s32 lua_mget(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 2) - { - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - u8 value = core->api.mget(tic, x, y); - lua_pushinteger(lua, value); - return 1; - } - else luaL_error(lua, "invalid params, mget(x,y)\n"); - - return 0; -} - -static s32 lua_mset(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 3) - { - s32 x = getLuaNumber(lua, 1); - s32 y = getLuaNumber(lua, 2); - u8 val = getLuaNumber(lua, 3); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.mset(tic, x, y, val); - } - else luaL_error(lua, "invalid params, mget(x,y)\n"); - - return 0; -} - -typedef struct -{ - lua_State* lua; - s32 reg; -} RemapData; - -static void remapCallback(void* data, s32 x, s32 y, RemapResult* result) -{ - RemapData* remap = (RemapData*)data; - lua_State* lua = remap->lua; - - lua_rawgeti(lua, LUA_REGISTRYINDEX, remap->reg); - lua_pushinteger(lua, result->index); - lua_pushinteger(lua, x); - lua_pushinteger(lua, y); - lua_pcall(lua, 3, 3, 0); - - result->index = getLuaNumber(lua, -3); - result->flip = getLuaNumber(lua, -2); - result->rotate = getLuaNumber(lua, -1); -} - -static s32 lua_map(lua_State* lua) -{ - s32 x = 0; - s32 y = 0; - s32 w = TIC_MAP_SCREEN_WIDTH; - s32 h = TIC_MAP_SCREEN_HEIGHT; - s32 sx = 0; - s32 sy = 0; - s32 scale = 1; - static u8 colors[TIC_PALETTE_SIZE]; - s32 count = 0; - - s32 top = lua_gettop(lua); - - if(top >= 2) - { - x = getLuaNumber(lua, 1); - y = getLuaNumber(lua, 2); - - if(top >= 4) - { - w = getLuaNumber(lua, 3); - h = getLuaNumber(lua, 4); - - if(top >= 6) - { - sx = getLuaNumber(lua, 5); - sy = getLuaNumber(lua, 6); - - if(top >= 7) - { - if(lua_istable(lua, 7)) - { - for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) - { - lua_rawgeti(lua, 7, i); - if(lua_isnumber(lua, -1)) - { - colors[i-1] = getLuaNumber(lua, -1); - count++; - lua_pop(lua, 1); - } - else - { - lua_pop(lua, 1); - break; - } - } - } - else - { - colors[0] = getLuaNumber(lua, 7); - count = 1; - } - - if(top >= 8) - { - scale = getLuaNumber(lua, 8); - - if(top >= 9) - { - if (lua_isfunction(lua, 9)) - { - s32 remap = luaL_ref(lua, LUA_REGISTRYINDEX); - - RemapData data = {lua, remap}; - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.map(tic, x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data); - - luaL_unref(lua, LUA_REGISTRYINDEX, data.reg); - - return 0; - } - } - } - } - } - } - } - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.map((tic_mem*)getLuaCore(lua), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); - - return 0; -} - -static s32 lua_music(lua_State* lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top == 0) core->api.music(tic, -1, 0, 0, false, false, -1, -1); - else if(top >= 1) - { - s32 track = getLuaNumber(lua, 1); - - if(track > MUSIC_TRACKS - 1) - { - luaL_error(lua, "invalid music track index"); - return 0; - } - - core->api.music(tic, -1, 0, 0, false, false, -1, -1); - - s32 frame = -1; - s32 row = -1; - bool loop = true; - bool sustain = false; - s32 tempo = -1; - s32 speed = -1; - - if(top >= 2) - { - frame = getLuaNumber(lua, 2); - - if(top >= 3) - { - row = getLuaNumber(lua, 3); - - if(top >= 4) - { - loop = lua_toboolean(lua, 4); - - if (top >= 5) - { - sustain = lua_toboolean(lua, 5); - - if (top >= 6) - { - tempo = getLuaNumber(lua, 6); - - if (top >= 7) - { - speed = getLuaNumber(lua, 7); - } - } - } - - } - } - } - - core->api.music(tic, track, frame, row, loop, sustain, tempo, speed); - } - else luaL_error(lua, "invalid params, use music(track)\n"); - - return 0; -} - -static s32 lua_sfx(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top >= 1) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 note = -1; - s32 octave = -1; - s32 duration = -1; - s32 channel = 0; - s32 volumes[TIC80_SAMPLE_CHANNELS] = {MAX_VOLUME, MAX_VOLUME}; - s32 speed = SFX_DEF_SPEED; - - s32 index = getLuaNumber(lua, 1); - - if(index < SFX_COUNT) - { - if (index >= 0) - { - tic_sample* effect = tic->ram->sfx.samples.data + index; - - note = effect->note; - octave = effect->octave; - speed = effect->speed; - } - - if(top >= 2) - { - if(lua_isinteger(lua, 2)) - { - s32 id = getLuaNumber(lua, 2); - note = id % NOTES; - octave = id / NOTES; - } - else if(lua_isstring(lua, 2)) - { - const char* noteStr = lua_tostring(lua, 2); - - if(!parse_note(noteStr, ¬e, &octave)) - { - luaL_error(lua, "invalid note, should be like C#4\n"); - return 0; - } - } - - if(top >= 3) - { - duration = getLuaNumber(lua, 3); - - if(top >= 4) - { - channel = getLuaNumber(lua, 4); - - if(top >= 5) - { - if(lua_istable(lua, 5)) - { - for(s32 i = 0; i < COUNT_OF(volumes); i++) - { - volumes[i] = lua_rawgeti(lua, 5, i + 1); - lua_pop(lua, 1); - } - } - else volumes[0] = volumes[1] = getLuaNumber(lua, 5); - - if(top >= 6) - { - speed = getLuaNumber(lua, 6); - } - } - } - } - } - - if (channel >= 0 && channel < TIC_SOUND_CHANNELS) - { - core->api.sfx(tic, index, note, octave, duration, channel, volumes[0] & 0xf, volumes[1] & 0xf, speed); - } - else luaL_error(lua, "unknown channel\n"); - } - else luaL_error(lua, "unknown sfx index\n"); - } - else luaL_error(lua, "invalid sfx params\n"); - - return 0; -} - -static s32 lua_vbank(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 prev = core->state.vbank.id; - - if(lua_gettop(lua) == 1) - core->api.vbank(tic, getLuaNumber(lua, 1)); - - lua_pushinteger(lua, prev); - return 1; -} - -static s32 lua_sync(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - bool toCart = false; - u32 mask = 0; - s32 bank = 0; - - if(lua_gettop(lua) >= 1) - { - mask = getLuaNumber(lua, 1); - - if(lua_gettop(lua) >= 2) - { - bank = getLuaNumber(lua, 2); - - if(lua_gettop(lua) >= 3) - { - toCart = lua_toboolean(lua, 3); - } - } - } - - if(bank >= 0 && bank < TIC_BANKS) - core->api.sync(tic, mask, bank, toCart); - else - luaL_error(lua, "sync() error, invalid bank"); - - return 0; -} - -static s32 lua_reset(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - - core->state.initialized = false; - - return 0; -} - -static s32 lua_key(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = &core->memory; - - s32 top = lua_gettop(lua); - - if (top == 0) - { - lua_pushboolean(lua, core->api.key(tic, tic_key_unknown)); - } - else if (top == 1) - { - tic_key key = getLuaNumber(lua, 1); - - if(key < tic_keys_count) - lua_pushboolean(lua, core->api.key(tic, key)); - else - { - luaL_error(lua, "unknown keyboard code\n"); - return 0; - } - } - else - { - luaL_error(lua, "invalid params, key [code]\n"); - return 0; - } - - return 1; -} - -static s32 lua_keyp(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = &core->memory; - - s32 top = lua_gettop(lua); - - if (top == 0) - { - lua_pushboolean(lua, core->api.keyp(tic, tic_key_unknown, -1, -1)); - } - else - { - tic_key key = getLuaNumber(lua, 1); - - if(key >= tic_keys_count) - { - luaL_error(lua, "unknown keyboard code\n"); - } - else - { - if(top == 1) - { - lua_pushboolean(lua, core->api.keyp(tic, key, -1, -1)); - } - else if(top == 3) - { - u32 hold = getLuaNumber(lua, 2); - u32 period = getLuaNumber(lua, 3); - - lua_pushboolean(lua, core->api.keyp(tic, key, hold, period)); - } - else - { - luaL_error(lua, "invalid params, keyp [ code [ hold period ] ]\n"); - return 0; - } - } - } - - return 1; -} - -static s32 lua_memcpy(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 3) - { - s32 dest = getLuaNumber(lua, 1); - s32 src = getLuaNumber(lua, 2); - s32 size = getLuaNumber(lua, 3); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - core->api.memcpy(tic, dest, src, size); - } - else luaL_error(lua, "invalid params, memcpy(dest,src,size)\n"); - - return 0; -} - -static s32 lua_memset(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top == 3) - { - s32 dest = getLuaNumber(lua, 1); - u8 value = getLuaNumber(lua, 2); - s32 size = getLuaNumber(lua, 3); - - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.memset(tic, dest, value, size); - } - else luaL_error(lua, "invalid params, memset(dest,val,size)\n"); - - return 0; -} - -static const char* printString(lua_State* lua, s32 index) -{ - lua_getglobal(lua, "tostring"); - lua_pushvalue(lua, -1); - lua_pushvalue(lua, index); - lua_call(lua, 1, 1); - - const char* text = lua_tostring(lua, -1); - - lua_pop(lua, 2); - - return text; -} - -static s32 lua_font(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - s32 top = lua_gettop(lua); - - if(top >= 1) - { - const char* text = printString(lua, 1); - s32 x = 0; - s32 y = 0; - s32 width = TIC_SPRITESIZE; - s32 height = TIC_SPRITESIZE; - u8 chromakey = 0; - bool fixed = false; - s32 scale = 1; - bool alt = false; - - if(top >= 3) - { - x = getLuaNumber(lua, 2); - y = getLuaNumber(lua, 3); - - if(top >= 4) - { - chromakey = getLuaNumber(lua, 4); - - if(top >= 6) - { - width = getLuaNumber(lua, 5); - height = getLuaNumber(lua, 6); - - if(top >= 7) - { - fixed = lua_toboolean(lua, 7); - - if(top >= 8) - { - scale = getLuaNumber(lua, 8); - - if(top >= 9) - { - alt = lua_toboolean(lua, 9); - } - } - } - } - } - } - - if(scale == 0) - { - lua_pushinteger(lua, 0); - return 1; - } - - s32 size = core->api.font(tic, text, x, y, &chromakey, 1, width, height, fixed, scale, alt); - - lua_pushinteger(lua, size); - - return 1; - } - - return 0; -} - -static s32 lua_print(lua_State* lua) -{ - s32 top = lua_gettop(lua); - - if(top >= 1) - { - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - s32 x = 0; - s32 y = 0; - s32 color = TIC_DEFAULT_COLOR; - bool fixed = false; - s32 scale = 1; - bool alt = false; - - const char* text = printString(lua, 1); - - if(top >= 3) - { - x = getLuaNumber(lua, 2); - y = getLuaNumber(lua, 3); - - if(top >= 4) - { - color = getLuaNumber(lua, 4) % TIC_PALETTE_SIZE; - - if(top >= 5) - { - fixed = lua_toboolean(lua, 5); - - if(top >= 6) - { - scale = getLuaNumber(lua, 6); - - if(top >= 7) - { - alt = lua_toboolean(lua, 7); - } - } - } - } - } - - if(scale == 0) - { - lua_pushinteger(lua, 0); - return 1; - } - - s32 size = core->api.print(tic, text ? text : "nil", x, y, color, fixed, scale, alt); - - lua_pushinteger(lua, size); - - return 1; - } - - return 0; -} - -static s32 lua_trace(lua_State *lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - if(top >= 1) - { - const char* text = printString(lua, 1); - u8 color = TIC_DEFAULT_COLOR; - - if(top >= 2) - { - color = getLuaNumber(lua, 2); - } - - core->api.trace(tic, text, color); - } - else luaL_error(lua, "invalid params, trace(text,[color])\n"); - - return 0; -} - -static s32 lua_pmem(lua_State *lua) -{ - s32 top = lua_gettop(lua); - tic_core* core = getLuaCore(lua); - tic_mem* tic = &core->memory; - - if(top >= 1) - { - u32 index = getLuaNumber(lua, 1); - - if(index < TIC_PERSISTENT_SIZE) - { - u32 val = core->api.pmem(tic, index, 0, false); - - if(top >= 2) - { - core->api.pmem(tic, index, (u32)lua_tointeger(lua, 2), true); - } - - lua_pushinteger(lua, val); - - return 1; - } - - luaL_error(lua, "invalid persistent tic index\n"); - } - else luaL_error(lua, "invalid params, pmem(index [val]) -> val\n"); - - return 0; -} - -static s32 lua_time(lua_State *lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - lua_pushnumber(lua, core->api.time(tic)); - - return 1; -} - -static s32 lua_tstamp(lua_State *lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - lua_pushnumber(lua, core->api.tstamp(tic)); - - return 1; -} - -static s32 lua_exit(lua_State *lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - - core->api.exit(tic); - - return 0; -} - -static s32 lua_mouse(lua_State *lua) -{ - tic_core* core = getLuaCore(lua); - - { - tic_point pos = core->api.mouse((tic_mem*)core); - - lua_pushinteger(lua, pos.x); - lua_pushinteger(lua, pos.y); - } - - const tic80_mouse* mouse = &core->memory.ram->input.mouse; - - lua_pushboolean(lua, mouse->left); - lua_pushboolean(lua, mouse->middle); - lua_pushboolean(lua, mouse->right); - lua_pushinteger(lua, mouse->scrollx); - lua_pushinteger(lua, mouse->scrolly); - - return 7; -} - -static s32 lua_fget(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - s32 top = lua_gettop(lua); - - if(top >= 1) - { - u32 index = getLuaNumber(lua, 1); - - if(top >= 2) - { - u32 flag = getLuaNumber(lua, 2); - lua_pushboolean(lua, core->api.fget(tic, index, flag)); - return 1; - } - } - - luaL_error(lua, "invalid params, fget(sprite,flag)\n"); - - return 0; -} - -static s32 lua_fset(lua_State* lua) -{ - tic_core* core = getLuaCore(lua); - tic_mem* tic = (tic_mem*)core; - s32 top = lua_gettop(lua); - - if(top >= 1) - { - u32 index = getLuaNumber(lua, 1); - - if(top >= 2) - { - u32 flag = getLuaNumber(lua, 2); - - if(top >= 3) - { - bool value = lua_toboolean(lua, 3); - core->api.fset(tic, index, flag, value); - return 0; - } - } - } - - luaL_error(lua, "invalid params, fset(sprite,flag,value)\n"); - - return 0; -} - -static s32 lua_dofile(lua_State *lua) -{ - luaL_error(lua, "unknown method: \"dofile\"\n"); - - return 0; -} - -static s32 lua_loadfile(lua_State *lua) -{ - luaL_error(lua, "unknown method: \"loadfile\"\n"); - - return 0; -} - -void lua_open_builtins(lua_State *lua) -{ - static const luaL_Reg loadedlibs[] = - { - { "_G", luaopen_base }, - { LUA_LOADLIBNAME, luaopen_package }, - { LUA_COLIBNAME, luaopen_coroutine }, - { LUA_TABLIBNAME, luaopen_table }, - { LUA_STRLIBNAME, luaopen_string }, - { LUA_MATHLIBNAME, luaopen_math }, - { LUA_DBLIBNAME, luaopen_debug }, - { NULL, NULL } - }; - - for (const luaL_Reg *lib = loadedlibs; lib->func; lib++) - { - luaL_requiref(lua, lib->name, lib->func, 1); - lua_pop(lua, 1); - } -} - -void initLuaAPI(tic_core* core) -{ - static const struct{lua_CFunction func; const char* name;} ApiItems[] = - { -#define API_FUNC_DEF(name, ...) {lua_ ## name, #name}, - TIC_API_LIST(API_FUNC_DEF) -#undef API_FUNC_DEF - -#if defined(BUILD_DEPRECATED) - {lua_textri, "textri"}, -#endif - }; - - for (s32 i = 0; i < COUNT_OF(ApiItems); i++) - registerLuaFunction(core, ApiItems[i].func, ApiItems[i].name); - - registerLuaFunction(core, lua_dofile, "dofile"); - registerLuaFunction(core, lua_loadfile, "loadfile"); -} - -void closeLua(tic_mem* tic) -{ - tic_core* core = (tic_core*)tic; - - if(core->currentVM) - { - lua_close(core->currentVM); - core->currentVM = NULL; - } -} - static bool initLua(tic_mem* tic, const char* code) { tic_core* core = (tic_core*)tic; - closeLua(tic); + luaapi_close(tic); lua_State* lua = core->currentVM = luaL_newstate(); - lua_open_builtins(lua); + luaapi_open(lua); - initLuaAPI(core); + luaapi_init(core); { lua_State* lua = core->currentVM; @@ -1616,135 +55,6 @@ static bool initLua(tic_mem* tic, const char* code) return true; } -/* -** Message handler which appends stract trace to exceptions. -** This function was extractred from lua.c. -*/ -static s32 msghandler (lua_State *lua) -{ - const char *msg = lua_tostring(lua, 1); - if (msg == NULL) /* is error object not a string? */ - { - if (luaL_callmeta(lua, 1, "__tostring") && /* does it have a metamethod */ - lua_type(lua, -1) == LUA_TSTRING) /* that produces a string? */ - return 1; /* that is the message */ - else - msg = lua_pushfstring(lua, "(error object is a %s value)", luaL_typename(lua, 1)); - } - luaL_traceback(lua, lua, msg, 1); /* append a standard traceback */ - return 1; /* return the traceback */ -} - -/* -** Interface to 'lua_pcall', which sets appropriate message handler function. -** Please use this function for all top level lua functions. -** This function was extractred from lua.c (and stripped of signal handling) -*/ -static s32 docall (lua_State *lua, s32 narg, s32 nres) -{ - s32 status = 0; - s32 base = lua_gettop(lua) - narg; /* function index */ - lua_pushcfunction(lua, msghandler); /* push message handler */ - lua_insert(lua, base); /* put it under function and args */ - status = lua_pcall(lua, narg, nres, base); - lua_remove(lua, base); /* remove message handler from the stack */ - return status; -} - -void callLuaTick(tic_mem* tic) -{ - tic_core* core = (tic_core*)tic; - - lua_State* lua = core->currentVM; - - if(lua) - { - lua_getglobal(lua, TIC_FN); - if(lua_isfunction(lua, -1)) - { - if(docall(lua, 0, 0) != LUA_OK) - { - core->data->error(core->data->data, lua_tostring(lua, -1)); - return; - } - -#if defined(BUILD_DEPRECATED) - // call OVR() callback for backward compatibility - { - lua_getglobal(lua, OVR_FN); - if(lua_isfunction(lua, -1)) - { - OVR(core) - { - if(docall(lua, 0, 0) != LUA_OK) - core->data->error(core->data->data, lua_tostring(lua, -1)); - } - } - else lua_pop(lua, 1); - } -#endif - } - else - { - lua_pop(lua, 1); - core->data->error(core->data->data, "'function TIC()...' isn't found :("); - } - } -} - -void callLuaIntCallback(tic_mem* tic, s32 value, void* data, const char* name) -{ - tic_core* core = (tic_core*)tic; - lua_State* lua = core->currentVM; - - if (lua) - { - lua_getglobal(lua, name); - if(lua_isfunction(lua, -1)) - { - lua_pushinteger(lua, value); - if(docall(lua, 1, 0) != LUA_OK) - core->data->error(core->data->data, lua_tostring(lua, -1)); - } - else lua_pop(lua, 1); - } -} - -void callLuaScanline(tic_mem* tic, s32 row, void* data) -{ - callLuaIntCallback(tic, row, data, SCN_FN); - - // try to call old scanline - callLuaIntCallback(tic, row, data, "scanline"); -} - -void callLuaBorder(tic_mem* tic, s32 row, void* data) -{ - callLuaIntCallback(tic, row, data, BDR_FN); -} - -void callLuaMenu(tic_mem* tic, s32 index, void* data) -{ - callLuaIntCallback(tic, index, data, MENU_FN); -} - -void callLuaBoot(tic_mem* tic) -{ - tic_core* core = (tic_core*)tic; - lua_State* lua = core->currentVM; - - if (lua) - { - lua_getglobal(lua, BOOT_FN); - if(lua_isfunction(lua, -1)) - { - if(docall(lua, 0, 0) != LUA_OK) - core->data->error(core->data->data, lua_tostring(lua, -1)); - } - else lua_pop(lua, 1); - } -} - static const char* const LuaKeywords [] = { "and", "break", "do", "else", "elseif", @@ -1816,7 +126,8 @@ static const tic_outline_item* getLuaOutline(const char* code, s32* size) return items; } -static void evalLua(tic_mem* tic, const char* code) { +static void evalLua(tic_mem* tic, const char* code) +{ tic_core* core = (tic_core*)tic; lua_State* lua = core->currentVM; @@ -1895,7 +206,7 @@ static const u8 DemoCar[] = #include "../build/assets/car.tic.dat" }; -const tic_script EXPORT_SCRIPT(Lua) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Lua) = { .id = 10, .name = "lua", @@ -1903,15 +214,15 @@ const tic_script EXPORT_SCRIPT(Lua) = .projectComment = "--", { .init = initLua, - .close = closeLua, - .tick = callLuaTick, - .boot = callLuaBoot, + .close = luaapi_close, + .tick = luaapi_tick, + .boot = luaapi_boot, .callback = { - .scanline = callLuaScanline, - .border = callLuaBorder, - .menu = callLuaMenu, + .scanline = luaapi_scn, + .border = luaapi_bdr, + .menu = luaapi_menu, }, }, diff --git a/src/api/luaapi.c b/src/api/luaapi.c new file mode 100644 index 00000000..cd1ce9df --- /dev/null +++ b/src/api/luaapi.c @@ -0,0 +1,1720 @@ +// MIT License + +// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "core/core.h" + +#include +#include +#include +#include +#include + +extern bool parse_note(const char* noteStr, s32* note, s32* octave); + +static inline s32 getLuaNumber(lua_State* lua, s32 index) +{ + return (s32)lua_tonumber(lua, index); +} + +static void registerLuaFunction(tic_core* core, lua_CFunction func, const char *name) +{ + lua_pushlightuserdata(core->currentVM, core); + lua_pushcclosure(core->currentVM, func, 1); + lua_setglobal(core->currentVM, name); +} + +static tic_core* getLuaCore(lua_State* lua) +{ + tic_core* core = lua_touserdata(lua, lua_upvalueindex(1)); + return core; +} + +static s32 lua_peek(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top >= 1) + { + s32 address = getLuaNumber(lua, 1); + s32 bits = BITS_IN_BYTE; + + if(top == 2) + bits = getLuaNumber(lua, 2); + + lua_pushinteger(lua, core->api.peek(tic, address, bits)); + return 1; + } + else luaL_error(lua, "invalid parameters, peek(addr,bits)\n"); + + return 0; +} + +static s32 lua_poke(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top >= 2) + { + s32 address = getLuaNumber(lua, 1); + u8 value = getLuaNumber(lua, 2); + s32 bits = BITS_IN_BYTE; + + if(top == 3) + bits = getLuaNumber(lua, 3); + + core->api.poke(tic, address, value, bits); + } + else luaL_error(lua, "invalid parameters, poke(addr,val,bits)\n"); + + return 0; +} + +static s32 lua_peek1(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 1) + { + s32 address = getLuaNumber(lua, 1); + lua_pushinteger(lua, core->api.peek1(tic, address)); + return 1; + } + else luaL_error(lua, "invalid parameters, peek1(addr)\n"); + + return 0; +} + +static s32 lua_poke1(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 2) + { + s32 address = getLuaNumber(lua, 1); + u8 value = getLuaNumber(lua, 2); + + core->api.poke1(tic, address, value); + } + else luaL_error(lua, "invalid parameters, poke1(addr,val)\n"); + + return 0; +} + +static s32 lua_peek2(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 1) + { + s32 address = getLuaNumber(lua, 1); + lua_pushinteger(lua, core->api.peek2(tic, address)); + return 1; + } + else luaL_error(lua, "invalid parameters, peek2(addr)\n"); + + return 0; +} + +static s32 lua_poke2(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 2) + { + s32 address = getLuaNumber(lua, 1); + u8 value = getLuaNumber(lua, 2); + + core->api.poke2(tic, address, value); + } + else luaL_error(lua, "invalid parameters, poke2(addr,val)\n"); + + return 0; +} + +static s32 lua_peek4(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 1) + { + s32 address = getLuaNumber(lua, 1); + lua_pushinteger(lua, core->api.peek4(tic, address)); + return 1; + } + else luaL_error(lua, "invalid parameters, peek4(addr)\n"); + + return 0; +} + +static s32 lua_poke4(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 2) + { + s32 address = getLuaNumber(lua, 1); + u8 value = getLuaNumber(lua, 2); + + core->api.poke4(tic, address, value); + } + else luaL_error(lua, "invalid parameters, poke4(addr,val)\n"); + + return 0; +} + +static s32 lua_cls(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.cls(tic, top == 1 ? getLuaNumber(lua, 1) : 0); + + return 0; +} + +static s32 lua_pix(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top >= 2) + { + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top >= 3) + { + s32 color = getLuaNumber(lua, 3); + core->api.pix(tic, x, y, color, false); + } + else + { + lua_pushinteger(lua, core->api.pix(tic, x, y, 0, true)); + return 1; + } + + } + else luaL_error(lua, "invalid parameters, pix(x y [color])\n"); + + return 0; +} + +static s32 lua_line(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 5) + { + float x0 = lua_tonumber(lua, 1); + float y0 = lua_tonumber(lua, 2); + float x1 = lua_tonumber(lua, 3); + float y1 = lua_tonumber(lua, 4); + s32 color = getLuaNumber(lua, 5); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.line(tic, x0, y0, x1, y1, color); + } + else luaL_error(lua, "invalid parameters, line(x0,y0,x1,y1,color)\n"); + + return 0; +} + +static s32 lua_rect(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 5) + { + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 w = getLuaNumber(lua, 3); + s32 h = getLuaNumber(lua, 4); + s32 color = getLuaNumber(lua, 5); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.rect(tic, x, y, w, h, color); + } + else luaL_error(lua, "invalid parameters, rect(x,y,w,h,color)\n"); + + return 0; +} + +static s32 lua_rectb(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 5) + { + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 w = getLuaNumber(lua, 3); + s32 h = getLuaNumber(lua, 4); + s32 color = getLuaNumber(lua, 5); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.rectb(tic, x, y, w, h, color); + } + else luaL_error(lua, "invalid parameters, rectb(x,y,w,h,color)\n"); + + return 0; +} + +static s32 lua_circ(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 4) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 radius = getLuaNumber(lua, 3); + s32 color = getLuaNumber(lua, 4); + + core->api.circ(tic, x, y, radius, color); + } + else luaL_error(lua, "invalid parameters, circ(x,y,radius,color)\n"); + + return 0; +} + +static s32 lua_circb(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 4) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 radius = getLuaNumber(lua, 3); + s32 color = getLuaNumber(lua, 4); + + core->api.circb(tic, x, y, radius, color); + } + else luaL_error(lua, "invalid parameters, circb(x,y,radius,color)\n"); + + return 0; +} + +static s32 lua_elli(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 5) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 a = getLuaNumber(lua, 3); + s32 b = getLuaNumber(lua, 4); + s32 color = getLuaNumber(lua, 5); + + core->api.elli(tic, x, y, a, b, color); + } + else luaL_error(lua, "invalid parameters, elli(x,y,a,b,color)\n"); + + return 0; +} + +static s32 lua_ellib(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 5) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 a = getLuaNumber(lua, 3); + s32 b = getLuaNumber(lua, 4); + s32 color = getLuaNumber(lua, 5); + + core->api.ellib(tic, x, y, a, b, color); + } + else luaL_error(lua, "invalid parameters, ellib(x,y,a,b,color)\n"); + + return 0; +} + +static s32 lua_tri(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 7) + { + float pt[6]; + + for(s32 i = 0; i < COUNT_OF(pt); i++) + pt[i] = lua_tonumber(lua, i+1); + + s32 color = getLuaNumber(lua, 7); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.tri(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); + } + else luaL_error(lua, "invalid parameters, tri(x1,y1,x2,y2,x3,y3,color)\n"); + + return 0; +} + +static s32 lua_trib(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 7) + { + float pt[6]; + + for(s32 i = 0; i < COUNT_OF(pt); i++) + pt[i] = lua_tonumber(lua, i+1); + + s32 color = getLuaNumber(lua, 7); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.trib(tic, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color); + } + else luaL_error(lua, "invalid parameters, trib(x1,y1,x2,y2,x3,y3,color)\n"); + + return 0; +} + +#if defined(BUILD_DEPRECATED) + +static s32 lua_textri(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if (top >= 12) + { + float pt[12]; + + for (s32 i = 0; i < COUNT_OF(pt); i++) + pt[i] = (float)lua_tonumber(lua, i + 1); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + static u8 colors[TIC_PALETTE_SIZE]; + s32 count = 0; + bool use_map = false; + + // check for use map + if (top >= 13) + use_map = lua_toboolean(lua, 13); + + // check for chroma + if(top >= 14) + { + if(lua_istable(lua, 14)) + { + for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) + { + lua_rawgeti(lua, 14, i); + if(lua_isnumber(lua, -1)) + { + colors[i-1] = getLuaNumber(lua, -1); + count++; + lua_pop(lua, 1); + } + else + { + lua_pop(lua, 1); + break; + } + } + } + else + { + colors[0] = getLuaNumber(lua, 14); + count = 1; + } + } + + core->api.textri(tic, + pt[0], pt[1], // xy 1 + pt[2], pt[3], // xy 2 + pt[4], pt[5], // xy 3 + pt[6], pt[7], // uv 1 + pt[8], pt[9], // uv 2 + pt[10], pt[11], // uv 3 + use_map, // use map + colors, count); // chroma + } + + return 0; +} + +#endif + +static s32 lua_ttri(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if (top >= 12) + { + float pt[12]; + + for (s32 i = 0; i < COUNT_OF(pt); i++) + pt[i] = (float)lua_tonumber(lua, i + 1); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + static u8 colors[TIC_PALETTE_SIZE]; + s32 count = 0; + tic_texture_src src = tic_tiles_texture; + + // check for texture src + if (top >= 13) + { + src = lua_isboolean(lua, 13) + ? (lua_toboolean(lua, 13) ? tic_map_texture : tic_tiles_texture) + : lua_tointeger(lua, 13); + } + // check for chroma + if(top >= 14) + { + if(lua_istable(lua, 14)) + { + for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) + { + lua_rawgeti(lua, 14, i); + if(lua_isnumber(lua, -1)) + { + colors[i-1] = getLuaNumber(lua, -1); + count++; + lua_pop(lua, 1); + } + else + { + lua_pop(lua, 1); + break; + } + } + } + else + { + colors[0] = getLuaNumber(lua, 14); + count = 1; + } + } + + float z[3]; + bool depth = false; + + if(top == 17) + { + for (s32 i = 0; i < COUNT_OF(z); i++) + z[i] = (float)lua_tonumber(lua, i + 15); + + depth = true; + } + + core->api.ttri(tic, pt[0], pt[1], // xy 1 + pt[2], pt[3], // xy 2 + pt[4], pt[5], // xy 3 + pt[6], pt[7], // uv 1 + pt[8], pt[9], // uv 2 + pt[10], pt[11], // uv 3 + src, // texture source + colors, count, // chroma + z[0], z[1], z[2], depth); // depth + } + else luaL_error(lua, "invalid parameters, ttri(x1,y1,x2,y2,x3,y3,u1,v1,u2,v2,u3,v3,[src=0],[chroma=off],[z1=0],[z2=0],[z3=0])\n"); + return 0; +} + + +static s32 lua_clip(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 0) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.clip(tic, 0, 0, TIC80_WIDTH, TIC80_HEIGHT); + } + else if(top == 4) + { + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + s32 w = getLuaNumber(lua, 3); + s32 h = getLuaNumber(lua, 4); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.clip((tic_mem*)getLuaCore(lua), x, y, w, h); + } + else luaL_error(lua, "invalid parameters, use clip(x,y,w,h) or clip()\n"); + + return 0; +} + +static s32 lua_btnp(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 top = lua_gettop(lua); + + if (top == 0) + { + lua_pushinteger(lua, core->api.btnp(tic, -1, -1, -1)); + } + else if(top == 1) + { + s32 index = getLuaNumber(lua, 1) & 0x1f; + + lua_pushboolean(lua, core->api.btnp(tic, index, -1, -1)); + } + else if (top == 3) + { + s32 index = getLuaNumber(lua, 1) & 0x1f; + u32 hold = getLuaNumber(lua, 2); + u32 period = getLuaNumber(lua, 3); + + lua_pushboolean(lua, core->api.btnp(tic, index, hold, period)); + } + else + { + luaL_error(lua, "invalid params, btnp [ id [ hold period ] ]\n"); + return 0; + } + + return 1; +} + +static s32 lua_btn(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 top = lua_gettop(lua); + + if (top == 0) + { + lua_pushinteger(lua, core->api.btn(tic, -1)); + } + else if (top == 1) + { + bool pressed = core->api.btn(tic, getLuaNumber(lua, 1) & 0x1f); + lua_pushboolean(lua, pressed); + } + else + { + luaL_error(lua, "invalid params, btn [ id ]\n"); + return 0; + } + + return 1; +} + +static s32 lua_spr(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + s32 index = 0; + s32 x = 0; + s32 y = 0; + s32 w = 1; + s32 h = 1; + s32 scale = 1; + tic_flip flip = tic_no_flip; + tic_rotate rotate = tic_no_rotate; + static u8 colors[TIC_PALETTE_SIZE]; + s32 count = 0; + + if(top >= 1) + { + index = getLuaNumber(lua, 1); + + if(top >= 3) + { + x = getLuaNumber(lua, 2); + y = getLuaNumber(lua, 3); + + if(top >= 4) + { + if(lua_istable(lua, 4)) + { + for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) + { + lua_rawgeti(lua, 4, i); + if(lua_isnumber(lua, -1)) + { + colors[i-1] = getLuaNumber(lua, -1); + count++; + lua_pop(lua, 1); + } + else + { + lua_pop(lua, 1); + break; + } + } + } + else + { + colors[0] = getLuaNumber(lua, 4); + count = 1; + } + + if(top >= 5) + { + scale = getLuaNumber(lua, 5); + + if(top >= 6) + { + flip = getLuaNumber(lua, 6); + + if(top >= 7) + { + rotate = getLuaNumber(lua, 7); + + if(top >= 9) + { + w = getLuaNumber(lua, 8); + h = getLuaNumber(lua, 9); + } + } + } + } + } + } + } + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.spr(tic, index, x, y, w, h, colors, count, scale, flip, rotate); + + return 0; +} + +static s32 lua_mget(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 2) + { + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + u8 value = core->api.mget(tic, x, y); + lua_pushinteger(lua, value); + return 1; + } + else luaL_error(lua, "invalid params, mget(x,y)\n"); + + return 0; +} + +static s32 lua_mset(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 3) + { + s32 x = getLuaNumber(lua, 1); + s32 y = getLuaNumber(lua, 2); + u8 val = getLuaNumber(lua, 3); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.mset(tic, x, y, val); + } + else luaL_error(lua, "invalid params, mget(x,y)\n"); + + return 0; +} + +typedef struct +{ + lua_State* lua; + s32 reg; +} RemapData; + +static void remapCallback(void* data, s32 x, s32 y, RemapResult* result) +{ + RemapData* remap = (RemapData*)data; + lua_State* lua = remap->lua; + + lua_rawgeti(lua, LUA_REGISTRYINDEX, remap->reg); + lua_pushinteger(lua, result->index); + lua_pushinteger(lua, x); + lua_pushinteger(lua, y); + lua_pcall(lua, 3, 3, 0); + + result->index = getLuaNumber(lua, -3); + result->flip = getLuaNumber(lua, -2); + result->rotate = getLuaNumber(lua, -1); +} + +static s32 lua_map(lua_State* lua) +{ + s32 x = 0; + s32 y = 0; + s32 w = TIC_MAP_SCREEN_WIDTH; + s32 h = TIC_MAP_SCREEN_HEIGHT; + s32 sx = 0; + s32 sy = 0; + s32 scale = 1; + static u8 colors[TIC_PALETTE_SIZE]; + s32 count = 0; + + s32 top = lua_gettop(lua); + + if(top >= 2) + { + x = getLuaNumber(lua, 1); + y = getLuaNumber(lua, 2); + + if(top >= 4) + { + w = getLuaNumber(lua, 3); + h = getLuaNumber(lua, 4); + + if(top >= 6) + { + sx = getLuaNumber(lua, 5); + sy = getLuaNumber(lua, 6); + + if(top >= 7) + { + if(lua_istable(lua, 7)) + { + for(s32 i = 1; i <= TIC_PALETTE_SIZE; i++) + { + lua_rawgeti(lua, 7, i); + if(lua_isnumber(lua, -1)) + { + colors[i-1] = getLuaNumber(lua, -1); + count++; + lua_pop(lua, 1); + } + else + { + lua_pop(lua, 1); + break; + } + } + } + else + { + colors[0] = getLuaNumber(lua, 7); + count = 1; + } + + if(top >= 8) + { + scale = getLuaNumber(lua, 8); + + if(top >= 9) + { + if (lua_isfunction(lua, 9)) + { + s32 remap = luaL_ref(lua, LUA_REGISTRYINDEX); + + RemapData data = {lua, remap}; + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.map(tic, x, y, w, h, sx, sy, colors, count, scale, remapCallback, &data); + + luaL_unref(lua, LUA_REGISTRYINDEX, data.reg); + + return 0; + } + } + } + } + } + } + } + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.map((tic_mem*)getLuaCore(lua), x, y, w, h, sx, sy, colors, count, scale, NULL, NULL); + + return 0; +} + +static s32 lua_music(lua_State* lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top == 0) core->api.music(tic, -1, 0, 0, false, false, -1, -1); + else if(top >= 1) + { + s32 track = getLuaNumber(lua, 1); + + if(track > MUSIC_TRACKS - 1) + { + luaL_error(lua, "invalid music track index"); + return 0; + } + + core->api.music(tic, -1, 0, 0, false, false, -1, -1); + + s32 frame = -1; + s32 row = -1; + bool loop = true; + bool sustain = false; + s32 tempo = -1; + s32 speed = -1; + + if(top >= 2) + { + frame = getLuaNumber(lua, 2); + + if(top >= 3) + { + row = getLuaNumber(lua, 3); + + if(top >= 4) + { + loop = lua_toboolean(lua, 4); + + if (top >= 5) + { + sustain = lua_toboolean(lua, 5); + + if (top >= 6) + { + tempo = getLuaNumber(lua, 6); + + if (top >= 7) + { + speed = getLuaNumber(lua, 7); + } + } + } + + } + } + } + + core->api.music(tic, track, frame, row, loop, sustain, tempo, speed); + } + else luaL_error(lua, "invalid params, use music(track)\n"); + + return 0; +} + +static s32 lua_sfx(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top >= 1) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 note = -1; + s32 octave = -1; + s32 duration = -1; + s32 channel = 0; + s32 volumes[TIC80_SAMPLE_CHANNELS] = {MAX_VOLUME, MAX_VOLUME}; + s32 speed = SFX_DEF_SPEED; + + s32 index = getLuaNumber(lua, 1); + + if(index < SFX_COUNT) + { + if (index >= 0) + { + tic_sample* effect = tic->ram->sfx.samples.data + index; + + note = effect->note; + octave = effect->octave; + speed = effect->speed; + } + + if(top >= 2) + { + if(lua_isinteger(lua, 2)) + { + s32 id = getLuaNumber(lua, 2); + note = id % NOTES; + octave = id / NOTES; + } + else if(lua_isstring(lua, 2)) + { + const char* noteStr = lua_tostring(lua, 2); + + if(!parse_note(noteStr, ¬e, &octave)) + { + luaL_error(lua, "invalid note, should be like C#4\n"); + return 0; + } + } + + if(top >= 3) + { + duration = getLuaNumber(lua, 3); + + if(top >= 4) + { + channel = getLuaNumber(lua, 4); + + if(top >= 5) + { + if(lua_istable(lua, 5)) + { + for(s32 i = 0; i < COUNT_OF(volumes); i++) + { + volumes[i] = lua_rawgeti(lua, 5, i + 1); + lua_pop(lua, 1); + } + } + else volumes[0] = volumes[1] = getLuaNumber(lua, 5); + + if(top >= 6) + { + speed = getLuaNumber(lua, 6); + } + } + } + } + } + + if (channel >= 0 && channel < TIC_SOUND_CHANNELS) + { + core->api.sfx(tic, index, note, octave, duration, channel, volumes[0] & 0xf, volumes[1] & 0xf, speed); + } + else luaL_error(lua, "unknown channel\n"); + } + else luaL_error(lua, "unknown sfx index\n"); + } + else luaL_error(lua, "invalid sfx params\n"); + + return 0; +} + +static s32 lua_vbank(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 prev = core->state.vbank.id; + + if(lua_gettop(lua) == 1) + core->api.vbank(tic, getLuaNumber(lua, 1)); + + lua_pushinteger(lua, prev); + return 1; +} + +static s32 lua_sync(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + bool toCart = false; + u32 mask = 0; + s32 bank = 0; + + if(lua_gettop(lua) >= 1) + { + mask = getLuaNumber(lua, 1); + + if(lua_gettop(lua) >= 2) + { + bank = getLuaNumber(lua, 2); + + if(lua_gettop(lua) >= 3) + { + toCart = lua_toboolean(lua, 3); + } + } + } + + if(bank >= 0 && bank < TIC_BANKS) + core->api.sync(tic, mask, bank, toCart); + else + luaL_error(lua, "sync() error, invalid bank"); + + return 0; +} + +static s32 lua_reset(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + + core->state.initialized = false; + + return 0; +} + +static s32 lua_key(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = &core->memory; + + s32 top = lua_gettop(lua); + + if (top == 0) + { + lua_pushboolean(lua, core->api.key(tic, tic_key_unknown)); + } + else if (top == 1) + { + tic_key key = getLuaNumber(lua, 1); + + if(key < tic_keys_count) + lua_pushboolean(lua, core->api.key(tic, key)); + else + { + luaL_error(lua, "unknown keyboard code\n"); + return 0; + } + } + else + { + luaL_error(lua, "invalid params, key [code]\n"); + return 0; + } + + return 1; +} + +static s32 lua_keyp(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = &core->memory; + + s32 top = lua_gettop(lua); + + if (top == 0) + { + lua_pushboolean(lua, core->api.keyp(tic, tic_key_unknown, -1, -1)); + } + else + { + tic_key key = getLuaNumber(lua, 1); + + if(key >= tic_keys_count) + { + luaL_error(lua, "unknown keyboard code\n"); + } + else + { + if(top == 1) + { + lua_pushboolean(lua, core->api.keyp(tic, key, -1, -1)); + } + else if(top == 3) + { + u32 hold = getLuaNumber(lua, 2); + u32 period = getLuaNumber(lua, 3); + + lua_pushboolean(lua, core->api.keyp(tic, key, hold, period)); + } + else + { + luaL_error(lua, "invalid params, keyp [ code [ hold period ] ]\n"); + return 0; + } + } + } + + return 1; +} + +static s32 lua_memcpy(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 3) + { + s32 dest = getLuaNumber(lua, 1); + s32 src = getLuaNumber(lua, 2); + s32 size = getLuaNumber(lua, 3); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + core->api.memcpy(tic, dest, src, size); + } + else luaL_error(lua, "invalid params, memcpy(dest,src,size)\n"); + + return 0; +} + +static s32 lua_memset(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top == 3) + { + s32 dest = getLuaNumber(lua, 1); + u8 value = getLuaNumber(lua, 2); + s32 size = getLuaNumber(lua, 3); + + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.memset(tic, dest, value, size); + } + else luaL_error(lua, "invalid params, memset(dest,val,size)\n"); + + return 0; +} + +static const char* printString(lua_State* lua, s32 index) +{ + lua_getglobal(lua, "tostring"); + lua_pushvalue(lua, -1); + lua_pushvalue(lua, index); + lua_call(lua, 1, 1); + + const char* text = lua_tostring(lua, -1); + + lua_pop(lua, 2); + + return text; +} + +static s32 lua_font(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + s32 top = lua_gettop(lua); + + if(top >= 1) + { + const char* text = printString(lua, 1); + s32 x = 0; + s32 y = 0; + s32 width = TIC_SPRITESIZE; + s32 height = TIC_SPRITESIZE; + u8 chromakey = 0; + bool fixed = false; + s32 scale = 1; + bool alt = false; + + if(top >= 3) + { + x = getLuaNumber(lua, 2); + y = getLuaNumber(lua, 3); + + if(top >= 4) + { + chromakey = getLuaNumber(lua, 4); + + if(top >= 6) + { + width = getLuaNumber(lua, 5); + height = getLuaNumber(lua, 6); + + if(top >= 7) + { + fixed = lua_toboolean(lua, 7); + + if(top >= 8) + { + scale = getLuaNumber(lua, 8); + + if(top >= 9) + { + alt = lua_toboolean(lua, 9); + } + } + } + } + } + } + + if(scale == 0) + { + lua_pushinteger(lua, 0); + return 1; + } + + s32 size = core->api.font(tic, text, x, y, &chromakey, 1, width, height, fixed, scale, alt); + + lua_pushinteger(lua, size); + + return 1; + } + + return 0; +} + +static s32 lua_print(lua_State* lua) +{ + s32 top = lua_gettop(lua); + + if(top >= 1) + { + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + s32 x = 0; + s32 y = 0; + s32 color = TIC_DEFAULT_COLOR; + bool fixed = false; + s32 scale = 1; + bool alt = false; + + const char* text = printString(lua, 1); + + if(top >= 3) + { + x = getLuaNumber(lua, 2); + y = getLuaNumber(lua, 3); + + if(top >= 4) + { + color = getLuaNumber(lua, 4) % TIC_PALETTE_SIZE; + + if(top >= 5) + { + fixed = lua_toboolean(lua, 5); + + if(top >= 6) + { + scale = getLuaNumber(lua, 6); + + if(top >= 7) + { + alt = lua_toboolean(lua, 7); + } + } + } + } + } + + if(scale == 0) + { + lua_pushinteger(lua, 0); + return 1; + } + + s32 size = core->api.print(tic, text ? text : "nil", x, y, color, fixed, scale, alt); + + lua_pushinteger(lua, size); + + return 1; + } + + return 0; +} + +static s32 lua_trace(lua_State *lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + if(top >= 1) + { + const char* text = printString(lua, 1); + u8 color = TIC_DEFAULT_COLOR; + + if(top >= 2) + { + color = getLuaNumber(lua, 2); + } + + core->api.trace(tic, text, color); + } + else luaL_error(lua, "invalid params, trace(text,[color])\n"); + + return 0; +} + +static s32 lua_pmem(lua_State *lua) +{ + s32 top = lua_gettop(lua); + tic_core* core = getLuaCore(lua); + tic_mem* tic = &core->memory; + + if(top >= 1) + { + u32 index = getLuaNumber(lua, 1); + + if(index < TIC_PERSISTENT_SIZE) + { + u32 val = core->api.pmem(tic, index, 0, false); + + if(top >= 2) + { + core->api.pmem(tic, index, (u32)lua_tointeger(lua, 2), true); + } + + lua_pushinteger(lua, val); + + return 1; + } + + luaL_error(lua, "invalid persistent tic index\n"); + } + else luaL_error(lua, "invalid params, pmem(index [val]) -> val\n"); + + return 0; +} + +static s32 lua_time(lua_State *lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + lua_pushnumber(lua, core->api.time(tic)); + + return 1; +} + +static s32 lua_tstamp(lua_State *lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + lua_pushnumber(lua, core->api.tstamp(tic)); + + return 1; +} + +static s32 lua_exit(lua_State *lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + + core->api.exit(tic); + + return 0; +} + +static s32 lua_mouse(lua_State *lua) +{ + tic_core* core = getLuaCore(lua); + + { + tic_point pos = core->api.mouse((tic_mem*)core); + + lua_pushinteger(lua, pos.x); + lua_pushinteger(lua, pos.y); + } + + const tic80_mouse* mouse = &core->memory.ram->input.mouse; + + lua_pushboolean(lua, mouse->left); + lua_pushboolean(lua, mouse->middle); + lua_pushboolean(lua, mouse->right); + lua_pushinteger(lua, mouse->scrollx); + lua_pushinteger(lua, mouse->scrolly); + + return 7; +} + +static s32 lua_fget(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + s32 top = lua_gettop(lua); + + if(top >= 1) + { + u32 index = getLuaNumber(lua, 1); + + if(top >= 2) + { + u32 flag = getLuaNumber(lua, 2); + lua_pushboolean(lua, core->api.fget(tic, index, flag)); + return 1; + } + } + + luaL_error(lua, "invalid params, fget(sprite,flag)\n"); + + return 0; +} + +static s32 lua_fset(lua_State* lua) +{ + tic_core* core = getLuaCore(lua); + tic_mem* tic = (tic_mem*)core; + s32 top = lua_gettop(lua); + + if(top >= 1) + { + u32 index = getLuaNumber(lua, 1); + + if(top >= 2) + { + u32 flag = getLuaNumber(lua, 2); + + if(top >= 3) + { + bool value = lua_toboolean(lua, 3); + core->api.fset(tic, index, flag, value); + return 0; + } + } + } + + luaL_error(lua, "invalid params, fset(sprite,flag,value)\n"); + + return 0; +} + +static s32 lua_dofile(lua_State *lua) +{ + luaL_error(lua, "unknown method: \"dofile\"\n"); + + return 0; +} + +static s32 lua_loadfile(lua_State *lua) +{ + luaL_error(lua, "unknown method: \"loadfile\"\n"); + + return 0; +} + +void luaapi_open(lua_State *lua) +{ + static const luaL_Reg loadedlibs[] = + { + { "_G", luaopen_base }, + { LUA_LOADLIBNAME, luaopen_package }, + { LUA_COLIBNAME, luaopen_coroutine }, + { LUA_TABLIBNAME, luaopen_table }, + { LUA_STRLIBNAME, luaopen_string }, + { LUA_MATHLIBNAME, luaopen_math }, + { LUA_DBLIBNAME, luaopen_debug }, + { NULL, NULL } + }; + + for (const luaL_Reg *lib = loadedlibs; lib->func; lib++) + { + luaL_requiref(lua, lib->name, lib->func, 1); + lua_pop(lua, 1); + } +} + +void luaapi_init(tic_core* core) +{ + static const struct{lua_CFunction func; const char* name;} ApiItems[] = + { +#define API_FUNC_DEF(name, ...) {lua_ ## name, #name}, + TIC_API_LIST(API_FUNC_DEF) +#undef API_FUNC_DEF + +#if defined(BUILD_DEPRECATED) + {lua_textri, "textri"}, +#endif + }; + + for (s32 i = 0; i < COUNT_OF(ApiItems); i++) + registerLuaFunction(core, ApiItems[i].func, ApiItems[i].name); + + registerLuaFunction(core, lua_dofile, "dofile"); + registerLuaFunction(core, lua_loadfile, "loadfile"); +} + +void luaapi_close(tic_mem* tic) +{ + tic_core* core = (tic_core*)tic; + + if(core->currentVM) + { + lua_close(core->currentVM); + core->currentVM = NULL; + } +} + +/* +** Message handler which appends stract trace to exceptions. +** This function was extractred from lua.c. +*/ +static s32 msghandler (lua_State *lua) +{ + const char *msg = lua_tostring(lua, 1); + if (msg == NULL) /* is error object not a string? */ + { + if (luaL_callmeta(lua, 1, "__tostring") && /* does it have a metamethod */ + lua_type(lua, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(lua, "(error object is a %s value)", luaL_typename(lua, 1)); + } + luaL_traceback(lua, lua, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} + +/* +** Interface to 'lua_pcall', which sets appropriate message handler function. +** Please use this function for all top level lua functions. +** This function was extractred from lua.c (and stripped of signal handling) +*/ +static s32 docall (lua_State *lua, s32 narg, s32 nres) +{ + s32 status = 0; + s32 base = lua_gettop(lua) - narg; /* function index */ + lua_pushcfunction(lua, msghandler); /* push message handler */ + lua_insert(lua, base); /* put it under function and args */ + status = lua_pcall(lua, narg, nres, base); + lua_remove(lua, base); /* remove message handler from the stack */ + return status; +} + +void luaapi_tick(tic_mem* tic) +{ + tic_core* core = (tic_core*)tic; + + lua_State* lua = core->currentVM; + + if(lua) + { + lua_getglobal(lua, TIC_FN); + if(lua_isfunction(lua, -1)) + { + if(docall(lua, 0, 0) != LUA_OK) + { + core->data->error(core->data->data, lua_tostring(lua, -1)); + return; + } + +#if defined(BUILD_DEPRECATED) + // call OVR() callback for backward compatibility + { + lua_getglobal(lua, OVR_FN); + if(lua_isfunction(lua, -1)) + { + OVR(core) + { + if(docall(lua, 0, 0) != LUA_OK) + core->data->error(core->data->data, lua_tostring(lua, -1)); + } + } + else lua_pop(lua, 1); + } +#endif + } + else + { + lua_pop(lua, 1); + core->data->error(core->data->data, "'function TIC()...' isn't found :("); + } + } +} + +void callLuaIntCallback(tic_mem* tic, s32 value, void* data, const char* name) +{ + tic_core* core = (tic_core*)tic; + lua_State* lua = core->currentVM; + + if (lua) + { + lua_getglobal(lua, name); + if(lua_isfunction(lua, -1)) + { + lua_pushinteger(lua, value); + if(docall(lua, 1, 0) != LUA_OK) + core->data->error(core->data->data, lua_tostring(lua, -1)); + } + else lua_pop(lua, 1); + } +} + +void luaapi_scn(tic_mem* tic, s32 row, void* data) +{ + callLuaIntCallback(tic, row, data, SCN_FN); + + // try to call old scanline + callLuaIntCallback(tic, row, data, "scanline"); +} + +void luaapi_bdr(tic_mem* tic, s32 row, void* data) +{ + callLuaIntCallback(tic, row, data, BDR_FN); +} + +void luaapi_menu(tic_mem* tic, s32 index, void* data) +{ + callLuaIntCallback(tic, index, data, MENU_FN); +} + +void luaapi_boot(tic_mem* tic) +{ + tic_core* core = (tic_core*)tic; + lua_State* lua = core->currentVM; + + if (lua) + { + lua_getglobal(lua, BOOT_FN); + if(lua_isfunction(lua, -1)) + { + if(docall(lua, 0, 0) != LUA_OK) + core->data->error(core->data->data, lua_tostring(lua, -1)); + } + else lua_pop(lua, 1); + } +} diff --git a/src/api/lua_api.h b/src/api/luaapi.h similarity index 69% rename from src/api/lua_api.h rename to src/api/luaapi.h index e853d3a9..e76f9fe8 100644 --- a/src/api/lua_api.h +++ b/src/api/luaapi.h @@ -29,14 +29,11 @@ #include #include -extern void initLuaAPI(tic_core* core); -extern void callLuaTick(tic_mem* tic); -extern void callLuaBoot(tic_mem* tic); -extern void callLuaScanlineName(tic_mem* tic, s32 row, void* data, const char* name); -extern void callLuaScanline(tic_mem* tic, s32 row, void* data); -extern void callLuaBorder(tic_mem* tic, s32 row, void* data); -extern void callLuaOverline(tic_mem* tic, void* data); -extern void callLuaMenu(tic_mem* tic, s32 index, void* data); -extern void closeLua(tic_mem* tic); -extern void callLuaTick(tic_mem* tic); -extern void lua_open_builtins(lua_State *lua); +void luaapi_init(tic_core* core); +void luaapi_tick(tic_mem* tic); +void luaapi_boot(tic_mem* tic); +void luaapi_scn(tic_mem* tic, s32 row, void* data); +void luaapi_bdr(tic_mem* tic, s32 row, void* data); +void luaapi_menu(tic_mem* tic, s32 index, void* data); +void luaapi_close(tic_mem* tic); +void luaapi_open(lua_State *lua); diff --git a/src/api/moonscript.c b/src/api/moonscript.c index 505bf3e3..3c48907e 100644 --- a/src/api/moonscript.c +++ b/src/api/moonscript.c @@ -21,7 +21,7 @@ // SOFTWARE. #include "core/core.h" -#include "lua_api.h" +#include "luaapi.h" static const char _ms_loadstring[] = "_ms_loadstring"; @@ -77,15 +77,15 @@ extern s32 luaopen_lpeg(lua_State *lua); static bool initMoonscript(tic_mem* tic, const char* code) { tic_core* core = (tic_core*)tic; - closeLua(tic); + luaapi_close(tic); lua_State* lua = core->currentVM = luaL_newstate(); - lua_open_builtins(lua); + luaapi_open(lua); luaopen_lpeg(lua); setloaded(lua, "lpeg"); - initLuaAPI(core); + luaapi_init(core); { lua_State* moon = lua; @@ -196,7 +196,7 @@ static const u8 MarkRom[] = #include "../build/assets/moonmark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Moon) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Moon) = { .id = 13, .name = "moon", @@ -204,15 +204,15 @@ const tic_script EXPORT_SCRIPT(Moon) = .projectComment = "--", { .init = initMoonscript, - .close = closeLua, - .tick = callLuaTick, - .boot = callLuaBoot, + .close = luaapi_close, + .tick = luaapi_tick, + .boot = luaapi_boot, .callback = { - .scanline = callLuaScanline, - .border = callLuaBorder, - .menu = callLuaMenu, + .scanline = luaapi_scn, + .border = luaapi_bdr, + .menu = luaapi_menu, }, }, diff --git a/src/api/mruby.c b/src/api/mruby.c index 9450f99d..64bd0619 100644 --- a/src/api/mruby.c +++ b/src/api/mruby.c @@ -1226,7 +1226,7 @@ static const u8 MarkRom[] = #include "../build/assets/rubymark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Ruby) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Ruby) = { .id = 11, .name = "ruby", diff --git a/src/api/python.c b/src/api/python.c index 26598910..73952a2d 100644 --- a/src/api/python.c +++ b/src/api/python.c @@ -1527,7 +1527,7 @@ static const u8 MarkRom[] = #include "../build/assets/pythonmark.tic.dat" }; -PK_EXPORT const tic_script EXPORT_SCRIPT(Python) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Python) = { .id = 20, .name = "python", diff --git a/src/api/scheme.c b/src/api/scheme.c index f2dc9570..f4d01a0d 100644 --- a/src/api/scheme.c +++ b/src/api/scheme.c @@ -1028,7 +1028,7 @@ static const u8 MarkRom[] = #include "../build/assets/schememark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Scheme) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Scheme) = { .id = 19, .name = "scheme", diff --git a/src/api/squirrel.c b/src/api/squirrel.c index a26e06d8..ef4f897f 100644 --- a/src/api/squirrel.c +++ b/src/api/squirrel.c @@ -1858,7 +1858,7 @@ static const u8 MarkRom[] = #include "../build/assets/squirrelmark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Squirrel) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Squirrel) = { .id = 15, .name = "squirrel", diff --git a/src/api/wasm.c b/src/api/wasm.c index 9c105d4f..ad2635b5 100644 --- a/src/api/wasm.c +++ b/src/api/wasm.c @@ -1322,7 +1322,7 @@ static const u8 MarkRom[] = #include "../build/assets/wasmmark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Wasm) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Wasm) = { .id = 17, .name = "wasm", diff --git a/src/api/wren.c b/src/api/wren.c index 71bba182..63dfc7ee 100644 --- a/src/api/wren.c +++ b/src/api/wren.c @@ -1829,7 +1829,7 @@ static const u8 MarkRom[] = #include "../build/assets/wrenmark.tic.dat" }; -const tic_script EXPORT_SCRIPT(Wren) = +TIC_EXPORT const tic_script EXPORT_SCRIPT(Wren) = { .id = 16, .name = "wren",