switched to texture array, began working on lua scripting, changed terrain generation

This commit is contained in:
Tunacan 2022-11-12 20:47:28 +03:00
parent 8cce00eb73
commit 1f998cca67
15 changed files with 244 additions and 152 deletions

View file

@ -3,14 +3,14 @@ CPP = g++
STRIP = strip
CFLAGS = -Ofast -g -Wstrict-aliasing -Isrc -Iinclude
CPPFLAGS = -std=gnu++20 -Wno-deprecated-enum-enum-conversion $(CFLAGS)
LDFLAGS = -lglfw -lGL -lX11 -lpthread -lXrandr -lXi -ldl -lm -lnoise
LDFLAGS = -lglfw -lGL -lX11 -lpthread -lXrandr -lXi -ldl -lm -llua
BIN = voksel
ifeq ($(CROSS), mingw-w64)
CC = x86_64-w64-mingw32-gcc
CPP = x86_64-w64-mingw32-g++
STRIP = x86_64-w64-mingw32-strip
LDFLAGS = -static -lglfw3 -lopengl32 -lgdi32 -luser32 -lkernel32 -lssp -lnoise
LDFLAGS = -static -lglfw3 -lopengl32 -lgdi32 -luser32 -lkernel32 -lssp -llua
BIN = voksel.exe
endif

11
res/scripts/base.lua Normal file
View file

@ -0,0 +1,11 @@
print("Loading base content")
local stone = game.add_texture("res/textures/blocks/stone.png")
local dirt = game.add_texture("res/textures/blocks/dirt.png")
local grass_side = game.add_texture("res/textures/blocks/grass_side.png")
local grass_top = game.add_texture("res/textures/blocks/grass_top.png")
game.add_block_type(0, 0, 0, 0, 0, 0) -- void
game.add_block_type(stone, stone, stone, stone, stone, stone)
game.add_block_type(dirt, dirt, dirt, dirt, dirt, dirt)
game.add_block_type(grass_top, dirt, grass_side, grass_side, grass_side, grass_side)

View file

@ -1,12 +1,13 @@
#version 330 core
out vec4 fragColor;
in vec2 passTexCoord;
in vec3 passTexCoords;
in vec3 passLight;
uniform sampler2D a_texture;
uniform sampler2DArray textureArray;
void main() {
vec4 texColor = texture(a_texture, passTexCoord);
vec4 texColor = texture(textureArray, passTexCoords);
// texColor.rgb = pow(texColor.rgb, vec3(2.2));
fragColor = vec4(texColor.rgb * passLight, texColor.a);
}

View file

