aboutsummaryrefslogtreecommitdiff
path: root/source/Game/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Game/main.cpp')
-rw-r--r--source/Game/main.cpp461
1 files changed, 0 insertions, 461 deletions
diff --git a/source/Game/main.cpp b/source/Game/main.cpp
deleted file mode 100644
index c49fc0b..0000000
--- a/source/Game/main.cpp
+++ /dev/null
@@ -1,461 +0,0 @@
-#include "App.hpp"
-
-#include "AppConfig.hpp"
-#include "CommonVertexIndex.hpp"
-#include "EditorGuizmo.hpp"
-#include "Ires.hpp"
-#include "Level.hpp"
-#include "Material.hpp"
-#include "Shader.hpp"
-
-#define GLFW_INCLUDE_NONE
-#include <GLFW/glfw3.h>
-
-#include <backends/imgui_impl_glfw.h>
-#include <backends/imgui_impl_opengl2.h>
-#include <backends/imgui_impl_opengl3.h>
-#include <glad/glad.h>
-#include <imgui.h>
-#include <imgui_internal.h>
-#include <cstdlib>
-#include <cxxopts.hpp>
-#include <filesystem>
-#include <string>
-
-#include <tracy/Tracy.hpp>
-#include <tracy/TracyClient.cpp>
-
-namespace fs = std::filesystem;
-using namespace std::literals;
-
-struct GlfwUserData {
- App* app = nullptr;
-};
-
-void GlfwErrorCallback(int error, const char* description) {
- fprintf(stderr, "[GLFW] Error %d: %s\n", error, description);
-}
-
-void GlfwFramebufferResizeCallback(GLFWwindow* window, int width, int height) {
- AppConfig::mainWindowWidth = width;
- AppConfig::mainWindowHeight = height;
- AppConfig::mainWindowAspectRatio = (float)width / height;
-}
-
-void GlfwMouseCallback(GLFWwindow* window, int button, int action, int mods) {
- if (ImGui::GetIO().WantCaptureMouse) {
- return;
- }
-
- auto userData = static_cast<GlfwUserData*>(glfwGetWindowUserPointer(window));
- auto app = userData->app;
- app->HandleMouse(button, action);
-}
-
-void GlfwMouseMotionCallback(GLFWwindow* window, double xOff, double yOff) {
- if (ImGui::GetIO().WantCaptureMouse) {
- return;
- }
-
- auto userData = static_cast<GlfwUserData*>(glfwGetWindowUserPointer(window));
- auto app = userData->app;
- app->HandleMouseMotion(xOff, yOff);
-}
-
-void GlfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
- if (ImGui::GetIO().WantCaptureKeyboard) {
- return;
- }
-
- GLFWkeyboard* keyboard = glfwGetLastActiveKeyboard();
- if (keyboard) {
- auto userData = static_cast<GlfwUserData*>(glfwGetWindowUserPointer(window));
- auto app = userData->app;
- app->HandleKey(keyboard, key, action);
- }
-}
-
-// https://stackoverflow.com/questions/54499256/how-to-find-the-saved-games-folder-programmatically-in-c-c
-#if defined(_WIN32)
-# if defined(__MINGW32__)
-# include <ShlObj.h>
-# else
-# include <ShlObj_core.h>
-# endif
-# include <objbase.h>
-# pragma comment(lib, "shell32.lib")
-# pragma comment(lib, "ole32.lib")
-#elif defined(__linux__)
-fs::path GetEnvVar(const char* name, const char* backup) {
- if (const char* path = std::getenv(name)) {
- fs::path dataDir(path);
- fs::create_directories(dataDir);
- return dataDir;
- } else {
- fs::path dataDir(backup);
- fs::create_directories(dataDir);
- return dataDir;
- }
-}
-#endif
-
-int main(int argc, char* argv[]) {
- using namespace Tags;
-
- constexpr auto kImGuiBackend = "imgui-backend";
- constexpr auto kGameDataDir = "game-data-directory";
- constexpr auto kGameAssetDir = "game-asset-directory";
-
- cxxopts::Options options(std::string(AppConfig::kAppName), "");
- // clang-format off
- options.add_options()
- (kImGuiBackend, "ImGui backend. Options: opengl2, opengl3. Leave empty to default.", cxxopts::value<std::string>())
- (kGameAssetDir, "Directory in which assets are looked up from. Can be relative paths to the executable.", cxxopts::value<std::string>()->default_value("."))
- (kGameDataDir, "Directory in which game data (such as saves and options) are saved to. Leave empty to use the default directory on each platform.", cxxopts::value<std::string>())
- ;
- // clang-format on
- auto args = options.parse(argc, argv);
-
- bool imguiUseOpenGL3;
- if (args.count(kImGuiBackend) > 0) {
- auto imguiBackend = args[kImGuiBackend].as<std::string>();
- if (imguiBackend == "opengl2") {
- imguiUseOpenGL3 = false;
- } else if (imguiBackend == "opengl3") {
- imguiUseOpenGL3 = true;
- } else {
- // TODO support more backends?
- imguiUseOpenGL3 = true;
- }
- } else {
- imguiUseOpenGL3 = true;
- }
-
- if (args.count(kGameAssetDir) > 0) {
- auto assetDir = args[kGameAssetDir].as<std::string>();
-
- fs::path assetDirPath(assetDir);
- if (!fs::exists(assetDirPath)) {
- fprintf(stderr, "Invalid asset directory.\n");
- return -4;
- }
-
- AppConfig::assetDir = std::move(assetDir);
- AppConfig::assetDirPath = std::move(assetDirPath);
- } else {
-#if defined(_WIN32)
- fs::path dataDir;
-
- PWSTR path = nullptr;
- HRESULT hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, nullptr, &path);
- if (SUCCEEDED(hr)) {
- dataDir = fs::path(path) / AppConfig::kAppName;
- CoTaskMemFree(path);
-
- fs::create_directories(dataDir);
- } else {
- std::string msg;
- msg += "Failed to find/create the default user data directory at %APPDATA%. Error code: ";
- msg += hr;
- throw std::runtime_error(msg);
- }
-#elif defined(__APPLE__)
- // MacOS programming guide recommends apps to hardcode the path - user customization of "where data are stored" is done in Finder
- auto dataDir = fs::path("~/Library/Application Support/") / AppConfig::kAppName;
- fs::create_directories(dataDir);
-#elif defined(__linux__)
- auto dataDir = GetEnvVar("XDG_DATA_HOME", "~/.local/share") / AppConfig::kAppName;
- fs::create_directories(dataDir);
-#endif
- }
-
- if (args.count(kGameDataDir) > 0) {
- auto dataDir = args[kGameDataDir].as<std::string>();
-
- fs::path dataDirPath(dataDir);
- fs::create_directories(dataDir);
-
- AppConfig::dataDir = std::move(dataDir);
- AppConfig::dataDirPath = std::move(dataDirPath);
- } else {
- // TODO platform default path
- AppConfig::dataDir = ".";
- AppConfig::dataDirPath = fs::path(".");
- }
-
- if (!glfwInit()) {
- return -1;
- }
-
- glfwSetErrorCallback(&GlfwErrorCallback);
-
- glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
-
-#if defined(__APPLE__)
- const char* imguiGlslVersion = "#version 150";
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
-#else
- const char* imguiGlslVersion = "#version 130";
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
-#endif
-
- GlfwUserData glfwUserData;
-
- GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Command Palette Example", nullptr, nullptr);
- if (window == nullptr) {
- return -2;
- }
-
- glfwSetWindowUserPointer(window, &glfwUserData);
-
- // Window callbacks are retained by ImGui GLFW backend
- glfwSetFramebufferSizeCallback(window, &GlfwFramebufferResizeCallback);
- glfwSetKeyCallback(window, &GlfwKeyCallback);
- glfwSetMouseButtonCallback(window, &GlfwMouseCallback);
- glfwSetCursorPosCallback(window, &GlfwMouseMotionCallback);
-
- {
- int width, height;
- glfwGetFramebufferSize(window, &width, &height);
- GlfwFramebufferResizeCallback(window, width, height);
- }
-
- glfwMakeContextCurrent(window);
- glfwSwapInterval(1);
-
- // TODO setup opengl debug context
- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
- return -3;
- }
-
- IMGUI_CHECKVERSION();
- auto ctx = ImGui::CreateContext();
- auto& io = ImGui::GetIO();
- ImGuizmo::SetImGuiContext(ctx);
-
- ImGui_ImplGlfw_InitForOpenGL(window, true);
- if (imguiUseOpenGL3) {
- ImGui_ImplOpenGL3_Init(imguiGlslVersion);
- } else {
- ImGui_ImplOpenGL2_Init();
- }
-
- IresManager::instance = new IresManager();
- IresManager::instance->DiscoverFilesDesignatedLocation();
-
- LevelManager::instance = new LevelManager();
- LevelManager::instance->DiscoverFilesDesignatedLocation();
-
- gVformatStandard.Attach(new VertexFormat());
- gVformatStandard->AddElement(VertexElementFormat{
- .bindingIndex = 0,
- .type = VET_Float3,
- .semantic = VES_Position,
- });
- gVformatStandard->AddElement(VertexElementFormat{
- .bindingIndex = 0,
- .type = VET_Float2,
- .semantic = VES_TexCoords1,
- });
- gVformatStandard->AddElement(VertexElementFormat{
- .bindingIndex = 0,
- .type = VET_Ubyte4Norm,
- .semantic = VES_Color1,
- });
-
- gVformatStandardSplit.Attach(new VertexFormat());
- gVformatStandardSplit->AddElement(VertexElementFormat{
- .bindingIndex = 0,
- .type = VET_Float3,
- .semantic = VES_Position,
- });
- gVformatStandardSplit->AddElement(VertexElementFormat{
- .bindingIndex = 1,
- .type = VET_Float2,
- .semantic = VES_TexCoords1,
- });
- gVformatStandardSplit->AddElement(VertexElementFormat{
- .bindingIndex = 1,
- .type = VET_Ubyte4Norm,
- .semantic = VES_Color1,
- });
-
- // Matches gVformatStandard
- gDefaultShader.Attach(new Shader());
- gDefaultShader->InitFromSources(Shader::ShaderSources{
- .vertex = R"""(
-#version 330 core
-layout(location = 0) in vec3 pos;
-layout(location = 1) in vec4 color;
-out vec4 v2fColor;
-uniform mat4 transform;
-void main() {
- gl_Position = transform * vec4(pos, 1.0);
- v2fColor = color;
-}
-)"""sv,
- .fragment = R"""(
-#version 330 core
-in vec4 v2fColor;
-out vec4 fragColor;
-void main() {
- fragColor = v2fColor;
-}
-)"""sv,
- });
- { // in vec3 pos;
- ShaderMathVariable var;
- var.scalarType = GL_FLOAT;
- var.width = 1;
- var.height = 3;
- var.arrayLength = 1;
- var.semantic = VES_Position;
- var.location = 0;
- gDefaultShader->GetInfo().inputs.push_back(std::move(var));
- gDefaultShader->GetInfo().things.try_emplace(
- "pos"s,
- ShaderThingId{
- .kind = ShaderThingId::KD_Input,
- .index = (int)gDefaultShader->GetInfo().inputs.size() - 1,
- });
- }
- { // in vec4 color;
- ShaderMathVariable var;
- var.scalarType = GL_FLOAT;
- var.width = 1;
- var.height = 4;
- var.arrayLength = 1;
- var.semantic = VES_Color1;
- var.location = 1;
- gDefaultShader->GetInfo().inputs.push_back(std::move(var));
- gDefaultShader->GetInfo().things.try_emplace(
- "color"s,
- ShaderThingId{
- .kind = ShaderThingId::KD_Input,
- .index = (int)gDefaultShader->GetInfo().inputs.size() - 1,
- });
- }
- { // out vec4 fragColor;
- ShaderMathVariable var;
- var.scalarType = GL_FLOAT;
- var.width = 1;
- var.height = 4;
- var.arrayLength = 1;
- gDefaultShader->GetInfo().outputs.push_back(std::move(var));
- gDefaultShader->GetInfo().things.try_emplace(
- "fragColor"s,
- ShaderThingId{
- .kind = ShaderThingId::KD_Output,
- .index = (int)gDefaultShader->GetInfo().outputs.size() - 1,
- });
- }
- // NOTE: autofill uniforms not recorded here
-
- gDefaultMaterial.Attach(new Material());
- gDefaultMaterial->SetShader(gDefaultShader.Get());
-
- { // Main loop
- App app;
- glfwUserData.app = &app;
-
- // NOTE: don't enable backface culling, because the game mainly runs in 2D and sometimes we'd like to flip sprites around
- // it also helps with debugging layers in 3D view
- glEnable(GL_DEPTH_TEST);
-
- // 60 updates per second
- constexpr double kMsPerUpdate = 1000.0 / 60;
- constexpr double kSecondsPerUpdate = kMsPerUpdate / 1000;
- double prevTime = glfwGetTime();
- double accumulatedTime = 0.0;
- while (!glfwWindowShouldClose(window)) {
- {
- ZoneScopedN("GameInput");
- glfwPollEvents();
- }
-
- double currTime = glfwGetTime();
- double deltaTime = prevTime - currTime;
-
- // In seconds
- accumulatedTime += currTime - prevTime;
-
- // Update
- // Play "catch up" to ensure a deterministic number of Update()'s per second
- while (accumulatedTime >= kSecondsPerUpdate) {
- double beg = glfwGetTime();
- {
- ZoneScopedN("GameUpdate");
- app.Update();
- }
- double end = glfwGetTime();
-
- // Update is taking longer than it should be, start skipping updates
- auto diff = end - beg;
- if (diff >= kSecondsPerUpdate) {
- auto skippedUpdates = (int)(accumulatedTime / kSecondsPerUpdate);
- accumulatedTime = 0.0;
- fprintf(stderr, "Elapsed time %f, skipped %d updates.", diff, skippedUpdates);
- } else {
- accumulatedTime -= kSecondsPerUpdate;
- }
- }
-
- int fbWidth = AppConfig::mainWindowWidth;
- int fbHeight = AppConfig::mainWindowHeight;
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
- glViewport(0, 0, fbWidth, fbHeight);
- auto clearColor = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
- glClearColor(clearColor.x * clearColor.w, clearColor.y * clearColor.w, clearColor.z * clearColor.w, clearColor.w);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- { // Regular draw
- ZoneScopedN("Render");
- app.Draw(currTime, deltaTime);
- }
-
- { // ImGui draw
- ZoneScopedN("ImGui");
- if (imguiUseOpenGL3) {
- ImGui_ImplOpenGL3_NewFrame();
- } else {
- ImGui_ImplOpenGL2_NewFrame();
- }
- ImGui_ImplGlfw_NewFrame();
- ImGui::NewFrame();
-
- app.Show();
-
- ImGui::Render();
- if (imguiUseOpenGL3) {
- ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
- } else {
- ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
- }
- }
-
- glfwSwapBuffers(window);
- FrameMark;
-
- prevTime = currTime;
- }
- }
-
- if (imguiUseOpenGL3) {
- ImGui_ImplOpenGL3_Shutdown();
- } else {
- ImGui_ImplOpenGL2_Shutdown();
- }
- ImGui_ImplGlfw_Shutdown();
-
- ImGui::DestroyContext();
-
- glfwDestroyWindow(window);
- glfwTerminate();
-
- return 0;
-}