#include "App.hpp" #include "AppConfig.hpp" #include "EditorNotification.hpp" #include "Ires.hpp" #include "Mesh.hpp" #include "Shader.hpp" #define GLFW_INCLUDE_NONE #include #include #include #include #include #include #include #include #include #include namespace fs = std::filesystem; static void GlfwErrorCallback(int error, const char* description) { fprintf(stderr, "Glfw Error %d: %s\n", error, description); } static void GlfwMouseCallback(GLFWwindow* window, int button, int action, int mods) { if (ImGui::GetIO().WantCaptureMouse) { return; } App* app = static_cast(glfwGetWindowUserPointer(window)); app->HandleMouse(button, action); } static void GlfwMouseMotionCallback(GLFWwindow* window, double xOff, double yOff) { if (ImGui::GetIO().WantCaptureMouse) { return; } App* app = static_cast(glfwGetWindowUserPointer(window)); app->HandleMouseMotion(xOff, yOff); } static void GlfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (ImGui::GetIO().WantCaptureKeyboard) { return; } GLFWkeyboard* keyboard = glfwGetLastActiveKeyboard(); if (keyboard) { App* app = static_cast(glfwGetWindowUserPointer(window)); app->HandleKey(keyboard, key, action); } } 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()) (kGameAssetDir, "Directory in which assets are looked up from. Can be relative paths to the executable.", cxxopts::value()->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()) ; // clang-format on auto args = options.parse(argc, argv); bool imguiUseOpenGL3; { auto imguiBackend = args[kImGuiBackend].as(); if (imguiBackend == "opengl2") { imguiUseOpenGL3 = false; } else if (imguiBackend == "opengl3") { imguiUseOpenGL3 = true; } else { // TODO support more backends? imguiUseOpenGL3 = false; } } { auto assetDir = args[kGameAssetDir].as(); 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); } if (args.count(kGameDataDir) > 0) { auto dataDir = args[kGameDataDir].as(); 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); // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 const char* imguiGlslVersion = "#version 100"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); #elif defined(__APPLE__) // GL 3.2 + GLSL 150 const char* imguiGlslVersion = "#version 150"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac #else // GL 3.0 + GLSL 130 const char* imguiGlslVersion = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); #endif App app; GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Command Palette Example", nullptr, nullptr); if (window == nullptr) { return -2; } glfwSetWindowUserPointer(window, &app); // Window callbacks are retained by ImGui GLFW backend glfwSetKeyCallback(window, &GlfwKeyCallback); glfwSetMouseButtonCallback(window, &GlfwMouseCallback); glfwSetCursorPosCallback(window, &GlfwMouseMotionCallback); glfwMakeContextCurrent(window); glfwSwapInterval(1); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { return -3; } IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGui_ImplGlfw_InitForOpenGL(window, true); if (imguiUseOpenGL3) { ImGui_ImplOpenGL3_Init(imguiGlslVersion); } else { ImGui_ImplOpenGL2_Init(); } ShaderManager::instance = new ShaderManager(); IresManager::instance = new IresManager(); ShaderManager::instance->DiscoverShaders(); IresManager::instance->DiscoverFilesDesignatedLocation(); gVformatStandard.Attach(new VertexFormat()); gVformatStandard->AddElement(VertexElementFormat{ .bindingIndex = 0, .type = VET_Float3, .semantic = VES_Position, }); gVformatStandard->AddElement(VertexElementFormat{ .bindingIndex = 1, .type = VET_Float2, .semantic = VES_TexCoords1, }); gVformatStandard->AddElement(VertexElementFormat{ .bindingIndex = 1, .type = VET_Ubyte4Norm, .semantic = VES_Color1, }); gVformatStandardPacked.Attach(new VertexFormat()); gVformatStandardPacked->AddElement(VertexElementFormat{ .bindingIndex = 0, .type = VET_Float3, .semantic = VES_Position, }); gVformatStandardPacked->AddElement(VertexElementFormat{ .bindingIndex = 0, .type = VET_Float2, .semantic = VES_TexCoords1, }); gVformatStandardPacked->AddElement(VertexElementFormat{ .bindingIndex = 0, .type = VET_Ubyte4Norm, .semantic = VES_Color1, }); app.Init(); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); int fbWidth, fbHeight; 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); { // Regular draw app.Update(); app.Draw(); } { // ImGui stuff if (imguiUseOpenGL3) { ImGui_ImplOpenGL3_NewFrame(); } else { ImGui_ImplOpenGL2_NewFrame(); } ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); app.Show(); ImGui::ShowNotifications(); ImGui::Render(); if (imguiUseOpenGL3) { ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } else { ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); } } glfwSwapBuffers(window); } app.Shutdown(); if (imguiUseOpenGL3) { ImGui_ImplOpenGL3_Shutdown(); } else { ImGui_ImplOpenGL2_Shutdown(); } ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwDestroyWindow(window); glfwTerminate(); return 0; }