void game_startup(memory_t* memory) { if (SDL_BYTEORDER != SDL_LIL_ENDIAN) { LOG_ERROR("Machine is Big Endian; expected Little Endian."); exit(EXIT_FAILURE); } g_memory = memory; engine_t* engine = engine_mem_alloc(1, sizeof(*engine)); g_engine = engine; game_t* game = game_mem_alloc(1, sizeof(*game)); g_game = game; g_asset_mgr = &engine->asset_mgr; g_audio_mgr = &engine->audio_mgr; g_render_mgr = &engine->render_mgr; asset_mgr_startup(); audio_mgr_startup(); render_mgr_startup(); // Load data game->data = data_load("data.bin"); data_t* data = &game->data; state_t* state = &game->state; ui_t* ui = &game->ui; state->mode = MODE_MAIN_MENU; state->mode_last = MODE_MAIN_MENU; // Set up menus ui->main_menu = (ui_menu_t){ .widget_count = 3, .widgets = { {"Play", WINDOW_WIDTH/2, WINDOW_HEIGHT/2, menu_play}, {"Options", WINDOW_WIDTH/2, WINDOW_HEIGHT/2 + 40, menu_options}, {"Quit", WINDOW_WIDTH/2, WINDOW_HEIGHT/2 + 80, menu_quit}}, }; ui->pause_menu = (ui_menu_t){ .widget_count = 3, .widgets = { {"Resume", WINDOW_WIDTH/2, WINDOW_HEIGHT/2, menu_play}, {"Options", WINDOW_WIDTH/2, WINDOW_HEIGHT/2 + 40, menu_options}, {"Quit", WINDOW_WIDTH/2, WINDOW_HEIGHT/2 + 80, menu_quit}}, }; ui->options_menu = (ui_menu_t){ .widget_count = 1, .widgets = { {"Exit", WINDOW_WIDTH/2, WINDOW_HEIGHT/2, menu_exit}}, }; // Create systems state->camera = camera_create((vec3){28.0f, 29.0f, 1.0f}); audio_source_t audio_source = { .wav = get_sfx_by_name("SFX_Enemy"), .is_looping = true, .stereo = true}; // Set up world state->skulls[0].tile_pos.x = 1; state->skulls[0].tile_pos.y = 1; state->skulls[0].front = (vec3){0.0f, 1.0f, 0.0f}; audio_source.position = (vec3){ state->skulls[0].tile_pos.x*2.0f+1.0f, state->skulls[0].tile_pos.y*2.0f+1.0f, 1.0f}; state->skulls[0].audio_source_handle = play_sound(audio_source); state->skulls[1].tile_pos.x = 26; state->skulls[1].tile_pos.y = 1; state->skulls[1].front = (vec3){0.0f, 1.0f, 0.0f}; audio_source.position = (vec3){ state->skulls[1].tile_pos.x*2.0f+1.0f, state->skulls[1].tile_pos.y*2.0f+1.0f, 1.0f}; state->skulls[1].audio_source_handle = play_sound(audio_source); state->skulls[2].tile_pos.x = 1; state->skulls[2].tile_pos.y = 29; state->skulls[2].front = (vec3){0.0f, -1.0f, 0.0f}; audio_source.position = (vec3){ state->skulls[2].tile_pos.x*2.0f+1.0f, state->skulls[2].tile_pos.y*2.0f+1.0f, 1.0f}; state->skulls[2].audio_source_handle = play_sound(audio_source); state->skulls[3].tile_pos.x = 26; state->skulls[3].tile_pos.y = 29; state->skulls[3].front = (vec3){0.0f, -1.0f, 0.0f}; audio_source.position = (vec3){ state->skulls[3].tile_pos.x*2.0f+1.0f, state->skulls[3].tile_pos.y*2.0f+1.0f, 1.0f}; state->skulls[3].audio_source_handle = play_sound(audio_source); state->nodes[0] = (node_t){ .transform = (transform_t){(vec3){28.0f, 33.0f, 1.5f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){0.5f, 0.5f, 0.5f}}, .parent = -1, .children = {1, 2, 3}, .matrix = mat4_identity(), .rotation = mat4_identity()}; state->nodes[1] = (node_t){ .transform = (transform_t){(vec3){-0.5f, 0.0f, 0.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){1.0f, 1.0f, 1.0f}}, .parent = 0, .children = {-1, -1, -1}, .matrix = mat4_identity(), .rotation = mat4_identity()}; state->nodes[2] = (node_t){ .transform = (transform_t){(vec3){0.0f, 0.0f, 0.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){1.0f, 1.0f, 1.0f}}, .parent = 0, .children = {-1, -1, -1}, .matrix = mat4_identity(), .rotation = mat4_identity()}; state->nodes[3] = (node_t){ .transform = (transform_t){(vec3){0.5f, 0.0f, 0.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){1.0f, 1.0f, 1.0f}}, .parent = 0, .children = {-1, -1, -1}, .matrix = mat4_identity(), .rotation = mat4_identity()}; // Initalize footsteps state->footstep_timer = FOOTSTEP_TIMER; state->footstep_cycle = false; // Create a copy of the game items so we can restore the original layout on new game/level state->coin_count = data->items.coin_count; state->eyeball_count = data->items.eyeball_count; state->coins = game_mem_alloc(data->items.coin_count, sizeof(*state->coins)); state->eyeballs = game_mem_alloc(data->items.eyeball_count, sizeof(*state->eyeballs)); memcpy(state->coins, data->items.coins, data->items.coin_count * sizeof(*data->items.coins)); for (int i = 0; i < state->eyeball_count; i++) { state->eyeballs[i].transform = data->items.eyeballs[i]; state->eyeballs[i].used = false; } g_audio_mgr->listener.position = state->camera.position; g_audio_mgr->listener.front = state->camera.front; g_audio_mgr->listener.up = WORLD_UP; audio_source_t creepy_music = { .wav = get_music_by_name("MUS_Ambience"), .is_looping = true}; state->background_music_handle = play_sound(creepy_music); audio_source_t enemy_sfx = { .position = {28.0f, 33.0f, 1.0f}, .wav = get_sfx_by_name("SFX_SafeZone"), .stereo = true, .is_looping = true}; play_sound(enemy_sfx); } void game_shutdown(void) { } void game_update(memory_t* memory, float dt, input_t input, bool* quit_requested) { // Re-cache memory pointer in case of DLL reload g_memory = memory; engine_t* engine = (engine_t*)memory->engine.begin; game_t* game = (game_t*)memory->game.begin; state_t* state = &game->state; ui_t* ui = &game->ui; // Re-cache g_game = game; g_asset_mgr = &engine->asset_mgr; g_audio_mgr = &engine->audio_mgr; g_render_mgr = &engine->render_mgr; state->time += dt; if (input.pause && input.pause != state->input_prev.pause) { state->mode = MODE_PAUSE; } switch (state->mode) { case MODE_MAIN_MENU: { menu_update(input, &ui->main_menu); } break; case MODE_OPTIONS: { menu_update(input, &ui->options_menu); } break; case MODE_PAUSE: { menu_update(input, &ui->pause_menu); } break; case MODE_PLAY: { play(dt, input); } break; case MODE_QUIT: { *quit_requested = true; } default: break; } state->input_prev = input; } void game_render(void) { state_t* state = &g_game->state; ui_t* ui = &g_game->ui; reload_shaders(); switch (state->mode) { case MODE_MAIN_MENU: { menu_render(&ui->main_menu); } break; case MODE_OPTIONS: { menu_render(&ui->options_menu); } break; case MODE_PAUSE: { menu_render(&ui->pause_menu); } break; case MODE_PLAY: { render_geo(); render_screen(); } break; default: break; } } void game_debug(uint64_t update_time, uint64_t render_time, uint64_t frame_time) { state_t* state = &g_game->state; switch (state->mode) { case MODE_PLAY: { debug(update_time, render_time, frame_time); } break; default: break; } } void game_audio_callback(void* userdata, uint8_t* stream, int len) { (void)userdata; (void)stream; (void)len; fill_audio_buffer(stream, len); }