diff --git a/res/fragment_shader.dat b/res/fragment_shader.dat new file mode 100644 index 0000000..3e38817 --- /dev/null +++ b/res/fragment_shader.dat @@ -0,0 +1,37 @@ +#version 330 core + +out vec4 color; + +in vec3 position_pass; +in vec3 camera_position_pass; +in vec3 normal_pass; +in vec2 uv_pass; + +float min_brightness = 0.05; +vec3 sun_position = vec3(1000.0, 1000.0, 1000.0); + +float shine_dampener = 10; +float reflectivity = 5; + +uniform sampler2D sampler; + +void main() { + color = texture(sampler, uv_pass); + + vec3 to_sun_vector = normalize(sun_position - position_pass); + + float intensity = clamp(dot(to_sun_vector, normal_pass), 0.25, 1.0); + color.xyz *= intensity; + + //vec3 to_camera_vector = normalize(camera_position_pass - position_pass); + //vec3 reflection = reflect(-to_sun_vector, normal_pass); + + //float specular_intensity = max(dot(to_camera_vector, reflection), 0.0); + + //specular_intensity = pow(specular_intensity, shine_dampener); + + //specular_intensity *= reflectivity; + + //if (dot(normal_pass, to_camera_vector) >= 0.3) + //color.xyz += vec3(1.0, 1.0, 1.0) * specular_intensity; +} \ No newline at end of file diff --git a/res/textures.dat b/res/textures.dat new file mode 100644 index 0000000..8735a7c Binary files /dev/null and b/res/textures.dat differ diff --git a/res/vertex_shader.dat b/res/vertex_shader.dat new file mode 100644 index 0000000..b47a0c8 --- /dev/null +++ b/res/vertex_shader.dat @@ -0,0 +1,31 @@ +#version 330 core + +layout(location = 0) in vec3 vertex_position; +layout(location = 1) in vec3 vertex_normal; +layout(location = 2) in vec2 vertex_tex_coord; + +uniform mat4 model_matrix; +uniform mat4 view_matrix; +uniform mat4 proj_matrix; + +uniform vec3 camera_position; + +out vec3 position_pass; +out vec3 camera_position_pass; +out vec3 normal_pass; +out vec2 uv_pass; + +void main() { + mat4 mvp = proj_matrix * view_matrix * model_matrix; + + vec3 world_position = (model_matrix * vec4(vertex_position, 1.0)).xyz; + gl_Position = mvp * vec4(vertex_position, 1.0); + + normal_pass = normalize((model_matrix * vec4(vertex_normal, 0.0)).xyz); + + position_pass = world_position; + + camera_position_pass = (inverse(view_matrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz; + + uv_pass = vertex_tex_coord; +} \ No newline at end of file diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..cc8c637 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,80 @@ +#include "camera.h" +Camera::Camera() { + this->width = Window::width; + this->height = Window::height; + + this->field_of_view = glm::radians(80.0f); + + this->projection_matrix = glm::perspective( + this->field_of_view, + (float)this->width / (float)this->height, + 0.1f, + 1000.0f + ); + + Window::current_window->register_resize_callback((void(*)(void*, int, int))&Camera::update_projection_matrix, this); +} + +void Camera::update_projection_matrix(int width, int height) { + this->width = width; + this->height = height; + + this->projection_matrix = glm::perspective( + this->field_of_view, + (float)this->width / (float)this->height, + 0.1f, + 1000.0f + ); +} + +glm::mat4 Camera::get_projection_matrix() { + return this->projection_matrix; +} + +glm::mat4 Camera::get_view_matrix() { + glm::mat4 r1Matrix = glm::rotate(-this->rotation.x, glm::vec3(1, 0, 0)); + glm::mat4 r2Matrix = glm::rotate(-this->rotation.y, glm::vec3(0, 1, 0)); + glm::mat4 r3Matrix = glm::rotate(-this->rotation.z, glm::vec3(0, 0, 1)); + glm::mat4 tMatrix = glm::translate(glm::mat4(1.0f), -this->position); + return r1Matrix * r2Matrix * r3Matrix * tMatrix; +} + +glm::vec3 Camera::get_position() { + return this->position; +} +void Camera::set_position(glm::vec3 position) { + this->position = position; +} +void Camera::change_position_by(glm::vec3 position) { + this->position += position; +} + +glm::vec3 Camera::get_rotation() { + return this->rotation; +} +void Camera::set_rotation(glm::vec3 rotation) { + this->rotation = rotation; +} +void Camera::change_rotation_by(glm::vec3 rotation) { + this->rotation += rotation; +} + +void Camera::move_by(glm::vec3 position) { + glm::vec3 forward( + glm::cos(-this->rotation.x) * glm::sin(this->rotation.y), + glm::sin(-this->rotation.x), + glm::cos(-this->rotation.x) * glm::cos(this->rotation.y) + ); + + glm::vec3 right( + glm::sin(this->rotation.y + 1.57f), + 0, + glm::cos(this->rotation.y + 1.57f) + ); + + glm::vec3 up = -glm::cross(right, forward); + + this->position += right * position.x; + this->position += up * position.y; + this->position += forward * position.z; +} diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..3afa046 --- /dev/null +++ b/src/camera.h @@ -0,0 +1,38 @@ +#ifndef CAMERA_H +#define CAMERA_H +#include +#include +#include +#include +#include "window.h" +class Camera { +private: + glm::mat4 projection_matrix; + float field_of_view; + + glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f); + glm::vec3 rotation = glm::vec3(0.0f, 0.0f, 0.0f); + + int width; + int height; + + void update_projection_matrix(int width, int height); +public: + Camera(); + Camera(int width, int height); + + glm::mat4 get_projection_matrix(); + glm::mat4 get_view_matrix(); + + glm::vec3 get_position(); + void set_position(glm::vec3 position); + void change_position_by(glm::vec3 position); + + glm::vec3 get_rotation(); + void set_rotation(glm::vec3 rotation); + void change_rotation_by(glm::vec3 rotation); + + void move_by(glm::vec3 position); +}; + +#endif \ No newline at end of file diff --git a/src/chunk.cpp b/src/chunk.cpp new file mode 100644 index 0000000..c572be6 --- /dev/null +++ b/src/chunk.cpp @@ -0,0 +1,186 @@ +#include "chunk.h" + +#include "world.h" + +static glm::vec3 cube_vertexes[6][4] = { + {glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f)}, // Left + {glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 0.0f, 1.0f)}, // Right + {glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f)}, // Back + {glm::vec3(1.0f, 0.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec3(0.0f, 0.0f, 1.0f)}, // Front + {glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 1.0f)}, // Bottom + {glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 0.0f)}, // Top +}; + +static glm::vec3 cube_normals[6] = { + glm::vec3(-1.0f, 0.0f, 0.0f), // Left + glm::vec3(1.0f, 0.0f, 0.0f), // Right + glm::vec3(0.0f, 0.0f, -1.0f), // Back + glm::vec3(0.0f, 0.0f, 1.0f), // Front + glm::vec3(0.0f, -1.0f, 0.0f), // Bottom + glm::vec3(0.0f, 1.0f, 0.0f), // Top +}; + +void Chunk::set_block(int x, int y, int z, int block) { + if (x < 0 || x >= Chunk::horiz_size) + return; + if (z < 0 || z >= Chunk::horiz_size) + return; + if (y < 0 || y >= Chunk::vert_size) + return; + this->blocks[y * Chunk::horiz_size * Chunk::horiz_size + z * Chunk::horiz_size + x] = block; +} + +int Chunk::get_block(int x, int y, int z) { + if (x < 0 || x >= Chunk::horiz_size) + return 0; + if (z < 0 || z >= Chunk::horiz_size) + return 0; + if (y < 0 || y >= Chunk::vert_size) + return 0; + return this->blocks[y * Chunk::horiz_size * Chunk::horiz_size + z * Chunk::horiz_size + x]; +} + +Chunk::Chunk(int x, int z) { + this->x = x; + this->z = z; + + std::cerr << "Chunk created at X: " << x << " Z: " << z << "\n"; + + for (int x=0; xx * 16 + x, this->z * 16 + z); + + int stone_ceil = max_height / 1.2f; + + for (int y=0; y<=Chunk::vert_size; y++) { + if (y == 0) { + set_block(x, y, z, 1); + } else if (y < stone_ceil) { + set_block(x, y, z, 2); + } else if (y < max_height) { + set_block(x, y, z, 3); + } else if (y == max_height) { + set_block(x, y, z, 5); + } else { + set_block(x, y, z, 0); + } + } + } + } +} + +Chunk::~Chunk() { + glDeleteBuffers(4, this->VBOs); + glDeleteVertexArrays(1, &this->VAO); +} + + +void Chunk::generate() { + std::chrono::high_resolution_clock clock; + if (mesh_version < current_version) { + auto t1 = clock.now(); + mesh_version++; + + std::vector vertex_positions; + std::vector vertex_normals; + std::vector vertex_tex_coords; + std::vector vertex_indexes; + + int index=0; + + for (int x=0; xVAO); + glBindVertexArray(this->VAO); + glGenBuffers(4, this->VBOs); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, this->VBOs[0]); + glBufferData(GL_ARRAY_BUFFER, vertex_positions.size() * sizeof(glm::vec3), &vertex_positions[0].x, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, this->VBOs[1]); + glBufferData(GL_ARRAY_BUFFER, vertex_normals.size() * sizeof(glm::vec3), &vertex_normals[0].x, GL_STATIC_DRAW); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, (void*)0); + + glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, this->VBOs[2]); + glBufferData(GL_ARRAY_BUFFER, vertex_tex_coords.size() * sizeof(glm::vec2), &vertex_tex_coords[0].x, GL_STATIC_DRAW); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + + glEnableVertexAttribArray(3); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->VBOs[3]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertex_indexes.size() * sizeof(int), &vertex_indexes[0], GL_STATIC_DRAW); + glVertexAttribPointer(3, 1, GL_INT, GL_FALSE, 0, (void*)0); + + this->vertex_count = vertex_indexes.size(); + + auto t2 = clock.now(); + + std::chrono::duration d = (t2 - t1); + + std::cerr << "Generated chunk in " << d.count() << " seconds.\n"; + } +} + +bool Chunk::outdated() { + return mesh_version < current_version; +} + +glm::mat4 Chunk::get_transformation_matrix() { + return glm::translate(glm::mat4(1.0f), glm::vec3(Chunk::horiz_size * this->x, 0.0f, Chunk::horiz_size * this->z)); +} + +void Chunk::select() { + glBindVertexArray(this->VAO); +} \ No newline at end of file diff --git a/src/chunk.h b/src/chunk.h new file mode 100644 index 0000000..4acb89c --- /dev/null +++ b/src/chunk.h @@ -0,0 +1,45 @@ +#ifndef CHUNK_H +#define CHUNK_H + +#include +#include + +#include +#include +#include + +class Chunk { +private: + GLuint VAO = 0; + GLuint VBOs[4]; + + int mesh_version=0; + int current_version=1; + + static constexpr int horiz_size = 16; + static constexpr int vert_size = 256; + + int blocks[horiz_size * horiz_size * vert_size]; + + inline void set_block(int x, int y, int z, int block); + inline int get_block(int x, int y, int z); + +public: + int x; + int z; + + int vertex_count; + + Chunk(int x, int z); + ~Chunk(); + + void generate(); + + bool outdated(); + + glm::mat4 get_transformation_matrix(); + + void select(); +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a1b3b12..49bc0a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,27 +4,92 @@ #include #include "window.h" +#include "world.h" +#include "shader.h" +#include "texture.h" -int key_state[GLFW_KEY_LAST]; +#include + +extern const char _binary_res_vertex_shader_dat_start[]; +extern const char _binary_res_vertex_shader_dat_end[]; + +extern const char _binary_res_fragment_shader_dat_start[]; +extern const char _binary_res_fragment_shader_dat_end[]; + +extern const unsigned char _binary_res_textures_dat_start[]; + +World* world; +Camera* c; +Shader* s; + +int key_states[GLFW_KEY_LAST]; void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key < 0) return; if (action == GLFW_PRESS) - key_state[key] = 1; + key_states[key] = 1; else if (action == GLFW_RELEASE) - key_state[key] = 0; + key_states[key] = 0; } -void loop(double d, GLFWwindow* w) { +void loop(float deltatime, GLFWwindow* w) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0.2f, 0.6f, 0.7f, 1.0f); - std::cout << "Deltatime: " << d << "\n"; + std::cout << "Deltatime: " << deltatime << "\n"; + + float speed = 20.0f; + + if (key_states[GLFW_KEY_W]) + c->move_by(glm::vec3(0.0f, 0.0f, -speed) * deltatime); + if (key_states[GLFW_KEY_A]) + c->move_by(glm::vec3(-speed, 0.0f, 0.0f) * deltatime); + if (key_states[GLFW_KEY_S]) + c->move_by(glm::vec3(0.0f, 0.0f, speed) * deltatime); + if (key_states[GLFW_KEY_D]) + c->move_by(glm::vec3(speed, 0.0f, 0.0f) * deltatime); + if (key_states[GLFW_KEY_SPACE]) + c->change_position_by(glm::vec3(0.0f, speed, 0.0f) * deltatime); + if (key_states[GLFW_KEY_LEFT_SHIFT]) + c->change_position_by(glm::vec3(0.0f, -speed, 0.0f) * deltatime); + + double current_x_pos, current_y_pos; + glfwGetCursorPos(w, ¤t_x_pos, ¤t_y_pos); + + double delta_x = (double)(Window::width / 2) - current_x_pos; + double delta_y = (double)(Window::height / 2) - current_y_pos; + + c->change_rotation_by(glm::vec3(0.005f * (float)delta_y, 0.005f * (float)delta_x, 0.0f)); + glfwSetCursorPos(w, Window::width / 2, Window::height / 2); + + world->render(c, s); + + world->process(c->get_position().x, c->get_position().z); } int main() { Window w = Window(1280, 720, "xnoecraft", key_callback); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + glEnable(GL_CULL_FACE); + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + + Texture* t = new Texture(_binary_res_textures_dat_start); + + c = new Camera(); + c->set_position(glm::vec3(0.0f, 256.0f, 0.0f)); + + world = new World(); + world->generate_around(0, 0); + + ShaderSource vertex_shader(_binary_res_vertex_shader_dat_start, _binary_res_vertex_shader_dat_end); + ShaderSource fragment_shader(_binary_res_fragment_shader_dat_start, _binary_res_fragment_shader_dat_end); + + s = new Shader(vertex_shader, fragment_shader); + w.mainloop(loop); } \ No newline at end of file diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..ddca0e5 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,118 @@ +#include "shader.h" +ShaderSource::ShaderSource(const char* start, const char* end) { + this->source = start; + this->length = (int)(end - start); +} + +GLuint Shader::current_program = 0; + +GLuint Shader::compile_shader(GLenum type, const char* source, int source_length) { + std::stringstream error; + GLuint shader = glCreateShader(type); + + std::cout << "Length: " << source_length << "\n"; + + switch (type) { + case GL_VERTEX_SHADER: + std::cout << "Compiling Vertex Shader\n"; + break; + case GL_GEOMETRY_SHADER: + std::cout << "Compiling Geometry Shader\n"; + break; + case GL_FRAGMENT_SHADER: + std::cout << "Compiling Fragment Shader\n"; + break; + default: + break; + } + + GLint result = GL_FALSE; + int log_length; + + glShaderSource(shader, 1, &source, &source_length); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); + + if (log_length) { + error << "COMPILE FAILURE LOG: \n"; + error << "===================================================\n"; + char log_message[log_length+1]; + glGetShaderInfoLog(shader, log_length, 0, log_message); + error << log_message << "\n"; + error << "===================================================\n"; + glDeleteShader(shader); + throw std::runtime_error(error.str()); + } + + if (!result) { + error << "Failed to compile shader with no log message!\n"; + glDeleteShader(shader); + throw std::runtime_error(error.str()); + } + + return shader; +} + +Shader::Shader(ShaderSource vertex_shader, ShaderSource fragment_shader) { + std::stringstream error; + try { + this->vertex_shader = this->compile_shader(GL_VERTEX_SHADER, vertex_shader.source, vertex_shader.length); + this->fragment_shader = this->compile_shader(GL_FRAGMENT_SHADER, fragment_shader.source, fragment_shader.length); + } catch (std::runtime_error e) { + std::cerr << e.what(); + error << "Shader compilation failed... not attempting to link\n"; + throw std::runtime_error(error.str()); + } + + this->program = glCreateProgram(); + + glAttachShader(this->program, this->vertex_shader); + glAttachShader(this->program, this->fragment_shader); + glLinkProgram(this->program); + + GLint result = GL_FALSE; + int log_length; + + glGetProgramiv(this->program, GL_LINK_STATUS, &result); + glGetProgramiv(this->program, GL_INFO_LOG_LENGTH, &log_length); + + if (log_length) { + error << "LINK FAILURE LOG: \n"; + error << "===================================================\n"; + char log_message[log_length+1]; + glGetProgramInfoLog(this->program, log_length, 0, log_message); + error << log_message << "\n"; + error << "===================================================\n"; + throw std::runtime_error(error.str()); + } + + if (!result) { + error << "Failed to link program with no log message!\n"; + throw std::runtime_error(error.str()); + } + + glDetachShader(this->program, this->vertex_shader); + glDetachShader(this->program, this->fragment_shader); + glDeleteShader(this->vertex_shader); + glDeleteShader(this->fragment_shader); +} + +void Shader::use() { + if (Shader::current_program == this->program) + return; + + glUseProgram(this->program); + Shader::current_program = this->program; +} + +void Shader::load_mat4(glm::mat4 m, const char* uniform) { + GLuint location = glGetUniformLocation(this->program, uniform); + glUniformMatrix4fv(location, 1, GL_FALSE, &m[0][0]); +} + +void Shader::load_vec3(glm::vec3 v, const char* uniform) { + GLuint location = glGetUniformLocation(this->program, uniform); + glUniform3fv(location, 1, &v[0]); +} \ No newline at end of file diff --git a/src/shader.h b/src/shader.h new file mode 100644 index 0000000..11429ff --- /dev/null +++ b/src/shader.h @@ -0,0 +1,36 @@ +#ifndef SHADER_H +#define SHADER_H +#include +#include +#include +#include +#include +struct ShaderSource { + const char* source; + int length; + + ShaderSource(const char* start, const char* end); +}; + +class Shader { +private: + static GLuint current_program; + + GLuint vertex_shader; + GLuint fragment_shader; + + GLuint program; + + GLuint compile_shader(GLenum type, const char* source, int source_length); + +public: + + Shader(ShaderSource vertex_shader, ShaderSource fragment_shader); + + void load_mat4(glm::mat4 m, const char* uniform); + void load_vec3(glm::vec3 v, const char* uniform); + + void use(); +}; + +#endif \ No newline at end of file diff --git a/src/texture.cpp b/src/texture.cpp new file mode 100644 index 0000000..20815a9 --- /dev/null +++ b/src/texture.cpp @@ -0,0 +1,118 @@ +#include "texture.h" + +enum DIB_Header_Type { + BITMAPCOREHEADER, + OS22XBITMAPHEADER, + BITMAPINFOHEADER, + BITMAPV2INFOHEADER, + BITMAPV3INFOHEADER, + BITMAPV4HEADER, + BITMAPV5HEADER +}; + +void Texture::generate() { + glGenTextures(1, &this->texture); + glBindTexture(GL_TEXTURE_2D, this->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->width, this->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &this->pixel_data[0][0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} + +Texture::Texture(const unsigned char* bitmap_data) { + const unsigned char* pixel_data = &bitmap_data[*(uint32_t*)&bitmap_data[0x0a]]; + + int bmp_size = *(uint32_t*)&bitmap_data[0x02]; + + int dib_size = *(unsigned char*)&bitmap_data[0x0e]; + + DIB_Header_Type header_type; + + switch (dib_size) { + case 12: + header_type = BITMAPCOREHEADER; + break; + case 64: + header_type = OS22XBITMAPHEADER; + break; + case 16: + header_type = OS22XBITMAPHEADER; + case 40: + header_type = BITMAPINFOHEADER; + break; + case 52: + header_type = BITMAPV2INFOHEADER; + break; + case 56: + header_type = BITMAPV3INFOHEADER; + break; + case 108: + header_type = BITMAPV4HEADER; + break; + case 124: + header_type = BITMAPV5HEADER; + break; + default: + std::cerr << "0x0E: " << dib_size << "\n"; + throw std::runtime_error("Could not identify bitmap header type!"); + } + + if (header_type != BITMAPINFOHEADER) + throw std::runtime_error("Can only decode bitmaps with BITMAPINFOHEADER header type!"); + + int pixel_width = *(uint32_t*)&bitmap_data[0x12]; + int pixel_height = *(uint32_t*)&bitmap_data[0x16]; + + int ints_per_pixel = *(uint32_t*)&bitmap_data[0x1c] / 8; + + if (ints_per_pixel < 3) + throw std::runtime_error("BPP needs to be 24 or 32!"); + + //int image_size = bmp_size - *(uint32_t*)&bitmap_data[0x0a]; + + //image_size /= 4; + //image_size /= ints_per_pixel; + + int image_size = pixel_width * pixel_height * ints_per_pixel; + + for (int y=0; ypixel_data.emplace_back( + pixel_data[(y * pixel_width + x) * 4 + 2], + pixel_data[(y * pixel_width + x) * 4 + 1], + pixel_data[(y * pixel_width + x) * 4], + pixel_data[(y * pixel_width + x) * 4 + 3] + ); + } else { + this->pixel_data.emplace_back( + pixel_data[(y * pixel_width + x) * 3 + 2], + pixel_data[(y * pixel_width + x) * 3 + 1], + pixel_data[(y * pixel_width + x) * 3], + 255 + ); + } + } + } + + this->width = pixel_width; + this->height = pixel_height; + + this->generate(); +} + +Texture::Texture(glm::vec4 color) { + this->pixel_data.push_back(glm::vec4( + 255 * color.x, + 255 * color.y, + 255 * color.z, + 255 * color.w + )); + this->width = 1; + this->height = 1; + + this->generate(); +} + +void Texture::select() { + glBindTexture(GL_TEXTURE_2D, this->texture); +} \ No newline at end of file diff --git a/src/texture.h b/src/texture.h new file mode 100644 index 0000000..b2beb5a --- /dev/null +++ b/src/texture.h @@ -0,0 +1,28 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include +#include +#include +#include +#include +#include + +class Texture { +private: + GLuint texture; + std::vector> pixel_data; + + int width; + int height; + + void generate(); + +public: + Texture(const unsigned char* bitmap_data); + Texture(glm::vec4 color); + + void select(); +}; + +#endif \ No newline at end of file diff --git a/src/window.cpp b/src/window.cpp index 37ea178..1e9616a 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -44,7 +44,7 @@ Window::Window(int width, int height, char* title, void(*key_callback)(GLFWwindo glfwSetKeyCallback(this->window, key_callback); } -void Window::mainloop(std::function f) { +void Window::mainloop(std::function f) { std::chrono::high_resolution_clock clock; auto last_time = clock.now(); @@ -52,7 +52,7 @@ void Window::mainloop(std::function f) { while (!glfwWindowShouldClose(this->window)) { auto current_time = clock.now(); - std::chrono::duration deltatime = current_time - last_time; + std::chrono::duration deltatime = current_time - last_time; f(deltatime.count(), this->window); @@ -63,6 +63,6 @@ void Window::mainloop(std::function f) { } } -void Window::register_resize_callback(void* v, std::function f) { +void Window::register_resize_callback(std::function f, void* v) { this->resize_callbacks.emplace_back(v, f); } \ No newline at end of file diff --git a/src/window.h b/src/window.h index 883fef4..2b0b3f4 100644 --- a/src/window.h +++ b/src/window.h @@ -15,21 +15,22 @@ class Window { using callback_tuple = std::tuple>; private: GLFWwindow* window; - static Window* current_window; std::vector resize_callbacks; static void resize(GLFWwindow* window, int w, int h); public: + static Window* current_window; + static int width; static int height; Window(int width, int height, char* title, void(*key_callback)(GLFWwindow*, int, int, int, int)); - void mainloop(std::function); + void mainloop(std::function); - void register_resize_callback(void* v, std::function); + void register_resize_callback(std::function, void* v); }; #endif \ No newline at end of file diff --git a/src/world.cpp b/src/world.cpp new file mode 100644 index 0000000..12574f2 --- /dev/null +++ b/src/world.cpp @@ -0,0 +1,115 @@ +#include "world.h" + +World* World::world; +FastNoise World::noise; + +World::World() { + World::noise = FastNoise(); + World::noise.SetNoiseType(FastNoise::Perlin); +} + +void World::generate_around(int x, int z) { + int world_size_half = this->world_size / 2; + + this->world_center = glm::vec2(x, z); + + for (int x=-world_size_half; xchunks.push_back(c); + this->location_map[std::tuple(x, z)] = c; + } + } + + for (Chunk* c : this->chunks) + c->generate(); + + World::world = this; +} + +void World::process(int x, int z) { + x /= 16; + z /= 16; + if (x == this->world_center[0] && z == this->world_center[1]) + return; + + std::vector new_chunks; + + // Player has moved from the world center. + + // Determine world bounds. + + int world_size_half = this->world_size / 2; + + int x_low = x - world_size_half; + int x_high = x + world_size_half; + + int z_low = z - world_size_half; + int z_high = z + world_size_half; + + for (Chunk* chunk : this->chunks) { + // Check if the chunk is outside world bounds + if (chunk->x < x_low || chunk->x > x_high || chunk->z < z_low || chunk->z > z_high) { + // Determine the chunks position relative to the old world center. + + int rel_x = chunk->x - world_center[0]; // Positive = +x direction + int rel_z = chunk->z - world_center[1]; // Positive = +z direction + + if (chunk->x < x_low) + rel_x = -rel_x - 1; + else if (chunk->x > x_high) + rel_x = -rel_x + 1; + if (chunk->z < z_low) + rel_z = -rel_z - 1; + else if (chunk->z > z_high) + rel_z = -rel_z + 1; + + // Create a new chunk to take its place. + + Chunk* c = new Chunk(x + rel_x, z + rel_z); + new_chunks.push_back(c); + this->location_map[std::tuple(x + rel_x, z + rel_z)] = c; + + // Remove and delete it. + this->location_map.erase(std::tuple(chunk->x, chunk->z)); + delete chunk; + } else { + // If it's in bounds, keep it. + new_chunks.push_back(chunk); + } + } + + // Go through all the chunks and regenerate them if they are outdated + for (Chunk* chunk : new_chunks) + if (chunk->outdated()) + chunk->generate(); + + //new_chunks.swap(this->chunks); + this->chunks = new_chunks; + + world_center = glm::vec2(x, z); +} + +float World::get_height_at(int x, int z) { + return World::noise.GetNoise(x, z); +} + +Chunk* World::get_chunk(int x, int z) { + auto search = this->location_map.find(std::tuple(x, z)); + if (search == this->location_map.end()) + return 0; + return std::get<1>(*search); +} + +void World::render(Camera* c, Shader* s) { + s->use(); + s->load_mat4(c->get_view_matrix(), "view_matrix"); + s->load_mat4(c->get_projection_matrix(), "proj_matrix"); + s->load_vec3(c->get_position(), "camera_position"); + for (Chunk* chunk : this->chunks) { + s->load_mat4(chunk->get_transformation_matrix(), "model_matrix"); + chunk->select(); + + glDrawElements(GL_TRIANGLES, chunk->vertex_count, GL_UNSIGNED_INT, 0); + } +} \ No newline at end of file diff --git a/src/world.h b/src/world.h new file mode 100644 index 0000000..f10c732 --- /dev/null +++ b/src/world.h @@ -0,0 +1,49 @@ +#ifndef WORLD_H +#define WORLD_H + +#include +#include +#include + +#include "FastNoise.h" +#include "chunk.h" + +#include "camera.h" +#include "shader.h" + +namespace std { + template<> + struct hash> { + size_t operator()(std::tuple const& in) const { + return std::get<0>(in) ^ std::get<1>(in); + } + }; +} + +class World { +private: + std::unordered_map, Chunk*> location_map; + + std::vector chunks; + + static FastNoise noise; + + glm::ivec2 world_center; + + int world_size = 32; + + static World* world; + +public: + World(); + + void generate_around(int x, int z); + void process(int x, int z); + + static float get_height_at(int x, int z); + Chunk* get_chunk(int x, int z); + + void render(Camera* c, Shader* s); +}; + +#endif \ No newline at end of file