From c4acfd67c711edf3c28120202102a408c039e89b Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Sun, 18 May 2025 21:00:46 +0200 Subject: [PATCH 01/13] ff --- workspace/all/nextui/nextui.c | 129 +++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 17 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index a554f42a7..12b496e40 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1418,6 +1418,7 @@ static SDL_Surface* screen = NULL; // Must be assigned externally static int had_thumb = 0; static int ox; static int oy; + // queue a new image load task :D void enqueueTask(LoadBackgroundTask* task) { TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); @@ -1545,6 +1546,82 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); } +typedef void (*AnimTaskCallback)(SDL_Rect moveDst); +typedef struct AnimTask { + int startX; + int targetX; + int startY; + int targetY; + int startAlpha; + int targetAlpha; + const char* reveal_direction; + int move_w; + int move_h; + int reveal_w; + int reveal_h; + int reveal_x; + int reveal_y; + int duration; + AnimTaskCallback callback; +} AnimTask; + +SDL_Rect pillRect; +void animcallback(SDL_Rect dst) { + pillRect = dst; +} +int doAnimTask(AnimTask* task) { + const int fps = 60; + const int frame_delay = 1000 / fps; + const int total_frames = task->duration / frame_delay; + + for (int frame = 0; frame <= total_frames; ++frame) { + float t = (float)frame / total_frames; + if (t > 1.0f) t = 1.0f; + + int current_x = task->startX + (int)((task->targetX - task->startX) * t); + int current_y = task->startY + (int)(( task->targetY - task->startY) * t); + int current_opacity = task->startAlpha + (int)((task->targetAlpha - task->startAlpha) * t); + if (current_opacity < 0) current_opacity = 0; + if (current_opacity > 255) current_opacity = 255; + + + int reveal_src_x = 0, reveal_src_y = 0; + int reveal_draw_w = task->reveal_w, reveal_draw_h = task->reveal_h; + + if (strcmp(task->reveal_direction, "left") == 0) { + reveal_draw_w = (int)(task->reveal_w * t + 0.5f); + } + else if (strcmp(task->reveal_direction, "right") == 0) { + reveal_draw_w = (int)(task->reveal_w * t + 0.5f); + reveal_src_x = task->reveal_w - reveal_draw_w; + } + else if (strcmp(task->reveal_direction, "up") == 0) { + reveal_draw_h = (int)(task->reveal_h * t + 0.5f); + } + else if (strcmp(task->reveal_direction, "down") == 0) { + reveal_draw_h = (int)(task->reveal_h * t + 0.5f); + reveal_src_y = task->reveal_h - reveal_draw_h; + } + + SDL_Rect revealSrc = { reveal_src_x, reveal_src_y, reveal_draw_w, reveal_draw_h }; + SDL_Rect revealDst = { task->reveal_x + reveal_src_x, task->reveal_y + reveal_src_y, reveal_draw_w, reveal_draw_h }; + SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; + task->callback(moveDst); + SDL_Delay(16); + + + } + + +} + + +int animTaskThread(void *data) { + AnimTask *task = (AnimTask *)data; + task->callback = animcallback; + doAnimTask(task); + return 0; +} /////////////////////////////////////// enum { @@ -1630,6 +1707,16 @@ int main (int argc, char *argv[]) { pthread_t cpucheckthread; pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL); + + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); + + + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, 500, SCALE1(PILL_SIZE) + }); + LOG_info("Start time time %ims\n",SDL_GetTicks()); while (!quit) { @@ -2258,24 +2345,27 @@ int main (int argc, char *argv[]) { SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_unique ? entry_unique : entry_name, text_color); is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); - SDL_Surface *pill = SDL_CreateRGBSurfaceWithFormat( - SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 - ); - GFX_blitPillDark(ASSET_WHITE_PILL, pill, &(SDL_Rect){ - 0,0, max_width, SCALE1(PILL_SIZE) - }); + if(animationdirection == 0) { - GFX_flipHidden(); - GFX_animateAndRevealSurfaces( - pill,text, - SCALE1(BUTTON_MARGIN), SCALE1(previousY+PADDING),SCALE1(BUTTON_MARGIN),SCALE1(targetY+PADDING),max_width,SCALE1(PILL_SIZE), - SCALE1(BUTTON_MARGIN + BUTTON_PADDING),SCALE1(targetY+PADDING+4),max_width - SCALE1(BUTTON_PADDING*2),text->h, - selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down", - CFG_getMenuAnimations() ? 40:10,255,255,255,0,1 - ); + AnimTask* task = malloc(sizeof(AnimTask)); + task->startX = SCALE1(BUTTON_MARGIN); + task->startY = SCALE1(previousY+PADDING); + task->targetX = SCALE1(BUTTON_MARGIN); + task->targetY = SCALE1(targetY+PADDING); + task->move_w = max_width; + task->move_h = SCALE1(PILL_SIZE); + task->reveal_x = SCALE1(BUTTON_MARGIN + BUTTON_PADDING); + task->reveal_y = SCALE1(targetY+PADDING+4); + task->reveal_w = max_width - SCALE1(BUTTON_PADDING*2); + task->reveal_h = text->h; + task->reveal_direction = selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down"; + task->duration = 100; + task->startAlpha = 255; + task->targetAlpha = 255; + SDL_Thread *test = SDL_CreateThread(animTaskThread, "AnimThread", task); + } - SDL_FreeSurface(text); - SDL_FreeSurface(pill); + } } remember_selection = selected_row; @@ -2426,7 +2516,12 @@ int main (int argc, char *argv[]) { ); - } else if (!show_switcher && !show_version) { + } + if (!show_switcher && !show_version) { + + GFX_clearLayers(3); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); + PLAT_GPU_Flip(); PLAT_GPU_Flip(); } dirty = 0; From 90d2a5ed102a44e58ef75a9ebb160e3d47ff523e Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Sun, 18 May 2025 22:47:35 +0200 Subject: [PATCH 02/13] ff --- workspace/all/nextui/nextui.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 12b496e40..df1e69c8b 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -2359,7 +2359,7 @@ int main (int argc, char *argv[]) { task->reveal_w = max_width - SCALE1(BUTTON_PADDING*2); task->reveal_h = text->h; task->reveal_direction = selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down"; - task->duration = 100; + task->duration = 60; task->startAlpha = 255; task->targetAlpha = 255; SDL_Thread *test = SDL_CreateThread(animTaskThread, "AnimThread", task); @@ -2431,6 +2431,9 @@ int main (int argc, char *argv[]) { } SDL_UnlockMutex(thumbMutex); } + GFX_clearLayers(3); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); + PLAT_GPU_Flip(); GFX_flip(screen); dirty = 0; readytoscroll = 0; @@ -2518,10 +2521,8 @@ int main (int argc, char *argv[]) { } if (!show_switcher && !show_version) { - - GFX_clearLayers(3); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); - PLAT_GPU_Flip(); + GFX_clearLayers(3); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); PLAT_GPU_Flip(); } dirty = 0; From 0853ece540525a2aab42056cc2bdca9f06027cbc Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Mon, 19 May 2025 19:32:58 +0200 Subject: [PATCH 03/13] ok now its going in the good direction already works pretty good! --- workspace/all/nextui/nextui.c | 242 ++++++++++++++------------- workspace/tg5040/platform/platform.c | 14 ++ 2 files changed, 141 insertions(+), 115 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index df1e69c8b..6ab1279c7 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1393,16 +1393,39 @@ typedef struct { void* userData; } LoadBackgroundTask; +typedef void (*AnimTaskCallback)(SDL_Rect moveDst); +typedef struct AnimTask { + int startX; + int targetX; + int startY; + int targetY; + int move_w; + int move_h; + int duration; + AnimTaskCallback callback; + void* userData; +} AnimTask; // --- Thread pool structures --- typedef struct TaskNode { LoadBackgroundTask* task; struct TaskNode* next; } TaskNode; +typedef struct AnimTaskNode { + AnimTask* task; + struct AnimTaskNode* next; +} AnimTaskNode; static TaskNode* taskQueueHead = NULL; static TaskNode* taskQueueTail = NULL; +static AnimTaskNode* animTaskQueueHead = NULL; +static AnimTaskNode* animTtaskQueueTail = NULL; static SDL_mutex* queueMutex = NULL; +static SDL_mutex* animqueueMutex = NULL; static SDL_cond* queueCond = NULL; +static SDL_cond* animqueueCond = NULL; + +static SDL_mutex* animMutex = NULL; +static SDL_cond* flipCond = NULL; static SDL_mutex* imgLoadMutex = NULL; static SDL_mutex* folderBgMutex = NULL; @@ -1471,17 +1494,6 @@ int imageLoadWorker(void* unused) { return 0; } -void initImageLoaderPool() { - queueMutex = SDL_CreateMutex(); - queueCond = SDL_CreateCond(); - imgLoadMutex = SDL_CreateMutex(); - folderBgMutex = SDL_CreateMutex(); - thumbMutex = SDL_CreateMutex(); - - for (int i = 0; i < THREAD_POOL_SIZE; ++i) { - SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); - } -} int folderbgchanged=0; int thumbchanged=0; @@ -1546,82 +1558,91 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); } -typedef void (*AnimTaskCallback)(SDL_Rect moveDst); -typedef struct AnimTask { - int startX; - int targetX; - int startY; - int targetY; - int startAlpha; - int targetAlpha; - const char* reveal_direction; - int move_w; - int move_h; - int reveal_w; - int reveal_h; - int reveal_x; - int reveal_y; - int duration; - AnimTaskCallback callback; -} AnimTask; + SDL_Rect pillRect; + + + void animcallback(SDL_Rect dst) { pillRect = dst; } -int doAnimTask(AnimTask* task) { - const int fps = 60; - const int frame_delay = 1000 / fps; - const int total_frames = task->duration / frame_delay; +bool frameReady = false; +int pillanimdone = 0; +int animWorker(void* unused) { + while (true) { + SDL_LockMutex(animqueueMutex); + while (!animTaskQueueHead) { + SDL_CondWait(animqueueCond, animqueueMutex); + } + AnimTaskNode* node = animTaskQueueHead; + animTaskQueueHead = node->next; + if (!animTaskQueueHead) animTtaskQueueTail = NULL; + SDL_UnlockMutex(animqueueMutex); - for (int frame = 0; frame <= total_frames; ++frame) { - float t = (float)frame / total_frames; - if (t > 1.0f) t = 1.0f; + AnimTask* task = node->task; - int current_x = task->startX + (int)((task->targetX - task->startX) * t); - int current_y = task->startY + (int)(( task->targetY - task->startY) * t); - int current_opacity = task->startAlpha + (int)((task->targetAlpha - task->startAlpha) * t); - if (current_opacity < 0) current_opacity = 0; - if (current_opacity > 255) current_opacity = 255; - + int fps = 60; + int frame_delay = 1000 / fps; + int total_frames = task->duration / frame_delay; - int reveal_src_x = 0, reveal_src_y = 0; - int reveal_draw_w = task->reveal_w, reveal_draw_h = task->reveal_h; - - if (strcmp(task->reveal_direction, "left") == 0) { - reveal_draw_w = (int)(task->reveal_w * t + 0.5f); - } - else if (strcmp(task->reveal_direction, "right") == 0) { - reveal_draw_w = (int)(task->reveal_w * t + 0.5f); - reveal_src_x = task->reveal_w - reveal_draw_w; - } - else if (strcmp(task->reveal_direction, "up") == 0) { - reveal_draw_h = (int)(task->reveal_h * t + 0.5f); - } - else if (strcmp(task->reveal_direction, "down") == 0) { - reveal_draw_h = (int)(task->reveal_h * t + 0.5f); - reveal_src_y = task->reveal_h - reveal_draw_h; - } + for (int frame = 0; frame <= total_frames; ++frame) { + float t = (float)frame / total_frames; + if (t > 1.0f) t = 1.0f; - SDL_Rect revealSrc = { reveal_src_x, reveal_src_y, reveal_draw_w, reveal_draw_h }; - SDL_Rect revealDst = { task->reveal_x + reveal_src_x, task->reveal_y + reveal_src_y, reveal_draw_w, reveal_draw_h }; - SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; - task->callback(moveDst); - SDL_Delay(16); + int current_x = task->startX + (int)((task->targetX - task->startX) * t); + int current_y = task->startY + (int)(( task->targetY - task->startY) * t); + + SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; + task->callback(moveDst); + SDL_LockMutex(animMutex); + while (!frameReady) { + SDL_CondWait(flipCond, animMutex); + } + frameReady = false; + SDL_UnlockMutex(animMutex); - } + } + pillanimdone = 1; + } } +void enqueueanmimtask(AnimTask* task) { + AnimTaskNode* node = (AnimTaskNode*)malloc(sizeof(AnimTaskNode)); + node->task = task; + node->next = NULL; + pillanimdone = 0; + SDL_LockMutex(animqueueMutex); + if (animTtaskQueueTail) { + animTtaskQueueTail->next = node; + animTtaskQueueTail = node; + } else { + animTaskQueueHead = animTtaskQueueTail = node; + } + SDL_CondSignal(animqueueCond); + SDL_UnlockMutex(animqueueMutex); +} -int animTaskThread(void *data) { - AnimTask *task = (AnimTask *)data; +int animPill(AnimTask *task) { task->callback = animcallback; - doAnimTask(task); + enqueueanmimtask(task); return 0; } +void initImageLoaderPool() { + queueMutex = SDL_CreateMutex(); + queueCond = SDL_CreateCond(); + imgLoadMutex = SDL_CreateMutex(); + folderBgMutex = SDL_CreateMutex(); + thumbMutex = SDL_CreateMutex(); + + for (int i = 0; i < THREAD_POOL_SIZE; ++i) { + SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); + } + SDL_CreateThread(animWorker, "animWorker", NULL); +} /////////////////////////////////////// enum { @@ -1935,9 +1956,9 @@ int main (int argc, char *argv[]) { GFX_clearLayers(0); } else { - if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(2); - GFX_clearLayers(3); + if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(3); GFX_clearLayers(4); + GFX_clearLayers(5); } GFX_clear(screen); @@ -2297,14 +2318,6 @@ int main (int argc, char *argv[]) { int max_width = MIN(available_width, text_width); SDL_Color text_color = uintToColour(THEME_COLOR4_255); - - if (j == selected_row && animationdirection > 0) { - GFX_blitPillDark(ASSET_WHITE_PILL, screen, &(SDL_Rect){ - SCALE1(BUTTON_MARGIN),SCALE1(targetY+PADDING), max_width, SCALE1(PILL_SIZE) - }); - text_color = uintToColour(THEME_COLOR5_255); - } - SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; @@ -2342,8 +2355,12 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_unique ? entry_unique : entry_name, display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); SDL_Color text_color = uintToColour(THEME_COLOR5_255); - SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_unique ? entry_unique : entry_name, text_color); - + SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); + SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); + SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; + SDL_Rect dest_rect = { SCALE1(BUTTON_MARGIN + BUTTON_PADDING), SCALE1(PADDING + (j * PILL_SIZE)+4) }; + SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); + SDL_BlitSurface(text, &text_rect, screen, &dest_rect); is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); if(animationdirection == 0) { @@ -2354,15 +2371,8 @@ int main (int argc, char *argv[]) { task->targetY = SCALE1(targetY+PADDING); task->move_w = max_width; task->move_h = SCALE1(PILL_SIZE); - task->reveal_x = SCALE1(BUTTON_MARGIN + BUTTON_PADDING); - task->reveal_y = SCALE1(targetY+PADDING+4); - task->reveal_w = max_width - SCALE1(BUTTON_PADDING*2); - task->reveal_h = text->h; - task->reveal_direction = selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down"; - task->duration = 60; - task->startAlpha = 255; - task->targetAlpha = 255; - SDL_Thread *test = SDL_CreateThread(animTaskThread, "AnimThread", task); + task->duration = 50; + animPill(task); } @@ -2404,7 +2414,6 @@ int main (int argc, char *argv[]) { SDL_UnlockMutex(folderBgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { - GFX_clearLayers(2); int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; @@ -2425,19 +2434,24 @@ int main (int argc, char *argv[]) { int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h - GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,2); + GFX_clearLayers(3); + GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,3); } else if(thumbchanged) { - GFX_clearLayers(2); + GFX_clearLayers(3); } SDL_UnlockMutex(thumbMutex); } - GFX_clearLayers(3); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); - PLAT_GPU_Flip(); + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); GFX_flip(screen); + SDL_LockMutex(animMutex); + frameReady = true; + SDL_CondSignal(flipCond); + SDL_UnlockMutex(animMutex); dirty = 0; readytoscroll = 0; } else { + // honestly this whole thing is here only for the scrolling text, I set it now to run this at 30fps which is enough for scrolling text, should move this to seperate animation function eventually Uint32 now = SDL_GetTicks(); Uint32 frame_start = now; @@ -2453,7 +2467,6 @@ int main (int argc, char *argv[]) { SDL_UnlockMutex(folderBgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { - GFX_clearLayers(2); int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; @@ -2476,15 +2489,15 @@ int main (int argc, char *argv[]) { int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h - GFX_clearLayers(2); - GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,2); + GFX_clearLayers(3); + GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,3); thumbchanged = 0; } else if(thumbchanged) { - GFX_clearLayers(2); - } + GFX_clearLayers(3); + } SDL_UnlockMutex(thumbMutex); - if (!show_switcher && !show_version && is_scrolling) { + if (!show_switcher && !show_version && is_scrolling && pillanimdone) { int ow = GFX_blitHardwareGroup(screen, show_setting); Entry* entry = top->entries->items[top->selected]; @@ -2502,10 +2515,10 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_text, cached_display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); - - - + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + GFX_clearLayers(4); GFX_scrollTextTexture( font.large, @@ -2518,20 +2531,19 @@ int main (int argc, char *argv[]) { 1 ); - } - if (!show_switcher && !show_version) { - GFX_clearLayers(3); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); - PLAT_GPU_Flip(); + else if (!show_switcher && !show_version) { + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + PLAT_GPU_Flip(); } + SDL_LockMutex(animMutex); + frameReady = true; + SDL_CondSignal(flipCond); + SDL_UnlockMutex(animMutex); dirty = 0; - const int fps = 30; // 30fps is more then enough for scrolling text - const int frame_delay = 1000 / fps; - Uint32 frame_time = SDL_GetTicks() - frame_start; - if (frame_time < frame_delay) { - SDL_Delay(frame_delay - frame_time); - } + + } // handle HDMI change diff --git a/workspace/tg5040/platform/platform.c b/workspace/tg5040/platform/platform.c index 472c562b0..69d7d1d16 100644 --- a/workspace/tg5040/platform/platform.c +++ b/workspace/tg5040/platform/platform.c @@ -94,6 +94,7 @@ static struct VID_Context { SDL_Texture* stream_layer1; SDL_Texture* target_layer3; SDL_Texture* target_layer4; + SDL_Texture* target_layer5; SDL_Texture* target; SDL_Texture* effect; SDL_Texture* overlay; @@ -478,6 +479,7 @@ SDL_Surface* PLAT_initVideo(void) { vid.target_layer2 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer3 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer4 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); + vid.target_layer5 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target = NULL; // only needed for non-native sizes @@ -488,6 +490,7 @@ SDL_Surface* PLAT_initVideo(void) { SDL_SetTextureBlendMode(vid.target_layer2, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(vid.target_layer3, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(vid.target_layer4, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(vid.target_layer5, SDL_BLENDMODE_BLEND); vid.width = w; vid.height = h; @@ -737,6 +740,7 @@ void PLAT_quitVideo(void) { if (vid.target_layer1) SDL_DestroyTexture(vid.target_layer1); if (vid.target_layer2) SDL_DestroyTexture(vid.target_layer2); if (vid.target_layer4) SDL_DestroyTexture(vid.target_layer4); + if (vid.target_layer5) SDL_DestroyTexture(vid.target_layer5); if (overlay_path) free(overlay_path); SDL_DestroyTexture(vid.stream_layer1); SDL_DestroyRenderer(vid.renderer); @@ -1005,6 +1009,10 @@ void PLAT_clearLayers(int layer) { SDL_SetRenderTarget(vid.renderer, vid.target_layer4); SDL_RenderClear(vid.renderer); } + if(layer==0 || layer==5) { + SDL_SetRenderTarget(vid.renderer, vid.target_layer5); + SDL_RenderClear(vid.renderer); + } SDL_SetRenderTarget(vid.renderer, NULL); } @@ -1036,6 +1044,9 @@ void PLAT_drawOnLayer(SDL_Surface *inputSurface, int x, int y, int w, int h, flo case 4: SDL_SetRenderTarget(vid.renderer, vid.target_layer4); break; + case 5: + SDL_SetRenderTarget(vid.renderer, vid.target_layer5); + break; default: SDL_SetRenderTarget(vid.renderer, vid.target_layer1); break; @@ -1221,6 +1232,7 @@ void PLAT_GPU_Flip() { SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer5, NULL, NULL); SDL_RenderPresent(vid.renderer); } @@ -1670,6 +1682,7 @@ void PLAT_flipHidden() { SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer5, NULL, NULL); // SDL_RenderPresent(vid.renderer); // no present want to flip hidden } @@ -1684,6 +1697,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer5, NULL, NULL); SDL_RenderPresent(vid.renderer); return; } From 6661c37fb52fed7b45eda5ad4c404b958a4b693a Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Mon, 19 May 2025 20:00:37 +0200 Subject: [PATCH 04/13] ff --- workspace/all/nextui/nextui.c | 62 +++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 6ab1279c7..dd99d051b 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1435,26 +1435,48 @@ static SDL_Surface* folderbgbmp = NULL; static SDL_Surface* thumbbmp = NULL; static SDL_Surface* screen = NULL; // Must be assigned externally -// i think 2 is fine could probably even be 1 -#define THREAD_POOL_SIZE 2 static int had_thumb = 0; static int ox; static int oy; // queue a new image load task :D +#define MAX_QUEUE_SIZE 3 + +int currentQueueSize = 0; + void enqueueTask(LoadBackgroundTask* task) { TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); node->task = task; node->next = NULL; SDL_LockMutex(queueMutex); + + // If queue is full, drop the oldest task (head) + if (currentQueueSize >= MAX_QUEUE_SIZE) { + TaskNode* oldNode = taskQueueHead; + if (oldNode) { + taskQueueHead = oldNode->next; + if (!taskQueueHead) { + taskQueueTail = NULL; + } + if (oldNode->task) { + free(oldNode->task); // Only if task was malloc'd + } + free(oldNode); + currentQueueSize--; + } + } + + // Enqueue the new task if (taskQueueTail) { taskQueueTail->next = node; taskQueueTail = node; } else { taskQueueHead = taskQueueTail = node; } + + currentQueueSize++; SDL_CondSignal(queueCond); SDL_UnlockMutex(queueMutex); } @@ -1490,6 +1512,10 @@ int imageLoadWorker(void* unused) { if (task->callback) task->callback(result); free(task); + SDL_LockMutex(queueMutex); + if (!taskQueueHead) taskQueueTail = NULL; + currentQueueSize--; // <-- add this + SDL_UnlockMutex(queueMutex); } return 0; } @@ -1638,10 +1664,8 @@ void initImageLoaderPool() { folderBgMutex = SDL_CreateMutex(); thumbMutex = SDL_CreateMutex(); - for (int i = 0; i < THREAD_POOL_SIZE; ++i) { - SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); - } - SDL_CreateThread(animWorker, "animWorker", NULL); + SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); + SDL_CreateThread(animWorker, "animWorker", NULL); } /////////////////////////////////////// @@ -1956,6 +1980,7 @@ int main (int argc, char *argv[]) { GFX_clearLayers(0); } else { + GFX_clearLayers(2); if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(3); GFX_clearLayers(4); GFX_clearLayers(5); @@ -2077,7 +2102,7 @@ int main (int argc, char *argv[]) { SDL_FreeSurface(tmpsur); } else if(show_switcher) { - GFX_clearLayers(2); + GFX_clearLayers(0); // For all recents with resumable state (i.e. has savegame), show game switcher carousel @@ -2404,14 +2429,14 @@ int main (int argc, char *argv[]) { animationdirection=0; } if(lastScreen == SCREEN_GAMELIST) { - SDL_LockMutex(folderBgMutex); - if(folderbgchanged && folderbgbmp) { - GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,1); - folderbgchanged = 0; - } else if(folderbgchanged) { - GFX_clearLayers(1); - } - SDL_UnlockMutex(folderBgMutex); + SDL_LockMutex(folderBgMutex); + if(folderbgchanged && folderbgbmp) { + GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,1); + folderbgchanged = 0; + } else if(folderbgchanged) { + GFX_clearLayers(1); + } + SDL_UnlockMutex(folderBgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { int img_w = thumbbmp->w; @@ -2440,9 +2465,10 @@ int main (int argc, char *argv[]) { GFX_clearLayers(3); } SDL_UnlockMutex(thumbMutex); + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); } - GFX_clearLayers(2); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + GFX_flip(screen); SDL_LockMutex(animMutex); frameReady = true; @@ -2518,7 +2544,7 @@ int main (int argc, char *argv[]) { GFX_clearLayers(2); GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); - + GFX_clearLayers(4); GFX_scrollTextTexture( font.large, From 656392914cf8f30b24f43cd82d35d3c8b5297175 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Mon, 19 May 2025 20:25:34 +0200 Subject: [PATCH 05/13] ff --- workspace/all/nextui/nextui.c | 94 ++++++++++++++++------------------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index dd99d051b..711847cea 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1359,32 +1359,6 @@ static int remember_selection = 0; /////////////////////////////////////// -SDL_Surface* loadFolderBackground(char* rompath, int type) -{ - char imagePath[MAX_PATH]; - if(type == ENTRY_DIR) - snprintf(imagePath, sizeof(imagePath), "%s/.media/bg.png", rompath); - else if(type == ENTRY_ROM) - snprintf(imagePath, sizeof(imagePath), "%s/.media/bglist.png", rompath); - - //LOG_info("Loading folder bg from %s\n", imagePath); - if(exists(imagePath)) { - SDL_Surface *image = IMG_Load(imagePath); - if(!image) - return NULL; - - SDL_Surface *image565 = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGBA8888, 0); - if(image565) { - SDL_FreeSurface(image); - image = image565; - } - - return image; - } else { - return NULL; - } -} - typedef void (*BackgroundLoadedCallback)(SDL_Surface* surface); typedef struct { @@ -1405,7 +1379,7 @@ typedef struct AnimTask { AnimTaskCallback callback; void* userData; } AnimTask; -// --- Thread pool structures --- + typedef struct TaskNode { LoadBackgroundTask* task; struct TaskNode* next; @@ -1444,6 +1418,7 @@ static int oy; #define MAX_QUEUE_SIZE 3 int currentQueueSize = 0; +int currentAnimQueueSize = 0; void enqueueTask(LoadBackgroundTask* task) { TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); @@ -1498,16 +1473,12 @@ int imageLoadWorker(void* unused) { SDL_Surface* result = NULL; if (access(task->imagePath, F_OK) == 0) { - SDL_LockMutex(imgLoadMutex); SDL_Surface* image = IMG_Load(task->imagePath); - - if (image) { SDL_Surface* imageRGBA = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGBA8888, 0); SDL_FreeSurface(image); result = imageRGBA; } - SDL_UnlockMutex(imgLoadMutex); } if (task->callback) task->callback(result); @@ -1544,8 +1515,7 @@ void onBackgroundLoaded(SDL_Surface* surface) { } SDL_Surface* safeCopy = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0); - SDL_FreeSurface(surface); // Free the original from the thread - + SDL_FreeSurface(surface); if (!safeCopy) return; if (folderbgbmp) SDL_FreeSurface(folderbgbmp); @@ -1572,9 +1542,8 @@ void onThumbLoaded(SDL_Surface* surface) { return; } - // Convert to a known pixel format (e.g., RGBA8888) to ensure compatibility SDL_Surface* safeCopy = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0); - SDL_FreeSurface(surface); // Free the thread-allocated surface + SDL_FreeSurface(surface); if (!safeCopy) return; @@ -1584,12 +1553,8 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); } - - SDL_Rect pillRect; - - void animcallback(SDL_Rect dst) { pillRect = dst; } @@ -1627,10 +1592,11 @@ int animWorker(void* unused) { } frameReady = false; SDL_UnlockMutex(animMutex); - - - } + SDL_LockMutex(animqueueMutex); + if (!animTaskQueueHead) animTtaskQueueTail = NULL; + currentAnimQueueSize--; // <-- add this + SDL_UnlockMutex(animqueueMutex); pillanimdone = 1; } @@ -1640,18 +1606,39 @@ void enqueueanmimtask(AnimTask* task) { AnimTaskNode* node = (AnimTaskNode*)malloc(sizeof(AnimTaskNode)); node->task = task; node->next = NULL; - pillanimdone = 0; + SDL_LockMutex(animqueueMutex); + pillanimdone = 0; + // If queue is full, drop the oldest task (head) + if (currentAnimQueueSize >= MAX_QUEUE_SIZE) { + AnimTaskNode* oldNode = animTaskQueueHead; + if (oldNode) { + animTaskQueueHead = oldNode->next; + if (!animTaskQueueHead) { + animTtaskQueueTail = NULL; + } + if (oldNode->task) { + free(oldNode->task); // Only if task was malloc'd + } + free(oldNode); + currentAnimQueueSize--; + } + } + + // Enqueue the new task if (animTtaskQueueTail) { animTtaskQueueTail->next = node; animTtaskQueueTail = node; } else { animTaskQueueHead = animTtaskQueueTail = node; } + + currentAnimQueueSize++; SDL_CondSignal(animqueueCond); SDL_UnlockMutex(animqueueMutex); } + int animPill(AnimTask *task) { task->callback = animcallback; enqueueanmimtask(task); @@ -1753,14 +1740,14 @@ int main (int argc, char *argv[]) { pthread_t cpucheckthread; pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL); - SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( - SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 - ); + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); - GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ - 0,0, 500, SCALE1(PILL_SIZE) - }); + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, 500, SCALE1(PILL_SIZE) + }); LOG_info("Start time time %ims\n",SDL_GetTicks()); while (!quit) { @@ -2387,7 +2374,14 @@ int main (int argc, char *argv[]) { SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); SDL_BlitSurface(text, &text_rect, screen, &dest_rect); is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); - + if(globalpill) SDL_FreeSurface(globalpill); + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); + + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, max_width, SCALE1(PILL_SIZE) + }); if(animationdirection == 0) { AnimTask* task = malloc(sizeof(AnimTask)); task->startX = SCALE1(BUTTON_MARGIN); From e091490a0b815f539f0f91b324a1490c107f1543 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Sun, 18 May 2025 21:00:46 +0200 Subject: [PATCH 06/13] ff --- workspace/all/nextui/nextui.c | 129 +++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 17 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 0dd81bd40..83d854792 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1418,6 +1418,7 @@ static SDL_Surface* screen = NULL; // Must be assigned externally static int had_thumb = 0; static int ox; static int oy; + // queue a new image load task :D void enqueueTask(LoadBackgroundTask* task) { TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); @@ -1545,6 +1546,82 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); } +typedef void (*AnimTaskCallback)(SDL_Rect moveDst); +typedef struct AnimTask { + int startX; + int targetX; + int startY; + int targetY; + int startAlpha; + int targetAlpha; + const char* reveal_direction; + int move_w; + int move_h; + int reveal_w; + int reveal_h; + int reveal_x; + int reveal_y; + int duration; + AnimTaskCallback callback; +} AnimTask; + +SDL_Rect pillRect; +void animcallback(SDL_Rect dst) { + pillRect = dst; +} +int doAnimTask(AnimTask* task) { + const int fps = 60; + const int frame_delay = 1000 / fps; + const int total_frames = task->duration / frame_delay; + + for (int frame = 0; frame <= total_frames; ++frame) { + float t = (float)frame / total_frames; + if (t > 1.0f) t = 1.0f; + + int current_x = task->startX + (int)((task->targetX - task->startX) * t); + int current_y = task->startY + (int)(( task->targetY - task->startY) * t); + int current_opacity = task->startAlpha + (int)((task->targetAlpha - task->startAlpha) * t); + if (current_opacity < 0) current_opacity = 0; + if (current_opacity > 255) current_opacity = 255; + + + int reveal_src_x = 0, reveal_src_y = 0; + int reveal_draw_w = task->reveal_w, reveal_draw_h = task->reveal_h; + + if (strcmp(task->reveal_direction, "left") == 0) { + reveal_draw_w = (int)(task->reveal_w * t + 0.5f); + } + else if (strcmp(task->reveal_direction, "right") == 0) { + reveal_draw_w = (int)(task->reveal_w * t + 0.5f); + reveal_src_x = task->reveal_w - reveal_draw_w; + } + else if (strcmp(task->reveal_direction, "up") == 0) { + reveal_draw_h = (int)(task->reveal_h * t + 0.5f); + } + else if (strcmp(task->reveal_direction, "down") == 0) { + reveal_draw_h = (int)(task->reveal_h * t + 0.5f); + reveal_src_y = task->reveal_h - reveal_draw_h; + } + + SDL_Rect revealSrc = { reveal_src_x, reveal_src_y, reveal_draw_w, reveal_draw_h }; + SDL_Rect revealDst = { task->reveal_x + reveal_src_x, task->reveal_y + reveal_src_y, reveal_draw_w, reveal_draw_h }; + SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; + task->callback(moveDst); + SDL_Delay(16); + + + } + + +} + + +int animTaskThread(void *data) { + AnimTask *task = (AnimTask *)data; + task->callback = animcallback; + doAnimTask(task); + return 0; +} /////////////////////////////////////// enum { @@ -1630,6 +1707,16 @@ int main (int argc, char *argv[]) { pthread_t cpucheckthread; pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL); + + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); + + + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, 500, SCALE1(PILL_SIZE) + }); + LOG_info("Start time time %ims\n",SDL_GetTicks()); while (!quit) { @@ -2264,24 +2351,27 @@ int main (int argc, char *argv[]) { SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_unique ? entry_unique : entry_name, text_color); is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); - SDL_Surface *pill = SDL_CreateRGBSurfaceWithFormat( - SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 - ); - GFX_blitPillDark(ASSET_WHITE_PILL, pill, &(SDL_Rect){ - 0,0, max_width, SCALE1(PILL_SIZE) - }); + if(animationdirection == 0) { - GFX_flipHidden(); - GFX_animateAndRevealSurfaces( - pill,text, - SCALE1(BUTTON_MARGIN), SCALE1(previousY+PADDING),SCALE1(BUTTON_MARGIN),SCALE1(targetY+PADDING),max_width,SCALE1(PILL_SIZE), - SCALE1(BUTTON_MARGIN + BUTTON_PADDING),SCALE1(targetY+PADDING+4),max_width - SCALE1(BUTTON_PADDING*2),text->h, - selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down", - CFG_getMenuAnimations() ? 40:10,255,255,255,0,1 - ); + AnimTask* task = malloc(sizeof(AnimTask)); + task->startX = SCALE1(BUTTON_MARGIN); + task->startY = SCALE1(previousY+PADDING); + task->targetX = SCALE1(BUTTON_MARGIN); + task->targetY = SCALE1(targetY+PADDING); + task->move_w = max_width; + task->move_h = SCALE1(PILL_SIZE); + task->reveal_x = SCALE1(BUTTON_MARGIN + BUTTON_PADDING); + task->reveal_y = SCALE1(targetY+PADDING+4); + task->reveal_w = max_width - SCALE1(BUTTON_PADDING*2); + task->reveal_h = text->h; + task->reveal_direction = selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down"; + task->duration = 100; + task->startAlpha = 255; + task->targetAlpha = 255; + SDL_Thread *test = SDL_CreateThread(animTaskThread, "AnimThread", task); + } - SDL_FreeSurface(text); - SDL_FreeSurface(pill); + } } remember_selection = selected_row; @@ -2432,7 +2522,12 @@ int main (int argc, char *argv[]) { ); - } else if (!show_switcher && !show_version) { + } + if (!show_switcher && !show_version) { + + GFX_clearLayers(3); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); + PLAT_GPU_Flip(); PLAT_GPU_Flip(); } dirty = 0; From 93bca4f8686bc1e222ee4efa79a5b6e1fc002e10 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Sun, 18 May 2025 22:47:35 +0200 Subject: [PATCH 07/13] ff --- workspace/all/nextui/nextui.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 83d854792..881292c98 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -2365,7 +2365,7 @@ int main (int argc, char *argv[]) { task->reveal_w = max_width - SCALE1(BUTTON_PADDING*2); task->reveal_h = text->h; task->reveal_direction = selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down"; - task->duration = 100; + task->duration = 60; task->startAlpha = 255; task->targetAlpha = 255; SDL_Thread *test = SDL_CreateThread(animTaskThread, "AnimThread", task); @@ -2437,6 +2437,9 @@ int main (int argc, char *argv[]) { } SDL_UnlockMutex(thumbMutex); } + GFX_clearLayers(3); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); + PLAT_GPU_Flip(); GFX_flip(screen); dirty = 0; readytoscroll = 0; @@ -2524,10 +2527,8 @@ int main (int argc, char *argv[]) { } if (!show_switcher && !show_version) { - - GFX_clearLayers(3); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); - PLAT_GPU_Flip(); + GFX_clearLayers(3); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); PLAT_GPU_Flip(); } dirty = 0; From 573e645488dd42fc2efe18ea555458d3708b8c95 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Mon, 19 May 2025 19:32:58 +0200 Subject: [PATCH 08/13] ok now its going in the good direction already works pretty good! --- workspace/all/nextui/nextui.c | 242 ++++++++++++++------------- workspace/tg5040/platform/platform.c | 14 ++ 2 files changed, 141 insertions(+), 115 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 881292c98..078002c05 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1393,16 +1393,39 @@ typedef struct { void* userData; } LoadBackgroundTask; +typedef void (*AnimTaskCallback)(SDL_Rect moveDst); +typedef struct AnimTask { + int startX; + int targetX; + int startY; + int targetY; + int move_w; + int move_h; + int duration; + AnimTaskCallback callback; + void* userData; +} AnimTask; // --- Thread pool structures --- typedef struct TaskNode { LoadBackgroundTask* task; struct TaskNode* next; } TaskNode; +typedef struct AnimTaskNode { + AnimTask* task; + struct AnimTaskNode* next; +} AnimTaskNode; static TaskNode* taskQueueHead = NULL; static TaskNode* taskQueueTail = NULL; +static AnimTaskNode* animTaskQueueHead = NULL; +static AnimTaskNode* animTtaskQueueTail = NULL; static SDL_mutex* queueMutex = NULL; +static SDL_mutex* animqueueMutex = NULL; static SDL_cond* queueCond = NULL; +static SDL_cond* animqueueCond = NULL; + +static SDL_mutex* animMutex = NULL; +static SDL_cond* flipCond = NULL; static SDL_mutex* imgLoadMutex = NULL; static SDL_mutex* folderBgMutex = NULL; @@ -1471,17 +1494,6 @@ int imageLoadWorker(void* unused) { return 0; } -void initImageLoaderPool() { - queueMutex = SDL_CreateMutex(); - queueCond = SDL_CreateCond(); - imgLoadMutex = SDL_CreateMutex(); - folderBgMutex = SDL_CreateMutex(); - thumbMutex = SDL_CreateMutex(); - - for (int i = 0; i < THREAD_POOL_SIZE; ++i) { - SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); - } -} int folderbgchanged=0; int thumbchanged=0; @@ -1546,82 +1558,91 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); } -typedef void (*AnimTaskCallback)(SDL_Rect moveDst); -typedef struct AnimTask { - int startX; - int targetX; - int startY; - int targetY; - int startAlpha; - int targetAlpha; - const char* reveal_direction; - int move_w; - int move_h; - int reveal_w; - int reveal_h; - int reveal_x; - int reveal_y; - int duration; - AnimTaskCallback callback; -} AnimTask; + SDL_Rect pillRect; + + + void animcallback(SDL_Rect dst) { pillRect = dst; } -int doAnimTask(AnimTask* task) { - const int fps = 60; - const int frame_delay = 1000 / fps; - const int total_frames = task->duration / frame_delay; +bool frameReady = false; +int pillanimdone = 0; +int animWorker(void* unused) { + while (true) { + SDL_LockMutex(animqueueMutex); + while (!animTaskQueueHead) { + SDL_CondWait(animqueueCond, animqueueMutex); + } + AnimTaskNode* node = animTaskQueueHead; + animTaskQueueHead = node->next; + if (!animTaskQueueHead) animTtaskQueueTail = NULL; + SDL_UnlockMutex(animqueueMutex); - for (int frame = 0; frame <= total_frames; ++frame) { - float t = (float)frame / total_frames; - if (t > 1.0f) t = 1.0f; + AnimTask* task = node->task; - int current_x = task->startX + (int)((task->targetX - task->startX) * t); - int current_y = task->startY + (int)(( task->targetY - task->startY) * t); - int current_opacity = task->startAlpha + (int)((task->targetAlpha - task->startAlpha) * t); - if (current_opacity < 0) current_opacity = 0; - if (current_opacity > 255) current_opacity = 255; - + int fps = 60; + int frame_delay = 1000 / fps; + int total_frames = task->duration / frame_delay; - int reveal_src_x = 0, reveal_src_y = 0; - int reveal_draw_w = task->reveal_w, reveal_draw_h = task->reveal_h; - - if (strcmp(task->reveal_direction, "left") == 0) { - reveal_draw_w = (int)(task->reveal_w * t + 0.5f); - } - else if (strcmp(task->reveal_direction, "right") == 0) { - reveal_draw_w = (int)(task->reveal_w * t + 0.5f); - reveal_src_x = task->reveal_w - reveal_draw_w; - } - else if (strcmp(task->reveal_direction, "up") == 0) { - reveal_draw_h = (int)(task->reveal_h * t + 0.5f); - } - else if (strcmp(task->reveal_direction, "down") == 0) { - reveal_draw_h = (int)(task->reveal_h * t + 0.5f); - reveal_src_y = task->reveal_h - reveal_draw_h; - } + for (int frame = 0; frame <= total_frames; ++frame) { + float t = (float)frame / total_frames; + if (t > 1.0f) t = 1.0f; - SDL_Rect revealSrc = { reveal_src_x, reveal_src_y, reveal_draw_w, reveal_draw_h }; - SDL_Rect revealDst = { task->reveal_x + reveal_src_x, task->reveal_y + reveal_src_y, reveal_draw_w, reveal_draw_h }; - SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; - task->callback(moveDst); - SDL_Delay(16); + int current_x = task->startX + (int)((task->targetX - task->startX) * t); + int current_y = task->startY + (int)(( task->targetY - task->startY) * t); + + SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; + task->callback(moveDst); + SDL_LockMutex(animMutex); + while (!frameReady) { + SDL_CondWait(flipCond, animMutex); + } + frameReady = false; + SDL_UnlockMutex(animMutex); - } + } + pillanimdone = 1; + } } +void enqueueanmimtask(AnimTask* task) { + AnimTaskNode* node = (AnimTaskNode*)malloc(sizeof(AnimTaskNode)); + node->task = task; + node->next = NULL; + pillanimdone = 0; + SDL_LockMutex(animqueueMutex); + if (animTtaskQueueTail) { + animTtaskQueueTail->next = node; + animTtaskQueueTail = node; + } else { + animTaskQueueHead = animTtaskQueueTail = node; + } + SDL_CondSignal(animqueueCond); + SDL_UnlockMutex(animqueueMutex); +} -int animTaskThread(void *data) { - AnimTask *task = (AnimTask *)data; +int animPill(AnimTask *task) { task->callback = animcallback; - doAnimTask(task); + enqueueanmimtask(task); return 0; } +void initImageLoaderPool() { + queueMutex = SDL_CreateMutex(); + queueCond = SDL_CreateCond(); + imgLoadMutex = SDL_CreateMutex(); + folderBgMutex = SDL_CreateMutex(); + thumbMutex = SDL_CreateMutex(); + + for (int i = 0; i < THREAD_POOL_SIZE; ++i) { + SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); + } + SDL_CreateThread(animWorker, "animWorker", NULL); +} /////////////////////////////////////// enum { @@ -1937,9 +1958,9 @@ int main (int argc, char *argv[]) { GFX_clearLayers(0); } else { - if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(2); - GFX_clearLayers(3); + if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(3); GFX_clearLayers(4); + GFX_clearLayers(5); } GFX_clear(screen); @@ -2303,14 +2324,6 @@ int main (int argc, char *argv[]) { int max_width = MIN(available_width, text_width); SDL_Color text_color = uintToColour(THEME_COLOR4_255); - - if (j == selected_row && animationdirection > 0) { - GFX_blitPillDark(ASSET_WHITE_PILL, screen, &(SDL_Rect){ - SCALE1(BUTTON_MARGIN),SCALE1(targetY+PADDING), max_width, SCALE1(PILL_SIZE) - }); - text_color = uintToColour(THEME_COLOR5_255); - } - SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; @@ -2348,8 +2361,12 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_unique ? entry_unique : entry_name, display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); SDL_Color text_color = uintToColour(THEME_COLOR5_255); - SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_unique ? entry_unique : entry_name, text_color); - + SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); + SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); + SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; + SDL_Rect dest_rect = { SCALE1(BUTTON_MARGIN + BUTTON_PADDING), SCALE1(PADDING + (j * PILL_SIZE)+4) }; + SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); + SDL_BlitSurface(text, &text_rect, screen, &dest_rect); is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); if(animationdirection == 0) { @@ -2360,15 +2377,8 @@ int main (int argc, char *argv[]) { task->targetY = SCALE1(targetY+PADDING); task->move_w = max_width; task->move_h = SCALE1(PILL_SIZE); - task->reveal_x = SCALE1(BUTTON_MARGIN + BUTTON_PADDING); - task->reveal_y = SCALE1(targetY+PADDING+4); - task->reveal_w = max_width - SCALE1(BUTTON_PADDING*2); - task->reveal_h = text->h; - task->reveal_direction = selected_row == remember_selection ? "none" : selected_row > remember_selection ? "up":"down"; - task->duration = 60; - task->startAlpha = 255; - task->targetAlpha = 255; - SDL_Thread *test = SDL_CreateThread(animTaskThread, "AnimThread", task); + task->duration = 50; + animPill(task); } @@ -2410,7 +2420,6 @@ int main (int argc, char *argv[]) { SDL_UnlockMutex(folderBgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { - GFX_clearLayers(2); int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; @@ -2431,19 +2440,24 @@ int main (int argc, char *argv[]) { int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h - GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,2); + GFX_clearLayers(3); + GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,3); } else if(thumbchanged) { - GFX_clearLayers(2); + GFX_clearLayers(3); } SDL_UnlockMutex(thumbMutex); } - GFX_clearLayers(3); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); - PLAT_GPU_Flip(); + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); GFX_flip(screen); + SDL_LockMutex(animMutex); + frameReady = true; + SDL_CondSignal(flipCond); + SDL_UnlockMutex(animMutex); dirty = 0; readytoscroll = 0; } else { + // honestly this whole thing is here only for the scrolling text, I set it now to run this at 30fps which is enough for scrolling text, should move this to seperate animation function eventually Uint32 now = SDL_GetTicks(); Uint32 frame_start = now; @@ -2459,7 +2473,6 @@ int main (int argc, char *argv[]) { SDL_UnlockMutex(folderBgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { - GFX_clearLayers(2); int img_w = thumbbmp->w; int img_h = thumbbmp->h; double aspect_ratio = (double)img_h / img_w; @@ -2482,15 +2495,15 @@ int main (int argc, char *argv[]) { int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h - GFX_clearLayers(2); - GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,2); + GFX_clearLayers(3); + GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,3); thumbchanged = 0; } else if(thumbchanged) { - GFX_clearLayers(2); - } + GFX_clearLayers(3); + } SDL_UnlockMutex(thumbMutex); - if (!show_switcher && !show_version && is_scrolling) { + if (!show_switcher && !show_version && is_scrolling && pillanimdone) { int ow = GFX_blitHardwareGroup(screen, show_setting); Entry* entry = top->entries->items[top->selected]; @@ -2508,10 +2521,10 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_text, cached_display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); - - - + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + GFX_clearLayers(4); GFX_scrollTextTexture( font.large, @@ -2524,20 +2537,19 @@ int main (int argc, char *argv[]) { 1 ); - } - if (!show_switcher && !show_version) { - GFX_clearLayers(3); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 3); - PLAT_GPU_Flip(); + else if (!show_switcher && !show_version) { + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + PLAT_GPU_Flip(); } + SDL_LockMutex(animMutex); + frameReady = true; + SDL_CondSignal(flipCond); + SDL_UnlockMutex(animMutex); dirty = 0; - const int fps = 30; // 30fps is more then enough for scrolling text - const int frame_delay = 1000 / fps; - Uint32 frame_time = SDL_GetTicks() - frame_start; - if (frame_time < frame_delay) { - SDL_Delay(frame_delay - frame_time); - } + + } // handle HDMI change diff --git a/workspace/tg5040/platform/platform.c b/workspace/tg5040/platform/platform.c index 472c562b0..69d7d1d16 100644 --- a/workspace/tg5040/platform/platform.c +++ b/workspace/tg5040/platform/platform.c @@ -94,6 +94,7 @@ static struct VID_Context { SDL_Texture* stream_layer1; SDL_Texture* target_layer3; SDL_Texture* target_layer4; + SDL_Texture* target_layer5; SDL_Texture* target; SDL_Texture* effect; SDL_Texture* overlay; @@ -478,6 +479,7 @@ SDL_Surface* PLAT_initVideo(void) { vid.target_layer2 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer3 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target_layer4 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); + vid.target_layer5 = SDL_CreateTexture(vid.renderer,SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET , w,h); vid.target = NULL; // only needed for non-native sizes @@ -488,6 +490,7 @@ SDL_Surface* PLAT_initVideo(void) { SDL_SetTextureBlendMode(vid.target_layer2, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(vid.target_layer3, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(vid.target_layer4, SDL_BLENDMODE_BLEND); + SDL_SetTextureBlendMode(vid.target_layer5, SDL_BLENDMODE_BLEND); vid.width = w; vid.height = h; @@ -737,6 +740,7 @@ void PLAT_quitVideo(void) { if (vid.target_layer1) SDL_DestroyTexture(vid.target_layer1); if (vid.target_layer2) SDL_DestroyTexture(vid.target_layer2); if (vid.target_layer4) SDL_DestroyTexture(vid.target_layer4); + if (vid.target_layer5) SDL_DestroyTexture(vid.target_layer5); if (overlay_path) free(overlay_path); SDL_DestroyTexture(vid.stream_layer1); SDL_DestroyRenderer(vid.renderer); @@ -1005,6 +1009,10 @@ void PLAT_clearLayers(int layer) { SDL_SetRenderTarget(vid.renderer, vid.target_layer4); SDL_RenderClear(vid.renderer); } + if(layer==0 || layer==5) { + SDL_SetRenderTarget(vid.renderer, vid.target_layer5); + SDL_RenderClear(vid.renderer); + } SDL_SetRenderTarget(vid.renderer, NULL); } @@ -1036,6 +1044,9 @@ void PLAT_drawOnLayer(SDL_Surface *inputSurface, int x, int y, int w, int h, flo case 4: SDL_SetRenderTarget(vid.renderer, vid.target_layer4); break; + case 5: + SDL_SetRenderTarget(vid.renderer, vid.target_layer5); + break; default: SDL_SetRenderTarget(vid.renderer, vid.target_layer1); break; @@ -1221,6 +1232,7 @@ void PLAT_GPU_Flip() { SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer5, NULL, NULL); SDL_RenderPresent(vid.renderer); } @@ -1670,6 +1682,7 @@ void PLAT_flipHidden() { SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer5, NULL, NULL); // SDL_RenderPresent(vid.renderer); // no present want to flip hidden } @@ -1684,6 +1697,7 @@ void PLAT_flip(SDL_Surface* IGNORED, int ignored) { SDL_RenderCopy(vid.renderer, vid.stream_layer1, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer3, NULL, NULL); SDL_RenderCopy(vid.renderer, vid.target_layer4, NULL, NULL); + SDL_RenderCopy(vid.renderer, vid.target_layer5, NULL, NULL); SDL_RenderPresent(vid.renderer); return; } From 9496869c3b1de096309d30ac19bde5d8e2dad06f Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Mon, 19 May 2025 20:00:37 +0200 Subject: [PATCH 09/13] ff --- workspace/all/nextui/nextui.c | 62 +++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 078002c05..d93c47022 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1435,26 +1435,48 @@ static SDL_Surface* folderbgbmp = NULL; static SDL_Surface* thumbbmp = NULL; static SDL_Surface* screen = NULL; // Must be assigned externally -// i think 2 is fine could probably even be 1 -#define THREAD_POOL_SIZE 2 static int had_thumb = 0; static int ox; static int oy; // queue a new image load task :D +#define MAX_QUEUE_SIZE 3 + +int currentQueueSize = 0; + void enqueueTask(LoadBackgroundTask* task) { TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); node->task = task; node->next = NULL; SDL_LockMutex(queueMutex); + + // If queue is full, drop the oldest task (head) + if (currentQueueSize >= MAX_QUEUE_SIZE) { + TaskNode* oldNode = taskQueueHead; + if (oldNode) { + taskQueueHead = oldNode->next; + if (!taskQueueHead) { + taskQueueTail = NULL; + } + if (oldNode->task) { + free(oldNode->task); // Only if task was malloc'd + } + free(oldNode); + currentQueueSize--; + } + } + + // Enqueue the new task if (taskQueueTail) { taskQueueTail->next = node; taskQueueTail = node; } else { taskQueueHead = taskQueueTail = node; } + + currentQueueSize++; SDL_CondSignal(queueCond); SDL_UnlockMutex(queueMutex); } @@ -1490,6 +1512,10 @@ int imageLoadWorker(void* unused) { if (task->callback) task->callback(result); free(task); + SDL_LockMutex(queueMutex); + if (!taskQueueHead) taskQueueTail = NULL; + currentQueueSize--; // <-- add this + SDL_UnlockMutex(queueMutex); } return 0; } @@ -1638,10 +1664,8 @@ void initImageLoaderPool() { folderBgMutex = SDL_CreateMutex(); thumbMutex = SDL_CreateMutex(); - for (int i = 0; i < THREAD_POOL_SIZE; ++i) { - SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); - } - SDL_CreateThread(animWorker, "animWorker", NULL); + SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); + SDL_CreateThread(animWorker, "animWorker", NULL); } /////////////////////////////////////// @@ -1958,6 +1982,7 @@ int main (int argc, char *argv[]) { GFX_clearLayers(0); } else { + GFX_clearLayers(2); if(lastScreen!=SCREEN_GAMELIST) GFX_clearLayers(3); GFX_clearLayers(4); GFX_clearLayers(5); @@ -2079,7 +2104,7 @@ int main (int argc, char *argv[]) { SDL_FreeSurface(tmpsur); } else if(show_switcher) { - GFX_clearLayers(2); + GFX_clearLayers(0); // For all recents with resumable state (i.e. has savegame), show game switcher carousel @@ -2410,14 +2435,14 @@ int main (int argc, char *argv[]) { animationdirection=0; } if(lastScreen == SCREEN_GAMELIST) { - SDL_LockMutex(folderBgMutex); - if(folderbgchanged && folderbgbmp) { - GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,1); - folderbgchanged = 0; - } else if(folderbgchanged) { - GFX_clearLayers(1); - } - SDL_UnlockMutex(folderBgMutex); + SDL_LockMutex(folderBgMutex); + if(folderbgchanged && folderbgbmp) { + GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,1); + folderbgchanged = 0; + } else if(folderbgchanged) { + GFX_clearLayers(1); + } + SDL_UnlockMutex(folderBgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { int img_w = thumbbmp->w; @@ -2446,9 +2471,10 @@ int main (int argc, char *argv[]) { GFX_clearLayers(3); } SDL_UnlockMutex(thumbMutex); + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); } - GFX_clearLayers(2); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + GFX_flip(screen); SDL_LockMutex(animMutex); frameReady = true; @@ -2524,7 +2550,7 @@ int main (int argc, char *argv[]) { GFX_clearLayers(2); GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); - + GFX_clearLayers(4); GFX_scrollTextTexture( font.large, From ab4e983770a23e64ab2bbf38f2cfd176b4adb903 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Mon, 19 May 2025 20:25:34 +0200 Subject: [PATCH 10/13] ff --- workspace/all/nextui/nextui.c | 94 ++++++++++++++++------------------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index d93c47022..9f029a757 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1359,32 +1359,6 @@ static int remember_selection = 0; /////////////////////////////////////// -SDL_Surface* loadFolderBackground(char* rompath, int type) -{ - char imagePath[MAX_PATH]; - if(type == ENTRY_DIR) - snprintf(imagePath, sizeof(imagePath), "%s/.media/bg.png", rompath); - else if(type == ENTRY_ROM) - snprintf(imagePath, sizeof(imagePath), "%s/.media/bglist.png", rompath); - - //LOG_info("Loading folder bg from %s\n", imagePath); - if(exists(imagePath)) { - SDL_Surface *image = IMG_Load(imagePath); - if(!image) - return NULL; - - SDL_Surface *image565 = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGBA8888, 0); - if(image565) { - SDL_FreeSurface(image); - image = image565; - } - - return image; - } else { - return NULL; - } -} - typedef void (*BackgroundLoadedCallback)(SDL_Surface* surface); typedef struct { @@ -1405,7 +1379,7 @@ typedef struct AnimTask { AnimTaskCallback callback; void* userData; } AnimTask; -// --- Thread pool structures --- + typedef struct TaskNode { LoadBackgroundTask* task; struct TaskNode* next; @@ -1444,6 +1418,7 @@ static int oy; #define MAX_QUEUE_SIZE 3 int currentQueueSize = 0; +int currentAnimQueueSize = 0; void enqueueTask(LoadBackgroundTask* task) { TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); @@ -1498,16 +1473,12 @@ int imageLoadWorker(void* unused) { SDL_Surface* result = NULL; if (access(task->imagePath, F_OK) == 0) { - SDL_LockMutex(imgLoadMutex); SDL_Surface* image = IMG_Load(task->imagePath); - - if (image) { SDL_Surface* imageRGBA = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGBA8888, 0); SDL_FreeSurface(image); result = imageRGBA; } - SDL_UnlockMutex(imgLoadMutex); } if (task->callback) task->callback(result); @@ -1544,8 +1515,7 @@ void onBackgroundLoaded(SDL_Surface* surface) { } SDL_Surface* safeCopy = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0); - SDL_FreeSurface(surface); // Free the original from the thread - + SDL_FreeSurface(surface); if (!safeCopy) return; if (folderbgbmp) SDL_FreeSurface(folderbgbmp); @@ -1572,9 +1542,8 @@ void onThumbLoaded(SDL_Surface* surface) { return; } - // Convert to a known pixel format (e.g., RGBA8888) to ensure compatibility SDL_Surface* safeCopy = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0); - SDL_FreeSurface(surface); // Free the thread-allocated surface + SDL_FreeSurface(surface); if (!safeCopy) return; @@ -1584,12 +1553,8 @@ void onThumbLoaded(SDL_Surface* surface) { SDL_UnlockMutex(thumbMutex); } - - SDL_Rect pillRect; - - void animcallback(SDL_Rect dst) { pillRect = dst; } @@ -1627,10 +1592,11 @@ int animWorker(void* unused) { } frameReady = false; SDL_UnlockMutex(animMutex); - - - } + SDL_LockMutex(animqueueMutex); + if (!animTaskQueueHead) animTtaskQueueTail = NULL; + currentAnimQueueSize--; // <-- add this + SDL_UnlockMutex(animqueueMutex); pillanimdone = 1; } @@ -1640,18 +1606,39 @@ void enqueueanmimtask(AnimTask* task) { AnimTaskNode* node = (AnimTaskNode*)malloc(sizeof(AnimTaskNode)); node->task = task; node->next = NULL; - pillanimdone = 0; + SDL_LockMutex(animqueueMutex); + pillanimdone = 0; + // If queue is full, drop the oldest task (head) + if (currentAnimQueueSize >= MAX_QUEUE_SIZE) { + AnimTaskNode* oldNode = animTaskQueueHead; + if (oldNode) { + animTaskQueueHead = oldNode->next; + if (!animTaskQueueHead) { + animTtaskQueueTail = NULL; + } + if (oldNode->task) { + free(oldNode->task); // Only if task was malloc'd + } + free(oldNode); + currentAnimQueueSize--; + } + } + + // Enqueue the new task if (animTtaskQueueTail) { animTtaskQueueTail->next = node; animTtaskQueueTail = node; } else { animTaskQueueHead = animTtaskQueueTail = node; } + + currentAnimQueueSize++; SDL_CondSignal(animqueueCond); SDL_UnlockMutex(animqueueMutex); } + int animPill(AnimTask *task) { task->callback = animcallback; enqueueanmimtask(task); @@ -1753,14 +1740,14 @@ int main (int argc, char *argv[]) { pthread_t cpucheckthread; pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL); - SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( - SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 - ); + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); - GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ - 0,0, 500, SCALE1(PILL_SIZE) - }); + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, 500, SCALE1(PILL_SIZE) + }); LOG_info("Start time time %ims\n",SDL_GetTicks()); while (!quit) { @@ -2393,7 +2380,14 @@ int main (int argc, char *argv[]) { SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); SDL_BlitSurface(text, &text_rect, screen, &dest_rect); is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); - + if(globalpill) SDL_FreeSurface(globalpill); + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); + + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, max_width, SCALE1(PILL_SIZE) + }); if(animationdirection == 0) { AnimTask* task = malloc(sizeof(AnimTask)); task->startX = SCALE1(BUTTON_MARGIN); From 6a15fb497898e223db3e4ecf138a7eeeceac0582 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Tue, 20 May 2025 21:52:44 +0200 Subject: [PATCH 11/13] more changes --- workspace/all/nextui/nextui.c | 112 +++++++++++++++------------------- 1 file changed, 48 insertions(+), 64 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 9f029a757..a8c0e2863 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1375,7 +1375,7 @@ typedef struct AnimTask { int targetY; int move_w; int move_h; - int duration; + int frames; AnimTaskCallback callback; void* userData; } AnimTask; @@ -1415,7 +1415,7 @@ static int ox; static int oy; // queue a new image load task :D -#define MAX_QUEUE_SIZE 3 +#define MAX_QUEUE_SIZE 2 int currentQueueSize = 0; int currentAnimQueueSize = 0; @@ -1461,7 +1461,7 @@ int imageLoadWorker(void* unused) { while (true) { SDL_LockMutex(queueMutex); while (!taskQueueHead) { - SDL_CondWait(queueCond, queueMutex); + SDL_CondWait(queueCond, queueMutex); } TaskNode* node = taskQueueHead; taskQueueHead = node->next; @@ -1499,7 +1499,7 @@ void startLoadFolderBackground(const char* imagePath, int type, BackgroundLoaded LoadBackgroundTask* task = malloc(sizeof(LoadBackgroundTask)); if (!task) return; - snprintf(task->imagePath, sizeof(task->imagePath), "%s", imagePath); + snprintf(task->imagePath, sizeof(task->imagePath), "%s", imagePath); task->callback = callback; task->userData = userData; enqueueTask(task); @@ -1514,13 +1514,8 @@ void onBackgroundLoaded(SDL_Surface* surface) { return; } - SDL_Surface* safeCopy = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0); - SDL_FreeSurface(surface); - if (!safeCopy) return; - if (folderbgbmp) SDL_FreeSurface(folderbgbmp); - folderbgbmp = safeCopy; - + folderbgbmp = surface; SDL_UnlockMutex(folderBgMutex); } @@ -1573,9 +1568,7 @@ int animWorker(void* unused) { AnimTask* task = node->task; - int fps = 60; - int frame_delay = 1000 / fps; - int total_frames = task->duration / frame_delay; + int total_frames = task->frames; for (int frame = 0; frame <= total_frames; ++frame) { float t = (float)frame / total_frames; @@ -1641,7 +1634,7 @@ void enqueueanmimtask(AnimTask* task) { int animPill(AnimTask *task) { task->callback = animcallback; - enqueueanmimtask(task); + enqueueanmimtask(task); return 0; } void initImageLoaderPool() { @@ -1741,12 +1734,12 @@ int main (int argc, char *argv[]) { pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL); SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( - SDL_SWSURFACE, 500, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + SDL_SWSURFACE, screen->w, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 ); - + static int globallpillW = 0; GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ - 0,0, 500, SCALE1(PILL_SIZE) + 0,0, screen->w, SCALE1(PILL_SIZE) }); LOG_info("Start time time %ims\n",SDL_GetTicks()); @@ -2242,7 +2235,7 @@ int main (int argc, char *argv[]) { } else { static int lastType = -1; - SDL_LockMutex(folderBgMutex); + if(((entry->type == ENTRY_DIR || entry->type == ENTRY_ROM) && CFG_getRomsUseFolderBackground())) { char *newBg = entry->type == ENTRY_DIR ? entry->path:rompath; if((strcmp(newBg, folderBgPath) != 0 || lastType != entry->type) && sizeof(folderBgPath) != 1) { @@ -2266,7 +2259,7 @@ int main (int argc, char *argv[]) { startLoadFolderBackground(SDCARD_PATH "/bg.png", entry->type, onBackgroundLoaded, NULL); } - SDL_UnlockMutex(folderBgMutex); + // load game thumbnails if (total > 0) { char thumbpath[1024]; @@ -2336,6 +2329,31 @@ int main (int argc, char *argv[]) { int max_width = MIN(available_width, text_width); SDL_Color text_color = uintToColour(THEME_COLOR4_255); + if (j == selected_row) { + text_color = uintToColour(THEME_COLOR5_255); + is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); + if(globalpill) SDL_FreeSurface(globalpill); + SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); + + GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ + 0,0, max_width, SCALE1(PILL_SIZE) + }); + globallpillW = max_width; + if(animationdirection == 0) { + AnimTask* task = malloc(sizeof(AnimTask)); + task->startX = SCALE1(BUTTON_MARGIN); + task->startY = SCALE1(previousY+PADDING); + task->targetX = SCALE1(BUTTON_MARGIN); + task->targetY = SCALE1(targetY+PADDING); + task->move_w = max_width; + task->move_h = SCALE1(PILL_SIZE); + task->frames = 3; + animPill(task); + } + + } SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; @@ -2343,6 +2361,7 @@ int main (int argc, char *argv[]) { SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); SDL_BlitSurface(text, &text_rect, screen, &dest_rect); + SDL_FreeSurface(text_unique); // Free after use SDL_FreeSurface(text); // Free after use @@ -2361,48 +2380,7 @@ int main (int argc, char *argv[]) { if(lastScreen==SCREEN_OFF) { GFX_animateSurfaceOpacity(blackBG,0,0,screen->w,screen->h,255,0,CFG_getMenuTransitions() ? 200:20,3); } - for (int i = top->start, j = 0; i < top->end; i++, j++) { - if (j == selected_row) { - Entry* entry = top->entries->items[i]; - char* entry_name = entry->name; - char* entry_unique = entry->unique; - int available_width = (had_thumb ? ox + SCALE1(BUTTON_MARGIN) : screen->w - SCALE1(BUTTON_MARGIN)) - SCALE1(PADDING * 2); - if (i == top->start && !(had_thumb)) available_width -= ow; - trimSortingMeta(&entry_name); - char display_name[256]; - int text_width = GFX_getTextWidth(font.large, entry_unique ? entry_unique : entry_name, display_name, available_width, SCALE1(BUTTON_PADDING * 2)); - int max_width = MIN(available_width, text_width); - SDL_Color text_color = uintToColour(THEME_COLOR5_255); - SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); - SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); - SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; - SDL_Rect dest_rect = { SCALE1(BUTTON_MARGIN + BUTTON_PADDING), SCALE1(PADDING + (j * PILL_SIZE)+4) }; - SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); - SDL_BlitSurface(text, &text_rect, screen, &dest_rect); - is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); - if(globalpill) SDL_FreeSurface(globalpill); - SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( - SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 - ); - - GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ - 0,0, max_width, SCALE1(PILL_SIZE) - }); - if(animationdirection == 0) { - AnimTask* task = malloc(sizeof(AnimTask)); - task->startX = SCALE1(BUTTON_MARGIN); - task->startY = SCALE1(previousY+PADDING); - task->targetX = SCALE1(BUTTON_MARGIN); - task->targetY = SCALE1(targetY+PADDING); - task->move_w = max_width; - task->move_h = SCALE1(PILL_SIZE); - task->duration = 50; - animPill(task); - - } - - } - } + remember_selection = selected_row; } else { @@ -2466,7 +2444,9 @@ int main (int argc, char *argv[]) { } SDL_UnlockMutex(thumbMutex); GFX_clearLayers(2); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + SDL_LockMutex(animqueueMutex); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); + SDL_UnlockMutex(animqueueMutex); } GFX_flip(screen); @@ -2543,7 +2523,9 @@ int main (int argc, char *argv[]) { int max_width = MIN(available_width, text_width); GFX_clearLayers(2); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + SDL_LockMutex(animqueueMutex); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); + SDL_UnlockMutex(animqueueMutex); GFX_clearLayers(4); GFX_scrollTextTexture( @@ -2560,7 +2542,9 @@ int main (int argc, char *argv[]) { } else if (!show_switcher && !show_version) { GFX_clearLayers(2); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, pillRect.w, pillRect.h, 1.0f, 0, 2); + SDL_LockMutex(animqueueMutex); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); + SDL_UnlockMutex(animqueueMutex); PLAT_GPU_Flip(); } SDL_LockMutex(animMutex); From ffea432468734a79268eb030c002c5060c3b0f25 Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Wed, 21 May 2025 17:28:08 +0200 Subject: [PATCH 12/13] OK yeah I think all is done and ready for release --- workspace/all/nextui/nextui.c | 320 ++++++++++++++++++++++------------ 1 file changed, 207 insertions(+), 113 deletions(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index a8c0e2863..a4c21a09e 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1367,7 +1367,22 @@ typedef struct { void* userData; } LoadBackgroundTask; -typedef void (*AnimTaskCallback)(SDL_Rect moveDst); +typedef struct finishedTask { + int startX; + int targetX; + int startY; + int targetY; + int move_y; + int move_w; + int move_h; + int frames; + int done; + void* userData; + char *entry_name; + SDL_Rect dst; +} finishedTask; + +typedef void (*AnimTaskCallback)(finishedTask *task); typedef struct AnimTask { int startX; int targetX; @@ -1378,6 +1393,8 @@ typedef struct AnimTask { int frames; AnimTaskCallback callback; void* userData; + char *entry_name; + SDL_Rect dst; } AnimTask; typedef struct TaskNode { @@ -1398,13 +1415,12 @@ static SDL_mutex* animqueueMutex = NULL; static SDL_cond* queueCond = NULL; static SDL_cond* animqueueCond = NULL; +static SDL_mutex* bgMutex = NULL; +static SDL_mutex* thumbMutex = NULL; static SDL_mutex* animMutex = NULL; +static SDL_mutex* frameMutex = NULL; static SDL_cond* flipCond = NULL; -static SDL_mutex* imgLoadMutex = NULL; -static SDL_mutex* folderBgMutex = NULL; -static SDL_mutex* thumbMutex = NULL; - static SDL_Surface* folderbgbmp = NULL; static SDL_Surface* thumbbmp = NULL; static SDL_Surface* screen = NULL; // Must be assigned externally @@ -1413,20 +1429,22 @@ static SDL_Surface* screen = NULL; // Must be assigned externally static int had_thumb = 0; static int ox; static int oy; +int animationDraw = 1; +int folderbgchanged=0; +int thumbchanged=0; // queue a new image load task :D -#define MAX_QUEUE_SIZE 2 +#define MAX_QUEUE_SIZE 4 int currentQueueSize = 0; int currentAnimQueueSize = 0; void enqueueTask(LoadBackgroundTask* task) { + SDL_LockMutex(queueMutex); TaskNode* node = (TaskNode*)malloc(sizeof(TaskNode)); node->task = task; node->next = NULL; - SDL_LockMutex(queueMutex); - // If queue is full, drop the oldest task (head) if (currentQueueSize >= MAX_QUEUE_SIZE) { TaskNode* oldNode = taskQueueHead; @@ -1450,13 +1468,13 @@ void enqueueTask(LoadBackgroundTask* task) { } else { taskQueueHead = taskQueueTail = node; } - + currentQueueSize++; SDL_CondSignal(queueCond); SDL_UnlockMutex(queueMutex); } -// Worker threa +// Worker threadd int imageLoadWorker(void* unused) { while (true) { SDL_LockMutex(queueMutex); @@ -1467,7 +1485,8 @@ int imageLoadWorker(void* unused) { taskQueueHead = node->next; if (!taskQueueHead) taskQueueTail = NULL; SDL_UnlockMutex(queueMutex); - + // give processor lil space in between queue items for other shit + SDL_Delay(100); LoadBackgroundTask* task = node->task; free(node); @@ -1481,7 +1500,10 @@ int imageLoadWorker(void* unused) { } } - if (task->callback) task->callback(result); + if (task->callback) { + task->callback(result); + LOG_info("thumb loaded %s\n",task->imagePath); + } free(task); SDL_LockMutex(queueMutex); if (!taskQueueHead) taskQueueTail = NULL; @@ -1491,10 +1513,6 @@ int imageLoadWorker(void* unused) { return 0; } - -int folderbgchanged=0; -int thumbchanged=0; - void startLoadFolderBackground(const char* imagePath, int type, BackgroundLoadedCallback callback, void* userData) { LoadBackgroundTask* task = malloc(sizeof(LoadBackgroundTask)); if (!task) return; @@ -1506,17 +1524,16 @@ void startLoadFolderBackground(const char* imagePath, int type, BackgroundLoaded } void onBackgroundLoaded(SDL_Surface* surface) { - SDL_LockMutex(folderBgMutex); + SDL_LockMutex(bgMutex); folderbgchanged = 1; + if (folderbgbmp) SDL_FreeSurface(folderbgbmp); if (!surface) { folderbgbmp = NULL; - SDL_UnlockMutex(folderBgMutex); + SDL_UnlockMutex(bgMutex); return; } - - if (folderbgbmp) SDL_FreeSurface(folderbgbmp); folderbgbmp = surface; - SDL_UnlockMutex(folderBgMutex); + SDL_UnlockMutex(bgMutex); } void startLoadThumb(const char* thumbpath, BackgroundLoadedCallback callback, void* userData) { @@ -1531,30 +1548,71 @@ void startLoadThumb(const char* thumbpath, BackgroundLoadedCallback callback, vo void onThumbLoaded(SDL_Surface* surface) { SDL_LockMutex(thumbMutex); thumbchanged = 1; + if (thumbbmp) SDL_FreeSurface(thumbbmp); if (!surface) { thumbbmp = NULL; SDL_UnlockMutex(thumbMutex); return; } - - SDL_Surface* safeCopy = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0); - SDL_FreeSurface(surface); - if (!safeCopy) return; - - - if (thumbbmp) SDL_FreeSurface(thumbbmp); - thumbbmp = safeCopy; - - SDL_UnlockMutex(thumbMutex); + + + thumbbmp = surface; + int img_w = thumbbmp->w; + int img_h = thumbbmp->h; + double aspect_ratio = (double)img_h / img_w; + int max_w = (int)(screen->w * CFG_getGameArtWidth()); + int max_h = (int)(screen->h * 0.6); + int new_w = max_w; + int new_h = (int)(new_w * aspect_ratio); + + if (new_h > max_h) { + new_h = max_h; + new_w = (int)(new_h / aspect_ratio); + } + GFX_ApplyRoundedCorners_RGBA8888( + thumbbmp, + &(SDL_Rect){0, 0, thumbbmp->w, thumbbmp->h}, + SCALE1((float)CFG_getThumbnailRadius() * ((float)img_w / (float)new_w)) + ); + SDL_UnlockMutex(thumbMutex); } SDL_Rect pillRect; +SDL_Surface *globalpill; +SDL_Surface *globalText; +int pilltargetY =0; +void animcallback(finishedTask *task) { + SDL_LockMutex(animMutex); + pillRect = task->dst; + pilltargetY = -1024; // move offscreen + if(task->done) { + pilltargetY = task->targetY; + SDL_Color text_color = uintToColour(THEME_COLOR5_255); + SDL_Surface *tmp = TTF_RenderUTF8_Blended(font.large, task->entry_name, text_color); + + SDL_Surface *converted = SDL_ConvertSurfaceFormat(tmp, SDL_PIXELFORMAT_RGBA8888, 0); + SDL_FreeSurface(tmp); // tmp no longer needed + + SDL_Rect crop_rect = { 0, 0, task->move_w - SCALE1(BUTTON_PADDING * 2), converted->h }; + SDL_Surface *cropped = SDL_CreateRGBSurfaceWithFormat( + 0, crop_rect.w, crop_rect.h, 32, SDL_PIXELFORMAT_RGBA8888 + ); + if (!cropped) { + SDL_FreeSurface(converted); + } -void animcallback(SDL_Rect dst) { - pillRect = dst; + SDL_SetSurfaceBlendMode(converted, SDL_BLENDMODE_NONE); + SDL_BlitSurface(converted, &crop_rect, cropped, NULL); + SDL_FreeSurface(converted); + + globalText = cropped; + } + SDL_UnlockMutex(animMutex); + animationDraw = 1; } -bool frameReady = false; +bool frameReady = true; int pillanimdone = 0; + int animWorker(void* unused) { while (true) { SDL_LockMutex(animqueueMutex); @@ -1567,10 +1625,14 @@ int animWorker(void* unused) { SDL_UnlockMutex(animqueueMutex); AnimTask* task = node->task; - + finishedTask* finaltask = (finishedTask*)malloc(sizeof(finishedTask)); int total_frames = task->frames; + if(task->targetY > task->startY + SCALE1(PILL_SIZE) || task->targetY < task->startY - SCALE1(PILL_SIZE)) { + total_frames = 0; + } + - for (int frame = 0; frame <= total_frames; ++frame) { + for (int frame = 0; frame <= total_frames; frame++) { float t = (float)frame / total_frames; if (t > 1.0f) t = 1.0f; @@ -1578,19 +1640,32 @@ int animWorker(void* unused) { int current_y = task->startY + (int)(( task->targetY - task->startY) * t); SDL_Rect moveDst = { current_x, current_y, task->move_w, task->move_h }; - task->callback(moveDst); - SDL_LockMutex(animMutex); + finaltask->dst = moveDst; + finaltask->entry_name = task->entry_name; + finaltask->move_w = task->move_w; + finaltask->move_h = task->move_h; + finaltask->targetY = task->targetY; + finaltask->move_y = task->targetY+8; + finaltask->done = 0; + if(frame >= total_frames) finaltask->done=1; + task->callback(finaltask); + SDL_LockMutex(frameMutex); while (!frameReady) { - SDL_CondWait(flipCond, animMutex); + SDL_CondWait(flipCond, frameMutex); } frameReady = false; - SDL_UnlockMutex(animMutex); + SDL_UnlockMutex(frameMutex); + } SDL_LockMutex(animqueueMutex); if (!animTaskQueueHead) animTtaskQueueTail = NULL; currentAnimQueueSize--; // <-- add this SDL_UnlockMutex(animqueueMutex); + + SDL_LockMutex(animMutex); pillanimdone = 1; + free(finaltask); + SDL_UnlockMutex(animMutex); } } @@ -1603,7 +1678,7 @@ void enqueueanmimtask(AnimTask* task) { SDL_LockMutex(animqueueMutex); pillanimdone = 0; // If queue is full, drop the oldest task (head) - if (currentAnimQueueSize >= MAX_QUEUE_SIZE) { + if (currentAnimQueueSize >= 1) { AnimTaskNode* oldNode = animTaskQueueHead; if (oldNode) { animTaskQueueHead = oldNode->next; @@ -1640,9 +1715,13 @@ int animPill(AnimTask *task) { void initImageLoaderPool() { queueMutex = SDL_CreateMutex(); queueCond = SDL_CreateCond(); - imgLoadMutex = SDL_CreateMutex(); - folderBgMutex = SDL_CreateMutex(); - thumbMutex = SDL_CreateMutex(); + bgMutex = SDL_CreateMutex(); + thumbMutex = SDL_CreateMutex(); + animMutex = SDL_CreateMutex(); + animqueueMutex = SDL_CreateMutex(); + animqueueCond = SDL_CreateCond(); + frameMutex = SDL_CreateMutex(); + flipCond = SDL_CreateCond(); SDL_CreateThread(imageLoadWorker, "ImageLoadWorker", NULL); SDL_CreateThread(animWorker, "animWorker", NULL); @@ -1732,15 +1811,16 @@ int main (int argc, char *argv[]) { pthread_t cpucheckthread; pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL); - - SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_LockMutex(animMutex); + globalpill = SDL_CreateRGBSurfaceWithFormat( + SDL_SWSURFACE, screen->w, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 + ); + globalText = SDL_CreateRGBSurfaceWithFormat( SDL_SWSURFACE, screen->w, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 ); - static int globallpillW = 0; + static int globallpillW = 0; + SDL_UnlockMutex(animMutex); - GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ - 0,0, screen->w, SCALE1(PILL_SIZE) - }); LOG_info("Start time time %ims\n",SDL_GetTicks()); while (!quit) { @@ -2069,17 +2149,17 @@ int main (int argc, char *argv[]) { GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 0, screen, 1); } else if(startgame) { - + pilltargetY = -1024; animationdirection=0; SDL_Surface *tmpsur = GFX_captureRendererToSurface(); GFX_clearLayers(0); GFX_clear(screen); GFX_flipHidden(); + if(lastScreen==SCREEN_GAMESWITCHER) { GFX_animateSurfaceOpacityAndScale(tmpsur,screen->w/2,screen->h/2,screen->w,screen->h,screen->w*4,screen->h*4,255,0,CFG_getMenuTransitions() ? 150:20,1); } else { GFX_animateSurfaceOpacity(tmpsur,0,0,screen->w,screen->h,255,0,CFG_getMenuTransitions() ? 150:20,1); - GFX_clear(screen); } SDL_FreeSurface(tmpsur); } @@ -2266,7 +2346,7 @@ int main (int argc, char *argv[]) { if(CFG_getShowGameArt()) { snprintf(thumbpath, sizeof(thumbpath), "%s/.media/%s.png", rompath, res_copy); had_thumb = 0; - SDL_LockMutex(thumbMutex); + startLoadThumb(thumbpath, onThumbLoaded, NULL); int max_w = (int)(screen->w - (screen->w * CFG_getGameArtWidth())); @@ -2280,7 +2360,7 @@ int main (int argc, char *argv[]) { ox = screen->w; - SDL_UnlockMutex(thumbMutex); + } } @@ -2329,41 +2409,50 @@ int main (int argc, char *argv[]) { int max_width = MIN(available_width, text_width); SDL_Color text_color = uintToColour(THEME_COLOR4_255); - if (j == selected_row) { + int notext = 0; + if(selected_row == remember_selection && j == selected_row && (selected_row+1 >= (top->end-top->start) || selected_row == 0)) { text_color = uintToColour(THEME_COLOR5_255); + notext=1; + } + SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); + SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); + if (j == selected_row) { + is_scrolling = GFX_resetScrollText(font.large,display_name, max_width - SCALE1(BUTTON_PADDING*2)); + SDL_LockMutex(animMutex); if(globalpill) SDL_FreeSurface(globalpill); - SDL_Surface *globalpill = SDL_CreateRGBSurfaceWithFormat( + globalpill = SDL_CreateRGBSurfaceWithFormat( SDL_SWSURFACE, max_width, SCALE1(PILL_SIZE), FIXED_DEPTH, SDL_PIXELFORMAT_RGBA8888 ); - GFX_blitPillDark(ASSET_WHITE_PILL, globalpill, &(SDL_Rect){ 0,0, max_width, SCALE1(PILL_SIZE) }); globallpillW = max_width; - if(animationdirection == 0) { - AnimTask* task = malloc(sizeof(AnimTask)); - task->startX = SCALE1(BUTTON_MARGIN); - task->startY = SCALE1(previousY+PADDING); - task->targetX = SCALE1(BUTTON_MARGIN); - task->targetY = SCALE1(targetY+PADDING); - task->move_w = max_width; - task->move_h = SCALE1(PILL_SIZE); - task->frames = 3; - animPill(task); - } + SDL_UnlockMutex(animMutex); + AnimTask* task = malloc(sizeof(AnimTask)); + task->startX = SCALE1(BUTTON_MARGIN); + task->startY = SCALE1(previousY+PADDING); + task->targetX = SCALE1(BUTTON_MARGIN); + task->targetY = SCALE1(targetY+PADDING); + task->move_w = max_width; + task->move_h = SCALE1(PILL_SIZE); + task->frames = CFG_getMenuAnimations() ? 3:0; + task->entry_name = notext ? " ":entry_name; + animPill(task); + } - SDL_Surface* text = TTF_RenderUTF8_Blended(font.large, entry_name, text_color); - SDL_Surface* text_unique = TTF_RenderUTF8_Blended(font.large, display_name, COLOR_DARK_TEXT); SDL_Rect text_rect = { 0, 0, max_width - SCALE1(BUTTON_PADDING*2), text->h }; SDL_Rect dest_rect = { SCALE1(BUTTON_MARGIN + BUTTON_PADDING), SCALE1(PADDING + (j * PILL_SIZE)+4) }; + SDL_BlitSurface(text_unique, &text_rect, screen, &dest_rect); SDL_BlitSurface(text, &text_rect, screen, &dest_rect); - + SDL_FreeSurface(text_unique); // Free after use SDL_FreeSurface(text); // Free after use + + } if(lastScreen==SCREEN_GAMESWITCHER) { @@ -2407,14 +2496,15 @@ int main (int argc, char *argv[]) { animationdirection=0; } if(lastScreen == SCREEN_GAMELIST) { - SDL_LockMutex(folderBgMutex); + SDL_LockMutex(bgMutex); if(folderbgchanged && folderbgbmp) { GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,1); - folderbgchanged = 0; + } else if(folderbgchanged) { GFX_clearLayers(1); } - SDL_UnlockMutex(folderBgMutex); + folderbgchanged = 0; + SDL_UnlockMutex(bgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { int img_w = thumbbmp->w; @@ -2429,11 +2519,7 @@ int main (int argc, char *argv[]) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); } - GFX_ApplyRoundedCorners_RGBA8888( - thumbbmp, - &(SDL_Rect){0, 0, thumbbmp->w, thumbbmp->h}, - SCALE1((float)CFG_getThumbnailRadius() * ((float)img_w / (float)new_w)) - ); + int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h @@ -2443,34 +2529,37 @@ int main (int argc, char *argv[]) { GFX_clearLayers(3); } SDL_UnlockMutex(thumbMutex); + GFX_clearLayers(2); - SDL_LockMutex(animqueueMutex); + GFX_clearLayers(4); + + SDL_LockMutex(animMutex); GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); - SDL_UnlockMutex(animqueueMutex); + GFX_drawOnLayer(globalText, SCALE1(PADDING+BUTTON_PADDING), pilltargetY+SCALE1(PADDING)-3, globalText->w, globalText->h, 1.0f, 0, 4); + SDL_UnlockMutex(animMutex); } - - GFX_flip(screen); - SDL_LockMutex(animMutex); - frameReady = true; - SDL_CondSignal(flipCond); - SDL_UnlockMutex(animMutex); + if(!startgame) // dont flip if game gonna start + GFX_flip(screen); + + dirty = 0; readytoscroll = 0; - } else { + } else if(animationDraw || folderbgchanged || thumbchanged || is_scrolling) { // honestly this whole thing is here only for the scrolling text, I set it now to run this at 30fps which is enough for scrolling text, should move this to seperate animation function eventually Uint32 now = SDL_GetTicks(); Uint32 frame_start = now; static char cached_display_name[256] = ""; - SDL_LockMutex(folderBgMutex); + SDL_LockMutex(bgMutex); if(folderbgchanged && folderbgbmp) { GFX_drawOnLayer(folderbgbmp,0, 0, screen->w, screen->h,1.0f,0,1); - folderbgchanged = 0; + } else if(folderbgchanged) { GFX_clearLayers(1); } - SDL_UnlockMutex(folderBgMutex); + folderbgchanged = 0; + SDL_UnlockMutex(bgMutex); SDL_LockMutex(thumbMutex); if(thumbbmp && thumbchanged) { int img_w = thumbbmp->w; @@ -2487,23 +2576,25 @@ int main (int argc, char *argv[]) { new_h = max_h; new_w = (int)(new_h / aspect_ratio); } - GFX_ApplyRoundedCorners_RGBA8888( - thumbbmp, - &(SDL_Rect){0, 0, thumbbmp->w, thumbbmp->h}, - SCALE1((float)CFG_getThumbnailRadius() * ((float)img_w / (float)new_w)) - ); + int target_x = screen->w-(new_w + SCALE1(BUTTON_MARGIN*3)); int target_y = (int)(screen->h * 0.50); int center_y = target_y - (new_h / 2); // FIX: use new_h instead of thumbbmp->h GFX_clearLayers(3); GFX_drawOnLayer(thumbbmp,target_x,center_y,new_w,new_h,1.0f,0,3); thumbchanged = 0; - } else if(thumbchanged) { - GFX_clearLayers(3); + } else if(thumbchanged) { + GFX_clearLayers(3); } SDL_UnlockMutex(thumbMutex); - - if (!show_switcher && !show_version && is_scrolling && pillanimdone) { + SDL_LockMutex(animMutex); + if(animationDraw) { + GFX_clearLayers(2); + GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); + animationDraw = 0; + } + SDL_UnlockMutex(animMutex); + if (!show_switcher && !show_version && is_scrolling && pillanimdone && currentAnimQueueSize < 1) { int ow = GFX_blitHardwareGroup(screen, show_setting); Entry* entry = top->entries->items[top->selected]; @@ -2522,10 +2613,8 @@ int main (int argc, char *argv[]) { int text_width = GFX_getTextWidth(font.large, entry_text, cached_display_name, available_width, SCALE1(BUTTON_PADDING * 2)); int max_width = MIN(available_width, text_width); - GFX_clearLayers(2); - SDL_LockMutex(animqueueMutex); - GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); - SDL_UnlockMutex(animqueueMutex); + + GFX_clearLayers(4); GFX_scrollTextTexture( @@ -2538,24 +2627,29 @@ int main (int argc, char *argv[]) { text_color, 1 ); - } else if (!show_switcher && !show_version) { GFX_clearLayers(2); - SDL_LockMutex(animqueueMutex); + GFX_clearLayers(4); + SDL_LockMutex(animMutex); GFX_drawOnLayer(globalpill, pillRect.x, pillRect.y, globallpillW, globalpill->h, 1.0f, 0, 2); - SDL_UnlockMutex(animqueueMutex); - PLAT_GPU_Flip(); + GFX_drawOnLayer(globalText, SCALE1(PADDING+BUTTON_PADDING), pilltargetY+SCALE1(PADDING)-3, globalText->w, globalText->h, 1.0f, 0, 4); + SDL_UnlockMutex(animMutex); + PLAT_GPU_Flip(); } - SDL_LockMutex(animMutex); - frameReady = true; - SDL_CondSignal(flipCond); - SDL_UnlockMutex(animMutex); dirty = 0; + } + else { + PLAT_GPU_Flip(); - } + + SDL_LockMutex(frameMutex); + frameReady = true; + SDL_CondSignal(flipCond); + SDL_UnlockMutex(frameMutex); + // handle HDMI change static int had_hdmi = -1; int has_hdmi = GetHDMI(); From 8efb1499816b6797bc5c91059717e3b491a3acdb Mon Sep 17 00:00:00 2001 From: ro8inmorgan Date: Wed, 21 May 2025 17:34:00 +0200 Subject: [PATCH 13/13] removed log info --- workspace/all/nextui/nextui.c | 1 - 1 file changed, 1 deletion(-) diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index a4c21a09e..acb271c96 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -1502,7 +1502,6 @@ int imageLoadWorker(void* unused) { if (task->callback) { task->callback(result); - LOG_info("thumb loaded %s\n",task->imagePath); } free(task); SDL_LockMutex(queueMutex);