Infinite terrain

This commit is contained in:
Xnoe 2022-08-06 09:47:08 +01:00
parent a95f8287f7
commit a516f29be1
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
16 changed files with 958 additions and 11 deletions

37
res/fragment_shader.dat Normal file
View File

@ -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;
}

BIN
res/textures.dat Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

31
res/vertex_shader.dat Normal file
View File

@ -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;
}

80
src/camera.cpp Normal file
View File

@ -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;
}

38
src/camera.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef CAMERA_H
#define CAMERA_H
#include <glm/glm.hpp>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#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

186
src/chunk.cpp Normal file
View File

@ -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; x<Chunk::horiz_size; x++) {
for (int z=0; z<Chunk::horiz_size; z++) {
int max_height = 96 + 32 * World::get_height_at(this->x * 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<glm::vec3> vertex_positions;
std::vector<glm::vec3> vertex_normals;
std::vector<glm::vec2> vertex_tex_coords;
std::vector<int> vertex_indexes;
int index=0;
for (int x=0; x<Chunk::horiz_size; x++) {
for (int z=0; z<Chunk::horiz_size; z++) {
for (int y=0; y<Chunk::vert_size; y++) {
int block;
if (block = get_block(x, y, z)) {
bool faces[6] = {
!get_block(x-1, y, z), // Left
!get_block(x+1, y, z), // Right
!get_block(x, y, z-1), // Back
!get_block(x, y, z+1), // Front
!get_block(x, y-1, z), // Bottom
!get_block(x, y+1, z), // Top
};
for (int i=0; i<6; i++) {
if (faces[i]) {
vertex_positions.emplace_back(cube_vertexes[i][0].x + x, cube_vertexes[i][0].y + y, cube_vertexes[i][0].z + z);
vertex_positions.emplace_back(cube_vertexes[i][1].x + x, cube_vertexes[i][1].y + y, cube_vertexes[i][1].z + z);
vertex_positions.emplace_back(cube_vertexes[i][2].x + x, cube_vertexes[i][2].y + y, cube_vertexes[i][2].z + z);
vertex_positions.emplace_back(cube_vertexes[i][3].x + x, cube_vertexes[i][3].y + y, cube_vertexes[i][3].z + z);
vertex_normals.push_back(cube_normals[i]);
vertex_normals.push_back(cube_normals[i]);
vertex_normals.push_back(cube_normals[i]);
vertex_normals.push_back(cube_normals[i]);
int u = block % 16;
int v = block / 16;
float uv_step = 1.0f / 16.0f;
vertex_tex_coords.emplace_back(uv_step * (u), uv_step * (v));
vertex_tex_coords.emplace_back(uv_step * (u), uv_step * (v+1));
vertex_tex_coords.emplace_back(uv_step * (u+1), uv_step * (v+1));
vertex_tex_coords.emplace_back(uv_step * (u+1), uv_step * (v));
vertex_indexes.push_back(index + 0);
vertex_indexes.push_back(index + 1);
vertex_indexes.push_back(index + 2);
vertex_indexes.push_back(index + 2);
vertex_indexes.push_back(index + 3);
vertex_indexes.push_back(index + 0);
index += 4;
}
}
}
}
}
}
glGenVertexArrays(1, &this->VAO);
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<double> 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);
}

45
src/chunk.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef CHUNK_H
#define CHUNK_H
#include <glm/glm.hpp>
#include <glad/glad.h>
#include <tuple>
#include <chrono>
#include <iostream>
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

View File

@ -4,27 +4,92 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "window.h" #include "window.h"
#include "world.h"
#include "shader.h"
#include "texture.h"
int key_state[GLFW_KEY_LAST]; #include <glm/glm.hpp>
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) { void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if (key < 0) if (key < 0)
return; return;
if (action == GLFW_PRESS) if (action == GLFW_PRESS)
key_state[key] = 1; key_states[key] = 1;
else if (action == GLFW_RELEASE) 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); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.2f, 0.6f, 0.7f, 1.0f); 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, &current_x_pos, &current_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() { int main() {
Window w = Window(1280, 720, "xnoecraft", key_callback); 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); w.mainloop(loop);
} }

118
src/shader.cpp Normal file
View File

@ -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]);
}

36
src/shader.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <sstream>
#include <glm/glm.hpp>
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

