added source

pull/1/head
Sara 2023-04-06 15:20:08 +02:00
parent 548c1bcd6a
commit 97d6dda15a
16 changed files with 1061 additions and 0 deletions

74
src/assets.c Normal file
View File

@ -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;
}

36
src/assets.h Normal file
View File

@ -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 */

29
src/context.c Normal file
View File

@ -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();
}

27
src/context.h Normal file
View File

@ -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

53
src/engine.cc Normal file
View File

@ -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();
}

14
src/engine.hpp Normal file
View File

@ -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 */

130
src/game.cc Normal file
View File

@ -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(&current_tile_display);
}

27
src/hash.c Normal file
View File

@ -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

19
src/hash.h Normal file
View File

@ -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 */

135
src/input.c Normal file
View File

@ -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;
}

59
src/input.h Normal file
View File

@ -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 */

15
src/layers.h Normal file
View File

@ -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 */

241
src/render.c Normal file
View File

@ -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,
};
}

78
src/render.h Normal file
View File

@ -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 */

85
src/tilemap.cc Normal file
View File

@ -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;
}

39
src/tilemap.hpp Normal file
View File

@ -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 */