summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/examples/demo
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/SDL-3.2.20/examples/demo')
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/01-snake/README.txt1
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/01-snake/onmouseover.webpbin0 -> 30996 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/01-snake/snake.c350
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/01-snake/thumbnail.pngbin0 -> 2958 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/README.txt1
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/onmouseover.webpbin0 -> 468022 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/thumbnail.pngbin0 -> 25191 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c480
-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
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/README.txt4
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/bytepusher.c416
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/onmouseover.webpbin0 -> 430096 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/thumbnail.pngbin0 -> 23851 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/description.txt1
17 files changed, 1637 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/examples/demo/01-snake/README.txt b/src/contrib/SDL-3.2.20/examples/demo/01-snake/README.txt
new file mode 100644
index 0000000..1cf9784
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/01-snake/README.txt
@@ -0,0 +1 @@
A complete game of Snake, written in SDL.
diff --git a/src/contrib/SDL-3.2.20/examples/demo/01-snake/onmouseover.webp b/src/contrib/SDL-3.2.20/examples/demo/01-snake/onmouseover.webp
new file mode 100644
index 0000000..1757202
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/01-snake/onmouseover.webp
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/01-snake/snake.c b/src/contrib/SDL-3.2.20/examples/demo/01-snake/snake.c
new file mode 100644
index 0000000..0aca862
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/01-snake/snake.c
@@ -0,0 +1,350 @@
1/*
2 * Logic implementation of the Snake game. It is designed to efficiently
3 * represent the state of the game in memory.
4 *
5 * This code is public domain. Feel free to use it for any purpose!
6 */
7
8#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
9#include <SDL3/SDL.h>
10#include <SDL3/SDL_main.h>
11
12#define STEP_RATE_IN_MILLISECONDS 125
13#define SNAKE_BLOCK_SIZE_IN_PIXELS 24
14#define SDL_WINDOW_WIDTH (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_WIDTH)
15#define SDL_WINDOW_HEIGHT (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_HEIGHT)
16
17#define SNAKE_GAME_WIDTH 24U
18#define SNAKE_GAME_HEIGHT 18U
19#define SNAKE_MATRIX_SIZE (SNAKE_GAME_WIDTH * SNAKE_GAME_HEIGHT)
20
21#define THREE_BITS 0x7U /* ~CHAR_MAX >> (CHAR_BIT - SNAKE_CELL_MAX_BITS) */
22#define SHIFT(x, y) (((x) + ((y) * SNAKE_GAME_WIDTH)) * SNAKE_CELL_MAX_BITS)
23
24typedef enum
25{
26 SNAKE_CELL_NOTHING = 0U,
27 SNAKE_CELL_SRIGHT = 1U,
28 SNAKE_CELL_SUP = 2U,
29 SNAKE_CELL_SLEFT = 3U,
30 SNAKE_CELL_SDOWN = 4U,
31 SNAKE_CELL_FOOD = 5U
32} SnakeCell;
33
34#define SNAKE_CELL_MAX_BITS 3U /* floor(log2(SNAKE_CELL_FOOD)) + 1 */
35
36typedef enum
37{
38 SNAKE_DIR_RIGHT,
39 SNAKE_DIR_UP,
40 SNAKE_DIR_LEFT,
41 SNAKE_DIR_DOWN
42} SnakeDirection;
43
44typedef struct
45{
46 unsigned char cells[(SNAKE_MATRIX_SIZE * SNAKE_CELL_MAX_BITS) / 8U];
47 char head_xpos;
48 char head_ypos;
49 char tail_xpos;
50 char tail_ypos;
51 char next_dir;
52 char inhibit_tail_step;
53 unsigned occupied_cells;
54} SnakeContext;
55
56typedef struct
57{
58 SDL_Window *window;
59 SDL_Renderer *renderer;
60 SnakeContext snake_ctx;
61 Uint64 last_step;
62} AppState;
63
64SnakeCell snake_cell_at(const SnakeContext *ctx, char x, char y)
65{
66 const int shift = SHIFT(x, y);
67 unsigned short range;
68 SDL_memcpy(&range, ctx->cells + (shift / 8), sizeof(range));
69 return (SnakeCell)((range >> (shift % 8)) & THREE_BITS);
70}
71
72static void set_rect_xy_(SDL_FRect *r, short x, short y)
73{
74 r->x = (float)(x * SNAKE_BLOCK_SIZE_IN_PIXELS);
75 r->y = (float)(y * SNAKE_BLOCK_SIZE_IN_PIXELS);
76}
77
78static void put_cell_at_(SnakeContext *ctx, char x, char y, SnakeCell ct)
79{
80 const int shift = SHIFT(x, y);
81 const int adjust = shift % 8;
82 unsigned char *const pos = ctx->cells + (shift / 8);
83 unsigned short range;
84 SDL_memcpy(&range, pos, sizeof(range));
85 range &= ~(THREE_BITS << adjust); /* clear bits */
86 range |= (ct & THREE_BITS) << adjust;
87 SDL_memcpy(pos, &range, sizeof(range));
88}
89
90static int are_cells_full_(SnakeContext *ctx)
91{
92 return ctx->occupied_cells == SNAKE_GAME_WIDTH * SNAKE_GAME_HEIGHT;
93}
94
95static void new_food_pos_(SnakeContext *ctx)
96{
97 while (true) {
98 const char x = (char) SDL_rand(SNAKE_GAME_WIDTH);
99 const char y = (char) SDL_rand(SNAKE_GAME_HEIGHT);
100 if (snake_cell_at(ctx, x, y) == SNAKE_CELL_NOTHING) {
101 put_cell_at_(ctx, x, y, SNAKE_CELL_FOOD);
102 break;
103 }
104 }
105}
106
107void snake_initialize(SnakeContext *ctx)
108{
109 int i;
110 SDL_zeroa(ctx->cells);
111 ctx->head_xpos = ctx->tail_xpos = SNAKE_GAME_WIDTH / 2;
112 ctx->head_ypos = ctx->tail_ypos = SNAKE_GAME_HEIGHT / 2;
113 ctx->next_dir = SNAKE_DIR_RIGHT;
114 ctx->inhibit_tail_step = ctx->occupied_cells = 4;
115 --ctx->occupied_cells;
116 put_cell_at_(ctx, ctx->tail_xpos, ctx->tail_ypos, SNAKE_CELL_SRIGHT);
117 for (i = 0; i < 4; i++) {
118 new_food_pos_(ctx);
119 ++ctx->occupied_cells;
120 }
121}
122
123void snake_redir(SnakeContext *ctx, SnakeDirection dir)
124{
125 SnakeCell ct = snake_cell_at(ctx, ctx->head_xpos, ctx->head_ypos);
126 if ((dir == SNAKE_DIR_RIGHT && ct != SNAKE_CELL_SLEFT) ||
127 (dir == SNAKE_DIR_UP && ct != SNAKE_CELL_SDOWN) ||
128 (dir == SNAKE_DIR_LEFT && ct != SNAKE_CELL_SRIGHT) ||
129 (dir == SNAKE_DIR_DOWN && ct != SNAKE_CELL_SUP)) {
130 ctx->next_dir = dir;
131 }
132}
133
134static void wrap_around_(char *val, char max)
135{
136 if (*val < 0) {
137 *val = max - 1;
138 } else if (*val > max - 1) {
139 *val = 0;
140 }
141}
142
143void snake_step(SnakeContext *ctx)
144{
145 const SnakeCell dir_as_cell = (SnakeCell)(ctx->next_dir + 1);
146 SnakeCell ct;
147 char prev_xpos;
148 char prev_ypos;
149 /* Move tail forward */
150 if (--ctx->inhibit_tail_step == 0) {
151 ++ctx->inhibit_tail_step;
152 ct = snake_cell_at(ctx, ctx->tail_xpos, ctx->tail_ypos);
153 put_cell_at_(ctx, ctx->tail_xpos, ctx->tail_ypos, SNAKE_CELL_NOTHING);
154 switch (ct) {
155 case SNAKE_CELL_SRIGHT:
156 ctx->tail_xpos++;
157 break;
158 case SNAKE_CELL_SUP:
159 ctx->tail_ypos--;
160 break;
161 case SNAKE_CELL_SLEFT:
162 ctx->tail_xpos--;
163 break;
164 case SNAKE_CELL_SDOWN:
165 ctx->tail_ypos++;
166 break;
167 default:
168 break;
169 }
170 wrap_around_(&ctx->tail_xpos, SNAKE_GAME_WIDTH);
171 wrap_around_(&ctx->tail_ypos, SNAKE_GAME_HEIGHT);
172 }
173 /* Move head forward */
174 prev_xpos = ctx->head_xpos;
175 prev_ypos = ctx->head_ypos;
176 switch (ctx->next_dir) {
177 case SNAKE_DIR_RIGHT:
178 ++ctx->head_xpos;
179 break;
180 case SNAKE_DIR_UP:
181 --ctx->head_ypos;
182 break;
183 case SNAKE_DIR_LEFT:
184 --ctx->head_xpos;
185 break;
186 case SNAKE_DIR_DOWN:
187 ++ctx->head_ypos;
188 break;
189 }
190 wrap_around_(&ctx->head_xpos, SNAKE_GAME_WIDTH);
191 wrap_around_(&ctx->head_ypos, SNAKE_GAME_HEIGHT);
192 /* Collisions */
193 ct = snake_cell_at(ctx, ctx->head_xpos, ctx->head_ypos);
194 if (ct != SNAKE_CELL_NOTHING && ct != SNAKE_CELL_FOOD) {
195 snake_initialize(ctx);
196 return;
197 }
198 put_cell_at_(ctx, prev_xpos, prev_ypos, dir_as_cell);
199 put_cell_at_(ctx, ctx->head_xpos, ctx->head_ypos, dir_as_cell);
200 if (ct == SNAKE_CELL_FOOD) {
201 if (are_cells_full_(ctx)) {
202 snake_initialize(ctx);
203 return;
204 }
205 new_food_pos_(ctx);
206 ++ctx->inhibit_tail_step;
207 ++ctx->occupied_cells;
208 }
209}
210
211static SDL_AppResult handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
212{
213 switch (key_code) {
214 /* Quit. */
215 case SDL_SCANCODE_ESCAPE:
216 case SDL_SCANCODE_Q:
217 return SDL_APP_SUCCESS;
218 /* Restart the game as if the program was launched. */
219 case SDL_SCANCODE_R:
220 snake_initialize(ctx);
221 break;
222 /* Decide new direction of the snake. */
223 case SDL_SCANCODE_RIGHT:
224 snake_redir(ctx, SNAKE_DIR_RIGHT);
225 break;
226 case SDL_SCANCODE_UP:
227 snake_redir(ctx, SNAKE_DIR_UP);
228 break;
229 case SDL_SCANCODE_LEFT:
230 snake_redir(ctx, SNAKE_DIR_LEFT);
231 break;
232 case SDL_SCANCODE_DOWN:
233 snake_redir(ctx, SNAKE_DIR_DOWN);
234 break;
235 default:
236 break;
237 }
238 return SDL_APP_CONTINUE;
239}
240
241SDL_AppResult SDL_AppIterate(void *appstate)
242{
243 AppState *as = (AppState *)appstate;
244 SnakeContext *ctx = &as->snake_ctx;
245 const Uint64 now = SDL_GetTicks();
246 SDL_FRect r;
247 unsigned i;
248 unsigned j;
249 int ct;
250
251 // run game logic if we're at or past the time to run it.
252 // if we're _really_ behind the time to run it, run it
253 // several times.
254 while ((now - as->last_step) >= STEP_RATE_IN_MILLISECONDS) {
255 snake_step(ctx);
256 as->last_step += STEP_RATE_IN_MILLISECONDS;
257 }
258
259 r.w = r.h = SNAKE_BLOCK_SIZE_IN_PIXELS;
260 SDL_SetRenderDrawColor(as->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
261 SDL_RenderClear(as->renderer);
262 for (i = 0; i < SNAKE_GAME_WIDTH; i++) {
263 for (j = 0; j < SNAKE_GAME_HEIGHT; j++) {
264 ct = snake_cell_at(ctx, i, j);
265 if (ct == SNAKE_CELL_NOTHING)
266 continue;
267 set_rect_xy_(&r, i, j);
268 if (ct == SNAKE_CELL_FOOD)
269 SDL_SetRenderDrawColor(as->renderer, 80, 80, 255, SDL_ALPHA_OPAQUE);
270 else /* body */
271 SDL_SetRenderDrawColor(as->renderer, 0, 128, 0, SDL_ALPHA_OPAQUE);
272 SDL_RenderFillRect(as->renderer, &r);
273 }
274 }
275 SDL_SetRenderDrawColor(as->renderer, 255, 255, 0, SDL_ALPHA_OPAQUE); /*head*/
276 set_rect_xy_(&r, ctx->head_xpos, ctx->head_ypos);
277 SDL_RenderFillRect(as->renderer, &r);
278 SDL_RenderPresent(as->renderer);
279 return SDL_APP_CONTINUE;
280}
281
282static const struct
283{
284 const char *key;
285 const char *value;
286} extended_metadata[] =
287{
288 { SDL_PROP_APP_METADATA_URL_STRING, "https://examples.libsdl.org/SDL3/demo/01-snake/" },
289 { SDL_PROP_APP_METADATA_CREATOR_STRING, "SDL team" },
290 { SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Placed in the public domain" },
291 { SDL_PROP_APP_METADATA_TYPE_STRING, "game" }
292};
293
294SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
295{
296 size_t i;
297
298 if (!SDL_SetAppMetadata("Example Snake game", "1.0", "com.example.Snake")) {
299 return SDL_APP_FAILURE;
300 }
301
302 for (i = 0; i < SDL_arraysize(extended_metadata); i++) {
303 if (!SDL_SetAppMetadataProperty(extended_metadata[i].key, extended_metadata[i].value)) {
304 return SDL_APP_FAILURE;
305 }
306 }
307
308 if (!SDL_Init(SDL_INIT_VIDEO)) {
309 return SDL_APP_FAILURE;
310 }
311
312 AppState *as = (AppState *)SDL_calloc(1, sizeof(AppState));
313 if (!as) {
314 return SDL_APP_FAILURE;
315 }
316
317 *appstate = as;
318
319 if (!SDL_CreateWindowAndRenderer("examples/demo/snake", SDL_WINDOW_WIDTH, SDL_WINDOW_HEIGHT, 0, &as->window, &as->renderer)) {
320 return SDL_APP_FAILURE;
321 }
322
323 snake_initialize(&as->snake_ctx);
324
325 as->last_step = SDL_GetTicks();
326
327 return SDL_APP_CONTINUE;
328}
329
330SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
331{
332 SnakeContext *ctx = &((AppState *)appstate)->snake_ctx;
333 switch (event->type) {
334 case SDL_EVENT_QUIT:
335 return SDL_APP_SUCCESS;
336 case SDL_EVENT_KEY_DOWN:
337 return handle_key_event_(ctx, event->key.scancode);
338 }
339 return SDL_APP_CONTINUE;
340}
341
342void SDL_AppQuit(void *appstate, SDL_AppResult result)
343{
344 if (appstate != NULL) {
345 AppState *as = (AppState *)appstate;
346 SDL_DestroyRenderer(as->renderer);
347 SDL_DestroyWindow(as->window);
348 SDL_free(as);
349 }
350}
diff --git a/src/contrib/SDL-3.2.20/examples/demo/01-snake/thumbnail.png b/src/contrib/SDL-3.2.20/examples/demo/01-snake/thumbnail.png
new file mode 100644
index 0000000..f0e27c5
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/01-snake/thumbnail.png
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/README.txt b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/README.txt
new file mode 100644
index 0000000..83de3e3
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/README.txt
@@ -0,0 +1 @@
Minimal splitscreen FPS with multiple mouse and keyboards, drawn with the 2D Render API. \ No newline at end of file
diff --git a/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/onmouseover.webp b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/onmouseover.webp
new file mode 100644
index 0000000..2e7f44f
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/onmouseover.webp
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/thumbnail.png b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/thumbnail.png
new file mode 100644
index 0000000..c8d1efa
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/thumbnail.png
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c
new file mode 100644
index 0000000..b97b06a
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c
@@ -0,0 +1,480 @@
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#define MAP_BOX_SCALE 16
10#define MAP_BOX_EDGES_LEN (12 + MAP_BOX_SCALE * 2)
11#define MAX_PLAYER_COUNT 4
12#define CIRCLE_DRAW_SIDES 32
13#define CIRCLE_DRAW_SIDES_LEN (CIRCLE_DRAW_SIDES + 1)
14
15typedef struct {
16 SDL_MouseID mouse;
17 SDL_KeyboardID keyboard;
18 double pos[3];
19 double vel[3];
20 unsigned int yaw;
21 int pitch;
22 float radius, height;
23 unsigned char color[3];
24 unsigned char wasd;
25} Player;
26
27typedef struct {
28 SDL_Window *window;
29 SDL_Renderer *renderer;
30 int player_count;
31 Player players[MAX_PLAYER_COUNT];
32 float edges[MAP_BOX_EDGES_LEN][6];
33} AppState;
34
35static const struct {
36 const char *key;
37 const char *value;
38} extended_metadata[] = {
39 { SDL_PROP_APP_METADATA_URL_STRING, "https://examples.libsdl.org/SDL3/demo/02-woodeneye-008/" },
40 { SDL_PROP_APP_METADATA_CREATOR_STRING, "SDL team" },
41 { SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Placed in the public domain" },
42 { SDL_PROP_APP_METADATA_TYPE_STRING, "game" }
43};
44
45static int whoseMouse(SDL_MouseID mouse, const Player players[], int players_len)
46{
47 int i;
48 for (i = 0; i < players_len; i++) {
49 if (players[i].mouse == mouse) return i;
50 }
51 return -1;
52}
53
54static int whoseKeyboard(SDL_KeyboardID keyboard, const Player players[], int players_len)
55{
56 int i;
57 for (i = 0; i < players_len; i++) {
58 if (players[i].keyboard == keyboard) return i;
59 }
60 return -1;
61}
62
63static void shoot(int shooter, Player players[], int players_len)
64{
65 int i, j;
66 double x0 = players[shooter].pos[0];
67 double y0 = players[shooter].pos[1];
68 double z0 = players[shooter].pos[2];
69 double bin_rad = SDL_PI_D / 2147483648.0;
70 double yaw_rad = bin_rad * players[shooter].yaw;
71 double pitch_rad = bin_rad * players[shooter].pitch;
72 double cos_yaw = SDL_cos( yaw_rad);
73 double sin_yaw = SDL_sin( yaw_rad);
74 double cos_pitch = SDL_cos(pitch_rad);
75 double sin_pitch = SDL_sin(pitch_rad);
76 double vx = -sin_yaw*cos_pitch;
77 double vy = sin_pitch;
78 double vz = -cos_yaw*cos_pitch;
79 for (i = 0; i < players_len; i++) {
80 if (i == shooter) continue;
81 Player *target = &(players[i]);
82 int hit = 0;
83 for (j = 0; j < 2; j++) {
84 double r = target->radius;
85 double h = target->height;
86 double dx = target->pos[0] - x0;
87 double dy = target->pos[1] - y0 + (j == 0 ? 0 : r - h);
88 double dz = target->pos[2] - z0;
89 double vd = vx*dx + vy*dy + vz*dz;
90 double dd = dx*dx + dy*dy + dz*dz;
91 double vv = vx*vx + vy*vy + vz*vz;
92 double rr = r * r;
93 if (vd < 0) continue;
94 if (vd * vd >= vv * (dd - rr)) hit += 1;
95 }
96 if (hit) {
97 target->pos[0] = (double)(MAP_BOX_SCALE * (SDL_rand(256) - 128)) / 256;
98 target->pos[1] = (double)(MAP_BOX_SCALE * (SDL_rand(256) - 128)) / 256;
99 target->pos[2] = (double)(MAP_BOX_SCALE * (SDL_rand(256) - 128)) / 256;
100 }
101 }
102}
103
104static void update(Player *players, int players_len, Uint64 dt_ns)
105{
106 int i;
107 for (i = 0; i < players_len; i++) {
108 Player *player = &players[i];
109 double rate = 6.0;
110 double time = (double)dt_ns * 1e-9;
111 double drag = SDL_exp(-time * rate);
112 double diff = 1.0 - drag;
113 double mult = 60.0;
114 double grav = 25.0;
115 double yaw = (double)player->yaw;
116 double rad = yaw * SDL_PI_D / 2147483648.0;
117 double cos = SDL_cos(rad);
118 double sin = SDL_sin(rad);
119 unsigned char wasd = player->wasd;
120 double dirX = (wasd & 8 ? 1.0 : 0.0) - (wasd & 2 ? 1.0 : 0.0);
121 double dirZ = (wasd & 4 ? 1.0 : 0.0) - (wasd & 1 ? 1.0 : 0.0);
122 double norm = dirX * dirX + dirZ * dirZ;
123 double accX = mult * (norm == 0 ? 0 : ( cos*dirX + sin*dirZ) / SDL_sqrt(norm));
124 double accZ = mult * (norm == 0 ? 0 : (-sin*dirX + cos*dirZ) / SDL_sqrt(norm));
125 double velX = player->vel[0];
126 double velY = player->vel[1];
127 double velZ = player->vel[2];
128 player->vel[0] -= velX * diff;
129 player->vel[1] -= grav * time;
130 player->vel[2] -= velZ * diff;
131 player->vel[0] += diff * accX / rate;
132 player->vel[2] += diff * accZ / rate;
133 player->pos[0] += (time - diff/rate) * accX / rate + diff * velX / rate;
134 player->pos[1] += -0.5 * grav * time * time + velY * time;
135 player->pos[2] += (time - diff/rate) * accZ / rate + diff * velZ / rate;
136 double scale = (double)MAP_BOX_SCALE;
137 double bound = scale - player->radius;
138 double posX = SDL_max(SDL_min(bound, player->pos[0]), -bound);
139 double posY = SDL_max(SDL_min(bound, player->pos[1]), player->height - scale);
140 double posZ = SDL_max(SDL_min(bound, player->pos[2]), -bound);
141 if (player->pos[0] != posX) player->vel[0] = 0;
142 if (player->pos[1] != posY) player->vel[1] = (wasd & 16) ? 8.4375 : 0;
143 if (player->pos[2] != posZ) player->vel[2] = 0;
144 player->pos[0] = posX;
145 player->pos[1] = posY;
146 player->pos[2] = posZ;
147 }
148}
149
150static void drawCircle(SDL_Renderer *renderer, float r, float x, float y)
151{
152 float ang;
153 SDL_FPoint points[CIRCLE_DRAW_SIDES_LEN];
154 int i;
155 for (i = 0; i < CIRCLE_DRAW_SIDES_LEN; i++) {
156 ang = 2.0f * SDL_PI_F * (float)i / (float)CIRCLE_DRAW_SIDES;
157 points[i].x = x + r * SDL_cosf(ang);
158 points[i].y = y + r * SDL_sinf(ang);
159 }
160 SDL_RenderLines(renderer, (const SDL_FPoint*)&points, CIRCLE_DRAW_SIDES_LEN);
161}
162
163static void drawClippedSegment(
164 SDL_Renderer *renderer,
165 float ax, float ay, float az,
166 float bx, float by, float bz,
167 float x, float y, float z, float w)
168{
169 if (az >= -w && bz >= -w) return;
170 float dx = ax - bx;
171 float dy = ay - by;
172 if (az > -w) {
173 float t = (-w - bz) / (az - bz);
174 ax = bx + dx * t;
175 ay = by + dy * t;
176 az = -w;
177 } else if (bz > -w) {
178 float t = (-w - az) / (bz - az);
179 bx = ax - dx * t;
180 by = ay - dy * t;
181 bz = -w;
182 }
183 ax = -z * ax / az;
184 ay = -z * ay / az;
185 bx = -z * bx / bz;
186 by = -z * by / bz;
187 SDL_RenderLine(renderer, x + ax, y - ay, x + bx, y - by);
188}
189
190static char debug_string[32];
191static void draw(SDL_Renderer *renderer, const float (*edges)[6], const Player players[], int players_len)
192{
193 int w, h, i, j, k;
194 if (!SDL_GetRenderOutputSize(renderer, &w, &h)) {
195 return;
196 }
197 SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
198 SDL_RenderClear(renderer);
199 if (players_len > 0) {
200 float wf = (float)w;
201 float hf = (float)h;
202 int part_hor = players_len > 2 ? 2 : 1;
203 int part_ver = players_len > 1 ? 2 : 1;
204 float size_hor = wf / ((float)part_hor);
205 float size_ver = hf / ((float)part_ver);
206 for (i = 0; i < players_len; i++) {
207 const Player *player = &players[i];
208 float mod_x = (float)(i % part_hor);
209 float mod_y = (float)(i / part_hor);
210 float hor_origin = (mod_x + 0.5f) * size_hor;
211 float ver_origin = (mod_y + 0.5f) * size_ver;
212 float cam_origin = (float)(0.5 * SDL_sqrt(size_hor * size_hor + size_ver * size_ver));
213 float hor_offset = mod_x * size_hor;
214 float ver_offset = mod_y * size_ver;
215 SDL_Rect rect;
216 rect.x = (int)hor_offset;
217 rect.y = (int)ver_offset;
218 rect.w = (int)size_hor;
219 rect.h = (int)size_ver;
220 SDL_SetRenderClipRect(renderer, &rect);
221 double x0 = player->pos[0];
222 double y0 = player->pos[1];
223 double z0 = player->pos[2];
224 double bin_rad = SDL_PI_D / 2147483648.0;
225 double yaw_rad = bin_rad * player->yaw;
226 double pitch_rad = bin_rad * player->pitch;
227 double cos_yaw = SDL_cos( yaw_rad);
228 double sin_yaw = SDL_sin( yaw_rad);
229 double cos_pitch = SDL_cos(pitch_rad);
230 double sin_pitch = SDL_sin(pitch_rad);
231 double mat[9] = {
232 cos_yaw , 0, -sin_yaw ,
233 sin_yaw*sin_pitch, cos_pitch, cos_yaw*sin_pitch,
234 sin_yaw*cos_pitch, -sin_pitch, cos_yaw*cos_pitch
235 };
236 SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
237 for (k = 0; k < MAP_BOX_EDGES_LEN; k++) {
238 const float *line = edges[k];
239 float ax = (float)(mat[0] * (line[0] - x0) + mat[1] * (line[1] - y0) + mat[2] * (line[2] - z0));
240 float ay = (float)(mat[3] * (line[0] - x0) + mat[4] * (line[1] - y0) + mat[5] * (line[2] - z0));
241 float az = (float)(mat[6] * (line[0] - x0) + mat[7] * (line[1] - y0) + mat[8] * (line[2] - z0));
242 float bx = (float)(mat[0] * (line[3] - x0) + mat[1] * (line[4] - y0) + mat[2] * (line[5] - z0));
243 float by = (float)(mat[3] * (line[3] - x0) + mat[4] * (line[4] - y0) + mat[5] * (line[5] - z0));
244 float bz = (float)(mat[6] * (line[3] - x0) + mat[7] * (line[4] - y0) + mat[8] * (line[5] - z0));
245 drawClippedSegment(renderer, ax, ay, az, bx, by, bz, hor_origin, ver_origin, cam_origin, 1);
246 }
247 for (j = 0; j < players_len; j++) {
248 if (i == j) continue;
249 const Player *target = &players[j];
250 SDL_SetRenderDrawColor(renderer, target->color[0], target->color[1], target->color[2], 255);
251 for (k = 0; k < 2; k++) {
252 double rx = target->pos[0] - player->pos[0];
253 double ry = target->pos[1] - player->pos[1] + (target->radius - target->height) * (float)k;
254 double rz = target->pos[2] - player->pos[2];
255 double dx = mat[0] * rx + mat[1] * ry + mat[2] * rz;
256 double dy = mat[3] * rx + mat[4] * ry + mat[5] * rz;
257 double dz = mat[6] * rx + mat[7] * ry + mat[8] * rz;
258 double r_eff = target->radius * cam_origin / dz;
259 if (!(dz < 0)) continue;
260 drawCircle(renderer, (float)(r_eff), (float)(hor_origin - cam_origin*dx/dz), (float)(ver_origin + cam_origin*dy/dz));
261 }
262 }
263 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
264 SDL_RenderLine(renderer, hor_origin, ver_origin-10, hor_origin, ver_origin+10);
265 SDL_RenderLine(renderer, hor_origin-10, ver_origin, hor_origin+10, ver_origin);
266 }
267 }
268 SDL_SetRenderClipRect(renderer, 0);
269 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
270 SDL_RenderDebugText(renderer, 0, 0, debug_string);
271 SDL_RenderPresent(renderer);
272}
273
274static void initPlayers(Player *players, int len)
275{
276 int i;
277 for (i = 0; i < len; i++) {
278 players[i].pos[0] = 8.0 * (i & 1 ? -1.0 : 1.0);
279 players[i].pos[1] = 0;
280 players[i].pos[2] = 8.0 * (i & 1 ? -1.0 : 1.0) * (i & 2 ? -1.0 : 1.0);
281 players[i].vel[0] = 0;
282 players[i].vel[1] = 0;
283 players[i].vel[2] = 0;
284 players[i].yaw = 0x20000000 + (i & 1 ? 0x80000000 : 0) + (i & 2 ? 0x40000000 : 0);
285 players[i].pitch = -0x08000000;
286 players[i].radius = 0.5f;
287 players[i].height = 1.5f;
288 players[i].wasd = 0;
289 players[i].mouse = 0;
290 players[i].keyboard = 0;
291 players[i].color[0] = (1 << (i / 2)) & 2 ? 0 : 0xff;
292 players[i].color[1] = (1 << (i / 2)) & 1 ? 0 : 0xff;
293 players[i].color[2] = (1 << (i / 2)) & 4 ? 0 : 0xff;
294 players[i].color[0] = (i & 1) ? players[i].color[0] : ~players[i].color[0];
295 players[i].color[1] = (i & 1) ? players[i].color[1] : ~players[i].color[1];
296 players[i].color[2] = (i & 1) ? players[i].color[2] : ~players[i].color[2];
297 }
298}
299
300static void initEdges(int scale, float (*edges)[6], int edges_len)
301{
302 int i, j;
303 const float r = (float)scale;
304 const int map[24] = {
305 0,1 , 1,3 , 3,2 , 2,0 ,
306 7,6 , 6,4 , 4,5 , 5,7 ,
307 6,2 , 3,7 , 0,4 , 5,1
308 };
309 for(i = 0; i < 12; i++) {
310 for (j = 0; j < 3; j++) {
311 edges[i][j+0] = (map[i*2+0] & (1 << j) ? r : -r);
312 edges[i][j+3] = (map[i*2+1] & (1 << j) ? r : -r);
313 }
314 }
315 for(i = 0; i < scale; i++) {
316 float d = (float)(i * 2);
317 for (j = 0; j < 2; j++) {
318 edges[i+12][3*j+0] = j ? r : -r;
319 edges[i+12][3*j+1] = -r;
320 edges[i+12][3*j+2] = d-r;
321 edges[i+12+scale][3*j+0] = d-r;
322 edges[i+12+scale][3*j+1] = -r;
323 edges[i+12+scale][3*j+2] = j ? r : -r;
324 }
325 }
326}
327
328SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
329{
330 if (!SDL_SetAppMetadata("Example splitscreen shooter game", "1.0", "com.example.woodeneye-008")) {
331 return SDL_APP_FAILURE;
332 }
333 int i;
334 for (i = 0; i < SDL_arraysize(extended_metadata); i++) {
335 if (!SDL_SetAppMetadataProperty(extended_metadata[i].key, extended_metadata[i].value)) {
336 return SDL_APP_FAILURE;
337 }
338 }
339
340 AppState *as = SDL_calloc(1, sizeof(AppState));
341 if (!as) {
342 return SDL_APP_FAILURE;
343 } else {
344 *appstate = as;
345 }
346
347 if (!SDL_Init(SDL_INIT_VIDEO)) {
348 return SDL_APP_FAILURE;
349 }
350 if (!SDL_CreateWindowAndRenderer("examples/demo/woodeneye-008", 640, 480, 0, &as->window, &as->renderer)) {
351 return SDL_APP_FAILURE;
352 }
353
354 as->player_count = 1;
355 initPlayers(as->players, MAX_PLAYER_COUNT);
356 initEdges(MAP_BOX_SCALE, as->edges, MAP_BOX_EDGES_LEN);
357 debug_string[0] = 0;
358
359 SDL_SetRenderVSync(as->renderer, false);
360 SDL_SetWindowRelativeMouseMode(as->window, true);
361 SDL_SetHintWithPriority(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1", SDL_HINT_OVERRIDE);
362 return SDL_APP_CONTINUE;
363}
364
365SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
366{
367 AppState *as = appstate;
368 Player *players = as->players;
369 int player_count = as->player_count;
370 int i;
371 switch (event->type) {
372 case SDL_EVENT_QUIT:
373 return SDL_APP_SUCCESS;
374 break;
375 case SDL_EVENT_MOUSE_REMOVED:
376 for (i = 0; i < player_count; i++) {
377 if (players[i].mouse == event->mdevice.which) {
378 players[i].mouse = 0;
379 }
380 }
381 break;
382 case SDL_EVENT_KEYBOARD_REMOVED:
383 for (i = 0; i < player_count; i++) {
384 if (players[i].keyboard == event->kdevice.which) {
385 players[i].keyboard = 0;
386 }
387 }
388 break;
389 case SDL_EVENT_MOUSE_MOTION: {
390 SDL_MouseID id = event->motion.which;
391 int index = whoseMouse(id, players, player_count);
392 if (index >= 0) {
393 players[index].yaw -= ((int)event->motion.xrel) * 0x00080000;
394 players[index].pitch = SDL_max(-0x40000000, SDL_min(0x40000000, players[index].pitch - ((int)event->motion.yrel) * 0x00080000));
395 } else if (id) {
396 for (i = 0; i < MAX_PLAYER_COUNT; i++) {
397 if (players[i].mouse == 0) {
398 players[i].mouse = id;
399 as->player_count = SDL_max(as->player_count, i + 1);
400 break;
401 }
402 }
403 }
404 break;
405 }
406 case SDL_EVENT_MOUSE_BUTTON_DOWN: {
407 SDL_MouseID id = event->button.which;
408 int index = whoseMouse(id, players, player_count);
409 if (index >= 0) {
410 shoot(index, players, player_count);
411 }
412 break;
413 }
414 case SDL_EVENT_KEY_DOWN: {
415 SDL_Keycode sym = event->key.key;
416 SDL_KeyboardID id = event->key.which;
417 int index = whoseKeyboard(id, players, player_count);
418 if (index >= 0) {
419 if (sym == SDLK_W) players[index].wasd |= 1;
420 if (sym == SDLK_A) players[index].wasd |= 2;
421 if (sym == SDLK_S) players[index].wasd |= 4;
422 if (sym == SDLK_D) players[index].wasd |= 8;
423 if (sym == SDLK_SPACE) players[index].wasd |= 16;
424 } else if (id) {
425 for (i = 0; i < MAX_PLAYER_COUNT; i++) {
426 if (players[i].keyboard == 0) {
427 players[i].keyboard = id;
428 as->player_count = SDL_max(as->player_count, i + 1);
429 break;
430 }
431 }
432 }
433 break;
434 }
435 case SDL_EVENT_KEY_UP: {
436 SDL_Keycode sym = event->key.key;
437 SDL_KeyboardID id = event->key.which;
438 if (sym == SDLK_ESCAPE) return SDL_APP_SUCCESS;
439 int index = whoseKeyboard(id, players, player_count);
440 if (index >= 0) {
441 if (sym == SDLK_W) players[index].wasd &= 30;
442 if (sym == SDLK_A) players[index].wasd &= 29;
443 if (sym == SDLK_S) players[index].wasd &= 27;
444 if (sym == SDLK_D) players[index].wasd &= 23;
445 if (sym == SDLK_SPACE) players[index].wasd &= 15;
446 }
447 break;
448 }
449 }
450 return SDL_APP_CONTINUE;
451}
452
453SDL_AppResult SDL_AppIterate(void *appstate)
454{
455 AppState *as = appstate;
456 static Uint64 accu = 0;
457 static Uint64 last = 0;
458 static Uint64 past = 0;
459 Uint64 now = SDL_GetTicksNS();
460 Uint64 dt_ns = now - past;
461 update(as->players, as->player_count, dt_ns);
462 draw(as->renderer, (const float (*)[6])as->edges, as->players, as->player_count);
463 if (now - last > 999999999) {
464 last = now;
465 SDL_snprintf(debug_string, sizeof(debug_string), "%" SDL_PRIu64 " fps", accu);
466 accu = 0;
467 }
468 past = now;
469 accu += 1;
470 Uint64 elapsed = SDL_GetTicksNS() - now;
471 if (elapsed < 999999) {
472 SDL_DelayNS(999999 - elapsed);
473 }
474 return SDL_APP_CONTINUE;
475}
476
477void SDL_AppQuit(void *appstate, SDL_AppResult result)
478{
479 SDL_free(appstate); // just free the memory, SDL will clean up the window/renderer for us.
480} \ No newline at end of file
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
diff --git a/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/README.txt b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/README.txt
new file mode 100644
index 0000000..dbee4ce
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/README.txt
@@ -0,0 +1,4 @@
1An implementation of the BytePusher VM
2
3For example programs and more information about BytePusher, see
4https://esolangs.org/wiki/BytePusher
diff --git a/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/bytepusher.c b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/bytepusher.c
new file mode 100644
index 0000000..acb2ea4
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/bytepusher.c
@@ -0,0 +1,416 @@
1/*
2 * An implementation of the BytePusher VM.
3 *
4 * For example programs and more information about BytePusher, see
5 * https://esolangs.org/wiki/BytePusher
6 *
7 * This code is public domain. Feel free to use it for any purpose!
8 */
9
10#define SDL_MAIN_USE_CALLBACKS
11#include <SDL3/SDL.h>
12#include <SDL3/SDL_main.h>
13#include <stdarg.h>
14
15#define SCREEN_W 256
16#define SCREEN_H 256
17#define RAM_SIZE 0x1000000
18#define FRAMES_PER_SECOND 60
19#define SAMPLES_PER_FRAME 256
20#define NS_PER_SECOND (Uint64)SDL_NS_PER_SECOND
21#define MAX_AUDIO_LATENCY_FRAMES 5
22
23#define IO_KEYBOARD 0
24#define IO_PC 2
25#define IO_SCREEN_PAGE 5
26#define IO_AUDIO_BANK 6
27
28typedef struct {
29 Uint8 ram[RAM_SIZE + 8];
30 Uint8 screenbuf[SCREEN_W * SCREEN_H];
31 Uint64 last_tick;
32 Uint64 tick_acc;
33 SDL_Window* window;
34 SDL_Renderer* renderer;
35 SDL_Surface* screen;
36 SDL_Texture* screentex;
37 SDL_Texture* rendertarget; /* we need this render target for text to look good */
38 SDL_AudioStream* audiostream;
39 char status[SCREEN_W / 8];
40 int status_ticks;
41 Uint16 keystate;
42 bool display_help;
43 bool positional_input;
44} BytePusher;
45
46static const struct {
47 const char *key;
48 const char *value;
49} extended_metadata[] = {
50 { SDL_PROP_APP_METADATA_URL_STRING, "https://examples.libsdl.org/SDL3/demo/04-bytepusher/" },
51 { SDL_PROP_APP_METADATA_CREATOR_STRING, "SDL team" },
52 { SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Placed in the public domain" },
53 { SDL_PROP_APP_METADATA_TYPE_STRING, "game" }
54};
55
56static inline Uint16 read_u16(const BytePusher* vm, Uint32 addr) {
57 const Uint8* ptr = &vm->ram[addr];
58 return ((Uint16)ptr[0] << 8) | ((Uint16)ptr[1]);
59}
60
61static inline Uint32 read_u24(const BytePusher* vm, Uint32 addr) {
62 const Uint8* ptr = &vm->ram[addr];
63 return ((Uint32)ptr[0] << 16) | ((Uint32)ptr[1] << 8) | ((Uint32)ptr[2]);
64}
65
66static void set_status(BytePusher* vm, const char* fmt, ...) {
67 va_list args;
68 va_start(args, fmt);
69 SDL_vsnprintf(vm->status, sizeof(vm->status), fmt, args);
70 va_end(args);
71 vm->status[sizeof(vm->status) - 1] = 0;
72 vm->status_ticks = FRAMES_PER_SECOND * 3;
73}
74
75static bool load(BytePusher* vm, SDL_IOStream* stream, bool closeio) {
76 size_t bytes_read = 0;
77 bool ok = true;
78
79 SDL_memset(vm->ram, 0, RAM_SIZE);
80
81 if (!stream) {
82 return false;
83 }
84
85 while (bytes_read < RAM_SIZE) {
86 size_t read = SDL_ReadIO(stream, &vm->ram[bytes_read], RAM_SIZE - bytes_read);
87 bytes_read += read;
88 if (read == 0) {
89 ok = SDL_GetIOStatus(stream) == SDL_IO_STATUS_EOF;
90 break;
91 }
92 }
93 if (closeio) {
94 SDL_CloseIO(stream);
95 }
96
97 SDL_ClearAudioStream(vm->audiostream);
98
99 vm->display_help = !ok;
100 return ok;
101}
102
103static const char* filename(const char* path) {
104 size_t i = SDL_strlen(path) + 1;
105 while (i > 0) {
106 i -= 1;
107 if (path[i] == '/' || path[i] == '\\') {
108 return path + i + 1;
109 }
110 }
111 return path;
112}
113
114static bool load_file(BytePusher* vm, const char* path) {
115 if (load(vm, SDL_IOFromFile(path, "rb"), true)) {
116 set_status(vm, "loaded %s", filename(path));
117 return true;
118 } else {
119 set_status(vm, "load failed: %s", filename(path));
120 return false;
121 }
122}
123
124static void print(BytePusher* vm, int x, int y, const char* str) {
125 SDL_SetRenderDrawColor(vm->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
126 SDL_RenderDebugText(vm->renderer, (float)(x + 1), (float)(y + 1), str);
127 SDL_SetRenderDrawColor(vm->renderer, 0xff, 0xff, 0xff, SDL_ALPHA_OPAQUE);
128 SDL_RenderDebugText(vm->renderer, (float)x, (float)y, str);
129 SDL_SetRenderDrawColor(vm->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
130}
131
132SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
133 BytePusher* vm;
134 SDL_Palette* palette;
135 SDL_Rect usable_bounds;
136 SDL_AudioSpec audiospec = { SDL_AUDIO_S8, 1, SAMPLES_PER_FRAME * FRAMES_PER_SECOND };
137 SDL_DisplayID primary_display;
138 SDL_PropertiesID texprops;
139 int zoom = 2;
140 int i;
141 Uint8 r, g, b;
142 (void)argc;
143 (void)argv;
144
145 if (!SDL_SetAppMetadata("SDL 3 BytePusher", "1.0", "com.example.SDL3BytePusher")) {
146 return SDL_APP_FAILURE;
147 }
148
149 for (i = 0; i < (int)SDL_arraysize(extended_metadata); i++) {
150 if (!SDL_SetAppMetadataProperty(extended_metadata[i].key, extended_metadata[i].value)) {
151 return SDL_APP_FAILURE;
152 }
153 }
154
155 if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) {
156 return SDL_APP_FAILURE;
157 }
158
159 if (!(vm = (BytePusher *)SDL_calloc(1, sizeof(*vm)))) {
160 return SDL_APP_FAILURE;
161 }
162 *(BytePusher**)appstate = vm;
163
164 vm->display_help = true;
165
166 primary_display = SDL_GetPrimaryDisplay();
167 if (SDL_GetDisplayUsableBounds(primary_display, &usable_bounds)) {
168 int zoom_w = (usable_bounds.w - usable_bounds.x) * 2 / 3 / SCREEN_W;
169 int zoom_h = (usable_bounds.h - usable_bounds.y) * 2 / 3 / SCREEN_H;
170 zoom = zoom_w < zoom_h ? zoom_w : zoom_h;
171 if (zoom < 1) {
172 zoom = 1;
173 }
174 }
175
176 if (!SDL_CreateWindowAndRenderer("SDL 3 BytePusher",
177 SCREEN_W * zoom, SCREEN_H * zoom, SDL_WINDOW_RESIZABLE,
178 &vm->window, &vm->renderer
179 )) {
180 return SDL_APP_FAILURE;
181 }
182
183 if (!SDL_SetRenderLogicalPresentation(
184 vm->renderer, SCREEN_W, SCREEN_H, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE
185 )) {
186 return SDL_APP_FAILURE;
187 }
188
189 if (!(vm->screen = SDL_CreateSurfaceFrom(
190 SCREEN_W, SCREEN_H, SDL_PIXELFORMAT_INDEX8, vm->screenbuf, SCREEN_W
191 ))) {
192 return SDL_APP_FAILURE;
193 }
194
195 if (!(palette = SDL_CreateSurfacePalette(vm->screen))) {
196 return SDL_APP_FAILURE;
197 }
198 i = 0;
199 for (r = 0; r < 6; ++r) {
200 for (g = 0; g < 6; ++g) {
201 for (b = 0; b < 6; ++b, ++i) {
202 SDL_Color color = { (Uint8)(r * 0x33), (Uint8)(g * 0x33), (Uint8)(b * 0x33), SDL_ALPHA_OPAQUE };
203 palette->colors[i] = color;
204 }
205 }
206 }
207 for (; i < 256; ++i) {
208 SDL_Color color = { 0, 0, 0, SDL_ALPHA_OPAQUE };
209 palette->colors[i] = color;
210 }
211
212 texprops = SDL_CreateProperties();
213 SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING);
214 SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, SCREEN_W);
215 SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, SCREEN_H);
216 vm->screentex = SDL_CreateTextureWithProperties(vm->renderer, texprops);
217 SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_TARGET);
218 vm->rendertarget = SDL_CreateTextureWithProperties(vm->renderer, texprops);
219 SDL_DestroyProperties(texprops);
220 if (!vm->screentex || !vm->rendertarget) {
221 return SDL_APP_FAILURE;
222 }
223 SDL_SetTextureScaleMode(vm->screentex, SDL_SCALEMODE_NEAREST);
224 SDL_SetTextureScaleMode(vm->rendertarget, SDL_SCALEMODE_NEAREST);
225
226 if (!(vm->audiostream = SDL_OpenAudioDeviceStream(
227 SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audiospec, NULL, NULL
228 ))) {
229 return SDL_APP_FAILURE;
230 }
231 SDL_SetAudioStreamGain(vm->audiostream, 0.1f); /* examples are loud! */
232 SDL_ResumeAudioStreamDevice(vm->audiostream);
233
234 set_status(vm, "renderer: %s", SDL_GetRendererName(vm->renderer));
235
236 vm->last_tick = SDL_GetTicksNS();
237 vm->tick_acc = NS_PER_SECOND;
238
239 return SDL_APP_CONTINUE;
240}
241
242SDL_AppResult SDL_AppIterate(void* appstate) {
243 BytePusher* vm = (BytePusher*)appstate;
244
245 Uint64 tick = SDL_GetTicksNS();
246 Uint64 delta = tick - vm->last_tick;
247 bool updated, skip_audio;
248
249 vm->last_tick = tick;
250
251 vm->tick_acc += delta * FRAMES_PER_SECOND;
252 updated = vm->tick_acc >= NS_PER_SECOND;
253 skip_audio = vm->tick_acc >= MAX_AUDIO_LATENCY_FRAMES * NS_PER_SECOND;
254
255 if (skip_audio) {
256 // don't let audio fall too far behind
257 SDL_ClearAudioStream(vm->audiostream);
258 }
259
260 while (vm->tick_acc >= NS_PER_SECOND) {
261 Uint32 pc;
262 int i;
263
264 vm->tick_acc -= NS_PER_SECOND;
265
266 vm->ram[IO_KEYBOARD] = (Uint8)(vm->keystate >> 8);
267 vm->ram[IO_KEYBOARD + 1] = (Uint8)(vm->keystate);
268
269 pc = read_u24(vm, IO_PC);
270 for (i = 0; i < SCREEN_W * SCREEN_H; ++i) {
271 Uint32 src = read_u24(vm, pc);
272 Uint32 dst = read_u24(vm, pc + 3);
273 vm->ram[dst] = vm->ram[src];
274 pc = read_u24(vm, pc + 6);
275 }
276
277 if (!skip_audio || vm->tick_acc < NS_PER_SECOND) {
278 SDL_PutAudioStreamData(
279 vm->audiostream,
280 &vm->ram[(Uint32)read_u16(vm, IO_AUDIO_BANK) << 8],
281 SAMPLES_PER_FRAME
282 );
283 }
284 }
285
286 if (updated) {
287 SDL_Surface *tex;
288
289 SDL_SetRenderTarget(vm->renderer, vm->rendertarget);
290
291 if (!SDL_LockTextureToSurface(vm->screentex, NULL, &tex)) {
292 return SDL_APP_FAILURE;
293 }
294 vm->screen->pixels = &vm->ram[(Uint32)vm->ram[IO_SCREEN_PAGE] << 16];
295 SDL_BlitSurface(vm->screen, NULL, tex, NULL);
296 SDL_UnlockTexture(vm->screentex);
297
298 SDL_RenderTexture(vm->renderer, vm->screentex, NULL, NULL);
299 }
300
301 if (vm->display_help) {
302 print(vm, 4, 4, "Drop a BytePusher file in this");
303 print(vm, 8, 12, "window to load and run it!");
304 print(vm, 4, 28, "Press ENTER to switch between");
305 print(vm, 8, 36, "positional and symbolic input.");
306 }
307
308 if (vm->status_ticks > 0) {
309 vm->status_ticks -= 1;
310 print(vm, 4, SCREEN_H - 12, vm->status);
311 }
312
313 SDL_SetRenderTarget(vm->renderer, NULL);
314 SDL_RenderClear(vm->renderer);
315 SDL_RenderTexture(vm->renderer, vm->rendertarget, NULL, NULL);
316 SDL_RenderPresent(vm->renderer);
317
318 return SDL_APP_CONTINUE;
319}
320
321static Uint16 keycode_mask(SDL_Keycode key) {
322 int index;
323 if (key >= SDLK_0 && key <= SDLK_9) {
324 index = key - SDLK_0;
325 } else if (key >= SDLK_A && key <= SDLK_F) {
326 index = key - SDLK_A + 10;
327 } else {
328 return 0;
329 }
330 return (Uint16)1 << index;
331}
332
333static Uint16 scancode_mask(SDL_Scancode scancode) {
334 int index;
335 switch (scancode) {
336 case SDL_SCANCODE_1: index = 0x1; break;
337 case SDL_SCANCODE_2: index = 0x2; break;
338 case SDL_SCANCODE_3: index = 0x3; break;
339 case SDL_SCANCODE_4: index = 0xc; break;
340 case SDL_SCANCODE_Q: index = 0x4; break;
341 case SDL_SCANCODE_W: index = 0x5; break;
342 case SDL_SCANCODE_E: index = 0x6; break;
343 case SDL_SCANCODE_R: index = 0xd; break;
344 case SDL_SCANCODE_A: index = 0x7; break;
345 case SDL_SCANCODE_S: index = 0x8; break;
346 case SDL_SCANCODE_D: index = 0x9; break;
347 case SDL_SCANCODE_F: index = 0xe; break;
348 case SDL_SCANCODE_Z: index = 0xa; break;
349 case SDL_SCANCODE_X: index = 0x0; break;
350 case SDL_SCANCODE_C: index = 0xb; break;
351 case SDL_SCANCODE_V: index = 0xf; break;
352 default: return 0;
353 }
354 return (Uint16)1 << index;
355}
356
357SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
358 BytePusher* vm = (BytePusher*)appstate;
359
360 switch (event->type) {
361 case SDL_EVENT_QUIT:
362 return SDL_APP_SUCCESS;
363
364 case SDL_EVENT_DROP_FILE:
365 load_file(vm, event->drop.data);
366 break;
367
368 case SDL_EVENT_KEY_DOWN:
369#ifndef __EMSCRIPTEN__
370 if (event->key.key == SDLK_ESCAPE) {
371 return SDL_APP_SUCCESS;
372 }
373#endif
374 if (event->key.key == SDLK_RETURN) {
375 vm->positional_input = !vm->positional_input;
376 vm->keystate = 0;
377 if (vm->positional_input) {
378 set_status(vm, "switched to positional input");
379 } else {
380 set_status(vm, "switched to symbolic input");
381 }
382 }
383 if (vm->positional_input) {
384 vm->keystate |= scancode_mask(event->key.scancode);
385 } else {
386 vm->keystate |= keycode_mask(event->key.key);
387 }
388 break;
389
390 case SDL_EVENT_KEY_UP:
391 if (vm->positional_input) {
392 vm->keystate &= ~scancode_mask(event->key.scancode);
393 } else {
394 vm->keystate &= ~keycode_mask(event->key.key);
395 }
396 break;
397 }
398
399 return SDL_APP_CONTINUE;
400}
401
402void SDL_AppQuit(void* appstate, SDL_AppResult result) {
403 if (result == SDL_APP_FAILURE) {
404 SDL_Log("Error: %s", SDL_GetError());
405 }
406 if (appstate) {
407 BytePusher* vm = (BytePusher*)appstate;
408 SDL_DestroyAudioStream(vm->audiostream);
409 SDL_DestroyTexture(vm->rendertarget);
410 SDL_DestroyTexture(vm->screentex);
411 SDL_DestroySurface(vm->screen);
412 SDL_DestroyRenderer(vm->renderer);
413 SDL_DestroyWindow(vm->window);
414 SDL_free(vm);
415 }
416}
diff --git a/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/onmouseover.webp b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/onmouseover.webp
new file mode 100644
index 0000000..b99e7dd
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/onmouseover.webp
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/thumbnail.png b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/thumbnail.png
new file mode 100644
index 0000000..891aa8f
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/thumbnail.png
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/demo/description.txt b/src/contrib/SDL-3.2.20/examples/demo/description.txt
new file mode 100644
index 0000000..77bcbb7
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/demo/description.txt
@@ -0,0 +1 @@
Full game and app demos \ No newline at end of file