This commit is contained in:
2024-08-27 01:48:58 +02:00
parent 68abd9eefe
commit 346bc96ca8
44 changed files with 2593 additions and 546 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
[Bb]uild/*
!*/.gitkeep
cmake-build-debug/*

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
gloom

2
.idea/VoxelEngine.iml generated Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/VoxelEngine.iml" filepath="$PROJECT_DIR$/.idea/VoxelEngine.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -4,6 +4,12 @@
cmake_minimum_required (VERSION 3.0)
project (gloom)
# set c++ 17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
#
# CMake setup
#
@@ -78,3 +84,15 @@ target_link_libraries (${PROJECT_NAME}
${GLAD_LIBRARIES})
set_target_properties (${PROJECT_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_NAME})
## Copy shaders to build directory with a symlink
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_SOURCE_DIR}/gloom/shaders
$<TARGET_FILE_DIR:${PROJECT_NAME}>/shaders)
## Copy assets folder to build folder
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/gloom/assets
$<TARGET_FILE_DIR:${PROJECT_NAME}>/assets)

BIN
gloom/assets/dirt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,8 +1,17 @@
#version 430 core
#version 460 core
precision highp float;
out vec4 color;
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
in vec3 pos;
uniform sampler2D ourTexture;
void main()
{
color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}
FragColor = texture(ourTexture, TexCoord);
// FragColor = vec4(1.0f, TexCoord.x, 1.0f, 1.0);
// FragColor = vec4(137 / 255, 85 / 255, 95 / 255, 1.0f);
}

View File

@@ -0,0 +1,34 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main()
{
FragColor = texture(ourTexture, TexCoord);
// FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0);
}

View File

@@ -1,8 +1,20 @@
#version 430 core
#version 460 core
precision highp float;
in vec3 position;
layout (location = 0) in vec3 aPos;
//layout (location = 1) in vec3 aColor;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
out vec3 pos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = vec4(position, 1.0f);
}
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord;
pos = aPos;
}

5
gloom/src/Block.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by Bram on 26/08/2024.
//
#include "Block.h"

26
gloom/src/Block.h Normal file
View File

@@ -0,0 +1,26 @@
//
// Created by Bram on 26/08/2024.
//
#ifndef GLOOM_BLOCK_H
#define GLOOM_BLOCK_H
//This will hold all the data of a block, but not the mesh since this is held by the chunk
#include "BlockType.h"
class Block {
public:
Block(BlockType type) : m_type(type) {}
BlockType getType() const { return m_type; }
private:
BlockType m_type;
};
#endif //GLOOM_BLOCK_H

17
gloom/src/BlockType.h Normal file
View File

@@ -0,0 +1,17 @@
//
// Created by Bram on 26/08/2024.
//
#ifndef GLOOM_BLOCKTYPE_H
#define GLOOM_BLOCKTYPE_H
enum class BlockType{
AIR = 0,
DIRT = 1,
STONE = 2,
GONCALO = 3,
SNOW = 4,
GRASS = 5
};
#endif //GLOOM_BLOCKTYPE_H

134
gloom/src/Chunk.cpp Normal file
View File

@@ -0,0 +1,134 @@
//
// Created by Bram on 25/08/2024.
//
#include "Chunk.h"
#include "gloom/Mesh.h"
#include "Cube.h"
#include "gloom/Singleton.h"
#include <vector>
#include "World.h"
void Chunk::loadBlocks() {
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
glm::vec3 actualPos = glm::vec3(x, y, z) + glm::vec3(m_chunkPos.x * CHUNK_SIZE, 0, m_chunkPos.y * CHUNK_SIZE);
BlockType blockType = generateTerrain(actualPos);
if (m_blocks[x][y][z] != nullptr) {
delete m_blocks[x][y][z];
}
m_blocks[x][y][z] = new Block(blockType);
}
}
}
}
void Chunk::loadMesh() {
std::vector<Mesh::Vertex> vertexes{};
std::vector<unsigned int> indices{};
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
//Check direction and call LoadFace on that direction
Block* block = this->getBlock(x, y, z);
if (block->getType() != BlockType::AIR) {
BlockType type = block->getType();
//Get the block in world space using World::GetInstance().getBlock
Block* leftBlock = World::GetInstance().getBlock(x - 1 + m_chunkPos.x * CHUNK_SIZE, y, z + m_chunkPos.y * CHUNK_SIZE);
Block* rightBlock = World::GetInstance().getBlock(x + 1 + m_chunkPos.x * CHUNK_SIZE, y, z + m_chunkPos.y * CHUNK_SIZE);
Block* bottomBlock = World::GetInstance().getBlock(x + m_chunkPos.x * CHUNK_SIZE, y - 1, z + m_chunkPos.y * CHUNK_SIZE);
Block* topBlock = World::GetInstance().getBlock(x + m_chunkPos.x * CHUNK_SIZE, y + 1, z + m_chunkPos.y * CHUNK_SIZE);
Block* backBlock = World::GetInstance().getBlock(x + m_chunkPos.x * CHUNK_SIZE, y, z - 1 + m_chunkPos.y * CHUNK_SIZE);
Block* frontBlock = World::GetInstance().getBlock(x + m_chunkPos.x * CHUNK_SIZE, y, z + 1 + m_chunkPos.y * CHUNK_SIZE);
if (leftBlock->getType() == BlockType::AIR) {
Cube::LoadFace(Face::LEFT, vertexes, indices, glm::vec3(x, y, z), type);
}
if (rightBlock->getType() == BlockType::AIR) {
Cube::LoadFace(Face::RIGHT, vertexes, indices, glm::vec3(x, y, z),type);
}
if (bottomBlock->getType() == BlockType::AIR) {
Cube::LoadFace(Face::BOTTOM, vertexes, indices, glm::vec3(x, y, z), type);
}
if (topBlock->getType() == BlockType::AIR) {
Cube::LoadFace(Face::TOP, vertexes, indices, glm::vec3(x, y, z), type);
}
if (backBlock->getType() == BlockType::AIR) {
Cube::LoadFace(Face::FRONT, vertexes, indices, glm::vec3(x, y, z), type);
}
if (frontBlock->getType() == BlockType::AIR) {
Cube::LoadFace(Face::BACK, vertexes, indices, glm::vec3(x, y, z), type);
}
}
}
}
}
m_mesh = Mesh(vertexes, indices);
m_mesh.setPosition(glm::vec3(m_chunkPos.x * CHUNK_SIZE, 0, m_chunkPos.y * CHUNK_SIZE));
m_mesh.setupMesh();
}
Chunk::Chunk(const glm::vec2 &pos): m_chunkPos(pos) {
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
m_blocks[x][y][z] = new Block(BlockType::AIR);
}
}
}
}
BlockType Chunk::generateTerrain(glm::vec3 position) {
double noise = perlin.octave2D_01((position.x * 0.01), (position.z * 0.01), 4);
noise = pow(noise, 3);
int height = noise * 70;
if (position.y > height) {
return BlockType::AIR;
}
else if (position.y == height) {
//snow
int variance = ((float)rand() / RAND_MAX) * 7; //between 0-7
if (position.y > 20 + variance)
return BlockType::SNOW; //snow
return BlockType::GRASS; //grass
}
else {
return BlockType::DIRT; //dirt
}
}
Chunk::Chunk() {
// m_chunkPos = glm::vec2(0, 0);
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
m_blocks[x][y][z] = new Block(BlockType::AIR);
}
}
}
}
Chunk::~Chunk() {
for (int x = 0; x < CHUNK_SIZE; ++x) {
for (int y = 0; y < CHUNK_HEIGHT; ++y) {
for (int z = 0; z < CHUNK_SIZE; ++z) {
delete m_blocks[x][y][z]; // Delete each dynamically allocated Block
m_blocks[x][y][z] = nullptr; // Set the pointer to nullptr to avoid dangling references
}
}
}
}

69
gloom/src/Chunk.h Normal file
View File

@@ -0,0 +1,69 @@
//
// Created by Bram on 25/08/2024.
//
#ifndef GLOOM_CHUNK_H
#define GLOOM_CHUNK_H
#include "gloom/config.hpp"
#include "gloom/Mesh.h"
#include "gloom/PerlinNoise.hpp"
#include "BlockType.h"
#include "Block.h"
enum class ChunkLoadStatus{
GENERATED,
GENERATING,
NOT_GENERATED,
NOT_AVAILABLE,
};
static const int BLOCK_TYPES_COUNT = 4;
class Chunk {
public:
Chunk();
Chunk(const glm::vec2& pos);
~Chunk();
void loadBlocks();
void loadMesh();
void Draw(GLuint shaderProgram) {
m_mesh.draw(shaderProgram);
}
Mesh m_mesh;
BlockType generateTerrain(glm::vec3 position);
Block* getBlock(int x, int y, int z) {
//if out of bounds, return dirt
if (x < 0 || x >= CHUNK_SIZE || y < 0 || y >= CHUNK_HEIGHT || z < 0 || z >= CHUNK_SIZE) {
return new Block(BlockType::AIR);
} else {
if(m_blocks[x][y][z] == nullptr) {
return new Block(BlockType::AIR);
} else {
return m_blocks[x][y][z];
}
}
}
void setBlock(int x, int y, int z, const Block& block) {
m_blocks[x][y][z] = new Block(block.getType());
}
private:
Block* m_blocks[CHUNK_SIZE][CHUNK_HEIGHT][CHUNK_SIZE]{ nullptr };
glm::vec3 m_position;
glm::vec2 m_chunkPos;
};
#endif //GLOOM_CHUNK_H

140
gloom/src/Cube.cpp Normal file
View File

@@ -0,0 +1,140 @@
//
// Created by Bram on 23/08/2024.
//
#include "Cube.h"
glm::vec3 unitVertices[8] = {
glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(1.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(1.0f, 0.0f, 1.0f),
glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 1.0f)
};
unsigned int faceVertices[6][4] = {
{3, 2, 6, 7},
{1, 0, 4, 5},
{4, 0, 3, 7},
{1, 5, 6, 2},
// FRONT (0, 1, 2, 3)
{0, 1, 2, 3},
// BACK (5, 4, 7, 6)
{5, 4, 7, 6}
};
static const glm::vec2 DIRTCOORDS = Cube::getTexCoords(0);
static const glm::vec2 STONECOORDS = Cube::getTexCoords(1);
static const glm::vec2 GONCALOCOORDS = Cube::getTexCoords(2);
static const glm::vec2 GRASSCOORDS = Cube::getTexCoords(3);
static const glm::vec2 SNOWCOORDS = Cube::getTexCoords(4);
Cube::Cube(const glm::vec3 &position, BlockType blockType) : position(position), texture("assets/dirt.png"),
type(blockType) {
// setupCube();
}
void Cube::LoadFace(Face face, std::vector<Mesh::Vertex> &vertices, std::vector<unsigned int> &indices, const glm::vec3 &position, BlockType type) {
glm::vec3 normal;
switch (face) {
case Face::TOP:
normal = glm::vec3(0.0f, 1.0f, 0.0f);
break;
case Face::BOTTOM:
normal = glm::vec3(0.0f, -1.0f, 0.0f);
break;
case Face::LEFT:
normal = glm::vec3(-1.0f, 0.0f, 0.0f);
break;
case Face::RIGHT:
normal = glm::vec3(1.0f, 0.0f, 0.0f);
break;
case Face::FRONT:
normal = glm::vec3(0.0f, 0.0f, 1.0f);
break;
case Face::BACK:
normal = glm::vec3(0.0f, 0.0f, -1.0f);
break;
}
glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f);
glm::vec2 textureOffset = glm::vec2(0.0f, 0.0f);
switch(type){
case BlockType::STONE:
textureOffset = STONECOORDS;
break;
case BlockType::DIRT:
textureOffset = DIRTCOORDS;
break;
case BlockType::GONCALO:
textureOffset = GONCALOCOORDS;
break;
case BlockType::GRASS:
textureOffset = GRASSCOORDS;
break;
case BlockType::SNOW:
textureOffset = SNOWCOORDS;
break;
}
glm::vec2 uvCoordinates[4] = {
glm::vec2(textureOffset.x, textureOffset.y + CELL_HEIGHT),
glm::vec2(textureOffset.x + CELL_WIDTH, textureOffset.y + CELL_HEIGHT),
glm::vec2(textureOffset.x + CELL_WIDTH, textureOffset.y),
glm::vec2(textureOffset.x, textureOffset.y)
};
unsigned int index = vertices.size();
for (int i = 0; i < 4; i++) {
unsigned int vertexIndex = faceVertices[faceToIndex(face)][i];
Mesh::Vertex v;
v.position = unitVertices[vertexIndex] + position;
v.texCoords = uvCoordinates[i];
vertices.push_back(v);
}
indices.push_back(index);
indices.push_back(index + 1);
indices.push_back(index + 2);
indices.push_back(index);
indices.push_back(index + 2);
indices.push_back(index + 3);
}
void Cube::LoadAllFaces(std::vector<Mesh::Vertex> &vertices, std::vector<unsigned int> &indices, const glm::vec3 &position, BlockType type) {
Cube::LoadFace(Face::TOP, vertices, indices, position, type);
Cube::LoadFace(Face::BOTTOM, vertices, indices, position, type);
Cube::LoadFace(Face::LEFT, vertices, indices, position, type);
Cube::LoadFace(Face::RIGHT, vertices, indices, position, type);
Cube::LoadFace(Face::FRONT, vertices, indices, position, type);
Cube::LoadFace(Face::BACK, vertices, indices, position, type);
}
int Cube::faceToIndex(Face face) {
switch (face) {
case Face::TOP:
return 0;
case Face::BOTTOM:
return 1;
case Face::LEFT:
return 2;
case Face::RIGHT:
return 3;
case Face::FRONT:
return 4;
case Face::BACK:
return 5;
}
}
glm::dvec2 Cube::getTexCoords(int pos) {
int x = pos % TEXTURE_WIDTH;
int y = pos / 16;
return glm::vec2(x * CELL_WIDTH, y * CELL_HEIGHT);
}

62
gloom/src/Cube.h Normal file
View File

@@ -0,0 +1,62 @@
//
// Created by Bram on 23/08/2024.
//
#ifndef GLOOM_CUBE_H
#define GLOOM_CUBE_H
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <vector>
#include <iostream>
#include <array>
#include "glad/glad.h"
#include "gloom/Texture.h"
#include "gloom/config.hpp"
#include "Chunk.h"
#include "gloom/Mesh.h"
struct CubeVertex {
CubeVertex(glm::vec3 pos, glm::vec3 color, glm::vec2 texCoords) : position(pos), color(color),
texCoords(texCoords) {};
glm::vec3 position;
glm::vec3 color;
glm::vec2 texCoords;
};
enum Face {
TOP = 0x01, // 0000 0001
BOTTOM = 0x02, // 0000 0010
LEFT = 0x04, // 0000 0100
RIGHT = 0x08, // 0000 1000
FRONT = 0x10, // 0001 0000
BACK = 0x20 // 0010 0000
};
class Cube {
public:
explicit Cube(const glm::vec3 &position, BlockType blockType);
static void LoadFace(Face face, std::vector<Mesh::Vertex>& vertices, std::vector<unsigned int>& indices, const glm::vec3& position, BlockType type);
static void LoadAllFaces(std::vector<Mesh::Vertex>& vertices, std::vector<unsigned int>& indices, const glm::vec3& position, BlockType type);
static int faceToIndex(Face face);
static glm::dvec2 getTexCoords(int pos);
Mesh* mesh;
private:
glm::vec3 position;
Texture texture;
BlockType type{ BlockType::AIR };
};
#endif //GLOOM_CUBE_H

273
gloom/src/Game.cpp Normal file
View File

@@ -0,0 +1,273 @@
//
// Created by Bram on 23/08/2024.
//
#include "Game.h"
#include "gloom/config.hpp"
#include "gloom/Camera.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
// A callback which allows GLFW to report errors whenever they occur
static void glfwErrorCallback(int error, const char *description) {
fprintf(stderr, "GLFW returned an error:\n\t%s (%i)\n", description, error);
}
static void mouse_callback(GLFWwindow *window, double xpos, double ypos) {
glm::vec2 mousePos((float) xpos, (float) -ypos);
Camera::getInstance().updateMouse(mousePos);
}
Game::Game() {
// Initialise GLFW
if (!glfwInit()) {
fprintf(stderr, "Could not start GLFW\n");
exit(EXIT_FAILURE);
}
// Set core window options (adjust version numbers if needed)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Enable the GLFW runtime error callback function defined previously.
glfwSetErrorCallback(glfwErrorCallback);
// We to good for errors
// Set additional window options
glfwWindowHint(GLFW_RESIZABLE, windowResizable);
// glfwWindowHint(GLFW_SAMPLES, windowSamples); // MSAA
// glDisable(GL_MULTISAMPLE);
// Create window using GLFW
m_window = glfwCreateWindow(windowWidth,
windowHeight,
windowTitle.c_str(),
nullptr,
nullptr);
// Ensure the window is set up correctly
if (!m_window) {
fprintf(stderr, "Could not open GLFW window\n");
//Get the error and print it
const char *description;
int error = glfwGetError(&description);
fprintf(stderr, "Error: %s\n", description);
glfwTerminate();
exit(EXIT_FAILURE);
}
// Let the window be the current OpenGL context and initialise glad
glfwMakeContextCurrent(m_window);
gladLoadGL();
// Print various OpenGL information to stdout
printf("%s: %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER));
printf("GLFW\t %s\n", glfwGetVersionString());
printf("OpenGL\t %s\n", glGetString(GL_VERSION));
printf("GLSL\t %s\n\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
// Set up the mouse callback
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetCursorPosCallback(m_window, mouse_callback);
// Set up the shader
m_shader.setShader("shaders/simple.vert", "shaders/simple.frag");
// Set up the block
// // 16 x 16
// for (int x = 0; x < CHUNK_SIZE; x+=1) {
// for(int y = 0; y < CHUNK_HEIGHT / 4; y+=1) {
// for (int z = 0; z < CHUNK_SIZE; z+=1) {
// BlockType type = static_cast<BlockType>(rand() % 3);
// m_cubes.emplace_back(glm::vec3(x, y, z), type);
// }
// }
// }
// //10 x 10 chunk
// for (int i = 0; i < 10; ++i) {
// for (int j = 0; j < 10; ++j) {
// m_chunks.push_back(new Chunk(glm::vec2(i, j)));
// m_chunks[m_chunks.size() - 1]->loadBlocks();
// m_chunks[m_chunks.size() - 1]->loadMesh();
// }
// }
m_world = &World::GetInstance();
m_world->generateChunk(0, 0);
// m_world->generateChunk(1, 0);
// m_world->getChunk(0, 0)->loadMesh();
// m_world->generateChunk(0, 1);
// m_world->generateChunk(1, 1);
// m_world->getChunk(1, 0)->loadMesh();
}
Game::~Game() {
glfwTerminate();
}
void Game::run() {
// Enable depth (Z) buffer (accept "closest" fragment)
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Configure miscellaneous OpenGL settings
// glEnable(GL_CULL_FACE);
// Set default colour after clearing the colour buffer
glClearColor(0.3f, 0.5f, 0.8f, 1.0f);
double lastChunkUpdate = glfwGetTime();
// Set up your scene here (create Vertex Array Objects, etc.)
// Rendering Loop
while (!glfwWindowShouldClose(this->m_window)) {
// Calculate delta time
double currentTime = glfwGetTime();
m_deltaTime = currentTime - m_lastFrameTime;
m_lastFrameTime = currentTime;
// // wait until next frame with fps
// while (glfwGetTime() - m_lastFrameTime < 1.0 / MAX_FPS) {
// }
// Clear colour and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw your scene here
// Set the shader program
m_shader.use();
glViewport(0, 0, windowWidth, windowHeight);
m_shader.setMat4("view", Camera::getInstance().getViewMatrix());
m_shader.setMat4("projection", Camera::getInstance().projectionMatrix);
// for (auto &chunk: m_chunks) {
// chunk->Draw(m_shader.ID);
// }
//
m_world->Draw(m_shader.ID, Camera::getInstance().camPos);
//
// // if player is above chunk that is not generated, generate it, add a variance of the renderdistance
int playerX = (int) Camera::getInstance().camPos.x / CHUNK_SIZE;
int playerZ = (int) Camera::getInstance().camPos.z / CHUNK_SIZE;
if(glfwGetTime() - lastChunkUpdate > 0.5) {
lastChunkUpdate = glfwGetTime();
for (int x = playerX - RENDER_DISTANCE; x < playerX + RENDER_DISTANCE; x++) {
for (int z = playerZ - RENDER_DISTANCE; z < playerZ + RENDER_DISTANCE; z++) {
if (m_world->isChunkGenerated(x,z) == ChunkLoadStatus::NOT_GENERATED) {
m_world->generateChunk(x, z);
//Now take the 4 chunks next to it and update those
//
if (m_world->isChunkGenerated(x + 1, z) == ChunkLoadStatus::GENERATED) {
m_world->getChunk(x + 1, z)->loadMesh();
}
if (m_world->isChunkGenerated(x - 1, z) == ChunkLoadStatus::GENERATED) {
m_world->getChunk(x - 1, z)->loadMesh();
}
if (m_world->isChunkGenerated(x, z + 1) == ChunkLoadStatus::GENERATED) {
m_world->getChunk(x, z + 1)->loadMesh();
}
if (m_world->isChunkGenerated(x, z - 1) == ChunkLoadStatus::GENERATED) {
m_world->getChunk(x, z - 1)->loadMesh();
}
}
}
}
}
//
// Handle other events
glfwPollEvents();
this->handleKeyboard();
// Flip buffers
glfwSwapBuffers(this->m_window);
}
}
void Game::handleKeyboard() {
if (glfwGetKey(m_window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(m_window, GL_TRUE);
}
glm::vec3 moveDir(0, 0, 0);
//movement
if (glfwGetKey(this->m_window, GLFW_KEY_W) == GLFW_PRESS)
moveDir.z -= 1; // Move forward
if (glfwGetKey(this->m_window, GLFW_KEY_S) == GLFW_PRESS)
moveDir.z += 1; // Move backward
if (glfwGetKey(this->m_window, GLFW_KEY_A) == GLFW_PRESS)
moveDir.x -= 1; // Move left
if (glfwGetKey(this->m_window, GLFW_KEY_D) == GLFW_PRESS)
moveDir.x += 1; // Move right
if (glfwGetKey(this->m_window, GLFW_KEY_E) == GLFW_PRESS)
moveDir.y += 1;
if (glfwGetKey(this->m_window, GLFW_KEY_Q) == GLFW_PRESS)
moveDir.y -= 1;
if (length(moveDir) > 0)
Camera::getInstance().updatePos(normalize(moveDir), m_deltaTime);
static bool lastR = false; //Kinda shitty but damm i could not care less
if (glfwGetKey(this->m_window, GLFW_KEY_R) == GLFW_PRESS && !lastR) {
renderWireframe = !renderWireframe;
lastR = true;
} else if (glfwGetKey(this->m_window, GLFW_KEY_R) == GLFW_RELEASE) {
lastR = false;
}
//unlock mouse
static bool keyWasPressed = false;
if (glfwGetKey(this->m_window, GLFW_KEY_T) == GLFW_PRESS) {
if (!keyWasPressed) {
m_isMouseLocked = !m_isMouseLocked; // Toggle the state
glfwSetInputMode(this->m_window, GLFW_CURSOR, m_isMouseLocked ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
keyWasPressed = true;
}
} else {
keyWasPressed = false;
}
static bool balls = false;
if (glfwGetKey(this->m_window, GLFW_KEY_F) == GLFW_PRESS) {
if (!balls) {
//Random number between 1234u and 500u
SEED = rand() * 10000u;
perlin = siv::PerlinNoise(SEED);
m_world->generateChunk(1, 0);
m_world->generateChunk(0, 1);
m_world->generateChunk(0, 0);
m_world->generateChunk(1, 1);
std::cout << "Seed: " << SEED << std::endl;
balls = true;
}
} else {
balls = false;
}
}

43
gloom/src/Game.h Normal file
View File

@@ -0,0 +1,43 @@
//
// Created by Bram on 23/08/2024.
//
#ifndef GLOOM_GAME_H
#define GLOOM_GAME_H
#include "GLFW/glfw3.h"
#include "gloom/Shader.h"
#include "Cube.h"
#include "World.h"
static void glfwErrorCallback(int error, const char *description);
class Game {
public:
Game();
~Game();
void run();
void handleKeyboard();
private:
GLFWwindow* m_window;
bool m_isMouseLocked{ false };
double m_lastFrameTime{ 0.0 };
double m_deltaTime{ 0.0 };
Shader m_shader;
// Mesh* m_mesh;
// std::vector<Chunk*> m_chunks;
// std::vector<Cube> m_cubes;
World* m_world;
};
#endif //GLOOM_GAME_H

104
gloom/src/World.cpp Normal file
View File

@@ -0,0 +1,104 @@
//
// Created by Bram on 26/08/2024.
//
#include "World.h"
#include <iostream>
Chunk * World::getChunk(int x, int z) {
return chunks[x][z];
}
void World::generateChunk(int x, int z) {
//Calc offset so there is a 1 block space between each chunk
// glm::vec2 offset = glm::vec2(x * 2, z * 2);
if(chunks[x][z] != nullptr){
delete chunks[x][z];
}
chunks[x][z] = new Chunk(glm::vec2(x, z));
chunkGenerated[x][z] = ChunkLoadStatus::GENERATING;
chunks[x][z]->loadBlocks();
chunks[x][z]->loadMesh();
chunkGenerated[x][z] = ChunkLoadStatus::GENERATED;
//Call the sourounding chunks to update their mesh
if (x > 0) {
if(chunkGenerated[x - 1][z] == ChunkLoadStatus::GENERATED)
chunks[x - 1][z]->loadMesh();
}
if (x < WORLD_WIDTH - 1) {
if(chunkGenerated[x + 1][z] == ChunkLoadStatus::GENERATED)
chunks[x + 1][z]->loadMesh();
}
if (z > 0) {
if(chunkGenerated[x][z - 1] == ChunkLoadStatus::GENERATED)
chunks[x][z - 1]->loadMesh();
}
if (z < WORLD_HEIGHT - 1) {
if(chunkGenerated[x][z + 1] == ChunkLoadStatus::GENERATED)
chunks[x][z + 1]->loadMesh();
}
}
Block* World::getBlock(int x, int y, int z) {
int chunkX = x / CHUNK_SIZE;
int chunkZ = z / CHUNK_SIZE;
int blockX = x % CHUNK_SIZE;
int blockZ = z % CHUNK_SIZE;
Chunk* chunk = chunks[chunkX][chunkZ];
ChunkLoadStatus status = isChunkGenerated(chunkX, chunkZ);
// check if the chunk is generated
switch(isChunkGenerated(chunkX, chunkZ)) {
case ChunkLoadStatus::NOT_GENERATED:
// generateChunk(chunkX, chunkZ);
return new Block(BlockType::DIRT);
break;
case ChunkLoadStatus::NOT_AVAILABLE:
return new Block(BlockType::AIR);
break;
case ChunkLoadStatus::GENERATING:
//Prob current chunk is generating
break;
default:
break;
}
return chunks[chunkX][chunkZ]->getBlock(blockX, y, blockZ);
}
void World::setBlock(int x, int y, int z, const Block &block) {
int chunkX = x / CHUNK_SIZE;
int chunkZ = z / CHUNK_SIZE;
int blockX = x % CHUNK_SIZE;
int blockZ = z % CHUNK_SIZE;
chunks[chunkX][chunkZ]->setBlock(blockX, y, blockZ, block);
}
void World::Draw(GLuint shaderProgram, glm::vec3 playerPos) {
for (int x = 0; x < WORLD_WIDTH; x++) {
for (int z = 0; z < WORLD_HEIGHT; z++) {
//Check if the player is RENDERDISTANCE chunks away from the chunk
if (glm::distance(playerPos, glm::vec3(x * CHUNK_SIZE, 0, z * CHUNK_SIZE)) > RENDER_DISTANCE * CHUNK_SIZE) {
continue;
}
if (chunkGenerated[x][z] == ChunkLoadStatus::GENERATED) {
chunks[x][z]->Draw(shaderProgram);
}
}
}
}
World::World() {
for (int x = 0; x < WORLD_WIDTH; x++) {
for (int z = 0; z < WORLD_HEIGHT; z++) {
chunks[x][z] = nullptr;
chunkGenerated[x][z] = ChunkLoadStatus::NOT_GENERATED;
}
}
}

42
gloom/src/World.h Normal file
View File

@@ -0,0 +1,42 @@
//
// Created by Bram on 26/08/2024.
//
#ifndef GLOOM_WORLD_H
#define GLOOM_WORLD_H
#include <vector>
#include "Chunk.h"
#include "gloom/Singleton.h"
class World: public Singleton<World> {
public:
World();
Chunk * getChunk(int x, int z);
void generateChunk(int x, int z);
//Optional ig
Block* getBlock(int x, int y, int z);
void setBlock(int x, int y, int z, const Block& block);
void Draw(GLuint shaderProgram, glm::vec3 playerPos);
ChunkLoadStatus isChunkGenerated(int x, int z) {
//if out of bounds, return true
if (x < 0 || x >= WORLD_WIDTH || z < 0 || z >= WORLD_HEIGHT) {
return ChunkLoadStatus::NOT_AVAILABLE;
} else {
return chunkGenerated[x][z];
}
}
private:
//2D array
Chunk* chunks[WORLD_HEIGHT][WORLD_WIDTH]{ nullptr };
ChunkLoadStatus chunkGenerated[WORLD_HEIGHT][WORLD_WIDTH]{ ChunkLoadStatus::NOT_GENERATED };
};
#endif //GLOOM_WORLD_H

View File

@@ -0,0 +1,64 @@
//
// Created by Bram on 23/08/2024.
//
#include "Camera.h"
const float CAM_SENSITIVITY = .002f;
const float CAM_SPEED = 20;
//projection params
Camera::Camera() {
projectionMatrix = glm::perspective(glm::radians(FOV), (float)SCR_WIDTH / SCR_HEIGHT, NEAR_PLANE, FAR_PLANE);
camPos = glm::vec3(0, 0, 0);
}
glm::vec3 Camera::getFrontVector() {
glm::vec3 front;
front.x = cos(cameraAngle.x) * cos(cameraAngle.y);
front.y = sin(cameraAngle.y);
front.z = sin(cameraAngle.x) * cos(cameraAngle.y);
return front;
}
void Camera::updateMouse(glm::vec2 mousePos) {
glm::vec2 offset = mousePos - lastMousePos;
lastMousePos = mousePos;
cameraAngle += offset * CAM_SENSITIVITY;
cameraAngle.y = glm::clamp(cameraAngle.y, glm::radians(-89.0f), glm::radians(89.0f));
}
void Camera::updatePos(glm::vec3 moveDirection, double dt) {
glm::vec3 up(0.0f, 1.0f, 0.0f);
glm::vec3 front = glm::normalize(getFrontVector());
glm::vec3 right = glm::normalize(glm::cross(front, up));
up = glm::normalize(glm::cross(right, front));
camPos += up * moveDirection.y * CAM_SPEED * (float)dt;
camPos += front * moveDirection.z * -CAM_SPEED * (float)dt;
camPos += right * moveDirection.x * CAM_SPEED * (float)dt;
// Camera::print();
}
glm::mat4 Camera::getViewMatrix() {
glm::vec3 front = getFrontVector();
glm::vec3 cameraTarget = camPos + front;
return glm::lookAt(camPos, cameraTarget, glm::vec3(0.0f, 1.0f, 0.0f));
}
void Camera::print() {
std::cout << "Camera Position: " << camPos.x << ", " << camPos.y << ", " <<camPos.z << std::endl;
}
Camera& Camera::getInstance() {
static Camera instance;
return instance;
}

44
gloom/src/gloom/Camera.h Normal file
View File

@@ -0,0 +1,44 @@
//
// Created by Bram on 23/08/2024.
//
#ifndef GLOOM_CAMERA_H
#define GLOOM_CAMERA_H
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
class Camera
{
private:
glm::vec2 cameraAngle; //pitch and yaw
glm::vec3 getFrontVector();
glm::vec2 lastMousePos = glm::vec2(400.0f, 300.0f);
Camera();
public:
//constants
static constexpr int SCR_WIDTH = 1200;
static constexpr int SCR_HEIGHT = 900;
static constexpr float FOV = 90;
static constexpr float NEAR_PLANE = 0.1f;
static constexpr float FAR_PLANE = 200.0f;
static Camera& getInstance();
glm::vec3 camPos = glm::vec3(0.0f, 0.0f, 0.0f);
void updateMouse(glm::vec2 mousePos);
void updatePos(glm::vec3 moveDirection, double dt);
void print();
glm::mat4 getViewMatrix();
glm::mat4 projectionMatrix;
};
#endif //GLOOM_CAMERA_H

89
gloom/src/gloom/Mesh.cpp Normal file
View File

@@ -0,0 +1,89 @@
//
// Created by Bram on 23/08/2024.
//
#include "Mesh.h"
#include "glad/glad.h"
#include "config.hpp"
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include "TextureManager.h"
Mesh::Mesh() {
VAO = 0;
VBO = 0;
EBO = 0;
VAOSIZE = 0;
}
Mesh::~Mesh() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
Mesh::Mesh(const std::vector<Vertex> &vertices, const std::vector<unsigned int> &indices) {
this->vertices = vertices;
this->indices = indices;
m_texture = TextureManager::GetInstance().getTexture("assets/dirt.png");
setupMesh();
}
void Mesh::draw(GLuint shaderID) {
glUseProgram(shaderID);
GLuint modelLoc = glGetUniformLocation(shaderID, "model");
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, m_position);
model = glm::rotate(model, glm::radians(m_rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(m_rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, glm::radians(m_rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::scale(model, m_scale);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(VAO);
if(renderWireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
m_texture->bind(0);
//Get error
glDrawElements(GL_TRIANGLES, VAOSIZE, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
}
void Mesh::setupMesh() {
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
// vertex positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, position));
glEnableVertexAttribArray(0);
// vertex texture coords
glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, texCoords));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// Free memory
VAOSIZE = indices.size(); // Now using the size of the indices
}

46
gloom/src/gloom/Mesh.h Normal file
View File

@@ -0,0 +1,46 @@
//
// Created by Bram on 23/08/2024.
//
#ifndef GLOOM_MESH_H
#define GLOOM_MESH_H
#include <glm/glm.hpp>
#include <vector>
#include "glad/glad.h"
#include "Texture.h"
class Mesh {
public:
struct Vertex{
glm::vec3 position;
glm::dvec2 texCoords;
};
Mesh();
~Mesh();
Mesh(const std::vector<Mesh::Vertex>& vertices, const std::vector<unsigned int>& indices);
void draw(GLuint shaderID);
void setupMesh();
void setPosition(glm::vec3 position) { m_position = position; }
void setRotation(glm::vec3 rotation) { m_rotation = rotation; }
void setScale(glm::vec3 scale) { m_scale = scale; }
private:
unsigned int VAO, VBO, EBO, VAOSIZE;
glm::vec3 m_position{ 0.0f, -5.0f, 0.0f };
glm::vec3 m_rotation{ 0.0f, 0.0f, 0.0f };
glm::vec3 m_scale{ 1.0f, 1.0f, 1.0f };
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
Texture* m_texture{ nullptr };
};
#endif //GLOOM_MESH_H

View File

@@ -0,0 +1,659 @@
//----------------------------------------------------------------------------------------
//
// siv::PerlinNoise
// Perlin noise library for modern C++
//
// Copyright (C) 2013-2021 Ryo Suzuki <reputeless@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//----------------------------------------------------------------------------------------
# pragma once
# include <cstdint>
# include <algorithm>
# include <array>
# include <iterator>
# include <numeric>
# include <random>
# include <type_traits>
# if __has_include(<concepts>) && defined(__cpp_concepts)
# include <concepts>
# endif
// Library major version
# define SIVPERLIN_VERSION_MAJOR 3
// Library minor version
# define SIVPERLIN_VERSION_MINOR 0
// Library revision version
# define SIVPERLIN_VERSION_REVISION 0
// Library version
# define SIVPERLIN_VERSION ((SIVPERLIN_VERSION_MAJOR * 100 * 100) + (SIVPERLIN_VERSION_MINOR * 100) + (SIVPERLIN_VERSION_REVISION))
// [[nodiscard]] for constructors
# if (201907L <= __has_cpp_attribute(nodiscard))
# define SIVPERLIN_NODISCARD_CXX20 [[nodiscard]]
# else
# define SIVPERLIN_NODISCARD_CXX20
# endif
// std::uniform_random_bit_generator concept
# if __cpp_lib_concepts
# define SIVPERLIN_CONCEPT_URBG template <std::uniform_random_bit_generator URBG>
# define SIVPERLIN_CONCEPT_URBG_ template <std::uniform_random_bit_generator URBG>
# else
# define SIVPERLIN_CONCEPT_URBG template <class URBG, std::enable_if_t<std::conjunction_v<std::is_invocable<URBG&>, std::is_unsigned<std::invoke_result_t<URBG&>>>>* = nullptr>
# define SIVPERLIN_CONCEPT_URBG_ template <class URBG, std::enable_if_t<std::conjunction_v<std::is_invocable<URBG&>, std::is_unsigned<std::invoke_result_t<URBG&>>>>*>
# endif
// arbitrary value for increasing entropy
# ifndef SIVPERLIN_DEFAULT_Y
# define SIVPERLIN_DEFAULT_Y (0.12345)
# endif
// arbitrary value for increasing entropy
# ifndef SIVPERLIN_DEFAULT_Z
# define SIVPERLIN_DEFAULT_Z (0.34567)
# endif
namespace siv
{
template <class Float>
class BasicPerlinNoise
{
public:
static_assert(std::is_floating_point_v<Float>);
///////////////////////////////////////
//
// Typedefs
//
using state_type = std::array<std::uint8_t, 256>;
using value_type = Float;
using default_random_engine = std::mt19937;
using seed_type = typename default_random_engine::result_type;
///////////////////////////////////////
//
// Constructors
//
SIVPERLIN_NODISCARD_CXX20
constexpr BasicPerlinNoise() noexcept;
SIVPERLIN_NODISCARD_CXX20
explicit BasicPerlinNoise(seed_type seed);
SIVPERLIN_CONCEPT_URBG
SIVPERLIN_NODISCARD_CXX20
explicit BasicPerlinNoise(URBG&& urbg);
///////////////////////////////////////
//
// Reseed
//
void reseed(seed_type seed);
SIVPERLIN_CONCEPT_URBG
void reseed(URBG&& urbg);
///////////////////////////////////////
//
// Serialization
//
[[nodiscard]]
constexpr const state_type& serialize() const noexcept;
constexpr void deserialize(const state_type& state) noexcept;
///////////////////////////////////////
//
// Noise (The result is in the range [-1, 1])
//
[[nodiscard]]
value_type noise1D(value_type x) const noexcept;
[[nodiscard]]
value_type noise2D(value_type x, value_type y) const noexcept;
[[nodiscard]]
value_type noise3D(value_type x, value_type y, value_type z) const noexcept;
///////////////////////////////////////
//
// Noise (The result is remapped to the range [0, 1])
//
[[nodiscard]]
value_type noise1D_01(value_type x) const noexcept;
[[nodiscard]]
value_type noise2D_01(value_type x, value_type y) const noexcept;
[[nodiscard]]
value_type noise3D_01(value_type x, value_type y, value_type z) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result can be out of the range [-1, 1])
//
[[nodiscard]]
value_type octave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is clamped to the range [-1, 1])
//
[[nodiscard]]
value_type octave1D_11(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D_11(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D_11(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is clamped and remapped to the range [0, 1])
//
[[nodiscard]]
value_type octave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is normalized to the range [-1, 1])
//
[[nodiscard]]
value_type normalizedOctave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is normalized and remapped to the range [0, 1])
//
[[nodiscard]]
value_type normalizedOctave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
private:
state_type m_permutation;
};
using PerlinNoise = BasicPerlinNoise<double>;
namespace perlin_detail
{
////////////////////////////////////////////////
//
// These functions are provided for consistency.
// You may get different results from std::shuffle() with different standard library implementations.
//
SIVPERLIN_CONCEPT_URBG
[[nodiscard]]
inline std::uint64_t Random(const std::uint64_t max, URBG&& urbg)
{
return (urbg() % (max + 1));
}
template <class RandomIt, class URBG>
inline void Shuffle(RandomIt first, RandomIt last, URBG&& urbg)
{
if (first == last)
{
return;
}
using difference_type = typename std::iterator_traits<RandomIt>::difference_type;
for (RandomIt it = first + 1; it < last; ++it)
{
const std::uint64_t n = static_cast<std::uint64_t>(it - first);
std::iter_swap(it, first + static_cast<difference_type>(Random(n, std::forward<URBG>(urbg))));
}
}
//
////////////////////////////////////////////////
template <class Float>
[[nodiscard]]
inline constexpr Float Fade(const Float t) noexcept
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Lerp(const Float a, const Float b, const Float t) noexcept
{
return (a + (b - a) * t);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Grad(const std::uint8_t hash, const Float x, const Float y, const Float z) noexcept
{
const std::uint8_t h = hash & 15;
const Float u = h < 8 ? x : y;
const Float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Remap_01(const Float x) noexcept
{
return (x * Float(0.5) + Float(0.5));
}
template <class Float>
[[nodiscard]]
inline constexpr Float Clamp_11(const Float x) noexcept
{
return std::clamp(x, Float(-1.0), Float(1.0));
}
template <class Float>
[[nodiscard]]
inline constexpr Float RemapClamp_01(const Float x) noexcept
{
if (x <= Float(-1.0))
{
return Float(0.0);
}
else if (Float(1.0) <= x)
{
return Float(1.0);
}
return (x * Float(0.5) + Float(0.5));
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave1D(const Noise& noise, Float x, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise1D(x) * amplitude);
x *= 2;
amplitude *= persistence;
}
return result;
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave2D(const Noise& noise, Float x, Float y, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise2D(x, y) * amplitude);
x *= 2;
y *= 2;
amplitude *= persistence;
}
return result;
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave3D(const Noise& noise, Float x, Float y, Float z, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise3D(x, y, z) * amplitude);
x *= 2;
y *= 2;
z *= 2;
amplitude *= persistence;
}
return result;
}
template <class Float>
[[nodiscard]]
inline constexpr Float MaxAmplitude(const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += amplitude;
amplitude *= persistence;
}
return result;
}
}
///////////////////////////////////////
template <class Float>
inline constexpr BasicPerlinNoise<Float>::BasicPerlinNoise() noexcept
: m_permutation{ 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 } {}
template <class Float>
inline BasicPerlinNoise<Float>::BasicPerlinNoise(const seed_type seed)
{
reseed(seed);
}
template <class Float>
SIVPERLIN_CONCEPT_URBG_
inline BasicPerlinNoise<Float>::BasicPerlinNoise(URBG&& urbg)
{
reseed(std::forward<URBG>(urbg));
}
///////////////////////////////////////
template <class Float>
inline void BasicPerlinNoise<Float>::reseed(const seed_type seed)
{
reseed(default_random_engine{ seed });
}
template <class Float>
SIVPERLIN_CONCEPT_URBG_
inline void BasicPerlinNoise<Float>::reseed(URBG&& urbg)
{
std::iota(m_permutation.begin(), m_permutation.end(), uint8_t{ 0 });
perlin_detail::Shuffle(m_permutation.begin(), m_permutation.end(), std::forward<URBG>(urbg));
}
///////////////////////////////////////
template <class Float>
inline constexpr const typename BasicPerlinNoise<Float>::state_type& BasicPerlinNoise<Float>::serialize() const noexcept
{
return m_permutation;
}
template <class Float>
inline constexpr void BasicPerlinNoise<Float>::deserialize(const state_type& state) noexcept
{
m_permutation = state;
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise1D(const value_type x) const noexcept
{
return noise3D(x,
static_cast<value_type>(SIVPERLIN_DEFAULT_Y),
static_cast<value_type>(SIVPERLIN_DEFAULT_Z));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise2D(const value_type x, const value_type y) const noexcept
{
return noise3D(x,
y,
static_cast<value_type>(SIVPERLIN_DEFAULT_Z));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise3D(const value_type x, const value_type y, const value_type z) const noexcept
{
const value_type _x = std::floor(x);
const value_type _y = std::floor(y);
const value_type _z = std::floor(z);
const std::int32_t ix = static_cast<std::int32_t>(_x) & 255;
const std::int32_t iy = static_cast<std::int32_t>(_y) & 255;
const std::int32_t iz = static_cast<std::int32_t>(_z) & 255;
const value_type fx = (x - _x);
const value_type fy = (y - _y);
const value_type fz = (z - _z);
const value_type u = perlin_detail::Fade(fx);
const value_type v = perlin_detail::Fade(fy);
const value_type w = perlin_detail::Fade(fz);
const std::uint8_t A = (m_permutation[ix & 255] + iy) & 255;
const std::uint8_t B = (m_permutation[(ix + 1) & 255] + iy) & 255;
const std::uint8_t AA = (m_permutation[A] + iz) & 255;
const std::uint8_t AB = (m_permutation[(A + 1) & 255] + iz) & 255;
const std::uint8_t BA = (m_permutation[B] + iz) & 255;
const std::uint8_t BB = (m_permutation[(B + 1) & 255] + iz) & 255;
const value_type p0 = perlin_detail::Grad(m_permutation[AA], fx, fy, fz);
const value_type p1 = perlin_detail::Grad(m_permutation[BA], fx - 1, fy, fz);
const value_type p2 = perlin_detail::Grad(m_permutation[AB], fx, fy - 1, fz);
const value_type p3 = perlin_detail::Grad(m_permutation[BB], fx - 1, fy - 1, fz);
const value_type p4 = perlin_detail::Grad(m_permutation[(AA + 1) & 255], fx, fy, fz - 1);
const value_type p5 = perlin_detail::Grad(m_permutation[(BA + 1) & 255], fx - 1, fy, fz - 1);
const value_type p6 = perlin_detail::Grad(m_permutation[(AB + 1) & 255], fx, fy - 1, fz - 1);
const value_type p7 = perlin_detail::Grad(m_permutation[(BB + 1) & 255], fx - 1, fy - 1, fz - 1);
const value_type q0 = perlin_detail::Lerp(p0, p1, u);
const value_type q1 = perlin_detail::Lerp(p2, p3, u);
const value_type q2 = perlin_detail::Lerp(p4, p5, u);
const value_type q3 = perlin_detail::Lerp(p6, p7, u);
const value_type r0 = perlin_detail::Lerp(q0, q1, v);
const value_type r1 = perlin_detail::Lerp(q2, q3, v);
return perlin_detail::Lerp(r0, r1, w);
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise1D_01(const value_type x) const noexcept
{
return perlin_detail::Remap_01(noise1D(x));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise2D_01(const value_type x, const value_type y) const noexcept
{
return perlin_detail::Remap_01(noise2D(x, y));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise3D_01(const value_type x, const value_type y, const value_type z) const noexcept
{
return perlin_detail::Remap_01(noise3D(x, y, z));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave1D(*this, x, octaves, persistence);
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave2D(*this, x, y, octaves, persistence);
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave3D(*this, x, y, z, octaves, persistence);
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D_11(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D_11(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D_11(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave3D(x, y, z, octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave3D(x, y, z, octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave1D(x, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave2D(x, y, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave3D(x, y, z, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave3D(x, y, z, octaves, persistence));
}
}
# undef SIVPERLIN_NODISCARD_CXX20
# undef SIVPERLIN_CONCEPT_URBG
# undef SIVPERLIN_CONCEPT_URBG_

157
gloom/src/gloom/Shader.cpp Normal file
View File

@@ -0,0 +1,157 @@
//
// Created by Bram on 23/08/2024.
//
#include "Shader.h"
Shader::Shader() {
}
void Shader::setShader(const char* vertexPath, const char* fragmentPath) {
std::string vertexCode, fragmentCode;
std::ifstream vShaderFile, fShaderFile;
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
//open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
vShaderFile.close();
fShaderFile.close();
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
//next, compile shaders
unsigned int vertex, fragment;
int success;
char infoLog[512];
//vertex
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
//vertex errors
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//fragment
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
//fragment compile errors
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//setup shader program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
//shader program linking errors
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
//cleanup
glDeleteShader(vertex);
glDeleteShader(fragment);
}
//shadow mapping
void Shader::setupShadowMap() {
// Create framebuffer to attach depth texture
glGenFramebuffers(1, &depthMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
// Create depth texture
glGenTextures(1, &depthMap);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthMap);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, shadowWidth, shadowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthMap, 0);
glDrawBuffer(GL_NONE);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "Error getting framebuffer" << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Shader::renderShadowMap(glm::mat4 lightSpaceMatrix) {
glViewport(0, 0, shadowWidth, shadowHeight);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
// Render the scene
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
//enable this shader
void Shader::use() {
glUseProgram(ID);
}
//uniform set functions
void Shader::setBool(const std::string& name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string& name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string& name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setMat4(const std::string& name, glm::mat4 value) const
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}
void Shader::setVec3(const std::string& name, glm::vec3 value) const {
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, glm::value_ptr(value));
}

41
gloom/src/gloom/Shader.h Normal file
View File

@@ -0,0 +1,41 @@
//
// Created by Bram on 23/08/2024.
//
#ifndef GLOOM_SHADER_H
#define GLOOM_SHADER_H
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Shader
{
public:
unsigned int ID;
Shader();
void use();
void setShader(const char* vertexPath, const char* fragmentPath);
void setBool(const std::string& name, bool value) const;
void setInt(const std::string& name, int value) const;
void setFloat(const std::string& name, float value) const;
void setMat4(const std::string& name, glm::mat4 value) const;
void setVec3(const std::string& name, glm::vec3 value) const;
//shadow map
unsigned int depthMapFBO, depthMap;
int shadowWidth = 4096, shadowHeight = 4096; // Adjust the size as needed
void setupShadowMap();
void renderShadowMap(glm::mat4 lightSpaceMatrix);
};
#endif //GLOOM_SHADER_H

View File

@@ -0,0 +1,35 @@
//
// Created by Bram on 25/08/2024.
//
#ifndef GLOOM_SINGLETON_H
#define GLOOM_SINGLETON_H
#ifndef SINGLETON_H
#define SINGLETON_H
template<typename T>
class Singleton {
public:
static T &GetInstance() {
static T instance{};
return instance;
}
virtual ~Singleton() = default;
Singleton(Singleton &&other) = delete;
Singleton(const Singleton &other) = delete;
Singleton &operator=(Singleton &&other) = delete;
Singleton &operator=(const Singleton &other) = delete;
protected:
Singleton() = default;
};
#endif // SINGLETON_H
#endif //GLOOM_SINGLETON_H

View File

@@ -0,0 +1,52 @@
//
// Created by Bram on 23/08/2024.
//
#include "Texture.h"
#include "glad/glad.h"
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
Texture::Texture(const std::string &filename) {
// Load the image
int width, height, channels;
unsigned char* image = stbi_load(filename.c_str(), &width, &height, &channels, 0);
// Generate a texture
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
// Set the texture wrapping/filtering options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//mipmap resizing
// Load and generate the texture
if (image) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
std::cerr << "Failed to load texture" << std::endl;
}
// Free the image
stbi_image_free(image);
}
void Texture::bind(unsigned int slot) const {
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_texture);
}
void Texture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}

24
gloom/src/gloom/Texture.h Normal file
View File

@@ -0,0 +1,24 @@
//
// Created by Bram on 23/08/2024.
//
#ifndef GLOOM_TEXTURE_H
#define GLOOM_TEXTURE_H
#include <string>
class Texture {
public:
Texture(const std::string& filename);
void bind(unsigned int slot = 0) const;
void unbind() const;
unsigned int getTexture() const { return m_texture; }
private:
unsigned int m_texture{ 0 };
};
#endif //GLOOM_TEXTURE_H

View File

@@ -0,0 +1,12 @@
//
// Created by Bram on 25/08/2024.
//
#include "TextureManager.h"
Texture * TextureManager::getTexture(const std::string &path) {
if (m_textures.find(path) == m_textures.end()) {
m_textures[path] = new Texture(path);
}
return m_textures[path];
}

View File

@@ -0,0 +1,27 @@
//
// Created by Bram on 25/08/2024.
//
#ifndef GLOOM_TEXTUREMANAGER_H
#define GLOOM_TEXTUREMANAGER_H
#include <unordered_map>
#include "Singleton.h"
#include "Texture.h"
#include <string>
class TextureManager: public Singleton<TextureManager>{
public:
TextureManager() = default;
~TextureManager() override = default;
Texture * getTexture(const std::string& path);
private:
std::unordered_map<std::string, Texture*> m_textures;
};
#endif //GLOOM_TEXTUREMANAGER_H

View File

@@ -1,200 +0,0 @@
#ifndef CAMERA_HPP
#define CAMERA_HPP
#pragma once
// System headers
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <GLFW/glfw3.h>
namespace Gloom
{
class Camera
{
public:
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 2.0f),
GLfloat movementSpeed = 5.0f,
GLfloat mouseSensitivity = 0.005f)
{
cPosition = position;
cMovementSpeed = movementSpeed;
cMouseSensitivity = mouseSensitivity;
// Set up the initial view matrix
updateViewMatrix();
}
// Public member functions
/* Getter for the view matrix */
glm::mat4 getViewMatrix() { return matView; }
/* Handle keyboard inputs from a callback mechanism */
void handleKeyboardInputs(int key, int action)
{
// Keep track of pressed/released buttons
if (key >= 0 && key < 512)
{
if (action == GLFW_PRESS)
{
keysInUse[key] = true;
}
else if (action == GLFW_RELEASE)
{
keysInUse[key] = false;
}
}
}
/* Handle mouse button inputs from a callback mechanism */
void handleMouseButtonInputs(int button, int action)
{
// Ensure that the camera only rotates when the left mouse button is
// pressed
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
{
isMousePressed = true;
}
else
{
isMousePressed = false;
resetMouse = true;
}
}
/* Handle cursor position from a callback mechanism */
void handleCursorPosInput(double xpos, double ypos)
{
// Do nothing if the left mouse button is not pressed
if (isMousePressed == false)
return;
// There should be no movement when the mouse button is released
if (resetMouse)
{
lastXPos = xpos;
lastYPos = ypos;
resetMouse = false;
}
// Keep track of pitch and yaw for the current frame
fYaw = xpos - lastXPos;
fPitch = ypos - lastYPos;
// Update last known cursor position
lastXPos = xpos;
lastYPos = ypos;
}
/* Update the camera position and view matrix
`deltaTime` is the time between the current and last frame */
void updateCamera(GLfloat deltaTime)
{
// Extract movement information from the view matrix
glm::vec3 dirX(matView[0][0], matView[1][0], matView[2][0]);
glm::vec3 dirY(matView[0][1], matView[1][1], matView[2][1]);
glm::vec3 dirZ(matView[0][2], matView[1][2], matView[2][2]);
// Alter position in the appropriate direction
glm::vec3 fMovement(0.0f, 0.0f, 0.0f);
if (keysInUse[GLFW_KEY_W]) // forward
fMovement -= dirZ;
if (keysInUse[GLFW_KEY_S]) // backward
fMovement += dirZ;
if (keysInUse[GLFW_KEY_A]) // left
fMovement -= dirX;
if (keysInUse[GLFW_KEY_D]) // right
fMovement += dirX;
if (keysInUse[GLFW_KEY_E]) // vertical up
fMovement += dirY;
if (keysInUse[GLFW_KEY_Q]) // vertical down
fMovement -= dirY;
// Trick to balance PC speed with movement
GLfloat velocity = cMovementSpeed * deltaTime;
// Update camera position using the appropriate velocity
cPosition += fMovement * velocity;
// Update the view matrix based on the new information
updateViewMatrix();
}
private:
// Disable copying and assignment
Camera(Camera const &) = delete;
Camera & operator =(Camera const &) = delete;
// Private member function
/* Update the view matrix based on the current information */
void updateViewMatrix()
{
// Adjust cursor movement using the specified sensitivity
fPitch *= cMouseSensitivity;
fYaw *= cMouseSensitivity;
// Create quaternions given the current pitch and yaw
glm::quat qPitch = glm::quat(glm::vec3(fPitch, 0.0f, 0.0f));
glm::quat qYaw = glm::quat(glm::vec3(0.0f, fYaw, 0.0f));
// Reset pitch and yaw values for the current rotation
fPitch = 0.0f;
fYaw = 0.0f;
// Update camera quaternion and normalise
cQuaternion = qYaw * qPitch * cQuaternion;
cQuaternion = glm::normalize(cQuaternion);
// Build rotation matrix using the camera quaternion
glm::mat4 matRotation = glm::mat4_cast(cQuaternion);
// Build translation matrix
glm::mat4 matTranslate = glm::translate(glm::mat4(1.0f), -cPosition);
// Update view matrix
matView = matRotation * matTranslate;
}
// Private member variables
// Camera quaternion and frame pitch and yaw
glm::quat cQuaternion;
GLfloat fPitch = 0.0f;
GLfloat fYaw = 0.0f;
// Camera position
glm::vec3 cPosition;
// Variables used for bookkeeping
GLboolean resetMouse = true;
GLboolean isMousePressed = false;
GLboolean keysInUse[512];
// Last cursor position
GLfloat lastXPos = 0.0f;
GLfloat lastYPos = 0.0f;
// Camera settings
GLfloat cMovementSpeed;
GLfloat cMouseSensitivity;
// View matrix
glm::mat4 matView;
};
}
#endif

