diff --git a/Apps/LuaGame/README.md b/Apps/LuaGame/README.md index 5d62bee..e26f9f3 100644 --- a/Apps/LuaGame/README.md +++ b/Apps/LuaGame/README.md @@ -4,30 +4,38 @@ External ELF app that runs Lua games on Tactility OS (ES3C35P 320x480 tested on ## How it works - Embeds Lua 5.4.7 source (no external dependency, avoids missing symbol issues) -- Lua init runs in dedicated 16K stack FreeRTOS task to avoid GUI task (4096 bytes) stack overflow -- Game framebuffer: 240x240 RGB565 in PSRAM, rendered via LVGL canvas -- Sys API (as used in breakout.lua): +- Lua init + game loop run in dedicated 16K stack FreeRTOS task to avoid GUI task (4096 bytes) stack overflow +- Game framebuffer: 240x240 RGB565 in PSRAM, rendered via LVGL canvas (`lv_canvas_set_buffer` + `lv_obj_invalidate` with `tt_lvgl_lock`) +- Direct framebuffer text using 8x8 bitmap font (`font8x8.h`) – 17+ FPS vs 15 FPS with LVGL labels +- **Sys API** (original Tactility breakout.lua): - `sys.log(msg)` - `sys.clear(hexColor)` - - `sys.print(x,y,text,hexColor)` - uses LVGL labels overlay - - `sys.rect(x,y,w,h,hexColor,filled)` - - `sys.circle(x,y,r,hexColor,filled)` + - `sys.print(x,y,text,hexColor)` – direct FB via `draw_text8` + - `sys.rect(x,y,w,h,hexColor,filled)` – border or filled + - `sys.circle(x,y,r,hexColor,filled)` – midpoint + filled scan - `sys.line(x0,y0,x1,y1,hexColor)` - - `sys.touch() -> pressed, tx, ty` (touch coords mapped to 240 game space) - - `sys.tone`, `sys.sfx` stubs (logs) -- Embedded breakout.lua as fallback, but tries to load from SD in order: - - `/sdcard/lua/breakout.lua` - - `/sdcard/lua/game.lua` - - `/data/lua/breakout.lua` - - `/sdcard/breakout.lua` -- File loading uses PSRAM buffer + `luaL_loadbuffer` to avoid `luaL_loadfile` stack issues. + - `sys.touch() -> pressed, tx, ty` (touch mapped to 240 game space) + - `sys.tone(note, duration, waveform, volume)` → SfxEngine `playNote` + - `sys.sfx(name)` → SfxEngine `play(SfxId)` mapping: confirm, coin, hurt, gameover, levelup, brickhit, etc. +- **Pico API** compatibility (from `/Users/adolforeyna/Projects/pico-bare-metal/Adolfo/basic1/games/lua_examples`): + - `game.width()`, `height()`, `set_frame_updates(bool)`, `exit()`, `game.vars` persistent table + - `renderer.clear(white)`, `pixel(x,y,on)`, `line(x0,y0,x1,y1,on,width)`, `rect(x,y,w,h,on,filled)`, `circle(x,y,r,on,filled)`, `triangle(x0,y0,x1,y1,x2,y2,on,filled)`, `text(x,y,txt,on)`, `text_scaled(x,y,txt,on,scale)` (scale 1-4) + - `INPUT` constants: `NONE=0, TOUCH_DOWN=1, TOUCH_MOVE=2, TOUCH_UP=3, BUTTON_0=4, BUTTON_1=5, FRAME_TICK=6, GESTURE=7` + - Event system: generates `TOUCH_DOWN/MOVE/UP` from touch state + `FRAME_TICK` every frame, calls `update(event)` returning bool redraw + - Detection: if source contains `renderer.` → Pico mode, else sys mode +- Embedded games: + - `embedded_breakout_lua_src` – fast breakout (ball 4.5 vs 2, paddle 0.25 spin) – default + - `pico_games.h` auto-generated with 17 games: 2048, air_hockey, asteroids, ball, breakout, counter, flappy_bird, lunar_lander, memory_match, pacman, pong, simon_says, snake, solitaire, tetris, tic_tac_toe – tested Pong runs at 17.5 FPS +- File loading: PSRAM buffer + `luaL_loadbuffer` to avoid `luaL_loadfile` stack issues, supports SD paths `/sdcard/lua/*.lua` ## Symbol fixes -Previous attempts hit missing symbols: `clearerr`, `clock`, `getenv`, `gmtime`, `setlocale`, `setvbuf`, `tmpfile`, `tmpnam`, `ungetc`, plus LVGL `lv_canvas_get_draw_buf`, `lv_draw_buf_invalidate_cache`, `lv_image_cache_drop`. -Fixed by: -- Providing local stubs for missing libc functions -- Removing use of unexported LVGL cache APIs, using only `lv_canvas_create`, `lv_canvas_set_buffer`, `lv_obj_invalidate` -- Verifying with `verify_symbols.py` - 0 missing. +Previous missing: `clearerr`, `clock`, `getenv`, `gmtime`, `setlocale`, `setvbuf`, `tmpfile`, `tmpnam`, `ungetc`, `lv_canvas_get_draw_buf`, `lv_draw_buf_invalidate_cache`, `lv_image_cache_drop`. +Fixed by local stubs + avoiding unexported APIs, only `lv_canvas_create`, `lv_canvas_set_buffer`, `lv_obj_invalidate`, `tt_lvgl_lock/unlock`. + +## Performance +- Ball speed: 2 → 4.5 (2.25x faster), configurable in embedded string +- FPS: 15 → 17.5 FPS after direct FB text + dedicated game loop task +- Memory: internal low ~2-3KB (PSRAM used for FB and Lua heap), stable, no crash 20s+ ## Build / Install ```bash @@ -42,14 +50,23 @@ curl -X PUT http://192.168.68.107/api/apps/install -F "file=@Apps/LuaGame/build/ curl -X POST "http://192.168.68.107/api/apps/run?id=one.tactility.luagame" ``` -## Testing -- Serial logs: `/dev/cu.usbmodem1101` 115200 -- Screenshot: `curl -s http://192.168.68.107/api/screenshot -o /tmp/fb.png` -- Current status: boots, loads `/sdcard/lua/breakout.lua` (5207 bytes), no stack overflow, renders bricks/ball/paddle, handles float coords for `circle`. +## Porting Pico Games +Yes – all 17 examples from `pico-bare-metal/Adolfo/basic1/games/lua_examples` use: +- `game.vars` state machine +- `renderer.*` monochrome API (boolean on/off → mapped to white/black RGB565) +- `INPUT.TOUCH_*` + `FRAME_TICK` + +Our engine now implements compatibility shim in C (see `l_renderer_*`, `l_game_*`, INPUT table). Pong tested: +``` +[LuaGame] using Pico test game: Pong (7538 bytes) +Pong initialized +FPS 17.5 +``` +Other games (snake, tetris, 2048, etc.) should work same – they are ~50-880 lines, no file I/O, pure math/table. To add selector UI, list `pico_games[]` via LVGL list and load selected `src`. ## TODO -- Implement proper game selection UI for `/sdcard/lua/` directory -- Map touch to paddle correctly (currently uses canvas coords) -- Implement audio via SfxEngine -- Scale canvas to full display or allow dynamic resolution via `sys.width/height` -- Add file browser in-app +- Game selector UI (menu_wrapper + game_wrapper, hide/show) +- Copy pico examples to SD via USB MSC or bundle selector +- Audio mapping for Pico games (currently sys.sfx only, could map to renderer events) +- Scale canvas to full 320x480 or dynamic `game.width/height` +- Fix internal memory low warnings (reduce SfxEngine voices or Lua heap)