diff --git a/.gitignore b/.gitignore index 9af1833..c2cd13a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ [Bb]uild/* !*/.gitkeep + +cmake-build-debug/* diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -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 diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..c4c5c0f --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +gloom \ No newline at end of file diff --git a/.idea/VoxelEngine.iml b/.idea/VoxelEngine.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/VoxelEngine.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..929ec77 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e09ceef..d5d5b6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 + $/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 + $/assets) diff --git a/gloom/assets/dirt.png b/gloom/assets/dirt.png new file mode 100644 index 0000000..d9ea267 Binary files /dev/null and b/gloom/assets/dirt.png differ diff --git a/gloom/shaders/simple.frag b/gloom/shaders/simple.frag index 91f8fff..20664b2 100644 --- a/gloom/shaders/simple.frag +++ b/gloom/shaders/simple.frag @@ -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); +} \ No newline at end of file diff --git a/gloom/shaders/simple.shader b/gloom/shaders/simple.shader new file mode 100644 index 0000000..5ca3a81 --- /dev/null +++ b/gloom/shaders/simple.shader @@ -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); +} \ No newline at end of file diff --git a/gloom/shaders/simple.vert b/gloom/shaders/simple.vert index 1178ec6..73dd368 100644 --- a/gloom/shaders/simple.vert +++ b/gloom/shaders/simple.vert @@ -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; +} \ No newline at end of file diff --git a/gloom/src/Block.cpp b/gloom/src/Block.cpp new file mode 100644 index 0000000..7a57f58 --- /dev/null +++ b/gloom/src/Block.cpp @@ -0,0 +1,5 @@ +// +// Created by Bram on 26/08/2024. +// + +#include "Block.h" diff --git a/gloom/src/Block.h b/gloom/src/Block.h new file mode 100644 index 0000000..4525031 --- /dev/null +++ b/gloom/src/Block.h @@ -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 diff --git a/gloom/src/BlockType.h b/gloom/src/BlockType.h new file mode 100644 index 0000000..6d3d9f3 --- /dev/null +++ b/gloom/src/BlockType.h @@ -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 diff --git a/gloom/src/Chunk.cpp b/gloom/src/Chunk.cpp new file mode 100644 index 0000000..9f8e629 --- /dev/null +++ b/gloom/src/Chunk.cpp @@ -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 +#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 vertexes{}; + std::vector 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 + } + } + } +} + + diff --git a/gloom/src/Chunk.h b/gloom/src/Chunk.h new file mode 100644 index 0000000..1325a90 --- /dev/null +++ b/gloom/src/Chunk.h @@ -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 diff --git a/gloom/src/Cube.cpp b/gloom/src/Cube.cpp new file mode 100644 index 0000000..03bf841 --- /dev/null +++ b/gloom/src/Cube.cpp @@ -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 &vertices, std::vector &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 &vertices, std::vector &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); +} diff --git a/gloom/src/Cube.h b/gloom/src/Cube.h new file mode 100644 index 0000000..d63cd65 --- /dev/null +++ b/gloom/src/Cube.h @@ -0,0 +1,62 @@ +// +// Created by Bram on 23/08/2024. +// + +#ifndef GLOOM_CUBE_H +#define GLOOM_CUBE_H + + +#include +#include +#include +#include +#include +#include +#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& vertices, std::vector& indices, const glm::vec3& position, BlockType type); + static void LoadAllFaces(std::vector& vertices, std::vector& 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 diff --git a/gloom/src/Game.cpp b/gloom/src/Game.cpp new file mode 100644 index 0000000..582a18e --- /dev/null +++ b/gloom/src/Game.cpp @@ -0,0 +1,273 @@ +// +// Created by Bram on 23/08/2024. +// + +#include "Game.h" +#include "gloom/config.hpp" +#include "gloom/Camera.h" + +#include +#include +#include +#include + +// 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(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; + } + +} diff --git a/gloom/src/Game.h b/gloom/src/Game.h new file mode 100644 index 0000000..ffa1f3e --- /dev/null +++ b/gloom/src/Game.h @@ -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 m_chunks; +// std::vector m_cubes; + + World* m_world; +}; + + +#endif //GLOOM_GAME_H diff --git a/gloom/src/World.cpp b/gloom/src/World.cpp new file mode 100644 index 0000000..e2fee1f --- /dev/null +++ b/gloom/src/World.cpp @@ -0,0 +1,104 @@ +// +// Created by Bram on 26/08/2024. +// + +#include "World.h" +#include +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; + } + } +} diff --git a/gloom/src/World.h b/gloom/src/World.h new file mode 100644 index 0000000..0869ea8 --- /dev/null +++ b/gloom/src/World.h @@ -0,0 +1,42 @@ +// +// Created by Bram on 26/08/2024. +// + +#ifndef GLOOM_WORLD_H +#define GLOOM_WORLD_H + +#include +#include "Chunk.h" +#include "gloom/Singleton.h" + + +class World: public Singleton { +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 diff --git a/gloom/src/gloom/Camera.cpp b/gloom/src/gloom/Camera.cpp new file mode 100644 index 0000000..bc6ddaa --- /dev/null +++ b/gloom/src/gloom/Camera.cpp @@ -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 << ", " < +#include +#include +#include + +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 diff --git a/gloom/src/gloom/Mesh.cpp b/gloom/src/gloom/Mesh.cpp new file mode 100644 index 0000000..eece878 --- /dev/null +++ b/gloom/src/gloom/Mesh.cpp @@ -0,0 +1,89 @@ +// +// Created by Bram on 23/08/2024. +// + +#include "Mesh.h" +#include "glad/glad.h" +#include "config.hpp" +#include +#include +#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 &vertices, const std::vector &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 +} diff --git a/gloom/src/gloom/Mesh.h b/gloom/src/gloom/Mesh.h new file mode 100644 index 0000000..6abb664 --- /dev/null +++ b/gloom/src/gloom/Mesh.h @@ -0,0 +1,46 @@ +// +// Created by Bram on 23/08/2024. +// + +#ifndef GLOOM_MESH_H +#define GLOOM_MESH_H + +#include +#include +#include "glad/glad.h" +#include "Texture.h" + +class Mesh { +public: + struct Vertex{ + glm::vec3 position; + glm::dvec2 texCoords; + }; + + Mesh(); + ~Mesh(); + Mesh(const std::vector& vertices, const std::vector& 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 vertices; + std::vector indices; + + Texture* m_texture{ nullptr }; +}; + + +#endif //GLOOM_MESH_H diff --git a/gloom/src/gloom/PerlinNoise.hpp b/gloom/src/gloom/PerlinNoise.hpp new file mode 100644 index 0000000..9dc3106 --- /dev/null +++ b/gloom/src/gloom/PerlinNoise.hpp @@ -0,0 +1,659 @@ +//---------------------------------------------------------------------------------------- +// +// siv::PerlinNoise +// Perlin noise library for modern C++ +// +// Copyright (C) 2013-2021 Ryo Suzuki +// +// 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 +# include +# include +# include +# include +# include +# include + +# if __has_include() && defined(__cpp_concepts) +# include +# 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 +# define SIVPERLIN_CONCEPT_URBG_ template +# else +# define SIVPERLIN_CONCEPT_URBG template , std::is_unsigned>>>* = nullptr> +# define SIVPERLIN_CONCEPT_URBG_ template , std::is_unsigned>>>*> +# 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 BasicPerlinNoise + { + public: + + static_assert(std::is_floating_point_v); + + /////////////////////////////////////// + // + // Typedefs + // + + using state_type = std::array; + + 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; + + 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 + inline void Shuffle(RandomIt first, RandomIt last, URBG&& urbg) + { + if (first == last) + { + return; + } + + using difference_type = typename std::iterator_traits::difference_type; + + for (RandomIt it = first + 1; it < last; ++it) + { + const std::uint64_t n = static_cast(it - first); + std::iter_swap(it, first + static_cast(Random(n, std::forward(urbg)))); + } + } + // + //////////////////////////////////////////////// + + template + [[nodiscard]] + inline constexpr Float Fade(const Float t) noexcept + { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + template + [[nodiscard]] + inline constexpr Float Lerp(const Float a, const Float b, const Float t) noexcept + { + return (a + (b - a) * t); + } + + template + [[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 + [[nodiscard]] + inline constexpr Float Remap_01(const Float x) noexcept + { + return (x * Float(0.5) + Float(0.5)); + } + + template + [[nodiscard]] + inline constexpr Float Clamp_11(const Float x) noexcept + { + return std::clamp(x, Float(-1.0), Float(1.0)); + } + + template + [[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 + [[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 + [[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 + [[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 + [[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 + inline constexpr BasicPerlinNoise::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 + inline BasicPerlinNoise::BasicPerlinNoise(const seed_type seed) + { + reseed(seed); + } + + template + SIVPERLIN_CONCEPT_URBG_ + inline BasicPerlinNoise::BasicPerlinNoise(URBG&& urbg) + { + reseed(std::forward(urbg)); + } + + /////////////////////////////////////// + + template + inline void BasicPerlinNoise::reseed(const seed_type seed) + { + reseed(default_random_engine{ seed }); + } + + template + SIVPERLIN_CONCEPT_URBG_ + inline void BasicPerlinNoise::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)); + } + + /////////////////////////////////////// + + template + inline constexpr const typename BasicPerlinNoise::state_type& BasicPerlinNoise::serialize() const noexcept + { + return m_permutation; + } + + template + inline constexpr void BasicPerlinNoise::deserialize(const state_type& state) noexcept + { + m_permutation = state; + } + + /////////////////////////////////////// + + template + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise1D(const value_type x) const noexcept + { + return noise3D(x, + static_cast(SIVPERLIN_DEFAULT_Y), + static_cast(SIVPERLIN_DEFAULT_Z)); + } + + template + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise2D(const value_type x, const value_type y) const noexcept + { + return noise3D(x, + y, + static_cast(SIVPERLIN_DEFAULT_Z)); + } + + template + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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(_x) & 255; + const std::int32_t iy = static_cast(_y) & 255; + const std::int32_t iz = static_cast(_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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise1D_01(const value_type x) const noexcept + { + return perlin_detail::Remap_01(noise1D(x)); + } + + template + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise2D_01(const value_type x, const value_type y) const noexcept + { + return perlin_detail::Remap_01(noise2D(x, y)); + } + + template + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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 + inline typename BasicPerlinNoise::value_type BasicPerlinNoise::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_ diff --git a/gloom/src/gloom/Shader.cpp b/gloom/src/gloom/Shader.cpp new file mode 100644 index 0000000..4525835 --- /dev/null +++ b/gloom/src/gloom/Shader.cpp @@ -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)); +} \ No newline at end of file diff --git a/gloom/src/gloom/Shader.h b/gloom/src/gloom/Shader.h new file mode 100644 index 0000000..700bded --- /dev/null +++ b/gloom/src/gloom/Shader.h @@ -0,0 +1,41 @@ +// +// Created by Bram on 23/08/2024. +// + +#ifndef GLOOM_SHADER_H +#define GLOOM_SHADER_H + +#include + +#include +#include +#include +#include + +#include +#include +#include + +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 diff --git a/gloom/src/gloom/Singleton.h b/gloom/src/gloom/Singleton.h new file mode 100644 index 0000000..ec1c0c8 --- /dev/null +++ b/gloom/src/gloom/Singleton.h @@ -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 +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 diff --git a/gloom/src/gloom/Texture.cpp b/gloom/src/gloom/Texture.cpp new file mode 100644 index 0000000..3c4342d --- /dev/null +++ b/gloom/src/gloom/Texture.cpp @@ -0,0 +1,52 @@ +// +// Created by Bram on 23/08/2024. +// + +#include "Texture.h" +#include "glad/glad.h" +#include + +#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); +} diff --git a/gloom/src/gloom/Texture.h b/gloom/src/gloom/Texture.h new file mode 100644 index 0000000..7fda4e5 --- /dev/null +++ b/gloom/src/gloom/Texture.h @@ -0,0 +1,24 @@ +// +// Created by Bram on 23/08/2024. +// + +#ifndef GLOOM_TEXTURE_H +#define GLOOM_TEXTURE_H + + +#include + +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 diff --git a/gloom/src/gloom/TextureManager.cpp b/gloom/src/gloom/TextureManager.cpp new file mode 100644 index 0000000..5d9c7a5 --- /dev/null +++ b/gloom/src/gloom/TextureManager.cpp @@ -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]; +} diff --git a/gloom/src/gloom/TextureManager.h b/gloom/src/gloom/TextureManager.h new file mode 100644 index 0000000..308a8f0 --- /dev/null +++ b/gloom/src/gloom/TextureManager.h @@ -0,0 +1,27 @@ +// +// Created by Bram on 25/08/2024. +// + +#ifndef GLOOM_TEXTUREMANAGER_H +#define GLOOM_TEXTUREMANAGER_H + + +#include +#include "Singleton.h" +#include "Texture.h" +#include + +class TextureManager: public Singleton{ +public: + TextureManager() = default; + ~TextureManager() override = default; + + Texture * getTexture(const std::string& path); + +private: + std::unordered_map m_textures; + +}; + + +#endif //GLOOM_TEXTUREMANAGER_H diff --git a/gloom/src/gloom/camera.hpp b/gloom/src/gloom/camera.hpp deleted file mode 100644 index bbfe338..0000000 --- a/gloom/src/gloom/camera.hpp +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef CAMERA_HPP -#define CAMERA_HPP -#pragma once - -// System headers -#include -#include -#include -#include -#include - - -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 diff --git a/gloom/src/gloom/config.hpp b/gloom/src/gloom/config.hpp new file mode 100644 index 0000000..5907b15 --- /dev/null +++ b/gloom/src/gloom/config.hpp @@ -0,0 +1,45 @@ +// Preprocessor directives +#ifndef GLOOM_HPP +#define GLOOM_HPP +#pragma once + +// System Headers +#include + +// Standard headers +#include +#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(SEED) }; + +#endif diff --git a/gloom/src/gloom/gloom.hpp b/gloom/src/gloom/gloom.hpp deleted file mode 100644 index a2eccbf..0000000 --- a/gloom/src/gloom/gloom.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// Preprocessor directives -#ifndef GLOOM_HPP -#define GLOOM_HPP -#pragma once - -// System Headers -#include - -// Standard headers -#include - -// Constants -const int windowWidth = 1024; -const int windowHeight = 768; -const std::string windowTitle = "OpenGL"; -const GLint windowResizable = GL_FALSE; -const int windowSamples = 4; - -#endif diff --git a/gloom/src/gloom/old/Cube.cpp b/gloom/src/gloom/old/Cube.cpp new file mode 100644 index 0000000..36195d0 --- /dev/null +++ b/gloom/src/gloom/old/Cube.cpp @@ -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 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 &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 &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); +//} diff --git a/gloom/src/gloom/old/Cube.h b/gloom/src/gloom/old/Cube.h new file mode 100644 index 0000000..66eb62f --- /dev/null +++ b/gloom/src/gloom/old/Cube.h @@ -0,0 +1,89 @@ +//// +//// Created by Bram on 23/08/2024. +//// +// +//#ifndef GLOOM_CUBE_H +//#define GLOOM_CUBE_H +// +// +//#include +//#include +//#include +//#include +//#include +//#include +//#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 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& vertices); +// void LoadAllFaces(std::vector& vertices); +// +// Mesh mesh; +//private: +// GLuint VAO{}, VBO{}, EBO{}; +// glm::vec3 position; +// +// Texture texture; +// BlockType type{ BlockType::AIR }; +// void setupCube(); +//}; +// +// +//#endif //GLOOM_CUBE_H diff --git a/gloom/src/gloom/shader.hpp b/gloom/src/gloom/shader.hpp deleted file mode 100644 index bd722be..0000000 --- a/gloom/src/gloom/shader.hpp +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef SHADER_HPP -#define SHADER_HPP -#pragma once - -// System headers -#include - -// Standard headers -#include -#include -#include -#include - - -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(fd), - (std::istreambuf_iterator())); - - // 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 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 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 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 diff --git a/gloom/src/main.cpp b/gloom/src/main.cpp index 2ee46a2..2291047 100644 --- a/gloom/src/main.cpp +++ b/gloom/src/main.cpp @@ -1,82 +1,19 @@ // Local headers -#include "gloom/gloom.hpp" -#include "program.hpp" - -// System headers -#include -#include +#include "gloom/config.hpp" +#include "Game.h" // Standard headers #include -// 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; } diff --git a/gloom/src/program.cpp b/gloom/src/program.cpp deleted file mode 100644 index e1e6d02..0000000 --- a/gloom/src/program.cpp +++ /dev/null @@ -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); - } -} diff --git a/gloom/src/program.hpp b/gloom/src/program.hpp deleted file mode 100644 index e38b73b..0000000 --- a/gloom/src/program.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef PROGRAM_HPP -#define PROGRAM_HPP -#pragma once - - -// System headers -#include -#include -#include - - -// 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