Skip to content

Commit c45b07e

Browse files
committed
Simplify and add support for reading scroll text from a file
Signed-off-by: Joachim Wiberg <[email protected]>
1 parent a1e0e14 commit c45b07e

File tree

2 files changed

+165
-154
lines changed

2 files changed

+165
-154
lines changed

README.md

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,34 +36,7 @@ make run
3636

3737
### Command-Line Options
3838

39-
The demo supports various display and playback options:
40-
41-
```
42-
./demo [OPTIONS] [SCENE...]
43-
44-
Display Options:
45-
-f, --fullscreen Run in fullscreen mode (scales to display)
46-
-w, --window WxH Set window size (e.g., 1920x1080)
47-
-s, --scale N Integer scaling (e.g., 2 = 1600x1200)
48-
49-
Playback Options:
50-
-d, --duration SEC Scene duration in seconds (default: 15)
51-
-h, --help Show help message
52-
53-
Scenes:
54-
0 - Starfield 3 - Tunnel 6 - 3D Star Ball
55-
1 - Plasma 4 - Bouncing Logo
56-
2 - Cube 5 - Raining Logo
57-
58-
Examples:
59-
./demo -f # Fullscreen, auto-cycle scenes
60-
./demo -s 2 # 2x window size (1600x1200)
61-
./demo -w 1920x1080 # Custom window size
62-
./demo -d 30 2 6 # Show cube & star ball, 30s each
63-
```
64-
65-
The demo renders internally at 800x600 and scales smoothly to any display
66-
size while maintaining the 4:3 aspect ratio.
39+
Run `./demo --help` to see all available options.
6740

6841
## Distribution
6942

@@ -124,3 +97,12 @@ The demo supports MOD/XM/IT tracker music files. To replace the music:
12497
4. Run `make clean && make`
12598

12699
[6]: https://modarchive.org/
100+
101+
## Customizing Scroll Text
102+
103+
Use the `-t` option to load custom scroll text from a file. This is especially
104+
useful when running in containers where you can mount your scroll text file:
105+
106+
```bash
107+
./demo -t /path/to/scroll.txt
108+
```

demo.c

Lines changed: 155 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <math.h>
1313
#include <stdio.h>
1414
#include <string.h>
15+
#include <getopt.h>
16+
#include <stdlib.h>
1517

1618
/* Embedded font, image, and music data */
1719
#include "font_data.h"
@@ -74,6 +76,7 @@ typedef struct {
7476
Uint32 scene_duration; /* Milliseconds per scene */
7577
int scene_list[6]; /* Custom scene order */
7678
int num_scenes; /* Number of scenes in list */
79+
char *scroll_text; /* Dynamically loaded scroll text */
7780
} DemoContext;
7881

7982
/* Plasma effect - optimized with lower resolution and LUT */
@@ -906,17 +909,9 @@ void render_raining_logo(DemoContext *ctx)
906909
/* Scroll text rendering with different styles */
907910
void render_scroll_text(DemoContext *ctx)
908911
{
909-
const char *text = "Infix OS - The Container demo"
910-
" *** Greetings to the demoscene <3"
911-
" *** API first: NETCONF + RESTCONF"
912-
" *** Say Hi to our mascot, Jack! :-)"
913-
" *** YANG is the real HERO tho ..."
914-
" *** Sponsored by Wires in Westeros"
915-
" *** From idea to production - we've got you!"
916-
" *** Visit us at https://wires.se"
917-
" *** ";
912+
const char *text = ctx->scroll_text;
918913

919-
if (ctx->scroll_style == SCROLL_NONE)
914+
if (ctx->scroll_style == SCROLL_NONE || !text)
920915
return;
921916

922917
int text_len = strlen(text);
@@ -1095,8 +1090,136 @@ void render_scroll_text(DemoContext *ctx)
10951090
}
10961091
}
10971092

