2025-04-06 02:03:23 +00:00
|
|
|
#include <iostream>
|
2025-04-06 03:14:06 +00:00
|
|
|
#include <cmath>
|
2025-04-06 04:20:54 +00:00
|
|
|
|
2025-04-06 02:09:28 +00:00
|
|
|
#include <GL/glew.h>
|
2025-04-06 02:03:23 +00:00
|
|
|
#include <GLFW/glfw3.h>
|
2025-04-06 04:20:54 +00:00
|
|
|
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
|
2025-04-06 02:03:23 +00:00
|
|
|
#include "imgui.h"
|
|
|
|
#include "imgui_impl_glfw.h"
|
|
|
|
#include "imgui_impl_opengl3.h"
|
2025-04-06 04:20:54 +00:00
|
|
|
|
2025-04-06 03:14:06 +00:00
|
|
|
#include "VoxelGame.h"
|
|
|
|
|
2025-04-06 04:20:54 +00:00
|
|
|
// camera globals
|
|
|
|
static glm::vec3 cameraPos = {32.0f, 32.0f, 80.0f};
|
|
|
|
static glm::vec3 cameraFront = {0.0f, 0.0f, -1.0f};
|
|
|
|
static glm::vec3 cameraUp = {0.0f, 1.0f, 0.0f};
|
|
|
|
static float yaw = -90.0f, pitch = 0.0f;
|
|
|
|
static bool firstMouse = true;
|
|
|
|
static float lastX, lastY;
|
2025-04-06 03:14:06 +00:00
|
|
|
|
2025-04-06 04:20:54 +00:00
|
|
|
static void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
|
2025-04-06 03:14:06 +00:00
|
|
|
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL)
|
2025-04-06 04:20:54 +00:00
|
|
|
return; // do not rotate if cursor is free
|
|
|
|
|
2025-04-06 03:14:06 +00:00
|
|
|
if (firstMouse) {
|
2025-04-06 04:20:54 +00:00
|
|
|
lastX = float(xpos);
|
|
|
|
lastY = float(ypos);
|
2025-04-06 03:14:06 +00:00
|
|
|
firstMouse = false;
|
|
|
|
}
|
2025-04-06 04:20:54 +00:00
|
|
|
float dx = float(xpos) - lastX;
|
|
|
|
float dy = lastY - float(ypos);
|
|
|
|
lastX = float(xpos);
|
|
|
|
lastY = float(ypos);
|
|
|
|
|
|
|
|
const float sensitivity = 0.1f;
|
|
|
|
dx *= sensitivity;
|
|
|
|
dy *= sensitivity;
|
|
|
|
|
|
|
|
yaw += dx;
|
|
|
|
pitch += dy;
|
|
|
|
pitch = std::clamp(pitch, -89.0f, 89.0f);
|
|
|
|
|
|
|
|
float ry = glm::radians(yaw);
|
|
|
|
float rp = glm::radians(pitch);
|
|
|
|
cameraFront = glm::normalize(glm::vec3(
|
|
|
|
cos(ry)*cos(rp),
|
|
|
|
sin(rp),
|
|
|
|
sin(ry)*cos(rp)
|
|
|
|
));
|
2025-04-06 03:14:06 +00:00
|
|
|
}
|
2025-04-06 02:03:23 +00:00
|
|
|
|
2025-04-06 04:20:54 +00:00
|
|
|
static GLFWwindow* initWindow(int w, int h, const char* title) {
|
|
|
|
if (!glfwInit()) return nullptr;
|
2025-04-06 02:03:23 +00:00
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
2025-04-06 04:20:54 +00:00
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
#ifdef __APPLE__
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
|
|
|
#endif
|
|
|
|
GLFWwindow* win = glfwCreateWindow(w, h, title, nullptr, nullptr);
|
|
|
|
if (!win) { glfwTerminate(); return nullptr; }
|
|
|
|
glfwMakeContextCurrent(win);
|
2025-04-06 03:14:06 +00:00
|
|
|
glewExperimental = GL_TRUE;
|
|
|
|
if (glewInit() != GLEW_OK) {
|
2025-04-06 04:20:54 +00:00
|
|
|
glfwDestroyWindow(win);
|
|
|
|
glfwTerminate();
|
2025-04-06 03:14:06 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2025-04-06 04:20:54 +00:00
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
glfwSetCursorPosCallback(win, mouse_callback);
|
|
|
|
// start with cursor disabled
|
|
|
|
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
|
|
|
lastX = w / 2.0f;
|
|
|
|
lastY = h / 2.0f;
|
|
|
|
return win;
|
2025-04-06 02:03:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
2025-04-06 04:20:54 +00:00
|
|
|
const int SCR_W = 1280, SCR_H = 720;
|
|
|
|
GLFWwindow* window = initWindow(SCR_W, SCR_H, "Voxel CSM");
|
|
|
|
if (!window) return -1;
|
|
|
|
|
|
|
|
// ImGui
|
2025-04-06 02:03:23 +00:00
|
|
|
IMGUI_CHECKVERSION();
|
|
|
|
ImGui::CreateContext();
|
|
|
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
|
|
|
ImGui_ImplOpenGL3_Init("#version 330");
|
2025-04-06 04:20:54 +00:00
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
|
|
|
|
// Our game
|
2025-04-06 02:03:23 +00:00
|
|
|
VoxelGame game;
|
2025-04-06 04:20:54 +00:00
|
|
|
if (!game.init(SCR_W, SCR_H)) {
|
|
|
|
std::cerr << "Failed to init VoxelGame\n";
|
2025-04-06 02:03:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2025-04-06 04:20:54 +00:00
|
|
|
|
|
|
|
float lastFrame = 0.0f;
|
|
|
|
bool cursorEnabled = false;
|
|
|
|
bool f1Pressed = false;
|
|
|
|
|
2025-04-06 02:03:23 +00:00
|
|
|
while (!glfwWindowShouldClose(window)) {
|
2025-04-06 04:20:54 +00:00
|
|
|
float now = float(glfwGetTime());
|
|
|
|
float dt = now - lastFrame;
|
|
|
|
lastFrame = now;
|
|
|
|
|
2025-04-06 02:03:23 +00:00
|
|
|
glfwPollEvents();
|
2025-04-06 04:20:54 +00:00
|
|
|
|
|
|
|
// Toggle cursor with F1 (when ImGui not capturing)
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_PRESS && !io.WantCaptureMouse) {
|
2025-04-06 03:14:06 +00:00
|
|
|
if (!f1Pressed) {
|
|
|
|
cursorEnabled = !cursorEnabled;
|
2025-04-06 04:20:54 +00:00
|
|
|
glfwSetInputMode(window, GLFW_CURSOR,
|
|
|
|
cursorEnabled ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED);
|
2025-04-06 03:14:06 +00:00
|
|
|
f1Pressed = true;
|
2025-04-06 04:20:54 +00:00
|
|
|
firstMouse = true; // reset for mouse callback
|
2025-04-06 03:14:06 +00:00
|
|
|
}
|
|
|
|
} else if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_RELEASE) {
|
|
|
|
f1Pressed = false;
|
|
|
|
}
|
2025-04-06 04:20:54 +00:00
|
|
|
|
|
|
|
// WASD movement
|
|
|
|
float speed = 5.0f * dt;
|
|
|
|
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
|
|
|
cameraPos += cameraFront * speed;
|
|
|
|
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
|
|
|
cameraPos -= cameraFront * speed;
|
|
|
|
glm::vec3 right = glm::normalize(glm::cross(cameraFront, cameraUp));
|
|
|
|
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
|
|
|
|
cameraPos -= right * speed;
|
|
|
|
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
|
|
|
cameraPos += right * speed;
|
|
|
|
|
|
|
|
// Build view/proj
|
|
|
|
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
|
|
|
|
glm::mat4 proj = glm::perspective(glm::radians(45.0f),
|
|
|
|
float(SCR_W)/SCR_H, 0.1f, 200.0f);
|
|
|
|
|
|
|
|
// Update & render
|
|
|
|
game.update(dt, cameraPos);
|
|
|
|
game.render(view, proj);
|
|
|
|
|
|
|
|
// Debug UI
|
2025-04-06 02:03:23 +00:00
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
|
|
ImGui_ImplGlfw_NewFrame();
|
|
|
|
ImGui::NewFrame();
|
|
|
|
game.debugUI();
|
|
|
|
ImGui::Render();
|
|
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
2025-04-06 04:20:54 +00:00
|
|
|
|
2025-04-06 02:03:23 +00:00
|
|
|
glfwSwapBuffers(window);
|
|
|
|
}
|
2025-04-06 04:20:54 +00:00
|
|
|
|
|
|
|
// Cleanup
|
2025-04-06 02:03:23 +00:00
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
|
|
ImGui_ImplGlfw_Shutdown();
|
|
|
|
ImGui::DestroyContext();
|
|
|
|
glfwDestroyWindow(window);
|
|
|
|
glfwTerminate();
|
|
|
|
return 0;
|
|
|
|
}
|