bettola/client/src/main.cpp

160 lines
4.6 KiB
C++

#include <memory>
#include <cstdio>
#include <GL/glew.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_keyboard.h>
/* For single player mode. */
#include <random>
#include <string>
#include <thread>
#include <chrono>
#include "../../server/src/network_manager.h"
#include "terminal.h"
#include "gfx/shape_renderer.h"
#include "ui/desktop.h"
#include "ui/ui_window.h"
void run_server(void) {
try {
NetworkManager server;
server.start(1337);
/*
* Server's start() method is non-blocking, but NetworkManager
* object must be kept alive. We'll just loop forever and let the OS
* clean up the thread when main exits ;)
*/
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(5));
}
} catch(const std::exception& e) {
fprintf(stderr, "Single-player server thread exception: %s\n", e.what());
}
}
const int SCREEN_WIDTH = 1280;
const int SCREEN_HEIGHT = 720;
int main(int argc, char** argv) {
if(argc > 1 && std::string(argv[1]) == "-sp") {
fprintf(stdout, "Starting in single-player mode...\n");
std::thread server_thread(run_server);
server_thread.detach();
fprintf(stdout, "Waiting for server initialise...\n");
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
/* 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 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);
/* Create terminal. */
auto term = std::make_unique<Terminal>();
/* Create UI window and pass it a terminal. */
auto test_window = std::make_unique<UIWindow>("Terminal", 100, 100, 800, 500);
test_window->set_content(std::move(term));
/* Create desktop and add the window. */
auto desktop = std::make_unique<Desktop>();
desktop->add_window(std::move(test_window));
/* timer for cursor blink. */
Uint32 last_blink_time = 0;
bool show_cursor = true;
bool running = true;
while(running) {
/* Event handling. */
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_EVENT_QUIT) { running = false; }
desktop.get()->handle_event(&event);
}
desktop.get()->update();
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.1f, 0.1f, 0.1, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
desktop.get()->render(shape_renderer_instance, txt_render_instance, SCREEN_HEIGHT, show_cursor);
/* It's really odd to call it SwapWindow now, rather than SwapBuffer. */
SDL_GL_SwapWindow(window);
}
/* Cleanup. */
desktop.reset();
delete shape_renderer_instance;
delete txt_render_instance;
SDL_GL_DestroyContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}