1
0
Fork 0
2022-untitled-game/code/src/main.c

349 lines
9.6 KiB
C

#include "common.h"
typedef struct game {
time_t mod_time;
memory_t memory;
const char* lib_name;
void* lib_ptr;
void (*startup)(memory_t*);
void (*shutdown)(void);
void (*update)(memory_t*, float, input_t, bool*);
void (*render)(void);
void (*debug)(uint64_t, uint64_t, uint64_t);
void (*audio_callback)(void* userdata, uint8_t* stream, int len);
} game_t;
typedef struct keystate {
int w; int a; int s; int d;
int up; int left; int down; int right;
int e;
int enter; int space; int esc;
} keystate_t;
int main(int argc, char* argv[])
{
(void)argc; (void)argv;
{
int ret;
ret = SDL_InitSubSystem(SDL_INIT_VIDEO);
if (ret != 0) {
fprintf(stderr, "Error initializing SDL Video subsystem: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
if (ret != 0) {
fprintf(stderr, "Error initializing SDL Audio subsystem: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
}
SDL_Window* window = NULL;
SDL_GLContext* context = NULL;
{
window = SDL_CreateWindow(
WINDOW_TITLE,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT,
SDL_WINDOW_OPENGL);
if (window == NULL) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
context = SDL_GL_CreateContext(window);
if (context == NULL) {
fprintf(stderr, "Error creating SDL GL context: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_GL_SetSwapInterval(0);
gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress);
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_ShowCursor(SDL_DISABLE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
game_t game = {0};
{
const char* platform = SDL_GetPlatform();
if (strcmp(platform, "Windows") == 0) {
game.lib_name = ".\\libgame.dll";
} else {
game.lib_name = "./libgame.so";
}
struct stat attrib;
stat(game.lib_name, &attrib);
game.mod_time = attrib.st_mtime;
game.lib_ptr = SDL_LoadObject(game.lib_name);
if (game.lib_ptr == NULL) {
fprintf(stderr, "Error loading game library: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.startup = SDL_LoadFunction(game.lib_ptr, "game_startup");
if (game.startup == NULL) {
fprintf(stderr, "Error loading game function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.shutdown = SDL_LoadFunction(game.lib_ptr, "game_shutdown");
if (game.shutdown == NULL) {
fprintf(stderr, "Error loading game function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.update = SDL_LoadFunction(game.lib_ptr, "game_update");
if (game.update == NULL) {
fprintf(stderr, "Error loading game function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.render = SDL_LoadFunction(game.lib_ptr, "game_render");
if (game.render == NULL) {
fprintf(stderr, "Error loading game function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.debug = SDL_LoadFunction(game.lib_ptr, "game_debug");
if (game.debug == NULL) {
fprintf(stderr, "Error loading game function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.audio_callback = SDL_LoadFunction(game.lib_ptr, "game_audio_callback");
if (game.audio_callback == NULL) {
fprintf(stderr, "Error loading game function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
game.memory.engine.begin = calloc(ENGINE_MEMORY_SIZE, 1);
game.memory.engine.end = game.memory.engine.begin + ENGINE_MEMORY_SIZE;
game.memory.engine.current = game.memory.engine.begin;
game.memory.engine.size = ENGINE_MEMORY_SIZE;
if (game.memory.engine.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for engine memory\n", ENGINE_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
game.memory.game.begin = calloc(GAME_MEMORY_SIZE, 1);
game.memory.game.end = game.memory.game.begin + GAME_MEMORY_SIZE;
game.memory.game.current = game.memory.game.begin;
game.memory.game.size = GAME_MEMORY_SIZE;
if (game.memory.game.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for game memory\n", GAME_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
game.memory.scratch.begin = calloc(SCRATCH_MEMORY_SIZE, 1);
game.memory.scratch.end = game.memory.scratch.begin + SCRATCH_MEMORY_SIZE;
game.memory.scratch.current = game.memory.scratch.begin ;
game.memory.scratch.size = SCRATCH_MEMORY_SIZE;
if (game.memory.scratch.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for scratch memory\n", SCRATCH_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
}
// Set up audio
SDL_AudioDeviceID audio_device;
SDL_AudioSpec audio_specs = {0};
{
audio_specs.freq = 8000;
audio_specs.format = AUDIO_F32;
audio_specs.channels = 2;
audio_specs.samples = 256;
audio_specs.callback = game.audio_callback;
audio_specs.userdata = &game.memory;
SDL_AudioSpec have;
audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_specs, &have, 0);
// Un-pause
SDL_PauseAudioDevice(audio_device, 0);
}
game.startup(&game.memory);
bool is_running = true;
keystate_t keystate = {0};
uint64_t previous_time = SDL_GetTicks64();
while (is_running)
{
float dt;
uint16_t frame_time;
{
uint64_t current_time = SDL_GetTicks64();
frame_time = current_time - previous_time;
if (frame_time < TARGET_FRAME_TIME)
{
uint64_t sleep_time = TARGET_FRAME_TIME - frame_time;
SDL_Delay(sleep_time);
current_time = SDL_GetTicks64();
frame_time = current_time - previous_time;
}
previous_time = current_time;
dt = frame_time / 1000.0f;
}
{
SDL_Event e;
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT) {
is_running = false;
}
else if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP)
{
switch (e.key.keysym.sym)
{
case SDLK_w: {
keystate.w = e.type;
} break;
case SDLK_a: {
keystate.a = e.type;
} break;
case SDLK_s: {
keystate.s = e.type;
} break;
case SDLK_d: {
keystate.d = e.type;
} break;
case SDLK_UP: {
keystate.up = e.type;
} break;
case SDLK_LEFT: {
keystate.left = e.type;
} break;
case SDLK_DOWN: {
keystate.down = e.type;
} break;
case SDLK_RIGHT: {
keystate.right = e.type;
} break;
case SDLK_e: {
keystate.e = e.type;
} break;
case SDLK_RETURN: {
keystate.enter = e.type;
} break;
case SDLK_SPACE: {
keystate.space= e.type;
} break;
case SDLK_ESCAPE: {
keystate.esc = e.type;
} break;
}
}
}
}
input_t input = {0};
if (keystate.w == SDL_KEYDOWN || keystate.up == SDL_KEYDOWN) { input.up = true; }
if (keystate.a == SDL_KEYDOWN || keystate.left == SDL_KEYDOWN) { input.left = true; }
if (keystate.s == SDL_KEYDOWN || keystate.down == SDL_KEYDOWN) { input.down = true; }
if (keystate.d == SDL_KEYDOWN || keystate.right == SDL_KEYDOWN) { input.right = true; }
if (keystate.e == SDL_KEYDOWN) { input.interact = true; }
if (keystate.enter == SDL_KEYDOWN || keystate.space == SDL_KEYDOWN) { input.select = true; }
if (keystate.esc == SDL_KEYDOWN) { input.pause = true; }
SDL_GetRelativeMouseState(&input.mouse_x_delta, &input.mouse_y_delta);
bool quit_requested = false;
#ifdef BUILD_RELEASE
game.update(&game.memory, dt, input, &quit_requested);
game.render(&game.memory);
#else
{
struct stat attrib;
stat(game.lib_name, &attrib);
time_t mod_time = attrib.st_mtime;
if (mod_time != game.mod_time)
{
SDL_CloseAudioDevice(audio_device);
SDL_UnloadObject(game.lib_ptr);
game.lib_ptr = NULL;
game.update = NULL;
game.render = NULL;
game.debug = NULL;
game.audio_callback = NULL;
game.shutdown = NULL;
// Failure here is likely the first few times while it attempts to load a library
// that has not finished compiling, so we let it fail and try again next time
game.lib_ptr = SDL_LoadObject(game.lib_name);
if (game.lib_ptr)
{
game.mod_time = mod_time;
game.update = SDL_LoadFunction(game.lib_ptr, "game_update");
game.render = SDL_LoadFunction(game.lib_ptr, "game_render");
game.shutdown = SDL_LoadFunction(game.lib_ptr, "game_shutdown");
game.debug = SDL_LoadFunction(game.lib_ptr, "game_debug");
game.audio_callback = SDL_LoadFunction(game.lib_ptr, "game_audio_callback");
if (game.audio_callback)
{
// Need to re-initialize the audio device so it gets the updated callback pointer
audio_specs.callback = game.audio_callback;
SDL_AudioSpec have;
audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_specs, &have, 0);
SDL_PauseAudioDevice(audio_device, 0);
}
}
}
}
if (game.update && game.render && game.debug)
{
uint64_t update_time;
{
uint64_t pre_time = SDL_GetTicks64();
game.update(&game.memory, dt, input, &quit_requested);
uint64_t post_time = SDL_GetTicks64();
update_time = post_time - pre_time;
}
uint16_t render_time;
{
uint64_t pre_time = SDL_GetTicks64();
game.render();
uint64_t post_time = SDL_GetTicks64();
render_time = post_time - pre_time;
}
game.debug(update_time, render_time, frame_time);
}
#endif
is_running = !quit_requested;
SDL_GL_SwapWindow(window);
}
game.shutdown();
SDL_UnloadObject(game.lib_ptr);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_Quit();
return EXIT_SUCCESS;
}