diff --git a/Apps/LuaGame/main/Source/main.c b/Apps/LuaGame/main/Source/main.c index 48af37d..3b9f22a 100644 --- a/Apps/LuaGame/main/Source/main.c +++ b/Apps/LuaGame/main/Source/main.c @@ -44,6 +44,26 @@ FILE* tmpfile(void){return NULL;} char* tmpnam(char* s){if(s)s[0]=0;return s;} int ungetc(int c,FILE* st){(void)st;return c;} +/* Custom Lua allocator using PSRAM to reduce internal memory pressure */ +static void* lua_psram_alloc(void *ud, void *ptr, size_t osize, size_t nsize){ + (void)ud; (void)osize; + if(nsize==0){ + if(ptr) heap_caps_free(ptr); + return NULL; + } + void* newptr = heap_caps_malloc(nsize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if(!newptr){ + newptr = heap_caps_malloc(nsize, MALLOC_CAP_8BIT); + } + if(!newptr) return NULL; + if(ptr){ + size_t copy = osize < nsize ? osize : nsize; + memcpy(newptr, ptr, copy); + heap_caps_free(ptr); + } + return newptr; +} + typedef struct { AppHandle app; lv_obj_t* root; @@ -393,8 +413,9 @@ static int l_game_set_frame_updates(lua_State* L){ static int l_game_exit(lua_State* L){ (void)L; AppCtx* ctx=g_ctx; - printf("[LuaGame] game.exit() called\n"); + printf("[LuaGame] game.exit() called -> stopping app\n"); if(ctx) ctx->should_exit = true; + tt_app_stop(); return 0; } @@ -484,9 +505,9 @@ static char* load_file_to_mem(const char* path, size_t* out_len){ } static void lua_init_task(void* arg){ AppCtx* ctx=(AppCtx*)arg; - printf("[LuaGame] init task start\n"); - audio_init(); - ctx->L=luaL_newstate(); + printf("[LuaGame] init task start (PSRAM alloc)\n"); + // Use PSRAM allocator for Lua to reduce internal memory pressure + ctx->L=lua_newstate(lua_psram_alloc, NULL); if(!ctx->L){ printf("[LuaGame] lua newstate fail\n"); vTaskDelete(NULL); return;} luaL_openlibs(ctx->L); register_sys(ctx->L); @@ -527,14 +548,27 @@ static void lua_init_task(void* arg){ } // Detect Pico API by content before loading bool detected_pico = false; + bool needs_audio = false; if(src_buf){ if(strstr(src_buf,"renderer.")!=NULL || strstr(src_buf,"INPUT.")!=NULL){ detected_pico = true; } + if(strstr(src_buf,"sfx")!=NULL || strstr(src_buf,"tone")!=NULL){ + needs_audio = true; + } } else { if(strstr(embedded_breakout_lua_src,"renderer.")!=NULL){ detected_pico = true; } + if(strstr(embedded_breakout_lua_src,"sfx")!=NULL || strstr(embedded_breakout_lua_src,"tone")!=NULL){ + needs_audio = true; + } + } + if(needs_audio){ + printf("[LuaGame] audio needed, init SfxEngine\n"); + audio_init(); + } else { + printf("[LuaGame] audio not needed, skipping SfxEngine to save RAM\n"); } int st; @@ -746,6 +780,14 @@ static void touch_event_cb(lv_event_t* e){ if(ly>=max_h) ly=max_h-1; ctx->touch_x=lx; ctx->touch_y=ly; }else{ctx->touch_x=pt.x; ctx->touch_y=pt.y;} + if(code==LV_EVENT_PRESSED){ + // Top-right corner 40x40 as exit gesture (since no toolbar) + if(ctx->touch_x > max_w - 40 && ctx->touch_y < 40){ + printf("[LuaGame] exit gesture top-right tap -> stopping app\n"); + tt_app_stop(); + return; + } + } if(code==LV_EVENT_PRESSING||code==LV_EVENT_PRESSED||code==LV_EVENT_CLICKED) ctx->touch_pressed=true; else if(code==LV_EVENT_RELEASED||code==LV_EVENT_PRESS_LOST) ctx->touch_pressed=false; } @@ -807,22 +849,18 @@ static void app_on_show(AppHandle app,void* data,lv_obj_t* parent){ lv_obj_remove_flag(cont,LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_style_radius(cont,0,0); ctx->canvas=lv_canvas_create(cont); - lv_canvas_set_buffer(ctx->canvas,ctx->fb,GAME_W,GAME_H,LV_COLOR_FORMAT_RGB565); + lv_canvas_set_buffer(ctx->canvas,ctx->fb,ctx->fb_w,ctx->fb_h,LV_COLOR_FORMAT_RGB565); lv_obj_set_style_bg_opa(ctx->canvas,LV_OPA_COVER,0); lv_obj_remove_flag(ctx->canvas,LV_OBJ_FLAG_SCROLLABLE); - ctx->label_layer=lv_obj_create(cont); - lv_obj_set_size(ctx->label_layer,GAME_W,GAME_H); - lv_obj_set_pos(ctx->label_layer,0,0); - lv_obj_set_style_bg_opa(ctx->label_layer,LV_OPA_TRANSP,0); - lv_obj_set_style_border_width(ctx->label_layer,0,0); - lv_obj_set_style_pad_all(ctx->label_layer,0,0); - lv_obj_remove_flag(ctx->label_layer,LV_OBJ_FLAG_SCROLLABLE); - lv_obj_remove_flag(ctx->label_layer,LV_OBJ_FLAG_CLICKABLE); - // FPS label outside canvas, top of game_area - ctx->fps_label=lv_label_create(ctx->game_area); - lv_label_set_text(ctx->fps_label,"FPS --"); - lv_obj_set_style_text_color(ctx->fps_label, lv_color_white(),0); - lv_obj_set_style_text_font(ctx->fps_label, lv_font_get_default(),0); + // Label layer removed to save RAM - text now drawn directly to FB + ctx->label_layer=NULL; + // FPS label kept small but optional - remove to save RAM for solitaire + // For now, keep disabled to save internal memory + ctx->fps_label=NULL; + // If you want FPS, uncomment: + // ctx->fps_label=lv_label_create(ctx->game_area); + // lv_label_set_text(ctx->fps_label,"FPS --"); + // lv_obj_set_style_text_color(ctx->fps_label, lv_color_white(),0); lv_obj_add_event_cb(ctx->game_area,touch_event_cb,LV_EVENT_PRESSED,ctx); lv_obj_add_event_cb(ctx->game_area,touch_event_cb,LV_EVENT_PRESSING,ctx);