Skip to content

Commit d1ac3e8

Browse files
committed
Next scene: 3D Star Ball with rasterbars and parallax starfield
Signed-off-by: Joachim Wiberg <[email protected]>
1 parent 356fc11 commit d1ac3e8

File tree

1 file changed

+236
-7
lines changed

1 file changed

+236
-7
lines changed

demo.c

Lines changed: 236 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
443665
void 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

Comments
 (0)