Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
422 changes: 211 additions & 211 deletions .clang-tidy

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ build
.vscode

# imgui
imgui.ini
imgui.ini

# trace
*.trace
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# Add source files
file(GLOB SOURCES "src/*.cpp")
file(GLOB SOURCES "src/main.cpp")

if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Xlinker /errorlimit:0")
endif()

# Add GLAD
add_library(glad libs/glad/src/glad.c)
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Voxel Engine

![frustum-demo (1)](https://github.com/user-attachments/assets/d3c4ed18-d3ca-42a8-bc0a-ac5dd6c6debc)
![preview](https://github.com/user-attachments/assets/f4f6eb2c-5e47-4f15-8a8e-db896befeffd)

## Overview
![overview](assets/overview.png)

### Instructions

Make sure to clone this repository recursively!
```
Expand Down
Binary file added assets/overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions src/Camera.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef CAMERA_H
#define CAMERA_H

#include "Frustum.h"

// Frustum createFrustumFromCamera(Camera camera);

struct Camera {
// TODO: figure out camera following
// Entity* attachedTo;
bool isFree = true;
// camera
float cameraSpeedMultiplier = 20.0f;
glm::vec3 cameraPos = glm::vec3(0.0f, 2.0f, 1.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);

glm::vec3 cameraRight = glm::vec3(1.0f, 0.0f, 0.0f);

// Calculate the left vector (opposite of right)
glm::vec3 cameraLeft = -cameraRight;

// The top vector is the same as the up vector in this case
glm::vec3 cameraTop = cameraUp;

bool firstMouse = true;
float yaw = -90.0f; // yaw is initialized to -90.0 degrees since a yaw of
// 0.0 results in a direction vector pointing to the
// right so we initially rotate a bit to the left.
float pitch = 0.0f;
float lastX = 800.0f / 2.0;
float lastY = 600.0 / 2.0;
float fov = 45.0f;

float zNear = 0.1f;
float zFar = 1000.0f;

Frustum frustum;

Camera();
};

Frustum createFrustumFromCamera(Camera camera) {
Frustum frustum;

float aspect = (float)SCR_WIDTH / (float)SCR_HEIGHT;
const float halfVSide =
camera.zFar * tanf((float)glm::radians(camera.fov) * .5f);
const float halfHSide = halfVSide * aspect;
const glm::vec3 frontMultFar = camera.zFar * camera.cameraFront;

frustum.planes[Frustum::FRUSTUM_NEAR] =
Plane3(camera.cameraPos + camera.zNear * camera.cameraFront,
camera.cameraFront);
camera.frustum.planes[Frustum::FRUSTUM_FAR] =
Plane3(camera.cameraPos + frontMultFar, -camera.cameraFront);
camera.frustum.planes[Frustum::FRUSTUM_RIGHT] =
Plane3(camera.cameraPos,
glm::cross(frontMultFar - camera.cameraRight * halfHSide,
camera.cameraUp));
frustum.planes[Frustum::FRUSTUM_LEFT] =
Plane3(camera.cameraPos,
glm::cross(camera.cameraUp,
frontMultFar + camera.cameraRight * halfHSide));
frustum.planes[Frustum::FRUSTUM_TOP] =
Plane3(camera.cameraPos,
glm::cross(camera.cameraRight,
frontMultFar - camera.cameraUp * halfVSide));
frustum.planes[Frustum::FRUSTUM_BOTTOM] = Plane3(
camera.cameraPos, glm::cross(frontMultFar + camera.cameraUp * halfVSide,
camera.cameraRight));

return frustum;
}

Camera::Camera() { frustum = createFrustumFromCamera(*this); }

#endif // CAMERA_H
11 changes: 6 additions & 5 deletions src/Chunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "ChunkMesh.h"
#include <glm/glm.hpp>
#include <learnopengl/shader_m.h>
#include <cstdlib>

/*
TODO LIST:
Expand Down Expand Up @@ -39,7 +38,7 @@ struct Chunk {
void unload();
void rebuildMesh();
void setup();
void render();
void render(Camera camera);
// BoundingBox getBoundingBox();
void initialize();
void AddCubeFace(ChunkMesh *mesh, int p1, int p2, int p3, int p4,
Expand Down Expand Up @@ -148,7 +147,7 @@ void Chunk::setup() {
}

// renders the chunk
void Chunk::render() { DrawChunkMesh(mesh, material, chunkPosition); }
void Chunk::render(Camera camera) { DrawChunkMesh(camera, mesh, material, chunkPosition); }

// BoundingBox Chunk::getBoundingBox() {
// glm::vec3 max = {chunkPosition.x + CHUNK_SIZE * Block::BLOCK_RENDER_SIZE,
Expand All @@ -164,8 +163,10 @@ void Chunk::initialize() {
for (int y = 0; y < CHUNK_SIZE; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
int index = getIndex(x, y, z);
blocks[index].isActive = (rand() % 2 == 0) ? false : true;
blocks[index].blockType = (rand() % 2 == 0) ? BlockType::Grass : BlockType::Sand;
// NOTE: there seems to be a "pattern" in some chunks - is the same seed be initted across threads?
// seems like it does: https://en.cppreference.com/w/cpp/numeric/random/rand
blocks[index].isActive = (std::rand() % 2 == 0) ? false : true;
blocks[index].blockType = (std::rand() % 2 == 0) ? BlockType::Grass : BlockType::Sand;
// blocks[index].isActive = true;
}
}
Expand Down
42 changes: 22 additions & 20 deletions src/ChunkManager.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef CHUNKMANAGER_H
#define CHUNKMANAGER_H

#include "Chunk.h"

#include <learnopengl/shader_m.h>
#include <unordered_map>
#include <vector>
Expand Down Expand Up @@ -73,16 +75,15 @@ struct ChunkManager {
ChunkManager(unsigned int _chunkGenDistance,
unsigned int _chunkRenderDistance, Shader *_terrainShader);
~ChunkManager();
void update(float dt, glm::vec3 newCameraPosition,
glm::vec3 newCameraLookAt);
void updateAsyncChunker(glm::vec3 newCameraPosition);
void update(float dt, Camera newCamera);
void updateAsyncChunker(Camera newCamera);
void updateLoadList();
void updateSetupList();
void updateRebuildList();
void updateFlagsList();
void updateUnloadList(glm::vec3 newCameraPosition);
void updateVisibilityList(glm::vec3 newCameraPosition);
void updateRenderList(glm::vec3 newCameraPosition);
void updateRenderList(glm::vec3 newCameraPosition, Frustum frustum);

void pregenerateChunks();

Expand All @@ -91,7 +92,7 @@ struct ChunkManager {
GetChunkGenRange(glm::vec3 newCameraPosition);
std::pair<glm::vec3, glm::vec3>
GetChunkRenderRange(glm::vec3 newCameraPosition);
void render();
void render(Camera newCamera);

Shader *terrainShader;

Expand All @@ -104,8 +105,7 @@ struct ChunkManager {

bool genChunk;
bool forceVisibilityupdate;
glm::vec3 cameraPosition;
glm::vec3 cameraLookAt;
Camera camera;

unsigned int chunkGenDistance;
unsigned int chunkRenderDistance;
Expand All @@ -130,8 +130,8 @@ ChunkManager::ChunkManager(unsigned int _chunkGenDistance,

ChunkManager::~ChunkManager() {}

void ChunkManager::update(float dt, glm::vec3 newCameraPosition,
glm::vec3 newCameraLookAt) {
// TODO: surely we can just pass the camera right?
void ChunkManager::update(float dt, Camera newCamera) {
// if (genChunk) {
// updateAsyncChunker(newCameraPosition);
// // asyncChunkFuture = std::async(&ChunkManager::updateAsyncChunker,
Expand All @@ -145,10 +145,11 @@ void ChunkManager::update(float dt, glm::vec3 newCameraPosition,
updateRebuildList();
// updateFlagsList();
// updateUnloadList(newCameraPosition);
updateVisibilityList(newCameraPosition);
updateRenderList(newCameraPosition);
cameraPosition = newCameraPosition;
cameraLookAt = newCameraLookAt;
updateVisibilityList(newCamera.cameraPos);
updateRenderList(newCamera.cameraPos, newCamera.frustum);
camera = newCamera;
// cameraPosition = camera.cameraPos;
// cameraLookAt = newCameraLookAt;
}

float roundUp(float number, float fixedBase) {
Expand Down Expand Up @@ -222,7 +223,7 @@ ChunkManager::GetChunkRenderRange(glm::vec3 newCameraPosition) {

void ChunkManager::pregenerateChunks() {
int halfWorldSize =
(WORLD_SIZE * (Chunk::CHUNK_SIZE * Block::BLOCK_RENDER_SIZE)) / 2;
(WORLD_SIZE * (Chunk::CHUNK_SIZE * Block::BLOCK_RENDER_SIZE)) / 2;

std::vector<std::future<void>> futures; // Store futures to manage threads

Expand Down Expand Up @@ -267,13 +268,13 @@ void ChunkManager::pregenerateChunks() {
}
}

void ChunkManager::updateAsyncChunker(glm::vec3 newCameraPosition) {
if (newCameraPosition == cameraPosition) {
void ChunkManager::updateAsyncChunker(Camera newCamera) {
if (newCamera.cameraPos == camera.cameraPos) {
return;
}

std::pair<glm::vec3, glm::vec3> chunkRange =
GetChunkGenRange(newCameraPosition);
GetChunkGenRange(camera.cameraPos);
glm::vec3 start = chunkRange.first;
glm::vec3 end = chunkRange.second;

Expand Down Expand Up @@ -444,7 +445,8 @@ void ChunkManager::updateRebuildList() {
// chunkUnloadList.clear();
// }

void ChunkManager::updateRenderList(glm::vec3 newCameraPosition) {
void ChunkManager::updateRenderList(glm::vec3 newCameraPosition,
Frustum frustum) {
// Clear the render list each frame BEFORE we do our tests to see what
// chunks should be rendered
chunkRenderList.clear();
Expand Down Expand Up @@ -497,9 +499,9 @@ void ChunkManager::updateVisibilityList(glm::vec3 newCameraPosition) {
}
}

void ChunkManager::render() {
void ChunkManager::render(Camera newCamera) {
for (Chunk *chunk : chunkRenderList) {
chunk->render();
chunk->render(newCamera);
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/ChunkMesh.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#ifndef MESH_H
#define MESH_H

#include "smolgl.h"
// #include "smolgl.h"
#include "Camera.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
Expand Down Expand Up @@ -124,14 +126,14 @@ void UnloadChunkMesh(ChunkMesh mesh) {
free(mesh.indices);
}

void DrawChunkMesh(ChunkMesh mesh, Material material, glm::vec3 position) {
void DrawChunkMesh(Camera camera, ChunkMesh mesh, Material material, glm::vec3 position) {
material.shader->use();

glm::mat4 projection = glm::perspective(
glm::radians(fov), (float)SCR_WIDTH / SCR_HEIGHT, zNear, zFar);
glm::radians(camera.fov), (float)SCR_WIDTH / SCR_HEIGHT, camera.zNear, camera.zFar);
material.shader->setMat4("projection", projection);

glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
glm::mat4 view = glm::lookAt(camera.cameraPos, camera.cameraPos + camera.cameraFront, camera.cameraUp);
material.shader->setMat4("view", view);

glm::mat4 model = glm::mat4(1.0f);
Expand Down
34 changes: 34 additions & 0 deletions src/Component.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef COMPONENT_H
#define COMPONENT_H

#include <cstdint>
#include <bitset>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

using ComponentType = std::uint8_t;

const ComponentType MAX_COMPONENTS = 32;
using Signature = std::bitset<MAX_COMPONENTS>;

struct Gravity
{
glm::vec3 force;
};

struct RigidBody
{
glm::vec3 velocity;
glm::vec3 acceleration;
};

struct Transform
{
glm::vec3 position;
glm::quat rotation;
glm::vec3 scale;
};

#endif // COMPONENT_H
Loading