View File

@@ -0,0 +1,45 @@
// Preprocessor directives
#ifndef GLOOM_HPP
#define GLOOM_HPP
#pragma once
// System Headers
#include <glad/glad.h>
// Standard headers
#include <string>
#include "PerlinNoise.hpp"
// Constants
const int windowWidth = 1200;
const int windowHeight = 900;
const std::string windowTitle = "OpenGL";
const GLint windowResizable = GL_FALSE;
const int windowSamples = 4;
const int MAX_FPS = 60;
static bool renderWireframe = false;
static const int CHUNK_SIZE = 16;
static const int CHUNK_HEIGHT = 256;
static const int TEXTURE_WIDTH = 16;
static const int TEXTURE_HEIGHT = 16;
static const int ATLAS_WIDTH = 128;
static const int ATLAS_HEIGHT = 128;
static const double CELL_WIDTH = 1.0 / ATLAS_WIDTH * TEXTURE_WIDTH;
static const double CELL_HEIGHT = 1.0 / ATLAS_HEIGHT * TEXTURE_HEIGHT;
static const int RENDER_DISTANCE = 10;
static const int WORLD_WIDTH = 128;
static const int WORLD_HEIGHT = 128;
static int SEED = 1234u;
static siv::PerlinNoise perlin{ static_cast<unsigned int>(SEED) };
#endif

