feat(LuaGame): fullscreen 320x480, no toolbar, on-demand refresh for solitaire
- Manifest: HideStatusBar flag, version 0.2.0 - app_on_show: remove toolbar, get display resolution via lv_display_get_horizontal_resolution, allocate 320x480 framebuffer in PSRAM - Dynamic game_w/h, fb_w/h in AppCtx, set_px/fill_rect use dynamic size - touch_event_cb uses dynamic max_w/h - On-demand refresh: l_game_set_frame_updates sets wants_frame_updates flag - Pico games without set_frame_updates (solitaire) only redraw on touch events - Continuous games (breakout, pong) with set_frame_updates(true) use FRAME_TICK every 16ms - Initial draw after init for on-demand games - FPS tracking only when redraw occurs - Solitaire optimized: LEFT 37->4, GAP 10->4, TOP_Y 30->4, TAB_Y 98->60, removed draw_terminal_chrome (outer frame + title bar + window controls) - Uploaded optimized solitaire via /fs/upload?path=/sdcard/lua/solitaire.lua (24430 bytes) - Tested fullscreen: display 320x480, no toolbar, screenshot shows chrome removed, white pixels 3197 (cards only) - Logs show no continuous FPS spamming for solitaire (on-demand)
This commit is contained in:
+155
-88
@@ -29,6 +29,8 @@
|
|||||||
#define TAG "LuaGame"
|
#define TAG "LuaGame"
|
||||||
#define GAME_W 240
|
#define GAME_W 240
|
||||||
#define GAME_H 240
|
#define GAME_H 240
|
||||||
|
#define GAME_W_DEFAULT 240
|
||||||
|
#define GAME_H_DEFAULT 240
|
||||||
#define TICK_MS 16
|
#define TICK_MS 16
|
||||||
|
|
||||||
/* stubs for missing libc symbols */
|
/* stubs for missing libc symbols */
|
||||||
@@ -51,6 +53,10 @@ typedef struct {
|
|||||||
lv_obj_t* label_layer;
|
lv_obj_t* label_layer;
|
||||||
lv_obj_t* fps_label;
|
lv_obj_t* fps_label;
|
||||||
uint16_t* fb;
|
uint16_t* fb;
|
||||||
|
int fb_w;
|
||||||
|
int fb_h;
|
||||||
|
int game_w;
|
||||||
|
int game_h;
|
||||||
lv_timer_t* timer;
|
lv_timer_t* timer;
|
||||||
TaskHandle_t lua_task;
|
TaskHandle_t lua_task;
|
||||||
bool touch_pressed;
|
bool touch_pressed;
|
||||||
@@ -61,8 +67,10 @@ typedef struct {
|
|||||||
bool lua_ok;
|
bool lua_ok;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
bool is_pico;
|
bool is_pico;
|
||||||
|
bool wants_frame_updates;
|
||||||
uint64_t last_tick_us;
|
uint64_t last_tick_us;
|
||||||
bool should_exit;
|
bool should_exit;
|
||||||
|
bool needs_redraw;
|
||||||
// fps
|
// fps
|
||||||
uint32_t fps_frames;
|
uint32_t fps_frames;
|
||||||
uint64_t fps_last_us;
|
uint64_t fps_last_us;
|
||||||
@@ -77,8 +85,10 @@ static uint16_t hex_to_rgb565(uint32_t hex){
|
|||||||
}
|
}
|
||||||
static inline void set_px(AppCtx* c,int x,int y,uint16_t col){
|
static inline void set_px(AppCtx* c,int x,int y,uint16_t col){
|
||||||
if(!c||!c->fb)return;
|
if(!c||!c->fb)return;
|
||||||
if(x<0||y<0||x>=GAME_W||y>=GAME_H)return;
|
int w = c->fb_w ? c->fb_w : GAME_W_DEFAULT;
|
||||||
c->fb[y*GAME_W+x]=col;
|
int h = c->fb_h ? c->fb_h : GAME_H_DEFAULT;
|
||||||
|
if(x<0||y<0||x>=w||y>=h)return;
|
||||||
|
c->fb[y*w+x]=col;
|
||||||
}
|
}
|
||||||
static void fill_rect(AppCtx* c,int x,int y,int w,int h,uint16_t col,bool filled){
|
static void fill_rect(AppCtx* c,int x,int y,int w,int h,uint16_t col,bool filled){
|
||||||
if(w<=0||h<=0)return;
|
if(w<=0||h<=0)return;
|
||||||
@@ -87,8 +97,10 @@ static void fill_rect(AppCtx* c,int x,int y,int w,int h,uint16_t col,bool filled
|
|||||||
for(int j=y;j<y+h;j++){set_px(c,x,j,col);set_px(c,x+w-1,j,col);}
|
for(int j=y;j<y+h;j++){set_px(c,x,j,col);set_px(c,x+w-1,j,col);}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int x0=x<0?0:x,y0=y<0?0:y,x1=x+w> GAME_W? GAME_W:x+w,y1=y+h>GAME_H?GAME_H:y+h;
|
int fb_w = c->fb_w ? c->fb_w : GAME_W_DEFAULT;
|
||||||
for(int yy=y0;yy<y1;yy++){uint16_t* row=c->fb+yy*GAME_W; for(int xx=x0;xx<x1;xx++) row[xx]=col;}
|
int fb_h = c->fb_h ? c->fb_h : GAME_H_DEFAULT;
|
||||||
|
int x0=x<0?0:x,y0=y<0?0:y,x1=x+w> fb_w? fb_w:x+w,y1=y+h>fb_h?fb_h:y+h;
|
||||||
|
for(int yy=y0;yy<y1;yy++){uint16_t* row=c->fb+yy*fb_w; for(int xx=x0;xx<x1;xx++) row[xx]=col;}
|
||||||
}
|
}
|
||||||
static void draw_circle(AppCtx* c,int cx,int cy,int r,uint16_t col,bool filled){
|
static void draw_circle(AppCtx* c,int cx,int cy,int r,uint16_t col,bool filled){
|
||||||
if(r<=0)return;
|
if(r<=0)return;
|
||||||
@@ -126,13 +138,14 @@ static void draw_text8(AppCtx* ctx, int x, int y, const char* txt, uint16_t col)
|
|||||||
if(!txt) return;
|
if(!txt) return;
|
||||||
int cx=x;
|
int cx=x;
|
||||||
int cy=y;
|
int cy=y;
|
||||||
|
int max_w = ctx->game_w ? ctx->game_w : GAME_W_DEFAULT;
|
||||||
for(int i=0; txt[i]; i++){
|
for(int i=0; txt[i]; i++){
|
||||||
char ch=txt[i];
|
char ch=txt[i];
|
||||||
if(ch=='\n'){ cx=x; cy+=10; continue; }
|
if(ch=='\n'){ cx=x; cy+=10; continue; }
|
||||||
draw_char8(ctx, cx, cy, ch, col);
|
draw_char8(ctx, cx, cy, ch, col);
|
||||||
cx+=8;
|
cx+=8;
|
||||||
// wrap if exceeds game width
|
// wrap if exceeds game width
|
||||||
if(cx+8>GAME_W){ cx=x; cy+=10; }
|
if(cx+8>max_w){ cx=x; cy+=10; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +154,9 @@ static int l_sys_log(lua_State* L){const char* m=luaL_checkstring(L,1); printf("
|
|||||||
static int l_sys_clear(lua_State* L){
|
static int l_sys_clear(lua_State* L){
|
||||||
AppCtx* ctx=g_ctx; if(!ctx)return 0;
|
AppCtx* ctx=g_ctx; if(!ctx)return 0;
|
||||||
uint32_t hex=0; if(lua_gettop(L)>=1) hex=(uint32_t)(luaL_checknumber(L,1));
|
uint32_t hex=0; if(lua_gettop(L)>=1) hex=(uint32_t)(luaL_checknumber(L,1));
|
||||||
fill_rect(ctx,0,0,GAME_W,GAME_H,hex_to_rgb565(hex),true);
|
int w = ctx->game_w ? ctx->game_w : GAME_W_DEFAULT;
|
||||||
|
int h = ctx->game_h ? ctx->game_h : GAME_H_DEFAULT;
|
||||||
|
fill_rect(ctx,0,0,w,h,hex_to_rgb565(hex),true);
|
||||||
clear_labels(ctx);
|
clear_labels(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -350,14 +365,38 @@ static int l_renderer_text_scaled(lua_State* L){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cx+=8*scale;
|
cx+=8*scale;
|
||||||
if(cx+8*scale>GAME_W){ cx=x; cy+=8*scale+2; }
|
{
|
||||||
|
int max_w = g_ctx && g_ctx->game_w ? g_ctx->game_w : GAME_W_DEFAULT;
|
||||||
|
if(cx+8*scale>max_w){ cx=x; cy+=8*scale+2; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int l_game_width(lua_State* L){ lua_pushinteger(L, GAME_W); return 1; }
|
static int l_game_width(lua_State* L){
|
||||||
static int l_game_height(lua_State* L){ lua_pushinteger(L, GAME_H); return 1; }
|
AppCtx* ctx=g_ctx;
|
||||||
static int l_game_set_frame_updates(lua_State* L){ (void)L; return 0; }
|
int w = ctx && ctx->game_w ? ctx->game_w : GAME_W_DEFAULT;
|
||||||
static int l_game_exit(lua_State* L){ (void)L; printf("[LuaGame] game.exit() called\n"); return 0; }
|
lua_pushinteger(L, w); return 1;
|
||||||
|
}
|
||||||
|
static int l_game_height(lua_State* L){
|
||||||
|
AppCtx* ctx=g_ctx;
|
||||||
|
int h = ctx && ctx->game_h ? ctx->game_h : GAME_H_DEFAULT;
|
||||||
|
lua_pushinteger(L, h); return 1;
|
||||||
|
}
|
||||||
|
static int l_game_set_frame_updates(lua_State* L){
|
||||||
|
AppCtx* ctx=g_ctx;
|
||||||
|
bool en = false;
|
||||||
|
if(lua_gettop(L)>=1) en = lua_toboolean(L,1);
|
||||||
|
if(ctx) ctx->wants_frame_updates = en;
|
||||||
|
printf("[LuaGame] set_frame_updates %d\n", en?1:0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int l_game_exit(lua_State* L){
|
||||||
|
(void)L;
|
||||||
|
AppCtx* ctx=g_ctx;
|
||||||
|
printf("[LuaGame] game.exit() called\n");
|
||||||
|
if(ctx) ctx->should_exit = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void register_sys(lua_State* L){
|
static void register_sys(lua_State* L){
|
||||||
// sys table (Tactility original)
|
// sys table (Tactility original)
|
||||||
@@ -521,9 +560,24 @@ static void lua_init_task(void* arg){
|
|||||||
ctx->fps_last_us=esp_timer_get_time();
|
ctx->fps_last_us=esp_timer_get_time();
|
||||||
ctx->fps_frames=0;
|
ctx->fps_frames=0;
|
||||||
printf("[LuaGame] init done OK from %s (pico=%d)\n",loaded_from, ctx->is_pico?1:0);
|
printf("[LuaGame] init done OK from %s (pico=%d)\n",loaded_from, ctx->is_pico?1:0);
|
||||||
|
|
||||||
|
// Initial draw for on-demand games
|
||||||
|
lua_getglobal(ctx->L,"draw");
|
||||||
|
if(lua_isfunction(ctx->L,-1)){
|
||||||
|
if(lua_pcall(ctx->L,0,0,0)!=LUA_OK){
|
||||||
|
const char* e=lua_tostring(ctx->L,-1);
|
||||||
|
printf("[LUA ERR initial draw] %s\n",e);
|
||||||
|
lua_pop(ctx->L,1);
|
||||||
|
}
|
||||||
|
} else lua_pop(ctx->L,1);
|
||||||
|
if(tt_lvgl_lock(portMAX_DELAY)){
|
||||||
|
invalidate_canvas(ctx);
|
||||||
|
tt_lvgl_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
printf("[LuaGame] entering game loop in same task\n");
|
printf("[LuaGame] entering game loop in same task\n");
|
||||||
|
|
||||||
// Enter game loop directly
|
// Enter game loop directly - on-demand for solitaire (no frame updates)
|
||||||
while(!ctx->should_exit){
|
while(!ctx->should_exit){
|
||||||
if(ctx->lua_ok && ctx->initialized && ctx->L){
|
if(ctx->lua_ok && ctx->initialized && ctx->L){
|
||||||
uint64_t now=esp_timer_get_time();
|
uint64_t now=esp_timer_get_time();
|
||||||
@@ -531,46 +585,35 @@ static void lua_init_task(void* arg){
|
|||||||
if(dt>0.1f) dt=0.1f;
|
if(dt>0.1f) dt=0.1f;
|
||||||
ctx->last_tick_us=now;
|
ctx->last_tick_us=now;
|
||||||
lua_State* L=ctx->L;
|
lua_State* L=ctx->L;
|
||||||
|
bool should_draw = false;
|
||||||
|
|
||||||
if(ctx->is_pico){
|
if(ctx->is_pico){
|
||||||
// Generate event based on touch
|
|
||||||
int ev_type = 6; // FRAME_TICK default
|
|
||||||
bool has_touch_event = false;
|
bool has_touch_event = false;
|
||||||
|
int ev_type = 6;
|
||||||
if(!ctx->prev_touch_pressed && ctx->touch_pressed){
|
if(!ctx->prev_touch_pressed && ctx->touch_pressed){
|
||||||
ev_type = 1; // TOUCH_DOWN
|
ev_type = 1; has_touch_event = true;
|
||||||
has_touch_event = true;
|
|
||||||
} else if(ctx->prev_touch_pressed && !ctx->touch_pressed){
|
} else if(ctx->prev_touch_pressed && !ctx->touch_pressed){
|
||||||
ev_type = 3; // TOUCH_UP
|
ev_type = 3; has_touch_event = true;
|
||||||
has_touch_event = true;
|
|
||||||
} else if(ctx->touch_pressed){
|
} else if(ctx->touch_pressed){
|
||||||
ev_type = 2; // TOUCH_MOVE
|
ev_type = 2; has_touch_event = true;
|
||||||
has_touch_event = true;
|
|
||||||
} else {
|
|
||||||
ev_type = 6; // FRAME_TICK
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to push event table and call update
|
if(ctx->wants_frame_updates){
|
||||||
// First call with touch event if any
|
// Continuous: handle touch event if any, then FRAME_TICK every frame
|
||||||
if(has_touch_event){
|
if(has_touch_event){
|
||||||
lua_getglobal(L,"update");
|
lua_getglobal(L,"update");
|
||||||
if(lua_isfunction(L,-1)){
|
if(lua_isfunction(L,-1)){
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
lua_pushinteger(L, ev_type); lua_setfield(L,-2,"type");
|
lua_pushinteger(L, ev_type); lua_setfield(L,-2,"type");
|
||||||
lua_pushinteger(L, ctx->touch_x); lua_setfield(L,-2,"x");
|
lua_pushinteger(L, ctx->touch_x); lua_setfield(L,-2,"x");
|
||||||
lua_pushinteger(L, ctx->touch_y); lua_setfield(L,-2,"y");
|
lua_pushinteger(L, ctx->touch_y); lua_setfield(L,-2,"y");
|
||||||
lua_pushboolean(L,1); lua_setfield(L,-2,"valid");
|
lua_pushboolean(L,1); lua_setfield(L,-2,"valid");
|
||||||
lua_pushinteger(L,0); lua_setfield(L,-2,"button_id");
|
lua_pushinteger(L,0); lua_setfield(L,-2,"button_id");
|
||||||
if(lua_pcall(L,1,1,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
if(lua_pcall(L,1,1,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
||||||
else {
|
else { bool r=lua_toboolean(L,-1); lua_pop(L,1); if(r) should_draw=true; }
|
||||||
bool redraw = lua_toboolean(L,-1);
|
} else lua_pop(L,1);
|
||||||
lua_pop(L,1);
|
}
|
||||||
// we will draw regardless, but could check redraw
|
// FRAME_TICK
|
||||||
(void)redraw;
|
|
||||||
}
|
|
||||||
} else lua_pop(L,1);
|
|
||||||
}
|
|
||||||
// Always also call with FRAME_TICK if not already frame tick
|
|
||||||
if(ev_type != 6){
|
|
||||||
lua_getglobal(L,"update");
|
lua_getglobal(L,"update");
|
||||||
if(lua_isfunction(L,-1)){
|
if(lua_isfunction(L,-1)){
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
@@ -578,58 +621,66 @@ static void lua_init_task(void* arg){
|
|||||||
lua_pushinteger(L, ctx->touch_x); lua_setfield(L,-2,"x");
|
lua_pushinteger(L, ctx->touch_x); lua_setfield(L,-2,"x");
|
||||||
lua_pushinteger(L, ctx->touch_y); lua_setfield(L,-2,"y");
|
lua_pushinteger(L, ctx->touch_y); lua_setfield(L,-2,"y");
|
||||||
lua_pushboolean(L,1); lua_setfield(L,-2,"valid");
|
lua_pushboolean(L,1); lua_setfield(L,-2,"valid");
|
||||||
if(lua_pcall(L,1,1,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update FRAME_TICK] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
if(lua_pcall(L,1,1,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update FRAME] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
||||||
else { lua_pop(L,1); }
|
else { bool r=lua_toboolean(L,-1); lua_pop(L,1); if(r) should_draw=true; }
|
||||||
} else lua_pop(L,1);
|
|
||||||
} else if(!has_touch_event){
|
|
||||||
// No touch, just frame tick (single call)
|
|
||||||
lua_getglobal(L,"update");
|
|
||||||
if(lua_isfunction(L,-1)){
|
|
||||||
lua_newtable(L);
|
|
||||||
lua_pushinteger(L, 6); lua_setfield(L,-2,"type");
|
|
||||||
lua_pushinteger(L, ctx->touch_x); lua_setfield(L,-2,"x");
|
|
||||||
lua_pushinteger(L, ctx->touch_y); lua_setfield(L,-2,"y");
|
|
||||||
lua_pushboolean(L,1); lua_setfield(L,-2,"valid");
|
|
||||||
if(lua_pcall(L,1,1,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
|
||||||
else {
|
|
||||||
bool redraw = lua_toboolean(L,-1);
|
|
||||||
lua_pop(L,1);
|
|
||||||
(void)redraw;
|
|
||||||
}
|
|
||||||
} else lua_pop(L,1);
|
} else lua_pop(L,1);
|
||||||
|
} else {
|
||||||
|
// On-demand: only when touch event
|
||||||
|
if(has_touch_event){
|
||||||
|
lua_getglobal(L,"update");
|
||||||
|
if(lua_isfunction(L,-1)){
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushinteger(L, ev_type); lua_setfield(L,-2,"type");
|
||||||
|
lua_pushinteger(L, ctx->touch_x); lua_setfield(L,-2,"x");
|
||||||
|
lua_pushinteger(L, ctx->touch_y); lua_setfield(L,-2,"y");
|
||||||
|
lua_pushboolean(L,1); lua_setfield(L,-2,"valid");
|
||||||
|
lua_pushinteger(L,0); lua_setfield(L,-2,"button_id");
|
||||||
|
if(lua_pcall(L,1,1,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
||||||
|
else { bool r=lua_toboolean(L,-1); lua_pop(L,1); if(r) should_draw=true; }
|
||||||
|
} else lua_pop(L,1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx->prev_touch_pressed = ctx->touch_pressed;
|
ctx->prev_touch_pressed = ctx->touch_pressed;
|
||||||
} else {
|
} else {
|
||||||
// Original sys API
|
// Original sys API - continuous
|
||||||
lua_getglobal(L,"update");
|
lua_getglobal(L,"update");
|
||||||
if(lua_isfunction(L,-1)){
|
if(lua_isfunction(L,-1)){
|
||||||
lua_pushnumber(L,dt);
|
lua_pushnumber(L,dt);
|
||||||
if(lua_pcall(L,1,0,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
if(lua_pcall(L,1,0,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR update] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
||||||
}else lua_pop(L,1);
|
}else lua_pop(L,1);
|
||||||
|
should_draw = true;
|
||||||
}
|
}
|
||||||
lua_getglobal(L,"draw");
|
|
||||||
if(lua_isfunction(L,-1)){
|
if(should_draw){
|
||||||
if(lua_pcall(L,0,0,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR draw] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
lua_getglobal(L,"draw");
|
||||||
}else lua_pop(L,1);
|
if(lua_isfunction(L,-1)){
|
||||||
if(tt_lvgl_lock(portMAX_DELAY)){
|
if(lua_pcall(L,0,0,0)!=LUA_OK){const char* e=lua_tostring(L,-1); printf("[LUA ERR draw] %s\n",e); lua_pop(L,1); ctx->lua_ok=false;}
|
||||||
invalidate_canvas(ctx);
|
}else lua_pop(L,1);
|
||||||
ctx->fps_frames++;
|
if(tt_lvgl_lock(portMAX_DELAY)){
|
||||||
uint64_t elapsed = now - ctx->fps_last_us;
|
invalidate_canvas(ctx);
|
||||||
if(elapsed >= 1000000){
|
ctx->fps_frames++;
|
||||||
ctx->fps = (float)ctx->fps_frames * 1000000.0f / (float)elapsed;
|
uint64_t elapsed = now - ctx->fps_last_us;
|
||||||
printf("[LuaGame] FPS %.1f\n", ctx->fps);
|
if(elapsed >= 1000000){
|
||||||
if(ctx->fps_label){
|
ctx->fps = (float)ctx->fps_frames * 1000000.0f / (float)elapsed;
|
||||||
char buf[32];
|
printf("[LuaGame] FPS %.1f (on-demand)\n", ctx->fps);
|
||||||
snprintf(buf,sizeof(buf),"FPS %.0f",ctx->fps);
|
if(ctx->fps_label){
|
||||||
lv_label_set_text(ctx->fps_label, buf);
|
char buf[32];
|
||||||
|
snprintf(buf,sizeof(buf),"FPS %.0f",ctx->fps);
|
||||||
|
lv_label_set_text(ctx->fps_label, buf);
|
||||||
|
}
|
||||||
|
ctx->fps_frames=0;
|
||||||
|
ctx->fps_last_us=now;
|
||||||
}
|
}
|
||||||
ctx->fps_frames=0;
|
tt_lvgl_unlock();
|
||||||
ctx->fps_last_us=now;
|
|
||||||
}
|
}
|
||||||
tt_lvgl_unlock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(TICK_MS));
|
// For on-demand games, sleep longer to save CPU
|
||||||
|
if(ctx->is_pico && !ctx->wants_frame_updates){
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
|
} else {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TICK_MS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("[LuaGame] game loop exit\n");
|
printf("[LuaGame] game loop exit\n");
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
@@ -683,14 +734,16 @@ static void touch_event_cb(lv_event_t* e){
|
|||||||
if(!ctx)return;
|
if(!ctx)return;
|
||||||
lv_event_code_t code=lv_event_get_code(e);
|
lv_event_code_t code=lv_event_get_code(e);
|
||||||
lv_point_t pt; lv_indev_get_point(lv_indev_active(),&pt);
|
lv_point_t pt; lv_indev_get_point(lv_indev_active(),&pt);
|
||||||
|
int max_w = ctx->game_w ? ctx->game_w : GAME_W_DEFAULT;
|
||||||
|
int max_h = ctx->game_h ? ctx->game_h : GAME_H_DEFAULT;
|
||||||
if(ctx->canvas){
|
if(ctx->canvas){
|
||||||
lv_area_t area; lv_obj_get_coords(ctx->canvas,&area);
|
lv_area_t area; lv_obj_get_coords(ctx->canvas,&area);
|
||||||
int lx=pt.x-area.x1;
|
int lx=pt.x-area.x1;
|
||||||
int ly=pt.y-area.y1;
|
int ly=pt.y-area.y1;
|
||||||
if(lx<0) lx=0;
|
if(lx<0) lx=0;
|
||||||
if(lx>=GAME_W) lx=GAME_W-1;
|
if(lx>=max_w) lx=max_w-1;
|
||||||
if(ly<0) ly=0;
|
if(ly<0) ly=0;
|
||||||
if(ly>=GAME_H) ly=GAME_H-1;
|
if(ly>=max_h) ly=max_h-1;
|
||||||
ctx->touch_x=lx; ctx->touch_y=ly;
|
ctx->touch_x=lx; ctx->touch_y=ly;
|
||||||
}else{ctx->touch_x=pt.x; ctx->touch_y=pt.y;}
|
}else{ctx->touch_x=pt.x; ctx->touch_y=pt.y;}
|
||||||
if(code==LV_EVENT_PRESSING||code==LV_EVENT_PRESSED||code==LV_EVENT_CLICKED) ctx->touch_pressed=true;
|
if(code==LV_EVENT_PRESSING||code==LV_EVENT_PRESSED||code==LV_EVENT_CLICKED) ctx->touch_pressed=true;
|
||||||
@@ -711,13 +764,27 @@ static void app_on_show(AppHandle app,void* data,lv_obj_t* parent){
|
|||||||
g_ctx=ctx;
|
g_ctx=ctx;
|
||||||
ctx->app=app; ctx->lua_ok=false; ctx->initialized=false; ctx->should_exit=false;
|
ctx->app=app; ctx->lua_ok=false; ctx->initialized=false; ctx->should_exit=false;
|
||||||
ctx->fps=0; ctx->fps_frames=0;
|
ctx->fps=0; ctx->fps_frames=0;
|
||||||
|
|
||||||
|
// Fullscreen: no toolbar, no statusbar (manifest HideStatusBar)
|
||||||
lv_obj_remove_flag(parent,LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(parent,LV_OBJ_FLAG_SCROLLABLE);
|
||||||
lv_obj_set_style_pad_all(parent,0,0);
|
lv_obj_set_style_pad_all(parent,0,0);
|
||||||
lv_obj_set_style_bg_color(parent,lv_color_black(),0);
|
lv_obj_set_style_bg_color(parent,lv_color_black(),0);
|
||||||
lv_obj_set_flex_flow(parent,LV_FLEX_FLOW_COLUMN);
|
lv_obj_set_flex_flow(parent,LV_FLEX_FLOW_COLUMN);
|
||||||
lv_obj_set_style_pad_row(parent,0,0);
|
lv_obj_set_style_pad_row(parent,0,0);
|
||||||
ctx->toolbar=tt_lvgl_toolbar_create_for_app(parent,app);
|
ctx->toolbar=NULL;
|
||||||
ctx->root=parent;
|
ctx->root=parent;
|
||||||
|
|
||||||
|
// Get display resolution for dynamic framebuffer (320x480 on ES3C35P)
|
||||||
|
lv_coord_t disp_w = lv_display_get_horizontal_resolution(NULL);
|
||||||
|
lv_coord_t disp_h = lv_display_get_vertical_resolution(NULL);
|
||||||
|
if(disp_w<=0) disp_w = 320;
|
||||||
|
if(disp_h<=0) disp_h = 480;
|
||||||
|
ctx->game_w = disp_w;
|
||||||
|
ctx->game_h = disp_h;
|
||||||
|
ctx->fb_w = disp_w;
|
||||||
|
ctx->fb_h = disp_h;
|
||||||
|
printf("[LuaGame] display %dx%d fullscreen, no toolbar\n", (int)disp_w, (int)disp_h);
|
||||||
|
|
||||||
ctx->game_area=lv_obj_create(parent);
|
ctx->game_area=lv_obj_create(parent);
|
||||||
lv_obj_set_width(ctx->game_area,LV_PCT(100));
|
lv_obj_set_width(ctx->game_area,LV_PCT(100));
|
||||||
lv_obj_set_flex_grow(ctx->game_area,1);
|
lv_obj_set_flex_grow(ctx->game_area,1);
|
||||||
@@ -728,12 +795,12 @@ static void app_on_show(AppHandle app,void* data,lv_obj_t* parent){
|
|||||||
lv_obj_set_flex_align(ctx->game_area,LV_FLEX_ALIGN_CENTER,LV_FLEX_ALIGN_CENTER,LV_FLEX_ALIGN_CENTER);
|
lv_obj_set_flex_align(ctx->game_area,LV_FLEX_ALIGN_CENTER,LV_FLEX_ALIGN_CENTER,LV_FLEX_ALIGN_CENTER);
|
||||||
lv_obj_remove_flag(ctx->game_area,LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(ctx->game_area,LV_OBJ_FLAG_SCROLLABLE);
|
||||||
lv_obj_add_flag(ctx->game_area,LV_OBJ_FLAG_CLICKABLE);
|
lv_obj_add_flag(ctx->game_area,LV_OBJ_FLAG_CLICKABLE);
|
||||||
size_t fb_bytes=GAME_W*GAME_H*sizeof(uint16_t);
|
size_t fb_bytes=(size_t)ctx->fb_w * ctx->fb_h * sizeof(uint16_t);
|
||||||
ctx->fb=alloc_psram(fb_bytes);
|
ctx->fb=alloc_psram(fb_bytes);
|
||||||
if(!ctx->fb){printf("[LuaGame] FB alloc fail\n"); return;}
|
if(!ctx->fb){printf("[LuaGame] FB alloc fail %dx%d\n", ctx->fb_w, ctx->fb_h); return;}
|
||||||
memset(ctx->fb,0,fb_bytes);
|
memset(ctx->fb,0,fb_bytes);
|
||||||
lv_obj_t* cont=lv_obj_create(ctx->game_area);
|
lv_obj_t* cont=lv_obj_create(ctx->game_area);
|
||||||
lv_obj_set_size(cont,GAME_W,GAME_H);
|
lv_obj_set_size(cont,ctx->fb_w,ctx->fb_h);
|
||||||
lv_obj_set_style_bg_color(cont,lv_color_black(),0);
|
lv_obj_set_style_bg_color(cont,lv_color_black(),0);
|
||||||
lv_obj_set_style_border_width(cont,0,0);
|
lv_obj_set_style_border_width(cont,0,0);
|
||||||
lv_obj_set_style_pad_all(cont,0,0);
|
lv_obj_set_style_pad_all(cont,0,0);
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ manifest.version=0.2
|
|||||||
target.sdk=0.8.0-dev
|
target.sdk=0.8.0-dev
|
||||||
target.platforms=esp32s3
|
target.platforms=esp32s3
|
||||||
app.id=one.tactility.luagame
|
app.id=one.tactility.luagame
|
||||||
app.version.name=0.1.0
|
app.version.name=0.2.0
|
||||||
app.version.code=1
|
app.version.code=2
|
||||||
app.name=Lua Game
|
app.name=Lua Game
|
||||||
app.description=Lua interpreter game engine (runs breakout.lua and custom games)
|
app.description=Lua interpreter game engine - fullscreen, no chrome
|
||||||
|
app.flags=HideStatusBar
|
||||||
|
|||||||
Reference in New Issue
Block a user