123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /*
- * This code is public domain. Feel free to use it for any purpose!
- */
- #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
- #include <SDL3/SDL.h>
- #include <SDL3/SDL_main.h>
- /* We will use this renderer to draw into this window every frame. */
- static SDL_Window *window = NULL;
- static SDL_Renderer *renderer = NULL;
- static char *text;
- static const char *end;
- static const char *progress;
- static SDL_Time start_time;
- static SDL_Time end_time;
- typedef struct {
- Uint32 *text;
- int length;
- } Line;
- int row = 0;
- int rows = 0;
- int cols = 0;
- static Line **lines;
- static Line monkey_chars;
- static int monkeys = 100;
- /* The highest and lowest scancodes a monkey can hit */
- #define MIN_MONKEY_SCANCODE SDL_SCANCODE_A
- #define MAX_MONKEY_SCANCODE SDL_SCANCODE_SLASH
- static const char *default_text =
- "Jabberwocky, by Lewis Carroll\n"
- "\n"
- "'Twas brillig, and the slithy toves\n"
- " Did gyre and gimble in the wabe:\n"
- "All mimsy were the borogoves,\n"
- " And the mome raths outgrabe.\n"
- "\n"
- "\"Beware the Jabberwock, my son!\n"
- " The jaws that bite, the claws that catch!\n"
- "Beware the Jubjub bird, and shun\n"
- " The frumious Bandersnatch!\"\n"
- "\n"
- "He took his vorpal sword in hand;\n"
- " Long time the manxome foe he sought-\n"
- "So rested he by the Tumtum tree\n"
- " And stood awhile in thought.\n"
- "\n"
- "And, as in uffish thought he stood,\n"
- " The Jabberwock, with eyes of flame,\n"
- "Came whiffling through the tulgey wood,\n"
- " And burbled as it came!\n"
- "\n"
- "One, two! One, two! And through and through\n"
- " The vorpal blade went snicker-snack!\n"
- "He left it dead, and with its head\n"
- " He went galumphing back.\n"
- "\n"
- "\"And hast thou slain the Jabberwock?\n"
- " Come to my arms, my beamish boy!\n"
- "O frabjous day! Callooh! Callay!\"\n"
- " He chortled in his joy.\n"
- "\n"
- "'Twas brillig, and the slithy toves\n"
- " Did gyre and gimble in the wabe:\n"
- "All mimsy were the borogoves,\n"
- " And the mome raths outgrabe.\n";
- static void FreeLines(void)
- {
- int i;
- if (rows > 0 && cols > 0) {
- for (i = 0; i < rows; ++i) {
- SDL_free(lines[i]->text);
- SDL_free(lines[i]);
- }
- SDL_free(lines);
- lines = NULL;
- }
- SDL_free(monkey_chars.text);
- monkey_chars.text = NULL;
- }
- static void OnWindowSizeChanged(void)
- {
- int w, h;
- if (!SDL_GetCurrentRenderOutputSize(renderer, &w, &h)) {
- return;
- }
- FreeLines();
- row = 0;
- rows = (h / SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) - 4;
- cols = (w / SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE);
- if (rows > 0 && cols > 0) {
- int i;
- lines = (Line **)SDL_malloc(rows * sizeof(Line *));
- if (lines) {
- for (i = 0; i < rows; ++i) {
- lines[i] = (Line *)SDL_malloc(sizeof(Line));
- if (!lines[i]) {
- FreeLines();
- break;
- }
- lines[i]->text = (Uint32 *)SDL_malloc(cols * sizeof(Uint32));
- if (!lines[i]->text) {
- FreeLines();
- break;
- }
- lines[i]->length = 0;
- }
- }
- monkey_chars.text = (Uint32 *)SDL_malloc(cols * sizeof(Uint32));
- if (monkey_chars.text) {
- for (i = 0; i < cols; ++i) {
- monkey_chars.text[i] = ' ';
- }
- monkey_chars.length = cols;
- }
- }
- }
- /* This function runs once at startup. */
- SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
- {
- int arg = 1;
- SDL_SetAppMetadata("Infinite Monkeys", "1.0", "com.example.infinite-monkeys");
- if (!SDL_Init(SDL_INIT_VIDEO)) {
- SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
- return SDL_APP_FAILURE;
- }
- if (!SDL_CreateWindowAndRenderer("examples/demo/infinite-monkeys", 640, 480, 0, &window, &renderer)) {
- SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
- return SDL_APP_FAILURE;
- }
- SDL_SetRenderVSync(renderer, 1);
- if (argv[arg] && SDL_strcmp(argv[arg], "--monkeys") == 0) {
- ++arg;
- if (argv[arg]) {
- monkeys = SDL_atoi(argv[arg]);
- ++arg;
- } else {
- SDL_Log("Usage: %s [--monkeys N] [file.txt]", argv[0]);
- return SDL_APP_FAILURE;
- }
- }
- if (argv[arg]) {
- const char *file = argv[arg];
- size_t size;
- text = (char *)SDL_LoadFile(file, &size);
- if (!text) {
- SDL_Log("Couldn't open %s: %s", file, SDL_GetError());
- return SDL_APP_FAILURE;
- }
- end = text + size;
- } else {
- text = SDL_strdup(default_text);
- end = text + SDL_strlen(text);
- }
- progress = text;
- SDL_GetCurrentTime(&start_time);
- OnWindowSizeChanged();
- return SDL_APP_CONTINUE; /* carry on with the program! */
- }
- /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
- SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
- {
- switch (event->type) {
- case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
- OnWindowSizeChanged();
- break;
- case SDL_EVENT_QUIT:
- return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
- }
- return SDL_APP_CONTINUE; /* carry on with the program! */
- }
- static void DisplayLine(float x, float y, Line *line)
- {
- /* Allocate maximum space potentially needed for this line */
- char *utf8 = (char *)SDL_malloc(line->length * 4 + 1);
- if (utf8) {
- char *spot = utf8;
- int i;
- for (i = 0; i < line->length; ++i) {
- spot = SDL_UCS4ToUTF8(line->text[i], spot);
- }
- *spot = '\0';
- SDL_RenderDebugText(renderer, x, y, utf8);
- SDL_free(utf8);
- }
- }
- static bool CanMonkeyType(Uint32 ch)
- {
- SDL_Keymod modstate;
- SDL_Scancode scancode = SDL_GetScancodeFromKey(ch, &modstate);
- if (scancode < MIN_MONKEY_SCANCODE || scancode > MAX_MONKEY_SCANCODE) {
- return false;
- }
- /* Monkeys can hit the shift key, but nothing else */
- if ((modstate & ~SDL_KMOD_SHIFT) != 0) {
- return false;
- }
- return true;
- }
- static void AdvanceRow(void)
- {
- Line *line;
- ++row;
- line = lines[row % rows];
- line->length = 0;
- }
- static void AddMonkeyChar(int monkey, Uint32 ch)
- {
- if (monkey >= 0 && monkey_chars.text) {
- monkey_chars.text[(monkey % cols)] = ch;
- }
- if (lines) {
- if (ch == '\n') {
- AdvanceRow();
- } else {
- Line *line = lines[row % rows];
- line->text[line->length++] = ch;
- if (line->length == cols) {
- AdvanceRow();
- }
- }
- }
- SDL_StepUTF8(&progress, NULL);
- }
- static Uint32 GetNextChar(void)
- {
- Uint32 ch = 0;
- while (progress < end) {
- const char *spot = progress;
- ch = SDL_StepUTF8(&spot, NULL);
- if (CanMonkeyType(ch)) {
- break;
- } else {
- /* This is a freebie, monkeys can't type this */
- AddMonkeyChar(-1, ch);
- }
- }
- return ch;
- }
- static Uint32 MonkeyPlay(void)
- {
- int count = (MAX_MONKEY_SCANCODE - MIN_MONKEY_SCANCODE + 1);
- SDL_Scancode scancode = (SDL_Scancode)(MIN_MONKEY_SCANCODE + SDL_rand(count));
- SDL_Keymod modstate = (SDL_rand(2) ? SDL_KMOD_SHIFT : 0);
- return SDL_GetKeyFromScancode(scancode, modstate, false);
- }
- /* This function runs once per frame, and is the heart of the program. */
- SDL_AppResult SDL_AppIterate(void *appstate)
- {
- int i, monkey;
- Uint32 next_char = 0, ch;
- float x, y;
- char *caption = NULL;
- SDL_Time now, elapsed;
- int hours, minutes, seconds;
- SDL_FRect rect;
- for (monkey = 0; monkey < monkeys; ++monkey) {
- if (next_char == 0) {
- next_char = GetNextChar();
- if (!next_char) {
- /* All done! */
- break;
- }
- }
- ch = MonkeyPlay();
- if (ch == next_char) {
- AddMonkeyChar(monkey, ch);
- next_char = 0;
- }
- }
- /* Clear the screen */
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
- SDL_RenderClear(renderer);
- /* Show the text already decoded */
- SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
- x = 0.0f;
- y = 0.0f;
- if (lines) {
- int row_offset = row - rows + 1;
- if (row_offset < 0) {
- row_offset = 0;
- }
- for (i = 0; i < rows; ++i) {
- Line *line = lines[(row_offset + i) % rows];
- DisplayLine(x, y, line);
- y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
- }
- /* Show the caption */
- y = (float)((rows + 1) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE);
- if (progress == end) {
- if (!end_time) {
- SDL_GetCurrentTime(&end_time);
- }
- now = end_time;
- } else {
- SDL_GetCurrentTime(&now);
- }
- elapsed = (now - start_time);
- elapsed /= SDL_NS_PER_SECOND;
- seconds = (int)(elapsed % 60);
- elapsed /= 60;
- minutes = (int)(elapsed % 60);
- elapsed /= 60;
- hours = (int)elapsed;
- SDL_asprintf(&caption, "Monkeys: %d - %dH:%dM:%dS", monkeys, hours, minutes, seconds);
- if (caption) {
- SDL_RenderDebugText(renderer, x, y, caption);
- SDL_free(caption);
- }
- y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
- /* Show the characters currently typed */
- DisplayLine(x, y, &monkey_chars);
- y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
- }
- /* Show the current progress */
- SDL_SetRenderDrawColor(renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
- rect.x = x;
- rect.y = y;
- rect.w = ((float)(progress - text) / (end - text)) * (cols * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE);
- rect.h = (float)SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
- SDL_RenderFillRect(renderer, &rect);
- SDL_RenderPresent(renderer);
- return SDL_APP_CONTINUE; /* carry on with the program! */
- }
- /* This function runs once at shutdown. */
- void SDL_AppQuit(void *appstate, SDL_AppResult result)
- {
- /* SDL will clean up the window/renderer for us. */
- FreeLines();
- SDL_free(text);
- }
|