Skip to content

Commit f73236d

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 f73236d

5 files changed

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

@@ -829,7 +954,11 @@ void menu_screensaver_frame(menu_screensaver_t *screensaver,
829954
screensaver->font_data.raster_block.carr.coords.vertices = 0;
830955

831956
/* Render text */
832-
for (i = 0; i < MENU_SS_NUM_PARTICLES; i++)
957+
max_particles = MENU_SS_NUM_PARTICLES;
958+
if (screensaver->effect == MENU_SCREENSAVER_MATRIX)
959+
max_particles = MENU_SS_MATRIX_DENSE_COUNT;
960+
961+
for (i = 0; i < max_particles; i++)
833962
{
834963
menu_ss_particle_t *particle = &screensaver->particles[i];
835964

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)