|
12 | 12 | #include <math.h> |
13 | 13 | #include <stdio.h> |
14 | 14 | #include <string.h> |
| 15 | +#include <getopt.h> |
| 16 | +#include <stdlib.h> |
15 | 17 |
|
16 | 18 | /* Embedded font, image, and music data */ |
17 | 19 | #include "font_data.h" |
@@ -74,6 +76,7 @@ typedef struct { |
74 | 76 | Uint32 scene_duration; /* Milliseconds per scene */ |
75 | 77 | int scene_list[6]; /* Custom scene order */ |
76 | 78 | int num_scenes; /* Number of scenes in list */ |
| 79 | + char *scroll_text; /* Dynamically loaded scroll text */ |
77 | 80 | } DemoContext; |
78 | 81 |
|
79 | 82 | /* Plasma effect - optimized with lower resolution and LUT */ |
@@ -906,17 +909,9 @@ void render_raining_logo(DemoContext *ctx) |
906 | 909 | /* Scroll text rendering with different styles */ |
907 | 910 | void render_scroll_text(DemoContext *ctx) |
908 | 911 | { |
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; |
918 | 913 |
|
919 | | - if (ctx->scroll_style == SCROLL_NONE) |
| 914 | + if (ctx->scroll_style == SCROLL_NONE || !text) |
920 | 915 | return; |
921 | 916 |
|
922 | 917 | int text_len = strlen(text); |
@@ -1095,8 +1090,136 @@ void render_scroll_text(DemoContext *ctx) |
1095 | 1090 | } |
1096 | 1091 | } |
1097 | 1092 |
|
| 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 | + |
1098 | 1118 | int main(int argc, char *argv[]) |
1099 | 1119 | { |
| 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 */ |
1100 | 1223 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { |
1101 | 1224 | fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); |
1102 | 1225 | return 1; |
@@ -1124,127 +1247,32 @@ int main(int argc, char *argv[]) |
1124 | 1247 | return 1; |
1125 | 1248 | } |
1126 | 1249 |
|
| 1250 | + /* Initialize demo context */ |
1127 | 1251 | DemoContext ctx = {0}; |
1128 | 1252 | ctx.fixed_scene = -1; /* -1 means auto-switch scenes */ |
1129 | 1253 | 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'; |
1246 | 1268 | } |
| 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); |
1247 | 1273 | } |
| 1274 | + } else { |
| 1275 | + ctx.scroll_text = strdup(default_text); |
1248 | 1276 | } |
1249 | 1277 |
|
1250 | 1278 | /* Handle scene selection */ |
@@ -1568,6 +1596,7 @@ int main(int argc, char *argv[]) |
1568 | 1596 | } |
1569 | 1597 |
|
1570 | 1598 | free(ctx.pixels); |
| 1599 | + free(ctx.scroll_text); |
1571 | 1600 | if (ctx.jack_surface) { |
1572 | 1601 | SDL_FreeSurface(ctx.jack_surface); |
1573 | 1602 | } |
|
0 commit comments