View File

@@ -1,19 +0,0 @@
// Preprocessor directives
#ifndef GLOOM_HPP
#define GLOOM_HPP
#pragma once
// System Headers
#include <glad/glad.h>
// Standard headers
#include <string>
// Constants
const int windowWidth = 1024;
const int windowHeight = 768;
const std::string windowTitle = "OpenGL";
const GLint windowResizable = GL_FALSE;
const int windowSamples = 4;
#endif

View File

@@ -0,0 +1,175 @@
////
//// Created by Bram on 23/08/2024.
////
//
//#include "Cube.h"
//
//glm::vec3 unitVertices[8] = {
// glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f),
// glm::vec3(1.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f),
// glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(1.0f, 0.0f, 1.0f),
// glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 1.0f)
//};
//
//unsigned int faceVertices[6][6] = {
// // TOP (3, 2, 6, 3, 6, 7)
// {3, 2, 6, 3, 6, 7},
// // BOTTOM (1, 0, 4, 1, 4, 5)
// {1, 0, 4, 1, 4, 5},
// // LEFT (0, 3, 7, 0, 7, 4)
// {0, 3, 7, 0, 7, 4},
// // RIGHT (2, 1, 5, 2, 5, 6)
// {2, 1, 5, 2, 5, 6},
// // FRONT (0, 1, 2, 0, 2, 3)
// {0, 1, 2, 0, 2, 3},
// // BACK (5, 4, 7, 5, 7, 6)
// {5, 4, 7, 5, 7, 6}
//};
//
//
//void Cube::Draw(GLuint shaderProgram) {
// // Use the shader program
// glUseProgram(shaderProgram);
//
// // Transform the cube
// glm::mat4 model = glm::translate(glm::mat4(1.0f), position);
// GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
// glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
//
// if(renderWireframe) {
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// } else {
// glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// }
//
// // Draw the cube
// texture.bind(0);
// glBindVertexArray(VAO);
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// glBindVertexArray(0);
//
//}
//
//void Cube::setupCube() {
//
//
//
//
// std::array<CubeVertex, 24> cubeVertices = {
// // Front face (z = 1.0f)
// CubeVertex(glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec2(0.0f, 0.0f)), // Bottom-left
// CubeVertex(glm::vec3( 1.0f, -1.0f, 1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec2(1.0f, 0.0f)), // Bottom-right
// CubeVertex(glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec2(1.0f, 1.0f)), // Top-right
// CubeVertex(glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec2(0.0f, 1.0f)), // Top-left
//
// // Back face (z = -1.0f)
// CubeVertex(glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec2(0.0f, 0.0f)), // Bottom-left
// CubeVertex(glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec2(1.0f, 0.0f)), // Bottom-right
// CubeVertex(glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec2(1.0f, 1.0f)), // Top-right
// CubeVertex(glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec2(0.0f, 1.0f)), // Top-left
//
// // Left face (x = -1.0f)
// CubeVertex(glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec2(0.0f, 0.0f)), // Bottom-left
// CubeVertex(glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec2(1.0f, 0.0f)), // Bottom-right
// CubeVertex(glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec2(1.0f, 1.0f)), // Top-right
// CubeVertex(glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3(1.0f, 1.0f, 0.0f), glm::vec2(0.0f, 1.0f)), // Top-left
//
// // Right face (x = 1.0f)
// CubeVertex(glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3(1.0f, 0.0f, 1.0f), glm::vec2(0.0f, 0.0f)), // Bottom-left
// CubeVertex(glm::vec3( 1.0f, -1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec2(1.0f, 0.0f)), // Bottom-right
// CubeVertex(glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec2(1.0f, 1.0f)), // Top-right
// CubeVertex(glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3(0.5f, 0.5f, 0.5f), glm::vec2(0.0f, 1.0f)), // Top-left
//
// // Bottom face (y = -1.0f)
// CubeVertex(glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec2(0.0f, 0.0f)), // Bottom-left
// CubeVertex(glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec2(1.0f, 0.0f)), // Bottom-right
// CubeVertex(glm::vec3( 1.0f, -1.0f, 1.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec2(1.0f, 1.0f)), // Top-right
// CubeVertex(glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 0.0f), glm::vec2(0.0f, 1.0f)), // Top-left
//
// // Top face (y = 1.0f)
// CubeVertex(glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3(1.0f, 0.0f, 1.0f), glm::vec2(0.0f, 0.0f)), // Bottom-left
// CubeVertex(glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec2(1.0f, 0.0f)), // Bottom-right
// CubeVertex(glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec2(1.0f, 1.0f)), // Top-right
// CubeVertex(glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3(0.5f, 0.5f, 0.5f), glm::vec2(0.0f, 1.0f)) // Top-left
// };
//
// glGenVertexArrays(1, &VAO);
// glGenBuffers(1, &VBO);
// glGenBuffers(1, &EBO);
//
// glBindVertexArray(VAO);
// glBindBuffer(GL_ARRAY_BUFFER, VBO);
// glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices.data(), GL_STATIC_DRAW);
//
//
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices.data(), GL_STATIC_DRAW);
//
//
// // Position attribute
// glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(CubeVertex), (void *) offsetof(CubeVertex, position));
// glEnableVertexAttribArray(0);
//
// // Color attribute
// glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(CubeVertex), (void *) offsetof(CubeVertex, color));
// glEnableVertexAttribArray(1);
//
// // Texture Coords
// glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(CubeVertex), (void *) offsetof(CubeVertex, texCoords));
// glEnableVertexAttribArray(2);
//
// glBindBuffer(GL_ARRAY_BUFFER, 0);
// glBindVertexArray(0);
//}
//
//Cube::Cube(const glm::vec3 &position, BlockType blockType): position(position), texture("assets/dirt.png"), type(blockType) {
// setupCube();
//}
//
//void Cube::LoadFace(Face face, std::vector<CubeVertex> &vertices) {
//
// glm::vec3 normal;
// switch (face) {
// case Face::TOP:
// normal = glm::vec3(0.0f, 1.0f, 0.0f);
// break;
// case Face::BOTTOM:
// normal = glm::vec3(0.0f, -1.0f, 0.0f);
// break;
// case Face::LEFT:
// normal = glm::vec3(-1.0f, 0.0f, 0.0f);
// break;
// case Face::RIGHT:
// normal = glm::vec3(1.0f, 0.0f, 0.0f);
// break;
// case Face::FRONT:
// normal = glm::vec3(0.0f, 0.0f, 1.0f);
// break;
// case Face::BACK:
// normal = glm::vec3(0.0f, 0.0f, -1.0f);
// break;
// }
//
// glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f);
// glm::vec2 texCoords = glm::vec2(0.0f, 0.0f);
//
// for (int i = 0; i < 6; i++) {
// CubeVertex vertex = {
// unitVertices[faceVertices[face][i]],
// color,
// texCoords
// };
// vertices.push_back(vertex);
// }
//
//}
//
//void Cube::LoadAllFaces(std::vector<CubeVertex> &vertices) {
// LoadFace(Face::TOP, vertices);
// LoadFace(Face::BOTTOM, vertices);
// LoadFace(Face::LEFT, vertices);
// LoadFace(Face::RIGHT, vertices);
// LoadFace(Face::FRONT, vertices);
// LoadFace(Face::BACK, vertices);
//}

