added world mesh

This commit is contained in:
0x01FE 2025-11-10 23:39:58 -06:00
parent 90c99734bf
commit f6de6a6758
6 changed files with 208 additions and 44 deletions

View File

@ -20,6 +20,9 @@ add_executable(VoxelEngine
src/Object3D.cpp src/Object3D.cpp
src/Camera.h src/Camera.h
src/World.h src/World.h
src/World.cpp
src/Mesh.h
src/Mesh.cpp
) )
# --- Configure GLAD (from your src/ and include/ folders) --- # --- Configure GLAD (from your src/ and include/ folders) ---
@ -38,4 +41,4 @@ target_include_directories(VoxelEngine PUBLIC
# 2. Tell CMake to link against the specific GLFW .lib file # 2. Tell CMake to link against the specific GLFW .lib file
target_link_libraries(VoxelEngine PUBLIC target_link_libraries(VoxelEngine PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/vendor/lib-vc2022/glfw3.lib ${CMAKE_CURRENT_SOURCE_DIR}/vendor/lib-vc2022/glfw3.lib
) )

56
src/Mesh.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "Mesh.h"
Mesh::Mesh() : m_VAO(0), m_VBO(0), m_EBO(0), m_indexCount(0) {}
Mesh::~Mesh() {
glDeleteVertexArrays(1, &m_VAO);
glDeleteBuffers(1, &m_VBO);
glDeleteBuffers(1, &m_EBO);
}
void Mesh::init() {
// Generate all the OpenGL objects
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
glGenBuffers(1, &m_EBO);
// Bind the VAO and set up the vertex attributes
glBindVertexArray(m_VAO);
// 1. Bind VBO
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
// 2. Set up attributes (this layout is now saved in the VAO)
// Position Attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Normal Attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 3. Bind EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
// 4. Unbind VAO (good practice)
glBindVertexArray(0);
}
void Mesh::uploadData(const std::vector<float> &vboData, const std::vector<unsigned int> &eboData) {
m_indexCount = eboData.size();
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, vboData.size() * sizeof(float), vboData.data(), GL_STATIC_DRAW);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, eboData.size() * sizeof(unsigned int), eboData.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
}
void Mesh::draw() {
if (m_indexCount == 0) return;
glBindVertexArray(m_VAO);
glDrawElements(GL_TRIANGLES, m_indexCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
}

27
src/Mesh.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef MESH_H
#define MESH_H
#include <vector>
#include <glad/glad.h>
class Mesh {
public:
Mesh();
~Mesh(); // Destructor to clean up GPU memory
// Initializes the VAO and buffer objects
void init();
// Uploads mesh data to the GPU
void uploadData(const std::vector<float>& vboData, const std::vector<unsigned int>& eboData);
// Binds the VAO and draws the mesh
void draw();
private:
unsigned int m_VAO, m_VBO, m_EBO;
size_t m_indexCount;
};
#endif MESH_H

98
src/World.cpp Normal file
View File

@ -0,0 +1,98 @@
#include "World.h"
#include <vector>
const int VERTEX_SIZE = 6;
const float topFace[24] = {
// x, y, z, nx, ny, nz
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f
};
const float bottomFace[24] = {
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f
};
const float rightFace[24] = {
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f
};
const float leftFace[24] = {
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f
};
const float frontFace[24] = {
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
const float backFace[24] = {
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f
};
void addFace(glm::ivec3 pos, const float *faceVertices, std::vector<float> &vbo, std::vector<unsigned int> &ebo) {
unsigned int vIndex = vbo.size() / VERTEX_SIZE;
for (int i = 0; i < 4; i++) {
const float* v = &faceVertices[i * VERTEX_SIZE];
vbo.push_back(v[0] + pos.x);
vbo.push_back(v[1] + pos.y);
vbo.push_back(v[2] + pos.z);
vbo.push_back(v[3]);
vbo.push_back(v[4]);
vbo.push_back(v[5]);
}
ebo.push_back(vIndex + 0);
ebo.push_back(vIndex + 1);
ebo.push_back(vIndex + 2);
ebo.push_back(vIndex + 0);
ebo.push_back(vIndex + 2);
ebo.push_back(vIndex + 3);
}
World::World() {
m_mesh.init();
}
Mesh& World::getMesh() {
return m_mesh;
}
void World::generateMesh() {
std::vector<float> vboData;
std::vector<unsigned int> eboData;
for (const glm::ivec3 pos : voxels) {
if (voxels.count(pos + glm::ivec3(0, 1, 0)) == 0) {
addFace(pos, topFace, vboData, eboData);
}
if (voxels.count(pos + glm::ivec3(0, -1, 0)) == 0) {
addFace(pos, bottomFace, vboData, eboData);
}
if (voxels.count(pos + glm::ivec3(1, 0, 0)) == 0) {
addFace(pos, rightFace, vboData, eboData);
}
if (voxels.count(pos + glm::ivec3(-1, 0, 0)) == 0) {
addFace(pos, leftFace, vboData, eboData);
}
if (voxels.count(pos + glm::ivec3(0, 0, 1)) == 0) {
addFace(pos, frontFace, vboData, eboData);
}
if (voxels.count(pos + glm::ivec3(0, 0, -1)) == 0) {
addFace(pos, backFace, vboData, eboData);
}
}
// Now, upload this data to our mesh object
m_mesh.uploadData(vboData, eboData);
}

View File

@ -5,6 +5,8 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "Mesh.h"
// Hash function for glm::ivec3 to use with unordered_set // Hash function for glm::ivec3 to use with unordered_set
namespace std { namespace std {
template <> template <>
@ -25,6 +27,15 @@ class World
{ {
public: public:
std::unordered_set<glm::ivec3> voxels; std::unordered_set<glm::ivec3> voxels;
World();
void generateMesh();
Mesh& getMesh();
private:
Mesh m_mesh;
}; };
#endif WORLD_H #endif WORLD_H

View File

@ -238,35 +238,9 @@ int main() {
} }
world.voxels.insert(glm::ivec3(7, 0, 13)); world.voxels.insert(glm::ivec3(7, 0, 13));
std::cout << "Generating world mesh..." << std::endl;
unsigned int VBO, VAO, EBO; world.generateMesh();
glGenVertexArrays(1, &VAO); // 1. Create Vertex Array Object (VAO) std::cout << "Mesh generated!" << std::endl;
glGenBuffers(1, &VBO); // 2. Create Vertex Buffer Object (VBO)
glGenBuffers(1, &EBO);
glBindVertexArray(VAO); // 3. Bind the VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 4. Bind the VBO
// 5. Copy vertex data into VBO's memory
glBufferData(GL_ARRAY_BUFFER, cube.VBO_buffer.size() * sizeof(float), &cube.VBO_buffer.front(), GL_STATIC_DRAW);
// 6. Tell OpenGL how to interpret the vertex data
// Position Attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0); // Enable the vertex attribute (location 0)
// Normal Attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 6.5 Setup EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, cube.EBO_buffer.size() * sizeof(unsigned int), &cube.EBO_buffer.front(), GL_STATIC_DRAW);
// Unbind VBO and VAO (optional, but good practice)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
if (WIREFRAME_MODE) if (WIREFRAME_MODE)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@ -294,27 +268,26 @@ int main() {
view = camera.getView(); view = camera.getView();
shader.use();
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 mvp = projection * view * model;
shader.setMat4("u_mvp", mvp);
// ---- PASS 1: Draw solid grey cubes ---- // ---- PASS 1: Draw solid grey cubes ----
glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0); // Push solid faces "back" glPolygonOffset(1.0, 1.0); // Push solid faces "back"
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
shader.setVec3("u_Color", glm::vec3(0.5, 0.5, 0.5));
glm::vec3 solidColor = glm::vec3(0.5, 0.5, 0.5); // Grey world.getMesh().draw();
for (glm::ivec3 voxel_pos : world.voxels) {
// [UPDATED] Pass the grey color
draw_cube(voxel_pos, shader, VAO, cube.EBO_buffer.size(), view, projection, solidColor);
}
glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_POLYGON_OFFSET_FILL);
// ---- PASS 2: Draw wireframe on top ---- // ---- PASS 2: Draw wireframe on top ----
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Just the lines glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Just the lines
shader.setVec3("u_Color", glm::vec3(1.0, 1.0, 1.0));
glm::vec3 wireframeColor = glm::vec3(1.0, 1.0, 1.0); // White world.getMesh().draw();
for (glm::ivec3 voxel_pos : world.voxels) {
// [UPDATED] Pass the white wireframe color
draw_cube(voxel_pos, shader, VAO, cube.EBO_buffer.size(), view, projection, wireframeColor);
}
// --- Reset polygon mode for next frame (good practice) --- // --- Reset polygon mode for next frame (good practice) ---
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@ -332,10 +305,6 @@ int main() {
glfwPollEvents(); glfwPollEvents();
} }
// 7. --- Cleanup ---
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glfwTerminate(); // Clean up GLFW glfwTerminate(); // Clean up GLFW
return 0; return 0;
} }