add networking, 3d improvements, reorganize src structure
This commit is contained in:
parent
39b604b333
commit
415d424057
122 changed files with 5358 additions and 721 deletions
485
src/core/pxl8.c
Normal file
485
src/core/pxl8.c
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
#define PXL8_AUTHORS "asrael <asrael@pxl8.org>"
|
||||
#define PXL8_COPYRIGHT "Copyright (c) 2024-2025 pxl8.org"
|
||||
#define PXL8_VERSION "0.1.0"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pxl8_game.h"
|
||||
#include "pxl8_hal.h"
|
||||
#include "pxl8_log.h"
|
||||
#include "pxl8_macros.h"
|
||||
#include "pxl8_repl.h"
|
||||
#include "pxl8_replay.h"
|
||||
#include "pxl8_script.h"
|
||||
#include "pxl8_sfx.h"
|
||||
#include "pxl8_sys.h"
|
||||
|
||||
struct pxl8 {
|
||||
pxl8_cart* cart;
|
||||
pxl8_game* game;
|
||||
pxl8_repl* repl;
|
||||
pxl8_log log;
|
||||
const pxl8_hal* hal;
|
||||
void* platform_data;
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void pxl8_audio_event_callback(u8 event_type, u8 context_id, u8 note, f32 volume, void* userdata) {
|
||||
pxl8_game* game = (pxl8_game*)userdata;
|
||||
if (game && game->debug_replay) {
|
||||
pxl8_replay_write_audio_event(game->debug_replay, game->frame_count, event_type, context_id, note, volume);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pxl8* pxl8_create(const pxl8_hal* hal) {
|
||||
pxl8* sys = (pxl8*)calloc(1, sizeof(pxl8));
|
||||
if (!sys) return NULL;
|
||||
|
||||
pxl8_log_init(&sys->log);
|
||||
|
||||
if (!hal) {
|
||||
pxl8_error("hal cannot be null");
|
||||
free(sys);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sys->hal = hal;
|
||||
|
||||
sys->game = (pxl8_game*)calloc(1, sizeof(pxl8_game));
|
||||
if (!sys->game) {
|
||||
pxl8_error("failed to allocate game");
|
||||
free(sys);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sys;
|
||||
}
|
||||
|
||||
void pxl8_destroy(pxl8* sys) {
|
||||
if (!sys) return;
|
||||
|
||||
if (sys->game) free(sys->game);
|
||||
if (sys->cart) pxl8_cart_destroy(sys->cart);
|
||||
if (sys->hal && sys->platform_data) sys->hal->destroy(sys->platform_data);
|
||||
|
||||
free(sys);
|
||||
}
|
||||
|
||||
static void pxl8_print_help(void) {
|
||||
printf("pxl8 %s - pixel art game framework\n", PXL8_VERSION);
|
||||
printf("%s\n\n", PXL8_COPYRIGHT);
|
||||
printf("Usage: pxl8 [path] [--repl]\n\n");
|
||||
printf(" pxl8 Run main.fnl from current directory\n");
|
||||
printf(" pxl8 ./game Run game from folder\n");
|
||||
printf(" pxl8 game.pxc Run packed cart file\n");
|
||||
printf(" pxl8 --repl Run with REPL enabled\n\n");
|
||||
printf("Other commands:\n");
|
||||
printf(" pxl8 pack <folder> <out.pxc> Pack folder into cart file\n");
|
||||
printf(" pxl8 bundle <in> <out> Bundle cart into executable\n");
|
||||
printf(" pxl8 help Show this help\n");
|
||||
}
|
||||
|
||||
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
|
||||
if (!sys || !sys->game) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
pxl8_game* game = sys->game;
|
||||
const char* script_arg = NULL;
|
||||
bool bundle_mode = false;
|
||||
bool pack_mode = false;
|
||||
bool run_mode = false;
|
||||
const char* pack_input = NULL;
|
||||
const char* pack_output = NULL;
|
||||
|
||||
bool has_embedded = pxl8_cart_has_embedded(argv[0]);
|
||||
|
||||
for (i32 i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "help") == 0 || strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||
pxl8_print_help();
|
||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
} else if (strcmp(argv[i], "run") == 0) {
|
||||
run_mode = true;
|
||||
} else if (strcmp(argv[i], "--repl") == 0) {
|
||||
game->repl_mode = true;
|
||||
} else if (strcmp(argv[i], "bundle") == 0 || strcmp(argv[i], "--bundle") == 0) {
|
||||
bundle_mode = true;
|
||||
if (i + 2 < argc) {
|
||||
pack_input = argv[++i];
|
||||
pack_output = argv[++i];
|
||||
} else {
|
||||
pxl8_error("bundle requires <folder|.pxc> <output>");
|
||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
} else if (strcmp(argv[i], "pack") == 0 || strcmp(argv[i], "--pack") == 0) {
|
||||
pack_mode = true;
|
||||
if (i + 2 < argc) {
|
||||
pack_input = argv[++i];
|
||||
pack_output = argv[++i];
|
||||
} else {
|
||||
pxl8_error("pack requires <folder> <output.pxc>");
|
||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
} else if (!script_arg) {
|
||||
script_arg = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!run_mode && !bundle_mode && !pack_mode) {
|
||||
run_mode = true;
|
||||
}
|
||||
|
||||
if (bundle_mode) {
|
||||
char exe_path[1024];
|
||||
ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
|
||||
if (len == -1) {
|
||||
pxl8_error("failed to resolve executable path");
|
||||
return PXL8_ERROR_SYSTEM_FAILURE;
|
||||
}
|
||||
exe_path[len] = '\0';
|
||||
pxl8_result result = pxl8_cart_bundle(pack_input, pack_output, exe_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pack_mode) {
|
||||
pxl8_result result = pxl8_cart_pack(pack_input, pack_output);
|
||||
return result;
|
||||
}
|
||||
|
||||
pxl8_info("Starting up");
|
||||
|
||||
game->script = pxl8_script_create(game->repl_mode);
|
||||
if (!game->script) {
|
||||
pxl8_error("failed to initialize scripting: %s", pxl8_script_get_last_error(game->script));
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
const char* cart_path = script_arg;
|
||||
char* original_cwd = getcwd(NULL, 0);
|
||||
|
||||
bool load_embedded = has_embedded && !run_mode;
|
||||
bool load_from_path = false;
|
||||
|
||||
if (!load_embedded && run_mode) {
|
||||
if (!cart_path) {
|
||||
if (access("main.fnl", F_OK) == 0 || access("main.lua", F_OK) == 0) {
|
||||
cart_path = ".";
|
||||
} else {
|
||||
pxl8_error("no main.fnl or main.lua found in current directory");
|
||||
free(original_cwd);
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
}
|
||||
struct stat st;
|
||||
load_from_path = (stat(cart_path, &st) == 0 && S_ISDIR(st.st_mode)) ||
|
||||
strstr(cart_path, ".pxc");
|
||||
}
|
||||
|
||||
if (load_embedded || load_from_path) {
|
||||
sys->cart = pxl8_cart_create();
|
||||
pxl8_result load_result = load_embedded
|
||||
? pxl8_cart_load_embedded(sys->cart, argv[0])
|
||||
: pxl8_cart_load(sys->cart, cart_path);
|
||||
|
||||
if (!sys->cart || load_result != PXL8_OK) {
|
||||
pxl8_error("failed to load cart%s%s", load_from_path ? ": " : "", load_from_path ? cart_path : "");
|
||||
if (sys->cart) pxl8_cart_destroy(sys->cart);
|
||||
sys->cart = NULL;
|
||||
free(original_cwd);
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
pxl8_cart_mount(sys->cart);
|
||||
pxl8_script_load_cart_manifest(game->script, sys->cart);
|
||||
if (load_from_path) {
|
||||
pxl8_script_set_cart_path(game->script, pxl8_cart_get_base_path(sys->cart), original_cwd);
|
||||
}
|
||||
pxl8_strncpy(game->script_path, "main.fnl", sizeof(game->script_path));
|
||||
} else if (script_arg) {
|
||||
pxl8_strncpy(game->script_path, script_arg, sizeof(game->script_path));
|
||||
}
|
||||
free(original_cwd);
|
||||
|
||||
const char* window_title = pxl8_cart_get_title(sys->cart);
|
||||
if (!window_title) window_title = "pxl8";
|
||||
pxl8_resolution resolution = pxl8_cart_get_resolution(sys->cart);
|
||||
pxl8_pixel_mode pixel_mode = pxl8_cart_get_pixel_mode(sys->cart);
|
||||
pxl8_size window_size = pxl8_cart_get_window_size(sys->cart);
|
||||
pxl8_size render_size = pxl8_get_resolution_dimensions(resolution);
|
||||
|
||||
sys->platform_data = sys->hal->create(render_size.w, render_size.h, window_title, window_size.w, window_size.h);
|
||||
if (!sys->platform_data) {
|
||||
pxl8_error("failed to create platform context");
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
game->gfx = pxl8_gfx_create(sys->hal, sys->platform_data, pixel_mode, resolution);
|
||||
if (!game->gfx) {
|
||||
pxl8_error("failed to create graphics context");
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
if (pxl8_gfx_load_font_atlas(game->gfx) != PXL8_OK) {
|
||||
pxl8_error("failed to load font atlas");
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
game->mixer = pxl8_sfx_mixer_create(sys->hal);
|
||||
if (!game->mixer) {
|
||||
pxl8_error("failed to create audio mixer");
|
||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
pxl8_rng_seed(&game->rng, (u32)sys->hal->get_ticks());
|
||||
|
||||
#ifndef NDEBUG
|
||||
game->debug_replay = pxl8_replay_create_buffer(60, 60);
|
||||
pxl8_sfx_mixer_set_event_callback(game->mixer, pxl8_audio_event_callback, game);
|
||||
#endif
|
||||
|
||||
if (game->repl_mode) {
|
||||
pxl8_info("starting in REPL mode with script: %s", game->script_path);
|
||||
}
|
||||
|
||||
pxl8_script_set_gfx(game->script, game->gfx);
|
||||
pxl8_script_set_input(game->script, &game->input);
|
||||
pxl8_script_set_rng(game->script, &game->rng);
|
||||
pxl8_script_set_sfx(game->script, game->mixer);
|
||||
pxl8_script_set_sys(game->script, sys);
|
||||
|
||||
if (game->script_path[0] != '\0') {
|
||||
pxl8_result result = pxl8_script_load_main(game->script, game->script_path);
|
||||
game->script_loaded = (result == PXL8_OK);
|
||||
|
||||
if (game->script_loaded && !game->repl_mode) {
|
||||
pxl8_result init_result = pxl8_script_call_function(game->script, "init");
|
||||
if (init_result != PXL8_OK) {
|
||||
pxl8_script_error("%s", pxl8_script_get_last_error(game->script));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game->last_time = sys->hal->get_ticks();
|
||||
game->running = true;
|
||||
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_update(pxl8* sys) {
|
||||
if (!sys || !sys->game) {
|
||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
pxl8_game* game = sys->game;
|
||||
u64 current_time = sys->hal->get_ticks();
|
||||
f32 dt = (f32)(current_time - game->last_time) / 1000000000.0f;
|
||||
|
||||
game->last_time = current_time;
|
||||
game->time += dt;
|
||||
game->fps_accumulator += dt;
|
||||
game->fps_frame_count++;
|
||||
|
||||
if (game->fps_accumulator >= 1.0f) {
|
||||
game->fps = (f32)game->fps_frame_count / game->fps_accumulator;
|
||||
game->fps_accumulator = 0.0f;
|
||||
game->fps_frame_count = 0;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
u32 rng_state_before_reload = game->rng.state;
|
||||
#endif
|
||||
bool reloaded = pxl8_script_check_reload(game->script);
|
||||
#ifndef NDEBUG
|
||||
if (reloaded) {
|
||||
game->rng.state = rng_state_before_reload;
|
||||
pxl8_debug("Hot-reload: restored RNG state 0x%08X", rng_state_before_reload);
|
||||
}
|
||||
#else
|
||||
(void)reloaded;
|
||||
#endif
|
||||
|
||||
if (game->repl_mode && !game->repl_started) {
|
||||
if (game->script_loaded) {
|
||||
pxl8_script_call_function(game->script, "init");
|
||||
}
|
||||
|
||||
if (pxl8_script_load_module(game->script, "pxl8") != PXL8_OK) {
|
||||
const char* err_msg = pxl8_script_get_last_error(game->script);
|
||||
pxl8_error("failed to setup pxl8 global: %s", err_msg);
|
||||
}
|
||||
|
||||
sys->repl = pxl8_repl_create();
|
||||
game->repl_started = true;
|
||||
}
|
||||
|
||||
if (game->repl_mode && sys->repl) {
|
||||
if (pxl8_repl_should_quit(sys->repl)) game->running = false;
|
||||
|
||||
pxl8_repl_command* cmd = pxl8_repl_pop_command(sys->repl);
|
||||
if (cmd) {
|
||||
pxl8_result result = pxl8_script_eval_repl(game->script, pxl8_repl_command_buffer(cmd));
|
||||
if (result != PXL8_OK) {
|
||||
if (pxl8_script_is_incomplete_input(game->script)) {
|
||||
pxl8_repl_signal_complete(sys->repl);
|
||||
} else {
|
||||
pxl8_error("%s", pxl8_script_get_last_error(game->script));
|
||||
pxl8_repl_clear_accumulator(sys->repl);
|
||||
pxl8_repl_signal_complete(sys->repl);
|
||||
}
|
||||
} else {
|
||||
pxl8_repl_clear_accumulator(sys->repl);
|
||||
pxl8_repl_signal_complete(sys->repl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_gfx_update(game->gfx, dt);
|
||||
pxl8_sfx_mixer_process(game->mixer);
|
||||
|
||||
if (game->script_loaded) {
|
||||
pxl8_script_call_function_f32(game->script, "update", dt);
|
||||
}
|
||||
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_frame(pxl8* sys) {
|
||||
if (!sys || !sys->game) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
pxl8_game* game = sys->game;
|
||||
pxl8_bounds bounds = pxl8_gfx_get_bounds(game->gfx);
|
||||
|
||||
if (game->script_loaded) {
|
||||
pxl8_result frame_result = pxl8_script_call_function(game->script, "frame");
|
||||
if (frame_result == PXL8_ERROR_SCRIPT_ERROR) {
|
||||
pxl8_error("error calling frame: %s", pxl8_script_get_last_error(game->script));
|
||||
}
|
||||
} else {
|
||||
pxl8_2d_clear(game->gfx, 32);
|
||||
|
||||
i32 render_w = pxl8_gfx_get_width(game->gfx);
|
||||
i32 render_h = pxl8_gfx_get_height(game->gfx);
|
||||
|
||||
for (i32 y = 0; y < render_h; y += 24) {
|
||||
for (i32 x = 0; x < render_w; x += 32) {
|
||||
u32 color = ((x / 32) + (y / 24) + (i32)(game->time * 2)) % 8;
|
||||
pxl8_2d_rect_fill(game->gfx, x, y, 31, 23, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_gfx_set_viewport(game->gfx, pxl8_gfx_viewport(bounds, pxl8_gfx_get_width(game->gfx), pxl8_gfx_get_height(game->gfx)));
|
||||
pxl8_gfx_upload_framebuffer(game->gfx);
|
||||
pxl8_gfx_present(game->gfx);
|
||||
|
||||
memset(game->input.keys_pressed, 0, sizeof(game->input.keys_pressed));
|
||||
memset(game->input.keys_released, 0, sizeof(game->input.keys_released));
|
||||
memset(game->input.mouse_buttons_pressed, 0, sizeof(game->input.mouse_buttons_pressed));
|
||||
memset(game->input.mouse_buttons_released, 0, sizeof(game->input.mouse_buttons_released));
|
||||
|
||||
game->frame_count++;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (game->debug_replay) {
|
||||
if (game->frame_count % 60 == 0) {
|
||||
pxl8_replay_write_keyframe(game->debug_replay, game->frame_count, game->time, &game->rng, &game->input);
|
||||
} else {
|
||||
pxl8_replay_write_input(game->debug_replay, game->frame_count, &game->prev_input, &game->input);
|
||||
}
|
||||
game->prev_input = game->input;
|
||||
}
|
||||
#endif
|
||||
|
||||
game->input.mouse_dx = 0;
|
||||
game->input.mouse_dy = 0;
|
||||
game->input.mouse_wheel_x = 0;
|
||||
game->input.mouse_wheel_y = 0;
|
||||
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
void pxl8_quit(pxl8* sys) {
|
||||
if (!sys || !sys->game) return;
|
||||
|
||||
pxl8_game* game = sys->game;
|
||||
|
||||
pxl8_info("Shutting down");
|
||||
|
||||
if (sys->cart) {
|
||||
pxl8_cart_unmount(sys->cart);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
pxl8_replay_destroy(game->debug_replay);
|
||||
#endif
|
||||
|
||||
pxl8_sfx_mixer_destroy(game->mixer);
|
||||
pxl8_gfx_destroy(game->gfx);
|
||||
pxl8_script_destroy(game->script);
|
||||
}
|
||||
|
||||
bool pxl8_is_running(const pxl8* sys) {
|
||||
return sys && sys->game && sys->game->running;
|
||||
}
|
||||
|
||||
void pxl8_set_running(pxl8* sys, bool running) {
|
||||
if (sys && sys->game) {
|
||||
sys->game->running = running;
|
||||
if (!running && sys->repl) {
|
||||
pxl8_repl_destroy(sys->repl);
|
||||
sys->repl = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f32 pxl8_get_fps(const pxl8* sys) {
|
||||
return (sys && sys->game) ? sys->game->fps : 0.0f;
|
||||
}
|
||||
|
||||
pxl8_gfx* pxl8_get_gfx(const pxl8* sys) {
|
||||
return (sys && sys->game) ? sys->game->gfx : NULL;
|
||||
}
|
||||
|
||||
pxl8_input_state* pxl8_get_input(const pxl8* sys) {
|
||||
return (sys && sys->game) ? &sys->game->input : NULL;
|
||||
}
|
||||
|
||||
pxl8_sfx_mixer* pxl8_get_sfx_mixer(const pxl8* sys) {
|
||||
return (sys && sys->game) ? sys->game->mixer : NULL;
|
||||
}
|
||||
|
||||
void pxl8_center_cursor(pxl8* sys) {
|
||||
if (!sys || !sys->hal || !sys->hal->center_cursor) return;
|
||||
sys->hal->center_cursor(sys->platform_data);
|
||||
}
|
||||
|
||||
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor) {
|
||||
if (!sys || !sys->hal || !sys->hal->set_cursor) return;
|
||||
sys->hal->set_cursor(sys->platform_data, cursor);
|
||||
}
|
||||
|
||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled) {
|
||||
if (!sys || !sys->hal || !sys->hal->set_relative_mouse_mode) return;
|
||||
sys->hal->set_relative_mouse_mode(sys->platform_data, enabled);
|
||||
if (sys->game) {
|
||||
sys->game->input.mouse_relative_mode = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution) {
|
||||
switch (resolution) {
|
||||
case PXL8_RESOLUTION_240x160: return (pxl8_size){240, 160};
|
||||
case PXL8_RESOLUTION_320x180: return (pxl8_size){320, 180};
|
||||
case PXL8_RESOLUTION_320x240: return (pxl8_size){320, 240};
|
||||
case PXL8_RESOLUTION_640x360: return (pxl8_size){640, 360};
|
||||
case PXL8_RESOLUTION_640x480: return (pxl8_size){640, 480};
|
||||
case PXL8_RESOLUTION_800x600: return (pxl8_size){800, 600};
|
||||
case PXL8_RESOLUTION_960x540: return (pxl8_size){960, 540};
|
||||
default: return (pxl8_size){640, 360};
|
||||
}
|
||||
}
|
||||
234
src/core/pxl8_bytes.c
Normal file
234
src/core/pxl8_bytes.c
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
#include "pxl8_bytes.h"
|
||||
#include <string.h>
|
||||
|
||||
void pxl8_pack_u8(u8* buf, size_t offset, u8 val) {
|
||||
buf[offset] = val;
|
||||
}
|
||||
|
||||
void pxl8_pack_u16_le(u8* buf, size_t offset, u16 val) {
|
||||
buf[offset] = (u8)(val);
|
||||
buf[offset + 1] = (u8)(val >> 8);
|
||||
}
|
||||
|
||||
void pxl8_pack_u16_be(u8* buf, size_t offset, u16 val) {
|
||||
buf[offset] = (u8)(val >> 8);
|
||||
buf[offset + 1] = (u8)(val);
|
||||
}
|
||||
|
||||
void pxl8_pack_u32_le(u8* buf, size_t offset, u32 val) {
|
||||
buf[offset] = (u8)(val);
|
||||
buf[offset + 1] = (u8)(val >> 8);
|
||||
buf[offset + 2] = (u8)(val >> 16);
|
||||
buf[offset + 3] = (u8)(val >> 24);
|
||||
}
|
||||
|
||||
void pxl8_pack_u32_be(u8* buf, size_t offset, u32 val) {
|
||||
buf[offset] = (u8)(val >> 24);
|
||||
buf[offset + 1] = (u8)(val >> 16);
|
||||
buf[offset + 2] = (u8)(val >> 8);
|
||||
buf[offset + 3] = (u8)(val);
|
||||
}
|
||||
|
||||
void pxl8_pack_u64_le(u8* buf, size_t offset, u64 val) {
|
||||
buf[offset] = (u8)(val);
|
||||
buf[offset + 1] = (u8)(val >> 8);
|
||||
buf[offset + 2] = (u8)(val >> 16);
|
||||
buf[offset + 3] = (u8)(val >> 24);
|
||||
buf[offset + 4] = (u8)(val >> 32);
|
||||
buf[offset + 5] = (u8)(val >> 40);
|
||||
buf[offset + 6] = (u8)(val >> 48);
|
||||
buf[offset + 7] = (u8)(val >> 56);
|
||||
}
|
||||
|
||||
void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val) {
|
||||
buf[offset] = (u8)(val >> 56);
|
||||
buf[offset + 1] = (u8)(val >> 48);
|
||||
buf[offset + 2] = (u8)(val >> 40);
|
||||
buf[offset + 3] = (u8)(val >> 32);
|
||||
buf[offset + 4] = (u8)(val >> 24);
|
||||
buf[offset + 5] = (u8)(val >> 16);
|
||||
buf[offset + 6] = (u8)(val >> 8);
|
||||
buf[offset + 7] = (u8)(val);
|
||||
}
|
||||
|
||||
void pxl8_pack_i8(u8* buf, size_t offset, i8 val) {
|
||||
buf[offset] = (u8)val;
|
||||
}
|
||||
|
||||
void pxl8_pack_i16_le(u8* buf, size_t offset, i16 val) {
|
||||
pxl8_pack_u16_le(buf, offset, (u16)val);
|
||||
}
|
||||
|
||||
void pxl8_pack_i16_be(u8* buf, size_t offset, i16 val) {
|
||||
pxl8_pack_u16_be(buf, offset, (u16)val);
|
||||
}
|
||||
|
||||
void pxl8_pack_i32_le(u8* buf, size_t offset, i32 val) {
|
||||
pxl8_pack_u32_le(buf, offset, (u32)val);
|
||||
}
|
||||
|
||||
void pxl8_pack_i32_be(u8* buf, size_t offset, i32 val) {
|
||||
pxl8_pack_u32_be(buf, offset, (u32)val);
|
||||
}
|
||||
|
||||
void pxl8_pack_i64_le(u8* buf, size_t offset, i64 val) {
|
||||
pxl8_pack_u64_le(buf, offset, (u64)val);
|
||||
}
|
||||
|
||||
void pxl8_pack_i64_be(u8* buf, size_t offset, i64 val) {
|
||||
pxl8_pack_u64_be(buf, offset, (u64)val);
|
||||
}
|
||||
|
||||
void pxl8_pack_f32_le(u8* buf, size_t offset, f32 val) {
|
||||
u32 bits;
|
||||
memcpy(&bits, &val, sizeof(bits));
|
||||
pxl8_pack_u32_le(buf, offset, bits);
|
||||
}
|
||||
|
||||
void pxl8_pack_f32_be(u8* buf, size_t offset, f32 val) {
|
||||
u32 bits;
|
||||
memcpy(&bits, &val, sizeof(bits));
|
||||
pxl8_pack_u32_be(buf, offset, bits);
|
||||
}
|
||||
|
||||
void pxl8_pack_f64_le(u8* buf, size_t offset, f64 val) {
|
||||
u64 bits;
|
||||
memcpy(&bits, &val, sizeof(bits));
|
||||
pxl8_pack_u64_le(buf, offset, bits);
|
||||
}
|
||||
|
||||
void pxl8_pack_f64_be(u8* buf, size_t offset, f64 val) {
|
||||
u64 bits;
|
||||
memcpy(&bits, &val, sizeof(bits));
|
||||
pxl8_pack_u64_be(buf, offset, bits);
|
||||
}
|
||||
|
||||
u8 pxl8_unpack_u8(const u8* buf, size_t offset) {
|
||||
return buf[offset];
|
||||
}
|
||||
|
||||
u16 pxl8_unpack_u16_le(const u8* buf, size_t offset) {
|
||||
return (u16)buf[offset] | ((u16)buf[offset + 1] << 8);
|
||||
}
|
||||
|
||||
u16 pxl8_unpack_u16_be(const u8* buf, size_t offset) {
|
||||
return ((u16)buf[offset] << 8) | (u16)buf[offset + 1];
|
||||
}
|
||||
|
||||
u32 pxl8_unpack_u32_le(const u8* buf, size_t offset) {
|
||||
return (u32)buf[offset] |
|
||||
((u32)buf[offset + 1] << 8) |
|
||||
((u32)buf[offset + 2] << 16) |
|
||||
((u32)buf[offset + 3] << 24);
|
||||
}
|
||||
|
||||
u32 pxl8_unpack_u32_be(const u8* buf, size_t offset) {
|
||||
return ((u32)buf[offset] << 24) |
|
||||
((u32)buf[offset + 1] << 16) |
|
||||
((u32)buf[offset + 2] << 8) |
|
||||
(u32)buf[offset + 3];
|
||||
}
|
||||
|
||||
u64 pxl8_unpack_u64_le(const u8* buf, size_t offset) {
|
||||
return (u64)buf[offset] |
|
||||
((u64)buf[offset + 1] << 8) |
|
||||
((u64)buf[offset + 2] << 16) |
|
||||
((u64)buf[offset + 3] << 24) |
|
||||
((u64)buf[offset + 4] << 32) |
|
||||
((u64)buf[offset + 5] << 40) |
|
||||
((u64)buf[offset + 6] << 48) |
|
||||
((u64)buf[offset + 7] << 56);
|
||||
}
|
||||
|
||||
u64 pxl8_unpack_u64_be(const u8* buf, size_t offset) {
|
||||
return ((u64)buf[offset] << 56) |
|
||||
((u64)buf[offset + 1] << 48) |
|
||||
((u64)buf[offset + 2] << 40) |
|
||||
((u64)buf[offset + 3] << 32) |
|
||||
((u64)buf[offset + 4] << 24) |
|
||||
((u64)buf[offset + 5] << 16) |
|
||||
((u64)buf[offset + 6] << 8) |
|
||||
(u64)buf[offset + 7];
|
||||
}
|
||||
|
||||
i8 pxl8_unpack_i8(const u8* buf, size_t offset) {
|
||||
return (i8)buf[offset];
|
||||
}
|
||||
|
||||
i16 pxl8_unpack_i16_le(const u8* buf, size_t offset) {
|
||||
return (i16)pxl8_unpack_u16_le(buf, offset);
|
||||
}
|
||||
|
||||
i16 pxl8_unpack_i16_be(const u8* buf, size_t offset) {
|
||||
return (i16)pxl8_unpack_u16_be(buf, offset);
|
||||
}
|
||||
|
||||
i32 pxl8_unpack_i32_le(const u8* buf, size_t offset) {
|
||||
return (i32)pxl8_unpack_u32_le(buf, offset);
|
||||
}
|
||||
|
||||
i32 pxl8_unpack_i32_be(const u8* buf, size_t offset) {
|
||||
return (i32)pxl8_unpack_u32_be(buf, offset);
|
||||
}
|
||||
|
||||
i64 pxl8_unpack_i64_le(const u8* buf, size_t offset) {
|
||||
return (i64)pxl8_unpack_u64_le(buf, offset);
|
||||
}
|
||||
|
||||
i64 pxl8_unpack_i64_be(const u8* buf, size_t offset) {
|
||||
return (i64)pxl8_unpack_u64_be(buf, offset);
|
||||
}
|
||||
|
||||
f32 pxl8_unpack_f32_le(const u8* buf, size_t offset) {
|
||||
u32 bits = pxl8_unpack_u32_le(buf, offset);
|
||||
f32 result;
|
||||
memcpy(&result, &bits, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
f32 pxl8_unpack_f32_be(const u8* buf, size_t offset) {
|
||||
u32 bits = pxl8_unpack_u32_be(buf, offset);
|
||||
f32 result;
|
||||
memcpy(&result, &bits, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
f64 pxl8_unpack_f64_le(const u8* buf, size_t offset) {
|
||||
u64 bits = pxl8_unpack_u64_le(buf, offset);
|
||||
f64 result;
|
||||
memcpy(&result, &bits, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
f64 pxl8_unpack_f64_be(const u8* buf, size_t offset) {
|
||||
u64 bits = pxl8_unpack_u64_be(buf, offset);
|
||||
f64 result;
|
||||
memcpy(&result, &bits, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
void pxl8_bit_set(u32* val, u8 bit) {
|
||||
*val |= (1u << bit);
|
||||
}
|
||||
|
||||
void pxl8_bit_clear(u32* val, u8 bit) {
|
||||
*val &= ~(1u << bit);
|
||||
}
|
||||
|
||||
bool pxl8_bit_test(u32 val, u8 bit) {
|
||||
return (val & (1u << bit)) != 0;
|
||||
}
|
||||
|
||||
u32 pxl8_bit_count(u32 val) {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return (u32)__builtin_popcount(val);
|
||||
#else
|
||||
val = val - ((val >> 1) & 0x55555555);
|
||||
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
|
||||
return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
void pxl8_bit_toggle(u32* val, u8 bit) {
|
||||
*val ^= (1u << bit);
|
||||
}
|
||||
251
src/core/pxl8_bytes.h
Normal file
251
src/core/pxl8_bytes.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "pxl8_types.h"
|
||||
|
||||
void pxl8_bit_clear(u32* val, u8 bit);
|
||||
u32 pxl8_bit_count(u32 val);
|
||||
void pxl8_bit_set(u32* val, u8 bit);
|
||||
bool pxl8_bit_test(u32 val, u8 bit);
|
||||
void pxl8_bit_toggle(u32* val, u8 bit);
|
||||
|
||||
void pxl8_pack_u8(u8* buf, size_t offset, u8 val);
|
||||
void pxl8_pack_u16_be(u8* buf, size_t offset, u16 val);
|
||||
void pxl8_pack_u16_le(u8* buf, size_t offset, u16 val);
|
||||
void pxl8_pack_u32_be(u8* buf, size_t offset, u32 val);
|
||||
void pxl8_pack_u32_le(u8* buf, size_t offset, u32 val);
|
||||
void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val);
|
||||
void pxl8_pack_u64_le(u8* buf, size_t offset, u64 val);
|
||||
void pxl8_pack_i8(u8* buf, size_t offset, i8 val);
|
||||
void pxl8_pack_i16_be(u8* buf, size_t offset, i16 val);
|
||||
void pxl8_pack_i16_le(u8* buf, size_t offset, i16 val);
|
||||
void pxl8_pack_i32_be(u8* buf, size_t offset, i32 val);
|
||||
void pxl8_pack_i32_le(u8* buf, size_t offset, i32 val);
|
||||
void pxl8_pack_i64_be(u8* buf, size_t offset, i64 val);
|
||||
void pxl8_pack_i64_le(u8* buf, size_t offset, i64 val);
|
||||
void pxl8_pack_f32_be(u8* buf, size_t offset, f32 val);
|
||||
void pxl8_pack_f32_le(u8* buf, size_t offset, f32 val);
|
||||
void pxl8_pack_f64_be(u8* buf, size_t offset, f64 val);
|
||||
void pxl8_pack_f64_le(u8* buf, size_t offset, f64 val);
|
||||
|
||||
u8 pxl8_unpack_u8(const u8* buf, size_t offset);
|
||||
u16 pxl8_unpack_u16_be(const u8* buf, size_t offset);
|
||||
u16 pxl8_unpack_u16_le(const u8* buf, size_t offset);
|
||||
u32 pxl8_unpack_u32_be(const u8* buf, size_t offset);
|
||||
u32 pxl8_unpack_u32_le(const u8* buf, size_t offset);
|
||||
u64 pxl8_unpack_u64_be(const u8* buf, size_t offset);
|
||||
u64 pxl8_unpack_u64_le(const u8* buf, size_t offset);
|
||||
i8 pxl8_unpack_i8(const u8* buf, size_t offset);
|
||||
i16 pxl8_unpack_i16_be(const u8* buf, size_t offset);
|
||||
i16 pxl8_unpack_i16_le(const u8* buf, size_t offset);
|
||||
i32 pxl8_unpack_i32_be(const u8* buf, size_t offset);
|
||||
i32 pxl8_unpack_i32_le(const u8* buf, size_t offset);
|
||||
i64 pxl8_unpack_i64_be(const u8* buf, size_t offset);
|
||||
i64 pxl8_unpack_i64_le(const u8* buf, size_t offset);
|
||||
f32 pxl8_unpack_f32_be(const u8* buf, size_t offset);
|
||||
f32 pxl8_unpack_f32_le(const u8* buf, size_t offset);
|
||||
f64 pxl8_unpack_f64_be(const u8* buf, size_t offset);
|
||||
f64 pxl8_unpack_f64_le(const u8* buf, size_t offset);
|
||||
|
||||
typedef struct {
|
||||
const u8* bytes;
|
||||
u32 offset;
|
||||
u32 size;
|
||||
bool overflow;
|
||||
} pxl8_stream;
|
||||
|
||||
typedef struct {
|
||||
u8* bytes;
|
||||
u32 capacity;
|
||||
u32 offset;
|
||||
bool overflow;
|
||||
} pxl8_write_stream;
|
||||
|
||||
static inline pxl8_stream pxl8_stream_create(const u8* bytes, u32 size) {
|
||||
return (pxl8_stream){
|
||||
.bytes = bytes,
|
||||
.offset = 0,
|
||||
.size = size,
|
||||
.overflow = false
|
||||
};
|
||||
}
|
||||
|
||||
static inline pxl8_write_stream pxl8_write_stream_create(u8* bytes, u32 capacity) {
|
||||
return (pxl8_write_stream){
|
||||
.bytes = bytes,
|
||||
.capacity = capacity,
|
||||
.offset = 0,
|
||||
.overflow = false
|
||||
};
|
||||
}
|
||||
|
||||
static inline bool pxl8_stream_can_read(const pxl8_stream* s, u32 count) {
|
||||
return !s->overflow && s->offset + count <= s->size;
|
||||
}
|
||||
|
||||
static inline bool pxl8_stream_has_overflow(const pxl8_stream* s) {
|
||||
return s->overflow;
|
||||
}
|
||||
|
||||
static inline bool pxl8_write_stream_has_overflow(const pxl8_write_stream* s) {
|
||||
return s->overflow;
|
||||
}
|
||||
|
||||
static inline u32 pxl8_stream_position(const pxl8_stream* s) {
|
||||
return s->offset;
|
||||
}
|
||||
|
||||
static inline u32 pxl8_write_stream_position(const pxl8_write_stream* s) {
|
||||
return s->offset;
|
||||
}
|
||||
|
||||
static inline void pxl8_stream_seek(pxl8_stream* s, u32 offset) {
|
||||
s->offset = offset;
|
||||
}
|
||||
|
||||
static inline u8 pxl8_read_u8(pxl8_stream* s) {
|
||||
if (s->offset + 1 > s->size) { s->overflow = true; return 0; }
|
||||
return pxl8_unpack_u8(s->bytes, s->offset++);
|
||||
}
|
||||
|
||||
static inline u16 pxl8_read_u16(pxl8_stream* s) {
|
||||
if (s->offset + 2 > s->size) { s->overflow = true; return 0; }
|
||||
u16 val = pxl8_unpack_u16_le(s->bytes, s->offset);
|
||||
s->offset += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u16 pxl8_read_u16_be(pxl8_stream* s) {
|
||||
if (s->offset + 2 > s->size) { s->overflow = true; return 0; }
|
||||
u16 val = pxl8_unpack_u16_be(s->bytes, s->offset);
|
||||
s->offset += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u32 pxl8_read_u32(pxl8_stream* s) {
|
||||
if (s->offset + 4 > s->size) { s->overflow = true; return 0; }
|
||||
u32 val = pxl8_unpack_u32_le(s->bytes, s->offset);
|
||||
s->offset += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u32 pxl8_read_u32_be(pxl8_stream* s) {
|
||||
if (s->offset + 4 > s->size) { s->overflow = true; return 0; }
|
||||
u32 val = pxl8_unpack_u32_be(s->bytes, s->offset);
|
||||
s->offset += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u64 pxl8_read_u64(pxl8_stream* s) {
|
||||
if (s->offset + 8 > s->size) { s->overflow = true; return 0; }
|
||||
u64 val = pxl8_unpack_u64_le(s->bytes, s->offset);
|
||||
s->offset += 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u64 pxl8_read_u64_be(pxl8_stream* s) {
|
||||
if (s->offset + 8 > s->size) { s->overflow = true; return 0; }
|
||||
u64 val = pxl8_unpack_u64_be(s->bytes, s->offset);
|
||||
s->offset += 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline i16 pxl8_read_i16(pxl8_stream* s) {
|
||||
return (i16)pxl8_read_u16(s);
|
||||
}
|
||||
|
||||
static inline i32 pxl8_read_i32(pxl8_stream* s) {
|
||||
return (i32)pxl8_read_u32(s);
|
||||
}
|
||||
|
||||
static inline f32 pxl8_read_f32(pxl8_stream* s) {
|
||||
if (s->offset + 4 > s->size) { s->overflow = true; return 0; }
|
||||
f32 val = pxl8_unpack_f32_le(s->bytes, s->offset);
|
||||
s->offset += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline f32 pxl8_read_f32_be(pxl8_stream* s) {
|
||||
if (s->offset + 4 > s->size) { s->overflow = true; return 0; }
|
||||
f32 val = pxl8_unpack_f32_be(s->bytes, s->offset);
|
||||
s->offset += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void pxl8_read_bytes(pxl8_stream* s, void* dest, u32 count) {
|
||||
if (s->offset + count > s->size) { s->overflow = true; return; }
|
||||
memcpy(dest, &s->bytes[s->offset], count);
|
||||
s->offset += count;
|
||||
}
|
||||
|
||||
static inline void pxl8_skip_bytes(pxl8_stream* s, u32 count) {
|
||||
if (s->offset + count > s->size) { s->overflow = true; return; }
|
||||
s->offset += count;
|
||||
}
|
||||
|
||||
static inline const u8* pxl8_read_ptr(pxl8_stream* s, u32 count) {
|
||||
if (s->offset + count > s->size) { s->overflow = true; return NULL; }
|
||||
const u8* ptr = &s->bytes[s->offset];
|
||||
s->offset += count;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u8(pxl8_write_stream* s, u8 val) {
|
||||
if (s->offset + 1 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u8(s->bytes, s->offset++, val);
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u16(pxl8_write_stream* s, u16 val) {
|
||||
if (s->offset + 2 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u16_le(s->bytes, s->offset, val);
|
||||
s->offset += 2;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u16_be(pxl8_write_stream* s, u16 val) {
|
||||
if (s->offset + 2 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u16_be(s->bytes, s->offset, val);
|
||||
s->offset += 2;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u32(pxl8_write_stream* s, u32 val) {
|
||||
if (s->offset + 4 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u32_le(s->bytes, s->offset, val);
|
||||
s->offset += 4;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u32_be(pxl8_write_stream* s, u32 val) {
|
||||
if (s->offset + 4 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u32_be(s->bytes, s->offset, val);
|
||||
s->offset += 4;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u64(pxl8_write_stream* s, u64 val) {
|
||||
if (s->offset + 8 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u64_le(s->bytes, s->offset, val);
|
||||
s->offset += 8;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_u64_be(pxl8_write_stream* s, u64 val) {
|
||||
if (s->offset + 8 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_u64_be(s->bytes, s->offset, val);
|
||||
s->offset += 8;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_f32(pxl8_write_stream* s, f32 val) {
|
||||
if (s->offset + 4 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_f32_le(s->bytes, s->offset, val);
|
||||
s->offset += 4;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_f32_be(pxl8_write_stream* s, f32 val) {
|
||||
if (s->offset + 4 > s->capacity) { s->overflow = true; return; }
|
||||
pxl8_pack_f32_be(s->bytes, s->offset, val);
|
||||
s->offset += 4;
|
||||
}
|
||||
|
||||
static inline void pxl8_write_bytes(pxl8_write_stream* s, const void* src, u32 count) {
|
||||
if (s->offset + count > s->capacity) { s->overflow = true; return; }
|
||||
memcpy(&s->bytes[s->offset], src, count);
|
||||
s->offset += count;
|
||||
}
|
||||
221
src/core/pxl8_io.c
Normal file
221
src/core/pxl8_io.c
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#include "pxl8_io.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pxl8_cart.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
static inline char pxl8_to_lower(char c) {
|
||||
return (c >= 'A' && c <= 'Z') ? c + 32 : c;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size) {
|
||||
if (!path || !content || !size) return PXL8_ERROR_NULL_POINTER;
|
||||
|
||||
pxl8_cart* cart = pxl8_get_cart();
|
||||
if (cart && pxl8_cart_is_packed(cart)) {
|
||||
u8* data = NULL;
|
||||
u32 cart_size = 0;
|
||||
pxl8_result result = pxl8_cart_read_file(cart, path, &data, &cart_size);
|
||||
if (result == PXL8_OK) {
|
||||
*content = realloc(data, cart_size + 1);
|
||||
if (!*content) {
|
||||
pxl8_cart_free_file(data);
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
(*content)[cart_size] = '\0';
|
||||
*size = cart_size;
|
||||
return PXL8_OK;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* file = fopen(path, "rb");
|
||||
if (!file) {
|
||||
return PXL8_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
long file_size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
if (file_size < 0) {
|
||||
fclose(file);
|
||||
return PXL8_ERROR_SYSTEM_FAILURE;
|
||||
}
|
||||
|
||||
*content = malloc(file_size + 1);
|
||||
if (!*content) {
|
||||
fclose(file);
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
size_t bytes_read = fread(*content, 1, file_size, file);
|
||||
(*content)[bytes_read] = '\0';
|
||||
*size = bytes_read;
|
||||
|
||||
fclose(file);
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t size) {
|
||||
if (!path || !content) return PXL8_ERROR_NULL_POINTER;
|
||||
|
||||
FILE* file = fopen(path, "wb");
|
||||
if (!file) {
|
||||
return PXL8_ERROR_SYSTEM_FAILURE;
|
||||
}
|
||||
|
||||
size_t bytes_written = fwrite(content, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
return (bytes_written == size) ? PXL8_OK : PXL8_ERROR_SYSTEM_FAILURE;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, size_t* size) {
|
||||
return pxl8_io_read_file(path, (char**)data, size);
|
||||
}
|
||||
|
||||
pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, size_t size) {
|
||||
return pxl8_io_write_file(path, (const char*)data, size);
|
||||
}
|
||||
|
||||
bool pxl8_io_file_exists(const char* path) {
|
||||
if (!path) return false;
|
||||
|
||||
struct stat st;
|
||||
return stat(path, &st) == 0;
|
||||
}
|
||||
|
||||
f64 pxl8_io_get_file_modified_time(const char* path) {
|
||||
if (!path) return 0.0;
|
||||
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0) {
|
||||
return st.st_mtime;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_io_create_directory(const char* path) {
|
||||
if (!path) return PXL8_ERROR_NULL_POINTER;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (mkdir(path) != 0) {
|
||||
#else
|
||||
if (mkdir(path, 0755) != 0) {
|
||||
#endif
|
||||
return PXL8_ERROR_SYSTEM_FAILURE;
|
||||
}
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
void pxl8_io_free_file_content(char* content) {
|
||||
if (content) {
|
||||
free(content);
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_io_free_binary_data(u8* data) {
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
static i32 pxl8_key_code(const char* key_name) {
|
||||
if (!key_name || !key_name[0]) return 0;
|
||||
|
||||
typedef struct { const char* name; i32 code; } KeyMapping;
|
||||
static const KeyMapping keys[] = {
|
||||
{"a", 4}, {"b", 5}, {"c", 6}, {"d", 7}, {"e", 8}, {"f", 9}, {"g", 10}, {"h", 11},
|
||||
{"i", 12}, {"j", 13}, {"k", 14}, {"l", 15}, {"m", 16}, {"n", 17}, {"o", 18}, {"p", 19},
|
||||
{"q", 20}, {"r", 21}, {"s", 22}, {"t", 23}, {"u", 24}, {"v", 25}, {"w", 26}, {"x", 27},
|
||||
{"y", 28}, {"z", 29},
|
||||
{"1", 30}, {"2", 31}, {"3", 32}, {"4", 33}, {"5", 34},
|
||||
{"6", 35}, {"7", 36}, {"8", 37}, {"9", 38}, {"0", 39},
|
||||
{"return", 40}, {"escape", 41}, {"backspace", 42}, {"tab", 43}, {"space", 44},
|
||||
{"-", 45}, {"=", 46}, {"`", 53},
|
||||
{"left", 80}, {"right", 79}, {"up", 82}, {"down", 81},
|
||||
{"f1", 58}, {"f2", 59}, {"f3", 60}, {"f4", 61}, {"f5", 62}, {"f6", 63},
|
||||
{"f7", 64}, {"f8", 65}, {"f9", 66}, {"f10", 67}, {"f11", 68}, {"f12", 69},
|
||||
{"capslock", 57}, {"lshift", 225}, {"rshift", 229},
|
||||
{"lctrl", 224}, {"rctrl", 228}, {"lalt", 226}, {"ralt", 230},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
char lower_name[64];
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(lower_name) - 1 && key_name[i]; i++) {
|
||||
lower_name[i] = pxl8_to_lower(key_name[i]);
|
||||
}
|
||||
lower_name[i] = '\0';
|
||||
|
||||
for (i = 0; keys[i].name; i++) {
|
||||
if (strcmp(lower_name, keys[i].name) == 0) {
|
||||
return keys[i].code;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool pxl8_key_down(const pxl8_input_state* input, const char* key_name) {
|
||||
if (!input) return false;
|
||||
i32 key = pxl8_key_code(key_name);
|
||||
if (key < 0 || key >= PXL8_MAX_KEYS) return false;
|
||||
return input->keys_down[key];
|
||||
}
|
||||
|
||||
bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name) {
|
||||
if (!input) return false;
|
||||
i32 key = pxl8_key_code(key_name);
|
||||
if (key < 0 || key >= PXL8_MAX_KEYS) return false;
|
||||
return input->keys_pressed[key];
|
||||
}
|
||||
|
||||
bool pxl8_key_released(const pxl8_input_state* input, const char* key_name) {
|
||||
if (!input) return false;
|
||||
i32 key = pxl8_key_code(key_name);
|
||||
if (key < 0 || key >= PXL8_MAX_KEYS) return false;
|
||||
return input->keys_released[key];
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_wheel_x(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_wheel_x;
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_wheel_y(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_wheel_y;
|
||||
}
|
||||
|
||||
bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button) {
|
||||
if (!input || button < 1 || button > 3) return false;
|
||||
return input->mouse_buttons_pressed[button - 1];
|
||||
}
|
||||
|
||||
bool pxl8_mouse_released(const pxl8_input_state* input, i32 button) {
|
||||
if (!input || button < 1 || button > 3) return false;
|
||||
return input->mouse_buttons_released[button - 1];
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_x(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_x;
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_y(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_y;
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_dx(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_dx;
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_dy(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_dy;
|
||||
}
|
||||
38
src/core/pxl8_io.h
Normal file
38
src/core/pxl8_io.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "pxl8_bytes.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
pxl8_result pxl8_io_create_directory(const char* path);
|
||||
bool pxl8_io_file_exists(const char* path);
|
||||
void pxl8_io_free_binary_data(u8* data);
|
||||
void pxl8_io_free_file_content(char* content);
|
||||
f64 pxl8_io_get_file_modified_time(const char* path);
|
||||
pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, size_t* size);
|
||||
pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size);
|
||||
pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, size_t size);
|
||||
pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t size);
|
||||
|
||||
bool pxl8_key_down(const pxl8_input_state* input, const char* key_name);
|
||||
bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name);
|
||||
bool pxl8_key_released(const pxl8_input_state* input, const char* key_name);
|
||||
|
||||
i32 pxl8_mouse_dx(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_dy(const pxl8_input_state* input);
|
||||
bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button);
|
||||
bool pxl8_mouse_released(const pxl8_input_state* input, i32 button);
|
||||
i32 pxl8_mouse_wheel_x(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_wheel_y(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_x(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_y(const pxl8_input_state* input);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
113
src/core/pxl8_log.c
Normal file
113
src/core/pxl8_log.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#include "pxl8_log.h"
|
||||
#include "pxl8_repl.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define PXL8_LOG_COLOR_ERROR "\033[38;2;251;73;52m"
|
||||
#define PXL8_LOG_COLOR_WARN "\033[38;2;250;189;47m"
|
||||
#define PXL8_LOG_COLOR_INFO "\033[38;2;184;187;38m"
|
||||
#define PXL8_LOG_COLOR_DEBUG "\033[38;2;131;165;152m"
|
||||
#define PXL8_LOG_COLOR_TRACE "\033[38;2;211;134;155m"
|
||||
#define PXL8_LOG_COLOR_RESET "\033[0m"
|
||||
|
||||
static pxl8_log* g_log = NULL;
|
||||
|
||||
void pxl8_log_init(pxl8_log* log) {
|
||||
g_log = log;
|
||||
g_log->level = PXL8_LOG_LEVEL_DEBUG;
|
||||
|
||||
const char* env_level = getenv("PXL8_LOG_LEVEL");
|
||||
if (env_level) {
|
||||
if (strcmp(env_level, "trace") == 0) g_log->level = PXL8_LOG_LEVEL_TRACE;
|
||||
else if (strcmp(env_level, "debug") == 0) g_log->level = PXL8_LOG_LEVEL_DEBUG;
|
||||
else if (strcmp(env_level, "info") == 0) g_log->level = PXL8_LOG_LEVEL_INFO;
|
||||
else if (strcmp(env_level, "warn") == 0) g_log->level = PXL8_LOG_LEVEL_WARN;
|
||||
else if (strcmp(env_level, "error") == 0) g_log->level = PXL8_LOG_LEVEL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_log_set_level(pxl8_log_level level) {
|
||||
if (g_log) g_log->level = level;
|
||||
}
|
||||
|
||||
static void log_timestamp(char* buffer, size_t size) {
|
||||
time_t now = time(NULL);
|
||||
struct tm* tm_info = localtime(&now);
|
||||
strftime(buffer, size, "%H:%M:%S", tm_info);
|
||||
}
|
||||
|
||||
static void log_output(const char* color, const char* level,
|
||||
const char* file, int line, const char* fmt, va_list args) {
|
||||
char buffer[4096];
|
||||
char timestamp[16];
|
||||
log_timestamp(timestamp, sizeof(timestamp));
|
||||
|
||||
int pos = 0;
|
||||
if (file) {
|
||||
pos = snprintf(buffer, sizeof(buffer), "%s[%s %s]" PXL8_LOG_COLOR_RESET " %s:%d: ",
|
||||
color, timestamp, level, file, line);
|
||||
} else {
|
||||
pos = snprintf(buffer, sizeof(buffer), "%s[%s %s]" PXL8_LOG_COLOR_RESET " ",
|
||||
color, timestamp, level);
|
||||
}
|
||||
|
||||
if (pos > 0 && pos < (int)sizeof(buffer)) {
|
||||
vsnprintf(buffer + pos, sizeof(buffer) - pos, fmt, args);
|
||||
}
|
||||
|
||||
strncat(buffer, "\n", sizeof(buffer) - strlen(buffer) - 1);
|
||||
|
||||
if (!pxl8_repl_push_log(buffer)) {
|
||||
printf("%s", buffer);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_log_write_trace(const char* file, int line, const char* fmt, ...) {
|
||||
if (!g_log || g_log->level > PXL8_LOG_LEVEL_TRACE) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_output(PXL8_LOG_COLOR_TRACE, "TRACE", file, line, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void pxl8_log_write_debug(const char* file, int line, const char* fmt, ...) {
|
||||
if (!g_log || g_log->level > PXL8_LOG_LEVEL_DEBUG) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_output(PXL8_LOG_COLOR_DEBUG, "DEBUG", file, line, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void pxl8_log_write_info(const char* fmt, ...) {
|
||||
if (!g_log || g_log->level > PXL8_LOG_LEVEL_INFO) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_output(PXL8_LOG_COLOR_INFO, "INFO", NULL, 0, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void pxl8_log_write_warn(const char* file, int line, const char* fmt, ...) {
|
||||
if (!g_log || g_log->level > PXL8_LOG_LEVEL_WARN) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_output(PXL8_LOG_COLOR_WARN, "WARN", file, line, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void pxl8_log_write_error(const char* file, int line, const char* fmt, ...) {
|
||||
if (!g_log || g_log->level > PXL8_LOG_LEVEL_ERROR) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_output(PXL8_LOG_COLOR_ERROR, "ERROR", file, line, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
31
src/core/pxl8_log.h
Normal file
31
src/core/pxl8_log.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
PXL8_LOG_LEVEL_TRACE = 0,
|
||||
PXL8_LOG_LEVEL_DEBUG = 1,
|
||||
PXL8_LOG_LEVEL_INFO = 2,
|
||||
PXL8_LOG_LEVEL_WARN = 3,
|
||||
PXL8_LOG_LEVEL_ERROR = 4,
|
||||
} pxl8_log_level;
|
||||
|
||||
typedef struct pxl8_log {
|
||||
pxl8_log_level level;
|
||||
} pxl8_log;
|
||||
|
||||
void pxl8_log_init(pxl8_log* log);
|
||||
void pxl8_log_set_level(pxl8_log_level level);
|
||||
|
||||
void pxl8_log_write_trace(const char* file, int line, const char* fmt, ...);
|
||||
void pxl8_log_write_debug(const char* file, int line, const char* fmt, ...);
|
||||
void pxl8_log_write_info(const char* fmt, ...);
|
||||
void pxl8_log_write_warn(const char* file, int line, const char* fmt, ...);
|
||||
void pxl8_log_write_error(const char* file, int line, const char* fmt, ...);
|
||||
|
||||
#define pxl8_trace(...) pxl8_log_write_trace(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define pxl8_debug(...) pxl8_log_write_debug(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define pxl8_info(...) pxl8_log_write_info(__VA_ARGS__)
|
||||
#define pxl8_warn(...) pxl8_log_write_warn(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define pxl8_error(...) pxl8_log_write_error(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define pxl8_script_error(...) pxl8_log_write_error(NULL, 0, __VA_ARGS__)
|
||||
18
src/core/pxl8_macros.h
Normal file
18
src/core/pxl8_macros.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef pxl8_min
|
||||
#define pxl8_min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef pxl8_max
|
||||
#define pxl8_max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef pxl8_strncpy
|
||||
#define pxl8_strncpy(dst, src, size) do { \
|
||||
strncpy((dst), (src), (size) - 1); \
|
||||
(dst)[(size) - 1] = '\0'; \
|
||||
} while (0)
|
||||
#endif
|
||||
24
src/core/pxl8_rng.c
Normal file
24
src/core/pxl8_rng.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "pxl8_rng.h"
|
||||
|
||||
void pxl8_rng_seed(pxl8_rng* rng, u32 seed) {
|
||||
if (!rng) return;
|
||||
rng->state = seed ? seed : 1;
|
||||
}
|
||||
|
||||
u32 pxl8_rng_next(pxl8_rng* rng) {
|
||||
if (!rng) return 0;
|
||||
rng->state ^= rng->state << 13;
|
||||
rng->state ^= rng->state >> 17;
|
||||
rng->state ^= rng->state << 5;
|
||||
return rng->state;
|
||||
}
|
||||
|
||||
f32 pxl8_rng_f32(pxl8_rng* rng) {
|
||||
return (f32)pxl8_rng_next(rng) / (f32)0xFFFFFFFF;
|
||||
}
|
||||
|
||||
i32 pxl8_rng_range(pxl8_rng* rng, i32 min, i32 max) {
|
||||
if (min >= max) return min;
|
||||
u32 range = (u32)(max - min);
|
||||
return min + (i32)(pxl8_rng_next(rng) % range);
|
||||
}
|
||||
20
src/core/pxl8_rng.h
Normal file
20
src/core/pxl8_rng.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "pxl8_types.h"
|
||||
|
||||
typedef struct pxl8_rng {
|
||||
u32 state;
|
||||
} pxl8_rng;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void pxl8_rng_seed(pxl8_rng* rng, u32 seed);
|
||||
u32 pxl8_rng_next(pxl8_rng* rng);
|
||||
f32 pxl8_rng_f32(pxl8_rng* rng);
|
||||
i32 pxl8_rng_range(pxl8_rng* rng, i32 min, i32 max);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
37
src/core/pxl8_sys.h
Normal file
37
src/core/pxl8_sys.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "pxl8_gfx.h"
|
||||
#include "pxl8_hal.h"
|
||||
#include "pxl8_io.h"
|
||||
#include "pxl8_sfx.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
typedef struct pxl8 pxl8;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
pxl8* pxl8_create(const pxl8_hal* hal);
|
||||
void pxl8_destroy(pxl8* sys);
|
||||
|
||||
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]);
|
||||
pxl8_result pxl8_update(pxl8* sys);
|
||||
pxl8_result pxl8_frame(pxl8* sys);
|
||||
void pxl8_quit(pxl8* sys);
|
||||
|
||||
f32 pxl8_get_fps(const pxl8* sys);
|
||||
pxl8_gfx* pxl8_get_gfx(const pxl8* sys);
|
||||
pxl8_input_state* pxl8_get_input(const pxl8* sys);
|
||||
pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution);
|
||||
pxl8_sfx_mixer* pxl8_get_sfx_mixer(const pxl8* sys);
|
||||
bool pxl8_is_running(const pxl8* sys);
|
||||
|
||||
void pxl8_center_cursor(pxl8* sys);
|
||||
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor);
|
||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);
|
||||
void pxl8_set_running(pxl8* sys, bool running);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
106
src/core/pxl8_types.h
Normal file
106
src/core/pxl8_types.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PXL8_DEFAULT_ATLAS_ENTRY_CAPACITY 64
|
||||
#define PXL8_DEFAULT_ATLAS_SIZE 1024
|
||||
#define PXL8_DEFAULT_SPRITE_CACHE_CAPACITY 64
|
||||
#define PXL8_MAX_ERROR_SIZE 2048
|
||||
#define PXL8_MAX_KEYS 256
|
||||
#define PXL8_MAX_PALETTE_SIZE 256
|
||||
#define PXL8_MAX_PATH 256
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
typedef __int128_t i128;
|
||||
typedef __uint128_t u128;
|
||||
#endif
|
||||
|
||||
typedef enum pxl8_pixel_mode {
|
||||
PXL8_PIXEL_INDEXED = 1,
|
||||
PXL8_PIXEL_HICOLOR = 2,
|
||||
PXL8_PIXEL_RGBA = 4,
|
||||
} pxl8_pixel_mode;
|
||||
|
||||
typedef enum pxl8_cursor {
|
||||
PXL8_CURSOR_ARROW,
|
||||
PXL8_CURSOR_HAND
|
||||
} pxl8_cursor;
|
||||
|
||||
typedef enum pxl8_resolution {
|
||||
PXL8_RESOLUTION_240x160,
|
||||
PXL8_RESOLUTION_320x180,
|
||||
PXL8_RESOLUTION_320x240,
|
||||
PXL8_RESOLUTION_640x360,
|
||||
PXL8_RESOLUTION_640x480,
|
||||
PXL8_RESOLUTION_800x600,
|
||||
PXL8_RESOLUTION_960x540
|
||||
} pxl8_resolution;
|
||||
|
||||
typedef enum pxl8_result {
|
||||
PXL8_OK = 0,
|
||||
PXL8_ERROR_ASE_INVALID_FRAME_MAGIC,
|
||||
PXL8_ERROR_ASE_INVALID_MAGIC,
|
||||
PXL8_ERROR_ASE_MALFORMED_CHUNK,
|
||||
PXL8_ERROR_ASE_TRUNCATED_FILE,
|
||||
PXL8_ERROR_FILE_NOT_FOUND,
|
||||
PXL8_ERROR_INITIALIZATION_FAILED,
|
||||
PXL8_ERROR_INVALID_ARGUMENT,
|
||||
PXL8_ERROR_INVALID_COORDINATE,
|
||||
PXL8_ERROR_INVALID_FORMAT,
|
||||
PXL8_ERROR_INVALID_SIZE,
|
||||
PXL8_ERROR_NOT_INITIALIZED,
|
||||
PXL8_ERROR_NULL_POINTER,
|
||||
PXL8_ERROR_OUT_OF_MEMORY,
|
||||
PXL8_ERROR_SCRIPT_ERROR,
|
||||
PXL8_ERROR_SYSTEM_FAILURE
|
||||
} pxl8_result;
|
||||
|
||||
typedef struct pxl8_bounds {
|
||||
i32 x, y;
|
||||
i32 w;
|
||||
i32 h;
|
||||
} pxl8_bounds;
|
||||
|
||||
typedef struct pxl8_input_state {
|
||||
bool keys_down[PXL8_MAX_KEYS];
|
||||
bool keys_pressed[PXL8_MAX_KEYS];
|
||||
bool keys_released[PXL8_MAX_KEYS];
|
||||
|
||||
bool mouse_buttons_down[3];
|
||||
bool mouse_buttons_pressed[3];
|
||||
bool mouse_buttons_released[3];
|
||||
i32 mouse_wheel_x;
|
||||
i32 mouse_wheel_y;
|
||||
i32 mouse_x;
|
||||
i32 mouse_y;
|
||||
i32 mouse_dx;
|
||||
i32 mouse_dy;
|
||||
bool mouse_relative_mode;
|
||||
} pxl8_input_state;
|
||||
|
||||
typedef struct pxl8_point {
|
||||
i32 x, y;
|
||||
} pxl8_point;
|
||||
|
||||
typedef struct pxl8_size {
|
||||
i32 w, h;
|
||||
} pxl8_size;
|
||||
|
||||
typedef struct pxl8_viewport {
|
||||
i32 offset_x, offset_y;
|
||||
i32 scaled_width, scaled_height;
|
||||
f32 scale;
|
||||
} pxl8_viewport;
|
||||
Loading…
Add table
Add a link
Reference in a new issue