Compare commits

2 Commits

Author SHA1 Message Date
benkyd
d6f12162a9 minor changes to make running easier 2022-05-11 14:02:36 +00:00
benkyd
4740c9a85c WOrking version 2022-05-11 13:44:34 +00:00
40 changed files with 21573 additions and 96 deletions

View File

@@ -1,9 +1,10 @@
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
project(MingeCraft) project(OpenGLPlayground)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CMakeModules/) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CMakeModules/)
cmake_policy(SET CMP0037 OLD)
# set(CMAKE_BUILD_TYPE Debug) set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "-Ofast") set(CMAKE_CXX_FLAGS "-Ofast")
set(executable output) set(executable output)
@@ -15,7 +16,6 @@ add_definitions(-DMC_RESOURCES="${CMAKE_SOURCE_DIR}/resources/")
message(${CMAKE_SOURCE_DIR}/resources) message(${CMAKE_SOURCE_DIR}/resources)
if (UNIX) if (UNIX)
find_package(glm REQUIRED)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
endif(UNIX) endif(UNIX)
@@ -46,23 +46,23 @@ include_directories(${executable}
file(GLOB SourceFiles file(GLOB SourceFiles
${SrcDIR}/* ${SrcDIR}/*
${SrcDIR}/ThirdParty/* ${SrcDIR}/util/*
${SrcDIR}/Rendering/* ${SrcDIR}/game/*
${SrcDIR}/Rendering/Platform/* ${SrcDIR}/world/*
${SrcDIR}/World/* ${SrcDIR}/world/chunk/*
${SrcDIR}/renderer/*
) )
add_executable(${executable} ${SourceFiles}) add_executable(${executable} ${SourceFiles})
set_target_properties(${executable} PROPERTIES set_target_properties(${executable} PROPERTIES
CXX_STANDARD 20 CXX_STANDARD 17
CXX_EXTENSIONS ON CXX_EXTENSIONS OFF
) )
if (UNIX) if (UNIX)
target_link_libraries(${executable} target_link_libraries(${executable}
SDL2 SDL2
glm
OpenGL::OpenGL OpenGL::OpenGL
OpenGL::GL OpenGL::GL
Threads::Threads Threads::Threads

View File

@@ -16,7 +16,7 @@ class Mesh
public: public:
Mesh(); Mesh();
private: private:
GLuint mVAO; GLuint mVAO;

View File

@@ -3,7 +3,6 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp> #include <glm/gtx/hash.hpp>
#include <glm/glm.hpp> #include <glm/glm.hpp>

16
src/config.hpp Normal file
View File

@@ -0,0 +1,16 @@
#ifndef MINECRAFT_CONFIG_H_
#define MINECRAFT_CONFIG_H_
#include "common.hpp"
class Config {
public:
std::string ResourceBase = MC_RESOURCES;
// std::string ResourceBase = "E:/Games/minecraft/resources/";
};
static Config GameConfig;
#endif

184
src/game.cpp Normal file
View File

@@ -0,0 +1,184 @@
#include "game.hpp"
// For glm::vec2 as the key of a hashmap
#define GLM_ENABLE_EXPERIMENTAL
#define LOGGER_DEFINITION
#include <logger.h>
#include "renderer/renderer.hpp"
#include "renderer/texture.hpp"
#include "renderer/shader.hpp"
#include "renderer/camera.hpp"
#include "world/chunk/chunk.hpp"
#include "world/entity.hpp"
#include "world/world.hpp"
#include "world/block.hpp"
#include "common.hpp"
#include "config.hpp"
Game::Game() {
}
void Game::Setup(int w, int h) {
m_logger = std::make_shared<Logger>();
*m_logger << "----------------" << LOGGER_ENDL;
*m_logger << "Minecraft 1.14.2" << LOGGER_ENDL;
*m_logger << "----------------" << LOGGER_ENDL;
*m_logger << LOGGER_ENDL;
#ifdef __DEBUG
*m_logger << LOGGER_DEBUG << "Debug mode enabled" << LOGGER_ENDL;
#endif
*m_logger << LOGGER_INFO << "Initializing display" << LOGGER_ENDL;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
// Create GL window
*m_logger << LOGGER_INFO << "Creating window" << LOGGER_ENDL;
m_window = SDL_CreateWindow("Minecraft 1.14.2",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, w, h,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
// Create GL context
*m_logger << LOGGER_INFO << "Creating OpenGL context" << LOGGER_ENDL;
m_glContext = SDL_GL_CreateContext(m_window);
SDL_SetRelativeMouseMode(SDL_TRUE);
// Set VSYNC swap interval
SDL_GL_SetSwapInterval(1);
*m_logger << LOGGER_INFO << "Display set up" << LOGGER_ENDL;
// Load OpenGL
gladLoadGLLoader(SDL_GL_GetProcAddress);
glEnable(GL_MULTISAMPLE);
// glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
*m_logger << LOGGER_INFO << "Loaded OpenGL" << LOGGER_ENDL;
*m_logger << LOGGER_ENDL;
IsDisplayOpen = true;
std::shared_ptr<Camera> playercamera = std::make_shared<Camera>(w, h);
m_player = std::make_shared<Player>(glm::vec3(0), glm::vec3(0), playercamera);
std::shared_ptr<CBlockDictionary> BlockDictionary = CBlockDictionary::GetInstance();
BlockDictionary->Build();
m_world = std::make_shared<World>();
Texture texture;
m_world->SetTextureMap(texture.LoadTextures(BlockDictionary->Textures));
m_world->LoadWorld();
}
void Game::Input(SDL_Event* e) {
Uint8* state = (Uint8*)SDL_GetKeyboardState(NULL);
while (SDL_PollEvent(e)) {
switch (e->type) {
case SDL_KEYDOWN:
{
if (e->key.keysym.sym == SDLK_ESCAPE) {
IsMouseActive = !IsMouseActive;
if (IsMouseActive)
SDL_SetRelativeMouseMode(SDL_TRUE);
else
SDL_SetRelativeMouseMode(SDL_FALSE);
}
break;
}
case SDL_WINDOWEVENT:
{
if (e->window.event == SDL_WINDOWEVENT_RESIZED) {
m_player->CameraUpdateProjection(e->window.data1, e->window.data2);
glViewport(0, 0, e->window.data1, e->window.data2);
}
break;
}
case SDL_QUIT:
{
IsDisplayOpen = false;
break;
}
}
if (IsMouseActive) m_player->HandleMouseSDL(*e);
}
m_player->MoveSDL(state);
}
void Game::Run() {
SDL_Event e;
const float clear[] = { 186.0f / 255.0f, 214.0f / 255.0f, 254.0f / 255.0f };
m_renderer = std::make_unique<Renderer>();
while (IsDisplayOpen) {
Input(&e);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearBufferfv(GL_COLOR, 0, clear);
m_world->Update(m_player);
m_renderer->Render(m_world, m_player);
SDL_GL_SwapWindow(m_window);
}
}

55
src/game.hpp Normal file
View File

@@ -0,0 +1,55 @@
#ifndef MINECRAFT_GAME_H_
#define MINECRAFT_GAME_H_
#ifdef NDEBUG
#define __DEBUG
#endif
#define __DEBUG
// #define __IMGUI
#include <memory>
#include <string>
#include <map>
#if _WIN32
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
class Logger;
class Renderer;
class Camera;
class Player;
class World;
class Game {
public:
Game();
void Setup(int w, int h);
void Input(SDL_Event* e);
void Run();
bool IsDisplayOpen = false;
bool IsMouseActive = true;
private:
SDL_Window* m_window = nullptr;
SDL_GLContext m_glContext = nullptr;
std::shared_ptr<Logger> m_logger;
std::shared_ptr<Renderer> m_renderer;
std::shared_ptr<World> m_world;
std::shared_ptr<Player> m_player;
};
#endif

View File

@@ -1,90 +1,14 @@
#include <iostream> #include <iostream>
#include <sstream>
#define LOGGER_DEFINITION #include "game.hpp"
#include <logger.h>
#if _WIN32
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#include "display.hpp"
#include "settings.hpp"
#include "Rendering/rendermaster.hpp"
#include "Rendering/texture.hpp"
#include "Rendering/camera.hpp"
#include "Rendering/mesh.hpp"
#define __DEBUG int main(int argc, char** argv) {
static const int VERSION_MAJOR = 0; Game game;
static const int VERSION_MINOR = 0; game.Setup(1080, 720);
static const int VERSION_PATCH = 1; game.Run();
void version()
{
std::stringstream version;
const auto& container = []( std::string s ) { std::string r = ""; for ( auto& c : s ) { r += "-"; } return r; };
version << "Minecraft ";
version << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH;
std::cout << container( version.str() ) << std::endl;
std::cout << version.str() << std::endl;
std::cout << container( version.str() ) << std::endl;
}
void Loop( Display* display )
{
SDL_Event e;
while ( display->IsWindowOpen )
{
display->PrepareFrame();
// make framerate agnostic
display->Input( &e );
// rendering here
display->NextFrame();
}
// cleanup
}
int main( int argc, char** argv )
{
version();
Logger mLogger;
#ifdef __DEBUG
mLogger << LOGGER_DEBUG << "Debug mode enabled" << LOGGER_ENDL;
#endif
// settup display
std::stringstream version;
version << "Minecraft ";
version << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH;
Display display { WindowWidth, WindowHeight, version.str() };
Loop( &display );
return 0; return 0;
} }

35
src/physics/collider.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "collider.hpp"
EntityCollider::EntityCollider() {
}
glm::vec3 EntityCollider::TerrainCollide(std::vector<uint8_t> terrain) {
}
bool EntityCollider::m_aabb(ColliderBox a, ColliderBox b) {
return {
(a.Min.x <= b.Min.x + b.Max.x && a.Min.x + a.Max.x >= b.Min.x) &&
(a.Min.y <= b.Min.y + b.Max.y && a.Min.y + a.Max.y >= b.Min.y) &&
(a.Min.z <= b.Min.z + b.Max.z && a.Min.z + a.Max.z >= b.Min.z)
};
}
float EntityCollider::m_xDepth(ColliderBox a, ColliderBox b) {
}
float EntityCollider::m_yDepth(ColliderBox a, ColliderBox b) {
}
float EntityCollider::m_zDepth(ColliderBox a, ColliderBox b) {
}

39
src/physics/collider.hpp Normal file
View File

@@ -0,0 +1,39 @@
#ifndef MINECRAFT_PHYSICS_COLLIDER_H_
#define MINECRAFT_PHYSICS_COLLIDER_H_
#include "../common.hpp"
class ColliderBox {
public:
glm::vec3 Min;
glm::vec3 Max;
};
class Collider : public ColliderBox {
public:
};
// TODO: Trees
class EntityCollider {
public:
EntityCollider();
// Surrounding blocks indexed XYZ
// Returns point of collision
glm::vec3 TerrainCollide(std::vector<uint8_t> surroundingBlocks);
ColliderBox Bounds;
private:
bool m_aabb(ColliderBox a, ColliderBox b);
float m_xDepth(ColliderBox a, ColliderBox b);
float m_yDepth(ColliderBox a, ColliderBox b);
float m_zDepth(ColliderBox a, ColliderBox b);
};
#endif

191
src/renderer/camera.cpp Normal file
View File

@@ -0,0 +1,191 @@
#include "camera.hpp"
Camera::Camera() {
projMatrix = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 1000.0f);
Roll = 0.0f;
Pitch = 0.0f;
Yaw = 0.0f;
Position = {};
LookDirection = {};
viewMatrix = {};
UpdateView();
}
Camera::Camera(int w, int h) {
projMatrix = glm::perspective(glm::radians(45.0f), (float)w / float(h), 0.1f, 1000.0f);
Roll = 0.0f;
Pitch = 0.0f;
Yaw = 0.0f;
Position = {};
LookDirection = {};
viewMatrix = {};
UpdateView();
}
void Camera::UpdateView() {
// roll can be removed
glm::mat4 matRoll = glm::mat4(1.0f); //identity matrix;
glm::mat4 matPitch = glm::mat4(1.0f);//identity matrix
glm::mat4 matYaw = glm::mat4(1.0f); //identity matrix
// roll, pitch and yaw
matRoll = glm::rotate(matRoll, Roll, glm::vec3(0.0f, 0.0f, 1.0f));
matPitch = glm::rotate(matPitch, Pitch, glm::vec3(1.0f, 0.0f, 0.0f));
matYaw = glm::rotate(matYaw, Yaw, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 rotate = matRoll * matPitch * matYaw;
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -Position);
viewMatrix = rotate * translate;
// Work out Look Vector
glm::mat4 inverseView = glm::inverse(viewMatrix);
LookDirection.x = inverseView[2][0];
LookDirection.y = inverseView[2][1];
LookDirection.z = inverseView[2][2];
}
glm::mat4 Camera::GetViewMatrix() {
return viewMatrix;
}
glm::mat4 Camera::GetProjectionMatrix() {
return projMatrix;
}
void Camera::UpdateProjection(int width, int height) {
projMatrix = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 1000.0f);
}
void Camera::HandleMouse(SDL_Event e) {
if (e.type != SDL_MOUSEMOTION)
return;
float mouseDX = e.motion.xrel;
float mouseDY = e.motion.yrel;
glm::vec2 mouseDelta{ mouseDX, mouseDY };
MouseMoved(mouseDelta);
}
void Camera::MoveCamera(Uint8* state) {
float dx = 0;
float dz = 0;
float dy = 0;
// Rotate by camera direction
glm::mat2 rotate {
cos(Yaw), -sin(Yaw),
sin(Yaw), cos(Yaw)
};
glm::vec2 f(0.0, 1.0);
f = f * rotate;
if (state[SDL_SCANCODE_W]) {
dz -= f.y;
dx -= f.x;
}
if (state[SDL_SCANCODE_S]) {
dz += f.y;
dx += f.x;
}
if (state[SDL_SCANCODE_A]) {
dz += f.x;
dx += -f.y;
}
if (state[SDL_SCANCODE_D]) {
dz -= f.x;
dx -= -f.y;
}
if (state[SDL_SCANCODE_SPACE]) {
dy += 1;
}
if (state[SDL_SCANCODE_LSHIFT]) {
dy -= 1;
}
// get current view matrix
glm::mat4 mat = GetViewMatrix();
glm::vec3 forward(mat[0][2], mat[1][2], mat[2][2]);
glm::vec3 strafe(mat[0][0], mat[1][0], mat[2][0]);
// forward vector must be negative to look forward.
// read :http://in2gpu.com/2015/05/17/view-matrix/
Position.x += dx * CameraSpeed;
Position.z += dz * CameraSpeed;
Position.y += dy * CameraSpeed;
// update the view matrix
UpdateView();
}
void Camera::MouseMoved(glm::vec2 mouseDelta) {
// note that yaw and pitch must be converted to radians.
// this is done in UpdateView() by glm::rotate
Yaw += MouseSensitivity * (mouseDelta.x/100);
Pitch += MouseSensitivity * (mouseDelta.y/100);
Pitch = glm::clamp<float>(Pitch, -M_PI/2, M_PI/2);
UpdateView();
}
void Camera::UpdatePosition(glm::vec3 position) {
Position = position;
UpdateView();
}
void Camera::UpdateEulerLookDirection(float roll, float pitch, float yaw) {
Roll = roll; Pitch = pitch; Yaw = yaw;
LookDirection.x = cos(Yaw) * cos(Pitch);
LookDirection.y = sin(Yaw) * cos(Pitch);
LookDirection.z = sin(Pitch);
UpdateView();
}
void Camera::UpdateLookDirection(glm::vec3 lookDirection) {
LookDirection = lookDirection;
Pitch = asin(-lookDirection.y);
Yaw = atan2(lookDirection.x, lookDirection.z);
UpdateView();
}

43
src/renderer/camera.hpp Normal file
View File

@@ -0,0 +1,43 @@
#ifndef MINECRAFT_RENDERER_CAMERA_H_
#define MINECRAFT_RENDERER_CAMERA_H_
#include "../common.hpp"
class Camera {
public:
Camera();
Camera(int w, int h);
void UpdateView();
glm::mat4 GetViewMatrix();
glm::mat4 GetProjectionMatrix();
glm::mat4 GetFrustrumMatrix();
void UpdateProjection(int width, int height);
// Keyboard
void MoveCamera(Uint8* state);
// Mouse
void HandleMouse(SDL_Event e);
void MouseMoved(glm::vec2 mouseDelta);
float MouseSensitivity = 0.1f;
float CameraSpeed = 2.0f;
void UpdatePosition(glm::vec3 position);
void UpdateEulerLookDirection(float roll, float pitch, float yaw);
void UpdateLookDirection(glm::vec3 lookDirection);
glm::vec3 Position = {};
float Roll, Pitch, Yaw;
glm::vec3 LookDirection = {};
private:
glm::mat4 viewMatrix = {};
glm::mat4 projMatrix = {};
};
#endif

View File

@@ -0,0 +1,3 @@
#include "frustrum.hpp"

36
src/renderer/frustrum.hpp Normal file
View File

@@ -0,0 +1,36 @@
#ifndef MINECRAFT_RENDERER_FRUSTRUM_H_
#define MINECRAFT_RENDERER_FRUSTRUM_H_
#include "../common.hpp"
namespace EFrustrumPlanes {
enum Planes {
Right,
Left,
Top,
Bottom,
Far,
Near
};
};
class FrustrumPlane {
public:
};
class Frustrum {
public:
};
#endif

16
src/renderer/renderer.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "renderer.hpp"
#include "../world/chunk/chunk.hpp"
#include "../world/world.hpp"
#include "shader.hpp"
Renderer::Renderer() {
}
// Perform the render passes
void Renderer::Render(std::shared_ptr<World> world, std::shared_ptr<Entity> entity) {
world->Render(entity);
}

18
src/renderer/renderer.hpp Normal file
View File

@@ -0,0 +1,18 @@
#ifndef MINECRAFT_RENDERER_RENDERER_H_
#define MINECRAFT_RENDERER_RENDERER_H_
#include "../common.hpp"
class Entity;
class World;
// Does GL render passes then returns to the game loop
class Renderer {
public:
Renderer();
void Render(std::shared_ptr<World> world, std::shared_ptr<Entity> entity);
};
#endif

109
src/renderer/shader.cpp Normal file
View File

@@ -0,0 +1,109 @@
#include "shader.hpp"
Shader::Shader()
: m_fileReader() {
Program = 0;
m_frag = 0;
m_vert = 0;
m_logger = std::make_shared<Logger>();
}
void Shader::Load(std::string path) {
std::string vertexLocation = path + ".vert";
Load(vertexLocation, GL_VERTEX_SHADER);
*m_logger << LOGGER_INFO << "Vertex shader at '" << vertexLocation << "' loaded..." << LOGGER_ENDL;
std::string fragmentLocation = path + ".frag";
Load(fragmentLocation, GL_FRAGMENT_SHADER);
*m_logger << LOGGER_INFO << "Fragment shader at '" << fragmentLocation << "' loaded..." << LOGGER_ENDL;
}
void Shader::Load(std::string path, GLenum type) {
GLuint activeShader = 0;
if (type == GL_VERTEX_SHADER)
m_vert = activeShader = glCreateShader(type);
if (type == GL_FRAGMENT_SHADER)
m_frag = activeShader = glCreateShader(type);
std::string loadedShaderSource = m_fileReader.LoadTextFromFile(path);
const char* shaderSource = loadedShaderSource.c_str();
int shaderSourceLength = loadedShaderSource.length();
glShaderSource(activeShader, 1, &shaderSource, &shaderSourceLength);
}
void Shader::Link() {
if (m_vert == 0 || m_frag == 0) {
*m_logger << LOGGER_ERROR << "Failed to link programs: Both programs not present" << LOGGER_ENDL;
return;
}
glCompileShader(m_vert);
if (m_CheckShader(m_vert)) {
*m_logger << LOGGER_INFO << "Vertex shader '" << m_vert << "' compiled..." << LOGGER_ENDL;
}
glCompileShader(m_frag);
if (m_CheckShader(m_frag)) {
*m_logger << LOGGER_INFO << "Fragment shader '" << m_frag << "' compiled..." << LOGGER_ENDL;
}
Program = glCreateProgram();
glAttachShader(Program, m_vert);
glAttachShader(Program, m_frag);
glLinkProgram(Program);
glDeleteShader(m_vert);
glDeleteShader(m_frag);
*m_logger << LOGGER_INFO << "Program '" << Program << "' loaded..." << LOGGER_ENDL;
}
void Shader::Use() {
glUseProgram(Program);
}
bool Shader::m_CheckShader(GLuint uid) {
GLint status = GL_TRUE;
glGetShaderiv(uid, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
char buf[512];
glGetShaderInfoLog(uid, 512, NULL, buf);
*m_logger << LOGGER_ERROR << buf << LOGGER_ENDL;
delete buf;
return false;
}
return true;
}
Shader::~Shader() {
glDeleteProgram(Program);
glDeleteShader(m_vert);
glDeleteShader(m_frag);
}

33
src/renderer/shader.hpp Normal file
View File

@@ -0,0 +1,33 @@
#ifndef MINECRAFT_RENDERER_SHADER_H_
#define MINECRAFT_RENDERER_SHADER_H_
#include <logger.h>
#include "../util/filereader.hpp"
#include "../common.hpp"
class Shader {
public:
Shader();
void Load(std::string path);
void Load(std::string path, GLenum type);
GLuint Program;
void Link();
void Use();
~Shader();
private:
std::shared_ptr<Logger> m_logger;
bool m_CheckShader(GLuint uid);
FileReader m_fileReader;
GLuint m_vert;
GLuint m_frag;
};
#endif

60
src/renderer/texture.cpp Normal file
View File

@@ -0,0 +1,60 @@
#include "texture.hpp"
#include <logger.h>
#include "../config.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "../util/stb_image.hpp"
GLuint Texture::LoadTextures(std::vector<std::string> textures) {
Logger logger;
std::string basePath = GameConfig.ResourceBase + "textures/";
int x = 16;
int y = 16;
GLsizei layers = textures.size();
GLubyte* texels = (GLubyte*)malloc(x * y * 4 * layers * sizeof(GLubyte));
for (int i = 0; i < layers; i++) {
std::string path = basePath + textures[i];
int xR = 0;
int yR = 0;
int cR = 0;
unsigned char* texture = stbi_load(path.c_str(), &xR, &yR, &cR, STBI_rgb_alpha);
memcpy(texels + (i * x * y * 4), texture, x * y * 4);
stbi_image_free(texture);
logger << LOGGER_INFO << "Texture at '" << path << "' Loaded..." << LOGGER_ENDL;
}
GLuint textureArray = 0;
glGenTextures(1, &textureArray);
glBindTexture(GL_TEXTURE_2D_ARRAY, textureArray);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, x, y, layers, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, x, y, layers, GL_RGBA, GL_UNSIGNED_BYTE, texels);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
free(texels);
return textureArray;
}

11
src/renderer/texture.hpp Normal file
View File

@@ -0,0 +1,11 @@
#ifndef MINECRAFT_RENDERER_TEXTURE_H_
#define MINECRAFT_RENDERER_TEXTURE_H_
#include "../common.hpp"
class Texture {
public:
GLuint LoadTextures(std::vector<std::string> textures);
};
#endif

View File

@@ -6,8 +6,8 @@
// TODO: import settings and stuff // TODO: import settings and stuff
// for now this works // for now this works
static const int WindowWidth = 1000; static const int WindowWidth = 1920;
static const int WindowHeight = 600; static const int WindowHeight = 1080;
static const std::string ResourceBase = MC_RESOURCES; static const std::string ResourceBase = MC_RESOURCES;

2250
src/util/fastnoise.cpp Normal file

File diff suppressed because it is too large Load Diff

311
src/util/fastnoise.hpp Normal file
View File

@@ -0,0 +1,311 @@
// FastNoise.h
//
// MIT License
//
// Copyright(c) 2017 Jordan Peck
//
// 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.
//
// The developer's email is jorzixdan.me2@gzixmail.com (for great email, take
// off every 'zix'.)
//
// VERSION: 0.4.1
#ifndef FASTNOISE_H
#define FASTNOISE_H
// Uncomment the line below to use doubles throughout FastNoise instead of floats
//#define FN_USE_DOUBLES
#define FN_CELLULAR_INDEX_MAX 3
#ifdef FN_USE_DOUBLES
typedef double FN_DECIMAL;
#else
typedef float FN_DECIMAL;
#endif
class FastNoise
{
public:
explicit FastNoise(int seed = 1337) { SetSeed(seed); CalculateFractalBounding(); }
enum NoiseType { Value, ValueFractal, Perlin, PerlinFractal, Simplex, SimplexFractal, Cellular, WhiteNoise, Cubic, CubicFractal };
enum Interp { Linear, Hermite, Quintic };
enum FractalType { FBM, Billow, RigidMulti };
enum CellularDistanceFunction { Euclidean, Manhattan, Natural };
enum CellularReturnType { CellValue, NoiseLookup, Distance, Distance2, Distance2Add, Distance2Sub, Distance2Mul, Distance2Div };
// Sets seed used for all noise types
// Default: 1337
void SetSeed(int seed);
// Returns seed used for all noise types
int GetSeed() const { return m_seed; }
// Sets frequency for all noise types
// Default: 0.01
void SetFrequency(FN_DECIMAL frequency) { m_frequency = frequency; }
// Returns frequency used for all noise types
FN_DECIMAL GetFrequency() const { return m_frequency; }
// Changes the interpolation method used to smooth between noise values
// Possible interpolation methods (lowest to highest quality) :
// - Linear
// - Hermite
// - Quintic
// Used in Value, Perlin Noise and Position Warping
// Default: Quintic
void SetInterp(Interp interp) { m_interp = interp; }
// Returns interpolation method used for supported noise types
Interp GetInterp() const { return m_interp; }
// Sets noise return type of GetNoise(...)
// Default: Simplex
void SetNoiseType(NoiseType noiseType) { m_noiseType = noiseType; }
// Returns the noise type used by GetNoise
NoiseType GetNoiseType() const { return m_noiseType; }
// Sets octave count for all fractal noise types
// Default: 3
void SetFractalOctaves(int octaves) { m_octaves = octaves; CalculateFractalBounding(); }
// Returns octave count for all fractal noise types
int GetFractalOctaves() const { return m_octaves; }
// Sets octave lacunarity for all fractal noise types
// Default: 2.0
void SetFractalLacunarity(FN_DECIMAL lacunarity) { m_lacunarity = lacunarity; }
// Returns octave lacunarity for all fractal noise types
FN_DECIMAL GetFractalLacunarity() const { return m_lacunarity; }
// Sets octave gain for all fractal noise types
// Default: 0.5
void SetFractalGain(FN_DECIMAL gain) { m_gain = gain; CalculateFractalBounding(); }
// Returns octave gain for all fractal noise types
FN_DECIMAL GetFractalGain() const { return m_gain; }
// Sets method for combining octaves in all fractal noise types
// Default: FBM
void SetFractalType(FractalType fractalType) { m_fractalType = fractalType; }
// Returns method for combining octaves in all fractal noise types
FractalType GetFractalType() const { return m_fractalType; }
// Sets distance function used in cellular noise calculations
// Default: Euclidean
void SetCellularDistanceFunction(CellularDistanceFunction cellularDistanceFunction) { m_cellularDistanceFunction = cellularDistanceFunction; }
// Returns the distance function used in cellular noise calculations
CellularDistanceFunction GetCellularDistanceFunction() const { return m_cellularDistanceFunction; }
// Sets return type from cellular noise calculations
// Note: NoiseLookup requires another FastNoise object be set with SetCellularNoiseLookup() to function
// Default: CellValue
void SetCellularReturnType(CellularReturnType cellularReturnType) { m_cellularReturnType = cellularReturnType; }
// Returns the return type from cellular noise calculations
CellularReturnType GetCellularReturnType() const { return m_cellularReturnType; }
// Noise used to calculate a cell value if cellular return type is NoiseLookup
// The lookup value is acquired through GetNoise() so ensure you SetNoiseType() on the noise lookup, value, Perlin or simplex is recommended
void SetCellularNoiseLookup(FastNoise* noise) { m_cellularNoiseLookup = noise; }
// Returns the noise used to calculate a cell value if the cellular return type is NoiseLookup
FastNoise* GetCellularNoiseLookup() const { return m_cellularNoiseLookup; }
// Sets the 2 distance indices used for distance2 return types
// Default: 0, 1
// Note: index0 should be lower than index1
// Both indices must be >= 0, index1 must be < 4
void SetCellularDistance2Indices(int cellularDistanceIndex0, int cellularDistanceIndex1);
// Returns the 2 distance indices used for distance2 return types
void GetCellularDistance2Indices(int& cellularDistanceIndex0, int& cellularDistanceIndex1) const;
// Sets the maximum distance a cellular point can move from its grid position
// Setting this high will make artifacts more common
// Default: 0.45
void SetCellularJitter(FN_DECIMAL cellularJitter) { m_cellularJitter = cellularJitter; }
// Returns the maximum distance a cellular point can move from its grid position
FN_DECIMAL GetCellularJitter() const { return m_cellularJitter; }
// Sets the maximum warp distance from original location when using GradientPerturb{Fractal}(...)
// Default: 1.0
void SetGradientPerturbAmp(FN_DECIMAL gradientPerturbAmp) { m_gradientPerturbAmp = gradientPerturbAmp; }
// Returns the maximum warp distance from original location when using GradientPerturb{Fractal}(...)
FN_DECIMAL GetGradientPerturbAmp() const { return m_gradientPerturbAmp; }
//2D
FN_DECIMAL GetValue(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetValueFractal(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetPerlin(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetPerlinFractal(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetSimplex(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetCellular(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetWhiteNoiseInt(int x, int y) const;
FN_DECIMAL GetCubic(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetCubicFractal(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL GetNoise(FN_DECIMAL x, FN_DECIMAL y) const;
void GradientPerturb(FN_DECIMAL& x, FN_DECIMAL& y) const;
void GradientPerturbFractal(FN_DECIMAL& x, FN_DECIMAL& y) const;
//3D
FN_DECIMAL GetValue(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetValueFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetPerlin(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetPerlinFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetSimplex(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetWhiteNoiseInt(int x, int y, int z) const;
FN_DECIMAL GetCubic(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetCubicFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL GetNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
void GradientPerturb(FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const;
void GradientPerturbFractal(FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const;
//4D
FN_DECIMAL GetSimplex(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const;
FN_DECIMAL GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const;
FN_DECIMAL GetWhiteNoiseInt(int x, int y, int z, int w) const;
private:
unsigned char m_perm[512];
unsigned char m_perm12[512];
int m_seed = 1337;
FN_DECIMAL m_frequency = FN_DECIMAL(0.01);
Interp m_interp = Quintic;
NoiseType m_noiseType = Simplex;
int m_octaves = 3;
FN_DECIMAL m_lacunarity = FN_DECIMAL(2);
FN_DECIMAL m_gain = FN_DECIMAL(0.5);
FractalType m_fractalType = FBM;
FN_DECIMAL m_fractalBounding;
CellularDistanceFunction m_cellularDistanceFunction = Euclidean;
CellularReturnType m_cellularReturnType = CellValue;
FastNoise* m_cellularNoiseLookup = nullptr;
int m_cellularDistanceIndex0 = 0;
int m_cellularDistanceIndex1 = 1;
FN_DECIMAL m_cellularJitter = FN_DECIMAL(0.45);
FN_DECIMAL m_gradientPerturbAmp = FN_DECIMAL(1);
void CalculateFractalBounding();
//2D
FN_DECIMAL SingleValueFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleValueFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleValueFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SinglePerlinFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SinglePerlinFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SinglePerlinFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleSimplexFractalBlend(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleCubicFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleCubicFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleCubicFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleCubic(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleCellular(FN_DECIMAL x, FN_DECIMAL y) const;
FN_DECIMAL SingleCellular2Edge(FN_DECIMAL x, FN_DECIMAL y) const;
void SingleGradientPerturb(unsigned char offset, FN_DECIMAL warpAmp, FN_DECIMAL frequency, FN_DECIMAL& x, FN_DECIMAL& y) const;
//3D
FN_DECIMAL SingleValueFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleValueFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleValueFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SinglePerlinFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SinglePerlinFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SinglePerlinFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleCubicFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleCubicFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleCubicFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleCubic(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
FN_DECIMAL SingleCellular2Edge(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const;
void SingleGradientPerturb(unsigned char offset, FN_DECIMAL warpAmp, FN_DECIMAL frequency, FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const;
//4D
FN_DECIMAL SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const;
inline unsigned char Index2D_12(unsigned char offset, int x, int y) const;
inline unsigned char Index3D_12(unsigned char offset, int x, int y, int z) const;
inline unsigned char Index4D_32(unsigned char offset, int x, int y, int z, int w) const;
inline unsigned char Index2D_256(unsigned char offset, int x, int y) const;
inline unsigned char Index3D_256(unsigned char offset, int x, int y, int z) const;
inline unsigned char Index4D_256(unsigned char offset, int x, int y, int z, int w) const;
inline FN_DECIMAL ValCoord2DFast(unsigned char offset, int x, int y) const;
inline FN_DECIMAL ValCoord3DFast(unsigned char offset, int x, int y, int z) const;
inline FN_DECIMAL GradCoord2D(unsigned char offset, int x, int y, FN_DECIMAL xd, FN_DECIMAL yd) const;
inline FN_DECIMAL GradCoord3D(unsigned char offset, int x, int y, int z, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd) const;
inline FN_DECIMAL GradCoord4D(unsigned char offset, int x, int y, int z, int w, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd, FN_DECIMAL wd) const;
};
#endif

15
src/util/filereader.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "filereader.hpp"
#include <fstream>
FileReader::FileReader() {
}
std::string FileReader::LoadTextFromFile(std::string path) {
std::ifstream t(path);
std::string text((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
return text;
}

14
src/util/filereader.hpp Normal file
View File

@@ -0,0 +1,14 @@
#ifndef MINECRAFT_UTIL_FILEREADER_H_
#define MINECRAFT_UTIL_FILEREADER_H_
#include <string>
class FileReader {
public:
FileReader();
std::string LoadTextFromFile(std::string path);
};
#endif

1843
src/util/glad.c Normal file

File diff suppressed because it is too large Load Diff

7568
src/util/stb_image.hpp Normal file

File diff suppressed because it is too large Load Diff

7568
src/util/stb_image_write.hpp Normal file

File diff suppressed because it is too large Load Diff

51
src/world/block.cpp Normal file
View File

@@ -0,0 +1,51 @@
#include "block.hpp"
#include "../config.hpp"
#include <iostream>
std::shared_ptr<CBlockDictionary> CBlockDictionary::Instance;
std::shared_ptr<CBlockDictionary> CBlockDictionary::GetInstance() {
if (!CBlockDictionary::Instance) {
CBlockDictionary::Instance = std::make_shared<CBlockDictionary>();
}
return CBlockDictionary::Instance;
}
void CBlockDictionary::Build() {
RegisterTexture("stone.png");
RegisterTexture("dirt.png");
RegisterTexture("grass_side.png");
RegisterTexture("grass_top.png");
RegisterTexture("cobblestone.png");
RegisterTexture("bedrock.png");
// Texture winding order - top, bottom, left, right, front, back
RegisterBlock(EBlockType::Air, { });
RegisterBlock(EBlockType::Stone, { EFaceTexture::Stone, EFaceTexture::Stone, EFaceTexture::Stone, EFaceTexture::Stone, EFaceTexture::Stone, EFaceTexture::Stone });
RegisterBlock(EBlockType::Dirt, { EFaceTexture::Dirt, EFaceTexture::Dirt, EFaceTexture::Dirt, EFaceTexture::Dirt, EFaceTexture::Dirt, EFaceTexture::Dirt });
RegisterBlock(EBlockType::Grass, { EFaceTexture::Grass, EFaceTexture::Dirt, EFaceTexture::GrassSide, EFaceTexture::GrassSide, EFaceTexture::GrassSide, EFaceTexture::GrassSide });
RegisterBlock(EBlockType::Cobblestone, { EFaceTexture::Cobblestone, EFaceTexture::Cobblestone, EFaceTexture::Cobblestone, EFaceTexture::Cobblestone, EFaceTexture::Cobblestone, EFaceTexture::Cobblestone });
RegisterBlock(EBlockType::Bedrock, { EFaceTexture::Bedrock, EFaceTexture::Bedrock, EFaceTexture::Bedrock, EFaceTexture::Bedrock, EFaceTexture::Bedrock, EFaceTexture::Bedrock });
}
void CBlockDictionary::RegisterTexture(std::string texture) {
Textures.push_back(texture);
}
void CBlockDictionary::RegisterBlock(EBlockType::Block block, std::vector<uint16_t> faceTextures) {
BlockEntries[block] = std::make_shared<CBlockEntry>((uint8_t)block, faceTextures);
}

86
src/world/block.hpp Normal file
View File

@@ -0,0 +1,86 @@
#ifndef MINECRAFT_WORLD_BLOCK_H_
#define MINECRAFT_WORLD_BLOCK_H_
#include "../common.hpp"
namespace EBlockType {
enum Block : uint8_t {
Air = 0,
Stone,
Grass,
Dirt,
Cobblestone,
Bedrock
};
}
namespace EFaceTexture {
enum Texture : uint16_t {
Stone,
Dirt,
GrassSide,
Grass,
Cobblestone,
Bedrock
};
}
// Texture winding order - top, bottom, left, right, front, back
class CBlockEntry {
public:
CBlockEntry(uint8_t id, std::vector<uint16_t> faceTextures)
: ID(id), FaceTextures(faceTextures) { }
uint8_t ID;
std::vector<uint16_t> FaceTextures;
};
// TODO: Make design of the class data oriented
// ie, import all the data used in the build from
// files and that
class CBlockDictionary {
public:
static std::shared_ptr<CBlockDictionary> GetInstance();
static std::shared_ptr<CBlockDictionary> Instance;
public:
void Build();
// The index of the texutres path in this array is equal to
// that textures ID, to be referenced in the block entry
std::vector<std::string> Textures;
// Only supports up to 255 blocs, 0 being air
// word stores vectors of chunks which are 16x16x256
// vectors of uint8_t which reference the block dictionary
std::map<uint8_t, std::shared_ptr<CBlockEntry>> BlockEntries;
// Expects textures to be inserted in order, 0-...
void RegisterTexture(std::string texture);
void RegisterBlock(EBlockType::Block block, std::vector<uint16_t> faceTextures);
};
// static std::vector<std::pair<int, std::string>> TextureIdsAndPaths {
// {0, "dirt.png"},
// {1, "grass_side.png"},
// {2, "grass_top.png"}
// };
#endif

279
src/world/chunk/chunk.cpp Normal file
View File

@@ -0,0 +1,279 @@
#include "chunk.hpp"
#include "voxel.hpp"
#include "../../renderer/shader.hpp"
#include "../../renderer/camera.hpp"
#include "../block.hpp"
#include "../../util/fastnoise.hpp"
#include <random>
static std::default_random_engine generator;
Chunk::Chunk() {
}
Chunk::Chunk(int x, int z) {
X = x, Z = z;
Load();
}
Chunk::Chunk(int x, int z, std::vector<uint8_t> voxels) {
X = x, Z = z;
Voxels = voxels;
Load();
}
Chunk::Chunk(int x, int z, std::shared_ptr<FastNoise> terrainGenerator) {
X = x, Z = z;
int y;
for (x = 0; x < CHUNK_WIDTH; x++)
for (y = 0; y < CHUNK_HEIGHT; y++)
for (z = 0; z < CHUNK_DEPTH; z++) {
if (y == 0) {
Voxels.push_back((uint8_t)EBlockType::Bedrock);
continue;
}
if (y == 1 && (float)rand() / (float)RAND_MAX > 0.5f) {
Voxels.push_back((uint8_t)EBlockType::Bedrock);
continue;
}
if (pow(y / (float)CHUNK_HEIGHT, 1.1024f) + terrainGenerator->GetNoise(x + (Z * CHUNK_WIDTH), y, z + (X * CHUNK_DEPTH)) * 0.60f < 0.5f) {
Voxels.push_back((uint8_t)EBlockType::Grass);
continue;
}
Voxels.push_back((uint8_t)EBlockType::Air);
}
for (x = 0; x < CHUNK_WIDTH; x++)
for (y = 0; y < CHUNK_HEIGHT; y++)
for (z = 0; z < CHUNK_DEPTH; z++) {
if (BlockAt(x, y, z) == EBlockType::Bedrock)
continue;
// No need for bounds checking as a closed loop
if (BlockAt(x, y + 1, z) == EBlockType::Grass)
Voxels[x + CHUNK_WIDTH * (y + CHUNK_HEIGHT * z)] = EBlockType::Dirt;
}
// Add stone 3 layers below dirt
for (x = 0; x < CHUNK_WIDTH; x++)
for (y = 0; y < CHUNK_HEIGHT; y++)
for (z = 0; z < CHUNK_DEPTH; z++) {
if (BlockAt(x, y, z) == EBlockType::Bedrock)
continue;
if (BlockAt(x, y + 1, z) == EBlockType::Dirt)
if (BlockAt(x, y + 2, z) == EBlockType::Dirt)
// if (BlockAt(x, y + 3, z) == EBlockType::Dirt)
Voxels[x + CHUNK_WIDTH * (y + CHUNK_HEIGHT * z)] = EBlockType::Stone;
}
// Add the rest of the stone
for (x = 0; x < CHUNK_WIDTH; x++)
for (y = 0; y < CHUNK_HEIGHT; y++)
for (z = 0; z < CHUNK_DEPTH; z++) {
if (BlockAt(x, y, z) == EBlockType::Bedrock)
continue;
if (BlockAt(x, y + 1, z) == EBlockType::Stone)
Voxels[x + CHUNK_WIDTH * (y + CHUNK_HEIGHT * z)] = EBlockType::Stone;
}
Load();
}
void Chunk::Load() {
if (Loaded)
return;
m_model = glm::translate(glm::mat4(1.0f), { X * CHUNK_WIDTH, 0, Z * CHUNK_DEPTH });
if (!Voxels.empty()) {
m_mesh();
Loaded = true;
return;
}
// Generate a superflat chunk if nothing is there
// [x + WIDTH * (y + HEIGHT * z)]
for (int x = 0; x < CHUNK_WIDTH; x++)
for (int y = 0; y < CHUNK_HEIGHT; y++)
for (int z = 0; z < CHUNK_DEPTH; z++) {
if (y > 32) {
Voxels.push_back((uint8_t)EBlockType::Air);
continue;
}
if (y == 0)
Voxels.push_back((uint8_t)EBlockType::Bedrock);
else if (y < 28)
Voxels.push_back((uint8_t)EBlockType::Stone);
else if (y < 32)
Voxels.push_back((uint8_t)EBlockType::Dirt);
else
Voxels.push_back((uint8_t)EBlockType::Grass);
}
m_mesh();
Loaded = true;
}
void Chunk::UploadMesh() {
if (!MeshReady)
return;
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
std::vector<glm::vec3> data;
data.insert(data.end(), m_vertices.begin(), m_vertices.end());
data.insert(data.end(), m_uvs.begin(), m_uvs.end());
m_numVerts = m_vertices.size();
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(glm::vec3), &data[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const void*)(m_vertices.size() * sizeof(glm::vec3)));
m_vertices.clear();
m_uvs.clear();
data.clear();
glBindVertexArray(0);
MeshReady = !MeshReady;
}
void Chunk::Render(std::shared_ptr<Camera> camera, std::shared_ptr<Shader> shader) {
if (!Loaded)
return;
shader->Use();
glBindVertexArray(m_vao);
GLint uniTrans = glGetUniformLocation(shader->Program, "model");
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(m_model));
GLint uniView = glGetUniformLocation(shader->Program, "view");
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(camera->GetViewMatrix()));
GLint uniProj = glGetUniformLocation(shader->Program, "proj");
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(camera->GetProjectionMatrix()));
glDrawArrays(GL_TRIANGLES, 0, m_numVerts);
}
void Chunk::Update(std::vector<uint8_t> voxels) {
Voxels = voxels;
m_mesh();
}
uint8_t Chunk::BlockAt(int x, int y, int z) {
if (x > CHUNK_WIDTH - 1) return 0;
if (y > CHUNK_HEIGHT - 1) return 0;
if (z > CHUNK_DEPTH - 1) return 0;
if (x < 0) return 0;
if (y < 0) return 0;
if (z < 0) return 0;
return Voxels[x + CHUNK_WIDTH * (y + CHUNK_HEIGHT * z)];
}
void Chunk::m_mesh() {
// TODO: Use greedy meshing for MAXIMUM performance
for (int x = 0; x < CHUNK_WIDTH; x++)
for (int y = 0; y < CHUNK_HEIGHT; y++)
for (int z = 0; z < CHUNK_DEPTH; z++) {
std::vector<glm::vec3> tempVerts;
std::vector<glm::vec3> tempUVs;
uint8_t block = BlockAt(x, y, z);
if (block == EBlockType::Air) continue;
Voxel tmp({x, y, z}, block);
if (BlockAt(x + 1, y, z) == EBlockType::Air)
tmp.AddFace(EFaceType::Right);
if (BlockAt(x - 1, y, z) == EBlockType::Air)
tmp.AddFace(EFaceType::Left);
if (BlockAt(x, y + 1, z) == EBlockType::Air)
tmp.AddFace(EFaceType::Top);
if (BlockAt(x, y - 1, z) == EBlockType::Air)
tmp.AddFace(EFaceType::Bottom);
if (BlockAt(x, y, z + 1) == EBlockType::Air)
tmp.AddFace(EFaceType::Front);
if (BlockAt(x, y, z - 1) == EBlockType::Air)
tmp.AddFace(EFaceType::Back);
tmp.GetMesh(tempVerts, tempUVs);
m_vertices.insert(m_vertices.end(), tempVerts.begin(), tempVerts.end());
m_uvs.insert(m_uvs.end(), tempUVs.begin(), tempUVs.end());
tmp.Clear();
}
MeshReady = true;
}
Chunk::~Chunk() {
}

69
src/world/chunk/chunk.hpp Normal file
View File

@@ -0,0 +1,69 @@
#ifndef MINECRAFT_RENDERER_CHUNK_H_
#define MINECRAFT_RENDERER_CHUNK_H_
#include "../../common.hpp"
#define CHUNK_HEIGHT 128
#define CHUNK_WIDTH 16
#define CHUNK_DEPTH 16
class FastNoise;
class Camera;
class Shader;
class Voxel;
class Chunk {
public:
Chunk();
Chunk(int x, int z);
Chunk(int x, int z, std::vector<uint8_t> voxels);
Chunk(int x, int z, std::shared_ptr<FastNoise> terrainGenerator);
void Load();
void UploadMesh();
bool MeshReady = false;
void Render(std::shared_ptr<Camera> camera, std::shared_ptr<Shader> shader);
void Update(std::vector<uint8_t> voxels);
uint8_t BlockAt(int x, int y, int z);
// Indexed sequentially [x + WIDTH * (y + HEIGHT * z)] = voxelID
// the voxel id is used to index the block dictionary to get properties
// to generate a mesh and send it to the GPU
std::vector<uint8_t> Voxels;
// To only be changed by the class its self
bool Loaded = false;
// To only be changed by render components
bool ShouldRender = false;
// Chunk World pos
int X,Z;
~Chunk();
private:
void m_mesh();
GLuint m_vao = 0;
GLuint m_vbo = 0;
// Must be translated by a multiple of 16 in the x or z, nothing in y
glm::mat4 m_model;
std::vector<glm::vec3> m_vertices;
int m_numVerts = 0;
std::vector<glm::vec3> m_uvs;
};
#endif

127
src/world/chunk/face.hpp Normal file
View File

@@ -0,0 +1,127 @@
#ifndef MINECRAFT_RENDERER_FACE_H_
#define MINECRAFT_RENDERER_FACE_H_
#include "../../common.hpp"
namespace EFaceType {
enum Face : uint8_t {
Top,
Bottom,
Left,
Right,
Front,
Back,
};
}
static std::vector<glm::vec3> CubeTopFace = {
{ -0.5f, 0.5f, -0.5f },
{ 0.5f, 0.5f, -0.5f },
{ 0.5f, 0.5f, 0.5f },
{ 0.5f, 0.5f, 0.5f },
{ -0.5f, 0.5f, 0.5f },
{ -0.5f, 0.5f, -0.5f }
};
static std::vector<glm::vec2> CubeTopFaceUVs = {
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f },
{ 1.0f, 1.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f }
};
static std::vector<glm::vec3> CubeBottomFace = {
{ -0.5f, -0.5f, -0.5f },
{ 0.5f, -0.5f, -0.5f },
{ 0.5f, -0.5f, 0.5f },
{ 0.5f, -0.5f, 0.5f },
{ -0.5f, -0.5f, 0.5f },
{ -0.5f, -0.5f, -0.5f }
};
static std::vector<glm::vec2> CubeBottomFaceUVs = {
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f },
{ 1.0f, 1.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f }
};
static std::vector<glm::vec3> CubeLeftFace = {
{ -0.5f, 0.5f, 0.5f },
{ -0.5f, 0.5f, -0.5f },
{ -0.5f, -0.5f, -0.5f },
{ -0.5f, -0.5f, -0.5f },
{ -0.5f, -0.5f, 0.5f },
{ -0.5f, 0.5f, 0.5f }
};
static std::vector<glm::vec2> CubeLeftFaceUVs = {
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f },
{ 1.0f, 1.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f }
};
static std::vector<glm::vec3> CubeRightFace = {
{ 0.5f, 0.5f, 0.5f },
{ 0.5f, 0.5f, -0.5f },
{ 0.5f, -0.5f, -0.5f },
{ 0.5f, -0.5f, -0.5f },
{ 0.5f, -0.5f, 0.5f },
{ 0.5f, 0.5f, 0.5f },
};
static std::vector<glm::vec2> CubeRightFaceUVs = {
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f },
{ 1.0f, 1.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f }
};
static std::vector<glm::vec3> CubeFrontFace = {
{ -0.5f, -0.5f, 0.5f },
{ 0.5f, -0.5f, 0.5f },
{ 0.5f, 0.5f, 0.5f },
{ 0.5f, 0.5f, 0.5f },
{ -0.5f, 0.5f, 0.5f },
{ -0.5f, -0.5f, 0.5f }
};
static std::vector<glm::vec2> CubeFrontFaceUVs = {
{ 1.0f, 1.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f }
};
static std::vector<glm::vec3> CubeBackFace = {
{ -0.5f, -0.5f, -0.5f },
{ 0.5f, -0.5f, -0.5f },
{ 0.5f, 0.5f, -0.5f },
{ 0.5f, 0.5f, -0.5f },
{ -0.5f, 0.5f, -0.5f },
{ -0.5f, -0.5f, -0.5f }
};
static std::vector<glm::vec2> CubeBackFaceUVs = {
{ 1.0f, 1.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f }
};
#endif

132
src/world/chunk/voxel.cpp Normal file
View File

@@ -0,0 +1,132 @@
#include "voxel.hpp"
#include <iostream>
#include <memory>
#include "../../renderer/shader.hpp"
#include "../../renderer/camera.hpp"
#include "face.hpp"
#include "../block.hpp"
Voxel::Voxel(glm::vec3 coordsInChunk, uint8_t block) {
// Texture winding order - top, bottom, left, right, front, back
Block = block;
m_coordsInChunk = coordsInChunk;
}
void Voxel::AddFace(EFaceType::Face face) {
std::vector<glm::vec3> verts;
std::vector<glm::vec2> uvs;
switch (face) {
case EFaceType::Top:
{
verts = CubeTopFace;
uvs = CubeTopFaceUVs;
break;
}
case EFaceType::Bottom:
{
verts = CubeBottomFace;
uvs = CubeBottomFaceUVs;
break;
}
case EFaceType::Left:
{
verts = CubeLeftFace;
uvs = CubeLeftFaceUVs;
break;
}
case EFaceType::Right:
{
verts = CubeRightFace;
uvs = CubeRightFaceUVs;
break;
}
case EFaceType::Front:
{
verts = CubeFrontFace;
uvs = CubeFrontFaceUVs;
break;
}
case EFaceType::Back:
{
verts = CubeBackFace;
uvs = CubeBackFaceUVs;
break;
}
}
verts = m_translateIntoChunk(verts, m_coordsInChunk);
m_vertices.insert(m_vertices.end(), verts.begin(), verts.end());
std::shared_ptr<CBlockEntry> block = CBlockDictionary::GetInstance()->BlockEntries[Block];
uint16_t tex = block->FaceTextures[(uint16_t)face];
std::vector<glm::vec3> uvws = {
{ uvs[0].x, uvs[0].y, (float)tex },
{ uvs[1].x, uvs[1].y, (float)tex },
{ uvs[2].x, uvs[2].y, (float)tex },
{ uvs[3].x, uvs[3].y, (float)tex },
{ uvs[4].x, uvs[4].y, (float)tex },
{ uvs[5].x, uvs[5].y, (float)tex },
};
m_uvs.insert(m_uvs.end(), uvws.begin(), uvws.end());
}
void Voxel::GetMesh(std::vector<glm::vec3>& verts, std::vector<glm::vec3>& uvs) {
verts = m_vertices;
uvs = m_uvs;
}
void Voxel::Clear() {
m_vertices.clear();
m_uvs.clear();
}
std::vector<glm::vec3> Voxel::m_translateIntoChunk(std::vector<glm::vec3> verts, glm::vec3 trans) {
for (int i = 0; i < verts.size(); i++) {
verts[i].x += trans.x;
verts[i].y += trans.y;
verts[i].z += trans.z;
}
return verts;
}

33
src/world/chunk/voxel.hpp Normal file
View File

@@ -0,0 +1,33 @@
#ifndef MINECRAFT_RENDERER_VOXEL_H_
#define MINECRAFT_RENDERER_VOXEL_H_
#include "../../common.hpp"
#include "face.hpp"
class Camera;
class Shader;
class Voxel {
public:
Voxel(glm::vec3 coordsInChunk, uint8_t block);
void AddFace(EFaceType::Face face);
void GetMesh(std::vector<glm::vec3>& verts, std::vector<glm::vec3>& uvs);
void Clear();
uint8_t Block;
private:
glm::vec3 m_coordsInChunk;
std::vector<glm::vec3> m_translateIntoChunk(std::vector<glm::vec3> verts, glm::vec3 trans);
std::vector<glm::vec3> m_vertices;
std::vector<glm::vec3> m_uvs;
};
#endif

59
src/world/entity.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include "entity.hpp"
#include "../renderer/camera.hpp"
Entity::Entity(glm::vec3 postion, glm::vec3 direction, std::shared_ptr<Camera> camera)
: Position(Position)
, Direction(direction)
, EntityCamera(camera)
{
if (EntityCamera) {
EntityCamera->UpdateView();
}
}
Player::Player(glm::vec3 position, glm::vec3 direction, std::shared_ptr<Camera> camera)
: Entity(position, direction, camera) {
Position = { 0, 64, 0 };
EntityCamera->Position = { Position.x, Position.y + EyePosition, Position.z };
EntityCamera->UpdateView();
}
void Player::MoveSDL(Uint8* state) {
EntityCamera->MoveCamera(state);
Position = EntityCamera->Position;
Position.y -= EyePosition;
}
void Player::HandleMouseSDL(SDL_Event e) {
EntityCamera->HandleMouse(e);
Direction = EntityCamera->LookDirection;
}
void Player::UpdatePosition(glm::vec3 position) {
Position = position;
EntityCamera->UpdatePosition({ Position.x, Position.y + EyePosition, Position.z });
}
void Player::UpdateDirection(glm::vec3 direction) {
Direction = direction;
EntityCamera->UpdateLookDirection(direction);
}
void Player::CameraUpdateProjection(int xres, int yres) {
EntityCamera->UpdateProjection(xres, yres);
}

51
src/world/entity.hpp Normal file
View File

@@ -0,0 +1,51 @@
#ifndef MINECRAFT_WORLD_ENTITY_H_
#define MINECRAFT_WORLD_ENTITY_H_
#include "../common.hpp"
class Camera;
class Collider;
class Entity {
public:
Entity(glm::vec3 position, glm::vec3 direction = { 0.0f, 0.0f, 0.0f }, std::shared_ptr<Camera> camera = std::make_shared<Camera>());
// World position, 1.7 units below the
// camera position.
glm::vec3 Position;
// Look direction of the camera
glm::vec3 Direction;
// Velocity in direction
// of movement
glm::vec3 Velocity;
// Can be null
std::shared_ptr<Camera> EntityCamera;
// Collider
// std::unique_ptr<Collider> EntityCollider;
// Mesh (or reference to)
};
class Player : public Entity {
public:
Player(glm::vec3 position, glm::vec3 direction, std::shared_ptr<Camera> camera);
float EyePosition = 1.7f;
void MoveSDL(Uint8* state);
void HandleMouseSDL(SDL_Event e);
void UpdatePosition(glm::vec3 position);
void UpdateDirection(glm::vec3 direction);
void CameraUpdateProjection(int xres, int yres);
};
#endif

View File

@@ -0,0 +1,14 @@
#include "../../util/fastnoise.hpp"
void dp() {
FastNoise noise;
noise.SetSeed(121212);
noise.SetNoiseType(FastNoise::SimplexFractal);
noise.SetFractalOctaves(3);
}

View File

@@ -0,0 +1,2 @@

158
src/world/world.cpp Normal file
View File

@@ -0,0 +1,158 @@
#include "world.hpp"
#include "chunk/chunk.hpp"
#include "../renderer/shader.hpp"
#include "../util/fastnoise.hpp"
#include "../config.hpp"
#include "entity.hpp"
World::World() {
}
void World::LoadWorld() {
m_shaders["Basic"] = std::make_shared<Shader>();
m_shaders["Basic"]->Load(GameConfig.ResourceBase + "shaders/simple");
m_shaders["Basic"]->Link();
srand(time(NULL));
m_noiseGenerator = std::make_shared<FastNoise>();
m_noiseGenerator->SetSeed(rand());
m_noiseGenerator->SetNoiseType(FastNoise::Perlin);
m_noiseGenerator->SetFractalOctaves(8);
for (int x = -4; x < 5; x++)
for (int y = -5; y < 4; y++) {
m_chunkLoaderQueue.push({ x, y });
}
// Spawn generator threads
for (int i = 0; i < 6; i++) {
m_generatorThreads.push_back(std::thread([&]() {
m_loadChunks();
}));
}
m_generatorRunning = true;
}
void World::SetTextureMap(GLuint map) {
m_textureMapID = map;
}
glm::vec2 World::GetChunkCoords(glm::vec3 wordCoords) {
return { wordCoords.x / CHUNK_WIDTH, wordCoords.z / CHUNK_DEPTH };
}
std::vector<std::shared_ptr<Chunk>> World::GetRenderableChunks() {
std::vector<std::shared_ptr<Chunk>> chunks;
for (auto& chunk : m_chunks) {
// Should the chunk be rendererd ?
if (chunk.second->ShouldRender) {
m_chunkMutex.lock();
if (chunk.second->MeshReady)
chunk.second->UploadMesh();
m_chunkMutex.unlock();
// If not, add it
chunks.push_back(chunk.second);
}
}
return chunks;
}
void World::Update(std::shared_ptr<Entity> player) {
}
void World::Render(std::shared_ptr<Entity> player) {
glBindTexture(GL_TEXTURE_2D_ARRAY, m_textureMapID);
std::vector<std::shared_ptr<Chunk>> chunks = GetRenderableChunks();
for (int i = 0; i < chunks.size(); i++) {
chunks[i]->Render(player->EntityCamera, m_shaders["Basic"]);
}
}
World::~World() {
m_generatorRunning = false;
for (int i = 0; i < m_generatorThreads.size(); i++) {
m_generatorThreads[i].join();
}
}
void World::m_loadChunks() {
while (m_generatorRunning) {
m_chunkMutex.lock();
glm::vec2 coords = m_chunkLoaderQueue.front();
m_chunkLoaderQueue.pop();
m_chunkMutex.unlock();
std::shared_ptr<Chunk> loadingChunk = std::make_shared<Chunk>(coords.x, coords.y, m_noiseGenerator);
std::cout << "Loaded chunk " << coords.x << ":" << coords.y << std::endl;
m_chunkMutex.lock();
m_chunks[coords] = loadingChunk;
m_chunks[coords]->ShouldRender = true;
m_chunkMutex.unlock();
while (m_chunkLoaderQueue.empty()) {
if (!m_generatorRunning) break;
static std::chrono::milliseconds dura(1);
std::this_thread::sleep_for(dura);
}
}
}

75
src/world/world.hpp Normal file
View File

@@ -0,0 +1,75 @@
#ifndef MINECRAFT_WORLD_WORLD_H_
#define MINECRAFT_WORLD_WORLD_H_
#include "../common.hpp"
#include "../renderer/camera.hpp"
#include "chunk/chunk.hpp"
#include <unordered_map>
#include <thread>
#include <mutex>
#include <queue>
class FastNoise;
class Shader;
class Entity;
class World {
public:
// Default constructor
World();
// Preps the render threads and loads all of the shaders
void LoadWorld();
void SetTextureMap(GLuint map);
// Takes world coordinates and gets a chunks coordinates
glm::vec2 GetChunkCoords(glm::vec3 wordCoords);
std::vector<std::shared_ptr<Chunk>> GetRenderableChunks();
void Update(std::shared_ptr<Entity> player);
void Render(std::shared_ptr<Entity> player);
~World();
private:
// GL stuff
// Main texture map id
GLuint m_textureMapID;
// Shaders indexed by name
std::map<std::string, std::shared_ptr<Shader>> m_shaders;
// Threads used for chunk generation
std::vector<std::thread> m_generatorThreads;
bool m_generatorRunning = false;
// Chuks
// Indexed by chunk coorinates
std::unordered_map<glm::vec2, std::shared_ptr<Chunk>> m_chunks;
std::queue<glm::vec2> m_chunkUpdatesQueue;
std::queue<glm::vec2> m_chunkLoaderQueue;
std::mutex m_chunkMutex;
// Generator
std::shared_ptr<FastNoise> m_noiseGenerator;
void m_loadChunks();
};
#endif