feat: grass (#11)

* feat: add grass texture and update grass_block texture

* feat: add block data

* feat: add blocks_tool

* feat: add sync info and change function in blocks_tools

* feat: add check and new function

* refactor: make block texture loading data-driven

* feat: add rendering for grass

* feat: passable grass

* feat: random grass place

* fix: memory leak in TextureManager::load_cross_plane_texture
This commit is contained in:
zhenyan121
2026-05-28 21:34:36 +08:00
committed by GitHub
parent bbf8b4e969
commit 5901ab7cd9
47 changed files with 1193 additions and 210 deletions

View File

@@ -8,7 +8,6 @@ constexpr int WORLD_SIZE_Y = 256;
constexpr int CHUNK_SIZE = 16;
constexpr int SEA_LEVEL = 64;
constexpr int MAX_BLOCK_NUM = 9;
constexpr int MAX_UI_NUM = 1;
constexpr int MAX_BLOCK_STATUS = 1;
constexpr int MAX_BIOME_SUM = 4;
@@ -17,7 +16,7 @@ constexpr int MAX_CHARACTER = 128;
constexpr int PRE_LOAD_DISTANCE = 24;
constexpr int MAX_DISTANCE = 128;
constexpr int CROSS_PLANE_DISTANCE = 8;
constexpr float DEFAULT_FOV = 70.0f;
constexpr float DEFAULT_MAX_WALK_SPEED = 4.5f;
constexpr float DEFAULT_MAX_RUN_SPEED = 7.0f;

View File

@@ -1,8 +1,5 @@
#pragma once
#include "Cubed/constants.hpp"
#include "Cubed/tools/cubed_assert.hpp"
#include <array>
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
@@ -40,16 +37,40 @@ struct LookBlock {
glm::ivec3 normal;
};
constexpr std::array<std::string_view, MAX_BLOCK_NUM> BLOCK_REISTER{
"air", "grass_block", "dirt", "stone", "sand", "log", "leaf",
"water", "snowy_grass_block"};
struct BlockData {
std::string name;
BlockType id = 0;
const std::array<bool, MAX_BLOCK_NUM> TRANSPARENT_MAP{
true, false, false, false, false, false, true, false, false};
bool is_liquid = false;
inline bool is_in_transparent_map(unsigned id) {
ASSERT_MSG(id < MAX_BLOCK_NUM, "ID is invaild");
return TRANSPARENT_MAP[id];
bool is_passable = false;
bool is_cross_plane = false;
bool is_transparent = false;
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
bool passable, bool cross_plane, bool transparent)
: name(b_name), id(b_id), is_liquid(liquid), is_passable(passable),
is_cross_plane(cross_plane), is_transparent(transparent) {}
};
class BlockManager {
public:
static const std::vector<BlockData>& datas();
static void init();
static unsigned sums();
static unsigned cross_plane_sum();
static const std::string& name_form_id(BlockType id);
static bool is_cross_plane(BlockType id);
static bool is_transparent(BlockType id);
static bool is_passable(BlockType id);
static BlockType cross_plane_index(BlockType id);
private:
static void set_up_cross_plane_map();
static inline std::vector<BlockData> m_datas;
static inline bool is_init = false;
static inline std::unordered_map<BlockType, BlockType> m_cross_plane_map;
};
} // namespace Cubed

View File

@@ -12,5 +12,6 @@ public:
protected:
void build_bottom();
void place_grass();
};
} // namespace Cubed

View File

