Skip to content

Commit f2b6f57

Browse files
committed
Menu/Screensaver: Add Matrix Digital Rain effect
This adds a new "Matrix Digital Rain" animation to the menu screensaver options. * Implements a dedicated rendering logic using 230 active particles to ensure memory safety and isolate it from other effects. * Maps 17 custom character symbols exclusively to the Unicode Private Use Area (PUA) to prevent interference with stock ASCII font buffers. * Features downward moving particles with randomized speeds, glitching character swaps, and smoothly fading trails in pure green. This Pull Requests is from Lakka (libretro/Lakka-LibreELEC#2230) This Pull Requests needs retroarch_assets pkg/osd-font.ttf update.
1 parent e32ae26 commit f2b6f57

5 files changed

Lines changed: 139 additions & 1 deletion

File tree

intl/msg_hash_us.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6297,6 +6297,10 @@ MSG_HASH(
62976297
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_VORTEX,
62986298
"Vortex"
62996299
)
6300+
MSG_HASH(
6301+
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_MATRIX,
6302+
"Matrix Digital Rain"
6303+
)
63006304
MSG_HASH(
63016305
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_SPEED,
63026306
"Menu Screensaver Animation Speed"

menu/menu_defines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ enum menu_screensaver_effect
571571
MENU_SCREENSAVER_SNOW,
572572
MENU_SCREENSAVER_STARFIELD,
573573
MENU_SCREENSAVER_VORTEX,
574+
MENU_SCREENSAVER_MATRIX,
574575
MENU_SCREENSAVER_LAST
575576
};
576577

menu/menu_screensaver.c

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
* > lum must not exceed 1.0f */
7474
#define MENU_SS_PARTICLE_COLOR(tint_r, tint_g, tint_b, lum) (((uint32_t)(tint_r * lum) << 24) | ((uint32_t)(tint_g * lum) << 16) | ((uint32_t)(tint_b * lum) << 8) | 0xFF)
7575

76+
/* Specifies the precise number of active rendering particles for the Matrix effect.
77+
* Kept under the system cap of 256 to ensure complete memory safety and isolate
78+
* this high-density effect from other default screen savers like Snow. */
79+
#define MENU_SS_MATRIX_DENSE_COUNT 230
80+
7681
/* Definition of screensaver 'particle':
7782
* - symbol: string representation of a font glyph
7883
* - x: centre x-coordinate of draw position
@@ -160,6 +165,29 @@ static const char * const menu_ss_vortex_symbols[] = {
160165
"\xE2\x97\x86" /* Black Diamond, U+25C6 */
161166
};
162167

168+
/* Matrix character symbols mapped exclusively to Unicode Private Use Area (PUA)
169+
* U+E000 to U+E00F. This ensures 100% isolation from stock ASCII character font buffers. */
170+
#define MENU_SS_NUM_MATRIX_SYMBOLS 17
171+
static const char * const menu_ss_matrix_symbols[] = {
172+
"\xEE\x80\x80", /* PUA 0x00 (Custom glyph for '0') */
173+
"\xEE\x80\x81", /* PUA 0x01 (Custom glyph for '1') */
174+
"\xEE\x80\x82", /* PUA 0x02 (Custom glyph for '2') */
175+
"\xEE\x80\x83", /* PUA 0x03 (Custom glyph for '3') */
176+
"\xEE\x80\x84", /* PUA 0x04 (Custom glyph for '4') */
177+
"\xEE\x80\x85", /* PUA 0x05 (Custom glyph for '5') */
178+
"\xEE\x80\x86", /* PUA 0x06 (Custom glyph for '6') */
179+
"\xEE\x80\x87", /* PUA 0x07 (Custom glyph for '7') */
180+
"\xEE\x80\x88", /* PUA 0x08 (Custom glyph for '8') */
181+
"\xEE\x80\x89", /* PUA 0x09 (Custom glyph for '9') */
182+
"\xEE\x80\x8A", /* PUA 0x0A (Custom glyph for 'ウ') */
183+
"\xEE\x80\x8B", /* PUA 0x0B (Custom glyph for 'カ') */
184+
"\xEE\x80\x8C", /* PUA 0x0C (Custom glyph for 'メ') */
185+
"\xEE\x80\x8D", /* PUA 0x0D (Custom glyph for 'モ') */
186+
"\xEE\x80\x8E", /* PUA 0x0E (Custom glyph for 'ワ') */
187+
"\xEE\x80\x8F", /* PUA 0x0F (Custom glyph for 'レ') */
188+
"\xEE\x80\x90" /* PUA 0x10 (Custom glyph for '*') */
189+
};
190+
163191
/***********************/
164192
/* Pseudo-random numbers */
165193
/***********************/
@@ -195,6 +223,16 @@ static INLINE uint32_t menu_ss_rand(void)
195223
return x;
196224
}
197225