118
src/texture.cpp Normal file
View File

@ -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; y<pixel_height; y++) {
for (int x=0; x<pixel_width; x++) {
if (ints_per_pixel == 4) {
this->pixel_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);
}

28
src/texture.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef TEXTURE_H
#define TEXTURE_H
#include <vector>
#include <glm/glm.hpp>
#include <cstdint>
#include <stdexcept>
#include <glad/glad.h>
#include <iostream>
class Texture {
private:
GLuint texture;
std::vector<glm::vec<4, unsigned char>> pixel_data;
int width;
int height;
void generate();
public:
Texture(const unsigned char* bitmap_data);
Texture(glm::vec4 color);
void select();
};
#endif

View File

@ -44,7 +44,7 @@ Window::Window(int width, int height, char* title, void(*key_callback)(GLFWwindo
glfwSetKeyCallback(this->window, key_callback); glfwSetKeyCallback(this->window, key_callback);
} }
void Window::mainloop(std::function<void(double, GLFWwindow*)> f) { void Window::mainloop(std::function<void(float, GLFWwindow*)> f) {
std::chrono::high_resolution_clock clock; std::chrono::high_resolution_clock clock;
auto last_time = clock.now(); auto last_time = clock.now();
@ -52,7 +52,7 @@ void Window::mainloop(std::function<void(double, GLFWwindow*)> f) {
while (!glfwWindowShouldClose(this->window)) { while (!glfwWindowShouldClose(this->window)) {
auto current_time = clock.now(); auto current_time = clock.now();
std::chrono::duration<double> deltatime = current_time - last_time; std::chrono::duration<float> deltatime = current_time - last_time;
f(deltatime.count(), this->window); f(deltatime.count(), this->window);
@ -63,6 +63,6 @@ void Window::mainloop(std::function<void(double, GLFWwindow*)> f) {
} }
} }
void Window::register_resize_callback(void* v, std::function<void(void*, int, int)> f) { void Window::register_resize_callback(std::function<void(void*, int, int)> f, void* v) {
this->resize_callbacks.emplace_back(v, f); this->resize_callbacks.emplace_back(v, f);
} }

View File

@ -15,21 +15,22 @@ class Window {
using callback_tuple = std::tuple<void*, std::function<void(void*, int, int)>>; using callback_tuple = std::tuple<void*, std::function<void(void*, int, int)>>;
private: private:
GLFWwindow* window; GLFWwindow* window;
static Window* current_window;
std::vector<callback_tuple> resize_callbacks; std::vector<callback_tuple> resize_callbacks;
static void resize(GLFWwindow* window, int w, int h); static void resize(GLFWwindow* window, int w, int h);
public: public:
static Window* current_window;
static int width; static int width;
static int height; static int height;
Window(int width, int height, char* title, void(*key_callback)(GLFWwindow*, int, int, int, int)); Window(int width, int height, char* title, void(*key_callback)(GLFWwindow*, int, int, int, int));
void mainloop(std::function<void(double, GLFWwindow*)>); void mainloop(std::function<void(float, GLFWwindow*)>);
void register_resize_callback(void* v, std::function<void(void*, int, int)>); void register_resize_callback(std::function<void(void*, int, int)>, void* v);
}; };
#endif #endif

115
src/world.cpp Normal file
View File

@ -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; x<world_size_half; x++) {
for (int z=-world_size_half; z<world_size_half; z++) {
Chunk* c = new Chunk(x, z);
this->chunks.push_back(c);
this->location_map[std::tuple<int, int>(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<Chunk*> 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<int, int>(x + rel_x, z + rel_z)] = c;
// Remove and delete it.
this->location_map.erase(std::tuple<int, int>(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<int, int>(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);
}
}

49
src/world.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef WORLD_H
#define WORLD_H
#include <unordered_map>
#include <tuple>
#include <vector>
#include "FastNoise.h"
#include "chunk.h"
#include "camera.h"
#include "shader.h"
namespace std {
template<>
struct hash<std::tuple<int, int>> {
size_t operator()(std::tuple<int, int> const& in) const {
return std::get<0>(in) ^ std::get<1>(in);
}
};
}
class World {
private:
std::unordered_map<std::tuple<int, int>, Chunk*> location_map;
std::vector<Chunk*> 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