partially done work on total source tree rework, separation of engine context and game context, generalization of renderer for different backends as well as web platform target
This commit is contained in:
231
src/twn_util.c
Normal file
231
src/twn_util.c
Normal file
@ -0,0 +1,231 @@
|
||||
#include "twn_util.h"
|
||||
#include "twn_context.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <physfsrwops.h>
|
||||
#define STB_DS_IMPLEMENTATION
|
||||
#define STBDS_ASSERT SDL_assert
|
||||
#include <stb_ds.h>
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#define STBRP_ASSERT SDL_assert
|
||||
#include <stb_rect_pack.h>
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <stb_truetype.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdnoreturn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void cry_impl(const char *file, const int line, const char *title, const char *text) {
|
||||
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"TEARS AT %s:%d: %s ... %s", file, line, title, text);
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void log_impl(const char *restrict format, va_list args, SDL_LogPriority priority) {
|
||||
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION,
|
||||
priority,
|
||||
format,
|
||||
args);
|
||||
}
|
||||
|
||||
|
||||
void log_info(const char *restrict format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_impl(format, args, SDL_LOG_PRIORITY_INFO);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void log_critical(const char *restrict format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_impl(format, args, SDL_LOG_PRIORITY_CRITICAL);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void log_warn(const char *restrict format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_impl(format, args, SDL_LOG_PRIORITY_WARN);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
noreturn static void alloc_failure_death(void) {
|
||||
log_critical("Allocation failure. Aborting NOW.");
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
|
||||
"MEMORY ALLOCATION FAILURE.",
|
||||
"FAILED TO ALLOCATE MEMORY. "
|
||||
"YOU MIGHT BE UNLUCKY. "
|
||||
"THE GAME WILL EXIT NOW.",
|
||||
NULL);
|
||||
|
||||
die_abruptly();
|
||||
}
|
||||
|
||||
|
||||
noreturn void die_abruptly(void) {
|
||||
/* a zombie window will linger if we don't at least try to quit SDL */
|
||||
SDL_Quit();
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void *cmalloc(size_t size) {
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
alloc_failure_death();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *crealloc(void *ptr, size_t size) {
|
||||
void *out = realloc(ptr, size);
|
||||
if (out == NULL)
|
||||
alloc_failure_death();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void *ccalloc(size_t num, size_t size) {
|
||||
void *ptr = calloc(num, size);
|
||||
if (ptr == NULL)
|
||||
alloc_failure_death();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
double clamp(double d, double min, double max) {
|
||||
const double t = d < min ? min : d;
|
||||
return t > max ? max : t;
|
||||
}
|
||||
|
||||
|
||||
float clampf(float f, float min, float max) {
|
||||
const float t = f < min ? min : f;
|
||||
return t > max ? max : t;
|
||||
}
|
||||
|
||||
|
||||
int clampi(int i, int min, int max) {
|
||||
const int t = i < min ? min : i;
|
||||
return t > max ? max : t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int64_t file_to_bytes(const char *path, unsigned char **buf_out) {
|
||||
SDL_RWops *handle = PHYSFSRWOPS_openRead(path);
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t data_size = SDL_RWseek(handle, 0, RW_SEEK_END);
|
||||
SDL_RWseek(handle, 0, RW_SEEK_SET); /* reset offset into data */
|
||||
|
||||
*buf_out = cmalloc(data_size);
|
||||
SDL_RWread(handle, *buf_out, sizeof **buf_out, data_size / sizeof **buf_out);
|
||||
SDL_RWclose(handle); /* we got all we needed from the stream */
|
||||
|
||||
return data_size;
|
||||
}
|
||||
|
||||
|
||||
char *file_to_str(const char *path) {
|
||||
SDL_RWops *handle = PHYSFSRWOPS_openRead(path);
|
||||
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t data_size = SDL_RWseek(handle, 0, RW_SEEK_END);
|
||||
SDL_RWseek(handle, 0, RW_SEEK_SET); /* reset offset into data */
|
||||
|
||||
char *str_out = cmalloc(data_size + 1); /* data plus final null */
|
||||
size_t len = data_size / sizeof *str_out;
|
||||
|
||||
SDL_RWread(handle, str_out, sizeof *str_out, len);
|
||||
SDL_RWclose(handle); /* we got all we needed from the stream */
|
||||
|
||||
str_out[len] = '\0';
|
||||
|
||||
return str_out;
|
||||
}
|
||||
|
||||
|
||||
bool strends(const char *str, const char *suffix) {
|
||||
size_t str_length = strlen(str);
|
||||
size_t suffix_length = strlen(suffix);
|
||||
|
||||
if (suffix_length > str_length)
|
||||
return false;
|
||||
|
||||
return memcmp((str + str_length) - suffix_length, suffix, suffix_length) == 0;
|
||||
}
|
||||
|
||||
|
||||
bool intersect_rect(const t_rect *a, const t_rect *b, t_rect *result) {
|
||||
SDL_Rect a_sdl = { a->x, a->y, a->w, a->h };
|
||||
SDL_Rect b_sdl = { b->x, b->y, b->w, b->h };
|
||||
SDL_Rect result_sdl = { 0 };
|
||||
|
||||
bool intersection = SDL_IntersectRect(&a_sdl, &b_sdl, &result_sdl);
|
||||
|
||||
*result = (t_rect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h };
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
bool intersect_frect(const t_frect *a, const t_frect *b, t_frect *result) {
|
||||
SDL_FRect a_sdl = { a->x, a->y, a->w, a->h };
|
||||
SDL_FRect b_sdl = { b->x, b->y, b->w, b->h };
|
||||
SDL_FRect result_sdl = { 0 };
|
||||
|
||||
bool intersection = SDL_IntersectFRect(&a_sdl, &b_sdl, &result_sdl);
|
||||
|
||||
*result = (t_frect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h };
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
t_frect to_frect(t_rect rect) {
|
||||
return (t_frect) {
|
||||
.h = (float)rect.h,
|
||||
.w = (float)rect.w,
|
||||
.x = (float)rect.x,
|
||||
.y = (float)rect.y,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
t_fvec2 frect_center(t_frect rect) {
|
||||
return (t_fvec2){
|
||||
.x = rect.x + rect.w / 2,
|
||||
.y = rect.y + rect.h / 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void tick_timer(int *value) {
|
||||
*value = MAX(*value - 1, 0);
|
||||
}
|
||||
|
||||
void tick_ftimer(float *value) {
|
||||
*value = MAX(*value - ((float)ctx.delta_time / (float)ctx.clocks_per_second), 0.0f);
|
||||
}
|
||||
|
||||
bool repeat_ftimer(float *value, float at) {
|
||||
*value -= (float)ctx.delta_time / (float)ctx.clocks_per_second;
|
||||
if (*value < 0.0f) {
|
||||
*value += at;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
Reference in New Issue
Block a user