fixed indenting style to fit new requirements #20
|
@ -12,136 +12,136 @@ resource_t g_assets[NUM_ASSETS];
|
||||||
resource_t* g_assets_endptr = g_assets;
|
resource_t* g_assets_endptr = g_assets;
|
||||||
|
|
||||||
static resource_t* insert_asset(const resource_t* resource) {
|
static resource_t* insert_asset(const resource_t* resource) {
|
||||||
*g_assets_endptr = *resource;
|
*g_assets_endptr = *resource;
|
||||||
resource_t* inserted = g_assets_endptr;
|
resource_t* inserted = g_assets_endptr;
|
||||||
++g_assets_endptr;
|
++g_assets_endptr;
|
||||||
return inserted;
|
return inserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_arbitrary_asset(void* memory, deleter_fn deleter) {
|
void add_arbitrary_asset(void* memory, deleter_fn deleter) {
|
||||||
char name_buf[99];
|
char name_buf[99];
|
||||||
// generate the name of the arbitrary block based on adresses
|
// generate the name of the arbitrary block based on adresses
|
||||||
sprintf(name_buf, "%p%p", memory, deleter);
|
sprintf(name_buf, "%p%p", memory, deleter);
|
||||||
int len = strlen(name_buf);
|
int len = strlen(name_buf);
|
||||||
resource_t res = (resource_t){
|
resource_t res = (resource_t){
|
||||||
.type = RESOURCETYPE_ARBITRARY,
|
.type = RESOURCETYPE_ARBITRARY,
|
||||||
.hash = hashstr(name_buf),
|
.hash = hashstr(name_buf),
|
||||||
.name = (char*)calloc(len+1, sizeof(char)),
|
.name = (char*)calloc(len+1, sizeof(char)),
|
||||||
.arbitrary_type={
|
.arbitrary_type={
|
||||||
.memory=memory,.deleter=deleter
|
.memory=memory,.deleter=deleter
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
strcpy(res.name, name_buf);
|
strcpy(res.name, name_buf);
|
||||||
insert_asset(&res);
|
insert_asset(&res);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture* load_texture(const char* file) {
|
SDL_Texture* load_texture(const char* file) {
|
||||||
int len = strlen(file);
|
int len = strlen(file);
|
||||||
resource_t res = (resource_t){
|
resource_t res = (resource_t){
|
||||||
.type = RESOURCETYPE_TEXTURE,
|
.type = RESOURCETYPE_TEXTURE,
|
||||||
.hash = hashstr(file),
|
.hash = hashstr(file),
|
||||||
.name = (char*)calloc(len+1, sizeof(char)),
|
.name = (char*)calloc(len+1, sizeof(char)),
|
||||||
.texture = IMG_LoadTexture(g_context.renderer, file),
|
.texture = IMG_LoadTexture(g_context.renderer, file),
|
||||||
};
|
};
|
||||||
strcpy(res.name, file);
|
strcpy(res.name, file);
|
||||||
return insert_asset(&res)->texture;
|
return insert_asset(&res)->texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
TTF_Font* load_font(const char* file, int size) {
|
TTF_Font* load_font(const char* file, int size) {
|
||||||
int len = strlen(file);
|
int len = strlen(file);
|
||||||
resource_t res = (resource_t) {
|
resource_t res = (resource_t) {
|
||||||
.type = RESOURCETYPE_FONT,
|
.type = RESOURCETYPE_FONT,
|
||||||
.hash = hashstr(file),
|
.hash = hashstr(file),
|
||||||
.name = calloc(len+1, sizeof(char)),
|
.name = calloc(len+1, sizeof(char)),
|
||||||
.font = {
|
.font = {
|
||||||
.size = size,
|
.size = size,
|
||||||
.font = TTF_OpenFont(file, size)
|
.font = TTF_OpenFont(file, size)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
strcpy(res.name, file);
|
strcpy(res.name, file);
|
||||||
return insert_asset(&res)->font.font;
|
return insert_asset(&res)->font.font;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture* get_texture(const char* file) {
|
SDL_Texture* get_texture(const char* file) {
|
||||||
resource_t* found = get_asset(file);
|
resource_t* found = get_asset(file);
|
||||||
if(found != NULL && found->type == RESOURCETYPE_TEXTURE) {
|
if(found != NULL && found->type == RESOURCETYPE_TEXTURE) {
|
||||||
return found->texture;
|
return found->texture;
|
||||||
} else {
|
} else {
|
||||||
return load_texture(file);
|
return load_texture(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TTF_Font* get_font(const char *file, int size) {
|
TTF_Font* get_font(const char *file, int size) {
|
||||||
uint32_t hash = hashstr(file);
|
uint32_t hash = hashstr(file);
|
||||||
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
||||||
if(res->hash == hash
|
if(res->hash == hash
|
||||||
&& strcmp(res->name, file) == 0
|
&& strcmp(res->name, file) == 0
|
||||||
&& res->type == RESOURCETYPE_FONT
|
&& res->type == RESOURCETYPE_FONT
|
||||||
&& res->font.size == size) {
|
&& res->font.size == size) {
|
||||||
return res->font.font;
|
return res->font.font;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return load_font(file, size);
|
return load_font(file, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
resource_t* get_asset(const char* file) {
|
resource_t* get_asset(const char* file) {
|
||||||
uint32_t hash = hashstr(file);
|
uint32_t hash = hashstr(file);
|
||||||
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
||||||
if(res->hash == hash
|
if(res->hash == hash
|
||||||
&& strcmp(res->name, file) == 0) {
|
&& strcmp(res->name, file) == 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _delete_referenced_asset(resource_t* res) {
|
static void _delete_referenced_asset(resource_t* res) {
|
||||||
free(res->name);
|
free(res->name);
|
||||||
switch(res->type) {
|
switch(res->type) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case RESOURCETYPE_TEXTURE:
|
case RESOURCETYPE_TEXTURE:
|
||||||
SDL_DestroyTexture(res->texture);
|
SDL_DestroyTexture(res->texture);
|
||||||
break;
|
break;
|
||||||
case RESOURCETYPE_FONT:
|
case RESOURCETYPE_FONT:
|
||||||
TTF_CloseFont(res->font.font);
|
TTF_CloseFont(res->font.font);
|
||||||
break;
|
break;
|
||||||
case RESOURCETYPE_ARBITRARY:
|
case RESOURCETYPE_ARBITRARY:
|
||||||
res->arbitrary_type.deleter(res->arbitrary_type.memory);
|
res->arbitrary_type.deleter(res->arbitrary_type.memory);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int asset_exists(const char* name) {
|
int asset_exists(const char* name) {
|
||||||
return get_asset(name) != NULL;
|
return get_asset(name) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
resourcetype_t asset_type(const char* name) {
|
resourcetype_t asset_type(const char* name) {
|
||||||
resource_t* r = get_asset(name);
|
resource_t* r = get_asset(name);
|
||||||
if(r != NULL) {
|
if(r != NULL) {
|
||||||
return r->type;
|
return r->type;
|
||||||
} else {
|
} else {
|
||||||
return RESOURCETYPE_MIN;
|
return RESOURCETYPE_MIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int delete_by_name(const char* name) {
|
int delete_by_name(const char* name) {
|
||||||
resource_t* r = get_asset(name);
|
resource_t* r = get_asset(name);
|
||||||
if(r == NULL) return 0;
|
if(r == NULL) return 0;
|
||||||
_remove_asset(r);
|
_remove_asset(r);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clean_assets() {
|
void clean_assets() {
|
||||||
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
||||||
_delete_referenced_asset(res);
|
_delete_referenced_asset(res);
|
||||||
}
|
}
|
||||||
g_assets_endptr = g_assets;
|
g_assets_endptr = g_assets;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _remove_asset(resource_t* res) {
|
static void _remove_asset(resource_t* res) {
|
||||||
_delete_referenced_asset(res);
|
_delete_referenced_asset(res);
|
||||||
resource_t* last = g_assets_endptr - 1;
|
resource_t* last = g_assets_endptr - 1;
|
||||||
memmove(res, last, sizeof(resource_t));
|
memmove(res, last, sizeof(resource_t));
|
||||||
--g_assets_endptr;
|
--g_assets_endptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,30 +10,30 @@ extern "C" {
|
||||||
#include "SDL2/SDL.h"
|
#include "SDL2/SDL.h"
|
||||||
|
|
||||||
typedef enum resourcetype_t {
|
typedef enum resourcetype_t {
|
||||||
RESOURCETYPE_MIN,
|
RESOURCETYPE_MIN,
|
||||||
RESOURCETYPE_TEXTURE,
|
RESOURCETYPE_TEXTURE,
|
||||||
RESOURCETYPE_FONT,
|
RESOURCETYPE_FONT,
|
||||||
RESOURCETYPE_ARBITRARY,
|
RESOURCETYPE_ARBITRARY,
|
||||||
RESOURCETYPE_MAX
|
RESOURCETYPE_MAX
|
||||||
} resourcetype_t;
|
} resourcetype_t;
|
||||||
|
|
||||||
typedef void(*deleter_fn)(void* target);
|
typedef void(*deleter_fn)(void* target);
|
||||||
|
|
||||||
typedef struct resource_t {
|
typedef struct resource_t {
|
||||||
resourcetype_t type;
|
resourcetype_t type;
|
||||||
uintptr_t hash;
|
uintptr_t hash;
|
||||||
char* name;
|
char* name;
|
||||||
union {
|
union {
|
||||||
SDL_Texture* texture;
|
SDL_Texture* texture;
|
||||||
struct {
|
struct {
|
||||||
int size;
|
int size;
|
||||||
TTF_Font* font;
|
TTF_Font* font;
|
||||||
} font;
|
} font;
|
||||||
struct {
|
struct {
|
||||||
void* memory;
|
void* memory;
|
||||||
deleter_fn deleter;
|
deleter_fn deleter;
|
||||||
} arbitrary_type;
|
} arbitrary_type;
|
||||||
};
|
};
|
||||||
} resource_t;
|
} resource_t;
|
||||||
|
|
||||||
extern void add_arbitrary_asset(void* memory, deleter_fn deleter);
|
extern void add_arbitrary_asset(void* memory, deleter_fn deleter);
|
||||||
|
|
|
@ -5,32 +5,32 @@
|
||||||
#include <SDL2/SDL_messagebox.h>
|
#include <SDL2/SDL_messagebox.h>
|
||||||
|
|
||||||
context_t g_context = {
|
context_t g_context = {
|
||||||
.window = NULL,
|
.window = NULL,
|
||||||
.renderer = NULL,
|
.renderer = NULL,
|
||||||
.running = 1
|
.running = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_context() {
|
void init_context() {
|
||||||
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
||||||
SDL_Log("ERROR LOADING SDL %s", SDL_GetError());
|
SDL_Log("ERROR LOADING SDL %s", SDL_GetError());
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING SDL", SDL_GetError(), NULL);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING SDL", SDL_GetError(), NULL);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) == 0) {
|
if(IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) == 0) {
|
||||||
SDL_Log("ERROR LOADING IMG %s", IMG_GetError());
|
SDL_Log("ERROR LOADING IMG %s", IMG_GetError());
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING IMG", IMG_GetError(), NULL);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING IMG", IMG_GetError(), NULL);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
if(TTF_Init() != 0) {
|
if(TTF_Init() != 0) {
|
||||||
SDL_Log("ERROR LOADING TTF %s", TTF_GetError());
|
SDL_Log("ERROR LOADING TTF %s", TTF_GetError());
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING IMG", IMG_GetError(), NULL);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING IMG", IMG_GetError(), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_context() {
|
void close_context() {
|
||||||
SDL_DestroyRenderer(g_context.renderer);
|
SDL_DestroyRenderer(g_context.renderer);
|
||||||
SDL_DestroyWindow(g_context.window);
|
SDL_DestroyWindow(g_context.window);
|
||||||
TTF_Quit();
|
TTF_Quit();
|
||||||
IMG_Quit();
|
IMG_Quit();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ extern "C" {
|
||||||
#include "SDL2/SDL_events.h"
|
#include "SDL2/SDL_events.h"
|
||||||
|
|
||||||
typedef struct context_t {
|
typedef struct context_t {
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
SDL_Renderer* renderer;
|
SDL_Renderer* renderer;
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
short running;
|
short running;
|
||||||
} context_t;
|
} context_t;
|
||||||
|
|
||||||
extern context_t g_context;
|
extern context_t g_context;
|
||||||
|
|
|
@ -14,89 +14,89 @@ static struct timespec start_last_frame;
|
||||||
|
|
||||||
inline static
|
inline static
|
||||||
double timespec_to_sec(struct timespec spec) {
|
double timespec_to_sec(struct timespec spec) {
|
||||||
return (double)spec.tv_sec + (double)spec.tv_nsec * 1E-09;
|
return (double)spec.tv_sec + (double)spec.tv_nsec * 1E-09;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float delta_time() {
|
inline float delta_time() {
|
||||||
return (float)_delta_time;
|
return (float)_delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_frame_interval(double frame_interval) {
|
void set_frame_interval(double frame_interval) {
|
||||||
_min_frame_interval = frame_interval;
|
_min_frame_interval = frame_interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_frame_rate_limit(int fps) {
|
void set_frame_rate_limit(int fps) {
|
||||||
_min_frame_interval = 1.0/(double)fps;
|
_min_frame_interval = 1.0/(double)fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int _engine_start() {
|
int _engine_start() {
|
||||||
init_context();
|
init_context();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int _engine_shutdown() {
|
int _engine_shutdown() {
|
||||||
game_exit();
|
game_exit();
|
||||||
clean_assets();
|
clean_assets();
|
||||||
close_context();
|
close_context();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _handle_events() {
|
void _handle_events() {
|
||||||
while(SDL_PollEvent(&g_context.event)) {
|
while(SDL_PollEvent(&g_context.event)) {
|
||||||
input_notify_event(g_context.event);
|
input_notify_event(g_context.event);
|
||||||
switch(g_context.event.type) {
|
switch(g_context.event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
g_context.running = 0;
|
g_context.running = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int _engine_run() {
|
int _engine_run() {
|
||||||
SDL_DisplayMode mode;
|
SDL_DisplayMode mode;
|
||||||
SDL_GetDesktopDisplayMode(0, &mode);
|
SDL_GetDesktopDisplayMode(0, &mode);
|
||||||
SDL_Window* window = SDL_CreateWindow("Tabletop", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.w, mode.h, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
SDL_Window* window = SDL_CreateWindow("Tabletop", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, mode.w, mode.h, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||||
|
|
||||||
g_context = (context_t){
|
g_context = (context_t){
|
||||||
.window = window,
|
.window = window,
|
||||||
.renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED),
|
.renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED),
|
||||||
.running = 1,
|
.running = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
input_init();
|
input_init();
|
||||||
world_clear();
|
world_clear();
|
||||||
start_game();
|
start_game();
|
||||||
|
|
||||||
timespec_get(&start_last_frame, TIME_UTC);
|
timespec_get(&start_last_frame, TIME_UTC);
|
||||||
struct timespec next_time;
|
struct timespec next_time;
|
||||||
while(g_context.running) {
|
while(g_context.running) {
|
||||||
timespec_get(&next_time, TIME_UTC);
|
timespec_get(&next_time, TIME_UTC);
|
||||||
_delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame);
|
_delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame);
|
||||||
start_last_frame = next_time;
|
start_last_frame = next_time;
|
||||||
_handle_events();
|
_handle_events();
|
||||||
update_input();
|
update_input();
|
||||||
_render_mode = 1;
|
_render_mode = 1;
|
||||||
update_ui();
|
update_ui();
|
||||||
_render_mode = 0;
|
_render_mode = 0;
|
||||||
update_game();
|
update_game();
|
||||||
world_update(); // update world objects
|
world_update(); // update world objects
|
||||||
world_draw(); // draw world objects
|
world_draw(); // draw world objects
|
||||||
swap_buffer();
|
swap_buffer();
|
||||||
do {
|
do {
|
||||||
timespec_get(&next_time, TIME_UTC);
|
timespec_get(&next_time, TIME_UTC);
|
||||||
_delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame);
|
_delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame);
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
} while(_delta_time < _min_frame_interval);
|
} while(_delta_time < _min_frame_interval);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
_engine_start();
|
_engine_start();
|
||||||
_engine_run();
|
_engine_run();
|
||||||
_engine_shutdown();
|
_engine_shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,18 @@ extern "C" {
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
uintptr_t hashstr(const char* str) {
|
uintptr_t hashstr(const char* str) {
|
||||||
return hashmem(str, strlen(str));
|
return hashmem(str, strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t hashmem(const char* mem, size_t size) {
|
uintptr_t hashmem(const char* mem, size_t size) {
|
||||||
const size_t last4shift = sizeof(uintptr_t)*4 - 4;
|
const size_t last4shift = sizeof(uintptr_t)*4 - 4;
|
||||||
uintptr_t hash = 0;
|
uintptr_t hash = 0;
|
||||||
while(size --> 0) {
|
while(size --> 0) {
|
||||||
hash = (hash | *mem) << 1;
|
hash = (hash | *mem) << 1;
|
||||||
hash |= hash >> last4shift;
|
hash |= hash >> last4shift;
|
||||||
++mem;
|
++mem;
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -7,32 +7,32 @@
|
||||||
#include <SDL2/SDL_events.h>
|
#include <SDL2/SDL_events.h>
|
||||||
|
|
||||||
enum INPUT_LISTENER_TYPE_T {
|
enum INPUT_LISTENER_TYPE_T {
|
||||||
INPUT_LISTENER_MOUSE,
|
INPUT_LISTENER_MOUSE,
|
||||||
INPUT_LISTENER_AXIS,
|
INPUT_LISTENER_AXIS,
|
||||||
INPUT_LISTENER_SCROLL,
|
INPUT_LISTENER_SCROLL,
|
||||||
INPUT_LISTENER_BUTTON,
|
INPUT_LISTENER_BUTTON,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct input_listener_t {
|
typedef struct input_listener_t {
|
||||||
enum INPUT_LISTENER_TYPE_T type;
|
enum INPUT_LISTENER_TYPE_T type;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
input_axis_fn delegate;
|
input_axis_fn delegate;
|
||||||
SDL_Scancode positive, negative;
|
SDL_Scancode positive, negative;
|
||||||
int last_positive, last_negative;
|
int last_positive, last_negative;
|
||||||
} axis;
|
} axis;
|
||||||
struct {
|
struct {
|
||||||
input_mouse_fn delegate;
|
input_mouse_fn delegate;
|
||||||
} mouse;
|
} mouse;
|
||||||
struct {
|
struct {
|
||||||
input_button_fn delegate;
|
input_button_fn delegate;
|
||||||
uint32_t button;
|
uint32_t button;
|
||||||
int last;
|
int last;
|
||||||
} button;
|
} button;
|
||||||
struct {
|
struct {
|
||||||
input_scroll_fn delegate;
|
input_scroll_fn delegate;
|
||||||
} scroll;
|
} scroll;
|
||||||
};
|
};
|
||||||
} input_listener_t;
|
} input_listener_t;
|
||||||
|
|
||||||
const Uint8* g_key_states = NULL;
|
const Uint8* g_key_states = NULL;
|
||||||
|
@ -45,158 +45,158 @@ static uint32_t _mouse_left_seconds = 0;
|
||||||
static float _scroll_delta = 0;
|
static float _scroll_delta = 0;
|
||||||
|
|
||||||
void add_key_listener(SDL_Scancode negative, SDL_Scancode positive,
|
void add_key_listener(SDL_Scancode negative, SDL_Scancode positive,
|
||||||
input_axis_fn delegate) {
|
input_axis_fn delegate) {
|
||||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||||
g_key_listeners_endptr->type = INPUT_LISTENER_AXIS;
|
g_key_listeners_endptr->type = INPUT_LISTENER_AXIS;
|
||||||
g_key_listeners_endptr->axis.delegate = delegate;
|
g_key_listeners_endptr->axis.delegate = delegate;
|
||||||
g_key_listeners_endptr->axis.positive = positive;
|
g_key_listeners_endptr->axis.positive = positive;
|
||||||
g_key_listeners_endptr->axis.negative = negative;
|
g_key_listeners_endptr->axis.negative = negative;
|
||||||
g_key_listeners_endptr->axis.last_positive =
|
g_key_listeners_endptr->axis.last_positive =
|
||||||
g_key_listeners_endptr->axis.last_negative = 0;
|
g_key_listeners_endptr->axis.last_negative = 0;
|
||||||
++g_key_listeners_endptr;
|
++g_key_listeners_endptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_mouse_listener(input_mouse_fn delegate) {
|
void add_mouse_listener(input_mouse_fn delegate) {
|
||||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||||
g_key_listeners_endptr->type = INPUT_LISTENER_MOUSE;
|
g_key_listeners_endptr->type = INPUT_LISTENER_MOUSE;
|
||||||
g_key_listeners_endptr->mouse.delegate = delegate;
|
g_key_listeners_endptr->mouse.delegate = delegate;
|
||||||
++g_key_listeners_endptr;
|
++g_key_listeners_endptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_mouse_button_listener(uint32_t button, input_button_fn delegate) {
|
void add_mouse_button_listener(uint32_t button, input_button_fn delegate) {
|
||||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||||
g_key_listeners_endptr->type = INPUT_LISTENER_BUTTON;
|
g_key_listeners_endptr->type = INPUT_LISTENER_BUTTON;
|
||||||
g_key_listeners_endptr->button.delegate = delegate;
|
g_key_listeners_endptr->button.delegate = delegate;
|
||||||
g_key_listeners_endptr->button.button = button;
|
g_key_listeners_endptr->button.button = button;
|
||||||
g_key_listeners_endptr->button.last = 0;
|
g_key_listeners_endptr->button.last = 0;
|
||||||
++g_key_listeners_endptr;
|
++g_key_listeners_endptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_scroll_listener(input_scroll_fn delegate) {
|
void add_scroll_listener(input_scroll_fn delegate) {
|
||||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||||
g_key_listeners_endptr->type = INPUT_LISTENER_SCROLL;
|
g_key_listeners_endptr->type = INPUT_LISTENER_SCROLL;
|
||||||
g_key_listeners_endptr->scroll.delegate = delegate;
|
g_key_listeners_endptr->scroll.delegate = delegate;
|
||||||
++g_key_listeners_endptr;
|
++g_key_listeners_endptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_listener_at(size_t index) {
|
void remove_listener_at(size_t index) {
|
||||||
input_listener_t* listener = g_key_listeners + index;
|
input_listener_t* listener = g_key_listeners + index;
|
||||||
--g_key_listeners_endptr;
|
--g_key_listeners_endptr;
|
||||||
*listener = *g_key_listeners_endptr;
|
*listener = *g_key_listeners_endptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mouse_screen_position(float *ox, float *oy) {
|
void mouse_screen_position(float *ox, float *oy) {
|
||||||
*ox = _last_screen_mouse_x;
|
*ox = _last_screen_mouse_x;
|
||||||
*oy = _last_screen_mouse_y;
|
*oy = _last_screen_mouse_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mouse_world_position(float *ox, float *oy) {
|
void mouse_world_position(float *ox, float *oy) {
|
||||||
mouse_screen_position(ox, oy);
|
mouse_screen_position(ox, oy);
|
||||||
screen_to_view(ox, oy);
|
screen_to_view(ox, oy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_init() {
|
void input_init() {
|
||||||
g_key_states = SDL_GetKeyboardState(NULL);
|
g_key_states = SDL_GetKeyboardState(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _process_mouse_listener(input_listener_t* listener, float dx, float dy) {
|
void _process_mouse_listener(input_listener_t* listener, float dx, float dy) {
|
||||||
if(dx != 0.0 && dy != 0.0) {
|
if(dx != 0.0 && dy != 0.0) {
|
||||||
listener->mouse.delegate(dx, dy);
|
listener->mouse.delegate(dx, dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_input() {
|
void update_input() {
|
||||||
float dx, dy;
|
float dx, dy;
|
||||||
int px, py;
|
int px, py;
|
||||||
SDL_GetMouseState(&px, &py);
|
SDL_GetMouseState(&px, &py);
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_GetRendererOutputSize(g_context.renderer, &width, &height);
|
SDL_GetRendererOutputSize(g_context.renderer, &width, &height);
|
||||||
dx = (float)(px - _last_mouse_x)/width; dy = (float)(py - _last_mouse_y)/width;
|
dx = (float)(px - _last_mouse_x)/width; dy = (float)(py - _last_mouse_y)/width;
|
||||||
|
|
||||||
for(input_listener_t* listener = g_key_listeners; listener != g_key_listeners_endptr; ++listener) {
|
for(input_listener_t* listener = g_key_listeners; listener != g_key_listeners_endptr; ++listener) {
|
||||||
if(listener->type == INPUT_LISTENER_MOUSE) {
|
if(listener->type == INPUT_LISTENER_MOUSE) {
|
||||||
_process_mouse_listener(listener, dx, dy);
|
_process_mouse_listener(listener, dx, dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_last_mouse_x = px; _last_mouse_y = py;
|
_last_mouse_x = px; _last_mouse_y = py;
|
||||||
_last_screen_mouse_x = (float)px / width;
|
_last_screen_mouse_x = (float)px / width;
|
||||||
_last_screen_mouse_y = (float)py / width;
|
_last_screen_mouse_y = (float)py / width;
|
||||||
_scroll_delta = 0;
|
_scroll_delta = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _handle_key_event(const SDL_Event event) {
|
void _handle_key_event(const SDL_Event event) {
|
||||||
for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) {
|
for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) {
|
||||||
if(listener->type == INPUT_LISTENER_AXIS) {
|
if(listener->type == INPUT_LISTENER_AXIS) {
|
||||||
const SDL_Scancode scode = event.key.keysym.scancode;
|
const SDL_Scancode scode = event.key.keysym.scancode;
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
if(listener->axis.positive == scode) {
|
if(listener->axis.positive == scode) {
|
||||||
int new = event.key.state == SDL_PRESSED;
|
int new = event.key.state == SDL_PRESSED;
|
||||||
changed = new != listener->axis.last_positive;
|
changed = new != listener->axis.last_positive;
|
||||||
listener->axis.last_positive = new;
|
listener->axis.last_positive = new;
|
||||||
}
|
}
|
||||||
else if(listener->axis.negative == scode) {
|
else if(listener->axis.negative == scode) {
|
||||||
int new = event.key.state == SDL_PRESSED;
|
int new = event.key.state == SDL_PRESSED;
|
||||||
changed = new != listener->axis.last_negative;
|
changed = new != listener->axis.last_negative;
|
||||||
listener->axis.last_negative = new;
|
listener->axis.last_negative = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(changed)
|
if(changed)
|
||||||
listener->axis.delegate(listener->axis.last_positive - listener->axis.last_negative);
|
listener->axis.delegate(listener->axis.last_positive - listener->axis.last_negative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _handle_scroll_event(const SDL_Event event) {
|
void _handle_scroll_event(const SDL_Event event) {
|
||||||
_scroll_delta = event.wheel.y;
|
_scroll_delta = event.wheel.y;
|
||||||
for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) {
|
for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) {
|
||||||
if(listener->type == INPUT_LISTENER_SCROLL) {
|
if(listener->type == INPUT_LISTENER_SCROLL) {
|
||||||
listener->scroll.delegate(_scroll_delta);
|
listener->scroll.delegate(_scroll_delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _handle_mousebutton_event(const SDL_Event event) {
|
void _handle_mousebutton_event(const SDL_Event event) {
|
||||||
for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) {
|
for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) {
|
||||||
if(listener->type == INPUT_LISTENER_BUTTON
|
if(listener->type == INPUT_LISTENER_BUTTON
|
||||||
|| listener->button.button == event.button.button) {
|
|| listener->button.button == event.button.button) {
|
||||||
listener->button.last = event.button.state == SDL_PRESSED;
|
listener->button.last = event.button.state == SDL_PRESSED;
|
||||||
listener->button.delegate(listener->button.last);
|
listener->button.delegate(listener->button.last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_notify_event(SDL_Event event) {
|
void input_notify_event(SDL_Event event) {
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
_handle_key_event(event);
|
_handle_key_event(event);
|
||||||
return;
|
return;
|
||||||
case SDL_MOUSEWHEEL:
|
case SDL_MOUSEWHEEL:
|
||||||
_handle_scroll_event(event);
|
_handle_scroll_event(event);
|
||||||
return;
|
return;
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_MOUSEBUTTONUP:
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
_handle_mousebutton_event(event);
|
_handle_mousebutton_event(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int input_get_keydown(SDL_Scancode scancode) {
|
int input_get_keydown(SDL_Scancode scancode) {
|
||||||
return g_key_states[scancode];
|
return g_key_states[scancode];
|
||||||
}
|
}
|
||||||
|
|
||||||
int input_get_mousedown(int mousebtn) {
|
int input_get_mousedown(int mousebtn) {
|
||||||
uint32_t mask = SDL_BUTTON(mousebtn);
|
uint32_t mask = SDL_BUTTON(mousebtn);
|
||||||
return (SDL_GetMouseState(NULL, NULL) & mask) != 0;
|
return (SDL_GetMouseState(NULL, NULL) & mask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_disconnect_all() {
|
void input_disconnect_all() {
|
||||||
g_key_listeners_endptr = g_key_listeners;
|
g_key_listeners_endptr = g_key_listeners;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ typedef void(*input_scroll_fn)(float delta);
|
||||||
extern const Uint8* g_key_states;
|
extern const Uint8* g_key_states;
|
||||||
|
|
||||||
extern void add_key_listener(SDL_Scancode negative, SDL_Scancode positive,
|
extern void add_key_listener(SDL_Scancode negative, SDL_Scancode positive,
|
||||||
input_axis_fn delegate);
|
input_axis_fn delegate);
|
||||||
extern void add_mouse_listener(input_mouse_fn delegate);
|
extern void add_mouse_listener(input_mouse_fn delegate);
|
||||||
extern void add_mouse_button_listener(uint32_t button, input_button_fn delegate);
|
extern void add_mouse_button_listener(uint32_t button, input_button_fn delegate);
|
||||||
extern void add_scroll_listener(input_scroll_fn delegate);
|
extern void add_scroll_listener(input_scroll_fn delegate);
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RLAYER_TILEMAP 100
|
#define RLAYER_TILEMAP 100
|
||||||
#define RLAYER_SPRITES 0
|
#define RLAYER_SPRITES 0
|
||||||
#define RLAYER_UI -100
|
#define RLAYER_UI -100
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
object_t object_default() {
|
object_t object_default() {
|
||||||
return (object_t){
|
return (object_t){
|
||||||
.active = 1,
|
.active = 1,
|
||||||
.physics = physics_default(),
|
.physics = physics_default(),
|
||||||
.evt_draw = &object_draw_sprite,
|
.evt_draw = &object_draw_sprite,
|
||||||
.evt_update = NULL,
|
.evt_update = NULL,
|
||||||
.sprite = sprite_default(),
|
.sprite = sprite_default(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void object_draw_sprite(object_t* object) {
|
void object_draw_sprite(object_t* object) {
|
||||||
draw_sprite(&object->sprite);
|
draw_sprite(&object->sprite);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,15 @@ typedef void(*tick_fn)(struct object_t*);
|
||||||
typedef void(*draw_fn)(struct object_t*);
|
typedef void(*draw_fn)(struct object_t*);
|
||||||
|
|
||||||
struct object_t {
|
struct object_t {
|
||||||
sprite_t sprite;
|
sprite_t sprite;
|
||||||
int active; // 1 if this object's events should be triggered by the game world update.
|
int active; // 1 if this object's events should be triggered by the game world update.
|
||||||
int wants_to_be_deleted;
|
int wants_to_be_deleted;
|
||||||
physics_t physics; // the collider to use for this object's physics interaction.
|
physics_t physics; // the collider to use for this object's physics interaction.
|
||||||
|
|
||||||
uintptr_t timer; // free to use for whatever
|
uintptr_t timer; // free to use for whatever
|
||||||
|
|
||||||
tick_fn evt_update;
|
tick_fn evt_update;
|
||||||
draw_fn evt_draw;
|
draw_fn evt_draw;
|
||||||
};
|
};
|
||||||
|
|
||||||
object_t object_default();
|
object_t object_default();
|
||||||
|
@ -26,7 +26,7 @@ object_t object_default();
|
||||||
void object_draw_sprite(object_t* object);
|
void object_draw_sprite(object_t* object);
|
||||||
static inline
|
static inline
|
||||||
int object_is_valid(const object_t* object) {
|
int object_is_valid(const object_t* object) {
|
||||||
return object != NULL && object->wants_to_be_deleted == 0;
|
return object != NULL && object->wants_to_be_deleted == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _object_h */
|
#endif /* _object_h */
|
||||||
|
|
|
@ -5,268 +5,268 @@
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
float fclampf(float x, float min_, float max_) {
|
float fclampf(float x, float min_, float max_) {
|
||||||
return fminf(max_, fmaxf(min_, x));
|
return fminf(max_, fmaxf(min_, x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
physics_t physics_default() {
|
physics_t physics_default() {
|
||||||
return (physics_t) {
|
return (physics_t) {
|
||||||
.type=COLLIDERTYPE_NONE,
|
.type=COLLIDERTYPE_NONE,
|
||||||
.velocity_x = 0.f,
|
.velocity_x = 0.f,
|
||||||
.velocity_y = 0.f,
|
.velocity_y = 0.f,
|
||||||
.solver = &solve_collision_slide
|
.solver = &solve_collision_slide
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void object_broadcast_collision(object_t* this, object_t* other) {
|
void object_broadcast_collision(object_t* this, object_t* other) {
|
||||||
if(this->physics.evt_collision != NULL) {
|
if(this->physics.evt_collision != NULL) {
|
||||||
this->physics.evt_collision(this, other);
|
this->physics.evt_collision(this, other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
short can_collide(const object_t* this) {
|
short can_collide(const object_t* this) {
|
||||||
return object_is_valid(this);
|
return object_is_valid(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int _rect_overlap(float aminx, float aminy, float amaxx, float amaxy, float bminx, float bminy, float bmaxx, float bmaxy) {
|
int _rect_overlap(float aminx, float aminy, float amaxx, float amaxy, float bminx, float bminy, float bmaxx, float bmaxy) {
|
||||||
return
|
return
|
||||||
(
|
(
|
||||||
(aminx < bmaxx && aminx > bminx)
|
(aminx < bmaxx && aminx > bminx)
|
||||||
||
|
||
|
||||||
(bminx < amaxx && bminx > aminx)
|
(bminx < amaxx && bminx > aminx)
|
||||||
) && (
|
) && (
|
||||||
(aminy < bmaxy && aminy > bminy)
|
(aminy < bmaxy && aminy > bminy)
|
||||||
||
|
||
|
||||||
(bminy < amaxy && bminy > aminy)
|
(bminy < amaxy && bminy > aminy)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
short _collision_aabb_aabb(const object_t* a, const object_t* b) {
|
short _collision_aabb_aabb(const object_t* a, const object_t* b) {
|
||||||
const float aminx = a->physics.aabb.x + a->sprite.x,
|
const float aminx = a->physics.aabb.x + a->sprite.x,
|
||||||
aminy = a->physics.aabb.y + a->sprite.y;
|
aminy = a->physics.aabb.y + a->sprite.y;
|
||||||
const float amaxx = aminx + a->physics.aabb.w,
|
const float amaxx = aminx + a->physics.aabb.w,
|
||||||
amaxy = aminy + a->physics.aabb.h;
|
amaxy = aminy + a->physics.aabb.h;
|
||||||
|
|
||||||
const float bminx = b->physics.aabb.x + b->sprite.x,
|
const float bminx = b->physics.aabb.x + b->sprite.x,
|
||||||
bminy = b->physics.aabb.y + b->sprite.y;
|
bminy = b->physics.aabb.y + b->sprite.y;
|
||||||
const float bmaxx = bminx + b->physics.aabb.w,
|
const float bmaxx = bminx + b->physics.aabb.w,
|
||||||
bmaxy = bminy + b->physics.aabb.h;
|
bmaxy = bminy + b->physics.aabb.h;
|
||||||
|
|
||||||
return _rect_overlap(aminx, aminy, amaxx, amaxy, bminx, bminy, bmaxx, bmaxy);
|
return _rect_overlap(aminx, aminy, amaxx, amaxy, bminx, bminy, bmaxx, bmaxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
short _collision_circle_circle(const object_t* a, const object_t* b) {
|
short _collision_circle_circle(const object_t* a, const object_t* b) {
|
||||||
const float ax = a->sprite.x + a->physics.circle.x,
|
const float ax = a->sprite.x + a->physics.circle.x,
|
||||||
ay = a->sprite.y + a->physics.circle.y,
|
ay = a->sprite.y + a->physics.circle.y,
|
||||||
bx = b->sprite.x + b->physics.circle.x,
|
bx = b->sprite.x + b->physics.circle.x,
|
||||||
by = b->sprite.y + b->physics.circle.y;
|
by = b->sprite.y + b->physics.circle.y;
|
||||||
const float dx = fabsf(ax-bx), dy = fabsf(ay-by);
|
const float dx = fabsf(ax-bx), dy = fabsf(ay-by);
|
||||||
const float sqrdist = dx*dx+dy*dy;
|
const float sqrdist = dx*dx+dy*dy;
|
||||||
const float mindist = a->physics.circle.radius + b->physics.circle.radius;
|
const float mindist = a->physics.circle.radius + b->physics.circle.radius;
|
||||||
const float mindistsqr = mindist*mindist;
|
const float mindistsqr = mindist*mindist;
|
||||||
return sqrdist < mindistsqr;
|
return sqrdist < mindistsqr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
short _collision_circle_aabb(const object_t* circle, const object_t* aabb) {
|
short _collision_circle_aabb(const object_t* circle, const object_t* aabb) {
|
||||||
// generate a point on the edge of the rectangle that is closest to the circle
|
// generate a point on the edge of the rectangle that is closest to the circle
|
||||||
const float bbminx = aabb->physics.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->physics.aabb.w,
|
const float bbminx = aabb->physics.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->physics.aabb.w,
|
||||||
bbminy = aabb->physics.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->physics.aabb.h;
|
bbminy = aabb->physics.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->physics.aabb.h;
|
||||||
const float cx = circle->sprite.x + circle->physics.circle.x,
|
const float cx = circle->sprite.x + circle->physics.circle.x,
|
||||||
cy = circle->sprite.y + circle->physics.circle.y;
|
cy = circle->sprite.y + circle->physics.circle.y;
|
||||||
const float x = fclampf(cx, bbminx, bbmaxx),
|
const float x = fclampf(cx, bbminx, bbmaxx),
|
||||||
y = fclampf(cy, bbminy, bbmaxy);
|
y = fclampf(cy, bbminy, bbmaxy);
|
||||||
const float dx = fabsf(cx - x), dy = fabsf(cy - y);
|
const float dx = fabsf(cx - x), dy = fabsf(cy - y);
|
||||||
|
|
||||||
// calculate the square distance from the centre of the circle to the edge of the aabb
|
// calculate the square distance from the centre of the circle to the edge of the aabb
|
||||||
const float distsqr = dx*dx+dy*dy;
|
const float distsqr = dx*dx+dy*dy;
|
||||||
const float rsqr = circle->physics.circle.radius*circle->physics.circle.radius;
|
const float rsqr = circle->physics.circle.radius*circle->physics.circle.radius;
|
||||||
|
|
||||||
// return if the square distance is larger than the square of the radius
|
// return if the square distance is larger than the square of the radius
|
||||||
return distsqr < rsqr;
|
return distsqr < rsqr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
short _collision_check(const object_t* a, const object_t* b) {
|
short _collision_check(const object_t* a, const object_t* b) {
|
||||||
if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_AABB) {
|
if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_AABB) {
|
||||||
return _collision_aabb_aabb(a, b);
|
return _collision_aabb_aabb(a, b);
|
||||||
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
||||||
return _collision_circle_circle(a, b);
|
return _collision_circle_circle(a, b);
|
||||||
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_AABB) {
|
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_AABB) {
|
||||||
return _collision_circle_aabb(a, b);
|
return _collision_circle_aabb(a, b);
|
||||||
} else if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
} else if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
||||||
return _collision_circle_aabb(b, a);
|
return _collision_circle_aabb(b, a);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
float _solve_circle_aabb(const object_t* circle, const object_t* aabb, float* out_px, float* out_py) {
|
float _solve_circle_aabb(const object_t* circle, const object_t* aabb, float* out_px, float* out_py) {
|
||||||
// generate a point on the edge of the rectangle that is closest to the circle
|
// generate a point on the edge of the rectangle that is closest to the circle
|
||||||
const float bbminx = aabb->physics.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->physics.aabb.w,
|
const float bbminx = aabb->physics.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->physics.aabb.w,
|
||||||
bbminy = aabb->physics.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->physics.aabb.h;
|
bbminy = aabb->physics.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->physics.aabb.h;
|
||||||
// the centre of the circle in world space
|
// the centre of the circle in world space
|
||||||
const float cx = circle->sprite.x + circle->physics.circle.x,
|
const float cx = circle->sprite.x + circle->physics.circle.x,
|
||||||
cy = circle->sprite.y + circle->physics.circle.y;
|
cy = circle->sprite.y + circle->physics.circle.y;
|
||||||
// the point on the rectangle closest to the centre of the circle
|
// the point on the rectangle closest to the centre of the circle
|
||||||
const float x = fclampf(cx, bbminx, bbmaxx),
|
const float x = fclampf(cx, bbminx, bbmaxx),
|
||||||
y = fclampf(cy, bbminy, bbmaxy);
|
y = fclampf(cy, bbminy, bbmaxy);
|
||||||
// the relative position of the point on the rectangle
|
// the relative position of the point on the rectangle
|
||||||
const float dif_x = cx - x,
|
const float dif_x = cx - x,
|
||||||
dif_y = cy - y;
|
dif_y = cy - y;
|
||||||
// absolute difference for use in calculating euclidean distance
|
// absolute difference for use in calculating euclidean distance
|
||||||
const float dist_x = fabsf(dif_x),
|
const float dist_x = fabsf(dif_x),
|
||||||
dist_y = fabsf(dif_y);
|
dist_y = fabsf(dif_y);
|
||||||
// euclidean distance
|
// euclidean distance
|
||||||
const float dist = sqrt(dist_x*dist_x + dist_y*dist_y);
|
const float dist = sqrt(dist_x*dist_x + dist_y*dist_y);
|
||||||
const float solve_distance = circle->physics.circle.radius - dist;
|
const float solve_distance = circle->physics.circle.radius - dist;
|
||||||
// distance to solve collision
|
// distance to solve collision
|
||||||
float solve_x, solve_y;
|
float solve_x, solve_y;
|
||||||
normalize(dif_x, dif_y, &solve_x, &solve_y);
|
normalize(dif_x, dif_y, &solve_x, &solve_y);
|
||||||
*out_px = solve_x * solve_distance;
|
*out_px = solve_x * solve_distance;
|
||||||
*out_py = solve_y * solve_distance;
|
*out_py = solve_y * solve_distance;
|
||||||
return solve_distance;
|
return solve_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
float _solve_circle_circle(const object_t* a, const object_t* b, float* out_px, float* out_py) {
|
float _solve_circle_circle(const object_t* a, const object_t* b, float* out_px, float* out_py) {
|
||||||
const float x1 = a->physics.circle.x + a->sprite.x, y1 = a->physics.circle.y + a->sprite.y;
|
const float x1 = a->physics.circle.x + a->sprite.x, y1 = a->physics.circle.y + a->sprite.y;
|
||||||
const float x2 = b->physics.circle.x + b->sprite.x, y2 = b->physics.circle.y + b->sprite.y;
|
const float x2 = b->physics.circle.x + b->sprite.x, y2 = b->physics.circle.y + b->sprite.y;
|
||||||
const float dif_x = x1 - x2, dif_y = y1 - y2;
|
const float dif_x = x1 - x2, dif_y = y1 - y2;
|
||||||
const float difference = sqrtf(fabsf(dif_x*dif_x) + fabsf(dif_y*dif_y));
|
const float difference = sqrtf(fabsf(dif_x*dif_x) + fabsf(dif_y*dif_y));
|
||||||
const float target_difference = a->physics.circle.radius + b->physics.circle.radius;
|
const float target_difference = a->physics.circle.radius + b->physics.circle.radius;
|
||||||
float dir_x, dir_y;
|
float dir_x, dir_y;
|
||||||
normalize(dif_x, dif_y, &dir_x, &dir_y);
|
normalize(dif_x, dif_y, &dir_x, &dir_y);
|
||||||
*out_px = dir_x * target_difference;
|
*out_px = dir_x * target_difference;
|
||||||
*out_py = dir_y * target_difference;
|
*out_py = dir_y * target_difference;
|
||||||
return target_difference;
|
return target_difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
float _solve_aabb_aabb(const object_t* a, const object_t* b, float* out_px, float* out_py) {
|
float _solve_aabb_aabb(const object_t* a, const object_t* b, float* out_px, float* out_py) {
|
||||||
float aminx = a->physics.aabb.x + a->sprite.x;
|
float aminx = a->physics.aabb.x + a->sprite.x;
|
||||||
float amaxx = aminx + a->physics.aabb.w;
|
float amaxx = aminx + a->physics.aabb.w;
|
||||||
float bminx = b->physics.aabb.x + b->sprite.x;
|
float bminx = b->physics.aabb.x + b->sprite.x;
|
||||||
float bmaxx = bminx + b->physics.aabb.w;
|
float bmaxx = bminx + b->physics.aabb.w;
|
||||||
|
|
||||||
float aminy = a->physics.aabb.y + a->sprite.y;
|
float aminy = a->physics.aabb.y + a->sprite.y;
|
||||||
float amaxy = aminy + a->physics.aabb.h;
|
float amaxy = aminy + a->physics.aabb.h;
|
||||||
float bminy = b->physics.aabb.y + b->sprite.y;
|
float bminy = b->physics.aabb.y + b->sprite.y;
|
||||||
float bmaxy = bminy + b->physics.aabb.h;
|
float bmaxy = bminy + b->physics.aabb.h;
|
||||||
|
|
||||||
float right = bmaxx - aminx;
|
float right = bmaxx - aminx;
|
||||||
float left = bminx - amaxx;
|
float left = bminx - amaxx;
|
||||||
float top = bminy - amaxy;
|
float top = bminy - amaxy;
|
||||||
float bottom = bmaxy - aminy;
|
float bottom = bmaxy - aminy;
|
||||||
|
|
||||||
float ret = right;
|
float ret = right;
|
||||||
*out_px = right;
|
*out_px = right;
|
||||||
*out_py = 0.f;
|
*out_py = 0.f;
|
||||||
if(fabsf(left) < fabsf(ret)) {
|
if(fabsf(left) < fabsf(ret)) {
|
||||||
*out_px = left;
|
*out_px = left;
|
||||||
*out_py = 0.f;
|
*out_py = 0.f;
|
||||||
ret = left;
|
ret = left;
|
||||||
}
|
}
|
||||||
if(fabsf(top) < fabsf(ret)) {
|
if(fabsf(top) < fabsf(ret)) {
|
||||||
*out_px = 0.f;
|
*out_px = 0.f;
|
||||||
*out_py = top;
|
*out_py = top;
|
||||||
ret = top;
|
ret = top;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fabsf(bottom) < fabsf(ret)) {
|
if(fabsf(bottom) < fabsf(ret)) {
|
||||||
*out_px = 0.f;
|
*out_px = 0.f;
|
||||||
*out_py = bottom;
|
*out_py = bottom;
|
||||||
return bottom;
|
return bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_solve_force(const object_t* a, const object_t* b, float* out_px, float* out_py) {
|
float get_solve_force(const object_t* a, const object_t* b, float* out_px, float* out_py) {
|
||||||
if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_AABB) {
|
if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_AABB) {
|
||||||
return _solve_aabb_aabb(a, b, out_px, out_py);
|
return _solve_aabb_aabb(a, b, out_px, out_py);
|
||||||
} else if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
} else if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
||||||
float penetration_distance = _solve_circle_aabb(b, a, out_px, out_py);
|
float penetration_distance = _solve_circle_aabb(b, a, out_px, out_py);
|
||||||
*out_px = -(*out_px);
|
*out_px = -(*out_px);
|
||||||
*out_py = -(*out_py);
|
*out_py = -(*out_py);
|
||||||
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_AABB) {
|
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_AABB) {
|
||||||
return _solve_circle_aabb(a, b, out_px, out_py);
|
return _solve_circle_aabb(a, b, out_px, out_py);
|
||||||
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
} else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_CIRCLE) {
|
||||||
return _solve_circle_circle(a, b, out_px, out_py);
|
return _solve_circle_circle(a, b, out_px, out_py);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void solve_collision_slide(object_t* left, object_t* right) {
|
void solve_collision_slide(object_t* left, object_t* right) {
|
||||||
float dx, dy;
|
float dx, dy;
|
||||||
get_solve_force(left, right, &dx, &dy);
|
get_solve_force(left, right, &dx, &dy);
|
||||||
left->sprite.x += dx;
|
left->sprite.x += dx;
|
||||||
left->sprite.y += dy;
|
left->sprite.y += dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _solve_move(object_t* this) {
|
void _solve_move(object_t* this) {
|
||||||
// loop over all objects and check collision if applicable
|
// loop over all objects and check collision if applicable
|
||||||
for(int i = 0; i < world_num_objects(); ++i) {
|
for(int i = 0; i < world_num_objects(); ++i) {
|
||||||
// get pointer to other object
|
// get pointer to other object
|
||||||
object_t* other = world_get_object(i);
|
object_t* other = world_get_object(i);
|
||||||
// check collision, return if found
|
// check collision, return if found
|
||||||
if(can_collide(other) && this != other && _collision_check(other, this)) {
|
if(can_collide(other) && this != other && _collision_check(other, this)) {
|
||||||
object_broadcast_collision(other, this);
|
object_broadcast_collision(other, this);
|
||||||
object_broadcast_collision(this, other);
|
object_broadcast_collision(this, other);
|
||||||
this->physics.solver(this, other);
|
this->physics.solver(this, other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void physics_move(object_t* this, float delta_time) {
|
void physics_move(object_t* this, float delta_time) {
|
||||||
const float max_step_size = this->physics.max_interpolate_step_size;
|
const float max_step_size = this->physics.max_interpolate_step_size;
|
||||||
// calculate step delta
|
// calculate step delta
|
||||||
float dx = this->physics.velocity_x * delta_time, dy = this->physics.velocity_y * delta_time;
|
float dx = this->physics.velocity_x * delta_time, dy = this->physics.velocity_y * delta_time;
|
||||||
const float target_x = this->sprite.x + dx,
|
const float target_x = this->sprite.x + dx,
|
||||||
target_y = this->sprite.y + dy;
|
target_y = this->sprite.y + dy;
|
||||||
if(dx == 0 && dy == 0)
|
if(dx == 0 && dy == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// calculate direction x,y
|
// calculate direction x,y
|
||||||
float m = sqrtf(dx*dx + dy*dy);
|
float m = sqrtf(dx*dx + dy*dy);
|
||||||
dx = dx / m * max_step_size;
|
dx = dx / m * max_step_size;
|
||||||
dy = dy / m * max_step_size;
|
dy = dy / m * max_step_size;
|
||||||
|
|
||||||
const int step_count = max_step_size / m;
|
const int step_count = max_step_size / m;
|
||||||
|
|
||||||
// ensure this object would ever collide
|
// ensure this object would ever collide
|
||||||
// if it wouldn't collide anyway, just set position
|
// if it wouldn't collide anyway, just set position
|
||||||
if(!can_collide(this)) {
|
if(!can_collide(this)) {
|
||||||
this->sprite.x = target_x;
|
this->sprite.x = target_x;
|
||||||
this->sprite.y = target_y;
|
this->sprite.y = target_y;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(step_count == 0) {
|
if(step_count == 0) {
|
||||||
this->sprite.x = target_x;
|
this->sprite.x = target_x;
|
||||||
this->sprite.y = target_y;
|
this->sprite.y = target_y;
|
||||||
_solve_move(this);
|
_solve_move(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1. move towards target
|
* 1. move towards target
|
||||||
* 2. check collision with every other object
|
* 2. check collision with every other object
|
||||||
*/
|
*/
|
||||||
for(int steps = 0; steps <= step_count && (this->sprite.x != target_x || this->sprite.y != target_y); ++steps) {
|
for(int steps = 0; steps <= step_count && (this->sprite.x != target_x || this->sprite.y != target_y); ++steps) {
|
||||||
// move towards target, snap to target if distance is too low
|
// move towards target, snap to target if distance is too low
|
||||||
const float distx = fabsf(this->sprite.x - target_x), disty = fabsf(this->sprite.y - target_y);
|
const float distx = fabsf(this->sprite.x - target_x), disty = fabsf(this->sprite.y - target_y);
|
||||||
const float sqdist = distx*distx + disty*disty;
|
const float sqdist = distx*distx + disty*disty;
|
||||||
if(sqdist > max_step_size*max_step_size) {
|
if(sqdist > max_step_size*max_step_size) {
|
||||||
this->sprite.x += dx;
|
this->sprite.x += dx;
|
||||||
this->sprite.y += dy;
|
this->sprite.y += dy;
|
||||||
} else {
|
} else {
|
||||||
this->sprite.x = target_x;
|
this->sprite.x = target_x;
|
||||||
this->sprite.y = target_y;
|
this->sprite.y = target_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
_solve_move(this);
|
_solve_move(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,28 +9,28 @@ typedef void(*collided_fn)(object_t*, object_t*);
|
||||||
typedef void(*solver_fn)(object_t* left, object_t* right);
|
typedef void(*solver_fn)(object_t* left, object_t* right);
|
||||||
|
|
||||||
typedef enum collider_type_t {
|
typedef enum collider_type_t {
|
||||||
COLLIDERTYPE_MIN,
|
COLLIDERTYPE_MIN,
|
||||||
COLLIDERTYPE_NONE,
|
COLLIDERTYPE_NONE,
|
||||||
COLLIDERTYPE_CIRCLE,
|
COLLIDERTYPE_CIRCLE,
|
||||||
COLLIDERTYPE_AABB,
|
COLLIDERTYPE_AABB,
|
||||||
COLLIDERTYPE_MAX,
|
COLLIDERTYPE_MAX,
|
||||||
} collider_type_t;
|
} collider_type_t;
|
||||||
|
|
||||||
typedef struct circle_t {
|
typedef struct circle_t {
|
||||||
float x, y;
|
float x, y;
|
||||||
float radius;
|
float radius;
|
||||||
} circle_t;
|
} circle_t;
|
||||||
|
|
||||||
typedef struct physics_t {
|
typedef struct physics_t {
|
||||||
collider_type_t type;
|
collider_type_t type;
|
||||||
collided_fn evt_collision;
|
collided_fn evt_collision;
|
||||||
solver_fn solver;
|
solver_fn solver;
|
||||||
float velocity_x, velocity_y;
|
float velocity_x, velocity_y;
|
||||||
float max_interpolate_step_size;
|
float max_interpolate_step_size;
|
||||||
union {
|
union {
|
||||||
circle_t circle;
|
circle_t circle;
|
||||||
SDL_FRect aabb;
|
SDL_FRect aabb;
|
||||||
};
|
};
|
||||||
} physics_t;
|
} physics_t;
|
||||||
|
|
||||||
extern physics_t physics_default();
|
extern physics_t physics_default();
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
#define NUM_DRAWCMDS 2048
|
#define NUM_DRAWCMDS 2048
|
||||||
|
|
||||||
drawcmd_t g_drawdata[NUM_DRAWCMDS];
|
drawcmd_t g_drawdata[NUM_DRAWCMDS];
|
||||||
drawcmd_t* g_drawdata_endptr = g_drawdata;
|
drawcmd_t* g_drawdata_endptr = g_drawdata;
|
||||||
int _render_mode = 0;
|
int _render_mode = 0;
|
||||||
|
|
||||||
#define DEFAULT_VIEW (view_t){.x=0.0,.y=0.0,.width=1.0}
|
#define DEFAULT_VIEW (view_t){.x=0.0,.y=0.0,.width=1.0}
|
||||||
|
|
||||||
|
@ -27,474 +27,474 @@ view_t g_active_view = DEFAULT_VIEW;
|
||||||
int d_debug_next_frame = 0;
|
int d_debug_next_frame = 0;
|
||||||
|
|
||||||
void screen_to_view(float *x, float *y) {
|
void screen_to_view(float *x, float *y) {
|
||||||
float xx = *x, yy = *y;
|
float xx = *x, yy = *y;
|
||||||
|
|
||||||
xx *= g_active_view.width;
|
xx *= g_active_view.width;
|
||||||
yy *= g_active_view.width;
|
yy *= g_active_view.width;
|
||||||
|
|
||||||
xx += g_active_view.x - g_active_view.width * 0.5f;
|
xx += g_active_view.x - g_active_view.width * 0.5f;
|
||||||
yy += g_active_view.y - g_active_view.width * _aspect_ratio * 0.5f;
|
yy += g_active_view.y - g_active_view.width * _aspect_ratio * 0.5f;
|
||||||
|
|
||||||
*x = xx;
|
*x = xx;
|
||||||
*y = yy;
|
*y = yy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_buffer() {
|
void clear_buffer() {
|
||||||
SDL_SetRenderDrawBlendMode(g_context.renderer, SDL_BLENDMODE_BLEND);
|
SDL_SetRenderDrawBlendMode(g_context.renderer, SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetRenderDrawColor(g_context.renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(g_context.renderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(g_context.renderer);
|
SDL_RenderClear(g_context.renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_scaling_factors(float* width, float* height,
|
void get_scaling_factors(float* width, float* height,
|
||||||
float* width_mul, float* height_mul, short ui) {
|
float* width_mul, float* height_mul, short ui) {
|
||||||
float aspectr;
|
float aspectr;
|
||||||
(*width)=_render_width; (*height)=_render_height;
|
(*width)=_render_width; (*height)=_render_height;
|
||||||
aspectr = _aspect_ratio;
|
aspectr = _aspect_ratio;
|
||||||
if(ui == 0) {
|
if(ui == 0) {
|
||||||
(*width_mul) = (*width)/g_active_view.width;
|
(*width_mul) = (*width)/g_active_view.width;
|
||||||
(*height_mul) = (*height)/(g_active_view.width*aspectr);
|
(*height_mul) = (*height)/(g_active_view.width*aspectr);
|
||||||
} else {
|
} else {
|
||||||
(*height_mul) = (*width_mul) = (*width);
|
(*height_mul) = (*width_mul) = (*width);
|
||||||
}
|
}
|
||||||
(*width) = g_active_view.width;
|
(*width) = g_active_view.width;
|
||||||
(*height) = (*width)*aspectr;
|
(*height) = (*width)*aspectr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_FRect get_dest_with_size(SDL_FRect untransformed, int ui) {
|
SDL_FRect get_dest_with_size(SDL_FRect untransformed, int ui) {
|
||||||
float fw, fh, fwm, fhm;
|
float fw, fh, fwm, fhm;
|
||||||
get_scaling_factors(&fw, &fh, &fwm, &fhm, ui);
|
get_scaling_factors(&fw, &fh, &fwm, &fhm, ui);
|
||||||
SDL_FRect r = (SDL_FRect) {
|
SDL_FRect r = (SDL_FRect) {
|
||||||
.x=((-g_active_view.x)+(fw*0.5f)+untransformed.x)*fwm,
|
.x=((-g_active_view.x)+(fw*0.5f)+untransformed.x)*fwm,
|
||||||
.y=((-g_active_view.y)+(fh*0.5f)+untransformed.y)*fwm,
|
.y=((-g_active_view.y)+(fh*0.5f)+untransformed.y)*fwm,
|
||||||
.w=untransformed.w*fwm,
|
.w=untransformed.w*fwm,
|
||||||
.h=untransformed.h*fwm
|
.h=untransformed.h*fwm
|
||||||
};
|
};
|
||||||
if(ui) {
|
if(ui) {
|
||||||
r.x = untransformed.x * fwm;
|
r.x = untransformed.x * fwm;
|
||||||
r.y = untransformed.y * fhm;
|
r.y = untransformed.y * fhm;
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _exec_sprite_cmd(const drawcmd_t* cmd) {
|
void _exec_sprite_cmd(const drawcmd_t* cmd) {
|
||||||
const sprite_t* sprite = &cmd->sprite;
|
const sprite_t* sprite = &cmd->sprite;
|
||||||
SDL_FRect untransformed = {sprite->x, sprite->y, sprite->sx, sprite->sy};
|
SDL_FRect untransformed = {sprite->x, sprite->y, sprite->sx, sprite->sy};
|
||||||
untransformed.x -= sprite->origin.x;
|
untransformed.x -= sprite->origin.x;
|
||||||
untransformed.y -= sprite->origin.y;
|
untransformed.y -= sprite->origin.y;
|
||||||
SDL_FRect destrect = get_dest_with_size(untransformed, cmd->ui);
|
SDL_FRect destrect = get_dest_with_size(untransformed, cmd->ui);
|
||||||
SDL_FPoint origin = {destrect.w * sprite->origin.x, destrect.h * sprite->origin.y};
|
SDL_FPoint origin = {destrect.w * sprite->origin.x, destrect.h * sprite->origin.y};
|
||||||
SDL_RenderCopyExF(g_context.renderer, sprite->texture,
|
SDL_RenderCopyExF(g_context.renderer, sprite->texture,
|
||||||
&sprite->uv, &destrect, sprite->rot,
|
&sprite->uv, &destrect, sprite->rot,
|
||||||
&origin, sprite->flip);
|
&origin, sprite->flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _exec_rect_cmd(const drawcmd_t* cmd) {
|
void _exec_rect_cmd(const drawcmd_t* cmd) {
|
||||||
float w, h, wm, hm;
|
float w, h, wm, hm;
|
||||||
get_scaling_factors(&w, &h, &wm, &hm, cmd->ui);
|
get_scaling_factors(&w, &h, &wm, &hm, cmd->ui);
|
||||||
SDL_FRect rect = (SDL_FRect) {
|
SDL_FRect rect = (SDL_FRect) {
|
||||||
.x=((-g_active_view.x)+(w*0.5f)+cmd->rect.x)*wm,
|
.x=((-g_active_view.x)+(w*0.5f)+cmd->rect.x)*wm,
|
||||||
.y=((-g_active_view.y)+(h*0.5f)+cmd->rect.y)*hm,
|
.y=((-g_active_view.y)+(h*0.5f)+cmd->rect.y)*hm,
|
||||||
.w=cmd->rect.w*wm, .h=cmd->rect.h*hm
|
.w=cmd->rect.w*wm, .h=cmd->rect.h*hm
|
||||||
};
|
};
|
||||||
if(cmd->ui) {
|
if(cmd->ui) {
|
||||||
rect.x = cmd->rect.x * wm;
|
rect.x = cmd->rect.x * wm;
|
||||||
rect.y = cmd->rect.y * hm;
|
rect.y = cmd->rect.y * hm;
|
||||||
}
|
}
|
||||||
SDL_Color c = cmd->rect.background;
|
SDL_Color c = cmd->rect.background;
|
||||||
SDL_SetRenderDrawColor(g_context.renderer, c.r, c.g, c.b, c.a);
|
SDL_SetRenderDrawColor(g_context.renderer, c.r, c.g, c.b, c.a);
|
||||||
SDL_RenderFillRectF(g_context.renderer, &rect);
|
SDL_RenderFillRectF(g_context.renderer, &rect);
|
||||||
c = cmd->rect.line;
|
c = cmd->rect.line;
|
||||||
SDL_SetRenderDrawColor(g_context.renderer, c.r, c.g, c.b, c.a);
|
SDL_SetRenderDrawColor(g_context.renderer, c.r, c.g, c.b, c.a);
|
||||||
|
|
||||||
SDL_FRect r = {
|
SDL_FRect r = {
|
||||||
rect.x, rect.y,
|
rect.x, rect.y,
|
||||||
cmd->rect.line_width*wm, rect.h
|
cmd->rect.line_width*wm, rect.h
|
||||||
};
|
};
|
||||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||||
r = (SDL_FRect){
|
r = (SDL_FRect){
|
||||||
rect.x, rect.y,
|
rect.x, rect.y,
|
||||||
rect.w, cmd->rect.line_width*hm
|
rect.w, cmd->rect.line_width*hm
|
||||||
};
|
};
|
||||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||||
r = (SDL_FRect){
|
r = (SDL_FRect){
|
||||||
rect.x, rect.y+rect.h-cmd->rect.line_width*hm,
|
rect.x, rect.y+rect.h-cmd->rect.line_width*hm,
|
||||||
rect.w, cmd->rect.line_width*hm
|
rect.w, cmd->rect.line_width*hm
|
||||||
};
|
};
|
||||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||||
r = (SDL_FRect){
|
r = (SDL_FRect){
|
||||||
rect.x+rect.w-cmd->rect.line_width*wm, rect.y,
|
rect.x+rect.w-cmd->rect.line_width*wm, rect.y,
|
||||||
cmd->rect.line_width*wm, rect.h
|
cmd->rect.line_width*wm, rect.h
|
||||||
};
|
};
|
||||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _exec_sliced_cmd(const drawcmd_t* cmd) {
|
void _exec_sliced_cmd(const drawcmd_t* cmd) {
|
||||||
const nineslice_t* sliced = &cmd->sliced;
|
const nineslice_t* sliced = &cmd->sliced;
|
||||||
|
|
||||||
// target rect in world space
|
// target rect in world space
|
||||||
SDL_FRect rect = sliced->rect;
|
SDL_FRect rect = sliced->rect;
|
||||||
// sliced texture
|
// sliced texture
|
||||||
SDL_Texture* t = sliced->texture;
|
SDL_Texture* t = sliced->texture;
|
||||||
|
|
||||||
// width and height of sliced texture
|
// width and height of sliced texture
|
||||||
int tw, th;
|
int tw, th;
|
||||||
SDL_QueryTexture(t, NULL, NULL, &tw, &th);
|
SDL_QueryTexture(t, NULL, NULL, &tw, &th);
|
||||||
|
|
||||||
// top-left
|
// top-left
|
||||||
SDL_Rect srcr = {
|
SDL_Rect srcr = {
|
||||||
0, 0, sliced->corner_size, sliced->corner_size
|
0, 0, sliced->corner_size, sliced->corner_size
|
||||||
};
|
};
|
||||||
SDL_FRect dstr = get_dest_with_size((SDL_FRect){
|
SDL_FRect dstr = get_dest_with_size((SDL_FRect){
|
||||||
rect.x, rect.y, sliced->radius, sliced->radius
|
rect.x, rect.y, sliced->radius, sliced->radius
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// top - centre
|
// top - centre
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
sliced->corner_size, 0,
|
sliced->corner_size, 0,
|
||||||
tw - sliced->corner_size*2, sliced->corner_size
|
tw - sliced->corner_size*2, sliced->corner_size
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect){
|
dstr = get_dest_with_size((SDL_FRect){
|
||||||
rect.x + sliced->radius, rect.y, sliced->rect.w - sliced->radius * 2, sliced->radius
|
rect.x + sliced->radius, rect.y, sliced->rect.w - sliced->radius * 2, sliced->radius
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// top-right
|
// top-right
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
tw - sliced->corner_size, 0, sliced->corner_size, sliced->corner_size
|
tw - sliced->corner_size, 0, sliced->corner_size, sliced->corner_size
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect){
|
dstr = get_dest_with_size((SDL_FRect){
|
||||||
rect.x + rect.w - sliced->radius, rect.y, sliced->radius, sliced->radius
|
rect.x + rect.w - sliced->radius, rect.y, sliced->radius, sliced->radius
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// centre-left
|
// centre-left
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
0, sliced->corner_size, sliced->corner_size, th - sliced->corner_size * 2
|
0, sliced->corner_size, sliced->corner_size, th - sliced->corner_size * 2
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect) {
|
dstr = get_dest_with_size((SDL_FRect) {
|
||||||
rect.x, rect.y + sliced->radius, sliced->radius, rect.h - sliced->radius * 2
|
rect.x, rect.y + sliced->radius, sliced->radius, rect.h - sliced->radius * 2
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// centre-centre
|
// centre-centre
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
sliced->corner_size, sliced->corner_size, tw - sliced->corner_size * 2, th - sliced->corner_size * 2
|
sliced->corner_size, sliced->corner_size, tw - sliced->corner_size * 2, th - sliced->corner_size * 2
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect) {
|
dstr = get_dest_with_size((SDL_FRect) {
|
||||||
rect.x + sliced->radius, rect.y + sliced->radius, rect.w - sliced->radius * 2, rect.h - sliced->radius * 2
|
rect.x + sliced->radius, rect.y + sliced->radius, rect.w - sliced->radius * 2, rect.h - sliced->radius * 2
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// centre-right
|
// centre-right
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
tw - sliced->corner_size, sliced->corner_size, sliced->corner_size, th - sliced->corner_size * 2
|
tw - sliced->corner_size, sliced->corner_size, sliced->corner_size, th - sliced->corner_size * 2
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect) {
|
dstr = get_dest_with_size((SDL_FRect) {
|
||||||
rect.x + rect.w - sliced->radius, rect.y + sliced->radius, sliced->radius, rect.h - sliced->radius * 2
|
rect.x + rect.w - sliced->radius, rect.y + sliced->radius, sliced->radius, rect.h - sliced->radius * 2
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// bottom-left
|
// bottom-left
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
0, th - sliced->corner_size, sliced->corner_size, sliced->corner_size
|
0, th - sliced->corner_size, sliced->corner_size, sliced->corner_size
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect){
|
dstr = get_dest_with_size((SDL_FRect){
|
||||||
rect.x, rect.y + rect.h - sliced->radius, sliced->radius, sliced->radius
|
rect.x, rect.y + rect.h - sliced->radius, sliced->radius, sliced->radius
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// bottom-centre
|
// bottom-centre
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
sliced->corner_size, th - sliced->corner_size, tw - sliced->corner_size * 2, sliced->corner_size
|
sliced->corner_size, th - sliced->corner_size, tw - sliced->corner_size * 2, sliced->corner_size
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect) {
|
dstr = get_dest_with_size((SDL_FRect) {
|
||||||
rect.x + sliced->radius, rect.y + rect.h - sliced->radius, rect.w - sliced->radius * 2, sliced->radius
|
rect.x + sliced->radius, rect.y + rect.h - sliced->radius, rect.w - sliced->radius * 2, sliced->radius
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
|
|
||||||
// bottom-right
|
// bottom-right
|
||||||
srcr = (SDL_Rect) {
|
srcr = (SDL_Rect) {
|
||||||
tw - sliced->corner_size, th - sliced->corner_size, sliced->corner_size, sliced->corner_size
|
tw - sliced->corner_size, th - sliced->corner_size, sliced->corner_size, sliced->corner_size
|
||||||
};
|
};
|
||||||
dstr = get_dest_with_size((SDL_FRect) {
|
dstr = get_dest_with_size((SDL_FRect) {
|
||||||
rect.x + rect.w - sliced->radius, rect.y + rect.h - sliced->radius, sliced->radius, sliced->radius
|
rect.x + rect.w - sliced->radius, rect.y + rect.h - sliced->radius, sliced->radius, sliced->radius
|
||||||
}, cmd->ui);
|
}, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &dstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _exec_text_cmd(const drawcmd_t* cmd) {
|
void _exec_text_cmd(const drawcmd_t* cmd) {
|
||||||
SDL_FRect r = cmd->text.area;
|
SDL_FRect r = cmd->text.area;
|
||||||
int fh = TTF_FontHeight(cmd->text.style.font);
|
int fh = TTF_FontHeight(cmd->text.style.font);
|
||||||
int wrap = (int)(fh * r.w / cmd->text.style.size);
|
int wrap = (int)(fh * r.w / cmd->text.style.size);
|
||||||
SDL_Surface* s = TTF_RenderText_Solid_Wrapped(cmd->text.style.font, cmd->text.text, cmd->text.style.color, wrap);
|
SDL_Surface* s = TTF_RenderText_Solid_Wrapped(cmd->text.style.font, cmd->text.text, cmd->text.style.color, wrap);
|
||||||
if(s != NULL) {
|
if(s != NULL) {
|
||||||
SDL_Rect srcr = {0,0,s->w, s->h};
|
SDL_Rect srcr = {0,0,s->w, s->h};
|
||||||
SDL_Texture* t = SDL_CreateTextureFromSurface(g_context.renderer, s);
|
SDL_Texture* t = SDL_CreateTextureFromSurface(g_context.renderer, s);
|
||||||
SDL_FreeSurface(s);
|
SDL_FreeSurface(s);
|
||||||
|
|
||||||
float asp_dst = r.w / r.h;
|
float asp_dst = r.w / r.h;
|
||||||
float asp_src = (float)srcr.w / (float)srcr.h;
|
float asp_src = (float)srcr.w / (float)srcr.h;
|
||||||
if((float)s->h / fh * cmd->text.style.size > r.h) {
|
if((float)s->h / fh * cmd->text.style.size > r.h) {
|
||||||
srcr.h = srcr.w / asp_dst;
|
srcr.h = srcr.w / asp_dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.w = (float)srcr.w / fh * cmd->text.style.size;
|
r.w = (float)srcr.w / fh * cmd->text.style.size;
|
||||||
r.h = (float)srcr.h / fh * cmd->text.style.size;
|
r.h = (float)srcr.h / fh * cmd->text.style.size;
|
||||||
|
|
||||||
r = get_dest_with_size(r, cmd->ui);
|
r = get_dest_with_size(r, cmd->ui);
|
||||||
SDL_RenderCopyF(g_context.renderer, t, &srcr, &r);
|
SDL_RenderCopyF(g_context.renderer, t, &srcr, &r);
|
||||||
SDL_DestroyTexture(t);
|
SDL_DestroyTexture(t);
|
||||||
}
|
}
|
||||||
free(cmd->text.text);
|
free(cmd->text.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite_t sprite_default() {
|
sprite_t sprite_default() {
|
||||||
return (sprite_t){
|
return (sprite_t){
|
||||||
.texture = NULL,
|
.texture = NULL,
|
||||||
.x = 0.f, .y = 0.f,
|
.x = 0.f, .y = 0.f,
|
||||||
.origin = (SDL_FPoint){0.f, 0.f},
|
.origin = (SDL_FPoint){0.f, 0.f},
|
||||||
.sx = 1.f, .sy = 1.f,
|
.sx = 1.f, .sy = 1.f,
|
||||||
.rot = 0.f,
|
.rot = 0.f,
|
||||||
.depth = RLAYER_SPRITES,
|
.depth = RLAYER_SPRITES,
|
||||||
.uv = (SDL_Rect){0.f, 0.f, 0.f, 0.f},
|
.uv = (SDL_Rect){0.f, 0.f, 0.f, 0.f},
|
||||||
.flip = SDL_FLIP_NONE,
|
.flip = SDL_FLIP_NONE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite_t render_text(const char* str, SDL_FRect area, text_style_t style) {
|
sprite_t render_text(const char* str, SDL_FRect area, text_style_t style) {
|
||||||
SDL_FRect r = area;
|
SDL_FRect r = area;
|
||||||
int fh = TTF_FontHeight(style.font);
|
int fh = TTF_FontHeight(style.font);
|
||||||
int wrap = (int)(fh * r.w / style.size);
|
int wrap = (int)(fh * r.w / style.size);
|
||||||
SDL_Surface* s = TTF_RenderText_Solid_Wrapped(style.font, str, style.color, wrap);
|
SDL_Surface* s = TTF_RenderText_Solid_Wrapped(style.font, str, style.color, wrap);
|
||||||
if(s != NULL) {
|
if(s != NULL) {
|
||||||
SDL_Rect srcr = {0,0,s->w, s->h};
|
SDL_Rect srcr = {0,0,s->w, s->h};
|
||||||
SDL_Texture* t = SDL_CreateTextureFromSurface(g_context.renderer, s);
|
SDL_Texture* t = SDL_CreateTextureFromSurface(g_context.renderer, s);
|
||||||
SDL_FreeSurface(s);
|
SDL_FreeSurface(s);
|
||||||
|
|
||||||
float asp_dst = r.w / r.h;
|
float asp_dst = r.w / r.h;
|
||||||
float asp_src = (float)srcr.w / (float)srcr.h;
|
float asp_src = (float)srcr.w / (float)srcr.h;
|
||||||
if((float)s->h / fh * style.size > r.h) {
|
if((float)s->h / fh * style.size > r.h) {
|
||||||
srcr.h = srcr.w / asp_dst;
|
srcr.h = srcr.w / asp_dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.w = (float)srcr.w / fh * style.size;
|
r.w = (float)srcr.w / fh * style.size;
|
||||||
r.h = (float)srcr.h / fh * style.size;
|
r.h = (float)srcr.h / fh * style.size;
|
||||||
|
|
||||||
return (sprite_t) {
|
return (sprite_t) {
|
||||||
.depth=RLAYER_SPRITES,
|
.depth=RLAYER_SPRITES,
|
||||||
.origin={0,0},
|
.origin={0,0},
|
||||||
.rot=0,
|
.rot=0,
|
||||||
.sx=area.w, .sy=area.h,
|
.sx=area.w, .sy=area.h,
|
||||||
.x=area.x, .y=area.y,
|
.x=area.x, .y=area.y,
|
||||||
.texture=t,
|
.texture=t,
|
||||||
.uv=srcr,
|
.uv=srcr,
|
||||||
.flip=SDL_FLIP_NONE,
|
.flip=SDL_FLIP_NONE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return (sprite_t) {
|
return (sprite_t) {
|
||||||
.depth=0,
|
.depth=0,
|
||||||
.origin={0,0}, .rot=0,
|
.origin={0,0}, .rot=0,
|
||||||
.sx=0, .sy=0,
|
.sx=0, .sy=0,
|
||||||
.texture=NULL,
|
.texture=NULL,
|
||||||
.uv={0,0,0,0},
|
.uv={0,0,0,0},
|
||||||
.x=0,.y=0,
|
.x=0,.y=0,
|
||||||
.flip=SDL_FLIP_NONE,
|
.flip=SDL_FLIP_NONE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void(*drawcmd_delegate)(const drawcmd_t*);
|
typedef void(*drawcmd_delegate)(const drawcmd_t*);
|
||||||
static drawcmd_delegate const drawcmd_funcs[] = {
|
static drawcmd_delegate const drawcmd_funcs[] = {
|
||||||
&_exec_sprite_cmd,
|
&_exec_sprite_cmd,
|
||||||
&_exec_rect_cmd,
|
&_exec_rect_cmd,
|
||||||
&_exec_sliced_cmd,
|
&_exec_sliced_cmd,
|
||||||
&_exec_text_cmd,
|
&_exec_text_cmd,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _exec_buffer() {
|
void _exec_buffer() {
|
||||||
if(d_debug_next_frame) printf("debug capture of draw buffer\ncount: %zu\n", (size_t)(g_drawdata_endptr - g_drawdata));
|
if(d_debug_next_frame) printf("debug capture of draw buffer\ncount: %zu\n", (size_t)(g_drawdata_endptr - g_drawdata));
|
||||||
for(const drawcmd_t* cmd = g_drawdata; cmd != g_drawdata_endptr; ++cmd) {
|
for(const drawcmd_t* cmd = g_drawdata; cmd != g_drawdata_endptr; ++cmd) {
|
||||||
if(cmd->type > DRAWCMDTYPE_MIN && cmd->type < DRAWCMDTYPE_MAX) {
|
if(cmd->type > DRAWCMDTYPE_MIN && cmd->type < DRAWCMDTYPE_MAX) {
|
||||||
if(d_debug_next_frame) {
|
if(d_debug_next_frame) {
|
||||||
printf("depth: %d, type: %d\n", cmd->depth, cmd->type);
|
printf("depth: %d, type: %d\n", cmd->depth, cmd->type);
|
||||||
}
|
}
|
||||||
drawcmd_funcs[cmd->type](cmd);
|
drawcmd_funcs[cmd->type](cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap_buffer() {
|
void swap_buffer() {
|
||||||
clear_buffer();
|
clear_buffer();
|
||||||
int iw, ih;
|
int iw, ih;
|
||||||
SDL_GetRendererOutputSize(g_context.renderer, &iw, &ih);
|
SDL_GetRendererOutputSize(g_context.renderer, &iw, &ih);
|
||||||
_render_width = (float)iw; _render_height = (float)ih;
|
_render_width = (float)iw; _render_height = (float)ih;
|
||||||
_aspect_ratio = _render_height/_render_width;
|
_aspect_ratio = _render_height/_render_width;
|
||||||
_exec_buffer();
|
_exec_buffer();
|
||||||
SDL_RenderPresent(g_context.renderer);
|
SDL_RenderPresent(g_context.renderer);
|
||||||
g_drawdata_endptr = g_drawdata;
|
g_drawdata_endptr = g_drawdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _insert_drawcmd_at(size_t index, const drawcmd_t* cmd) {
|
void _insert_drawcmd_at(size_t index, const drawcmd_t* cmd) {
|
||||||
drawcmd_t* insertpoint = g_drawdata + index;
|
drawcmd_t* insertpoint = g_drawdata + index;
|
||||||
drawcmd_t* dest = insertpoint + 1;
|
drawcmd_t* dest = insertpoint + 1;
|
||||||
size_t size = (size_t)(g_drawdata_endptr - g_drawdata);
|
size_t size = (size_t)(g_drawdata_endptr - g_drawdata);
|
||||||
++g_drawdata_endptr;
|
++g_drawdata_endptr;
|
||||||
if(size > index) {
|
if(size > index) {
|
||||||
size_t count = (size - index);
|
size_t count = (size - index);
|
||||||
if(size > 0)
|
if(size > 0)
|
||||||
{
|
{
|
||||||
memmove(dest, insertpoint, count*sizeof(drawcmd_t));
|
memmove(dest, insertpoint, count*sizeof(drawcmd_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*insertpoint = *cmd;
|
*insertpoint = *cmd;
|
||||||
insertpoint->ui = _render_mode == 1;
|
insertpoint->ui = _render_mode == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void _draw(const drawcmd_t* cmd) {
|
void _draw(const drawcmd_t* cmd) {
|
||||||
if(g_drawdata_endptr == g_drawdata) {
|
if(g_drawdata_endptr == g_drawdata) {
|
||||||
_insert_drawcmd_at(0, cmd);
|
_insert_drawcmd_at(0, cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long top = (size_t)(g_drawdata_endptr - g_drawdata),
|
long top = (size_t)(g_drawdata_endptr - g_drawdata),
|
||||||
bot = 0,
|
bot = 0,
|
||||||
med = 0;
|
med = 0;
|
||||||
|
|
||||||
if(top != bot) {
|
if(top != bot) {
|
||||||
while(bot <= top) {
|
while(bot <= top) {
|
||||||
med = floor((float)(top + bot) / 2);
|
med = floor((float)(top + bot) / 2);
|
||||||
if(g_drawdata[med].depth > cmd->depth) {
|
if(g_drawdata[med].depth > cmd->depth) {
|
||||||
bot = med+1;
|
bot = med+1;
|
||||||
} else if(g_drawdata[med].depth < cmd->depth) {
|
} else if(g_drawdata[med].depth < cmd->depth) {
|
||||||
top = med-1;
|
top = med-1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t count = (g_drawdata_endptr - g_drawdata);
|
size_t count = (g_drawdata_endptr - g_drawdata);
|
||||||
int diff = g_drawdata[med].depth - cmd->depth;
|
int diff = g_drawdata[med].depth - cmd->depth;
|
||||||
while(diff > 0 && med < count) {
|
while(diff > 0 && med < count) {
|
||||||
med++;
|
med++;
|
||||||
diff = g_drawdata[med].depth - cmd->depth;
|
diff = g_drawdata[med].depth - cmd->depth;
|
||||||
}
|
}
|
||||||
_insert_drawcmd_at(med, cmd);
|
_insert_drawcmd_at(med, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_sprite(const sprite_t* sprite) {
|
void draw_sprite(const sprite_t* sprite) {
|
||||||
drawcmd_t d = {
|
drawcmd_t d = {
|
||||||
.type=DRAWCMDTYPE_SPRITE,
|
.type=DRAWCMDTYPE_SPRITE,
|
||||||
.depth=sprite->depth,
|
.depth=sprite->depth,
|
||||||
.sprite=*sprite
|
.sprite=*sprite
|
||||||
};
|
};
|
||||||
_draw(&d);
|
_draw(&d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_rect(const rectshape_t* rect) {
|
void draw_rect(const rectshape_t* rect) {
|
||||||
drawcmd_t d = {
|
drawcmd_t d = {
|
||||||
.type=DRAWCMDTYPE_RECT,
|
.type=DRAWCMDTYPE_RECT,
|
||||||
.depth=rect->depth,
|
.depth=rect->depth,
|
||||||
.rect=*rect
|
.rect=*rect
|
||||||
};
|
};
|
||||||
_draw(&d);
|
_draw(&d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_sliced(const nineslice_t *sliced) {
|
void draw_sliced(const nineslice_t *sliced) {
|
||||||
drawcmd_t d = {
|
drawcmd_t d = {
|
||||||
.type=DRAWCMDTYPE_SLICED,
|
.type=DRAWCMDTYPE_SLICED,
|
||||||
.depth=sliced->depth,
|
.depth=sliced->depth,
|
||||||
.sliced=*sliced
|
.sliced=*sliced
|
||||||
};
|
};
|
||||||
_draw(&d);
|
_draw(&d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_text(const char *str, SDL_FRect area, text_style_t style, depth_t depth) {
|
void draw_text(const char *str, SDL_FRect area, text_style_t style, depth_t depth) {
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
textarea_t t = {
|
textarea_t t = {
|
||||||
.text = calloc(len+1, sizeof(char)),
|
.text = calloc(len+1, sizeof(char)),
|
||||||
.area = area,
|
.area = area,
|
||||||
.style = style,
|
.style = style,
|
||||||
};
|
};
|
||||||
strcpy(t.text, str);
|
strcpy(t.text, str);
|
||||||
drawcmd_t d = {
|
drawcmd_t d = {
|
||||||
.type=DRAWCMDTYPE_TEXT,
|
.type=DRAWCMDTYPE_TEXT,
|
||||||
.text=t,
|
.text=t,
|
||||||
.depth=depth,
|
.depth=depth,
|
||||||
};
|
};
|
||||||
_draw(&d);
|
_draw(&d);
|
||||||
}
|
}
|
||||||
|
|
||||||
spritesheet_t make_spritesheet(const char *file, int tiles_x, int tiles_y) {
|
spritesheet_t make_spritesheet(const char *file, int tiles_x, int tiles_y) {
|
||||||
spritesheet_t sheet=(spritesheet_t){
|
spritesheet_t sheet=(spritesheet_t){
|
||||||
.texture=get_texture(file),
|
.texture=get_texture(file),
|
||||||
.w=0,.h=0,
|
.w=0,.h=0,
|
||||||
};
|
};
|
||||||
SDL_QueryTexture(sheet.texture, NULL, NULL, &sheet.w, &sheet.h);
|
SDL_QueryTexture(sheet.texture, NULL, NULL, &sheet.w, &sheet.h);
|
||||||
sheet.tile_width = sheet.w / tiles_x;
|
sheet.tile_width = sheet.w / tiles_x;
|
||||||
sheet.tile_height = sheet.h / tiles_y;
|
sheet.tile_height = sheet.h / tiles_y;
|
||||||
return sheet;
|
return sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
nineslice_t make_nineslice(const char *file, int corner_px, float radius) {
|
nineslice_t make_nineslice(const char *file, int corner_px, float radius) {
|
||||||
nineslice_t sliced = {
|
nineslice_t sliced = {
|
||||||
.depth = RLAYER_UI,
|
.depth = RLAYER_UI,
|
||||||
.corner_size = corner_px,
|
.corner_size = corner_px,
|
||||||
.radius = radius,
|
.radius = radius,
|
||||||
.rect= {0.0, 0.0, 1.0, 1.0},
|
.rect= {0.0, 0.0, 1.0, 1.0},
|
||||||
.texture=get_texture(file)
|
.texture=get_texture(file)
|
||||||
};
|
};
|
||||||
return sliced;
|
return sliced;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite_t make_sprite(const char* file, float x, float y) {
|
sprite_t make_sprite(const char* file, float x, float y) {
|
||||||
sprite_t sprite=(sprite_t){
|
sprite_t sprite=(sprite_t){
|
||||||
.texture=get_texture(file),
|
.texture=get_texture(file),
|
||||||
.x=x,.y=y,
|
.x=x,.y=y,
|
||||||
.origin=(SDL_FPoint){.x=0.0,.y=0.0},
|
.origin=(SDL_FPoint){.x=0.0,.y=0.0},
|
||||||
.sx=1.0,.sy=1.0,
|
.sx=1.0,.sy=1.0,
|
||||||
.rot=0,
|
.rot=0,
|
||||||
.depth=RLAYER_SPRITES,
|
.depth=RLAYER_SPRITES,
|
||||||
.uv=(SDL_Rect){0,0,0,0},
|
.uv=(SDL_Rect){0,0,0,0},
|
||||||
.flip=SDL_FLIP_NONE,
|
.flip=SDL_FLIP_NONE,
|
||||||
};
|
};
|
||||||
SDL_QueryTexture(sprite.texture, NULL, NULL, &sprite.uv.w, &sprite.uv.h);
|
SDL_QueryTexture(sprite.texture, NULL, NULL, &sprite.uv.w, &sprite.uv.h);
|
||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite_t sprite_from_spritesheet(spritesheet_t *sheet, int index) {
|
sprite_t sprite_from_spritesheet(spritesheet_t *sheet, int index) {
|
||||||
SDL_Rect rect = get_srcrect_from(sheet, index);
|
SDL_Rect rect = get_srcrect_from(sheet, index);
|
||||||
return (sprite_t) {
|
return (sprite_t) {
|
||||||
.texture=sheet->texture,
|
.texture=sheet->texture,
|
||||||
.x=0, .y=0,
|
.x=0, .y=0,
|
||||||
.origin=(SDL_FPoint){0,0},
|
.origin=(SDL_FPoint){0,0},
|
||||||
.sx=1.0, .sy=1.0,
|
.sx=1.0, .sy=1.0,
|
||||||
.rot=0,
|
.rot=0,
|
||||||
.depth=RLAYER_SPRITES,
|
.depth=RLAYER_SPRITES,
|
||||||
.uv=rect,
|
.uv=rect,
|
||||||
.flip=SDL_FLIP_NONE,
|
.flip=SDL_FLIP_NONE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
text_style_t make_text_style(const char *font, SDL_Color color, int dpi, float size) {
|
text_style_t make_text_style(const char *font, SDL_Color color, int dpi, float size) {
|
||||||
TTF_Font* fnt = get_font(font, dpi);
|
TTF_Font* fnt = get_font(font, dpi);
|
||||||
return (text_style_t){
|
return (text_style_t){
|
||||||
.font = fnt,
|
.font = fnt,
|
||||||
.size = size,
|
.size = size,
|
||||||
.color = color
|
.color = color
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Rect get_srcrect_from(spritesheet_t *sheet, int index) {
|
SDL_Rect get_srcrect_from(spritesheet_t *sheet, int index) {
|
||||||
int pixels = index * sheet->tile_width;
|
int pixels = index * sheet->tile_width;
|
||||||
int w = sheet->w / sheet->tile_width;
|
int w = sheet->w / sheet->tile_width;
|
||||||
return (SDL_Rect) {
|
return (SDL_Rect) {
|
||||||
pixels%sheet->w, index/w * sheet->tile_height,
|
pixels%sheet->w, index/w * sheet->tile_height,
|
||||||
sheet->tile_width, sheet->tile_height,
|
sheet->tile_width, sheet->tile_height,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,74 +13,74 @@ typedef int depth_t;
|
||||||
extern int d_debug_next_frame;
|
extern int d_debug_next_frame;
|
||||||
|
|
||||||
typedef enum drawcmdtype_t {
|
typedef enum drawcmdtype_t {
|
||||||
DRAWCMDTYPE_MIN = -1,
|
DRAWCMDTYPE_MIN = -1,
|
||||||
DRAWCMDTYPE_SPRITE = 0,
|
DRAWCMDTYPE_SPRITE = 0,
|
||||||
DRAWCMDTYPE_RECT = 1,
|
DRAWCMDTYPE_RECT = 1,
|
||||||
DRAWCMDTYPE_SLICED = 2,
|
DRAWCMDTYPE_SLICED = 2,
|
||||||
DRAWCMDTYPE_TEXT = 3,
|
DRAWCMDTYPE_TEXT = 3,
|
||||||
DRAWCMDTYPE_MAX
|
DRAWCMDTYPE_MAX
|
||||||
} drawcmdtype_t;
|
} drawcmdtype_t;
|
||||||
|
|
||||||
typedef struct text_style_t {
|
typedef struct text_style_t {
|
||||||
TTF_Font* font;
|
TTF_Font* font;
|
||||||
float size;
|
float size;
|
||||||
SDL_Color color;
|
SDL_Color color;
|
||||||
} text_style_t;
|
} text_style_t;
|
||||||
|
|
||||||
typedef struct spritesheet_t {
|
typedef struct spritesheet_t {
|
||||||
SDL_Texture* texture;
|
SDL_Texture* texture;
|
||||||
int w, h; // width and height of texture
|
int w, h; // width and height of texture
|
||||||
int tile_width, tile_height; // the width and height of each tile of each
|
int tile_width, tile_height; // the width and height of each tile of each
|
||||||
} spritesheet_t; // sliced up sheet of sprites
|
} spritesheet_t; // sliced up sheet of sprites
|
||||||
|
|
||||||
typedef struct nineslice_t {
|
typedef struct nineslice_t {
|
||||||
SDL_Texture* texture;
|
SDL_Texture* texture;
|
||||||
SDL_FRect rect; // the rectangle to fit into
|
SDL_FRect rect; // the rectangle to fit into
|
||||||
depth_t depth;
|
depth_t depth;
|
||||||
float radius;
|
float radius;
|
||||||
int corner_size;
|
int corner_size;
|
||||||
} nineslice_t; // nine-sliced texture for ui
|
} nineslice_t; // nine-sliced texture for ui
|
||||||
|
|
||||||
typedef struct textarea_t {
|
typedef struct textarea_t {
|
||||||
char* text;
|
char* text;
|
||||||
text_style_t style;
|
text_style_t style;
|
||||||
SDL_FRect area;
|
SDL_FRect area;
|
||||||
} textarea_t;
|
} textarea_t;
|
||||||
|
|
||||||
typedef struct sprite_t {
|
typedef struct sprite_t {
|
||||||
SDL_Texture* texture;
|
SDL_Texture* texture;
|
||||||
float x, y; // positions of x,y
|
float x, y; // positions of x,y
|
||||||
SDL_FPoint origin; // the origin point on the sprite
|
SDL_FPoint origin; // the origin point on the sprite
|
||||||
float sx, sy; // the x and y scale of the sprite
|
float sx, sy; // the x and y scale of the sprite
|
||||||
float rot; // rotation around origin of the sprite
|
float rot; // rotation around origin of the sprite
|
||||||
depth_t depth; // depth to render at, lower is on top, higher is on bottom
|
depth_t depth; // depth to render at, lower is on top, higher is on bottom
|
||||||
SDL_Rect uv; // the source rect to render from the texture
|
SDL_Rect uv; // the source rect to render from the texture
|
||||||
SDL_RendererFlip flip; // the flipped state of the sprite
|
SDL_RendererFlip flip; // the flipped state of the sprite
|
||||||
} sprite_t; // a drawable and transformable texture sprite
|
} sprite_t; // a drawable and transformable texture sprite
|
||||||
|
|
||||||
typedef struct rectshape_t {
|
typedef struct rectshape_t {
|
||||||
float x, y, w, h; // the top-left, width and height of a rect
|
float x, y, w, h; // the top-left, width and height of a rect
|
||||||
float line_width; // the width of the lines
|
float line_width; // the width of the lines
|
||||||
int depth; // the depth to render at, lower is on top, higher is on bottom
|
int depth; // the depth to render at, lower is on top, higher is on bottom
|
||||||
SDL_Color background; // the colour of the background
|
SDL_Color background; // the colour of the background
|
||||||
SDL_Color line; // the colour of the line
|
SDL_Color line; // the colour of the line
|
||||||
} rectshape_t; // a drawable rectangle with outline and background
|
} rectshape_t; // a drawable rectangle with outline and background
|
||||||
|
|
||||||
typedef struct drawcmd_t {
|
typedef struct drawcmd_t {
|
||||||
drawcmdtype_t type; // the thing to render
|
drawcmdtype_t type; // the thing to render
|
||||||
depth_t depth; // the depth to render at
|
depth_t depth; // the depth to render at
|
||||||
short ui; // 0 if this should be rendered in world space, 1 if this should be rendered in ui space
|
short ui; // 0 if this should be rendered in world space, 1 if this should be rendered in ui space
|
||||||
union {
|
union {
|
||||||
sprite_t sprite; // if type is sprite, render this
|
sprite_t sprite; // if type is sprite, render this
|
||||||
rectshape_t rect; // if type is rect, render this
|
rectshape_t rect; // if type is rect, render this
|
||||||
nineslice_t sliced;
|
nineslice_t sliced;
|
||||||
textarea_t text;
|
textarea_t text;
|
||||||
};
|
};
|
||||||
} drawcmd_t; // an orderable command to render, should not be directly used, use draw_* functions instead
|
} drawcmd_t; // an orderable command to render, should not be directly used, use draw_* functions instead
|
||||||
|
|
||||||
typedef struct view_t {
|
typedef struct view_t {
|
||||||
float x, y; // the x,y position of the centre of the screen
|
float x, y; // the x,y position of the centre of the screen
|
||||||
float width; // the width of the camera
|
float width; // the width of the camera
|
||||||
} view_t;
|
} view_t;
|
||||||
|
|
||||||
extern int _render_mode;
|
extern int _render_mode;
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
|
|
||||||
static
|
static
|
||||||
struct type_handler_t {
|
struct type_handler_t {
|
||||||
uintptr_t hash;
|
uintptr_t hash;
|
||||||
char* type;
|
char* type;
|
||||||
type_handler_fn handler;
|
type_handler_fn handler;
|
||||||
} _type_handlers[99];
|
} _type_handlers[99];
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -24,197 +24,197 @@ int _type_handler_num = 0;
|
||||||
|
|
||||||
static
|
static
|
||||||
struct type_handler_t* _find_handler_for(const char* type) {
|
struct type_handler_t* _find_handler_for(const char* type) {
|
||||||
uintptr_t hash = hashstr(type);
|
uintptr_t hash = hashstr(type);
|
||||||
for(int i = 0; i < 99; ++i) {
|
for(int i = 0; i < 99; ++i) {
|
||||||
if(_type_handlers[i].hash == hash && strcmp(type, _type_handlers[i].type) == 0) {
|
if(_type_handlers[i].hash == hash && strcmp(type, _type_handlers[i].type) == 0) {
|
||||||
return _type_handlers + i;
|
return _type_handlers + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
struct type_handler_t* _new_handler_for(const char* type) {
|
struct type_handler_t* _new_handler_for(const char* type) {
|
||||||
_type_handlers[_type_handler_num].type = malloc(strlen(type) * sizeof(char));
|
_type_handlers[_type_handler_num].type = malloc(strlen(type) * sizeof(char));
|
||||||
strcpy(_type_handlers[_type_handler_num].type, type);
|
strcpy(_type_handlers[_type_handler_num].type, type);
|
||||||
_type_handlers[_type_handler_num].hash = hashstr(type);
|
_type_handlers[_type_handler_num].hash = hashstr(type);
|
||||||
struct type_handler_t* ptr = _type_handlers + _type_handler_num;
|
struct type_handler_t* ptr = _type_handlers + _type_handler_num;
|
||||||
++_type_handler_num;
|
++_type_handler_num;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_type_handler(const char* type, type_handler_fn handler) {
|
void set_type_handler(const char* type, type_handler_fn handler) {
|
||||||
struct type_handler_t* ptr = _find_handler_for(type);
|
struct type_handler_t* ptr = _find_handler_for(type);
|
||||||
if(ptr == NULL) {
|
if(ptr == NULL) {
|
||||||
ptr = _new_handler_for(type);
|
ptr = _new_handler_for(type);
|
||||||
}
|
}
|
||||||
ptr->handler = handler;
|
ptr->handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int fpeekc(FILE* file) {
|
int fpeekc(FILE* file) {
|
||||||
int c = fgetc(file);
|
int c = fgetc(file);
|
||||||
ungetc(c, file);
|
ungetc(c, file);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void freadto(FILE* file, char c) {
|
void freadto(FILE* file, char c) {
|
||||||
char read;
|
char read;
|
||||||
do {
|
do {
|
||||||
read = fgetc(file);
|
read = fgetc(file);
|
||||||
} while(read != c);
|
} while(read != c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int nextnw(FILE* file) {
|
int nextnw(FILE* file) {
|
||||||
int next;
|
int next;
|
||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
next = fgetc(file);
|
next = fgetc(file);
|
||||||
c = (char)next;
|
c = (char)next;
|
||||||
} while(isspace(c));
|
} while(isspace(c));
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int _parse_key(FILE* file, char* out) {
|
int _parse_key(FILE* file, char* out) {
|
||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
c = fgetc(file);
|
c = fgetc(file);
|
||||||
if(c == ':' || c == ';') {
|
if(c == ':' || c == ';') {
|
||||||
*out = '\0';
|
*out = '\0';
|
||||||
} else if(c == '#') {
|
} else if(c == '#') {
|
||||||
freadto(file, '\n');
|
freadto(file, '\n');
|
||||||
} else if(!isspace(c)) {
|
} else if(!isspace(c)) {
|
||||||
*out = c;
|
*out = c;
|
||||||
++out;
|
++out;
|
||||||
}
|
}
|
||||||
} while(c != ':' && c != ';');
|
} while(c != ':' && c != ';');
|
||||||
|
|
||||||
return c == ':';
|
return c == ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _parse_value(FILE* file, char* out, int* _argc, char** argv) {
|
void _parse_value(FILE* file, char* out, int* _argc, char** argv) {
|
||||||
char c;
|
char c;
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
argv[argc] = out;
|
argv[argc] = out;
|
||||||
++argc;
|
++argc;
|
||||||
do {
|
do {
|
||||||
c = fgetc(file);
|
c = fgetc(file);
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '#':
|
case '#':
|
||||||
freadto(file, '\n');
|
freadto(file, '\n');
|
||||||
// fall through
|
// fall through
|
||||||
case '\n':
|
case '\n':
|
||||||
ungetc(nextnw(file), file);
|
ungetc(nextnw(file), file);
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
*out = '\0';
|
*out = '\0';
|
||||||
break;
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
*out = '\0';
|
*out = '\0';
|
||||||
++out;
|
++out;
|
||||||
argv[argc] = out;
|
argv[argc] = out;
|
||||||
++argc;
|
++argc;
|
||||||
ungetc(nextnw(file), file);
|
ungetc(nextnw(file), file);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*out = c;
|
*out = c;
|
||||||
++out;
|
++out;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(c != ';');
|
} while(c != ';');
|
||||||
*_argc = argc;
|
*_argc = argc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _parse_config(FILE* file) {
|
void _parse_config(FILE* file) {
|
||||||
char key[24];
|
char key[24];
|
||||||
char value[128];
|
char value[128];
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
char* argv[24];
|
char* argv[24];
|
||||||
|
|
||||||
char begin = nextnw(file);
|
char begin = nextnw(file);
|
||||||
ungetc(begin, file);
|
ungetc(begin, file);
|
||||||
|
|
||||||
int has_args = _parse_key(file, key);
|
int has_args = _parse_key(file, key);
|
||||||
ungetc(nextnw(file), file);
|
ungetc(nextnw(file), file);
|
||||||
if(has_args) {
|
if(has_args) {
|
||||||
_parse_value(file, value, &argc, argv);
|
_parse_value(file, value, &argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct type_handler_t* handler = _find_handler_for(key);
|
struct type_handler_t* handler = _find_handler_for(key);
|
||||||
|
|
||||||
if(handler != NULL) {
|
if(handler != NULL) {
|
||||||
if(begin == '!') {
|
if(begin == '!') {
|
||||||
handler->handler(NULL, argc, argv);
|
handler->handler(NULL, argc, argv);
|
||||||
} else {
|
} else {
|
||||||
handler->handler(make_object(), argc, argv);
|
handler->handler(make_object(), argc, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(fpeekc(file) == EOF) return;
|
if(fpeekc(file) == EOF) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _parse_scene(FILE* file) {
|
void _parse_scene(FILE* file) {
|
||||||
int next;
|
int next;
|
||||||
do {
|
do {
|
||||||
_parse_config(file);
|
_parse_config(file);
|
||||||
next = nextnw(file);
|
next = nextnw(file);
|
||||||
ungetc(next, file);
|
ungetc(next, file);
|
||||||
} while(next != EOF);
|
} while(next != EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int _validate_config(FILE* file) {
|
int _validate_config(FILE* file) {
|
||||||
char c;
|
char c;
|
||||||
int colon_count = 0;
|
int colon_count = 0;
|
||||||
do {
|
do {
|
||||||
c = nextnw(file);
|
c = nextnw(file);
|
||||||
switch(c) {
|
switch(c) {
|
||||||
default: break;
|
default: break;
|
||||||
case ':':
|
case ':':
|
||||||
colon_count++;
|
colon_count++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(c != ';');
|
} while(c != ';');
|
||||||
|
|
||||||
return colon_count <= 1;
|
return colon_count <= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int _validate_scene(FILE* file) {
|
int _validate_scene(FILE* file) {
|
||||||
if(file == NULL) return 0;
|
if(file == NULL) return 0;
|
||||||
|
|
||||||
int next;
|
int next;
|
||||||
int validated;
|
int validated;
|
||||||
do {
|
do {
|
||||||
validated = _validate_config(file);
|
validated = _validate_config(file);
|
||||||
next = nextnw(file);
|
next = nextnw(file);
|
||||||
ungetc(next, file);
|
ungetc(next, file);
|
||||||
} while(validated == 1 && next != EOF);
|
} while(validated == 1 && next != EOF);
|
||||||
|
|
||||||
rewind(file);
|
rewind(file);
|
||||||
|
|
||||||
return validated;
|
return validated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_scene(const char* filename) {
|
void load_scene(const char* filename) {
|
||||||
FILE* file = fopen(filename, "r");
|
FILE* file = fopen(filename, "r");
|
||||||
if(_validate_scene(file)) {
|
if(_validate_scene(file)) {
|
||||||
input_disconnect_all();
|
input_disconnect_all();
|
||||||
world_clear();
|
world_clear();
|
||||||
_parse_scene(file);
|
_parse_scene(file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_scene_additive(const char* filename) {
|
void load_scene_additive(const char* filename) {
|
||||||
FILE* file = fopen(filename, "r");
|
FILE* file = fopen(filename, "r");
|
||||||
if(_validate_scene(file)) {
|
if(_validate_scene(file)) {
|
||||||
_parse_scene(file);
|
_parse_scene(file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,118 +5,118 @@
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
size_t num;
|
size_t num;
|
||||||
object_t** objects;
|
object_t** objects;
|
||||||
} _world_objects = {
|
} _world_objects = {
|
||||||
.num = 0,
|
.num = 0,
|
||||||
.objects = NULL
|
.objects = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int _expand_world() {
|
int _expand_world() {
|
||||||
size_t new_num = _world_objects.num * 2;
|
size_t new_num = _world_objects.num * 2;
|
||||||
if(new_num == 0) {
|
if(new_num == 0) {
|
||||||
new_num = 16;
|
new_num = 16;
|
||||||
}
|
}
|
||||||
object_t** new_list = realloc(_world_objects.objects, new_num * sizeof(object_t*));
|
object_t** new_list = realloc(_world_objects.objects, new_num * sizeof(object_t*));
|
||||||
|
|
||||||
if(new_list == NULL) {
|
if(new_list == NULL) {
|
||||||
assert(!"ERROR: Out of memory");
|
assert(!"ERROR: Out of memory");
|
||||||
exit(-10);
|
exit(-10);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = _world_objects.num; i < new_num; ++i) {
|
for(size_t i = _world_objects.num; i < new_num; ++i) {
|
||||||
new_list[i] = NULL;
|
new_list[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_world_objects.objects = new_list;
|
_world_objects.objects = new_list;
|
||||||
_world_objects.num = new_num;
|
_world_objects.num = new_num;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
size_t _find_free_object() {
|
size_t _find_free_object() {
|
||||||
for(int i = 0; i < _world_objects.num; ++i) {
|
for(int i = 0; i < _world_objects.num; ++i) {
|
||||||
if(!object_is_valid(_world_objects.objects[i])) {
|
if(!object_is_valid(_world_objects.objects[i])) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t num = _world_objects.num;
|
size_t num = _world_objects.num;
|
||||||
_expand_world();
|
_expand_world();
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void world_clear() {
|
void world_clear() {
|
||||||
// free all allocated objects
|
// free all allocated objects
|
||||||
for(int i = 0; i < _world_objects.num; ++i) {
|
for(int i = 0; i < _world_objects.num; ++i) {
|
||||||
object_t* object = _world_objects.objects[i];
|
object_t* object = _world_objects.objects[i];
|
||||||
if(object != NULL) {
|
if(object != NULL) {
|
||||||
free(object);
|
free(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// free world array
|
// free world array
|
||||||
free(_world_objects.objects);
|
free(_world_objects.objects);
|
||||||
// reset world objects struct
|
// reset world objects struct
|
||||||
_world_objects.objects = NULL;
|
_world_objects.objects = NULL;
|
||||||
_world_objects.num = 0;
|
_world_objects.num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_t* make_object() {
|
object_t* make_object() {
|
||||||
// acquire pointer to empty slot
|
// acquire pointer to empty slot
|
||||||
size_t index = _find_free_object();
|
size_t index = _find_free_object();
|
||||||
// allocate new object
|
// allocate new object
|
||||||
if(_world_objects.objects[index] == NULL) {
|
if(_world_objects.objects[index] == NULL) {
|
||||||
_world_objects.objects[index] = malloc(sizeof(object_t));
|
_world_objects.objects[index] = malloc(sizeof(object_t));
|
||||||
}
|
}
|
||||||
// initialize object to default
|
// initialize object to default
|
||||||
object_t* o = _world_objects.objects[index];
|
object_t* o = _world_objects.objects[index];
|
||||||
*o = object_default();
|
*o = object_default();
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_t* instantiate_object(const object_t *original) {
|
object_t* instantiate_object(const object_t *original) {
|
||||||
// create new object with default settings
|
// create new object with default settings
|
||||||
object_t* obj = make_object();
|
object_t* obj = make_object();
|
||||||
*obj = *original;
|
*obj = *original;
|
||||||
obj->active = 1;
|
obj->active = 1;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void world_update() {
|
void world_update() {
|
||||||
for(int i = 0; i < _world_objects.num; ++i) {
|
for(int i = 0; i < _world_objects.num; ++i) {
|
||||||
object_t* object = world_get_object(i);
|
object_t* object = world_get_object(i);
|
||||||
if(object_is_valid(object)
|
if(object_is_valid(object)
|
||||||
&& object->evt_update != NULL) {
|
&& object->evt_update != NULL) {
|
||||||
object->evt_update(object);
|
object->evt_update(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void world_draw() {
|
void world_draw() {
|
||||||
for(int i = 0; i < _world_objects.num; ++i) {
|
for(int i = 0; i < _world_objects.num; ++i) {
|
||||||
object_t* object = world_get_object(i);
|
object_t* object = world_get_object(i);
|
||||||
if(object_is_valid(object)
|
if(object_is_valid(object)
|
||||||
&& object->evt_draw != NULL) {
|
&& object->evt_draw != NULL) {
|
||||||
object->evt_draw(object);
|
object->evt_draw(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object_t* world_get_object(size_t at) {
|
object_t* world_get_object(size_t at) {
|
||||||
if(at < _world_objects.num) {
|
if(at < _world_objects.num) {
|
||||||
return _world_objects.objects[at];
|
return _world_objects.objects[at];
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t world_num_objects() {
|
size_t world_num_objects() {
|
||||||
return _world_objects.num;
|
return _world_objects.num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void world_reserve_objects(size_t min) {
|
void world_reserve_objects(size_t min) {
|
||||||
while(_world_objects.num < min) {
|
while(_world_objects.num < min) {
|
||||||
_expand_world();
|
_expand_world();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/game.c
12
src/game.c
|
@ -6,19 +6,19 @@
|
||||||
#include "corelib/layers.h"
|
#include "corelib/layers.h"
|
||||||
|
|
||||||
void start_game() {
|
void start_game() {
|
||||||
// called when the game is done initializing the backend and ready to start
|
// called when the game is done initializing the backend and ready to start
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_game() {
|
void update_game() {
|
||||||
// called every frame,
|
// called every frame,
|
||||||
// render calls made in this function will be in *world* space
|
// render calls made in this function will be in *world* space
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_ui() {
|
void update_ui() {
|
||||||
// called every frame,
|
// called every frame,
|
||||||
// render calls made in this function will be in *screen* space
|
// render calls made in this function will be in *screen* space
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_exit() {
|
void game_exit() {
|
||||||
// called when the game shuts down
|
// called when the game shuts down
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue