diff options
Diffstat (limited to 'source/Game/main.cpp')
-rw-r--r-- | source/Game/main.cpp | 461 |
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; -} |