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