added source code
This commit is contained in:
parent
267d73167b
commit
c1207d8b8a
11
src/fencer.c
Normal file
11
src/fencer.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "program.h"
|
||||||
|
#include "tilemap.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
struct ProgramSettings config = {
|
||||||
|
.target_fps = 0, // unbounded speed
|
||||||
|
.title = "fencer",
|
||||||
|
.view_resolution = {160, 140}
|
||||||
|
};
|
||||||
|
return program_run(&config);
|
||||||
|
}
|
60
src/program.c
Normal file
60
src/program.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include "program.h"
|
||||||
|
#include <SDL2/SDL_video.h>
|
||||||
|
|
||||||
|
struct Program g_program;
|
||||||
|
|
||||||
|
#define INITFLAGS SDL_INIT_EVENTS | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER
|
||||||
|
|
||||||
|
int program_run(const struct ProgramSettings* settings) {
|
||||||
|
SDL_Init(INITFLAGS);
|
||||||
|
|
||||||
|
g_program.window = SDL_CreateWindow(
|
||||||
|
settings->title,
|
||||||
|
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
|
||||||
|
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
|
||||||
|
settings->view_resolution.x,
|
||||||
|
settings->view_resolution.y,
|
||||||
|
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
|
g_program.render_context = render_init(&g_program, settings);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
SDL_Delay(1);
|
||||||
|
program_handle_events(&g_program);
|
||||||
|
render_present(g_program.render_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_quit(struct Program* self) {
|
||||||
|
render_destroy(self->render_context);
|
||||||
|
SDL_DestroyWindow(self->window);
|
||||||
|
SDL_Quit();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_handle_events(struct Program* self) {
|
||||||
|
SDL_Event event;
|
||||||
|
while(SDL_PollEvent(&event)) {
|
||||||
|
switch(event.type) {
|
||||||
|
default: break;
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
if(event.window.windowID == SDL_GetWindowID(self->window)) {
|
||||||
|
program_handle_windowevent(self, &event.window);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_QUIT:
|
||||||
|
program_quit(self);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_handle_windowevent(struct Program* self, SDL_WindowEvent* event) {
|
||||||
|
switch(event->type) {
|
||||||
|
default:
|
||||||
|
render_handle_resize(self->render_context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
29
src/program.h
Normal file
29
src/program.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef _fencer_program_h
|
||||||
|
#define _fencer_program_h
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
#include "vmath.h"
|
||||||
|
#include "render.h"
|
||||||
|
|
||||||
|
extern struct Program g_program;
|
||||||
|
|
||||||
|
struct ProgramSettings {
|
||||||
|
const char* title;
|
||||||
|
IVector view_resolution;
|
||||||
|
int target_fps;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Program {
|
||||||
|
SDL_Window* window;
|
||||||
|
struct RenderContext* render_context;
|
||||||
|
double delta_time;
|
||||||
|
double start_frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int program_run(const struct ProgramSettings* settings);
|
||||||
|
extern void program_quit(struct Program* self);
|
||||||
|
extern void program_handle_events(struct Program* self);
|
||||||
|
extern void program_handle_windowevent(struct Program* self, SDL_WindowEvent* event);
|
||||||
|
|
||||||
|
#endif // !_fencer_program_h
|
85
src/render.c
Normal file
85
src/render.c
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#include "render.h"
|
||||||
|
#include "program.h"
|
||||||
|
#include <SDL2/SDL_pixels.h>
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
|
||||||
|
struct RenderContext* render_init(const struct Program* program, const struct ProgramSettings* settings) {
|
||||||
|
struct RenderContext* self = malloc(sizeof(struct RenderContext));
|
||||||
|
|
||||||
|
// create renderer, needs to be able to target textures, preferably hardware accelerated
|
||||||
|
self->renderer = SDL_CreateRenderer(program->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
|
||||||
|
// create render target texture
|
||||||
|
self->render_target = SDL_CreateTexture(
|
||||||
|
self->renderer,
|
||||||
|
SDL_PIXELFORMAT_ARGB32,
|
||||||
|
SDL_TEXTUREACCESS_TARGET,
|
||||||
|
settings->view_resolution.x, settings->view_resolution.y);
|
||||||
|
|
||||||
|
// store the desired view resolution
|
||||||
|
self->render_resolution = settings->view_resolution;
|
||||||
|
|
||||||
|
// get the destination area for rendering the target onto the window
|
||||||
|
render_calculate_render_area(self);
|
||||||
|
|
||||||
|
// clear target black
|
||||||
|
SDL_SetRenderTarget(self->renderer, self->render_target);
|
||||||
|
SDL_SetRenderDrawColor(self->renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(self->renderer);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_destroy(struct RenderContext* self) {
|
||||||
|
// clear up allocated SDL objects
|
||||||
|
SDL_DestroyTexture(self->render_target);
|
||||||
|
SDL_DestroyRenderer(self->renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_present(struct RenderContext* self) {
|
||||||
|
// clear window white
|
||||||
|
SDL_SetRenderTarget(self->renderer, NULL);
|
||||||
|
SDL_SetRenderDrawColor(self->renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(self->renderer);
|
||||||
|
// copy render target
|
||||||
|
SDL_Rect source_rect = {0, 0, self->render_resolution.x, self->render_resolution.y};
|
||||||
|
SDL_RenderCopy(self->renderer, self->render_target, &source_rect, &self->render_area);
|
||||||
|
SDL_RenderPresent(self->renderer);
|
||||||
|
// clear render target
|
||||||
|
SDL_SetRenderTarget(self->renderer, self->render_target);
|
||||||
|
SDL_SetRenderDrawColor(self->renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(self->renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_calculate_render_area(struct RenderContext* self) {
|
||||||
|
// get aspect ratios of both the window and the rendertexture
|
||||||
|
IVector window_resolution = render_get_window_size(self);
|
||||||
|
float window_aspect = (float)window_resolution.x / (float)window_resolution.y;
|
||||||
|
float target_aspect = (float)self->render_resolution.x / (float)self->render_resolution.y;
|
||||||
|
|
||||||
|
// calculate the largest area that will fit the entire rendertexture into the window space
|
||||||
|
self->render_area = (SDL_Rect) {0, 0, window_resolution.x, window_resolution.y};
|
||||||
|
if(window_aspect <= target_aspect) {
|
||||||
|
self->render_area.h = window_resolution.x / target_aspect;
|
||||||
|
self->render_area.y = (window_resolution.y - self->render_area.h) / 2;
|
||||||
|
} else {
|
||||||
|
self->render_area.w = window_resolution.y * target_aspect;
|
||||||
|
self->render_area.x += (window_resolution.x - self->render_area.w) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IVector render_get_window_size(struct RenderContext* self) {
|
||||||
|
// select window as target (store target to reset)
|
||||||
|
SDL_Texture* target = SDL_GetRenderTarget(self->renderer);
|
||||||
|
SDL_SetRenderTarget(self->renderer, NULL);
|
||||||
|
// fetch output size (= window size) of renderer
|
||||||
|
int window_width, window_height;
|
||||||
|
SDL_GetRendererOutputSize(self->renderer, &window_width, &window_height);
|
||||||
|
// reset render target
|
||||||
|
SDL_SetRenderTarget(self->renderer, target);
|
||||||
|
// construct IVector from fetched output size
|
||||||
|
return (IVector){window_width, window_height};
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_handle_resize(struct RenderContext* self) {
|
||||||
|
render_calculate_render_area(self);
|
||||||
|
}
|
36
src/render.h
Normal file
36
src/render.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef _fencer_render_h
|
||||||
|
#define _fencer_render_h
|
||||||
|
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
#include <SDL2/SDL_rect.h>
|
||||||
|
#include "vmath.h"
|
||||||
|
|
||||||
|
struct Program;
|
||||||
|
struct ProgramSettings;
|
||||||
|
|
||||||
|
struct RenderContext {
|
||||||
|
// renderer created from window in Program passed to render_init
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
|
||||||
|
// render target
|
||||||
|
SDL_Texture* render_target;
|
||||||
|
// area of window to render render_target to
|
||||||
|
SDL_Rect render_area;
|
||||||
|
|
||||||
|
// size of render_target
|
||||||
|
IVector render_resolution;
|
||||||
|
|
||||||
|
// current world location of camera
|
||||||
|
IVector camera_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct RenderContext* render_init(const struct Program* program, const struct ProgramSettings* settings);
|
||||||
|
extern void render_destroy(struct RenderContext* self);
|
||||||
|
extern void render_present(struct RenderContext* self);
|
||||||
|
|
||||||
|
extern void render_calculate_render_area(struct RenderContext* self);
|
||||||
|
extern IVector render_get_window_size(struct RenderContext* self);
|
||||||
|
extern void render_handle_resize(struct RenderContext* self);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // !_fencer_render_h
|
141
src/tilemap.c
Normal file
141
src/tilemap.c
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
#include "tilemap.h"
|
||||||
|
#include "program.h"
|
||||||
|
#include <SDL2/SDL_image.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct Tilemap tilemap_load(const char* tilemap_file, const char* tileset_file) {
|
||||||
|
struct Tilemap self = {
|
||||||
|
.dimensions = {1,1},
|
||||||
|
.tiles = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
FILE* fs = fopen(tilemap_file, "r");
|
||||||
|
int n = 0;
|
||||||
|
do {
|
||||||
|
n = fgetc(fs);
|
||||||
|
if(n == ',') {
|
||||||
|
self.dimensions.x++;
|
||||||
|
}
|
||||||
|
} while(n != '\n');
|
||||||
|
do {
|
||||||
|
n = fgetc(fs);
|
||||||
|
if(n == '\n') {
|
||||||
|
self.dimensions.y++;
|
||||||
|
}
|
||||||
|
} while(n != '\0');
|
||||||
|
|
||||||
|
rewind(fs);
|
||||||
|
|
||||||
|
self.tiles = malloc(self.dimensions.x * self.dimensions.y * sizeof(int));
|
||||||
|
|
||||||
|
char csv_buffer[6];
|
||||||
|
csv_buffer[5] = '\0';
|
||||||
|
char* writer = csv_buffer;
|
||||||
|
int* tile = self.tiles;
|
||||||
|
|
||||||
|
do {
|
||||||
|
n = fgetc(fs);
|
||||||
|
if(isalnum(n)) {
|
||||||
|
*writer = n;
|
||||||
|
++writer;
|
||||||
|
} else if(n == ',' || n == '\0' || n == '\n') {
|
||||||
|
*writer = '\0';
|
||||||
|
writer = csv_buffer;
|
||||||
|
*tile = atoi(csv_buffer);
|
||||||
|
++tile;
|
||||||
|
}
|
||||||
|
} while(n != '\0');
|
||||||
|
|
||||||
|
fclose(fs);
|
||||||
|
|
||||||
|
self.tileset = tileset_load(tileset_file);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int is_path_char(int n) {
|
||||||
|
return isalnum(n) || n == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Tileset tileset_load(const char* filename) {
|
||||||
|
char* texture_path = NULL;
|
||||||
|
char* writer = NULL;
|
||||||
|
char num_buffer[6];
|
||||||
|
num_buffer[5] = '\0';
|
||||||
|
int n = 0;
|
||||||
|
struct Tileset self = {
|
||||||
|
.texture = NULL,
|
||||||
|
.tile_size = {0,0}
|
||||||
|
};
|
||||||
|
size_t len = 1;
|
||||||
|
|
||||||
|
FILE* fs = fopen(filename, "r");
|
||||||
|
|
||||||
|
do {
|
||||||
|
n = fgetc(fs);
|
||||||
|
if(is_path_char(n)) {
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
} while(n != ',');
|
||||||
|
|
||||||
|
texture_path = malloc(len * sizeof(char));
|
||||||
|
|
||||||
|
rewind(fs);
|
||||||
|
writer = texture_path;
|
||||||
|
|
||||||
|
do {
|
||||||
|
n = fgetc(fs);
|
||||||
|
if(is_path_char(n)) {
|
||||||
|
*writer = n;
|
||||||
|
++writer;
|
||||||
|
} else if(n == ',') {
|
||||||
|
*writer = '\0';
|
||||||
|
}
|
||||||
|
} while(n != ',');
|
||||||
|
|
||||||
|
self.texture = IMG_LoadTexture(g_program.render_context->renderer, texture_path);
|
||||||
|
SDL_QueryTexture(self.texture, NULL, NULL, &self.texture_resolution.x, &self.texture_resolution.y);
|
||||||
|
self.shear = floor((float)self.texture_resolution.x / self.tile_size.x);
|
||||||
|
|
||||||
|
writer = num_buffer;
|
||||||
|
|
||||||
|
do {
|
||||||
|
n = fgetc(fs);
|
||||||
|
if(isdigit(n) || n == '-') {
|
||||||
|
*writer= n;
|
||||||
|
++writer;
|
||||||
|
} else if(n == ',' || feof(fs) || n == '\n') {
|
||||||
|
*writer = '\0';
|
||||||
|
writer = num_buffer;
|
||||||
|
if(self.tile_size.x == 0) {
|
||||||
|
self.tile_size.x = atoi(num_buffer);
|
||||||
|
} else {
|
||||||
|
self.tile_size.y = atoi(num_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(!feof(fs));
|
||||||
|
|
||||||
|
fclose(fs);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect tileset_index_to_rect(struct Tileset* self, size_t index) {
|
||||||
|
SDL_Rect rect = {0,0, self->tile_size.x, self->tile_size.y};
|
||||||
|
rect.x = (index % self->shear) * rect.w;
|
||||||
|
rect.y = (index / self->shear) * rect.h;
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tilemap_render(struct Tilemap* self, struct RenderContext* render) {
|
||||||
|
size_t num_tiles = self->dimensions.x * self->dimensions.y;
|
||||||
|
SDL_Rect source_rect = {0, 0, self->tileset.tile_size.x, self->tileset.tile_size.y};
|
||||||
|
SDL_Rect dest_rect = source_rect;
|
||||||
|
for(int i = 0; i < num_tiles; ++i) {
|
||||||
|
source_rect = tileset_index_to_rect(&self->tileset, self->tiles[i]);
|
||||||
|
dest_rect.x = (i % self->dimensions.x) * dest_rect.w;
|
||||||
|
dest_rect.y = (i / self->dimensions.y) * dest_rect.h;
|
||||||
|
SDL_RenderCopy(render->renderer, self->tileset.texture, &source_rect, &dest_rect);
|
||||||
|
}
|
||||||
|
}
|
27
src/tilemap.h
Normal file
27
src/tilemap.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef _fencer_tilemap_h
|
||||||
|
#define _fencer_tilemap_h
|
||||||
|
|
||||||
|
#include "vmath.h"
|
||||||
|
#include "render.h"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
struct Tileset {
|
||||||
|
SDL_Texture* texture;
|
||||||
|
IVector tile_size;
|
||||||
|
IVector texture_resolution;
|
||||||
|
int shear;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Tilemap {
|
||||||
|
IVector dimensions;
|
||||||
|
int* tiles;
|
||||||
|
struct Tileset tileset;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct Tilemap tilemap_load(const char* tilemap_file, const char* tileset_file);
|
||||||
|
extern struct Tileset tileset_load(const char* filename);
|
||||||
|
extern SDL_Rect tileset_index_to_rect(struct Tileset* self, size_t index);
|
||||||
|
|
||||||
|
extern void tilemap_render(struct Tilemap* map, struct RenderContext* render);
|
||||||
|
|
||||||
|
#endif // !_fencer_tilemap_h
|
14
src/vmath.h
Normal file
14
src/vmath.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef _fencer_vmath_h
|
||||||
|
#define _fencer_vmath_h
|
||||||
|
|
||||||
|
typedef struct Vector {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} Vector;
|
||||||
|
|
||||||
|
typedef struct IVector {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} IVector;
|
||||||
|
|
||||||
|
#endif // !_fencer_vmath_h
|
Loading…
Reference in a new issue