1093+
static int usage(int rc)
1094+
{
1095+
printf("Usage: demo [OPTIONS] [SCENE...]\n");
1096+
printf("\nDisplay Options:\n");
1097+
printf(" -f, --fullscreen Run in fullscreen mode (scales to display)\n");
1098+
printf(" -w, --window WxH Set window size (e.g., 1920x1080)\n");
1099+
printf(" -s, --scale N Integer scaling (e.g., 2 = 1600x1200)\n");
1100+
printf("\nPlayback Options:\n");
1101+
printf(" -d, --duration SEC Scene duration in seconds (default: 15)\n");
1102+
printf(" -t, --text FILE Load scroll text from file\n");
1103+
printf(" -h, --help Show this help message\n");
1104+
printf("\nScenes:\n");
1105+
printf(" 0 - Starfield 3 - Tunnel 6 - 3D Star Ball\n");
1106+
printf(" 1 - Plasma 4 - Bouncing Logo\n");
1107+
printf(" 2 - Cube 5 - Raining Logo\n");
1108+
printf("\nExamples:\n");
1109+
printf(" demo -f # Fullscreen, auto-cycle scenes\n");
1110+
printf(" demo -s 2 # 2x window size (1600x1200)\n");
1111+
printf(" demo -w 1920x1080 # Custom window size\n");
1112+
printf(" demo -d 30 2 6 # Show cube & star ball, 30s each\n");
1113+
printf(" demo -t /mnt/scroll.txt # Custom scroll text\n");
1114+
1115+
return rc;
1116+
}
1117+
10981118
int main(int argc, char *argv[])
10991119
{
1120+
/* Window/display settings */
1121+
int fullscreen = 0;
1122+
int window_width = 0; /* 0 = auto-detect */
1123+
int window_height = 0;
1124+
int scale_factor = 1;
1125+
int auto_resolution = 1; /* Auto-detect and adapt resolution */
1126+
const char *scroll_file_path = NULL;
1127+
int scene_list[6];
1128+
int num_scenes = 0;
1129+
int scene_duration = 15000; /* Default: 15 seconds per scene */
1130+
1131+
/* Default scroll text */
1132+
const char *default_text = "Infix OS - The Container demo"
1133+
" *** Greetings to the demoscene <3"
1134+
" *** API first: NETCONF + RESTCONF"
1135+
" *** Say Hi to our mascot, Jack! :-)"
1136+
" *** YANG is the real HERO tho ..."
1137+
" *** Sponsored by Wires in Westeros"
1138+
" *** From idea to production - we've got you!"
1139+
" *** Visit us at https://wires.se"
1140+
" *** ";
1141+
1142+
/* Parse command-line arguments */
1143+
1144+
static struct option long_options[] = {
1145+
{"help", no_argument, NULL, 'h'},
1146+
{"duration", required_argument, NULL, 'd'},
1147+
{"fullscreen", no_argument, NULL, 'f'},
1148+
{"window", required_argument, NULL, 'w'},
1149+
{"scale", required_argument, NULL, 's'},
1150+
{"text", required_argument, NULL, 't'},
1151+
{NULL, 0, NULL, 0}
1152+
};
1153+
1154+
int opt;
1155+
while ((opt = getopt_long(argc, argv, "hd:fw:s:t:", long_options, NULL)) != -1) {
1156+
switch (opt) {
1157+
case 'h':
1158+
return usage(0);
1159+
1160+
case 'd':
1161+
{
1162+
int duration_sec = atoi(optarg);
1163+
if (duration_sec > 0) {
1164+
scene_duration = duration_sec * 1000;
1165+
} else {
1166+
fprintf(stderr, "Error: Invalid duration '%s'. Must be positive.\n", optarg);
1167+
return 1;
1168+
}
1169+
}
1170+
break;
1171+
1172+
case 'f':
1173+
fullscreen = 1;
1174+
break;
1175+
1176+
case 'w':
1177+
if (sscanf(optarg, "%dx%d", &window_width, &window_height) != 2) {
1178+
fprintf(stderr, "Error: Invalid window size '%s'. Use format WxH (e.g., 1920x1080)\n", optarg);
1179+
return 1;
1180+
}
1181+
/* Adapt render resolution to match aspect ratio */
1182+
{
1183+
float aspect = (float)window_width / window_height;
1184+
WIDTH = 800;
1185+
HEIGHT = (int)(800.0f / aspect);
1186+
auto_resolution = 0; /* Manual window size disables auto-detection */
1187+
}
1188+
break;
1189+
1190+
case 's':
1191+
scale_factor = atoi(optarg);
1192+
if (scale_factor < 1) {
1193+
fprintf(stderr, "Error: Invalid scale factor '%s'. Must be >= 1\n", optarg);
1194+
return 1;
1195+
}
1196+
window_width = WIDTH * scale_factor;
1197+
window_height = HEIGHT * scale_factor;
1198+
break;
1199+
1200+
case 't':
1201+
scroll_file_path = optarg;
1202+
break;
1203+
1204+
default:
1205+
return usage(1);
1206+
}
1207+
}
1208+
1209+
/* Parse non-option arguments as scene numbers */
1210+
for (int i = optind; i < argc; i++) {
1211+
int scene = atoi(argv[i]);
1212+
if (scene >= 0 && scene <= 6) {
1213+
if (num_scenes < 7) {
1214+
scene_list[num_scenes++] = scene;
1215+
}
1216+
} else {
1217+
fprintf(stderr, "Error: Invalid scene number '%s'. Use 0-6.\n", argv[i]);
1218+
return 1;
1219+
}
1220+
}
1221+
1222+
/* Initialize SDL and libraries */
11001223
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
11011224
fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
11021225
return 1;
@@ -1124,127 +1247,32 @@ int main(int argc, char *argv[])
11241247
return 1;
11251248
}
11261249