View File

@@ -0,0 +1,89 @@
////
//// Created by Bram on 23/08/2024.
////
//
//#ifndef GLOOM_CUBE_H
//#define GLOOM_CUBE_H
//
//
//#include <glm/glm.hpp>
//#include <glm/gtc/matrix_transform.hpp>
//#include <glm/gtc/type_ptr.hpp>
//#include <vector>
//#include <iostream>
//#include <array>
//#include "glad/glad.h"
//#include "gloom/Texture.h"
//#include "gloom/config.hpp"
//#include "Chunk.h"
//#include "gloom/Mesh.h"
//
//struct CubeVertex {
// CubeVertex(glm::vec3 pos, glm::vec3 color, glm::vec2 texCoords) : position(pos), color(color),
// texCoords(texCoords) {};
//
// glm::vec3 position;
// glm::vec3 color;
// glm::vec2 texCoords;
//};
//
//struct CubeFace {
//};
//
//static std::array<unsigned int, 36> cubeIndices = {
// // Front face
// 0, 1, 2, // First triangle (0, 1, 2)
// 0, 2, 3, // Second triangle (0, 2, 3)
//
// // Back face
// 4, 5, 6, // First triangle (4, 5, 6)
// 4, 6, 7, // Second triangle (4, 6, 7)
//
// // Left face
// 8, 9, 10, // First triangle (8, 9, 10)
// 8, 10, 11,// Second triangle (8, 10, 11)
//
// // Right face
// 12, 13, 14,// First triangle (12, 13, 14)
// 12, 14, 15,// Second triangle (12, 14, 15)
//
// // Bottom face
// 16, 17, 18,// First triangle (16, 17, 18)
// 16, 18, 19,// Second triangle (16, 18, 19)
//
// // Top face
// 20, 21, 22,// First triangle (20, 21, 22)
// 20, 22, 23 // Second triangle (20, 22, 23)
//};
//
//enum Face {
// TOP = 0x01, // 0000 0001
// BOTTOM = 0x02, // 0000 0010
// LEFT = 0x04, // 0000 0100
// RIGHT = 0x08, // 0000 1000
// FRONT = 0x10, // 0001 0000
// BACK = 0x20 // 0010 0000
//};
//
//
//class Cube {
//public:
// explicit Cube(const glm::vec3 &position, BlockType blockType);
//
// void Draw(GLuint shaderProgram);
//
// void LoadFace(Face face, std::vector<CubeVertex>& vertices);
// void LoadAllFaces(std::vector<CubeVertex>& vertices);
//
// Mesh mesh;
//private:
// GLuint VAO{}, VBO{}, EBO{};
// glm::vec3 position;
//
// Texture texture;
// BlockType type{ BlockType::AIR };
// void setupCube();
//};
//
//
//#endif //GLOOM_CUBE_H

