#include #include #include #include #include #include #include #include "db/db.h" #include "gfx/shape_renderer.h" #include "gfx/txt_renderer.h" #include "game_state.h" #include "ui/ui_renderer.h" #include "gfx/types.h" #include "ui/cursor_manager.h" #include "debug/debug_stats.h" const int SCREEN_WIDTH = 1280; const int SCREEN_HEIGHT = 720; int main(int argc, char** argv) { /* Init SDL. */ if(!SDL_Init(SDL_INIT_VIDEO)) { printf("SDL could not initialise! SDL_ERROR: %s\n", SDL_GetError()); return 1; } /* Set OpenGL attributes. */ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); /* Create a window. */ SDL_Window* window = SDL_CreateWindow( "Bettola Client", SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL ); if(window == NULL) { printf("Unable to create window! SDL_ERROR: %s\n", SDL_GetError()); return 1; } /* Create OpenGL context. */ SDL_GLContext context = SDL_GL_CreateContext(window); if(context == NULL) { printf("OpenGL context could not be created! SDL_ERROR: %s\n", SDL_GetError()); return 1; } /* Initialise GLEW. */ glewExperimental = GL_TRUE; GLenum glewError = glewInit(); if (glewError != GLEW_OK) { /* NOTE: * Dear future self, or other intrepid developer: * In some environments (like the Fedora VM I tested), * glewInit() returns an error here even when the context is valid. * This is a known quirk. We print the error but continue anyway, * because it's not fatal. Don't "fix" this by making it exit. Thank you. * It's GLEW, not you. */ fprintf(stderr, "Warning: glewInit failed with error code %u: %s. Attempting to continue anyway.\n", glewError, glewGetErrorString(glewError)); } /* Configure OpenGL. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* Listen for text input. */ SDL_StartTextInput(window); /* Init cursor manager. */ CursorManager::init(); /* Init text renderer. */ TextRenderer* txt_render_instance = new TextRenderer(SCREEN_WIDTH, SCREEN_HEIGHT); txt_render_instance->load_font("assets/fonts/hack/Hack-Regular.ttf", 14); /* Init shape renderer. */ ShapeRenderer* shape_renderer_instance = new ShapeRenderer(SCREEN_WIDTH, SCREEN_HEIGHT); /* Init UI renderer. */ UIRenderer* ui_renderer_instance = new UIRenderer(shape_renderer_instance, txt_render_instance, SCREEN_HEIGHT); auto game_state = std::make_unique(); if(argc > 1 && std::string(argv[1]) == "-sp") { game_state->start_single_player_now(SCREEN_WIDTH, SCREEN_HEIGHT); } else { game_state->init(SCREEN_WIDTH, SCREEN_HEIGHT); } /* timer for cursor blink. */ Uint32 last_blink_time = 0; bool show_cursor = true; /* Timestep. */ Uint64 last_frame_time = SDL_GetPerformanceCounter(); float dt = 0.0f; bool running = true; while(running) { /* Reset per-frame stats. */ DebugStats::reset(); /* Event handling. */ SDL_Event event; while(SDL_PollEvent(&event)) { if(event.type == SDL_EVENT_QUIT) { running = false; } game_state->handle_event(&event, SCREEN_WIDTH, SCREEN_HEIGHT); } /* Calculate delta time. */ Uint64 current_frame_time = SDL_GetPerformanceCounter(); dt = (current_frame_time - last_frame_time) / (float)SDL_GetPerformanceFrequency(); last_frame_time = current_frame_time; /* Clamp dt to avoid large jumps. */ if(dt > 0.1f) dt = 0.1f; Uint32 current_time = SDL_GetTicks(); if(current_time - last_blink_time > 500) { /* Every 500ms. */ show_cursor = !show_cursor; last_blink_time = current_time; } /* Clear screen. */ glClearColor(0.04f, 0.05f, 0.06, 1.0f); glClear(GL_COLOR_BUFFER_BIT); RenderContext context = { ui_renderer_instance, SCREEN_HEIGHT, show_cursor }; game_state->render(context); /* Update game state after rendering so stats are for the frame just rendered. * I know this is unusual, but given the text based nature of the game * we won't see a negative impact, and this is better than a large refactor ;) */ game_state->update(dt, DebugStats::draw_calls, DebugStats::shape_vertices, DebugStats::text_vertices); /* It's really odd to call it SwapWindow now, rather than SwapBuffer. */ SDL_GL_SwapWindow(window); } /* Cleanup. */ game_state.reset(); delete ui_renderer_instance; delete shape_renderer_instance; delete txt_render_instance; SDL_GL_DestroyContext(context); CursorManager::quit(); SDL_DestroyWindow(window); SDL_Quit(); return 0; }