@@ -439,6 +439,228 @@ void render_tunnel(DemoContext *ctx)
439439 }
440440}
441441
442+ /* 3D star ball that bounces */
443+ void render_star_ball (DemoContext * ctx )
444+ {
445+ /* Generate sphere vertices using fibonacci sphere */
446+ #define NUM_BALL_STARS 200
447+ #define NUM_BG_STARS 150
448+ static float sphere_points [NUM_BALL_STARS ][3 ];
449+ static int initialized = 0 ;
450+ static float ball_x = 400.0f ;
451+ static float ball_y = 300.0f ;
452+ static float vel_x = 3.0f ;
453+ static float vel_y = 2.5f ;
454+ static float squash_x = 1.0f ;
455+ static float squash_y = 1.0f ;
456+
457+ /* Parallax background stars (3 layers) */
458+ typedef struct {
459+ float x , y ;
460+ int layer ; /* 0=far, 1=mid, 2=near */
461+ int brightness ;
462+ } BgStar ;
463+ static BgStar bg_stars [NUM_BG_STARS ];
464+ static int bg_initialized = 0 ;
465+
466+ if (!initialized ) {
467+ /* Generate points on sphere using fibonacci spiral */
468+ float phi = (1.0f + sqrtf (5.0f )) / 2.0f ; /* Golden ratio */
469+ for (int i = 0 ; i < NUM_BALL_STARS ; i ++ ) {
470+ float t = (float )i / NUM_BALL_STARS ;
471+ float inc = acosf (1.0f - 2.0f * t );
472+ float azi = 2.0f * PI * i / phi ;
473+
474+ sphere_points [i ][0 ] = sinf (inc ) * cosf (azi );
475+ sphere_points [i ][1 ] = sinf (inc ) * sinf (azi );
476+ sphere_points [i ][2 ] = cosf (inc );
477+ }
478+ initialized = 1 ;
479+ }
480+
481+ if (!bg_initialized ) {
482+ /* Initialize background stars with random positions */
483+ for (int i = 0 ; i < NUM_BG_STARS ; i ++ ) {
484+ bg_stars [i ].x = (float )(rand () % WIDTH );
485+ bg_stars [i ].y = (float )(rand () % HEIGHT );
486+ bg_stars [i ].layer = i % 3 ; /* Distribute across 3 layers */
487+ /* Fainter stars for farther layers */
488+ bg_stars [i ].brightness = (bg_stars [i ].layer == 0 ) ? 40 :
489+ (bg_stars [i ].layer == 1 ) ? 60 : 80 ;
490+ }
491+ bg_initialized = 1 ;
492+ }
493+
494+ /* Clear to black */
495+ for (int i = 0 ; i < WIDTH * HEIGHT ; i ++ ) {
496+ ctx -> pixels [i ] = 0xFF000000 ;
497+ }
498+
499+ /* Render and update parallax background stars (scrolling opposite to text) */
500+ float scroll_speed = 180.0f ; /* Match text scroll speed */
501+ for (int i = 0 ; i < NUM_BG_STARS ; i ++ ) {
502+ /* Different speeds per layer for parallax effect */
503+ float layer_speed = (bg_stars [i ].layer == 0 ) ? 0.2f :
504+ (bg_stars [i ].layer == 1 ) ? 0.4f : 0.6f ;
505+
506+ /* Scroll left (opposite of text which scrolls left to right when viewing) */
507+ bg_stars [i ].x += scroll_speed * layer_speed * 0.016f ;
508+
509+ /* Wrap around */
510+ if (bg_stars [i ].x > WIDTH ) {
511+ bg_stars [i ].x = 0 ;
512+ }
513+
514+ /* Draw star */
515+ int sx = (int )bg_stars [i ].x ;
516+ int sy = (int )bg_stars [i ].y ;
517+ if (sx >= 0 && sx < WIDTH && sy >= 0 && sy < HEIGHT ) {
518+ int b = bg_stars [i ].brightness ;
519+ Uint32 color = 0xFF000000 | (b << 16 ) | (b << 8 ) | b ;
520+ ctx -> pixels [sy * WIDTH + sx ] = color ;
521+ }
522+ }
523+
524+ /* Render horizontal raster bars behind the ball */
525+ float t = ctx -> time ;
526+ int num_bars = 6 ;
527+ for (int i = 0 ; i < num_bars ; i ++ ) {
528+ /* Calculate bar position with sine wave motion */
529+ float base_y = (i * HEIGHT / num_bars ) + sinf (t * 1.2f + i * 0.9f ) * 60.0f ;
530+ int bar_height = 50 ; /* Fatter bars */
531+
532+ /* HSV to RGB for rainbow effect */
533+ float hue = (i / (float )num_bars + t * 0.15f );
534+ hue = hue - floorf (hue ); /* Keep in 0-1 range */
535+
536+ int h_section = (int )(hue * 6 );
537+ float f = hue * 6 - h_section ;
538+ int v = 200 ; /* Slightly dimmer so ball stands out */
539+ int p = 0 ;
540+ int q = (int )(v * (1 - f ));
541+ int t_val = (int )(v * f );
542+
543+ int r , g , b ;
544+ switch (h_section % 6 ) {
545+ case 0 : r = v ; g = t_val ; b = p ; break ;
546+ case 1 : r = q ; g = v ; b = p ; break ;
547+ case 2 : r = p ; g = v ; b = t_val ; break ;
548+ case 3 : r = p ; g = q ; b = v ; break ;
549+ case 4 : r = t_val ; g = p ; b = v ; break ;
550+ default : r = v ; g = p ; b = q ; break ;
551+ }
552+
553+ /* Draw bar with gradient */
554+ for (int dy = 0 ; dy < bar_height ; dy ++ ) {
555+ int y = (int )base_y + dy ;
556+ if (y >= 0 && y < HEIGHT - 100 ) { /* Leave room for scroll text */
557+ /* Gradient brightness based on position in bar */
558+ float brightness = 1.0f - fabsf (dy - bar_height / 2.0f ) / (bar_height / 2.0f );
559+ brightness = brightness * brightness ; /* Squared for sharper falloff */
560+
561+ int br = (int )(r * brightness );
562+ int bg = (int )(g * brightness );
563+ int bb = (int )(b * brightness );
564+
565+ Uint32 color = 0xFF000000 | (br << 16 ) | (bg << 8 ) | bb ;
566+ for (int x = 0 ; x < WIDTH ; x ++ ) {
567+ ctx -> pixels [y * WIDTH + x ] = color ;
568+ }
569+ }
570+ }
571+ }
572+
573+ /* Update ball position with physics */
574+ ball_x += vel_x ;
575+ ball_y += vel_y ;
576+
577+ float radius = 80.0f ;
578+ float squash_intensity = 0.15f ;
579+ float recovery_speed = 0.2f ;
580+
581+ /* Bounce off edges with squash */
582+ if (ball_x - radius < 0 || ball_x + radius > WIDTH ) {
583+ vel_x = - vel_x ;
584+ ball_x = (ball_x < WIDTH / 2 ) ? radius : WIDTH - radius ;
585+ squash_x = 1.0f - squash_intensity ; /* Squash horizontally */
586+ squash_y = 1.0f + squash_intensity ; /* Stretch vertically */
587+ }
588+ if (ball_y - radius < 0 || ball_y + radius > HEIGHT ) {
589+ vel_y = - vel_y ;
590+ ball_y = (ball_y < HEIGHT / 2 ) ? radius : HEIGHT - radius ;
591+ squash_y = 1.0f - squash_intensity ; /* Squash vertically */
592+ squash_x = 1.0f + squash_intensity ; /* Stretch horizontally */
593+ }
594+
595+ /* Recover to normal shape */
596+ squash_x += (1.0f - squash_x ) * recovery_speed ;
597+ squash_y += (1.0f - squash_y ) * recovery_speed ;
598+
599+ /* Rotation angles */
600+ float rot_x = ctx -> time * 0.7f ;
601+ float rot_y = ctx -> time * 0.5f ;
602+ float rot_z = ctx -> time * 0.3f ;
603+
604+ /* Render sphere points */
605+ for (int i = 0 ; i < NUM_BALL_STARS ; i ++ ) {
606+ float x = sphere_points [i ][0 ] * radius ;
607+ float y = sphere_points [i ][1 ] * radius ;
608+ float z = sphere_points [i ][2 ] * radius ;
609+
610+ /* Apply squash and stretch */
611+ x *= squash_x ;
612+ y *= squash_y ;
613+
614+ /* Rotate around X axis */
615+ float y1 = y * cosf (rot_x ) - z * sinf (rot_x );
616+ float z1 = y * sinf (rot_x ) + z * cosf (rot_x );
617+ y = y1 ;
618+ z = z1 ;
619+
620+ /* Rotate around Y axis */
621+ float x1 = x * cosf (rot_y ) + z * sinf (rot_y );
622+ z1 = - x * sinf (rot_y ) + z * cosf (rot_y );
623+ x = x1 ;
624+ z = z1 ;
625+
626+ /* Rotate around Z axis */
627+ float x2 = x * cosf (rot_z ) - y * sinf (rot_z );
628+ float y2 = x * sinf (rot_z ) + y * cosf (rot_z );
629+ x = x2 ;
630+ y = y2 ;
631+
632+ /* Project to 2D */
633+ float depth = 200.0f / (200.0f + z );
634+ int sx = (int )(ball_x + x * depth );
635+ int sy = (int )(ball_y + y * depth );
636+
637+ /* Color based on depth (closer = brighter) */
638+ int brightness = (int )(128 + 127 * depth );
639+ if (brightness < 0 ) brightness = 0 ;
640+ if (brightness > 255 ) brightness = 255 ;
641+
642+ /* Draw star with size based on depth */
643+ if (sx >= 1 && sx < WIDTH - 1 && sy >= 1 && sy < HEIGHT - 1 ) {
644+ Uint32 color = 0xFF000000 | (brightness << 16 ) | (brightness << 8 ) | brightness ;
645+
646+ /* Larger stars for closer points */
647+ if (z > 0 ) {
648+ ctx -> pixels [sy * WIDTH + sx ] = color ;
649+ ctx -> pixels [sy * WIDTH + sx - 1 ] = color ;
650+ ctx -> pixels [sy * WIDTH + sx + 1 ] = color ;
651+ ctx -> pixels [(sy - 1 ) * WIDTH + sx ] = color ;
652+ ctx -> pixels [(sy + 1 ) * WIDTH + sx ] = color ;
653+ } else {
654+ ctx -> pixels [sy * WIDTH + sx ] = color ;
655+ }
656+ }
657+ }
658+
659+ SDL_UpdateTexture (ctx -> texture , NULL , ctx -> pixels , WIDTH * sizeof (Uint32 ));
660+ SDL_RenderClear (ctx -> renderer );
661+ SDL_RenderCopy (ctx -> renderer , ctx -> texture , NULL , NULL );
662+ }
663+
442664/* Bouncing logo effect with squash and stretch */
443665void render_bouncing_logo (DemoContext * ctx )
444666{
@@ -922,12 +1144,13 @@ int main(int argc, char *argv[])
9221144 printf (" 3 - Tunnel\n" );
9231145 printf (" 4 - Bouncing Logo (hidden - manual only)\n" );
9241146 printf (" 5 - Raining Logo\n" );
1147+ printf (" 6 - 3D Star Ball\n" );
9251148 printf ("\nExamples:\n" );
926- printf (" %s # Auto-cycle through scenes 0-3 and 5 \n" , argv [0 ]);
1149+ printf (" %s # Auto-cycle through scenes 0-3, 5-6 \n" , argv [0 ]);
9271150 printf (" %s 2 # Show only cube scene\n" , argv [0 ]);
928- printf (" %s 1 3 5 # Cycle between plasma, tunnel, and raining logo\n" , argv [0 ]);
1151+ printf (" %s 1 3 5 6 # Cycle between plasma, tunnel, raining logo, and star ball \n" , argv [0 ]);
9291152 printf (" %s -d 30 # Auto-cycle with 30 second scenes\n" , argv [0 ]);
930- printf (" %s -d 10 2 5 # Cycle cube and raining logo , 10 sec each\n" , argv [0 ]);
1153+ printf (" %s -d 10 2 6 # Cycle cube and star ball , 10 sec each\n" , argv [0 ]);
9311154 IMG_Quit ();
9321155 TTF_Quit ();
9331156 SDL_Quit ();
@@ -955,12 +1178,12 @@ int main(int argc, char *argv[])
9551178 else {
9561179 /* Non-option argument - treat as scene number */
9571180 int scene = atoi (argv [i ]);
958- if (scene >= 0 && scene <= 5 ) {
959- if (num_scenes < 6 ) {
1181+ if (scene >= 0 && scene <= 6 ) {
1182+ if (num_scenes < 7 ) {
9601183 scene_list [num_scenes ++ ] = scene ;
9611184 }
9621185 } else {
963- fprintf (stderr , "Error: Invalid scene number '%s'. Use 0-5 .\n" , argv [i ]);
1186+ fprintf (stderr , "Error: Invalid scene number '%s'. Use 0-6 .\n" , argv [i ]);
9641187 IMG_Quit ();
9651188 TTF_Quit ();
9661189 SDL_Quit ();
@@ -990,7 +1213,8 @@ int main(int argc, char *argv[])
9901213 ctx .scene_list [2 ] = 2 ;
9911214 ctx .scene_list [3 ] = 3 ;
9921215 ctx .scene_list [4 ] = 5 ;
993- ctx .num_scenes = 5 ;
1216+ ctx .scene_list [5 ] = 6 ;
1217+ ctx .num_scenes = 6 ;
9941218 ctx .current_scene_index = 0 ;
9951219 ctx .current_scene = ctx .scene_list [0 ];
9961220 }
@@ -1224,6 +1448,11 @@ int main(int argc, char *argv[])
12241448 render_raining_logo (& ctx );
12251449 render_scroll_text (& ctx );
12261450 break ;
1451+ case 6 :
1452+ ctx .scroll_style = SCROLL_BOTTOM_TRADITIONAL ;
1453+ render_star_ball (& ctx );
1454+ render_scroll_text (& ctx );
1455+ break ;
12271456 }
12281457
12291458 /* Apply fade effect */
0 commit comments