summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys')
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/README.txt7
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/infinite-monkeys.c377
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/onmouseover.webpbin0 -> 95578 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/thumbnail.pngbin0 -> 7740 bytes
4 files changed, 384 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/README.txt b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/README.txt
new file mode 100644
index 0000000..3a80b69
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/README.txt
@@ -0,0 +1,7 @@
1
2How many monkeys does it take to write the complete works of Shakespeare?
3
4 Now you can find out!
5
6Cheer on your favorite monkey as they bash keyboards on their way through classic literature.
7
diff --git a/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/infinite-monkeys.c b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/infinite-monkeys.c
new file mode 100644
index 0000000..a8bfad1
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/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. */
10static SDL_Window *window = NULL;
11static SDL_Renderer *renderer = NULL;
12static char *text;
13static const char *end;
14static const char *progress;
15static SDL_Time start_time;
16static SDL_Time end_time;
17typedef struct {
18 Uint32 *text;
19 int length;
20} Line;
21int row = 0;
22int rows = 0;
23int cols = 0;
24static Line **lines;
25static Line monkey_chars;
26static 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
32static 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
71static 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
87static 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. */
131SDL_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. */
182SDL_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
194static 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
212static 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
226static void AdvanceRow(void)
227{
228 Line *line;
229
230 ++row;
231 line = lines[row % rows];
232 line->length = 0;
233}
234
235static 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
256static 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
272static 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. */
282SDL_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. */
370void 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
diff --git a/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/onmouseover.webp b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/onmouseover.webp
new file mode 100644
index 0000000..f522974
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/onmouseover.webp
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/thumbnail.png b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/thumbnail.png
new file mode 100644
index 0000000..418390b
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/thumbnail.png
Binary files differ