diff options
Diffstat (limited to 'contrib/SDL-3.2.8/examples/demo/03-infinite-monkeys/infinite-monkeys.c')
| -rw-r--r-- | contrib/SDL-3.2.8/examples/demo/03-infinite-monkeys/infinite-monkeys.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/examples/demo/03-infinite-monkeys/infinite-monkeys.c b/contrib/SDL-3.2.8/examples/demo/03-infinite-monkeys/infinite-monkeys.c new file mode 100644 index 0000000..a8bfad1 --- /dev/null +++ b/contrib/SDL-3.2.8/examples/demo/03-infinite-monkeys/infinite-monkeys.c | |||
| @@ -0,0 +1,377 @@ | |||
| 1 | /* | ||
| 2 | * This code is public domain. Feel free to use it for any purpose! | ||
| 3 | */ | ||
| 4 | |||
| 5 | #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ | ||
| 6 | #include <SDL3/SDL.h> | ||
| 7 | #include <SDL3/SDL_main.h> | ||
| 8 | |||
| 9 | /* We will use this renderer to draw into this window every frame. */ | ||
| 10 | static SDL_Window *window = NULL; | ||
| 11 | static SDL_Renderer *renderer = NULL; | ||
| 12 | static char *text; | ||
| 13 | static const char *end; | ||
| 14 | static const char *progress; | ||
| 15 | static SDL_Time start_time; | ||
| 16 | static SDL_Time end_time; | ||
| 17 | typedef struct { | ||
| 18 | Uint32 *text; | ||
| 19 | int length; | ||
| 20 | } Line; | ||
| 21 | int row = 0; | ||
| 22 | int rows = 0; | ||
| 23 | int cols = 0; | ||
| 24 | static Line **lines; | ||
| 25 | static Line monkey_chars; | ||
| 26 | static int monkeys = 100; | ||
| 27 | |||
| 28 | /* The highest and lowest scancodes a monkey can hit */ | ||
| 29 | #define MIN_MONKEY_SCANCODE SDL_SCANCODE_A | ||
| 30 | #define MAX_MONKEY_SCANCODE SDL_SCANCODE_SLASH | ||
| 31 | |||
| 32 | static const char *default_text = | ||
| 33 | "Jabberwocky, by Lewis Carroll\n" | ||
| 34 | "\n" | ||
| 35 | "'Twas brillig, and the slithy toves\n" | ||
| 36 | " Did gyre and gimble in the wabe:\n" | ||
| 37 | "All mimsy were the borogoves,\n" | ||
| 38 | " And the mome raths outgrabe.\n" | ||
| 39 | "\n" | ||
| 40 | "\"Beware the Jabberwock, my son!\n" | ||
| 41 | " The jaws that bite, the claws that catch!\n" | ||
| 42 | "Beware the Jubjub bird, and shun\n" | ||
| 43 | " The frumious Bandersnatch!\"\n" | ||
| 44 | "\n" | ||
| 45 | "He took his vorpal sword in hand;\n" | ||
| 46 | " Long time the manxome foe he sought-\n" | ||
| 47 | "So rested he by the Tumtum tree\n" | ||
| 48 | " And stood awhile in thought.\n" | ||
| 49 | "\n" | ||
| 50 | "And, as in uffish thought he stood,\n" | ||
| 51 | " The Jabberwock, with eyes of flame,\n" | ||
| 52 | "Came whiffling through the tulgey wood,\n" | ||
| 53 | " And burbled as it came!\n" | ||
| 54 | "\n" | ||
| 55 | "One, two! One, two! And through and through\n" | ||
| 56 | " The vorpal blade went snicker-snack!\n" | ||
| 57 | "He left it dead, and with its head\n" | ||
| 58 | " He went galumphing back.\n" | ||
| 59 | "\n" | ||
| 60 | "\"And hast thou slain the Jabberwock?\n" | ||
| 61 | " Come to my arms, my beamish boy!\n" | ||
| 62 | "O frabjous day! Callooh! Callay!\"\n" | ||
| 63 | " He chortled in his joy.\n" | ||
| 64 | "\n" | ||
| 65 | "'Twas brillig, and the slithy toves\n" | ||
| 66 | " Did gyre and gimble in the wabe:\n" | ||
| 67 | "All mimsy were the borogoves,\n" | ||
| 68 | " And the mome raths outgrabe.\n"; | ||
| 69 | |||
| 70 | |||
| 71 | static void FreeLines(void) | ||
| 72 | { | ||
| 73 | int i; | ||
| 74 | |||
| 75 | if (rows > 0 && cols > 0) { | ||
| 76 | for (i = 0; i < rows; ++i) { | ||
| 77 | SDL_free(lines[i]->text); | ||
| 78 | SDL_free(lines[i]); | ||
| 79 | } | ||
| 80 | SDL_free(lines); | ||
| 81 | lines = NULL; | ||
| 82 | } | ||
| 83 | SDL_free(monkey_chars.text); | ||
| 84 | monkey_chars.text = NULL; | ||
| 85 | } | ||
| 86 | |||
| 87 | static void OnWindowSizeChanged(void) | ||
| 88 | { | ||
| 89 | int w, h; | ||
| 90 | |||
| 91 | if (!SDL_GetCurrentRenderOutputSize(renderer, &w, &h)) { | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | |||
| 95 | FreeLines(); | ||
| 96 | |||
| 97 | row = 0; | ||
| 98 | rows = (h / SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) - 4; | ||
| 99 | cols = (w / SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE); | ||
| 100 | if (rows > 0 && cols > 0) { | ||
| 101 | int i; | ||
| 102 | |||
| 103 | lines = (Line **)SDL_malloc(rows * sizeof(Line *)); | ||
| 104 | if (lines) { | ||
| 105 | for (i = 0; i < rows; ++i) { | ||
| 106 | lines[i] = (Line *)SDL_malloc(sizeof(Line)); | ||
| 107 | if (!lines[i]) { | ||
| 108 | FreeLines(); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | lines[i]->text = (Uint32 *)SDL_malloc(cols * sizeof(Uint32)); | ||
| 112 | if (!lines[i]->text) { | ||
| 113 | FreeLines(); | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | lines[i]->length = 0; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | monkey_chars.text = (Uint32 *)SDL_malloc(cols * sizeof(Uint32)); | ||
| 121 | if (monkey_chars.text) { | ||
| 122 | for (i = 0; i < cols; ++i) { | ||
| 123 | monkey_chars.text[i] = ' '; | ||
| 124 | } | ||
| 125 | monkey_chars.length = cols; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | /* This function runs once at startup. */ | ||
| 131 | SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) | ||
| 132 | { | ||
| 133 | int arg = 1; | ||
| 134 | |||
| 135 | SDL_SetAppMetadata("Infinite Monkeys", "1.0", "com.example.infinite-monkeys"); | ||
| 136 | |||
| 137 | if (!SDL_Init(SDL_INIT_VIDEO)) { | ||
| 138 | SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); | ||
| 139 | return SDL_APP_FAILURE; | ||
| 140 | } | ||
| 141 | |||
| 142 | if (!SDL_CreateWindowAndRenderer("examples/demo/infinite-monkeys", 640, 480, 0, &window, &renderer)) { | ||
| 143 | SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); | ||
| 144 | return SDL_APP_FAILURE; | ||
| 145 | } | ||
| 146 | SDL_SetRenderVSync(renderer, 1); | ||
| 147 | |||
| 148 | if (argv[arg] && SDL_strcmp(argv[arg], "--monkeys") == 0) { | ||
| 149 | ++arg; | ||
| 150 | if (argv[arg]) { | ||
| 151 | monkeys = SDL_atoi(argv[arg]); | ||
| 152 | ++arg; | ||
| 153 | } else { | ||
| 154 | SDL_Log("Usage: %s [--monkeys N] [file.txt]", argv[0]); | ||
| 155 | return SDL_APP_FAILURE; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | if (argv[arg]) { | ||
| 160 | const char *file = argv[arg]; | ||
| 161 | size_t size; | ||
| 162 | text = (char *)SDL_LoadFile(file, &size); | ||
| 163 | if (!text) { | ||
| 164 | SDL_Log("Couldn't open %s: %s", file, SDL_GetError()); | ||
| 165 | return SDL_APP_FAILURE; | ||
| 166 | } | ||
| 167 | end = text + size; | ||
| 168 | } else { | ||
| 169 | text = SDL_strdup(default_text); | ||
| 170 | end = text + SDL_strlen(text); | ||
| 171 | } | ||
| 172 | progress = text; | ||
| 173 | |||
| 174 | SDL_GetCurrentTime(&start_time); | ||
| 175 | |||
| 176 | OnWindowSizeChanged(); | ||
| 177 | |||
| 178 | return SDL_APP_CONTINUE; /* carry on with the program! */ | ||
| 179 | } | ||
| 180 | |||
| 181 | /* This function runs when a new event (mouse input, keypresses, etc) occurs. */ | ||
| 182 | SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) | ||
| 183 | { | ||
| 184 | switch (event->type) { | ||
| 185 | case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: | ||
| 186 | OnWindowSizeChanged(); | ||
| 187 | break; | ||
| 188 | case SDL_EVENT_QUIT: | ||
| 189 | return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ | ||
| 190 | } | ||
| 191 | return SDL_APP_CONTINUE; /* carry on with the program! */ | ||
| 192 | } | ||
| 193 | |||
| 194 | static void DisplayLine(float x, float y, Line *line) | ||
| 195 | { | ||
| 196 | /* Allocate maximum space potentially needed for this line */ | ||
| 197 | char *utf8 = (char *)SDL_malloc(line->length * 4 + 1); | ||
| 198 | if (utf8) { | ||
| 199 | char *spot = utf8; | ||
| 200 | int i; | ||
| 201 | |||
| 202 | for (i = 0; i < line->length; ++i) { | ||
| 203 | spot = SDL_UCS4ToUTF8(line->text[i], spot); | ||
| 204 | } | ||
| 205 | *spot = '\0'; | ||
| 206 | |||
| 207 | SDL_RenderDebugText(renderer, x, y, utf8); | ||
| 208 | SDL_free(utf8); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | static bool CanMonkeyType(Uint32 ch) | ||
| 213 | { | ||
| 214 | SDL_Keymod modstate; | ||
| 215 | SDL_Scancode scancode = SDL_GetScancodeFromKey(ch, &modstate); | ||
| 216 | if (scancode < MIN_MONKEY_SCANCODE || scancode > MAX_MONKEY_SCANCODE) { | ||
| 217 | return false; | ||
| 218 | } | ||
| 219 | /* Monkeys can hit the shift key, but nothing else */ | ||
| 220 | if ((modstate & ~SDL_KMOD_SHIFT) != 0) { | ||
| 221 | return false; | ||
| 222 | } | ||
| 223 | return true; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void AdvanceRow(void) | ||
| 227 | { | ||
| 228 | Line *line; | ||
| 229 | |||
| 230 | ++row; | ||
| 231 | line = lines[row % rows]; | ||
| 232 | line->length = 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | static void AddMonkeyChar(int monkey, Uint32 ch) | ||
| 236 | { | ||
| 237 | if (monkey >= 0 && monkey_chars.text) { | ||
| 238 | monkey_chars.text[(monkey % cols)] = ch; | ||
| 239 | } | ||
| 240 | |||
| 241 | if (lines) { | ||
| 242 | if (ch == '\n') { | ||
| 243 | AdvanceRow(); | ||
| 244 | } else { | ||
| 245 | Line *line = lines[row % rows]; | ||
| 246 | line->text[line->length++] = ch; | ||
| 247 | if (line->length == cols) { | ||
| 248 | AdvanceRow(); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | SDL_StepUTF8(&progress, NULL); | ||
| 254 | } | ||
| 255 | |||
| 256 | static Uint32 GetNextChar(void) | ||
| 257 | { | ||
| 258 | Uint32 ch = 0; | ||
| 259 | while (progress < end) { | ||
| 260 | const char *spot = progress; | ||
| 261 | ch = SDL_StepUTF8(&spot, NULL); | ||
| 262 | if (CanMonkeyType(ch)) { | ||
| 263 | break; | ||
| 264 | } else { | ||
| 265 | /* This is a freebie, monkeys can't type this */ | ||
| 266 | AddMonkeyChar(-1, ch); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | return ch; | ||
| 270 | } | ||
| 271 | |||
| 272 | static Uint32 MonkeyPlay(void) | ||
| 273 | { | ||
| 274 | int count = (MAX_MONKEY_SCANCODE - MIN_MONKEY_SCANCODE + 1); | ||
| 275 | SDL_Scancode scancode = (SDL_Scancode)(MIN_MONKEY_SCANCODE + SDL_rand(count)); | ||
| 276 | SDL_Keymod modstate = (SDL_rand(2) ? SDL_KMOD_SHIFT : 0); | ||
| 277 | |||
| 278 | return SDL_GetKeyFromScancode(scancode, modstate, false); | ||
| 279 | } | ||
| 280 | |||
| 281 | /* This function runs once per frame, and is the heart of the program. */ | ||
| 282 | SDL_AppResult SDL_AppIterate(void *appstate) | ||
| 283 | { | ||
| 284 | int i, monkey; | ||
| 285 | Uint32 next_char = 0, ch; | ||
| 286 | float x, y; | ||
| 287 | char *caption = NULL; | ||
| 288 | SDL_Time now, elapsed; | ||
| 289 | int hours, minutes, seconds; | ||
| 290 | SDL_FRect rect; | ||
| 291 | |||
| 292 | for (monkey = 0; monkey < monkeys; ++monkey) { | ||
| 293 | if (next_char == 0) { | ||
| 294 | next_char = GetNextChar(); | ||
| 295 | if (!next_char) { | ||
| 296 | /* All done! */ | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | ch = MonkeyPlay(); | ||
| 302 | if (ch == next_char) { | ||
| 303 | AddMonkeyChar(monkey, ch); | ||
| 304 | next_char = 0; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | /* Clear the screen */ | ||
| 309 | SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); | ||
| 310 | SDL_RenderClear(renderer); | ||
| 311 | |||
| 312 | /* Show the text already decoded */ | ||
| 313 | SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); | ||
| 314 | x = 0.0f; | ||
| 315 | y = 0.0f; | ||
| 316 | if (lines) { | ||
| 317 | int row_offset = row - rows + 1; | ||
| 318 | if (row_offset < 0) { | ||
| 319 | row_offset = 0; | ||
| 320 | } | ||
| 321 | for (i = 0; i < rows; ++i) { | ||
| 322 | Line *line = lines[(row_offset + i) % rows]; | ||
| 323 | DisplayLine(x, y, line); | ||
| 324 | y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* Show the caption */ | ||
| 328 | y = (float)((rows + 1) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE); | ||
| 329 | if (progress == end) { | ||
| 330 | if (!end_time) { | ||
| 331 | SDL_GetCurrentTime(&end_time); | ||
| 332 | } | ||
| 333 | now = end_time; | ||
| 334 | } else { | ||
| 335 | SDL_GetCurrentTime(&now); | ||
| 336 | } | ||
| 337 | elapsed = (now - start_time); | ||
| 338 | elapsed /= SDL_NS_PER_SECOND; | ||
| 339 | seconds = (int)(elapsed % 60); | ||
| 340 | elapsed /= 60; | ||
| 341 | minutes = (int)(elapsed % 60); | ||
| 342 | elapsed /= 60; | ||
| 343 | hours = (int)elapsed; | ||
| 344 | SDL_asprintf(&caption, "Monkeys: %d - %dH:%dM:%dS", monkeys, hours, minutes, seconds); | ||
| 345 | if (caption) { | ||
| 346 | SDL_RenderDebugText(renderer, x, y, caption); | ||
| 347 | SDL_free(caption); | ||
| 348 | } | ||
| 349 | y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; | ||
| 350 | |||
| 351 | /* Show the characters currently typed */ | ||
| 352 | DisplayLine(x, y, &monkey_chars); | ||
| 353 | y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; | ||
| 354 | } | ||
| 355 | |||
| 356 | /* Show the current progress */ | ||
| 357 | SDL_SetRenderDrawColor(renderer, 0, 255, 0, SDL_ALPHA_OPAQUE); | ||
| 358 | rect.x = x; | ||
| 359 | rect.y = y; | ||
| 360 | rect.w = ((float)(progress - text) / (end - text)) * (cols * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE); | ||
| 361 | rect.h = (float)SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; | ||
| 362 | SDL_RenderFillRect(renderer, &rect); | ||
| 363 | |||
| 364 | SDL_RenderPresent(renderer); | ||
| 365 | |||
| 366 | return SDL_APP_CONTINUE; /* carry on with the program! */ | ||
| 367 | } | ||
| 368 | |||
| 369 | /* This function runs once at shutdown. */ | ||
| 370 | void SDL_AppQuit(void *appstate, SDL_AppResult result) | ||
| 371 | { | ||
| 372 | /* SDL will clean up the window/renderer for us. */ | ||
| 373 | |||
| 374 | FreeLines(); | ||
| 375 | SDL_free(text); | ||
| 376 | } | ||
| 377 | |||