1250+
/* Initialize demo context */
11271251
DemoContext ctx = {0};
11281252
ctx.fixed_scene = -1; /* -1 means auto-switch scenes */
11291253
ctx.current_scene_index = 0;
1130-
int scene_list[6];
1131-
int num_scenes = 0;
1132-
1133-
/* Window/display settings */
1134-
int fullscreen = 0;
1135-
int window_width = 0; /* 0 = auto-detect */
1136-
int window_height = 0;
1137-
int scale_factor = 1;
1138-
int auto_resolution = 1; /* Auto-detect and adapt resolution */
1139-
1140-
/* Parse command-line arguments */
1141-
ctx.scene_duration = 15000; /* Default: 15 seconds per scene */
1142-
1143-
for (int i = 1; i < argc; i++) {
1144-
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
1145-
printf("Usage: %s [OPTIONS] [SCENE...]\n", argv[0]);
1146-
printf("\nOptions:\n");
1147-
printf(" -h, --help Show this help message\n");
1148-
printf(" -d, --duration SEC Set scene duration in seconds (default: 15)\n");
1149-
printf(" -f, --fullscreen Run in fullscreen mode\n");
1150-
printf(" -w, --window WxH Set window size (e.g., 1920x1080)\n");
1151-
printf(" -s, --scale N Integer scaling factor (e.g., 2 = 1600x1200)\n");
1152-
printf("\nScenes:\n");
1153-
printf(" 0 - Starfield\n");
1154-
printf(" 1 - Plasma\n");
1155-
printf(" 2 - Cube\n");
1156-
printf(" 3 - Tunnel\n");
1157-
printf(" 4 - Bouncing Logo (hidden - manual only)\n");
1158-
printf(" 5 - Raining Logo\n");
1159-
printf(" 6 - 3D Star Ball\n");
1160-
printf("\nExamples:\n");
1161-
printf(" %s # Auto-cycle through scenes 0-3, 5-6\n", argv[0]);
1162-
printf(" %s 2 # Show only cube scene\n", argv[0]);
1163-
printf(" %s 1 3 5 6 # Cycle between plasma, tunnel, raining logo, and star ball\n", argv[0]);
1164-
printf(" %s -d 30 # Auto-cycle with 30 second scenes\n", argv[0]);
1165-
printf(" %s -d 10 2 6 # Cycle cube and star ball, 10 sec each\n", argv[0]);
1166-
IMG_Quit();
1167-
TTF_Quit();
1168-
SDL_Quit();
1169-
return 0;
1170-
}
1171-
else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--duration") == 0) {
1172-
if (i + 1 >= argc) {
1173-
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
1174-
IMG_Quit();
1175-
TTF_Quit();
1176-
SDL_Quit();
1177-
return 1;
1178-
}
1179-
int duration_sec = atoi(argv[++i]);
1180-
if (duration_sec > 0) {
1181-
ctx.scene_duration = duration_sec * 1000;
1182-
} else {
1183-
fprintf(stderr, "Error: Invalid duration '%s'. Must be positive.\n", argv[i]);
1184-
IMG_Quit();
1185-
TTF_Quit();
1186-
SDL_Quit();
1187-
return 1;
1188-
}
1189-
}
1190-
else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--fullscreen") == 0) {
1191-
fullscreen = 1;
1192-
}
1193-
else if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--window") == 0) {
1194-
if (i + 1 >= argc) {
1195-
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
1196-
IMG_Quit();
1197-
TTF_Quit();
1198-
SDL_Quit();
1199-
return 1;
1200-
}
1201-
if (sscanf(argv[++i], "%dx%d", &window_width, &window_height) != 2) {
1202-
fprintf(stderr, "Error: Invalid window size '%s'. Use format WxH (e.g., 1920x1080)\n", argv[i]);
1203-
IMG_Quit();
1204-
TTF_Quit();
1205-
SDL_Quit();
1206-
return 1;
1207-
}
1208-
/* Adapt render resolution to match aspect ratio */
1209-
float aspect = (float)window_width / window_height;
1210-
WIDTH = 800;
1211-
HEIGHT = (int)(800.0f / aspect);
1212-
auto_resolution = 0; /* Manual window size disables auto-detection */
1213-
}
1214-
else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--scale") == 0) {
1215-
if (i + 1 >= argc) {
1216-
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
1217-
IMG_Quit();
1218-
TTF_Quit();
1219-
SDL_Quit();
1220-
return 1;
1221-
}
1222-
scale_factor = atoi(argv[++i]);
1223-
if (scale_factor < 1) {
1224-
fprintf(stderr, "Error: Invalid scale factor '%s'. Must be >= 1\n", argv[i]);
1225-
IMG_Quit();
1226-
TTF_Quit();
1227-
SDL_Quit();
1228-
return 1;
1229-
}
1230-
window_width = WIDTH * scale_factor;
1231-
window_height = HEIGHT * scale_factor;
1232-
}
1233-
else {
1234-
/* Non-option argument - treat as scene number */
1235-
int scene = atoi(argv[i]);
1236-
if (scene >= 0 && scene <= 6) {
1237-
if (num_scenes < 7) {
1238-
scene_list[num_scenes++] = scene;
1239-
}
1240-
} else {
1241-
fprintf(stderr, "Error: Invalid scene number '%s'. Use 0-6.\n", argv[i]);
1242-
IMG_Quit();
1243-
TTF_Quit();
1244-
SDL_Quit();
1245-
return 1;
1254+
ctx.scene_duration = scene_duration;
1255+
1256+
/* Load scroll text from file or use default */
1257+
if (scroll_file_path) {
1258+
FILE *scroll_file = fopen(scroll_file_path, "r");
1259+
if (scroll_file) {
1260+
fseek(scroll_file, 0, SEEK_END);
1261+
long file_size = ftell(scroll_file);
1262+
fseek(scroll_file, 0, SEEK_SET);
1263+
1264+
ctx.scroll_text = malloc(file_size + 1);
1265+
if (ctx.scroll_text) {
1266+
size_t read_bytes = fread(ctx.scroll_text, 1, file_size, scroll_file);
1267+
ctx.scroll_text[read_bytes] = '\0';
12461268
}
1269+
fclose(scroll_file);
1270+
} else {
1271+
fprintf(stderr, "Warning: Could not open '%s', using default text\n", scroll_file_path);
1272+
ctx.scroll_text = strdup(default_text);
12471273
}
1274+
} else {
1275+
ctx.scroll_text = strdup(default_text);
12481276
}
12491277

12501278
/* Handle scene selection */
@@ -1568,6 +1596,7 @@ int main(int argc, char *argv[])
15681596
}
15691597

15701598
free(ctx.pixels);
1599+
free(ctx.scroll_text);
15711600
if (ctx.jack_surface) {
15721601
SDL_FreeSurface(ctx.jack_surface);
15731602
}

0 commit comments

Comments
 (0)