Infinite terrain
This commit is contained in:
parent
a95f8287f7
commit
a516f29be1
37
res/fragment_shader.dat
Normal file
37
res/fragment_shader.dat
Normal 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
BIN
res/textures.dat
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
31
res/vertex_shader.dat
Normal file
31
res/vertex_shader.dat
Normal 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
80
src/camera.cpp
Normal 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
38
src/camera.h
Normal 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
186
src/chunk.cpp
Normal 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
45
src/chunk.h
Normal 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
|
75
src/main.cpp
75
src/main.cpp
@ -4,27 +4,92 @@
|
||||
#include <GLFW/glfw3.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) {
|
||||
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);
|
||||
}
|
118
src/shader.cpp
Normal file
118
src/shader.cpp
Normal 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
36
src/shader.h
Normal 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
118
src/texture.cpp
Normal 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
28
src/texture.h
Normal 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
|
@ -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<void(double, GLFWwindow*)> f) {
|
||||
void Window::mainloop(std::function<void(float, GLFWwindow*)> f) {
|
||||
std::chrono::high_resolution_clock clock;
|
||||
|
||||
auto last_time = clock.now();
|
||||
@ -52,7 +52,7 @@ void Window::mainloop(std::function<void(double, GLFWwindow*)> f) {
|
||||
while (!glfwWindowShouldClose(this->window)) {
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
}
|
@ -15,21 +15,22 @@ class Window {
|
||||
using callback_tuple = std::tuple<void*, std::function<void(void*, int, int)>>;
|
||||
private:
|
||||
GLFWwindow* window;
|
||||
static Window* current_window;
|
||||
|
||||
std::vector<callback_tuple> 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(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
|
115
src/world.cpp
Normal file
115
src/world.cpp
Normal 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
49
src/world.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user