@ -1,17 +1,26 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 1) in uint tex;
layout (location = 2) in vec4 light;
layout (location = 3) in float sunlight;
out vec2 passTexCoord;
out vec3 passTexCoords;
out vec3 passLight;
uniform mat4 mvpMatrix;
uniform float globalSunlight;
const vec2 texCoords[4] = vec2[4](
vec2(0.0f, 0.0f),
vec2(0.0f, 1.0f),
vec2(1.0f, 0.0f),
vec2(1.0f, 1.0f)
);
void main() {
gl_Position = mvpMatrix * vec4(pos, 1.0f);
passTexCoord = vec2(texCoord.x, 1.0f - texCoord.y);
uint index = tex >> 30;
uint layer = tex & 0x3FFFFFFFu;
passTexCoords = vec3(texCoords[index].x, 1.0f - texCoords[index].y, layer);
passLight = light.rgb * light.a;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -3,27 +3,14 @@
#include <vector>
#include <glm/glm.hpp>
#include <types.hpp>
#include <texture.hpp>
class BlockType {
public:
glm::vec2 *top_tex_coords;
glm::vec2 *bottom_tex_coords;
glm::vec2 *north_tex_coords;
glm::vec2 *south_tex_coords;
glm::vec2 *west_tex_coords;
glm::vec2 *east_tex_coords;
u32 top_tex_layer, bottom_tex_layer, north_tex_layer, south_tex_layer, west_tex_layer, east_tex_layer;
BlockType(TextureAtlas *atlas, u32 ttx, u32 tty, u32 btx, u32 bty, u32 ntx, u32 nty, u32 stx, u32 sty,
u32 wtx, u32 wty, u32 etx, u32 ety)
{
top_tex_coords = atlas->get_tex_coords(ttx, tty);
bottom_tex_coords = atlas->get_inverse_tex_coords(btx, bty);
north_tex_coords = atlas->get_inverse_tex_coords(ntx, nty);
south_tex_coords = atlas->get_tex_coords(stx, sty);
west_tex_coords = atlas->get_inverse_tex_coords(wtx, wty);
east_tex_coords = atlas->get_tex_coords(etx, ety);
}
BlockType(u32 ttl, u32 btl, u32 ntl, u32 stl, u32 wtl, u32 etl) : top_tex_layer(ttl), bottom_tex_layer(btl),
north_tex_layer(ntl), south_tex_layer(stl), west_tex_layer(wtl), east_tex_layer(etl)
{}
};
extern std::vector<BlockType> g_block_types;

View file

@ -9,6 +9,7 @@
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <sol/sol.hpp>
#include <stb_image.h>
#include <types.hpp>
#include <camera.hpp>
@ -22,7 +23,7 @@ u32 window_width = 800;
u32 window_height = 600;
// camera
Camera camera(glm::vec3(0, 11, 0));
Camera camera(glm::vec3(0, 54, 0));
f64 mouse_x = 0.0;
f64 mouse_y = 0.0;
f32 last_x = window_width / 2.0f;
@ -41,7 +42,7 @@ std::vector<BlockType> g_block_types;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow *window, double x_pos, double y_pos);
void process_input(GLFWwindow *window, World *world, TextureAtlas *block_atlas);
void process_input(GLFWwindow *window, World *world);
int main(int argc, char *argv[]) {
glfwInit();
@ -77,7 +78,7 @@ int main(int argc, char *argv[]) {
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
glEnable(GL_FRAMEBUFFER_SRGB);
// glEnable(GL_MULTISAMPLE);
glEnable(GL_MULTISAMPLE);
stbi_set_flip_vertically_on_load(true);
Shader chunkShader("res/shaders/chunk.vs.glsl", "res/shaders/chunk.fs.glsl");
@ -103,20 +104,21 @@ int main(int argc, char *argv[]) {
Mesh<LineVertex, GL_LINES> hitbox_mesh(hitbox_vertices, hitbox_indices, 8, 24);
TextureAtlas *block_atlas = new TextureAtlas("res/textureatlas.png", GL_RGBA, 16);
g_block_types.push_back(BlockType(block_atlas, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
g_block_types.push_back(BlockType(block_atlas, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0));
g_block_types.push_back(BlockType(block_atlas, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0));
g_block_types.push_back(BlockType(block_atlas, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
g_block_types.push_back(BlockType(block_atlas, 5, 0, 5, 0, 4, 0, 4, 0, 4, 0, 4, 0));
g_block_types.push_back(BlockType(block_atlas, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0));
TextureArray *block_tex_array = new TextureArray(4, 16, 16);
sol::state lua;
lua.open_libraries();
lua.create_named_table("game");
lua["game"]["add_texture"] = [&](const char *texture_path) -> u32 {
return block_tex_array->add_texture(texture_path);
};
lua["game"]["add_block_type"] = [&](u32 a, u32 b, u32 c, u32 d, u32 e, u32 f) {
g_block_types.push_back(BlockType(a, b, c, d, e, f));
};
lua.script_file("res/scripts/base.lua");
World *world = new World();
auto seed = 1; //time(NULL);
world->noise.SetSeed(seed);
world->noise.SetFrequency(1.1);
world->noise.SetLacunarity(1.5);
srand(seed);
for (i32 x = -4; x < 5; x++)
@ -124,16 +126,16 @@ int main(int argc, char *argv[]) {
for (i32 z = -4; z < 5; z++)
world->generate_chunk(x, y, z);
world->set_block(BlockTypes::STONE, 0, 10, 0, nullptr);
world->set_block(BlockTypes::STONE, 0, 9, 0, nullptr);
world->set_block(BlockTypes::STONE, -1, 9, 0, nullptr);
world->set_block(BlockTypes::STONE, -1, 9, -1, nullptr);
world->set_block(BlockTypes::STONE, 0, 9, -1, nullptr);
world->set_block(BlockTypes::STONE, 1, 9, 1, nullptr);
world->set_block(BlockTypes::STONE, 0, 9, 1, nullptr);
world->set_block(BlockTypes::STONE, 1, 9, 0, nullptr);
world->set_block(BlockTypes::STONE, -1, 9, 1, nullptr);
world->set_block(BlockTypes::STONE, 1, 9, -1, nullptr);
world->set_block(BlockTypes::STONE, 0, 51, 0);
world->set_block(BlockTypes::STONE, 0, 50, 0);
world->set_block(BlockTypes::STONE, -1, 50, 0);
world->set_block(BlockTypes::STONE, -1, 50, -1);
world->set_block(BlockTypes::STONE, 0, 50, -1);
world->set_block(BlockTypes::STONE, 1, 50, 1);
world->set_block(BlockTypes::STONE, 0, 50, 1);
world->set_block(BlockTypes::STONE, 1, 50, 0);
world->set_block(BlockTypes::STONE, -1, 50, 1);
world->set_block(BlockTypes::STONE, 1, 50, -1);
/*
if (rand() % 50 == 0) { // tree generation
@ -174,21 +176,21 @@ int main(int argc, char *argv[]) {
// Rendering
ImGui::Render();
process_input(window, world, block_atlas);
process_input(window, world);
glClearColor(powf(0.53, 2.2), powf(0.81, 2.2), powf(0.98, 2.2), 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera.update_matrices(window_width, window_height);
world->render(&camera, &chunkShader, block_atlas);
world->render(&camera, &chunkShader, block_tex_array);
mouse_ray = camera.position;
block_distance = 0.0f;
block_distance = 0;
mouse_hit = true;
while (world->get_block((i32)round(mouse_ray.x), (i32)round(mouse_ray.y), (i32)round(mouse_ray.z)) == 0) {
mouse_ray += (camera.front * 0.1);
block_distance += 0.1f;
if (block_distance > 6.0f) {
mouse_ray += (camera.front * 0.05);
block_distance += 0.05;
if (block_distance > 6) {
mouse_hit = false;
break;
}
@ -208,7 +210,7 @@ int main(int argc, char *argv[]) {
if (world->chunks_to_build.size() > 0) {
auto c = world->chunks_to_build.begin();
auto p = c->first;
timeTaken += c->second->build_mesh(world, block_atlas, p.x, p.y, p.z);
timeTaken += c->second->build_mesh(world, p.x, p.y, p.z);
world->chunks_with_meshes[p] = c->second;
world->chunks_to_build.erase(p);
} else break;
@ -245,22 +247,34 @@ int main(int argc, char *argv[]) {
return 0;
}
void process_input(GLFWwindow *window, World *world, TextureAtlas *block_atlas) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
void process_input(GLFWwindow *window, World *world) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE))
glfwSetWindowShouldClose(window, true);
static bool tab_locked = false, cursor_free = false;
if (glfwGetKey(window, GLFW_KEY_TAB)) {
if (!tab_locked) {
if (cursor_free)
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
cursor_free = !cursor_free;
tab_locked = true;
}
} else tab_locked = false;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_W))
camera.process_keyboard(Camera::FORWARD, delta_time);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_S))
camera.process_keyboard(Camera::BACKWARD, delta_time);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_A))
camera.process_keyboard(Camera::LEFT, delta_time);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_D))
camera.process_keyboard(Camera::RIGHT, delta_time);
if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL))
camera.movement_speed = Camera::SPEED * 2;
else if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
else if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT))
camera.movement_speed = Camera::SPEED / 2;
else
camera.movement_speed = Camera::SPEED;
@ -273,17 +287,18 @@ void process_input(GLFWwindow *window, World *world, TextureAtlas *block_atlas)
last_x = mouse_x;
last_y = mouse_y;
camera.process_mouse_movement(x_offset, y_offset);
if (!cursor_free)
camera.process_mouse_movement(x_offset, y_offset);
int mouse_button_left = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
int mouse_button_right = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT);
if (mouse_hit && !mouse_pressed && mouse_button_left == GLFW_PRESS) {
if (mouse_hit && !mouse_pressed && mouse_button_left) {
mouse_pressed = true;
world->set_block(0, (i32)round(mouse_ray.x), (i32)round(mouse_ray.y), (i32)round(mouse_ray.z), block_atlas);
} else if (mouse_hit && !mouse_pressed && mouse_button_right == GLFW_PRESS) {
world->set_block(0, (i32)round(mouse_ray.x), (i32)round(mouse_ray.y), (i32)round(mouse_ray.z));
} else if (mouse_hit && !mouse_pressed && mouse_button_right) {
mouse_pressed = true;
glm::vec3 new_ray = (camera.front * (f64)(block_distance - 1)) + camera.position;
world->set_block(BlockTypes::STONE, (i32)round(new_ray.x), (i32)round(new_ray.y), (i32)round(new_ray.z), block_atlas);
glm::vec3 new_ray = (camera.front * (f64)(block_distance - 0.05)) + camera.position;
world->set_block(BlockTypes::STONE, (i32)round(new_ray.x), (i32)round(new_ray.y), (i32)round(new_ray.z));
}
if (mouse_button_left == GLFW_RELEASE && mouse_button_right == GLFW_RELEASE) mouse_pressed = false;
}

60
src/texture.cpp Normal file
View file

@ -0,0 +1,60 @@
#include <texture.hpp>
#include <iostream>
#include <glad/glad.h>
#include <stb_image.h>
Texture::Texture(const char *texture_path, int format) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
u8 *data = stbi_load(texture_path, &width, &height, &channel_count, 0);
if (data)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
else
std::cerr << texture_path << ": Failed to load texture" << std::endl;
stbi_image_free(data);
}
void Texture::bind(Shader *shader, const char *name, u32 unit) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, id);
shader->set_int(name, unit);
}
TextureAtlas::TextureAtlas(const char *texturePath, int format, u32 tileSize) : Texture(texturePath, format) {
stride = (f64)tileSize / (f64)width;
}
TextureArray::TextureArray(u64 num_textures, u64 width, u64 height) : m_width(width), m_height(height), m_layers(num_textures) {
glGenTextures(1, &m_id);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_id);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_SRGB, width, height, num_textures, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
u32 TextureArray::add_texture(const char *texture_path) {
i32 width = m_width, height = m_height, channel_count = 0;
u8 *data = stbi_load(texture_path, &width, &height, &channel_count, 0);
if (width != m_width || height != m_height)
std::cerr << texture_path << ": Invalid texture properties - width: " << width << " expected: " << m_width << ", height: " << height << " expected: " << m_height << std::endl;
if (data)
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, m_current_layer, m_width, m_height, 1, GL_RGB + (channel_count - 3), GL_UNSIGNED_BYTE, data);
else
std::cerr << texture_path << ": Failed to load texture" << std::endl;
stbi_image_free(data);
return m_current_layer++;
}
void TextureArray::bind(Shader *shader, const char *name, u32 unit) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_id);
shader->set_int(name, unit);
}

View file

@ -1,8 +1,9 @@
#pragma once
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <stb_image.h>
#include <string>
#include <utility>
#include <vector>
#include <types.hpp>
#include <shader.hpp>
@ -14,36 +15,16 @@ public:
i32 height;
i32 channel_count;
Texture(const char *texture_path, int format) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
u8 *data = stbi_load(texture_path, &width, &height, &channel_count, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, GL_UNSIGNED_BYTE, data);
} else {
printf("Failed to load texture\n");
}
stbi_image_free(data);
}
Texture(const char *texture_path, int format);
void bind(Shader *shader, const char *name, u32 unit) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, id);
shader->set_int(name, unit);
}
void bind(Shader *shader, const char *name, u32 unit);
};
class TextureAtlas : public Texture {
public:
f64 stride;
TextureAtlas(const char *texturePath, int format, u32 tileSize) : Texture(texturePath, format) {
stride = (f64)tileSize / (f64)width;
}
TextureAtlas(const char *texturePath, int format, u32 tileSize);
inline glm::vec2* get_tex_coords(u16 tileX, u16 tileY) {
auto a = new glm::vec2[4];
@ -63,3 +44,16 @@ public:
return a;
}
};
class TextureArray {
public:
u32 m_id;
u64 m_width;
u64 m_height;
u32 m_layers, m_current_layer = 0;
TextureArray(u64 num_textures, u64 width, u64 height);
u32 add_texture(const char *texture_path);
void bind(Shader *shader, const char *name, u32 unit);
};

View file

@ -1,16 +1,16 @@
#include <glm/ext/matrix_transform.hpp>
#include <world.hpp>
#include <block.hpp>
#include <cstring>
#include <chrono>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/noise.hpp>
World::World() {}
Chunk::Chunk() {}
// returns the time it took in microseconds
i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i32 chunk_y, i32 chunk_z) {
i64 Chunk::build_mesh(World *world, i32 chunk_x, i32 chunk_y, i32 chunk_z) {
delete mesh;
Chunk *neighbor_chunks[3][3][3];
@ -59,10 +59,10 @@ i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i3
auto pos = glm::vec3(x * 2, y * 2, z * 2);
if (topVisible) {
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, -1), b.top_tex_coords[0], nl[0][2][1], nl[1][2][0], nl[0][2][0], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, 1), b.top_tex_coords[1], nl[0][2][1], nl[1][2][2], nl[0][2][2], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, -1), b.top_tex_coords[2], nl[2][2][1], nl[1][2][0], nl[2][2][0], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, 1), b.top_tex_coords[3], nl[2][2][1], nl[1][2][2], nl[2][2][2], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, -1), 1, b.top_tex_layer, nl[0][2][1], nl[1][2][0], nl[0][2][0], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, 1), 3, b.top_tex_layer, nl[0][2][1], nl[1][2][2], nl[0][2][2], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, -1), 0, b.top_tex_layer, nl[2][2][1], nl[1][2][0], nl[2][2][0], nl[1][2][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, 1), 2, b.top_tex_layer, nl[2][2][1], nl[1][2][2], nl[2][2][2], nl[1][2][1]));
indices.push_back(last_index + 1); // 1
indices.push_back(last_index + 2); // 2
indices.push_back(last_index + 3); // 4
@ -72,10 +72,10 @@ i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i3
last_index += 4;
}
if (bottomVisible) {
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, -1), b.bottom_tex_coords[0], nl[0][0][1], nl[1][0][0], nl[0][0][0], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, -1), b.bottom_tex_coords[1], nl[2][0][1], nl[1][0][0], nl[2][0][0], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, 1), b.bottom_tex_coords[2], nl[0][0][1], nl[1][0][2], nl[0][0][2], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, 1), b.bottom_tex_coords[3], nl[2][0][1], nl[1][0][2], nl[2][0][2], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, -1), 1, b.bottom_tex_layer, nl[0][0][1], nl[1][0][0], nl[0][0][0], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, -1), 0, b.bottom_tex_layer, nl[2][0][1], nl[1][0][0], nl[2][0][0], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, 1), 3, b.bottom_tex_layer, nl[0][0][1], nl[1][0][2], nl[0][0][2], nl[1][0][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, 1), 2, b.bottom_tex_layer, nl[2][0][1], nl[1][0][2], nl[2][0][2], nl[1][0][1]));
indices.push_back(last_index + 1);
indices.push_back(last_index + 2);
indices.push_back(last_index + 3);
@ -85,10 +85,10 @@ i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i3
last_index += 4;
}
if (northVisible) {
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, -1), b.north_tex_coords[0], nl[2][0][1], nl[2][1][0], nl[2][0][0], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, -1), b.north_tex_coords[1], nl[2][2][1], nl[2][1][0], nl[2][2][0], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, 1), b.north_tex_coords[2], nl[2][0][1], nl[2][1][2], nl[2][0][2], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, 1), b.north_tex_coords[3], nl[2][2][1], nl[2][1][2], nl[2][2][2], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, -1), 1, b.north_tex_layer, nl[2][0][1], nl[2][1][0], nl[2][0][0], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, -1), 0, b.north_tex_layer, nl[2][2][1], nl[2][1][0], nl[2][2][0], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, 1), 3, b.north_tex_layer, nl[2][0][1], nl[2][1][2], nl[2][0][2], nl[2][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, 1), 2, b.north_tex_layer, nl[2][2][1], nl[2][1][2], nl[2][2][2], nl[2][1][1]));
indices.push_back(last_index + 1);
indices.push_back(last_index + 2);
indices.push_back(last_index + 3);
@ -98,10 +98,10 @@ i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i3
last_index += 4;
}
if (southVisible) {
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, -1), b.south_tex_coords[0], nl[0][0][1], nl[0][1][0], nl[0][0][0], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, 1), b.south_tex_coords[1], nl[0][0][1], nl[0][1][2], nl[0][0][2], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, -1), b.south_tex_coords[2], nl[0][2][1], nl[0][1][0], nl[0][2][0], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, 1), b.south_tex_coords[3], nl[0][2][1], nl[0][1][2], nl[0][2][2], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, -1), 1, b.south_tex_layer, nl[0][0][1], nl[0][1][0], nl[0][0][0], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, 1), 3, b.south_tex_layer, nl[0][0][1], nl[0][1][2], nl[0][0][2], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, -1), 0, b.south_tex_layer, nl[0][2][1], nl[0][1][0], nl[0][2][0], nl[0][1][1]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, 1), 2, b.south_tex_layer, nl[0][2][1], nl[0][1][2], nl[0][2][2], nl[0][1][1]));
indices.push_back(last_index + 1);
indices.push_back(last_index + 2);
indices.push_back(last_index + 3);
@ -111,10 +111,10 @@ i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i3
last_index += 4;
}
if (westVisible) {
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, -1), b.west_tex_coords[0], nl[0][1][0], nl[1][0][0], nl[0][0][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, -1), b.west_tex_coords[1], nl[0][1][0], nl[1][2][0], nl[0][2][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, -1), b.west_tex_coords[2], nl[2][1][0], nl[1][0][0], nl[2][0][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, -1), b.west_tex_coords[3], nl[2][1][0], nl[1][2][0], nl[2][2][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, -1), 1, b.west_tex_layer, nl[0][1][0], nl[1][0][0], nl[0][0][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, -1), 0, b.west_tex_layer, nl[0][1][0], nl[1][2][0], nl[0][2][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, -1), 3, b.west_tex_layer, nl[2][1][0], nl[1][0][0], nl[2][0][0], nl[1][1][0]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, -1), 2, b.west_tex_layer, nl[2][1][0], nl[1][2][0], nl[2][2][0], nl[1][1][0]));
indices.push_back(last_index + 1);
indices.push_back(last_index + 2);
indices.push_back(last_index + 3);
@ -124,10 +124,10 @@ i64 Chunk::build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i3
last_index += 4;
}
if (eastVisible) {
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, 1), b.east_tex_coords[0], nl[0][1][2], nl[1][0][2], nl[0][0][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, 1), b.east_tex_coords[1], nl[2][1][2], nl[1][0][2], nl[2][0][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, 1), b.east_tex_coords[2], nl[0][1][2], nl[1][2][2], nl[0][2][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, 1), b.east_tex_coords[3], nl[2][1][2], nl[1][2][2], nl[2][2][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, -1, 1), 1, b.east_tex_layer, nl[0][1][2], nl[1][0][2], nl[0][0][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, -1, 1), 3, b.east_tex_layer, nl[2][1][2], nl[1][0][2], nl[2][0][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3(-1, 1, 1), 0, b.east_tex_layer, nl[0][1][2], nl[1][2][2], nl[0][2][2], nl[1][1][2]));
vertices.push_back(ChunkVertex(pos + glm::vec3( 1, 1, 1), 2, b.east_tex_layer, nl[2][1][2], nl[1][2][2], nl[2][2][2], nl[1][1][2]));
indices.push_back(last_index + 1); // bottom left
indices.push_back(last_index + 2); // bottom right
indices.push_back(last_index + 3); // top left
@ -153,19 +153,35 @@ Chunk* World::generate_chunk(i32 chunk_x, i32 chunk_y, i32 chunk_z) {
Chunk *c = new Chunk();
int light = 0; //rand() % 4;
for (i32 x = 0; x < CHUNK_SIZE; x++) {
auto world_x = chunk_x * CHUNK_SIZE + x;
for (i32 z = 0; z < CHUNK_SIZE; z++) {
auto height = (i32)floor(this->noise.GetValue(((f32)chunk_x * (f32)CHUNK_SIZE + (f32)x) / (f32)CHUNK_SIZE + 0.01, 0.01, ((f32)chunk_z * (f32)CHUNK_SIZE + (f32)z) / (f32)CHUNK_SIZE + 0.01) * 10.0);
auto world_z = chunk_z * CHUNK_SIZE + z;
f32 simplex = glm::simplex(glm::vec2(world_x / 128.0f, world_z / 128.0f));
simplex = (simplex + 1) / 2;
simplex *= 64;
f32 perlin1 = glm::perlin(glm::vec2(world_x / 64.0f, world_z / 64.0f));
perlin1 = (perlin1 + 1) / 2;
perlin1 *= 8;
f32 perlin2 = glm::perlin(glm::vec2(world_x / 32.0f, world_z / 32.0f));
perlin2 = (perlin2 + 1) / 2;
perlin2 *= 4;
f32 perlin3 = glm::perlin(glm::vec2(world_x / 16.0f, world_z / 16.0f));
perlin3 = (perlin3 + 1) / 2;
perlin3 *= 2;
f32 perlin4 = glm::perlin(glm::vec2(world_x / 8.0f, world_z / 8.0f));
perlin4 = (perlin4 + 1) / 2;
i32 height = (i32)(simplex + (perlin1 * perlin2 * perlin3 * perlin4));
for (i32 y = 0; y < CHUNK_SIZE; y++) {
auto worldY = chunk_y * CHUNK_SIZE + y;
auto world_y = chunk_y * CHUNK_SIZE + y;
u32 b = 0;
if (light == 0) c->light_map[x][y][z] = (15 << 12) | (15 << 8) | (15 << 4) | 15;
if (light == 1) c->light_map[x][y][z] = (15 << 12) | (0 << 8) | (0 << 4) | 15;
if (light == 2) c->light_map[x][y][z] = (15 << 12) | (15 << 8) | (0 << 4) | 0;
if (light == 3) c->light_map[x][y][z] = (15 << 12) | (0 << 8) | (15 << 4) | 0;
if (worldY <= height) {
if (worldY == height) b = BlockTypes::GRASS;
else if (worldY >= height - 2) b = BlockTypes::DIRT;
if (world_y <= height) {
if (world_y == height) b = BlockTypes::GRASS;
else if (world_y >= height - 2) b = BlockTypes::DIRT;
else b = BlockTypes::STONE;
c->light_map[x][y][z] = 0;
}
@ -208,7 +224,7 @@ u32 World::get_block(i32 x, i32 y, i32 z) {
return chunk->blocks[xr][yr][zr];
}
void World::set_block(u32 block, i32 x, i32 y, i32 z, TextureAtlas *texture_atlas) {
void World::set_block(u32 block, i32 x, i32 y, i32 z) {
i32 xd = x / CHUNK_SIZE;
i32 yd = y / CHUNK_SIZE;
i32 zd = z / CHUNK_SIZE;
@ -232,23 +248,23 @@ void World::set_block(u32 block, i32 x, i32 y, i32 z, TextureAtlas *texture_atla
chunk->blocks[xr][yr][zr] = block;
if (block) chunk->light_map[xr][yr][zr] = 0;
else chunk->light_map[xr][yr][zr] = (15 << 12) | (15 << 8) | (15 << 4) | 15;
if (texture_atlas != nullptr && old_block != block) {
chunk->build_mesh(this, texture_atlas, xd, yd, zd);
if (xr == 0) get_chunk(xd - 1, yd, zd)->build_mesh(this, texture_atlas, xd - 1, yd, zd);
if (xr == CHUNK_SIZE - 1) get_chunk(xd + 1, yd, zd)->build_mesh(this, texture_atlas, xd + 1, yd, zd);
if (yr == 0) get_chunk(xd, yd - 1, zd)->build_mesh(this, texture_atlas, xd, yd - 1, zd);
if (yr == CHUNK_SIZE - 1) get_chunk(xd, yd + 1, zd)->build_mesh(this, texture_atlas, xd, yd + 1, zd);
if (zr == 0) get_chunk(xd, yd, zd - 1)->build_mesh(this, texture_atlas, xd, yd, zd - 1);
if (zr == CHUNK_SIZE - 1) get_chunk(xd, yd, zd + 1)->build_mesh(this, texture_atlas, xd, yd, zd + 1);
if (old_block != block) {
chunk->build_mesh(this, xd, yd, zd);
if (xr == 0) get_chunk(xd - 1, yd, zd)->build_mesh(this, xd - 1, yd, zd);
if (xr == CHUNK_SIZE - 1) get_chunk(xd + 1, yd, zd)->build_mesh(this, xd + 1, yd, zd);
if (yr == 0) get_chunk(xd, yd - 1, zd)->build_mesh(this, xd, yd - 1, zd);
if (yr == CHUNK_SIZE - 1) get_chunk(xd, yd + 1, zd)->build_mesh(this, xd, yd + 1, zd);
if (zr == 0) get_chunk(xd, yd, zd - 1)->build_mesh(this, xd, yd, zd - 1);
if (zr == CHUNK_SIZE - 1) get_chunk(xd, yd, zd + 1)->build_mesh(this, xd, yd, zd + 1);
}
}
void World::render(Camera *camera, Shader *shader, TextureAtlas *texture_atlas) {
void World::render(Camera *camera, Shader *shader, TextureArray *texture_array) {
shader->use();
texture_atlas->bind(shader, "a_texture", 0);
for (i32 x = floor(camera->position.x / 16) - camera->render_distance; x < floor(camera->position.x / 16) + camera->render_distance; x++)
for (i32 y = floor(camera->position.y / 16) - camera->render_distance; y < floor(camera->position.y / 16) + camera->render_distance; y++)
for (i32 z = floor(camera->position.z / 16) - camera->render_distance; z < floor(camera->position.z / 16) + camera->render_distance; z++) {
texture_array->bind(shader, "textureArray", 0);
for (i32 x = camera->position.x / 16 - camera->render_distance; x < camera->position.x / 16 + camera->render_distance; x++)
for (i32 y = camera->position.y / 16 - camera->render_distance; y < camera->position.y / 16 + camera->render_distance; y++)
for (i32 z = camera->position.z / 16 - camera->render_distance; z < camera->position.z / 16 + camera->render_distance; z++) {
glm::mat4 model = glm::mat4(1);
model = glm::translate(model, glm::vec3(x, y, z) * (f32)CHUNK_SIZE);
model = glm::scale(model, glm::vec3(0.5));

View file

@ -3,7 +3,6 @@
#include <vector>
#include <unordered_map>
#include <glm/glm.hpp>
#include <noise/noise.h>
#include <mesh.hpp>
#include <shader.hpp>
#include <texture.hpp>
@ -16,12 +15,13 @@ class World;
struct ChunkVertex {
glm::vec3 pos;
glm::vec2 tex;
u32 tex; // first 30 bits for layer, last 2 bits for index
glm::vec4 light;
f32 sunlight;
inline ChunkVertex() {};
inline ChunkVertex(glm::vec3 pos, glm::vec2 tex, u32 a, u32 b, u32 c, u32 d) : pos(pos), tex(tex) {
inline ChunkVertex(glm::vec3 pos, u32 tex_index, u32 tex_layer, u32 a, u32 b, u32 c, u32 d) : pos(pos) {
tex = ((tex_index & 0b11) << 30) | (tex_layer & ~((u32)0b11 << 30));
light.r = (f32)((a & 0xF) + (b & 0xF) + (c & 0xF) + (d & 0xF)) / 60.0f;
light.g = (f32)((a >> 4 & 0xF) + (b >> 4 & 0xF) + (c >> 4 & 0xF) + (d >> 4 & 0xF)) / 60.0f;
light.b = (f32)((a >> 8 & 0xF) + (b >> 8 & 0xF) + (c >> 8 & 0xF) + (d >> 8 & 0xF)) / 60.0f;
@ -30,13 +30,13 @@ struct ChunkVertex {
}
static void setup_attrib_pointers() {
glVertexAttribPointer(0, 3, GL_FLOAT, false, 40, (void*)0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(ChunkVertex), (void*)offsetof(ChunkVertex, pos));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 40, (void*)12);
glVertexAttribIPointer(1, 1, GL_UNSIGNED_INT, sizeof(ChunkVertex), (void*)offsetof(ChunkVertex, tex));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 4, GL_FLOAT, false, 40, (void*)20);
glVertexAttribPointer(2, 4, GL_FLOAT, false, sizeof(ChunkVertex), (void*)offsetof(ChunkVertex, light));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 1, GL_FLOAT, false, 40, (void*)36);
glVertexAttribPointer(3, 1, GL_FLOAT, false, sizeof(ChunkVertex), (void*)offsetof(ChunkVertex, sunlight));
glEnableVertexAttribArray(3);
}
};
@ -49,12 +49,11 @@ public:
Chunk();
i64 build_mesh(World *world, TextureAtlas *texture_atlas, i32 chunk_x, i32 chunk_y, i32 chunk_z);
i64 build_mesh(World *world, i32 chunk_x, i32 chunk_y, i32 chunk_z);
};
class World {
public:
noise::module::Perlin noise;
std::unordered_map<ivec3, Chunk*> chunks;
std::unordered_map<ivec3, Chunk*> chunks_to_build;
std::unordered_map<ivec3, Chunk*> chunks_with_meshes;
@ -64,7 +63,7 @@ public:
Chunk* generate_chunk(i32 chunk_x, i32 chunk_y, i32 chunk_z);
Chunk* get_chunk(i32 chunk_x, i32 chunk_y, i32 chunk_z);
u32 get_block(i32 x, i32 y, i32 z);
void set_block(u32 block, i32 x, i32 y, i32 z, TextureAtlas *texture_atlas);
void set_block(u32 block, i32 x, i32 y, i32 z);
void render(Camera *camera, Shader *shader, TextureAtlas *texture_atlas);
void render(Camera *camera, Shader *shader, TextureArray *texture_array);
};