View File

@@ -1,146 +0,0 @@
#ifndef SHADER_HPP
#define SHADER_HPP
#pragma once
// System headers
#include <glad/glad.h>
// Standard headers
#include <cassert>
#include <fstream>
#include <memory>
#include <string>
namespace Gloom
{
class Shader
{
public:
Shader() { mProgram = glCreateProgram(); }
// Public member functions
void activate() { glUseProgram(mProgram); }
void deactivate() { glUseProgram(0); }
GLuint get() { return mProgram; }
void destroy() { glDeleteProgram(mProgram); }
/* Attach a shader to the current shader program */
void attach(std::string const &filename)
{
// Load GLSL Shader from source
std::ifstream fd(filename.c_str());
if (fd.fail())
{
fprintf(stderr,
"Something went wrong when attaching the Shader file at \"%s\".\n"
"The file may not exist or is currently inaccessible.\n",
filename.c_str());
return;
}
auto src = std::string(std::istreambuf_iterator<char>(fd),
(std::istreambuf_iterator<char>()));
// Create shader object
const char * source = src.c_str();
auto shader = create(filename);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
// Display errors
glGetShaderiv(shader, GL_COMPILE_STATUS, &mStatus);
if (!mStatus)
{
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &mLength);
std::unique_ptr<char[]> buffer(new char[mLength]);
glGetShaderInfoLog(shader, mLength, nullptr, buffer.get());
fprintf(stderr, "%s\n%s", filename.c_str(), buffer.get());
}
assert(mStatus);
// Attach shader and free allocated memory
glAttachShader(mProgram, shader);
glDeleteShader(shader);
}
/* Links all attached shaders together into a shader program */
void link()
{
// Link all attached shaders
glLinkProgram(mProgram);
// Display errors
glGetProgramiv(mProgram, GL_LINK_STATUS, &mStatus);
if (!mStatus)
{
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &mLength);
std::unique_ptr<char[]> buffer(new char[mLength]);
glGetProgramInfoLog(mProgram, mLength, nullptr, buffer.get());
fprintf(stderr, "%s\n", buffer.get());
}
assert(mStatus);
}
/* Convenience function that attaches and links a vertex and a
fragment shader in a shader program */
void makeBasicShader(std::string const &vertexFilename,
std::string const &fragmentFilename)
{
attach(vertexFilename);
attach(fragmentFilename);
link();
}
/* Used for debugging shader programs (expensive to run) */
bool isValid()
{
// Validate linked shader program
glValidateProgram(mProgram);
// Display errors
glGetProgramiv(mProgram, GL_VALIDATE_STATUS, &mStatus);
if (!mStatus)
{
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &mLength);
std::unique_ptr<char[]> buffer(new char[mLength]);
glGetProgramInfoLog(mProgram, mLength, nullptr, buffer.get());
fprintf(stderr, "%s\n", buffer.get());
return false;
}
return true;
}
/* Helper function for creating shaders */
GLuint create(std::string const &filename)
{
// Extract file extension and create the correct shader type
auto idx = filename.rfind(".");
auto ext = filename.substr(idx + 1);
if (ext == "comp") return glCreateShader(GL_COMPUTE_SHADER);
else if (ext == "frag") return glCreateShader(GL_FRAGMENT_SHADER);
else if (ext == "geom") return glCreateShader(GL_GEOMETRY_SHADER);
else if (ext == "tcs") return glCreateShader(GL_TESS_CONTROL_SHADER);
else if (ext == "tes") return glCreateShader(GL_TESS_EVALUATION_SHADER);
else if (ext == "vert") return glCreateShader(GL_VERTEX_SHADER);
else return false;
}
private:
// Disable copying and assignment
Shader(Shader const &) = delete;
Shader & operator =(Shader const &) = delete;
// Private member variables
GLuint mProgram;
GLint mStatus;
GLint mLength;
};
}
#endif

