small-projects/cpp-voxel-engine/main.cpp
2025-04-05 22:14:06 -05:00

194 lines
6.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <cmath>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include "imgui.h"
#include "imgui_internal.h" // For Im_PI
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include "VoxelGame.h"
// Global camera variables.
float yaw = -90.0f;
float pitch = 0.0f;
float lastX = 400.0f, lastY = 300.0f;
bool firstMouse = true;
float cameraPos[3] = {32.0f, 32.0f, 80.0f};
float cameraFront[3] = {0.0f, 0.0f, -1.0f};
float cameraUp[3] = {0.0f, 1.0f, 0.0f};
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL)
return;
if (firstMouse) {
lastX = static_cast<float>(xpos);
lastY = static_cast<float>(ypos);
firstMouse = false;
}
float xoffset = static_cast<float>(xpos) - lastX;
float yoffset = lastY - static_cast<float>(ypos);
lastX = static_cast<float>(xpos);
lastY = static_cast<float>(ypos);
float sensitivity = 0.1f;
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
if (pitch > 89.0f) pitch = 89.0f;
if (pitch < -89.0f) pitch = -89.0f;
float radYaw = yaw * static_cast<float>(IM_PI) / 180.0f;
float radPitch = pitch * static_cast<float>(IM_PI) / 180.0f;
cameraFront[0] = cos(radYaw) * cos(radPitch);
cameraFront[1] = sin(radPitch);
cameraFront[2] = sin(radYaw) * cos(radPitch);
float len = std::sqrt(cameraFront[0]*cameraFront[0] +
cameraFront[1]*cameraFront[1] +
cameraFront[2]*cameraFront[2]);
cameraFront[0] /= len;
cameraFront[1] /= len;
cameraFront[2] /= len;
}
GLFWwindow* initWindow(int width, int height, const char* title) {
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW\n";
return nullptr;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
GLFWwindow* window = glfwCreateWindow(width, height, title, nullptr, nullptr);
if (!window) {
std::cerr << "Failed to create GLFW window\n";
glfwTerminate();
return nullptr;
}
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "GLEW Error\n";
return nullptr;
}
return window;
}
int main() {
GLFWwindow* window = initWindow(800, 600, "Voxel Game");
if (!window)
return -1;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 330");
VoxelGame game;
if (!game.init()) {
std::cerr << "Failed to initialize game\n";
return -1;
}
float deltaTime = 0.0f, lastFrame = 0.0f;
static bool cursorEnabled = false;
static bool f1Pressed = false;
while (!glfwWindowShouldClose(window)) {
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glfwPollEvents();
// Toggle cursor lock with F1 (if ImGui isnt capturing the mouse).
if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_PRESS && !ImGui::GetIO().WantCaptureMouse) {
if (!f1Pressed) {
cursorEnabled = !cursorEnabled;
glfwSetInputMode(window, GLFW_CURSOR, cursorEnabled ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED);
f1Pressed = true;
firstMouse = true;
}
} else if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_RELEASE) {
f1Pressed = false;
}
float cameraSpeed = 5.0f * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
cameraPos[0] += cameraFront[0] * cameraSpeed;
cameraPos[1] += cameraFront[1] * cameraSpeed;
cameraPos[2] += cameraFront[2] * cameraSpeed;
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
cameraPos[0] -= cameraFront[0] * cameraSpeed;
cameraPos[1] -= cameraFront[1] * cameraSpeed;
cameraPos[2] -= cameraFront[2] * cameraSpeed;
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
float right[3] = {
cameraFront[1]*cameraUp[2] - cameraFront[2]*cameraUp[1],
cameraFront[2]*cameraUp[0] - cameraFront[0]*cameraUp[2],
cameraFront[0]*cameraUp[1] - cameraFront[1]*cameraUp[0]
};
float rLen = std::sqrt(right[0]*right[0] + right[1]*right[1] + right[2]*right[2]);
right[0] /= rLen; right[1] /= rLen; right[2] /= rLen;
cameraPos[0] -= right[0] * cameraSpeed;
cameraPos[1] -= right[1] * cameraSpeed;
cameraPos[2] -= right[2] * cameraSpeed;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
float right[3] = {
cameraFront[1]*cameraUp[2] - cameraFront[2]*cameraUp[1],
cameraFront[2]*cameraUp[0] - cameraFront[0]*cameraUp[2],
cameraFront[0]*cameraUp[1] - cameraFront[1]*cameraUp[0]
};
float rLen = std::sqrt(right[0]*right[0] + right[1]*right[1] + right[2]*right[2]);
right[0] /= rLen; right[1] /= rLen; right[2] /= rLen;
cameraPos[0] += right[0] * cameraSpeed;
cameraPos[1] += right[1] * cameraSpeed;
cameraPos[2] += right[2] * cameraSpeed;
}
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 800.0/600.0, 0.1, 200.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float centerX = cameraPos[0] + cameraFront[0];
float centerY = cameraPos[1] + cameraFront[1];
float centerZ = cameraPos[2] + cameraFront[2];
gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
centerX, centerY, centerZ,
cameraUp[0], cameraUp[1], cameraUp[2]);
game.update(deltaTime, cameraPos);
game.render();
game.debugUI();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}