summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c
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/02-woodeneye-008/woodeneye-008.c
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c')
-rw-r--r--src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c480
1 files changed, 480 insertions, 0 deletions
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