Make chunks check adjacent chunks when generating mesh

This commit is contained in:
Xnoe 2022-08-07 15:04:42 +01:00
parent a516f29be1
commit 4a8bf7d05b
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
5 changed files with 136 additions and 97 deletions

View File

@ -1,11 +1,11 @@
CXX = g++
CXXFLAGS = -g -Isrc
CXXFLAGS = -O3 -Isrc
LD = ld
LINKFLAGS = -lGL -lglfw
CC = gcc
CCFLAGS = -g -Isrc
CCFLAGS = -O3 -Isrc
XNOECRAFT_CPP_SRCS = $(shell find src/ -name '*.cpp')
XNOECRAFT_C_SRCS = $(shell find src/ -name '*.c')

View File

@ -31,12 +31,37 @@ void Chunk::set_block(int x, int y, int z, int 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;
if (x < 0) {
Chunk* c;
if (c = World::get_chunk(this->x-1, this->z))
return c->get_block(Chunk::horiz_size-1, y, z);
else
return 0;
} else if (x >= Chunk::horiz_size) {
Chunk* c;
if (c = World::get_chunk(this->x+1, this->z))
return c->get_block(0, y, z);
else
return 0;
}
if (z < 0) {
Chunk* c;
if (c = World::get_chunk(this->x, this->z-1))
return c->get_block(x, y, Chunk::horiz_size-1);
else
return 0;
} else if (z >= Chunk::horiz_size) {
Chunk* c;
if (c = World::get_chunk(this->x, this->z+1))
return c->get_block(x, y, 0);
else
return 0;
}
return this->blocks[y * Chunk::horiz_size * Chunk::horiz_size + z * Chunk::horiz_size + x];
}
@ -77,100 +102,98 @@ Chunk::~Chunk() {
void Chunk::generate() {
std::chrono::high_resolution_clock clock;
if (mesh_version < current_version) {
auto t1 = clock.now();
mesh_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;
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;
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 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);
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]);
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;
int u = block % 16;
int v = block / 16;
float uv_step = 1.0f / 16.0f;
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_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);
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;
}
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";
}
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() {

View File

@ -6,10 +6,11 @@ FastNoise World::noise;
World::World() {
World::noise = FastNoise();
World::noise.SetNoiseType(FastNoise::Perlin);
World::world = this;
}
void World::generate_around(int x, int z) {
int world_size_half = this->world_size / 2;
int world_size_half = this->world_size;
this->world_center = glm::vec2(x, z);
@ -23,8 +24,6 @@ void World::generate_around(int x, int z) {
for (Chunk* c : this->chunks)
c->generate();
World::world = this;
}
void World::process(int x, int z) {
@ -34,12 +33,13 @@ void World::process(int x, int z) {
return;
std::vector<Chunk*> new_chunks;
std::vector<Chunk*> to_generate;
// Player has moved from the world center.
// Determine world bounds.
int world_size_half = this->world_size / 2;
int world_size_half = this->world_size;
int x_low = x - world_size_half;
int x_high = x + world_size_half;
@ -68,21 +68,37 @@ void World::process(int x, int z) {
Chunk* c = new Chunk(x + rel_x, z + rel_z);
new_chunks.push_back(c);
to_generate.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.
// If it's in bounds, keep it
new_chunks.push_back(chunk);
// Determine if its mesh needs regeneration
if (x < this->world_center[0]) {
if (chunk->x == x_low+2 || chunk->x == x_high)
to_generate.push_back(chunk);
} else if (x > this->world_center[0]) {
if (chunk->x == x_low || chunk->x == x_high-2)
to_generate.push_back(chunk);
}
if (z < this->world_center[1]) {
if (chunk->z == z_low+2 || chunk->z == z_high)
to_generate.push_back(chunk);
} else if (z > this->world_center[1]) {
if (chunk->z == z_low || chunk->z == z_high-2)
to_generate.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();
for (Chunk* chunk : to_generate)
chunk->generate();
//new_chunks.swap(this->chunks);
this->chunks = new_chunks;
@ -95,8 +111,8 @@ float World::get_height_at(int x, int 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())
auto search = World::world->location_map.find(std::tuple<int, int>(x, z));
if (search == World::world->location_map.end())
return 0;
return std::get<1>(*search);
}

View File

@ -30,7 +30,7 @@ private:
glm::ivec2 world_center;
int world_size = 32;
int world_size = 16;
static World* world;
@ -41,7 +41,7 @@ public:
void process(int x, int z);
static float get_height_at(int x, int z);
Chunk* get_chunk(int x, int z);
static Chunk* get_chunk(int x, int z);
void render(Camera* c, Shader* s);
};