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