From 6aaedb813fa11ba0679c3051bc2eb28646b9506c Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 30 Aug 2025 16:53:58 -0700 Subject: Update to SDL3 --- .../SDL-3.2.20/examples/demo/01-snake/README.txt | 1 + .../examples/demo/01-snake/onmouseover.webp | Bin 0 -> 30996 bytes .../SDL-3.2.20/examples/demo/01-snake/snake.c | 350 +++++++++++++++ .../examples/demo/01-snake/thumbnail.png | Bin 0 -> 2958 bytes .../examples/demo/02-woodeneye-008/README.txt | 1 + .../demo/02-woodeneye-008/onmouseover.webp | Bin 0 -> 468022 bytes .../examples/demo/02-woodeneye-008/thumbnail.png | Bin 0 -> 25191 bytes .../examples/demo/02-woodeneye-008/woodeneye-008.c | 480 +++++++++++++++++++++ .../examples/demo/03-infinite-monkeys/README.txt | 7 + .../demo/03-infinite-monkeys/infinite-monkeys.c | 377 ++++++++++++++++ .../demo/03-infinite-monkeys/onmouseover.webp | Bin 0 -> 95578 bytes .../demo/03-infinite-monkeys/thumbnail.png | Bin 0 -> 7740 bytes .../examples/demo/04-bytepusher/README.txt | 4 + .../examples/demo/04-bytepusher/bytepusher.c | 416 ++++++++++++++++++ .../examples/demo/04-bytepusher/onmouseover.webp | Bin 0 -> 430096 bytes .../examples/demo/04-bytepusher/thumbnail.png | Bin 0 -> 23851 bytes .../SDL-3.2.20/examples/demo/description.txt | 1 + 17 files changed, 1637 insertions(+) create mode 100644 src/contrib/SDL-3.2.20/examples/demo/01-snake/README.txt create mode 100644 src/contrib/SDL-3.2.20/examples/demo/01-snake/onmouseover.webp create mode 100644 src/contrib/SDL-3.2.20/examples/demo/01-snake/snake.c create mode 100644 src/contrib/SDL-3.2.20/examples/demo/01-snake/thumbnail.png create mode 100644 src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/README.txt create mode 100644 src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/onmouseover.webp create mode 100644 src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/thumbnail.png create mode 100644 src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/woodeneye-008.c create mode 100644 src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/README.txt create mode 100644 src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/infinite-monkeys.c create mode 100644 src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/onmouseover.webp create mode 100644 src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/thumbnail.png create mode 100644 src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/README.txt create mode 100644 src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/bytepusher.c create mode 100644 src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/onmouseover.webp create mode 100644 src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/thumbnail.png create mode 100644 src/contrib/SDL-3.2.20/examples/demo/description.txt (limited to 'src/contrib/SDL-3.2.20/examples/demo') 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/01-snake/onmouseover.webp 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 @@ +/* + * Logic implementation of the Snake game. It is designed to efficiently + * represent the state of the game in memory. + * + * 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 +#include + +#define STEP_RATE_IN_MILLISECONDS 125 +#define SNAKE_BLOCK_SIZE_IN_PIXELS 24 +#define SDL_WINDOW_WIDTH (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_WIDTH) +#define SDL_WINDOW_HEIGHT (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_HEIGHT) + +#define SNAKE_GAME_WIDTH 24U +#define SNAKE_GAME_HEIGHT 18U +#define SNAKE_MATRIX_SIZE (SNAKE_GAME_WIDTH * SNAKE_GAME_HEIGHT) + +#define THREE_BITS 0x7U /* ~CHAR_MAX >> (CHAR_BIT - SNAKE_CELL_MAX_BITS) */ +#define SHIFT(x, y) (((x) + ((y) * SNAKE_GAME_WIDTH)) * SNAKE_CELL_MAX_BITS) + +typedef enum +{ + SNAKE_CELL_NOTHING = 0U, + SNAKE_CELL_SRIGHT = 1U, + SNAKE_CELL_SUP = 2U, + SNAKE_CELL_SLEFT = 3U, + SNAKE_CELL_SDOWN = 4U, + SNAKE_CELL_FOOD = 5U +} SnakeCell; + +#define SNAKE_CELL_MAX_BITS 3U /* floor(log2(SNAKE_CELL_FOOD)) + 1 */ + +typedef enum +{ + SNAKE_DIR_RIGHT, + SNAKE_DIR_UP, + SNAKE_DIR_LEFT, + SNAKE_DIR_DOWN +} SnakeDirection; + +typedef struct +{ + unsigned char cells[(SNAKE_MATRIX_SIZE * SNAKE_CELL_MAX_BITS) / 8U]; + char head_xpos; + char head_ypos; + char tail_xpos; + char tail_ypos; + char next_dir; + char inhibit_tail_step; + unsigned occupied_cells; +} SnakeContext; + +typedef struct +{ + SDL_Window *window; + SDL_Renderer *renderer; + SnakeContext snake_ctx; + Uint64 last_step; +} AppState; + +SnakeCell snake_cell_at(const SnakeContext *ctx, char x, char y) +{ + const int shift = SHIFT(x, y); + unsigned short range; + SDL_memcpy(&range, ctx->cells + (shift / 8), sizeof(range)); + return (SnakeCell)((range >> (shift % 8)) & THREE_BITS); +} + +static void set_rect_xy_(SDL_FRect *r, short x, short y) +{ + r->x = (float)(x * SNAKE_BLOCK_SIZE_IN_PIXELS); + r->y = (float)(y * SNAKE_BLOCK_SIZE_IN_PIXELS); +} + +static void put_cell_at_(SnakeContext *ctx, char x, char y, SnakeCell ct) +{ + const int shift = SHIFT(x, y); + const int adjust = shift % 8; + unsigned char *const pos = ctx->cells + (shift / 8); + unsigned short range; + SDL_memcpy(&range, pos, sizeof(range)); + range &= ~(THREE_BITS << adjust); /* clear bits */ + range |= (ct & THREE_BITS) << adjust; + SDL_memcpy(pos, &range, sizeof(range)); +} + +static int are_cells_full_(SnakeContext *ctx) +{ + return ctx->occupied_cells == SNAKE_GAME_WIDTH * SNAKE_GAME_HEIGHT; +} + +static void new_food_pos_(SnakeContext *ctx) +{ + while (true) { + const char x = (char) SDL_rand(SNAKE_GAME_WIDTH); + const char y = (char) SDL_rand(SNAKE_GAME_HEIGHT); + if (snake_cell_at(ctx, x, y) == SNAKE_CELL_NOTHING) { + put_cell_at_(ctx, x, y, SNAKE_CELL_FOOD); + break; + } + } +} + +void snake_initialize(SnakeContext *ctx) +{ + int i; + SDL_zeroa(ctx->cells); + ctx->head_xpos = ctx->tail_xpos = SNAKE_GAME_WIDTH / 2; + ctx->head_ypos = ctx->tail_ypos = SNAKE_GAME_HEIGHT / 2; + ctx->next_dir = SNAKE_DIR_RIGHT; + ctx->inhibit_tail_step = ctx->occupied_cells = 4; + --ctx->occupied_cells; + put_cell_at_(ctx, ctx->tail_xpos, ctx->tail_ypos, SNAKE_CELL_SRIGHT); + for (i = 0; i < 4; i++) { + new_food_pos_(ctx); + ++ctx->occupied_cells; + } +} + +void snake_redir(SnakeContext *ctx, SnakeDirection dir) +{ + SnakeCell ct = snake_cell_at(ctx, ctx->head_xpos, ctx->head_ypos); + if ((dir == SNAKE_DIR_RIGHT && ct != SNAKE_CELL_SLEFT) || + (dir == SNAKE_DIR_UP && ct != SNAKE_CELL_SDOWN) || + (dir == SNAKE_DIR_LEFT && ct != SNAKE_CELL_SRIGHT) || + (dir == SNAKE_DIR_DOWN && ct != SNAKE_CELL_SUP)) { + ctx->next_dir = dir; + } +} + +static void wrap_around_(char *val, char max) +{ + if (*val < 0) { + *val = max - 1; + } else if (*val > max - 1) { + *val = 0; + } +} + +void snake_step(SnakeContext *ctx) +{ + const SnakeCell dir_as_cell = (SnakeCell)(ctx->next_dir + 1); + SnakeCell ct; + char prev_xpos; + char prev_ypos; + /* Move tail forward */ + if (--ctx->inhibit_tail_step == 0) { + ++ctx->inhibit_tail_step; + ct = snake_cell_at(ctx, ctx->tail_xpos, ctx->tail_ypos); + put_cell_at_(ctx, ctx->tail_xpos, ctx->tail_ypos, SNAKE_CELL_NOTHING); + switch (ct) { + case SNAKE_CELL_SRIGHT: + ctx->tail_xpos++; + break; + case SNAKE_CELL_SUP: + ctx->tail_ypos--; + break; + case SNAKE_CELL_SLEFT: + ctx->tail_xpos--; + break; + case SNAKE_CELL_SDOWN: + ctx->tail_ypos++; + break; + default: + break; + } + wrap_around_(&ctx->tail_xpos, SNAKE_GAME_WIDTH); + wrap_around_(&ctx->tail_ypos, SNAKE_GAME_HEIGHT); + } + /* Move head forward */ + prev_xpos = ctx->head_xpos; + prev_ypos = ctx->head_ypos; + switch (ctx->next_dir) { + case SNAKE_DIR_RIGHT: + ++ctx->head_xpos; + break; + case SNAKE_DIR_UP: + --ctx->head_ypos; + break; + case SNAKE_DIR_LEFT: + --ctx->head_xpos; + break; + case SNAKE_DIR_DOWN: + ++ctx->head_ypos; + break; + } + wrap_around_(&ctx->head_xpos, SNAKE_GAME_WIDTH); + wrap_around_(&ctx->head_ypos, SNAKE_GAME_HEIGHT); + /* Collisions */ + ct = snake_cell_at(ctx, ctx->head_xpos, ctx->head_ypos); + if (ct != SNAKE_CELL_NOTHING && ct != SNAKE_CELL_FOOD) { + snake_initialize(ctx); + return; + } + put_cell_at_(ctx, prev_xpos, prev_ypos, dir_as_cell); + put_cell_at_(ctx, ctx->head_xpos, ctx->head_ypos, dir_as_cell); + if (ct == SNAKE_CELL_FOOD) { + if (are_cells_full_(ctx)) { + snake_initialize(ctx); + return; + } + new_food_pos_(ctx); + ++ctx->inhibit_tail_step; + ++ctx->occupied_cells; + } +} + +static SDL_AppResult handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code) +{ + switch (key_code) { + /* Quit. */ + case SDL_SCANCODE_ESCAPE: + case SDL_SCANCODE_Q: + return SDL_APP_SUCCESS; + /* Restart the game as if the program was launched. */ + case SDL_SCANCODE_R: + snake_initialize(ctx); + break; + /* Decide new direction of the snake. */ + case SDL_SCANCODE_RIGHT: + snake_redir(ctx, SNAKE_DIR_RIGHT); + break; + case SDL_SCANCODE_UP: + snake_redir(ctx, SNAKE_DIR_UP); + break; + case SDL_SCANCODE_LEFT: + snake_redir(ctx, SNAKE_DIR_LEFT); + break; + case SDL_SCANCODE_DOWN: + snake_redir(ctx, SNAKE_DIR_DOWN); + break; + default: + break; + } + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppIterate(void *appstate) +{ + AppState *as = (AppState *)appstate; + SnakeContext *ctx = &as->snake_ctx; + const Uint64 now = SDL_GetTicks(); + SDL_FRect r; + unsigned i; + unsigned j; + int ct; + + // run game logic if we're at or past the time to run it. + // if we're _really_ behind the time to run it, run it + // several times. + while ((now - as->last_step) >= STEP_RATE_IN_MILLISECONDS) { + snake_step(ctx); + as->last_step += STEP_RATE_IN_MILLISECONDS; + } + + r.w = r.h = SNAKE_BLOCK_SIZE_IN_PIXELS; + SDL_SetRenderDrawColor(as->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(as->renderer); + for (i = 0; i < SNAKE_GAME_WIDTH; i++) { + for (j = 0; j < SNAKE_GAME_HEIGHT; j++) { + ct = snake_cell_at(ctx, i, j); + if (ct == SNAKE_CELL_NOTHING) + continue; + set_rect_xy_(&r, i, j); + if (ct == SNAKE_CELL_FOOD) + SDL_SetRenderDrawColor(as->renderer, 80, 80, 255, SDL_ALPHA_OPAQUE); + else /* body */ + SDL_SetRenderDrawColor(as->renderer, 0, 128, 0, SDL_ALPHA_OPAQUE); + SDL_RenderFillRect(as->renderer, &r); + } + } + SDL_SetRenderDrawColor(as->renderer, 255, 255, 0, SDL_ALPHA_OPAQUE); /*head*/ + set_rect_xy_(&r, ctx->head_xpos, ctx->head_ypos); + SDL_RenderFillRect(as->renderer, &r); + SDL_RenderPresent(as->renderer); + return SDL_APP_CONTINUE; +} + +static const struct +{ + const char *key; + const char *value; +} extended_metadata[] = +{ + { SDL_PROP_APP_METADATA_URL_STRING, "https://examples.libsdl.org/SDL3/demo/01-snake/" }, + { SDL_PROP_APP_METADATA_CREATOR_STRING, "SDL team" }, + { SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Placed in the public domain" }, + { SDL_PROP_APP_METADATA_TYPE_STRING, "game" } +}; + +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + size_t i; + + if (!SDL_SetAppMetadata("Example Snake game", "1.0", "com.example.Snake")) { + return SDL_APP_FAILURE; + } + + for (i = 0; i < SDL_arraysize(extended_metadata); i++) { + if (!SDL_SetAppMetadataProperty(extended_metadata[i].key, extended_metadata[i].value)) { + return SDL_APP_FAILURE; + } + } + + if (!SDL_Init(SDL_INIT_VIDEO)) { + return SDL_APP_FAILURE; + } + + AppState *as = (AppState *)SDL_calloc(1, sizeof(AppState)); + if (!as) { + return SDL_APP_FAILURE; + } + + *appstate = as; + + if (!SDL_CreateWindowAndRenderer("examples/demo/snake", SDL_WINDOW_WIDTH, SDL_WINDOW_HEIGHT, 0, &as->window, &as->renderer)) { + return SDL_APP_FAILURE; + } + + snake_initialize(&as->snake_ctx); + + as->last_step = SDL_GetTicks(); + + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + SnakeContext *ctx = &((AppState *)appstate)->snake_ctx; + switch (event->type) { + case SDL_EVENT_QUIT: + return SDL_APP_SUCCESS; + case SDL_EVENT_KEY_DOWN: + return handle_key_event_(ctx, event->key.scancode); + } + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + if (appstate != NULL) { + AppState *as = (AppState *)appstate; + SDL_DestroyRenderer(as->renderer); + SDL_DestroyWindow(as->window); + SDL_free(as); + } +} 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/01-snake/thumbnail.png 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/onmouseover.webp 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/02-woodeneye-008/thumbnail.png 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 @@ +/* + * 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 +#include + +#define MAP_BOX_SCALE 16 +#define MAP_BOX_EDGES_LEN (12 + MAP_BOX_SCALE * 2) +#define MAX_PLAYER_COUNT 4 +#define CIRCLE_DRAW_SIDES 32 +#define CIRCLE_DRAW_SIDES_LEN (CIRCLE_DRAW_SIDES + 1) + +typedef struct { + SDL_MouseID mouse; + SDL_KeyboardID keyboard; + double pos[3]; + double vel[3]; + unsigned int yaw; + int pitch; + float radius, height; + unsigned char color[3]; + unsigned char wasd; +} Player; + +typedef struct { + SDL_Window *window; + SDL_Renderer *renderer; + int player_count; + Player players[MAX_PLAYER_COUNT]; + float edges[MAP_BOX_EDGES_LEN][6]; +} AppState; + +static const struct { + const char *key; + const char *value; +} extended_metadata[] = { + { SDL_PROP_APP_METADATA_URL_STRING, "https://examples.libsdl.org/SDL3/demo/02-woodeneye-008/" }, + { SDL_PROP_APP_METADATA_CREATOR_STRING, "SDL team" }, + { SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Placed in the public domain" }, + { SDL_PROP_APP_METADATA_TYPE_STRING, "game" } +}; + +static int whoseMouse(SDL_MouseID mouse, const Player players[], int players_len) +{ + int i; + for (i = 0; i < players_len; i++) { + if (players[i].mouse == mouse) return i; + } + return -1; +} + +static int whoseKeyboard(SDL_KeyboardID keyboard, const Player players[], int players_len) +{ + int i; + for (i = 0; i < players_len; i++) { + if (players[i].keyboard == keyboard) return i; + } + return -1; +} + +static void shoot(int shooter, Player players[], int players_len) +{ + int i, j; + double x0 = players[shooter].pos[0]; + double y0 = players[shooter].pos[1]; + double z0 = players[shooter].pos[2]; + double bin_rad = SDL_PI_D / 2147483648.0; + double yaw_rad = bin_rad * players[shooter].yaw; + double pitch_rad = bin_rad * players[shooter].pitch; + double cos_yaw = SDL_cos( yaw_rad); + double sin_yaw = SDL_sin( yaw_rad); + double cos_pitch = SDL_cos(pitch_rad); + double sin_pitch = SDL_sin(pitch_rad); + double vx = -sin_yaw*cos_pitch; + double vy = sin_pitch; + double vz = -cos_yaw*cos_pitch; + for (i = 0; i < players_len; i++) { + if (i == shooter) continue; + Player *target = &(players[i]); + int hit = 0; + for (j = 0; j < 2; j++) { + double r = target->radius; + double h = target->height; + double dx = target->pos[0] - x0; + double dy = target->pos[1] - y0 + (j == 0 ? 0 : r - h); + double dz = target->pos[2] - z0; + double vd = vx*dx + vy*dy + vz*dz; + double dd = dx*dx + dy*dy + dz*dz; + double vv = vx*vx + vy*vy + vz*vz; + double rr = r * r; + if (vd < 0) continue; + if (vd * vd >= vv * (dd - rr)) hit += 1; + } + if (hit) { + target->pos[0] = (double)(MAP_BOX_SCALE * (SDL_rand(256) - 128)) / 256; + target->pos[1] = (double)(MAP_BOX_SCALE * (SDL_rand(256) - 128)) / 256; + target->pos[2] = (double)(MAP_BOX_SCALE * (SDL_rand(256) - 128)) / 256; + } + } +} + +static void update(Player *players, int players_len, Uint64 dt_ns) +{ + int i; + for (i = 0; i < players_len; i++) { + Player *player = &players[i]; + double rate = 6.0; + double time = (double)dt_ns * 1e-9; + double drag = SDL_exp(-time * rate); + double diff = 1.0 - drag; + double mult = 60.0; + double grav = 25.0; + double yaw = (double)player->yaw; + double rad = yaw * SDL_PI_D / 2147483648.0; + double cos = SDL_cos(rad); + double sin = SDL_sin(rad); + unsigned char wasd = player->wasd; + double dirX = (wasd & 8 ? 1.0 : 0.0) - (wasd & 2 ? 1.0 : 0.0); + double dirZ = (wasd & 4 ? 1.0 : 0.0) - (wasd & 1 ? 1.0 : 0.0); + double norm = dirX * dirX + dirZ * dirZ; + double accX = mult * (norm == 0 ? 0 : ( cos*dirX + sin*dirZ) / SDL_sqrt(norm)); + double accZ = mult * (norm == 0 ? 0 : (-sin*dirX + cos*dirZ) / SDL_sqrt(norm)); + double velX = player->vel[0]; + double velY = player->vel[1]; + double velZ = player->vel[2]; + player->vel[0] -= velX * diff; + player->vel[1] -= grav * time; + player->vel[2] -= velZ * diff; + player->vel[0] += diff * accX / rate; + player->vel[2] += diff * accZ / rate; + player->pos[0] += (time - diff/rate) * accX / rate + diff * velX / rate; + player->pos[1] += -0.5 * grav * time * time + velY * time; + player->pos[2] += (time - diff/rate) * accZ / rate + diff * velZ / rate; + double scale = (double)MAP_BOX_SCALE; + double bound = scale - player->radius; + double posX = SDL_max(SDL_min(bound, player->pos[0]), -bound); + double posY = SDL_max(SDL_min(bound, player->pos[1]), player->height - scale); + double posZ = SDL_max(SDL_min(bound, player->pos[2]), -bound); + if (player->pos[0] != posX) player->vel[0] = 0; + if (player->pos[1] != posY) player->vel[1] = (wasd & 16) ? 8.4375 : 0; + if (player->pos[2] != posZ) player->vel[2] = 0; + player->pos[0] = posX; + player->pos[1] = posY; + player->pos[2] = posZ; + } +} + +static void drawCircle(SDL_Renderer *renderer, float r, float x, float y) +{ + float ang; + SDL_FPoint points[CIRCLE_DRAW_SIDES_LEN]; + int i; + for (i = 0; i < CIRCLE_DRAW_SIDES_LEN; i++) { + ang = 2.0f * SDL_PI_F * (float)i / (float)CIRCLE_DRAW_SIDES; + points[i].x = x + r * SDL_cosf(ang); + points[i].y = y + r * SDL_sinf(ang); + } + SDL_RenderLines(renderer, (const SDL_FPoint*)&points, CIRCLE_DRAW_SIDES_LEN); +} + +static void drawClippedSegment( + SDL_Renderer *renderer, + float ax, float ay, float az, + float bx, float by, float bz, + float x, float y, float z, float w) +{ + if (az >= -w && bz >= -w) return; + float dx = ax - bx; + float dy = ay - by; + if (az > -w) { + float t = (-w - bz) / (az - bz); + ax = bx + dx * t; + ay = by + dy * t; + az = -w; + } else if (bz > -w) { + float t = (-w - az) / (bz - az); + bx = ax - dx * t; + by = ay - dy * t; + bz = -w; + } + ax = -z * ax / az; + ay = -z * ay / az; + bx = -z * bx / bz; + by = -z * by / bz; + SDL_RenderLine(renderer, x + ax, y - ay, x + bx, y - by); +} + +static char debug_string[32]; +static void draw(SDL_Renderer *renderer, const float (*edges)[6], const Player players[], int players_len) +{ + int w, h, i, j, k; + if (!SDL_GetRenderOutputSize(renderer, &w, &h)) { + return; + } + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + if (players_len > 0) { + float wf = (float)w; + float hf = (float)h; + int part_hor = players_len > 2 ? 2 : 1; + int part_ver = players_len > 1 ? 2 : 1; + float size_hor = wf / ((float)part_hor); + float size_ver = hf / ((float)part_ver); + for (i = 0; i < players_len; i++) { + const Player *player = &players[i]; + float mod_x = (float)(i % part_hor); + float mod_y = (float)(i / part_hor); + float hor_origin = (mod_x + 0.5f) * size_hor; + float ver_origin = (mod_y + 0.5f) * size_ver; + float cam_origin = (float)(0.5 * SDL_sqrt(size_hor * size_hor + size_ver * size_ver)); + float hor_offset = mod_x * size_hor; + float ver_offset = mod_y * size_ver; + SDL_Rect rect; + rect.x = (int)hor_offset; + rect.y = (int)ver_offset; + rect.w = (int)size_hor; + rect.h = (int)size_ver; + SDL_SetRenderClipRect(renderer, &rect); + double x0 = player->pos[0]; + double y0 = player->pos[1]; + double z0 = player->pos[2]; + double bin_rad = SDL_PI_D / 2147483648.0; + double yaw_rad = bin_rad * player->yaw; + double pitch_rad = bin_rad * player->pitch; + double cos_yaw = SDL_cos( yaw_rad); + double sin_yaw = SDL_sin( yaw_rad); + double cos_pitch = SDL_cos(pitch_rad); + double sin_pitch = SDL_sin(pitch_rad); + double mat[9] = { + cos_yaw , 0, -sin_yaw , + sin_yaw*sin_pitch, cos_pitch, cos_yaw*sin_pitch, + sin_yaw*cos_pitch, -sin_pitch, cos_yaw*cos_pitch + }; + SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255); + for (k = 0; k < MAP_BOX_EDGES_LEN; k++) { + const float *line = edges[k]; + float ax = (float)(mat[0] * (line[0] - x0) + mat[1] * (line[1] - y0) + mat[2] * (line[2] - z0)); + float ay = (float)(mat[3] * (line[0] - x0) + mat[4] * (line[1] - y0) + mat[5] * (line[2] - z0)); + float az = (float)(mat[6] * (line[0] - x0) + mat[7] * (line[1] - y0) + mat[8] * (line[2] - z0)); + float bx = (float)(mat[0] * (line[3] - x0) + mat[1] * (line[4] - y0) + mat[2] * (line[5] - z0)); + float by = (float)(mat[3] * (line[3] - x0) + mat[4] * (line[4] - y0) + mat[5] * (line[5] - z0)); + float bz = (float)(mat[6] * (line[3] - x0) + mat[7] * (line[4] - y0) + mat[8] * (line[5] - z0)); + drawClippedSegment(renderer, ax, ay, az, bx, by, bz, hor_origin, ver_origin, cam_origin, 1); + } + for (j = 0; j < players_len; j++) { + if (i == j) continue; + const Player *target = &players[j]; + SDL_SetRenderDrawColor(renderer, target->color[0], target->color[1], target->color[2], 255); + for (k = 0; k < 2; k++) { + double rx = target->pos[0] - player->pos[0]; + double ry = target->pos[1] - player->pos[1] + (target->radius - target->height) * (float)k; + double rz = target->pos[2] - player->pos[2]; + double dx = mat[0] * rx + mat[1] * ry + mat[2] * rz; + double dy = mat[3] * rx + mat[4] * ry + mat[5] * rz; + double dz = mat[6] * rx + mat[7] * ry + mat[8] * rz; + double r_eff = target->radius * cam_origin / dz; + if (!(dz < 0)) continue; + drawCircle(renderer, (float)(r_eff), (float)(hor_origin - cam_origin*dx/dz), (float)(ver_origin + cam_origin*dy/dz)); + } + } + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderLine(renderer, hor_origin, ver_origin-10, hor_origin, ver_origin+10); + SDL_RenderLine(renderer, hor_origin-10, ver_origin, hor_origin+10, ver_origin); + } + } + SDL_SetRenderClipRect(renderer, 0); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDebugText(renderer, 0, 0, debug_string); + SDL_RenderPresent(renderer); +} + +static void initPlayers(Player *players, int len) +{ + int i; + for (i = 0; i < len; i++) { + players[i].pos[0] = 8.0 * (i & 1 ? -1.0 : 1.0); + players[i].pos[1] = 0; + players[i].pos[2] = 8.0 * (i & 1 ? -1.0 : 1.0) * (i & 2 ? -1.0 : 1.0); + players[i].vel[0] = 0; + players[i].vel[1] = 0; + players[i].vel[2] = 0; + players[i].yaw = 0x20000000 + (i & 1 ? 0x80000000 : 0) + (i & 2 ? 0x40000000 : 0); + players[i].pitch = -0x08000000; + players[i].radius = 0.5f; + players[i].height = 1.5f; + players[i].wasd = 0; + players[i].mouse = 0; + players[i].keyboard = 0; + players[i].color[0] = (1 << (i / 2)) & 2 ? 0 : 0xff; + players[i].color[1] = (1 << (i / 2)) & 1 ? 0 : 0xff; + players[i].color[2] = (1 << (i / 2)) & 4 ? 0 : 0xff; + players[i].color[0] = (i & 1) ? players[i].color[0] : ~players[i].color[0]; + players[i].color[1] = (i & 1) ? players[i].color[1] : ~players[i].color[1]; + players[i].color[2] = (i & 1) ? players[i].color[2] : ~players[i].color[2]; + } +} + +static void initEdges(int scale, float (*edges)[6], int edges_len) +{ + int i, j; + const float r = (float)scale; + const int map[24] = { + 0,1 , 1,3 , 3,2 , 2,0 , + 7,6 , 6,4 , 4,5 , 5,7 , + 6,2 , 3,7 , 0,4 , 5,1 + }; + for(i = 0; i < 12; i++) { + for (j = 0; j < 3; j++) { + edges[i][j+0] = (map[i*2+0] & (1 << j) ? r : -r); + edges[i][j+3] = (map[i*2+1] & (1 << j) ? r : -r); + } + } + for(i = 0; i < scale; i++) { + float d = (float)(i * 2); + for (j = 0; j < 2; j++) { + edges[i+12][3*j+0] = j ? r : -r; + edges[i+12][3*j+1] = -r; + edges[i+12][3*j+2] = d-r; + edges[i+12+scale][3*j+0] = d-r; + edges[i+12+scale][3*j+1] = -r; + edges[i+12+scale][3*j+2] = j ? r : -r; + } + } +} + +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + if (!SDL_SetAppMetadata("Example splitscreen shooter game", "1.0", "com.example.woodeneye-008")) { + return SDL_APP_FAILURE; + } + int i; + for (i = 0; i < SDL_arraysize(extended_metadata); i++) { + if (!SDL_SetAppMetadataProperty(extended_metadata[i].key, extended_metadata[i].value)) { + return SDL_APP_FAILURE; + } + } + + AppState *as = SDL_calloc(1, sizeof(AppState)); + if (!as) { + return SDL_APP_FAILURE; + } else { + *appstate = as; + } + + if (!SDL_Init(SDL_INIT_VIDEO)) { + return SDL_APP_FAILURE; + } + if (!SDL_CreateWindowAndRenderer("examples/demo/woodeneye-008", 640, 480, 0, &as->window, &as->renderer)) { + return SDL_APP_FAILURE; + } + + as->player_count = 1; + initPlayers(as->players, MAX_PLAYER_COUNT); + initEdges(MAP_BOX_SCALE, as->edges, MAP_BOX_EDGES_LEN); + debug_string[0] = 0; + + SDL_SetRenderVSync(as->renderer, false); + SDL_SetWindowRelativeMouseMode(as->window, true); + SDL_SetHintWithPriority(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1", SDL_HINT_OVERRIDE); + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + AppState *as = appstate; + Player *players = as->players; + int player_count = as->player_count; + int i; + switch (event->type) { + case SDL_EVENT_QUIT: + return SDL_APP_SUCCESS; + break; + case SDL_EVENT_MOUSE_REMOVED: + for (i = 0; i < player_count; i++) { + if (players[i].mouse == event->mdevice.which) { + players[i].mouse = 0; + } + } + break; + case SDL_EVENT_KEYBOARD_REMOVED: + for (i = 0; i < player_count; i++) { + if (players[i].keyboard == event->kdevice.which) { + players[i].keyboard = 0; + } + } + break; + case SDL_EVENT_MOUSE_MOTION: { + SDL_MouseID id = event->motion.which; + int index = whoseMouse(id, players, player_count); + if (index >= 0) { + players[index].yaw -= ((int)event->motion.xrel) * 0x00080000; + players[index].pitch = SDL_max(-0x40000000, SDL_min(0x40000000, players[index].pitch - ((int)event->motion.yrel) * 0x00080000)); + } else if (id) { + for (i = 0; i < MAX_PLAYER_COUNT; i++) { + if (players[i].mouse == 0) { + players[i].mouse = id; + as->player_count = SDL_max(as->player_count, i + 1); + break; + } + } + } + break; + } + case SDL_EVENT_MOUSE_BUTTON_DOWN: { + SDL_MouseID id = event->button.which; + int index = whoseMouse(id, players, player_count); + if (index >= 0) { + shoot(index, players, player_count); + } + break; + } + case SDL_EVENT_KEY_DOWN: { + SDL_Keycode sym = event->key.key; + SDL_KeyboardID id = event->key.which; + int index = whoseKeyboard(id, players, player_count); + if (index >= 0) { + if (sym == SDLK_W) players[index].wasd |= 1; + if (sym == SDLK_A) players[index].wasd |= 2; + if (sym == SDLK_S) players[index].wasd |= 4; + if (sym == SDLK_D) players[index].wasd |= 8; + if (sym == SDLK_SPACE) players[index].wasd |= 16; + } else if (id) { + for (i = 0; i < MAX_PLAYER_COUNT; i++) { + if (players[i].keyboard == 0) { + players[i].keyboard = id; + as->player_count = SDL_max(as->player_count, i + 1); + break; + } + } + } + break; + } + case SDL_EVENT_KEY_UP: { + SDL_Keycode sym = event->key.key; + SDL_KeyboardID id = event->key.which; + if (sym == SDLK_ESCAPE) return SDL_APP_SUCCESS; + int index = whoseKeyboard(id, players, player_count); + if (index >= 0) { + if (sym == SDLK_W) players[index].wasd &= 30; + if (sym == SDLK_A) players[index].wasd &= 29; + if (sym == SDLK_S) players[index].wasd &= 27; + if (sym == SDLK_D) players[index].wasd &= 23; + if (sym == SDLK_SPACE) players[index].wasd &= 15; + } + break; + } + } + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppIterate(void *appstate) +{ + AppState *as = appstate; + static Uint64 accu = 0; + static Uint64 last = 0; + static Uint64 past = 0; + Uint64 now = SDL_GetTicksNS(); + Uint64 dt_ns = now - past; + update(as->players, as->player_count, dt_ns); + draw(as->renderer, (const float (*)[6])as->edges, as->players, as->player_count); + if (now - last > 999999999) { + last = now; + SDL_snprintf(debug_string, sizeof(debug_string), "%" SDL_PRIu64 " fps", accu); + accu = 0; + } + past = now; + accu += 1; + Uint64 elapsed = SDL_GetTicksNS() - now; + if (elapsed < 999999) { + SDL_DelayNS(999999 - elapsed); + } + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + SDL_free(appstate); // just free the memory, SDL will clean up the window/renderer for us. +} \ 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 @@ + +How many monkeys does it take to write the complete works of Shakespeare? + + Now you can find out! + +Cheer on your favorite monkey as they bash keyboards on their way through classic literature. + 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 @@ +/* + * 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 +#include + +/* 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); +} + 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/onmouseover.webp 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/03-infinite-monkeys/thumbnail.png 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 @@ +An implementation of the BytePusher VM + +For example programs and more information about BytePusher, see +https://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 @@ +/* + * An implementation of the BytePusher VM. + * + * For example programs and more information about BytePusher, see + * https://esolangs.org/wiki/BytePusher + * + * This code is public domain. Feel free to use it for any purpose! + */ + +#define SDL_MAIN_USE_CALLBACKS +#include +#include +#include + +#define SCREEN_W 256 +#define SCREEN_H 256 +#define RAM_SIZE 0x1000000 +#define FRAMES_PER_SECOND 60 +#define SAMPLES_PER_FRAME 256 +#define NS_PER_SECOND (Uint64)SDL_NS_PER_SECOND +#define MAX_AUDIO_LATENCY_FRAMES 5 + +#define IO_KEYBOARD 0 +#define IO_PC 2 +#define IO_SCREEN_PAGE 5 +#define IO_AUDIO_BANK 6 + +typedef struct { + Uint8 ram[RAM_SIZE + 8]; + Uint8 screenbuf[SCREEN_W * SCREEN_H]; + Uint64 last_tick; + Uint64 tick_acc; + SDL_Window* window; + SDL_Renderer* renderer; + SDL_Surface* screen; + SDL_Texture* screentex; + SDL_Texture* rendertarget; /* we need this render target for text to look good */ + SDL_AudioStream* audiostream; + char status[SCREEN_W / 8]; + int status_ticks; + Uint16 keystate; + bool display_help; + bool positional_input; +} BytePusher; + +static const struct { + const char *key; + const char *value; +} extended_metadata[] = { + { SDL_PROP_APP_METADATA_URL_STRING, "https://examples.libsdl.org/SDL3/demo/04-bytepusher/" }, + { SDL_PROP_APP_METADATA_CREATOR_STRING, "SDL team" }, + { SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Placed in the public domain" }, + { SDL_PROP_APP_METADATA_TYPE_STRING, "game" } +}; + +static inline Uint16 read_u16(const BytePusher* vm, Uint32 addr) { + const Uint8* ptr = &vm->ram[addr]; + return ((Uint16)ptr[0] << 8) | ((Uint16)ptr[1]); +} + +static inline Uint32 read_u24(const BytePusher* vm, Uint32 addr) { + const Uint8* ptr = &vm->ram[addr]; + return ((Uint32)ptr[0] << 16) | ((Uint32)ptr[1] << 8) | ((Uint32)ptr[2]); +} + +static void set_status(BytePusher* vm, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + SDL_vsnprintf(vm->status, sizeof(vm->status), fmt, args); + va_end(args); + vm->status[sizeof(vm->status) - 1] = 0; + vm->status_ticks = FRAMES_PER_SECOND * 3; +} + +static bool load(BytePusher* vm, SDL_IOStream* stream, bool closeio) { + size_t bytes_read = 0; + bool ok = true; + + SDL_memset(vm->ram, 0, RAM_SIZE); + + if (!stream) { + return false; + } + + while (bytes_read < RAM_SIZE) { + size_t read = SDL_ReadIO(stream, &vm->ram[bytes_read], RAM_SIZE - bytes_read); + bytes_read += read; + if (read == 0) { + ok = SDL_GetIOStatus(stream) == SDL_IO_STATUS_EOF; + break; + } + } + if (closeio) { + SDL_CloseIO(stream); + } + + SDL_ClearAudioStream(vm->audiostream); + + vm->display_help = !ok; + return ok; +} + +static const char* filename(const char* path) { + size_t i = SDL_strlen(path) + 1; + while (i > 0) { + i -= 1; + if (path[i] == '/' || path[i] == '\\') { + return path + i + 1; + } + } + return path; +} + +static bool load_file(BytePusher* vm, const char* path) { + if (load(vm, SDL_IOFromFile(path, "rb"), true)) { + set_status(vm, "loaded %s", filename(path)); + return true; + } else { + set_status(vm, "load failed: %s", filename(path)); + return false; + } +} + +static void print(BytePusher* vm, int x, int y, const char* str) { + SDL_SetRenderDrawColor(vm->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderDebugText(vm->renderer, (float)(x + 1), (float)(y + 1), str); + SDL_SetRenderDrawColor(vm->renderer, 0xff, 0xff, 0xff, SDL_ALPHA_OPAQUE); + SDL_RenderDebugText(vm->renderer, (float)x, (float)y, str); + SDL_SetRenderDrawColor(vm->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); +} + +SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { + BytePusher* vm; + SDL_Palette* palette; + SDL_Rect usable_bounds; + SDL_AudioSpec audiospec = { SDL_AUDIO_S8, 1, SAMPLES_PER_FRAME * FRAMES_PER_SECOND }; + SDL_DisplayID primary_display; + SDL_PropertiesID texprops; + int zoom = 2; + int i; + Uint8 r, g, b; + (void)argc; + (void)argv; + + if (!SDL_SetAppMetadata("SDL 3 BytePusher", "1.0", "com.example.SDL3BytePusher")) { + return SDL_APP_FAILURE; + } + + for (i = 0; i < (int)SDL_arraysize(extended_metadata); i++) { + if (!SDL_SetAppMetadataProperty(extended_metadata[i].key, extended_metadata[i].value)) { + return SDL_APP_FAILURE; + } + } + + if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) { + return SDL_APP_FAILURE; + } + + if (!(vm = (BytePusher *)SDL_calloc(1, sizeof(*vm)))) { + return SDL_APP_FAILURE; + } + *(BytePusher**)appstate = vm; + + vm->display_help = true; + + primary_display = SDL_GetPrimaryDisplay(); + if (SDL_GetDisplayUsableBounds(primary_display, &usable_bounds)) { + int zoom_w = (usable_bounds.w - usable_bounds.x) * 2 / 3 / SCREEN_W; + int zoom_h = (usable_bounds.h - usable_bounds.y) * 2 / 3 / SCREEN_H; + zoom = zoom_w < zoom_h ? zoom_w : zoom_h; + if (zoom < 1) { + zoom = 1; + } + } + + if (!SDL_CreateWindowAndRenderer("SDL 3 BytePusher", + SCREEN_W * zoom, SCREEN_H * zoom, SDL_WINDOW_RESIZABLE, + &vm->window, &vm->renderer + )) { + return SDL_APP_FAILURE; + } + + if (!SDL_SetRenderLogicalPresentation( + vm->renderer, SCREEN_W, SCREEN_H, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE + )) { + return SDL_APP_FAILURE; + } + + if (!(vm->screen = SDL_CreateSurfaceFrom( + SCREEN_W, SCREEN_H, SDL_PIXELFORMAT_INDEX8, vm->screenbuf, SCREEN_W + ))) { + return SDL_APP_FAILURE; + } + + if (!(palette = SDL_CreateSurfacePalette(vm->screen))) { + return SDL_APP_FAILURE; + } + i = 0; + for (r = 0; r < 6; ++r) { + for (g = 0; g < 6; ++g) { + for (b = 0; b < 6; ++b, ++i) { + SDL_Color color = { (Uint8)(r * 0x33), (Uint8)(g * 0x33), (Uint8)(b * 0x33), SDL_ALPHA_OPAQUE }; + palette->colors[i] = color; + } + } + } + for (; i < 256; ++i) { + SDL_Color color = { 0, 0, 0, SDL_ALPHA_OPAQUE }; + palette->colors[i] = color; + } + + texprops = SDL_CreateProperties(); + SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING); + SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, SCREEN_W); + SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, SCREEN_H); + vm->screentex = SDL_CreateTextureWithProperties(vm->renderer, texprops); + SDL_SetNumberProperty(texprops, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_TARGET); + vm->rendertarget = SDL_CreateTextureWithProperties(vm->renderer, texprops); + SDL_DestroyProperties(texprops); + if (!vm->screentex || !vm->rendertarget) { + return SDL_APP_FAILURE; + } + SDL_SetTextureScaleMode(vm->screentex, SDL_SCALEMODE_NEAREST); + SDL_SetTextureScaleMode(vm->rendertarget, SDL_SCALEMODE_NEAREST); + + if (!(vm->audiostream = SDL_OpenAudioDeviceStream( + SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audiospec, NULL, NULL + ))) { + return SDL_APP_FAILURE; + } + SDL_SetAudioStreamGain(vm->audiostream, 0.1f); /* examples are loud! */ + SDL_ResumeAudioStreamDevice(vm->audiostream); + + set_status(vm, "renderer: %s", SDL_GetRendererName(vm->renderer)); + + vm->last_tick = SDL_GetTicksNS(); + vm->tick_acc = NS_PER_SECOND; + + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppIterate(void* appstate) { + BytePusher* vm = (BytePusher*)appstate; + + Uint64 tick = SDL_GetTicksNS(); + Uint64 delta = tick - vm->last_tick; + bool updated, skip_audio; + + vm->last_tick = tick; + + vm->tick_acc += delta * FRAMES_PER_SECOND; + updated = vm->tick_acc >= NS_PER_SECOND; + skip_audio = vm->tick_acc >= MAX_AUDIO_LATENCY_FRAMES * NS_PER_SECOND; + + if (skip_audio) { + // don't let audio fall too far behind + SDL_ClearAudioStream(vm->audiostream); + } + + while (vm->tick_acc >= NS_PER_SECOND) { + Uint32 pc; + int i; + + vm->tick_acc -= NS_PER_SECOND; + + vm->ram[IO_KEYBOARD] = (Uint8)(vm->keystate >> 8); + vm->ram[IO_KEYBOARD + 1] = (Uint8)(vm->keystate); + + pc = read_u24(vm, IO_PC); + for (i = 0; i < SCREEN_W * SCREEN_H; ++i) { + Uint32 src = read_u24(vm, pc); + Uint32 dst = read_u24(vm, pc + 3); + vm->ram[dst] = vm->ram[src]; + pc = read_u24(vm, pc + 6); + } + + if (!skip_audio || vm->tick_acc < NS_PER_SECOND) { + SDL_PutAudioStreamData( + vm->audiostream, + &vm->ram[(Uint32)read_u16(vm, IO_AUDIO_BANK) << 8], + SAMPLES_PER_FRAME + ); + } + } + + if (updated) { + SDL_Surface *tex; + + SDL_SetRenderTarget(vm->renderer, vm->rendertarget); + + if (!SDL_LockTextureToSurface(vm->screentex, NULL, &tex)) { + return SDL_APP_FAILURE; + } + vm->screen->pixels = &vm->ram[(Uint32)vm->ram[IO_SCREEN_PAGE] << 16]; + SDL_BlitSurface(vm->screen, NULL, tex, NULL); + SDL_UnlockTexture(vm->screentex); + + SDL_RenderTexture(vm->renderer, vm->screentex, NULL, NULL); + } + + if (vm->display_help) { + print(vm, 4, 4, "Drop a BytePusher file in this"); + print(vm, 8, 12, "window to load and run it!"); + print(vm, 4, 28, "Press ENTER to switch between"); + print(vm, 8, 36, "positional and symbolic input."); + } + + if (vm->status_ticks > 0) { + vm->status_ticks -= 1; + print(vm, 4, SCREEN_H - 12, vm->status); + } + + SDL_SetRenderTarget(vm->renderer, NULL); + SDL_RenderClear(vm->renderer); + SDL_RenderTexture(vm->renderer, vm->rendertarget, NULL, NULL); + SDL_RenderPresent(vm->renderer); + + return SDL_APP_CONTINUE; +} + +static Uint16 keycode_mask(SDL_Keycode key) { + int index; + if (key >= SDLK_0 && key <= SDLK_9) { + index = key - SDLK_0; + } else if (key >= SDLK_A && key <= SDLK_F) { + index = key - SDLK_A + 10; + } else { + return 0; + } + return (Uint16)1 << index; +} + +static Uint16 scancode_mask(SDL_Scancode scancode) { + int index; + switch (scancode) { + case SDL_SCANCODE_1: index = 0x1; break; + case SDL_SCANCODE_2: index = 0x2; break; + case SDL_SCANCODE_3: index = 0x3; break; + case SDL_SCANCODE_4: index = 0xc; break; + case SDL_SCANCODE_Q: index = 0x4; break; + case SDL_SCANCODE_W: index = 0x5; break; + case SDL_SCANCODE_E: index = 0x6; break; + case SDL_SCANCODE_R: index = 0xd; break; + case SDL_SCANCODE_A: index = 0x7; break; + case SDL_SCANCODE_S: index = 0x8; break; + case SDL_SCANCODE_D: index = 0x9; break; + case SDL_SCANCODE_F: index = 0xe; break; + case SDL_SCANCODE_Z: index = 0xa; break; + case SDL_SCANCODE_X: index = 0x0; break; + case SDL_SCANCODE_C: index = 0xb; break; + case SDL_SCANCODE_V: index = 0xf; break; + default: return 0; + } + return (Uint16)1 << index; +} + +SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { + BytePusher* vm = (BytePusher*)appstate; + + switch (event->type) { + case SDL_EVENT_QUIT: + return SDL_APP_SUCCESS; + + case SDL_EVENT_DROP_FILE: + load_file(vm, event->drop.data); + break; + + case SDL_EVENT_KEY_DOWN: +#ifndef __EMSCRIPTEN__ + if (event->key.key == SDLK_ESCAPE) { + return SDL_APP_SUCCESS; + } +#endif + if (event->key.key == SDLK_RETURN) { + vm->positional_input = !vm->positional_input; + vm->keystate = 0; + if (vm->positional_input) { + set_status(vm, "switched to positional input"); + } else { + set_status(vm, "switched to symbolic input"); + } + } + if (vm->positional_input) { + vm->keystate |= scancode_mask(event->key.scancode); + } else { + vm->keystate |= keycode_mask(event->key.key); + } + break; + + case SDL_EVENT_KEY_UP: + if (vm->positional_input) { + vm->keystate &= ~scancode_mask(event->key.scancode); + } else { + vm->keystate &= ~keycode_mask(event->key.key); + } + break; + } + + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void* appstate, SDL_AppResult result) { + if (result == SDL_APP_FAILURE) { + SDL_Log("Error: %s", SDL_GetError()); + } + if (appstate) { + BytePusher* vm = (BytePusher*)appstate; + SDL_DestroyAudioStream(vm->audiostream); + SDL_DestroyTexture(vm->rendertarget); + SDL_DestroyTexture(vm->screentex); + SDL_DestroySurface(vm->screen); + SDL_DestroyRenderer(vm->renderer); + SDL_DestroyWindow(vm->window); + SDL_free(vm); + } +} 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/onmouseover.webp 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 Binary files /dev/null and b/src/contrib/SDL-3.2.20/examples/demo/04-bytepusher/thumbnail.png 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 -- cgit v1.2.3