@@ -7,7 +7,7 @@
#include "Cubed/primitive_data.hpp"
#include <atomic>
#include <mutex>
namespace Cubed {
class World;
@@ -21,7 +21,8 @@ private:
std::atomic<bool> m_dirty{false};
std::atomic<bool> m_need_upload{true};
std::atomic<bool> m_is_on_gen_vertex_data{false};
std::atomic<size_t> m_vertex_sum = 0;
std::atomic<size_t> m_normal_vertices_sum = 0;
std::atomic<size_t> m_cross_vertices_sum = 0;
std::atomic<BiomeType> m_biome = BiomeType::PLAIN;
std::mutex m_vertexs_data_mutex;
@@ -32,9 +33,10 @@ private:
HeightMapArray m_heightmap;
// the index is a array of block id
std::vector<BlockType> m_blocks;
GLuint m_vbo = 0;
std::vector<Vertex> m_vertexs_data;
GLuint m_normal_vbo = 0;
GLuint m_cross_plane_vbo = 0;
std::vector<Vertex> m_normal_vertices;
std::vector<Vertex> m_cross_plane_vertices;
float frequency = 0.01f;
float height = 80;
unsigned m_seed = 0;
@@ -42,6 +44,9 @@ private:
BiomeConditions m_conditions;
void clear_dirty();
void gen_normal_vertices(
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
void gen_cross_plane_vertices();
public:
Chunk(World& world, ChunkPos chunk_pos);
@@ -93,8 +98,10 @@ public:
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
void upload_to_gpu();
GLuint get_vbo() const;
size_t get_vertex_sum() const;
GLuint get_normal_vbo() const;
size_t get_normal_vertices_sum() const;
GLuint get_cross_vbo() const;
size_t get_cross_vertices_sum() const;
bool is_dirty() const;
void mark_dirty();

View File

@@ -15,14 +15,16 @@
namespace Cubed {
struct ChunkRenderSnapshot {
GLuint vbo;
size_t vertex_count;
GLuint normal_vbo;
size_t normal_vertices_count;
GLuint cross_vbo;
size_t cross_vertices_count;
glm::vec3 center;
glm::vec3 half_extents;
};
class Player;
class TextureManager;
class World {
private:
using ChunkPtrUpdateList = std::vector<std::pair<ChunkPos, Chunk*>>;
@@ -91,11 +93,13 @@ public:
int get_block(const glm::ivec3& block_pos) const;
bool is_block(const glm::ivec3& block_pos) const;
bool can_pass_block(const glm::ivec3& block_pos) const;
static ChunkPos chunk_pos(int world_x, int world_z);
void need_gen();
void render(const glm::mat4& mvp_matrix);
void render(const glm::mat4& mvp_matrix,
const TextureManager& texture_manager);
void set_block(const glm::ivec3& pos, unsigned id);
void update(float delta_time);

View File

@@ -1,21 +1,25 @@
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
// #include <string>
// #include <unordered_map>
// #include <vector>
namespace Cubed {
class MapTable {
private:
static inline std::unordered_map<unsigned, std::string> id_to_name_map;
static inline std::unordered_map<size_t, unsigned> name_to_id_map;
static inline std::vector<std::string> item_id_to_name;
/*
static inline std::unordered_map<unsigned, std::string> id_to_name_map;
static inline std::unordered_map<size_t, unsigned> name_to_id_map;
static inline std::vector<std::string> item_id_to_name;
*/
public:
// please using reference
/*
static std::string_view get_name_from_id(unsigned id);
static unsigned get_id_from_name(const std::string& name);
static std::string_view item_name(unsigned id);
static const std::vector<std::string>& item_map();
*/
static void init_map();
};

View File

@@ -1,7 +1,7 @@
#pragma once
namespace Cubed {
#pragma region NORMAL_BLOCK
constexpr float VERTICES_POS[6][6][3] = {
// ===== front (z = +1) =====
{{0.0f, 0.0f, 1.0f}, // bottom left
@@ -91,7 +91,7 @@ constexpr float TEX_COORDS[6][6][2] = {
{0.0f, 1.0f}, // back left
{0.0f, 0.0f}} // front left
};
#pragma endregion
constexpr float CUBE_VER[24] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0};
@@ -112,7 +112,43 @@ constexpr float SQUARE_TEXTURE_POS[6][2] = {
{0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f},
{1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f},
};
#pragma region CROSS_PLANE
constexpr float CROSS_VERTICES_POS[2][6][3] = {
// ===== Plane 1: bottom-front-left to top-back-right =====
{{0.0f, 0.0f, 0.0f}, // bottom front left
{0.0f, 1.0f, 0.0f}, // top front left
{1.0f, 1.0f, 1.0f}, // top back right
{1.0f, 1.0f, 1.0f}, // top back right
{1.0f, 0.0f, 1.0f}, // bottom back right
{0.0f, 0.0f, 0.0f}}, // bottom front left
// ===== Plane 2: bottom-front-right to top-back-left =====
{{1.0f, 0.0f, 0.0f}, // bottom front right
{1.0f, 1.0f, 0.0f}, // top front right
{0.0f, 1.0f, 1.0f}, // top back left
{0.0f, 1.0f, 1.0f}, // top back left
{0.0f, 0.0f, 1.0f}, // bottom back left
{1.0f, 0.0f, 0.0f}}, // bottom front right
};
constexpr float CROSS_TEX_COORDS[2][6][2] = {
// ===== Plane 1: bottom-front-left to top-back-right =====
{{0.0f, 1.0f}, // bottom left
{0.0f, 0.0f}, // top left
{1.0f, 0.0f}, // top right
{1.0f, 0.0f}, // top right
{1.0f, 1.0f}, // bottom right
{0.0f, 1.0f}}, // bottom left
// ===== Plane 2: bottom-front-right to top-back-left =====
{{0.0f, 1.0f}, // bottom left
{0.0f, 0.0f}, // top left
{1.0f, 0.0f}, // top right
{1.0f, 0.0f}, // top right
{1.0f, 1.0f}, // bottom right
{0.0f, 1.0f}}, // bottom left
};
#pragma endregion
struct Vertex {
float x = 0.0f, y = 0.0f, z = 0.0f;
float s = 0.0f, t = 0.0f;

View File

@@ -8,16 +8,19 @@ namespace Cubed {
class TextureManager {
private:
bool m_need_reload = false;
GLuint m_block_status_array;
GLuint m_texture_array;
GLuint m_ui_array;
GLuint m_block_status_array = 0;
GLuint m_texture_array = 0;
GLuint m_cross_plane_array = 0;
GLuint m_ui_array = 0;
GLfloat m_max_aniso = 0.0f;
int m_aniso = 1;
std::vector<GLuint> m_item_textures;
void load_block_status(unsigned status_id);
void load_block_texture(unsigned block_id);
void load_item_texture(const std::string& name);
void load_block_item_texture(unsigned id);
void load_cross_plane_texture(unsigned id);
void load_ui_texture(unsigned id);
void init_item();
void init_block();
@@ -31,6 +34,7 @@ public:
void delet_texture();
GLuint get_block_status_array() const;
GLuint get_texture_array() const;
GLuint get_cross_plane_array() const;
GLuint get_ui_array() const;
const std::vector<GLuint>& item_textures() const;
// Must call after MapTable::init_map() and glfwMakeContextCurrent(window);