View File

@@ -1,82 +1,19 @@
// Local headers
#include "gloom/gloom.hpp"
#include "program.hpp"
// System headers
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "gloom/config.hpp"
#include "Game.h"
// Standard headers
#include <cstdlib>
// A callback which allows GLFW to report errors whenever they occur
static void glfwErrorCallback(int error, const char *description)
{
fprintf(stderr, "GLFW returned an error:\n\t%s (%i)\n", description, error);
}
GLFWwindow* initialise()
{
// Initialise GLFW
if (!glfwInit())
{
fprintf(stderr, "Could not start GLFW\n");
exit(EXIT_FAILURE);
}
// Set core window options (adjust version numbers if needed)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Enable the GLFW runtime error callback function defined previously.
glfwSetErrorCallback(glfwErrorCallback);
// Set additional window options
glfwWindowHint(GLFW_RESIZABLE, windowResizable);
glfwWindowHint(GLFW_SAMPLES, windowSamples); // MSAA
// Create window using GLFW
GLFWwindow* window = glfwCreateWindow(windowWidth,
windowHeight,
windowTitle.c_str(),
nullptr,
nullptr);
// Ensure the window is set up correctly
if (!window)
{
fprintf(stderr, "Could not open GLFW window\n");
glfwTerminate();
exit(EXIT_FAILURE);
}
// Let the window be the current OpenGL context and initialise glad
glfwMakeContextCurrent(window);
gladLoadGL();
// Print various OpenGL information to stdout
printf("%s: %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER));
printf("GLFW\t %s\n", glfwGetVersionString());
printf("OpenGL\t %s\n", glGetString(GL_VERSION));
printf("GLSL\t %s\n\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
return window;
}
int main(int argc, char* argb[])
{
// Initialise window using GLFW
GLFWwindow* window = initialise();
// Run an OpenGL application using this window
runProgram(window);
// Terminate GLFW (no need to call glfwDestroyWindow)
glfwTerminate();
int main(int argc, char *argb[]) {
srand(time(nullptr));
std::cout << "Seed: " << SEED << std::endl;
Game game;
game.run();
return EXIT_SUCCESS;
}

View File

@@ -1,45 +0,0 @@
// Local headers
#include "program.hpp"
#include "gloom/gloom.hpp"
void runProgram(GLFWwindow* window)
{
// Enable depth (Z) buffer (accept "closest" fragment)
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Configure miscellaneous OpenGL settings
glEnable(GL_CULL_FACE);
// Set default colour after clearing the colour buffer
glClearColor(0.3f, 0.5f, 0.8f, 1.0f);
// Set up your scene here (create Vertex Array Objects, etc.)
// Rendering Loop
while (!glfwWindowShouldClose(window))
{
// Clear colour and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw your scene here
// Handle other events
glfwPollEvents();
handleKeyboardInput(window);
// Flip buffers
glfwSwapBuffers(window);
}
}
void handleKeyboardInput(GLFWwindow* window)
{
// Use escape key for terminating the GLFW window
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, GL_TRUE);
}
}

View File

@@ -1,58 +0,0 @@
#ifndef PROGRAM_HPP
#define PROGRAM_HPP
#pragma once
// System headers
#include <GLFW/glfw3.h>
#include <glad/glad.h>
#include <string>
// Main OpenGL program
void runProgram(GLFWwindow* window);
// Function for handling keypresses
void handleKeyboardInput(GLFWwindow* window);
// Checks for whether an OpenGL error occurred. If one did,
// it prints out the error type and ID
inline void printGLError() {
int errorID = glGetError();
if(errorID != GL_NO_ERROR) {
std::string errorString;
switch(errorID) {
case GL_INVALID_ENUM:
errorString = "GL_INVALID_ENUM";
break;
case GL_INVALID_OPERATION:
errorString = "GL_INVALID_OPERATION";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
errorString = "GL_INVALID_FRAMEBUFFER_OPERATION";
break;
case GL_OUT_OF_MEMORY:
errorString = "GL_OUT_OF_MEMORY";
break;
case GL_STACK_UNDERFLOW:
errorString = "GL_STACK_UNDERFLOW";
break;
case GL_STACK_OVERFLOW:
errorString = "GL_STACK_OVERFLOW";
break;
default:
errorString = "[Unknown error ID]";
break;
}
fprintf(stderr, "An OpenGL error occurred (%i): %s.\n",
errorID, errorString.c_str());
}
}
#endif