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

498 lines
13 KiB
C

#ifdef BUILD_RELEASE
#include "all.c"
#else
#include "common.h"
#endif
typedef struct keystate {
int w; int a; int s; int d;
int up; int left; int down; int right;
int q; int e;
int enter; int space; int esc; int shift;
int f1;
} keystate_t;
#ifdef BUILD_DEBUG
typedef struct debug {
time_t mod_time;
const char* lib_name;
void* lib_ptr;
} debug_t;
void (*engine_reload)(memory_t*);
void (*engine_debug)(float, input_t, uint64_t, uint64_t, uint64_t);
void (*engine_startup)(memory_t*);
void (*engine_shutdown)(void);
void (*engine_update)(float, input_t, bool, bool*);
void (*engine_render)(void);
void (*engine_audio_callback)(void* userdata, uint8_t* stream, int len);
#endif
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);
}
memory_t memory;
{
memory.engine.begin = calloc(ENGINE_MEMORY_SIZE, 1);
memory.engine.end = memory.engine.begin + ENGINE_MEMORY_SIZE;
memory.engine.current = memory.engine.begin;
if (memory.engine.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for engine memory\n", ENGINE_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
memory.game.begin = calloc(GAME_MEMORY_SIZE, 1);
memory.game.end = memory.game.begin + GAME_MEMORY_SIZE;
memory.game.current = memory.game.begin;
if (memory.game.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for game memory\n", GAME_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
memory.data1.begin = calloc(DATA1_MEMORY_SIZE, 1);
memory.data1.end = memory.data1.begin + DATA1_MEMORY_SIZE;
memory.data1.current = memory.data1.begin;
if (memory.data1.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for data1 memory\n", DATA1_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
memory.data2.begin = calloc(DATA2_MEMORY_SIZE, 1);
memory.data2.end = memory.data2.begin + DATA2_MEMORY_SIZE;
memory.data2.current = memory.data2.begin;
if (memory.data2.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for data2 memory\n", DATA2_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
memory.scratch.begin = calloc(SCRATCH_MEMORY_SIZE, 1);
memory.scratch.end = memory.scratch.begin + SCRATCH_MEMORY_SIZE;
memory.scratch.current = memory.scratch.begin ;
if (memory.scratch.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for scratch memory\n", SCRATCH_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
}
#ifdef BUILD_DEBUG
debug_t debug = {0};
{
const char* platform_str = SDL_GetPlatform();
if (strcmp(platform_str, "Windows") == 0) {
debug.lib_name = ".\\libgame.dll";
} else {
debug.lib_name = "./libgame.so";
}
struct stat attrib;
stat(debug.lib_name, &attrib);
debug.mod_time = attrib.st_mtime;
debug.lib_ptr = SDL_LoadObject(debug.lib_name);
if (debug.lib_ptr == NULL) {
fprintf(stderr, "Error loading game library: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_startup = SDL_LoadFunction(debug.lib_ptr, "engine_startup");
if (engine_startup == NULL) {
fprintf(stderr, "Error loading startup function from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_shutdown = SDL_LoadFunction(debug.lib_ptr, "engine_shutdown");
if (engine_shutdown == NULL) {
fprintf(stderr, "Error loading shutdown function from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_update = SDL_LoadFunction(debug.lib_ptr, "engine_update");
if (engine_update == NULL) {
fprintf(stderr, "Error loading update function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_render = SDL_LoadFunction(debug.lib_ptr, "engine_render");
if (engine_render == NULL) {
fprintf(stderr, "Error loading render function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_audio_callback = SDL_LoadFunction(debug.lib_ptr, "engine_audio_callback");
if (engine_audio_callback == NULL) {
fprintf(stderr, "Error loading audio function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_debug = SDL_LoadFunction(debug.lib_ptr, "engine_debug");
if (engine_debug == NULL) {
fprintf(stderr, "Error loading debug function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
engine_reload = SDL_LoadFunction(debug.lib_ptr, "engine_reload");
if (engine_reload == NULL) {
fprintf(stderr, "Error loading reload function pointer from game lib: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
memory.debug.begin = calloc(DEBUG_MEMORY_SIZE, 1);
memory.debug.end = memory.debug.begin + DEBUG_MEMORY_SIZE;
memory.debug.current = memory.debug.begin ;
if (memory.debug.begin == NULL) {
fprintf(stderr, "Error requesting %lu bytes for debug memory\n", DEBUG_MEMORY_SIZE);
exit(EXIT_FAILURE);
}
}
#endif
// 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 = engine_audio_callback;
audio_specs.userdata = &memory;
SDL_AudioSpec have;
audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_specs, &have, 0);
// Un-pause
SDL_PauseAudioDevice(audio_device, 0);
}
engine_startup(&memory);
bool window_focus = true;
bool is_running = true;
keystate_t keystate_current = {0};
keystate_t keystate_previous = {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;
}
bool quit_requested = false;
{
SDL_Event e;
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT) {
quit_requested = true;
}
else if (e.type == SDL_WINDOWEVENT)
{
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
{
window_focus = false;
}
else if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
{
window_focus = true;
}
}
else if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP)
{
switch (e.key.keysym.sym)
{
case SDLK_w: {
keystate_current.w = e.type;
} break;
case SDLK_a: {
keystate_current.a = e.type;
} break;
case SDLK_s: {
keystate_current.s = e.type;
} break;
case SDLK_d: {
keystate_current.d = e.type;
} break;
case SDLK_UP: {
keystate_current.up = e.type;
} break;
case SDLK_LEFT: {
keystate_current.left = e.type;
} break;
case SDLK_DOWN: {
keystate_current.down = e.type;
} break;
case SDLK_RIGHT: {
keystate_current.right = e.type;
} break;
case SDLK_e: {
keystate_current.e = e.type;
} break;
case SDLK_q: {
keystate_current.q = e.type;
} break;
case SDLK_RETURN: {
keystate_current.enter = e.type;
} break;
case SDLK_SPACE: {
keystate_current.space= e.type;
} break;
case SDLK_ESCAPE: {
keystate_current.esc = e.type;
} break;
case SDLK_LSHIFT: {
keystate_current.shift = e.type;
} break;
case SDLK_F1: {
keystate_current.f1= e.type;
} break;
}
}
}
}
input_t input = {0};
SDL_GetRelativeMouseState(&input.mouse_x_delta, &input.mouse_y_delta);
// Continuous inputs
if (keystate_current.w == SDL_KEYDOWN) {
input.forward = true;
}
if (keystate_current.a == SDL_KEYDOWN) {
input.strafe_left = true;
}
if (keystate_current.s == SDL_KEYDOWN) {
input.backward = true;
}
if (keystate_current.d == SDL_KEYDOWN) {
input.strafe_right = true;
}
// Debounced inputs
if (keystate_current.up == SDL_KEYDOWN)
{
if (keystate_current.up != keystate_previous.up) {
input.up = true;
}
}
if (keystate_current.down == SDL_KEYDOWN)
{
if (keystate_current.down != keystate_previous.down) {
input.down = true;
}
}
if (keystate_current.left == SDL_KEYDOWN)
{
if (keystate_current.left != keystate_previous.left) {
input.left = true;
}
}
if (keystate_current.left == SDL_KEYDOWN)
{
if (keystate_current.left != keystate_previous.left) {
input.right = true;
}
}
if (keystate_current.e == SDL_KEYDOWN)
{
if (keystate_current.e != keystate_previous.e) {
input.interact = true;
}
}
if (keystate_current.enter == SDL_KEYDOWN)
{
if (keystate_current.enter != keystate_previous.enter) {
input.select = true;
}
}
if (keystate_current.esc == SDL_KEYDOWN)
{
if (keystate_current.esc != keystate_previous.esc) {
input.pause = true;
}
}
#ifdef BUILD_RELEASE
engine_update(dt, input, window_focus, &quit_requested);
engine_render();
#else
// Continuous inputs
if (keystate_current.q == SDL_KEYDOWN) {
input.debug.down = true;
}
if (keystate_current.e == SDL_KEYDOWN) {
input.debug.up = true;
}
if (keystate_current.shift == SDL_KEYDOWN) {
input.debug.speed = true;
}
// Debounced inputs
if (keystate_current.f1 == SDL_KEYDOWN)
{
if (keystate_current.f1 != keystate_previous.f1) {
input.debug.enable = true;
}
}
{
struct stat attrib;
stat(debug.lib_name, &attrib);
time_t mod_time = attrib.st_mtime;
if (mod_time != debug.mod_time)
{
SDL_CloseAudioDevice(audio_device);
SDL_UnloadObject(debug.lib_ptr);
debug.lib_ptr = NULL;
engine_debug= NULL;
engine_update = NULL;
engine_render = NULL;
engine_audio_callback = NULL;
engine_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
debug.lib_ptr = SDL_LoadObject(debug.lib_name);
if (debug.lib_ptr)
{
debug.mod_time = mod_time;
engine_update = SDL_LoadFunction(debug.lib_ptr, "engine_update");
engine_render = SDL_LoadFunction(debug.lib_ptr, "engine_render");
engine_shutdown = SDL_LoadFunction(debug.lib_ptr, "engine_shutdown");
engine_debug = SDL_LoadFunction(debug.lib_ptr, "engine_debug");
engine_reload = SDL_LoadFunction(debug.lib_ptr, "engine_reload");
engine_audio_callback = SDL_LoadFunction(debug.lib_ptr, "engine_audio_callback");
if (engine_audio_callback)
{
// Need to re-initialize the audio device so it gets the updated callback pointer
audio_specs.callback = engine_audio_callback;
SDL_AudioSpec have;
audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_specs, &have, 0);
SDL_PauseAudioDevice(audio_device, 0);
}
}
}
}
if (engine_update && engine_render && engine_debug && engine_reload)
{
engine_reload(&memory);
uint64_t update_time;
{
uint64_t pre_time = SDL_GetTicks64();
engine_update(dt, input, window_focus, &quit_requested);
uint64_t post_time = SDL_GetTicks64();
update_time = post_time - pre_time;
}
uint16_t render_time;
{
uint64_t pre_time = SDL_GetTicks64();
engine_render();
uint64_t post_time = SDL_GetTicks64();
render_time = post_time - pre_time;
}
engine_debug(dt, input, update_time, render_time, frame_time);
}
#endif
keystate_previous = keystate_current;
is_running = !quit_requested;
SDL_GL_SwapWindow(window);
}
engine_shutdown();
#ifdef BUILD_DEBUG
SDL_UnloadObject(debug.lib_ptr);
#endif
SDL_QuitSubSystem(SDL_INIT_AUDIO);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_Quit();
return EXIT_SUCCESS;
}