aboutsummaryrefslogtreecommitdiff
path: root/source/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/main.cpp')
-rw-r--r--source/main.cpp304
1 files changed, 250 insertions, 54 deletions
diff --git a/source/main.cpp b/source/main.cpp
index b166754..99a11c0 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -1,9 +1,10 @@
#include "App.hpp"
#include "AppConfig.hpp"
-#include "EditorNotification.hpp"
#include "Ires.hpp"
-#include "Mesh.hpp"
+#include "Material.hpp"
+#include "Shader.hpp"
+#include "VertexIndex.hpp"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
@@ -13,47 +14,86 @@
#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>
namespace fs = std::filesystem;
+using namespace std::literals;
-static void GlfwErrorCallback(int error, const char* description) {
- fprintf(stderr, "Glfw Error %d: %s\n", error, description);
+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::mainWidnowWidth = width;
+ AppConfig::mainWindowHeight = height;
+ AppConfig::mainWindowAspectRatio = (float)width / height;
}
-static void GlfwMouseCallback(GLFWwindow* window, int button, int action, int mods) {
+void GlfwMouseCallback(GLFWwindow* window, int button, int action, int mods) {
if (ImGui::GetIO().WantCaptureMouse) {
return;
}
- App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
+ auto userData = static_cast<GlfwUserData*>(glfwGetWindowUserPointer(window));
+ auto app = userData->app;
app->HandleMouse(button, action);
}
-static void GlfwMouseMotionCallback(GLFWwindow* window, double xOff, double yOff) {
+void GlfwMouseMotionCallback(GLFWwindow* window, double xOff, double yOff) {
if (ImGui::GetIO().WantCaptureMouse) {
return;
}
- App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
+ auto userData = static_cast<GlfwUserData*>(glfwGetWindowUserPointer(window));
+ auto app = userData->app;
app->HandleMouseMotion(xOff, yOff);
}
-static void GlfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
+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<App*>(glfwGetWindowUserPointer(window));
+ 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;
@@ -72,7 +112,7 @@ int main(int argc, char* argv[]) {
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;
@@ -80,11 +120,13 @@ int main(int argc, char* argv[]) {
imguiUseOpenGL3 = true;
} else {
// TODO support more backends?
- imguiUseOpenGL3 = false;
+ imguiUseOpenGL3 = true;
}
+ } else {
+ imguiUseOpenGL3 = true;
}
- {
+ if (args.count(kGameAssetDir) > 0) {
auto assetDir = args[kGameAssetDir].as<std::string>();
fs::path assetDirPath(assetDir);
@@ -95,6 +137,31 @@ int main(int argc, char* argv[]) {
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) {
@@ -118,13 +185,7 @@ int main(int argc, char* argv[]) {
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__)
+#if defined(__APPLE__)
// GL 3.2 + GLSL 150
const char* imguiGlslVersion = "#version 150";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@@ -132,29 +193,37 @@ int main(int argc, char* argv[]) {
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
+ // GL 3.3 + GLSL 130
const char* imguiGlslVersion = "#version 130";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#endif
- App app;
+ GlfwUserData glfwUserData;
GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Command Palette Example", nullptr, nullptr);
if (window == nullptr) {
return -2;
}
- glfwSetWindowUserPointer(window, &app);
+ 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;
}
@@ -169,6 +238,9 @@ int main(int argc, char* argv[]) {
ImGui_ImplOpenGL2_Init();
}
+ auto& io = ImGui::GetIO();
+ auto& ctx = *ImGui::GetCurrentContext();
+
IresManager::instance = new IresManager();
IresManager::instance->DiscoverFilesDesignatedLocation();
@@ -206,45 +278,169 @@ int main(int argc, char* argv[]) {
.semantic = VES_Color1,
});
- app.Init();
- while (!glfwWindowShouldClose(window)) {
- glfwPollEvents();
+ // Matches gVformatStandardPacked
+ gDefaultShader.Attach(new Shader());
+ gDefaultShader->InitFromSources(Shader::ShaderSources{
+ .vertex = R"""(
+#version 330 core
+layout(location = 0) in vec3 pos;
+layout(location = 1) in vec2 texcoord;
+layout(location = 2) in vec4 color;
+out vec4 v2fColor;
+uniform mat4 transformation;
+void main() {
+ gl_Position = transformation * 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 vec2 texcoord;
+ ShaderMathVariable var;
+ var.scalarType = GL_FLOAT;
+ var.width = 1;
+ var.height = 2;
+ var.arrayLength = 1;
+ var.semantic = VES_TexCoords1;
+ var.location = 1;
+ gDefaultShader->GetInfo().inputs.push_back(std::move(var));
+ gDefaultShader->GetInfo().things.try_emplace(
+ "texcoord"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 = 2;
+ 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
- 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);
+ gDefaultMaterial.Attach(new Material());
+ gDefaultMaterial->SetShader(gDefaultShader.Get());
- { // Regular draw
- app.Update();
- app.Draw();
- }
+ { // Main loop
+ App app;
+ glfwUserData.app = &app;
+
+ // 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)) {
+ glfwPollEvents();
+
+ double currTime = glfwGetTime();
+ double deltaTime = prevTime - currTime;
- { // ImGui stuff
- if (imguiUseOpenGL3) {
- ImGui_ImplOpenGL3_NewFrame();
- } else {
- ImGui_ImplOpenGL2_NewFrame();
+ // 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();
+ {
+ 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;
+ }
}
- ImGui_ImplGlfw_NewFrame();
- ImGui::NewFrame();
- app.Show();
- ImGui::ShowNotifications();
+ int fbWidth = AppConfig::mainWidnowWidth;
+ 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);
- ImGui::Render();
- if (imguiUseOpenGL3) {
- ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
- } else {
- ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
+ { // Regular draw
+ app.Draw(currTime, deltaTime);
}
- }
- glfwSwapBuffers(window);
+ { // ImGui draw
+ 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);
+ }
}
- app.Shutdown();
if (imguiUseOpenGL3) {
ImGui_ImplOpenGL3_Shutdown();