From 52052ec92140b18dbcd5460bff31d68a74a67c77 Mon Sep 17 00:00:00 2001 From: a Date: Mon, 30 Jun 2025 23:11:58 -0400 Subject: [PATCH] crash screen improvements --- src/game/game_init.c | 10 +-- src/init/crash_screen.c | 78 ++++++++++++++++-- src/init/main.c | 3 - .../crash_screen/crash_screen_font.ia1.png | Bin 739 -> 631 bytes 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/game/game_init.c b/src/game/game_init.c index da803633..529d5bb6 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -360,6 +360,9 @@ void select_gfx_pool(void) { * - Yields to the VI framerate twice, locking the game at 30 FPS. * - Selects which framebuffer will be rendered and displayed to next time. */ + +void crash_screen_set_framebuffer(u16 *framebuffer, u16 width, u16 height); + void display_and_vsync(void) { profiler_log_thread5_time(BEFORE_DISPLAY_LISTS); osRecvMesg(&gGfxVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); @@ -371,6 +374,7 @@ void display_and_vsync(void) { profiler_log_thread5_time(AFTER_DISPLAY_LISTS); osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFramebuffers[sRenderedFramebuffer])); + crash_screen_set_framebuffer((u16 *) gFramebuffers[sRenderedFramebuffer], SCREEN_WIDTH, SCREEN_HEIGHT); profiler_log_thread5_time(THREAD5_END); osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); if (++sRenderedFramebuffer == 3) { @@ -637,8 +641,6 @@ void setup_game_memory(void) { load_segment_decompress(2, _segment2_mio0SegmentRomStart, _segment2_mio0SegmentRomEnd); } -extern u32 bootTime; - /** * Main game loop thread. Runs forever as long as the game continues. */ @@ -687,16 +689,12 @@ void thread5_game_loop(UNUSED void *arg) { #endif osContStartReadData(&gSIEventMesgQueue); } - audio_game_loop_tick(); select_gfx_pool(); read_controller_inputs(); addr = level_script_execute(addr); display_and_vsync(); - char buff[64]; - //sprintf(buff, "BOOT TIME: %u", bootTime); - //print_text(64, 64, buff); // when debug info is enabled, print the "BUF %d" information. if (gShowDebugText) { // subtract the end of the gfx pool with the display list to obtain the diff --git a/src/init/crash_screen.c b/src/init/crash_screen.c index 86766dc9..e5540563 100644 --- a/src/init/crash_screen.c +++ b/src/init/crash_screen.c @@ -8,6 +8,12 @@ #include "lib/hackerlibultra/src/libc/xstdio.h" #include "n64-stdio.h" +#include "audio/external.h" +#include "sounds.h" +#include "seq_ids.h" + +extern u32 gGlobalTimer; + u8 gCrashScreenCharToGlyph[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, 43, -1, -1, 37, 38, -1, 42, @@ -60,6 +66,32 @@ struct { u16 height; } gCrashScreen; +void crash_screen_draw_bg() { + u16 *ptr; + s32 i, j; + + ptr = gCrashScreen.framebuffer + gCrashScreen.width; + for (i = 0; i < SCREEN_HEIGHT; i++) { + for (j = 0; j < SCREEN_WIDTH; j++) { + u16 pixel = *ptr; + + // Extract RGB (5 bits each) + u8 r = (pixel >> 11) & 0x1F; + u8 g = (pixel >> 6) & 0x1F; + u8 b = (pixel >> 1) & 0x1F; + u8 a = pixel & 0x01; + + // Tint: add a bit of blue while reducing red/green slightly + r = (r * 3) / 4; + g = (g * 3) / 4; + b = b + ((255 - b) / 4); // Move toward max blue + + *ptr++ = GPACK_RGBA5551(r, g, b, a); + } + ptr += gCrashScreen.width - SCREEN_WIDTH; + } +} + void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) { u16 *ptr; s32 i, j; @@ -67,8 +99,7 @@ void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) { ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { - // 0xe738 = 0b1110011100111000 - *ptr = ((*ptr & 0xe738) >> 2) | 1; + *ptr = GPACK_RGBA5551(0, 0, 0, 1); ptr++; } ptr += gCrashScreen.width - w; @@ -189,11 +220,28 @@ void draw_crash_screen(OSThread *thread) { } osWritebackDCacheAll(); - n64_printf("Size of crash font: %u", sizeof(gCrashScreenFont)); + + // disable reading AA coverage to prevent text being illegible + +#if defined(VERSION_US) || defined(VERSION_SH) || defined(VERSION_CN) + if (osTvType == OS_TV_NTSC) { + osViSetMode(&osViModeTable[OS_VI_NTSC_LPN1]); + } else { + osViSetMode(&osViModeTable[OS_VI_PAL_LPN1]); + } +#elif defined(VERSION_JP) + osViSetMode(&osViModeTable[OS_VI_NTSC_LPN1]); +#else // VERSION_EU + osViSetMode(&osViModeTable[OS_VI_PAL_LPN1]); +#endif + + osViSetSpecialFeatures(OS_VI_GAMMA_OFF); // automatically re-enabled from vi mode change + + crash_screen_draw_rect(25, 20, 270, 25); crash_screen_print(30, 25, "THREAD:%d (%s)", thread->id, gCauseDesc[cause]); crash_screen_print(30, 35, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr); - n64_printf("===================== CRASH ======================\n"); + n64_printf("=================== CRASH ===================\n"); n64_printf("THREAD: %d (%s)\n", thread->id, gCauseDesc[cause]); n64_printf("PC: %08XH SR: %08XH VA: %08XH\n\n", tc->pc, tc->sr, tc->badvaddr); crash_screen_sleep(2000); @@ -218,6 +266,9 @@ void draw_crash_screen(OSThread *thread) { (u32) tc->sp); crash_screen_print(30, 140, "S8:%08XH RA:%08XH", (u32) tc->s8, (u32) tc->ra); + // unfortunately, i could not get the crash screen print func + // to pass on the arguments to n64_printf without crashing the crash screen... + n64_printf("AT: %08XH V0: %08XH V1: %08XH\n", (u32) tc->at, (u32) tc->v0, (u32) tc->v1); n64_printf("A0: %08XH A1: %08XH A2: %08XH\n", (u32) tc->a0, (u32) tc->a1, (u32) tc->a2); n64_printf("A3: %08XH T0: %08XH T1: %08XH\n", (u32) tc->a3, (u32) tc->t0, (u32) tc->t1); @@ -252,7 +303,7 @@ void draw_crash_screen(OSThread *thread) { n64_printf("\n"); crash_screen_print_float_reg(30, 220, 30, &tc->fp30.f.f_even); n64_printf("\n"); - n64_printf("==================================================\n"); + n64_printf("==============================================\n"); osViBlack(FALSE); osViSwapBuffer(gCrashScreen.framebuffer); } @@ -281,7 +332,23 @@ void thread2_crash_screen(UNUSED void *arg) { osRecvMesg(&gCrashScreen.mesgQueue, &mesg, 1); thread = get_crashed_thread(); } while (thread == NULL); + + crash_screen_draw_bg(); + osWritebackDCacheAll(); draw_crash_screen(thread); + + if (thread->id == 5) { + gCrashScreen.thread.priority = 15; + stop_sounds_in_continuous_banks(); + stop_background_music(get_current_background_music()); + audio_signal_game_loop_tick(); + crash_screen_sleep(200); + play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource); + audio_signal_game_loop_tick(); + play_music(SEQ_PLAYER_LEVEL, SEQ_LEVEL_WATER, 0); + crash_screen_sleep(200); + } + for (;;) { } } @@ -293,7 +360,6 @@ void crash_screen_set_framebuffer(u16 *framebuffer, u16 width, u16 height) { } void crash_screen_init(void) { - gCrashScreen.framebuffer = (u16 *) (osMemSize | 0xA0000000) - SCREEN_WIDTH * SCREEN_HEIGHT; gCrashScreen.width = SCREEN_WIDTH; gCrashScreen.height = 0x10; osCreateMesgQueue(&gCrashScreen.mesgQueue, &gCrashScreen.mesg, 1); diff --git a/src/init/main.c b/src/init/main.c index 01ea8cf6..d495f963 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -41,8 +41,6 @@ OSMesg gSIEventMesgBuf[1]; OSMesg gIntrMesgBuf[16]; OSMesg gUnknownMesgBuf[16]; -//u32 bootTime = 0; - struct VblankHandler *gVblankHandler1 = NULL; struct VblankHandler *gVblankHandler2 = NULL; struct SPTask *gActiveSPTask = NULL; @@ -339,7 +337,6 @@ void thread3_main(UNUSED void *arg) { #ifndef LIBDRAGON_IPL3 load_engine_code_segment(); #endif - //bootTime = osGetCount(); crash_screen_init(); diff --git a/textures/crash_screen/crash_screen_font.ia1.png b/textures/crash_screen/crash_screen_font.ia1.png index 3a9a899e721f22af060ffbc5e9f3cd64fbb2f950..f978828b4ee4e29eadb4eafcf582e1b2a19595a3 100644 GIT binary patch delta 607 zcmaFN`kiHhayYQVtoDuIE)Y6b&?c)^@qfi?^b3`|Mh?k)`f+xyS#XJBC9Ebxdd zW?V&wW* z)yPPjIje&=9SN0oy4Y|pduHM^hk462(rS->cX`B-yY!G9%g1#KWk0L>EL|7&gx#gz zz}QVjSNQ6tSIJ-NEq3Zos1{9&lC|M6d+u7Sw`Q5*=4+}NEe)6MiYmWab1u5~vTx#n zi%VWHzARx0oW~rtJbHP_)z+2C^Gub}p8a5rZEUSmc(=BLwc7jTuk(R7y@VDQvGJhsw+y8w@GvjV~W52r{-EQ{l^2+;-3J<+{8OoOCeyILKq}TSOuFYrW zHQtigEE3i|Iiy;|_>$k!$x}Z?`#g^m$liMApQZioUh@|}Ij`PMd?ajXU$WnZzw|)( zN|}-+I<cuKTBW*MwzmefIMyPySlmE}#BW(AOh=!-n>c#m}qJ<^7fb7R_5Hn4qv#;E`FTuSbL=L@ZDba z%p6gke+Qj{R+%3zej2^3PZ!6Kin!#IgdhLsGjd2sN*;Ldzn+C#v2R^lBjYlzRkCSk{{I(P z%A@gUMUsM?PfKHCCnM{Dv#vK9o>)x?YT;Itij?@kFu_(pIdE^o8rFWs6J-Z`5>s3% z#9l?^)U{cNCi3r+a^YZP7B&?V@N;DmR(A7g{BpploAYuBTRjtlU@*^*IbAshdS)K> z+*M9YoK17uI|BajCAD}qACgHER_@X`H1|Z{sRIpZtVO?+RMTb%EIjKV;t+nmLt9Fb zPkqkD847idUuBtX>J+~Hbw9N}Vv+2_>OX<)ITDAq`%Dlyf1*QMMe1LfD>w0* zW5$^cjl0<`zZAMESFLk>W}L{KnN+Ogq0gPRmqEy_qCJ2u(eeDWo`_=hLlR$hBqS{m zSm2_ZbwzPD4_Dk37k+N_9gGu%IIBM_bkkfld12gvX{QvnE&466L}*HVQDWdZmd@ZD zvu2x?dA|&pdpLJaIv_i5$7X8_V?jM`hl#zhqQWXS9~d#+^u56>A;oR*{}9iixic;< zo+TK1y1t^*#Y1LZQ{hvGq+&HsPs!QGH-xR5u)w*3y<8~WK{qHdlYge$c|o3xDuX=@ zbN(fmJ?>2j@$`7j{EVq3_y2$8`t9BUUnWR#pLpdc77(*QAeBKyXG6G71+T*oQNb+| zZ3};K3f35ixyV^Y1TLPZp}$~So5WJKbsA2kyhTh-eQsNJ3EnNKIjT7;DrY5cBu{>p z3!hkvQ;F`4-h{>!hU9qO W@-(e?HyIch7(8A5T-G@yGywo4N+P)c