added source
parent
548c1bcd6a
commit
97d6dda15a
|
@ -0,0 +1,74 @@
|
|||
#include "assets.h"
|
||||
#include "hash.h"
|
||||
#include "context.h"
|
||||
#include "SDL2/SDL_image.h"
|
||||
#include "string.h"
|
||||
|
||||
#define NUM_ASSETS 256
|
||||
|
||||
resource_t g_assets[NUM_ASSETS];
|
||||
resource_t* g_assets_endptr = g_assets;
|
||||
|
||||
resource_t* insert_asset(const resource_t* resource) {
|
||||
*g_assets_endptr = *resource;
|
||||
resource_t* inserted = g_assets_endptr;
|
||||
++g_assets_endptr;
|
||||
return inserted;
|
||||
}
|
||||
|
||||
SDL_Texture* load_texture(const char* file) {
|
||||
int len = strlen(file);
|
||||
resource_t res = (resource_t){
|
||||
.type = RESOURCETYPE_TEXTURE,
|
||||
.hash = hashstr(file),
|
||||
.name = (char*)calloc(len+1, sizeof(char)),
|
||||
.texture = IMG_LoadTexture(g_context.renderer, file),
|
||||
};
|
||||
strcpy(res.name, file);
|
||||
return insert_asset(&res)->texture;
|
||||
}
|
||||
|
||||
SDL_Texture* get_texture(const char* file) {
|
||||
resource_t* found = get_asset(file);
|
||||
if(found != NULL && found->type == RESOURCETYPE_TEXTURE) {
|
||||
return found->texture;
|
||||
} else {
|
||||
return load_texture(file);
|
||||
}
|
||||
}
|
||||
|
||||
resource_t* get_asset(const char* file) {
|
||||
uint32_t hash = hashstr(file);
|
||||
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
||||
if(res->hash == hash
|
||||
&& strcmp(res->name, file) == 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _delete_referenced_asset(resource_t* res) {
|
||||
switch(res->type) {
|
||||
default:
|
||||
break;
|
||||
case RESOURCETYPE_TEXTURE:
|
||||
SDL_DestroyTexture(res->texture);
|
||||
free(res->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void clean_assets() {
|
||||
for(resource_t* res = g_assets; res != g_assets_endptr; ++res) {
|
||||
_delete_referenced_asset(res);
|
||||
}
|
||||
g_assets_endptr = g_assets;
|
||||
}
|
||||
|
||||
void _remove_asset(resource_t* res) {
|
||||
_delete_referenced_asset(res);
|
||||
resource_t* last = g_assets_endptr - 1;
|
||||
memmove(res, last, sizeof(resource_t));
|
||||
--g_assets_endptr;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef _assets_h
|
||||
#define _assets_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stddef.h"
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
typedef enum resourcetype_t {
|
||||
RESOURCETYPE_MIN,
|
||||
RESOURCETYPE_TEXTURE,
|
||||
RESOURCETYPE_MAX
|
||||
} resourcetype_t;
|
||||
|
||||
typedef struct resource_t {
|
||||
resourcetype_t type;
|
||||
uintptr_t hash;
|
||||
char* name;
|
||||
union {
|
||||
SDL_Texture* texture;
|
||||
};
|
||||
} resource_t;
|
||||
|
||||
extern SDL_Texture* load_texture(const char* file);
|
||||
extern SDL_Texture* get_texture(const char* file);
|
||||
extern resource_t* get_asset(const char* file);
|
||||
|
||||
extern void clean_assets();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _assets_h */
|
|
@ -0,0 +1,29 @@
|
|||
#include "context.h"
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_image.h"
|
||||
|
||||
context_t g_context = {
|
||||
.window = NULL,
|
||||
.renderer = NULL,
|
||||
.running = 1
|
||||
};
|
||||
|
||||
void init_context() {
|
||||
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
||||
SDL_Log("ERROR LOADING SDL %s", SDL_GetError());
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING SDL", SDL_GetError(), NULL);
|
||||
exit(1);
|
||||
}
|
||||
if(IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) == 0) {
|
||||
SDL_Log("ERROR LOADING IMG %s", IMG_GetError());
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR LOADING IMG", IMG_GetError(), NULL);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
void close_context() {
|
||||
SDL_DestroyRenderer(g_context.renderer);
|
||||
SDL_DestroyWindow(g_context.window);
|
||||
IMG_Quit();
|
||||
SDL_Quit();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _context_h
|
||||
#define _context_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "SDL2/SDL_render.h"
|
||||
#include "SDL2/SDL_events.h"
|
||||
|
||||
typedef struct context_t {
|
||||
SDL_Window* window;
|
||||
SDL_Renderer* renderer;
|
||||
SDL_Event event;
|
||||
short running;
|
||||
} context_t;
|
||||
|
||||
extern context_t g_context;
|
||||
extern void init_context();
|
||||
extern void close_context();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include "engine.hpp"
|
||||
#include "assets.h"
|
||||
#include "render.h"
|
||||
#include "SDL2/SDL_image.h"
|
||||
|
||||
int engine_start() {
|
||||
init_context();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int engine_shutdown() {
|
||||
clean_assets();
|
||||
close_context();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void handle_events() {
|
||||
while(SDL_PollEvent(&g_context.event)) {
|
||||
switch(g_context.event.type) {
|
||||
case SDL_QUIT:
|
||||
g_context.running = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int engine_run() {
|
||||
SDL_Window* window = SDL_CreateWindow("Tabletop", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 420, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
g_context = (context_t){
|
||||
.window = window,
|
||||
.renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED),
|
||||
.running = 1,
|
||||
};
|
||||
load_game();
|
||||
start_game();
|
||||
while(g_context.running) {
|
||||
handle_events();
|
||||
update_game();
|
||||
draw_game();
|
||||
_render_mode = 1;
|
||||
draw_game_ui();
|
||||
_render_mode = 0;
|
||||
swap_buffer();
|
||||
}
|
||||
engine_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
engine_start();
|
||||
engine_run();
|
||||
engine_shutdown();
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _engine_h
|
||||
#define _engine_h
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "context.h"
|
||||
|
||||
/* TO BE DEFINED IN GAME */
|
||||
extern void load_game();
|
||||
extern void start_game();
|
||||
extern void update_game();
|
||||
extern void draw_game();
|
||||
extern void draw_game_ui();
|
||||
|
||||
#endif /* _engine_h */
|
|
@ -0,0 +1,130 @@
|
|||
#include "engine.hpp"
|
||||
#include "input.h"
|
||||
#include "render.h"
|
||||
#include "assets.h"
|
||||
#include "tilemap.hpp"
|
||||
#include "SDL2/SDL_mouse.h"
|
||||
#include <SDL2/SDL_scancode.h>
|
||||
|
||||
void on_cycle_tile(int);
|
||||
|
||||
int cursor_tile = 1;
|
||||
int dragging = 0;
|
||||
int drawing = 0;
|
||||
sprite_t player;
|
||||
sprite_t current_tile_display;
|
||||
spritesheet_t world_sheet;
|
||||
|
||||
void on_save_key(int down) {
|
||||
if(down)
|
||||
save_tilemap("tilemap.csv");
|
||||
}
|
||||
|
||||
void on_load_key(int down) {
|
||||
if(down)
|
||||
load_tilemap("tilemap.csv");
|
||||
}
|
||||
|
||||
void on_clear_key(int down) {
|
||||
if(down) {
|
||||
for(int i = 0; i < g_tilemap.height * g_tilemap.width; ++i) {
|
||||
g_tilemap.tiles[i].value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_cycle_tile(int axis) {
|
||||
cursor_tile += axis;
|
||||
player.uv = get_srcrect_from(&world_sheet, cursor_tile);
|
||||
}
|
||||
|
||||
void on_quit_key(int down) {
|
||||
if(down) {
|
||||
g_context.running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void on_click(int down) {
|
||||
drawing = down;
|
||||
}
|
||||
|
||||
void on_drag_world(float dx, float dy) {
|
||||
if(dragging) {
|
||||
g_active_view.x -= dx * g_active_view.width;
|
||||
g_active_view.y -= dy * g_active_view.width;
|
||||
}
|
||||
}
|
||||
|
||||
void on_middle_mouse(int down) {
|
||||
dragging = down;
|
||||
}
|
||||
|
||||
void load_game() {
|
||||
g_tilemap.width = g_tilemap.height = 10;
|
||||
|
||||
player = make_sprite("tilemap.png", 0, 0);
|
||||
player.depth = -10;
|
||||
|
||||
current_tile_display = make_sprite("tilemap.png", 0, 0);
|
||||
current_tile_display.sx = 0.3f;
|
||||
current_tile_display.sy = 0.3f;
|
||||
|
||||
world_sheet = make_spritesheet("tilemap.png", 16, 16);
|
||||
|
||||
g_tilemap.tileset.set = {
|
||||
sprite_from_spritesheet(&world_sheet, 1),
|
||||
sprite_from_spritesheet(&world_sheet, 2),
|
||||
sprite_from_spritesheet(&world_sheet, 3),
|
||||
sprite_from_spritesheet(&world_sheet, 4),
|
||||
};
|
||||
|
||||
for(int i=0;i<g_tilemap.width*g_tilemap.height;++i) {
|
||||
g_tilemap.tiles[i].value = i%3;
|
||||
}
|
||||
on_cycle_tile(0);
|
||||
}
|
||||
|
||||
void start_game() {
|
||||
input_init();
|
||||
add_listener_for(SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_W, &on_save_key);
|
||||
add_listener_for(SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_R, &on_load_key);
|
||||
add_listener_for(SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_C, &on_clear_key);
|
||||
add_listener_for(SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_Q, &on_quit_key);
|
||||
add_listener_for(SDL_SCANCODE_A, SDL_SCANCODE_D, &on_cycle_tile);
|
||||
add_mouse_button_listener(SDL_BUTTON_LMASK, &on_click);
|
||||
add_mouse_button_listener(SDL_BUTTON_MMASK, &on_middle_mouse);
|
||||
add_mouse_listener(0, &on_drag_world);
|
||||
g_active_view.width = 21;
|
||||
}
|
||||
|
||||
void update_game() {
|
||||
update_input();
|
||||
mouse_world_position(&player.x, &player.y);
|
||||
|
||||
if(drawing) {
|
||||
int x, y;
|
||||
float fx, fy;
|
||||
mouse_world_position(&fx, &fy);
|
||||
x = floorf(fx);
|
||||
y = floorf(fy);
|
||||
get_tilemap_tile(x, y)->value = cursor_tile;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_game() {
|
||||
rectshape_t world_outline = {
|
||||
g_tilemap.x, g_tilemap.y, float(g_tilemap.width), float(g_tilemap.height),
|
||||
0.1f, 0, {0,0,0,0}, {255, 255, 255, 255}
|
||||
};
|
||||
draw_rect(&world_outline);
|
||||
draw_sprite(&player);
|
||||
draw_tilemap();
|
||||
}
|
||||
|
||||
void draw_game_ui() {
|
||||
rectshape_t shape = (rectshape_t){
|
||||
0.0, 0.0, 0.2, 0.2, 0, 0, {255,255,255,255}, {0,0,0,0}
|
||||
};
|
||||
draw_rect(&shape);
|
||||
draw_sprite(¤t_tile_display);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stddef.h"
|
||||
#include "hash.h"
|
||||
#include "string.h"
|
||||
|
||||
uintptr_t hashstr(const char* str) {
|
||||
return hashmem(str, strlen(str));
|
||||
}
|
||||
|
||||
uintptr_t hashmem(const char* mem, size_t size) {
|
||||
const size_t last4shift = sizeof(uintptr_t)*4 - 4;
|
||||
uintptr_t hash = 0;
|
||||
while(size --> 0) {
|
||||
hash = (hash | *mem) << 1;
|
||||
hash |= hash >> last4shift;
|
||||
++mem;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _hash_h
|
||||
#define _hash_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stddef.h"
|
||||
|
||||
uintptr_t hashstr(const char* str);
|
||||
|
||||
uintptr_t hashmem(const char* mem, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _hash_h */
|
|
@ -0,0 +1,135 @@
|
|||
#include "input.h"
|
||||
#include "render.h"
|
||||
#include "math.h"
|
||||
#include "SDL2/SDL_mouse.h"
|
||||
#include "SDL2/SDL_keyboard.h"
|
||||
#include "SDL2/SDL_render.h"
|
||||
|
||||
|
||||
const Uint8* g_key_states = NULL;
|
||||
input_listener_t g_key_listeners[24];
|
||||
input_listener_t* g_key_listeners_endptr = g_key_listeners;
|
||||
|
||||
int _last_mouse_x=0, _last_mouse_y=0;
|
||||
float _last_screen_mouse_x=0.0, _last_screen_mouse_y=0.0;
|
||||
uint32_t _mouse_left_seconds = 0;
|
||||
|
||||
size_t add_listener_for(SDL_Scancode negative, SDL_Scancode positive,
|
||||
input_axis_delegate_t delegate) {
|
||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||
g_key_listeners_endptr->type = INPUT_LISTENER_AXIS;
|
||||
g_key_listeners_endptr->axis.delegate = delegate;
|
||||
g_key_listeners_endptr->axis.positive = positive;
|
||||
g_key_listeners_endptr->axis.negative = negative;
|
||||
g_key_listeners_endptr->axis.last = 0;
|
||||
|
||||
++g_key_listeners_endptr;
|
||||
return (size_t)(g_key_listeners_endptr - g_key_listeners)-1;
|
||||
}
|
||||
|
||||
size_t add_mouse_listener(float min_move, input_mouse_delegate_t delegate) {
|
||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||
g_key_listeners_endptr->type = INPUT_LISTENER_MOUSE;
|
||||
g_key_listeners_endptr->mouse.delegate = delegate;
|
||||
g_key_listeners_endptr->mouse.min_delta = min_move;
|
||||
|
||||
++g_key_listeners_endptr;
|
||||
return (size_t)(g_key_listeners_endptr - g_key_listeners)-1;
|
||||
}
|
||||
|
||||
size_t add_mouse_button_listener(uint32_t button, input_button_delegate_t delegate) {
|
||||
memset(g_key_listeners_endptr, 0x0, sizeof(input_listener_t));
|
||||
g_key_listeners_endptr->type = INPUT_LISTENER_BUTTON;
|
||||
g_key_listeners_endptr->button.delegate = delegate;
|
||||
g_key_listeners_endptr->button.button = button;
|
||||
g_key_listeners_endptr->button.last = 0;
|
||||
|
||||
++g_key_listeners_endptr;
|
||||
return (size_t)(g_key_listeners_endptr - g_key_listeners)-1;
|
||||
}
|
||||
|
||||
void remove_listener_at(size_t index) {
|
||||
input_listener_t* listener = g_key_listeners + index;
|
||||
--g_key_listeners_endptr;
|
||||
*listener = *g_key_listeners_endptr;
|
||||
}
|
||||
|
||||
void mouse_screen_position(float *ox, float *oy) {
|
||||
*ox = _last_screen_mouse_x;
|
||||
*oy = _last_screen_mouse_y;
|
||||
}
|
||||
|
||||
void mouse_world_position(float *ox, float *oy) {
|
||||
mouse_screen_position(ox, oy);
|
||||
screen_to_view(ox, oy);
|
||||
}
|
||||
|
||||
void input_init() {
|
||||
g_key_states = SDL_GetKeyboardState(NULL);
|
||||
}
|
||||
|
||||
void process_axis_listener(input_listener_t* listener) {
|
||||
int val = 0;
|
||||
if(g_key_states[listener->axis.negative]) {
|
||||
val = -1;
|
||||
}
|
||||
if(g_key_states[listener->axis.positive]) {
|
||||
val += 1;
|
||||
}
|
||||
if(val != listener->axis.last) {
|
||||
listener->axis.last = val;
|
||||
listener->axis.delegate(val);
|
||||
}
|
||||
}
|
||||
|
||||
void process_mouse_listener(input_listener_t* listener, float dx, float dy) {
|
||||
float mind = listener->mouse.min_delta;
|
||||
if(dx*dx + dy*dy > mind*mind) {
|
||||
listener->mouse.delegate(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
void process_button_listener(input_listener_t* listener) {
|
||||
uint32_t state = SDL_GetMouseState(NULL, NULL);
|
||||
int is_down = (state & (listener->button.button)) != 0;
|
||||
if(is_down != listener->button.last) {
|
||||
listener->button.delegate(is_down);
|
||||
}
|
||||
listener->button.last = is_down;
|
||||
}
|
||||
|
||||
void update_input() {
|
||||
float dx, dy;
|
||||
int px, py;
|
||||
SDL_GetMouseState(&px, &py);
|
||||
int width, height;
|
||||
SDL_GetRendererOutputSize(g_context.renderer, &width, &height);
|
||||
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) {
|
||||
switch(listener->type) {
|
||||
case INPUT_LISTENER_AXIS:
|
||||
process_axis_listener(listener);
|
||||
break;
|
||||
case INPUT_LISTENER_MOUSE:
|
||||
process_mouse_listener(listener, dx, dy);
|
||||
break;
|
||||
case INPUT_LISTENER_BUTTON:
|
||||
process_button_listener(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_last_mouse_x = px; _last_mouse_y = py;
|
||||
_last_screen_mouse_x = (float)px / width;
|
||||
_last_screen_mouse_y = (float)py / width;
|
||||
}
|
||||
|
||||
int input_keydown(SDL_Scancode scancode) {
|
||||
return g_key_states[scancode];
|
||||
}
|
||||
|
||||
int input_mousedown(int mousebtn) {
|
||||
uint32_t mask = SDL_BUTTON(mousebtn);
|
||||
return (SDL_GetMouseState(NULL, NULL) & mask) != 0;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef _input_h
|
||||
#define _input_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
typedef void(*input_axis_delegate_t)(int value);
|
||||
typedef void(*input_mouse_delegate_t)(float dx, float dy);
|
||||
typedef void(*input_button_delegate_t)(int down);
|
||||
|
||||
enum INPUT_LISTENER_TYPE_T {
|
||||
INPUT_LISTENER_MOUSE,
|
||||
INPUT_LISTENER_AXIS,
|
||||
INPUT_LISTENER_BUTTON,
|
||||
};
|
||||
|
||||
typedef struct input_listener_t {
|
||||
enum INPUT_LISTENER_TYPE_T type;
|
||||
union {
|
||||
struct {
|
||||
input_axis_delegate_t delegate;
|
||||
SDL_Scancode positive, negative;
|
||||
int last;
|
||||
} axis;
|
||||
struct {
|
||||
input_mouse_delegate_t delegate;
|
||||
float min_delta;
|
||||
} mouse;
|
||||
struct {
|
||||
input_button_delegate_t delegate;
|
||||
uint32_t button;
|
||||
int last;
|
||||
} button;
|
||||
};
|
||||
} input_listener_t;
|
||||
|
||||
extern const Uint8* g_key_states;
|
||||
|
||||
extern size_t add_listener_for(SDL_Scancode negative, SDL_Scancode positive,
|
||||
input_axis_delegate_t delegate);
|
||||
extern size_t add_mouse_listener(float min_move, input_mouse_delegate_t delegate);
|
||||
extern size_t add_mouse_button_listener(uint32_t button, input_button_delegate_t delegate);
|
||||
extern void remove_listener_at(size_t index);
|
||||
extern void mouse_screen_position(float* ox, float* oy);
|
||||
extern void mouse_world_position(float* ox, float* oy);
|
||||
|
||||
extern void input_init();
|
||||
extern void update_input();
|
||||
extern int input_keydown(SDL_Scancode scancode);
|
||||
extern int input_mousedown(int mousebtn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _input_h */
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _layers_h
|
||||
#define _layers_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RLAYER_TILEMAP 10
|
||||
#define RLAYER_SPRITES 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _layers_h */
|
|
@ -0,0 +1,241 @@
|
|||
#include "render.h"
|
||||
#include "assets.h"
|
||||
#include "assert.h"
|
||||
#include "layers.h"
|
||||
#include "signal.h"
|
||||
#include "inttypes.h"
|
||||
#include "SDL2/SDL_blendmode.h"
|
||||
#include "SDL2/SDL_render.h"
|
||||
|
||||
#define NUM_DRAWCMDS 256
|
||||
|
||||
drawcmd_t g_drawdata[NUM_DRAWCMDS];
|
||||
drawcmd_t* g_drawdata_endptr = g_drawdata;
|
||||
int _render_mode = 0;
|
||||
|
||||
#define DEFAULT_VIEW (view_t){.x=0.0,.y=0.0,.width=1.0}
|
||||
|
||||
float _aspect_ratio;
|
||||
float _render_width=0, _render_height=0;
|
||||
|
||||
view_t g_active_view = DEFAULT_VIEW;
|
||||
|
||||
void screen_to_view(float *x, float *y) {
|
||||
float xx = *x, yy = *y;
|
||||
|
||||
xx *= g_active_view.width;
|
||||
yy *= g_active_view.width;
|
||||
|
||||
xx += g_active_view.x - g_active_view.width * 0.5f;
|
||||
yy += g_active_view.y - g_active_view.width * _aspect_ratio * 0.5f;
|
||||
|
||||
*x = xx;
|
||||
*y = yy;
|
||||
}
|
||||
|
||||
void clear_buffer() {
|
||||
SDL_SetRenderDrawBlendMode(g_context.renderer, SDL_BLENDMODE_ADD);
|
||||
SDL_SetRenderDrawColor(g_context.renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(g_context.renderer);
|
||||
}
|
||||
|
||||
void get_scaling_factors(float* width, float* height,
|
||||
float* width_mul, float* height_mul, short ui) {
|
||||
float aspectr;
|
||||
(*width)=_render_width; (*height)=_render_height;
|
||||
aspectr = _aspect_ratio;
|
||||
if(ui == 0) {
|
||||
(*width_mul) = (*width)/g_active_view.width;
|
||||
(*height_mul) = (*height)/(g_active_view.width*aspectr);
|
||||
} else {
|
||||
(*height_mul) = (*width_mul) = (*width);
|
||||
}
|
||||
(*width) = g_active_view.width;
|
||||
(*height) = (*width)*aspectr;
|
||||
}
|
||||
|
||||
void exec_sprite_cmd(const drawcmd_t* cmd) {
|
||||
const sprite_t* sprite = &cmd->sprite;
|
||||
float fw, fh, fwm, fhm;
|
||||
get_scaling_factors(&fw, &fh, &fwm, &fhm, cmd->ui);
|
||||
SDL_FRect destrect = (SDL_FRect){
|
||||
.x=((-g_active_view.x)+(fw*0.5f)+sprite->x)*fwm,
|
||||
.y=((-g_active_view.y)+(fh*0.5f)+sprite->y)*fwm,
|
||||
.w=sprite->sx*fwm,
|
||||
.h=sprite->sy*fwm
|
||||
};
|
||||
if(cmd->ui) {
|
||||
destrect.x = cmd->sprite.x * fwm;
|
||||
destrect.y = cmd->sprite.y * fhm;
|
||||
}
|
||||
SDL_RenderCopyExF(g_context.renderer, sprite->texture,
|
||||
&sprite->uv, &destrect, sprite->rot,
|
||||
&sprite->origin,SDL_FLIP_NONE);
|
||||
}
|
||||
|
||||
void exec_rect_cmd(const drawcmd_t* cmd) {
|
||||
float w, h, wm, hm;
|
||||
get_scaling_factors(&w, &h, &wm, &hm, cmd->ui);
|
||||
SDL_FRect rect = (SDL_FRect) {
|
||||
.x=((-g_active_view.x)+(w*0.5f)+cmd->rect.x)*wm,
|
||||
.y=((-g_active_view.y)+(h*0.5f)+cmd->rect.y)*hm,
|
||||
.w=cmd->rect.w*wm, .h=cmd->rect.h*hm
|
||||
};
|
||||
if(cmd->ui) {
|
||||
rect.x = cmd->rect.x * wm;
|
||||
rect.y = cmd->rect.y * hm;
|
||||
}
|
||||
SDL_Color c = cmd->rect.background;
|
||||
//SDL_SetRenderDrawBlendMode(g_context.renderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(g_context.renderer, c.r, c.g, c.b, c.a);
|
||||
SDL_RenderFillRectF(g_context.renderer, &rect);
|
||||
c = cmd->rect.line;
|
||||
SDL_SetRenderDrawColor(g_context.renderer, c.r, c.g, c.b, c.a);
|
||||
|
||||
SDL_FRect r = {
|
||||
rect.x, rect.y,
|
||||
cmd->rect.line_width*wm, rect.h
|
||||
};
|
||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||
r = (SDL_FRect){
|
||||
rect.x, rect.y,
|
||||
rect.w, cmd->rect.line_width*hm
|
||||
};
|
||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||
r = (SDL_FRect){
|
||||
rect.x, rect.y+rect.h-cmd->rect.line_width*hm,
|
||||
rect.w, cmd->rect.line_width*hm
|
||||
};
|
||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||
r = (SDL_FRect){
|
||||
rect.x+rect.w-cmd->rect.line_width*wm, rect.y,
|
||||
cmd->rect.line_width*wm, rect.h
|
||||
};
|
||||
SDL_RenderFillRectF(g_context.renderer, &r);
|
||||
}
|
||||
|
||||
typedef void(*drawcmd_delegate)(const drawcmd_t*);
|
||||
drawcmd_delegate const drawcmd_funcs[] = {
|
||||
&exec_sprite_cmd,
|
||||
&exec_rect_cmd
|
||||
};
|
||||
void exec_buffer() {
|
||||
for(const drawcmd_t* cmd = g_drawdata; cmd != g_drawdata_endptr; ++cmd) {
|
||||
if(cmd->type > DRAWCMDTYPE_MIN && cmd->type < DRAWCMDTYPE_MAX) {
|
||||
drawcmd_funcs[cmd->type](cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swap_buffer() {
|
||||
clear_buffer();
|
||||
int iw, ih;
|
||||
SDL_GetRendererOutputSize(g_context.renderer, &iw, &ih);
|
||||
_render_width = (float)iw; _render_height = (float)ih;
|
||||
_aspect_ratio = _render_height/_render_width;
|
||||
exec_buffer();
|
||||
SDL_RenderPresent(g_context.renderer);
|
||||
g_drawdata_endptr = g_drawdata;
|
||||
}
|
||||
|
||||
void insert_drawcmd_at(size_t index, const drawcmd_t* cmd) {
|
||||
drawcmd_t* insertpoint = g_drawdata + index;
|
||||
drawcmd_t* dest = insertpoint + 1;
|
||||
size_t size = (size_t)(g_drawdata_endptr - g_drawdata);
|
||||
size_t count = (size - index);
|
||||
++g_drawdata_endptr;
|
||||
if(size > 0)
|
||||
{
|
||||
memmove(dest, insertpoint, count*sizeof(drawcmd_t));
|
||||
}
|
||||
memcpy(insertpoint, cmd, sizeof(drawcmd_t));
|
||||
insertpoint->ui = _render_mode == 1;
|
||||
}
|
||||
|
||||
void draw(const drawcmd_t* cmd) {
|
||||
long top = (size_t)(g_drawdata_endptr - g_drawdata),
|
||||
bot = 0,
|
||||
med = 0;
|
||||
|
||||
int ui = _render_mode == 1;
|
||||
if(top != bot) {
|
||||
while(bot <= top) {
|
||||
med = floor((float)(top + bot) / 2);
|
||||
if(g_drawdata[med].ui > ui || g_drawdata[med].depth > cmd->depth) {
|
||||
bot = med+1;
|
||||
} else if(g_drawdata[med].ui <= ui || g_drawdata[med].depth < cmd->depth) {
|
||||
top = med-1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
insert_drawcmd_at(med, cmd);
|
||||
}
|
||||
|
||||
void draw_sprite(const sprite_t* sprite) {
|
||||
drawcmd_t d = {
|
||||
.type=DRAWCMDTYPE_SPRITE,
|
||||
.depth=sprite->depth,
|
||||
.sprite=*sprite
|
||||
};
|
||||
draw(&d);
|
||||
}
|
||||
|
||||
void draw_rect(const rectshape_t* rect) {
|
||||
drawcmd_t d = {
|
||||
.type=DRAWCMDTYPE_RECT,
|
||||
.depth=rect->depth,
|
||||
.rect=*rect
|
||||
};
|
||||
draw(&d);
|
||||
}
|
||||
|
||||
spritesheet_t make_spritesheet(const char *file, int tile_width, int tile_height) {
|
||||
spritesheet_t sheet=(spritesheet_t){
|
||||
.texture=get_texture(file),
|
||||
.w=0,.h=0,
|
||||
.tile_width=tile_width,
|
||||
.tile_height=tile_height,
|
||||
};
|
||||
SDL_QueryTexture(sheet.texture, NULL, NULL, &sheet.w, &sheet.h);
|
||||
return sheet;
|
||||
}
|
||||
|
||||
sprite_t make_sprite(const char* file, float x, float y) {
|
||||
sprite_t sprite=(sprite_t){
|
||||
.texture=get_texture(file),
|
||||
.x=x,.y=y,
|
||||
.origin=(SDL_FPoint){.x=0,.y=0},
|
||||
.sx=1.0,.sy=1.0,
|
||||
.rot=0,
|
||||
.depth=RLAYER_SPRITES,
|
||||
.uv=(SDL_Rect){
|
||||
.x=0,.y=0,.w=0,.h=0
|
||||
}
|
||||
};
|
||||
SDL_QueryTexture(sprite.texture, NULL, NULL, &sprite.uv.w, &sprite.uv.h);
|
||||
sprite.origin.x = -(float)sprite.uv.h/2.f; sprite.origin.y = -(float)sprite.uv.h/2.f;
|
||||
return sprite;
|
||||
}
|
||||
|
||||
sprite_t sprite_from_spritesheet(spritesheet_t *sheet, int index) {
|
||||
SDL_Rect rect = get_srcrect_from(sheet, index);
|
||||
return (sprite_t) {
|
||||
.texture=sheet->texture,
|
||||
.x=0, .y=0,
|
||||
.origin=(SDL_FPoint){0,0},
|
||||
.sx=1.0, .sy=1.0,
|
||||
.rot=0,
|
||||
.depth=RLAYER_SPRITES,
|
||||
.uv=rect,
|
||||
};
|
||||
}
|
||||
|
||||
SDL_Rect get_srcrect_from(spritesheet_t *sheet, int index) {
|
||||
int pixels = index * sheet->tile_width;
|
||||
return (SDL_Rect) {
|
||||
pixels%sheet->w, pixels/sheet->w*sheet->tile_height,
|
||||
sheet->tile_width, sheet->tile_height,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef _render_h
|
||||
#define _render_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "context.h"
|
||||
|
||||
typedef int depth_t;
|
||||
|
||||
typedef enum drawcmdtype_t {
|
||||
DRAWCMDTYPE_MIN = -1,
|
||||
DRAWCMDTYPE_SPRITE = 0,
|
||||
DRAWCMDTYPE_RECT = 1,
|
||||
DRAWCMDTYPE_MAX
|
||||
} drawcmdtype_t;
|
||||
|
||||
typedef struct spritesheet_t {
|
||||
SDL_Texture* texture;
|
||||
int w, h;
|
||||
int tile_width, tile_height;
|
||||
} spritesheet_t;
|
||||
|
||||
typedef struct sprite_t {
|
||||
SDL_Texture* texture;
|
||||
float x, y;
|
||||
SDL_FPoint origin;
|
||||
float sx, sy;
|
||||
float rot;
|
||||
depth_t depth;
|
||||
SDL_Rect uv;
|
||||
} sprite_t;
|
||||
|
||||
typedef struct rectshape_t {
|
||||
float x, y, w, h;
|
||||
float line_width;
|
||||
int depth;
|
||||
SDL_Color background;
|
||||
SDL_Color line;
|
||||
} rectshape_t;
|
||||
|
||||
typedef struct drawcmd_t {
|
||||
drawcmdtype_t type;
|
||||
depth_t depth;
|
||||
short ui;
|
||||
union {
|
||||
sprite_t sprite;
|
||||
rectshape_t rect;
|
||||
};
|
||||
} drawcmd_t;
|
||||
|
||||
typedef struct view_t {
|
||||
float x, y;
|
||||
float width;
|
||||
} view_t;
|
||||
|
||||
extern int _render_mode;
|
||||
extern view_t g_active_view;
|
||||
|
||||
extern void screen_to_view(float* x, float* y);
|
||||
|
||||
extern void clear_buffer();
|
||||
extern void swap_buffer();
|
||||
extern void draw(const drawcmd_t* cmd);
|
||||
|
||||
extern void draw_sprite(const sprite_t* sprite);
|
||||
extern void draw_rect(const rectshape_t* rect);
|
||||
extern spritesheet_t make_spritesheet(const char* file, int tile_width, int tile_height);
|
||||
extern sprite_t make_sprite(const char* file, float x, float y);
|
||||
extern sprite_t sprite_from_spritesheet(spritesheet_t* sheet, int index);
|
||||
extern SDL_Rect get_srcrect_from(spritesheet_t* sheet, int index);
|
||||
extern void set_active_view(const view_t* view);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _render_h */
|
|
@ -0,0 +1,85 @@
|
|||
#include "tilemap.hpp"
|
||||
#include "layers.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "signal.h"
|
||||
|
||||
tilemap_t g_tilemap = {
|
||||
.width = 0,.height = 0,
|
||||
.x=0,.y=0
|
||||
};
|
||||
|
||||
void draw_tilemap() {
|
||||
sprite_t sprite;
|
||||
for(int y=0;y<g_tilemap.height;++y) {
|
||||
for(int x=0;x<g_tilemap.width;++x) {
|
||||
auto tile = get_tilemap_tile(x, y);
|
||||
if(tile->value == 0) continue;
|
||||
sprite = g_tilemap.tileset.set[tile->value-1];
|
||||
sprite.depth = RLAYER_TILEMAP;
|
||||
sprite.x = x; sprite.y = y;
|
||||
draw_sprite(&sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int save_tilemap(const char* file) {
|
||||
FILE* fs = fopen(file, "w");
|
||||
if(fs == NULL) {
|
||||
fprintf(stderr, "ERROR: Failed to open file %s\n", file);
|
||||
return 1;
|
||||
}
|
||||
fprintf(fs, "%d,%d,", g_tilemap.width, g_tilemap.height);
|
||||
for(int i = 0; i < g_tilemap.width * g_tilemap.height; ++i)
|
||||
fprintf(fs,"%d,", g_tilemap.tiles[i].value);
|
||||
fclose(fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_tilemap(const char* file) {
|
||||
FILE* fs = fopen(file, "r");
|
||||
if(fs == NULL) {
|
||||
fprintf(stderr, "ERROR: Failed to open file %s\n", file);
|
||||
return 1;
|
||||
}
|
||||
char buf[99];
|
||||
char* writer = buf;
|
||||
int n = 0;
|
||||
tile_t* tile = g_tilemap.tiles;
|
||||
int entries=0;
|
||||
while(1) {
|
||||
n = fgetc(fs);
|
||||
const char c = (char)n;
|
||||
switch(n) {
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\t':
|
||||
// ignore
|
||||
break;
|
||||
case EOF:
|
||||
case ',':
|
||||
*writer = '\0';
|
||||
if(entries == 0) {
|
||||
g_tilemap.width = atoi(buf);
|
||||
} else if(entries == 1) {
|
||||
g_tilemap.height = atoi(buf);
|
||||
} else {
|
||||
tile->value = (short)atoi(buf);
|
||||
++tile;
|
||||
}
|
||||
writer = buf;
|
||||
++entries;
|
||||
if(n == EOF)
|
||||
goto end_while;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
*writer = c;
|
||||
++writer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_while:
|
||||
fclose(fs);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _tilemap_h
|
||||
#define _tilemap_h
|
||||
|
||||
#include "render.h"
|
||||
#include "vector"
|
||||
|
||||
#define TILEMAP_MAX_SIZE 128*128
|
||||
|
||||
typedef struct tile_t {
|
||||
short value;
|
||||
} tile_t;
|
||||
|
||||
typedef struct tileset_t {
|
||||
std::vector<sprite_t> set;
|
||||
} tileset_t;
|
||||
|
||||
typedef struct tilemap_t {
|
||||
tile_t tiles[TILEMAP_MAX_SIZE];
|
||||
tileset_t tileset;
|
||||
int width, height;
|
||||
float x, y;
|
||||
} tilemap_t;
|
||||
|
||||
extern tilemap_t g_tilemap;
|
||||
|
||||
static inline int get_tilemap_index(int x, int y) {
|
||||
return x + y * g_tilemap.width;
|
||||
}
|
||||
static inline tile_t* get_tilemap_tile(int x, int y) {
|
||||
return g_tilemap.tiles + get_tilemap_index(x, y);
|
||||
}
|
||||
|
||||
extern void draw_tilemap();
|
||||
/*load csv tilemap from file*/
|
||||
extern int load_tilemap(const char* file);
|
||||
/*write csv tilemap to file*/
|
||||
extern int save_tilemap(const char* file);
|
||||
|
||||
#endif /* _tilemap_h */
|
Loading…
Reference in New Issue