226+
/* Forward declarations for Matrix screen saver functions to avoid implicit declaration errors */
227+
static void menu_screensaver_init_matrix(
228+
menu_screensaver_t *screensaver,
229+
unsigned width, unsigned height);
230+
231+
static void menu_screensaver_animate_matrix(
232+
menu_screensaver_t *screensaver,
233+
float base_particle_size, float global_speed_factor,
234+
unsigned width, unsigned height);
235+
198236
/******************/
199237
/* Initialisation */
200238
/******************/
@@ -432,6 +470,9 @@ static bool menu_screensaver_init_effect(menu_screensaver_t *screensaver)
432470
}
433471
}
434472
break;
473+
case MENU_SCREENSAVER_MATRIX:
474+
menu_screensaver_init_matrix(screensaver, width, height);
475+
break;
435476
default:
436477
/* Error condition - do nothing */
437478
return false;
@@ -773,12 +814,94 @@ void menu_screensaver_iterate(
773814
(int (*)(const void *, const void *))menu_ss_vortex_qsort_func);
774815
}
775816
break;
817+
case MENU_SCREENSAVER_MATRIX:
818+
menu_screensaver_animate_matrix(screensaver, base_particle_size, global_speed_factor, width, height);
819+
break;
776820
default:
777821
/* Error condition - do nothing */
778822
break;
779823
}
780824
}
781825

