2024-09-16 06:07:01 +00:00
|
|
|
#include "twn_util.h"
|
2024-09-16 13:17:00 +00:00
|
|
|
#include "twn_engine_context_c.h"
|
2024-07-08 00:44:20 +00:00
|
|
|
|
|
|
|
#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>
|
2024-08-23 02:41:52 +00:00
|
|
|
#define STB_TRUETYPE_IMPLEMENTATION
|
|
|
|
#include <stb_truetype.h>
|
2024-07-08 00:44:20 +00:00
|
|
|
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-30 21:05:28 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-07-08 06:46:12 +00:00
|
|
|
int64_t file_to_bytes(const char *path, unsigned char **buf_out) {
|
2024-07-08 00:44:20 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-08 06:46:12 +00:00
|
|
|
char *file_to_str(const char *path) {
|
2024-07-08 00:44:20 +00:00
|
|
|
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 */
|
|
|
|
|
2024-07-30 21:05:28 +00:00
|
|
|
str_out[len] = '\0';
|
2024-07-08 00:44:20 +00:00
|
|
|
|
|
|
|
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;
|
2024-07-30 21:05:28 +00:00
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
return memcmp((str + str_length) - suffix_length, suffix, suffix_length) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-20 16:39:37 +00:00
|
|
|
bool overlap_rect(const t_rect *a, const t_rect *b, t_rect *result) {
|
2024-07-08 00:44:20 +00:00
|
|
|
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);
|
|
|
|
|
2024-09-20 16:39:37 +00:00
|
|
|
if (result != NULL)
|
|
|
|
*result = (t_rect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h };
|
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
return intersection;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-20 16:39:37 +00:00
|
|
|
bool overlap_frect(const t_frect *a, const t_frect *b, t_frect *result) {
|
2024-07-08 00:44:20 +00:00
|
|
|
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);
|
|
|
|
|
2024-09-20 16:39:37 +00:00
|
|
|
if (result != NULL)
|
|
|
|
*result = (t_frect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h };
|
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
return intersection;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-20 16:39:37 +00:00
|
|
|
bool intersect_rect(const t_rect *a, const t_rect *b) {
|
|
|
|
SDL_Rect a_sdl = { a->x, a->y, a->w, a->h };
|
|
|
|
SDL_Rect b_sdl = { b->x, b->y, b->w, b->h };
|
2024-09-21 01:57:55 +00:00
|
|
|
return SDL_HasIntersection(&a_sdl, &b_sdl);
|
2024-09-20 16:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool intersect_frect(const t_frect *a, const t_frect *b) {
|
|
|
|
SDL_FRect a_sdl = { a->x, a->y, a->w, a->h };
|
|
|
|
SDL_FRect b_sdl = { b->x, b->y, b->w, b->h };
|
2024-09-21 01:57:55 +00:00
|
|
|
return SDL_HasIntersectionF(&a_sdl, &b_sdl);
|
2024-09-20 16:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-27 13:55:38 +00:00
|
|
|
t_fvec2 frect_center(t_frect rect) {
|
|
|
|
return (t_fvec2){
|
|
|
|
.x = rect.x + rect.w / 2,
|
|
|
|
.y = rect.y + rect.h / 2,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-08 00:44:20 +00:00
|
|
|
void tick_timer(int *value) {
|
2024-07-08 20:47:22 +00:00
|
|
|
*value = MAX(*value - 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tick_ftimer(float *value) {
|
2024-09-16 13:17:00 +00:00
|
|
|
*value = MAX(*value - ((float)ctx.game.delta_time / (float)ctx.clocks_per_second), 0.0f);
|
2024-07-08 20:47:22 +00:00
|
|
|
}
|
|
|
|
|
2024-07-09 12:37:03 +00:00
|
|
|
bool repeat_ftimer(float *value, float at) {
|
2024-09-16 13:17:00 +00:00
|
|
|
*value -= (float)ctx.game.delta_time / (float)ctx.clocks_per_second;
|
2024-07-08 20:47:22 +00:00
|
|
|
if (*value < 0.0f) {
|
|
|
|
*value += at;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2024-07-08 00:44:20 +00:00
|
|
|
}
|