160 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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;
 | 
						|
}
 |