826+
/* --- Matrix Digital Rain Screen Saver --- */
827+
828+
/* Logic for updating and rendering the matrix rain effect */
829+
static void menu_screensaver_animate_matrix(
830+
menu_screensaver_t *screensaver,
831+
float base_particle_size, float global_speed_factor,
832+
unsigned width, unsigned height)
833+
{
834+
size_t i;
835+
836+
for (i = 0; i < MENU_SS_MATRIX_DENSE_COUNT; i++)
837+
{
838+
menu_ss_particle_t *particle = &screensaver->particles[i];
839+
float particle_size_px = particle->size * base_particle_size;
840+
841+
/* 1. Move downwards based on randomized particle speed (stored in 'a') */
842+
particle->y += global_speed_factor * particle->size * particle->a;
843+
844+
/* 2. Periodically change characters to mimic glitchy matrix rain (stored in 'b') */
845+
particle->b += global_speed_factor;
846+
if (particle->b > 9.5f)
847+
{
848+
particle->b = 0.0f;
849+
particle->symbol = menu_ss_matrix_symbols[(unsigned)(rand() % MENU_SS_NUM_MATRIX_SYMBOLS)];
850+
}
851+
852+
/* 3. Smoothly fade out the trails over time to create the iconic matrix fade effect */
853+
particle->c -= 0.00395f * global_speed_factor;
854+
if (particle->c < 0.05f)
855+
particle->c = 0.05f;
856+
857+
/* 4. Determine brightness/luminosity (stored in 'c' combined with scale size) */
858+
float luminosity = particle->c * (0.4f + (particle->size / 3.0f));
859+
if (luminosity > 1.0f)
860+
luminosity = 1.0f;
861+
862+
/* Pure Matrix green (No Red, Full Green, No Blue) */
863+
particle->color = MENU_SS_PARTICLE_COLOR(0, 255, 0, luminosity);
864+
865+
/* 5. Reset particle if it falls off the bottom screen boundary */
866+
if (particle->y > (float)height + particle_size_px)
867+
{
868+
particle->x = (float)(rand() % width);
869+
particle->y = -particle_size_px - (float)(rand() % 100);
870+
particle->a = 0.6f + ((float)(rand() % 20) * 0.1f); /* downward velocity */
871+
particle->b = 0.0f; /* glitch timer */
872+
particle->c = 1.0f; /* reset tail fade opacity to full */
873+
particle->size = 2.0f + ((float)(rand() % 150) / 100.0f); /* randomized font size scale */
874+
particle->symbol = menu_ss_matrix_symbols[(unsigned)(rand() % MENU_SS_NUM_MATRIX_SYMBOLS)];
875+
}
876+
}
877+
}
878+
879+
/* Initialization logic for the matrix rain effect */
880+
static void menu_screensaver_init_matrix(
881+
menu_screensaver_t *screensaver,
882+
unsigned width, unsigned height)
883+
{
884+
size_t i;
885+
float screen_size = (float)((width < height) ? width : height);
886+
float font_size = ((screen_size * MENU_SS_FONT_SIZE_FACTOR) + 0.5f) * 0.5f;
887+
float particle_scale = (screen_size * MENU_SS_PARTICLE_SIZE_FACTOR) / font_size;
888+
float base_particle_size = particle_scale * font_size;
889+
890+
for (i = 0; i < MENU_SS_MATRIX_DENSE_COUNT; i++)
891+
{
892+
menu_ss_particle_t *particle = &screensaver->particles[i];
893+
894+
particle->x = (float)(rand() % width);
895+
/* Stagger initial vertical positions to allow trail structures to form naturally */
896+
particle->y = (float)(rand() % height) - (base_particle_size * 4.0f);
897+
particle->a = 0.6f + ((float)(rand() % 20) * 0.1f); /* speed */
898+
particle->b = 0.0f; /* character swap timer */
899+
particle->c = (float)(rand() % 100) / 100.0f; /* randomized initial fade */
900+
particle->size = 2.0f + ((float)(rand() % 150) / 100.0f); /* scale */
901+
particle->symbol = menu_ss_matrix_symbols[(unsigned)(rand() % MENU_SS_NUM_MATRIX_SYMBOLS)];
902+
}
903+
}
904+
782905
/* Draws screensaver
783906
* Called every frame (on the video thread,
784907
* if threaded video is on) */
@@ -829,7 +952,11 @@ void menu_screensaver_frame(menu_screensaver_t *screensaver,
829952
screensaver->font_data.raster_block.carr.coords.vertices = 0;
830953

831954
/* Render text */
832-
for (i = 0; i < MENU_SS_NUM_PARTICLES; i++)
955+
size_t max_particles = MENU_SS_NUM_PARTICLES;
956+
if (screensaver->effect == MENU_SCREENSAVER_MATRIX)
957+
max_particles = MENU_SS_MATRIX_DENSE_COUNT;
958+
959+
for (i = 0; i < max_particles; i++)
833960
{
834961
menu_ss_particle_t *particle = &screensaver->particles[i];
835962

menu/menu_setting.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7515,6 +7515,11 @@ static size_t setting_get_string_representation_uint_menu_screensaver_animation(
75157515
msg_hash_to_str(
75167516
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_VORTEX),
75177517
len);
7518+
case MENU_SCREENSAVER_MATRIX:
7519+
return strlcpy(s,
7520+
msg_hash_to_str(
7521+
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_MATRIX),
7522+
len);
75187523
}
75197524
}
75207525
return 0;

msg_hash.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,7 @@ enum msg_hash_enums
15891589
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_SNOW,
15901590
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_STARFIELD,
15911591
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_VORTEX,
1592+
MENU_ENUM_LABEL_VALUE_MENU_SCREENSAVER_ANIMATION_MATRIX,
15921593

15931594
MENU_LABEL(MOUSE_ENABLE),
15941595
MENU_LABEL(POINTER_ENABLE),

0 commit comments

Comments
 (0)