added z index for tile placement

This commit is contained in:
Jay Robson 2024-07-19 14:27:41 +10:00
parent bffeac4099
commit dc8895b2dc
7 changed files with 128 additions and 91 deletions

View File

@ -20,12 +20,11 @@
using World::Builder;
Builder::Builder() {
m_tools.push_back(nullptr);
m_tools.push_back(std::make_unique<Tile::YellowBrick>());
m_tools.push_back(std::make_unique<Tile::BlueBrick>());
m_tools.push_back(std::make_unique<Tile::WhiteBrick>());
remesh_tool();
m_tools.push_back({nullptr, 0});
m_tools.push_back({nullptr, 1});
m_tools.push_back({std::make_unique<Tile::YellowBrick>(), 0});
m_tools.push_back({std::make_unique<Tile::BlueBrick>(), 1});
m_tools.push_back({std::make_unique<Tile::WhiteBrick>(), 0});
}
void Builder::do_click(State& state) {
@ -44,15 +43,20 @@ void Builder::do_click(State& state) {
return;
}
m_intersect = glm::round(glm::vec<2, double>(near - direction / direction.z * near.z) + player.m_pos);
glm::vec<2, int> intersect = glm::round(glm::vec<2, double>(near - direction / direction.z * near.z) + player.m_pos);
const auto& tool = m_tools[m_tool_index];
const Tile::TileBase* tile_cur = map.get_tile(m_intersect);
const Tile::TileBase* tile_next = m_tools[m_tool_index].get();
const Tile::TileBase* tile_cur = map.get_tile({intersect, tool.m_zpos});
if(tile_next && !tile_next->can_place(tile_cur) || !tile_next && !tile_cur) {
if(tool.m_tile && !tool.m_tile->can_place(tile_cur) || !tool.m_tile && !tile_cur) {
return;
}
if(intersect != m_intersect) {
m_intersect = intersect;
m_remesh_needed = true;
}
m_has_intersect = true;
if(!Graphics::Window::clicked) {
@ -63,14 +67,14 @@ void Builder::do_click(State& state) {
unsigned int texid;
bool texid_use_old = false;
if(tile_next) {
tile = tile_next->clone();
texid = tile_next->get_break_texture();
if(tool.m_tile) {
tile = tool.m_tile->clone();
texid = tool.m_tile->get_break_texture();
} else {
texid_use_old = true;
}
tile = map.set_tile(m_intersect, std::move(tile));
tile = map.set_tile({m_intersect, tool.m_zpos}, std::move(tile));
if(texid_use_old) {
if(tile) {
@ -91,18 +95,21 @@ void Builder::do_click(State& state) {
});
}
void Builder::remesh_tool() {
void Builder::remesh_tool(const State& state) {
const auto& tool = m_tools[m_tool_index];
Graphics::Mesh mesh;
if(m_tools[m_tool_index]) {
const Tile::TileBase* neighbours[4] = {nullptr};
m_tools[m_tool_index]->remesh(mesh, neighbours, {0, 0});
if(tool.m_tile) {
const Tile::TileBase* neighbours[4];
state.m_map.get_tile_neighbours(neighbours, glm::vec<3, int>{m_intersect, tool.m_zpos});
tool.m_tile->remesh(mesh, neighbours, {0, 0});
} else {
Graphics::Primitive<4, 6> prim = {
.m_vertices={
{.m_pos={-0.5, -0.5, 0.05, 1}, .m_uv={0, 0}},
{.m_pos={+0.5, -0.5, 0.05, 1}, .m_uv={2, 0}},
{.m_pos={-0.5, +0.5, 0.05, 1}, .m_uv={0, 2}},
{.m_pos={+0.5, +0.5, 0.05, 1}, .m_uv={2, 2}},
{.m_pos={-0.25, -0.25, 0.05, 1}, .m_uv={0, 0}},
{.m_pos={+0.25, -0.25, 0.05, 1}, .m_uv={1, 0}},
{.m_pos={-0.25, +0.25, 0.05, 1}, .m_uv={0, 1}},
{.m_pos={+0.25, +0.25, 0.05, 1}, .m_uv={1, 1}},
},
.m_indices={
0, 3, 2,
@ -112,17 +119,17 @@ void Builder::remesh_tool() {
prim.m_texid = Graphics::Texture::CROSS;
mesh.add_primitive(prim);
}
m_model.set(mesh, GL_DYNAMIC_DRAW);
m_remesh_needed = false;
}
void Builder::select_tool() {
int offset = std::clamp((int)std::round(Graphics::Window::scroll), -1, 1);
if(offset == 0) {
return;
}
if(offset) {
m_tool_index = Util::Math::mod(m_tool_index + offset, m_tools.size());
remesh_tool();
m_remesh_needed = true;
}
}
void Builder::update(State& state) {
@ -131,6 +138,9 @@ void Builder::update(State& state) {
select_tool();
do_click(state);
}
if(m_remesh_needed) {
remesh_tool(state);
}
}
void Builder::render(const Graphics::Context& ctx) const {
@ -138,7 +148,7 @@ void Builder::render(const Graphics::Context& ctx) const {
return;
}
glm::vec<2, double> pos = glm::round(m_intersect);
glm::vec<2, double> pos = m_intersect;
ctx.set_model_matrix(glm::translate(glm::mat4(1), {pos - ctx.m_transform, 0}));
ctx.set_colour_matrix(glm::mat4(1));
m_model.render(GL_TRIANGLES);

View File

@ -14,11 +14,17 @@ namespace World {
CLEAR,
};
std::vector<std::unique_ptr<Tile::TileBase>> m_tools;
struct ToolType {
std::unique_ptr<Tile::TileBase> m_tile;
int m_zpos;
};
std::vector<ToolType> m_tools;
Graphics::GL::Model m_model;
glm::vec<2, double> m_intersect;
glm::vec<2, int> m_intersect;
bool m_has_intersect = false;
bool m_remesh_needed = true;
int m_tool_index = 1;
Builder();
@ -29,8 +35,8 @@ namespace World {
private:
void do_click(State& state);
void remesh_tool(const State& state);
void select_tool();
void remesh_tool();
};
};

View File

@ -19,21 +19,21 @@ Chunk::Chunk(glm::vec<2, int> pos) {
m_pos = pos;
}
const TileBase* Chunk::get(glm::vec<2, int> p) const {
p = get_pos_mod(p);
return m_tiles[p.x * N + p.y].get();
const TileBase* Chunk::get(glm::vec<3, int> p) const {
p = {get_pos_mod(p), p.z};
return m_tiles[p.x + p.y * N + p.z * N * N].get();
}
TileBase* Chunk::get(glm::vec<2, int> p) {
p = get_pos_mod(p);
return m_tiles[p.x * N + p.y].get();
TileBase* Chunk::get(glm::vec<3, int> p) {
p = {get_pos_mod(p), p.z};
return m_tiles[p.x + p.y * N + p.z * N * N].get();
}
std::unique_ptr<TileBase> Chunk::set(glm::vec<2, int> p, std::unique_ptr<TileBase> v) {
p = get_pos_mod(p);
std::unique_ptr<TileBase> Chunk::set(glm::vec<3, int> p, std::unique_ptr<TileBase> v) {
p = {get_pos_mod(p), p.z};
bool is_empty_in = v == nullptr;
std::swap(m_tiles[p.x * N + p.y], v);
std::swap(m_tiles[p.x + p.y * N + p.z * N * N], v);
if(is_empty_in && v) {
m_used_tiles -= 1;
@ -57,16 +57,16 @@ void Chunk::update(Map& map) {
map.get_chunk(m_pos + glm::vec<2, int>(-N, 0)),
map.get_chunk(m_pos + glm::vec<2, int>(0, -N)),
};
const glm::vec<2, int> neighbours[4] = {
{1, 0},
{0, 1},
{-1, 0},
{0, -1},
const glm::vec<3, int> neighbours[4] = {
{1, 0, 0},
{0, 1, 0},
{-1, 0, 0},
{0, -1, 0},
};
for(int x = 0; x < N; x++) {
for(int y = 0; y < N; y++) {
glm::vec<2, int> t_off(x, y);
for(int x = 0; x < N; x++) for(int y = 0; y < N; y++) for(int z = 0; z < H; z++) {
glm::vec<3, int> t_off(x, y, z);
const Tile::TileBase* tile = get(t_off);
if(!tile) {
@ -76,7 +76,7 @@ void Chunk::update(Map& map) {
const Tile::TileBase* tiles[4];
for(int i = 0; i < std::size(neighbours); i++) {
glm::vec<2, int> n_off = neighbours[i] + t_off;
glm::vec<3, int> n_off = neighbours[i] + t_off;
const Chunk* chunk_check = this;
if(n_off.x == N) {
chunk_check = chunks[0];
@ -96,7 +96,6 @@ void Chunk::update(Map& map) {
tile->remesh(mesh, tiles, {x, y});
}
}
m_model.set(mesh, GL_DYNAMIC_DRAW);
m_dirty = false;
}

View File

@ -15,8 +15,9 @@ namespace World {
namespace World {
struct Chunk {
static constexpr int N = 16;
static constexpr int H = 2;
std::unique_ptr<Tile::TileBase> m_tiles[N*N] = {{}};
std::unique_ptr<Tile::TileBase> m_tiles[N*N*H] = {{}};
Graphics::GL::Model m_model;
glm::vec<2, int> m_pos;
int m_used_tiles = 0;
@ -26,9 +27,9 @@ namespace World {
void update(Map& map);
void render(const Graphics::Context& ctx) const;
const Tile::TileBase* get(glm::vec<2, int> p) const;
Tile::TileBase* get(glm::vec<2, int> p);
std::unique_ptr<Tile::TileBase> set(glm::vec<2, int> p, std::unique_ptr<Tile::TileBase> v);
const Tile::TileBase* get(glm::vec<3, int> p) const;
Tile::TileBase* get(glm::vec<3, int> p);
std::unique_ptr<Tile::TileBase> set(glm::vec<3, int> p, std::unique_ptr<Tile::TileBase> v);
};
};

View File

@ -56,31 +56,51 @@ void Map::mark_chunk_dirty(glm::vec<2, int> pos) {
}
}
const TileBase* Map::get_tile(glm::vec<2, int> pos) const {
const TileBase* Map::get_tile(glm::vec<3, int> pos) const {
const Chunk* c = get_chunk(pos);
return c ? c->get(pos) : nullptr;
}
TileBase* Map::get_tile(glm::vec<2, int> pos) {
TileBase* Map::get_tile(glm::vec<3, int> pos) {
Chunk* c = get_chunk(pos);
return c ? c->get(pos) : nullptr;
}
std::unique_ptr<TileBase> Map::set_tile(glm::vec<2, int> pos, std::unique_ptr<TileBase> tile) {
static const glm::vec<3, int> NEIGHBOURS[4] = {
{1, 0, 0},
{0, 1, 0},
{-1, 0, 0},
{0, -1, 0},
};
void Map::get_tile_neighbours(Tile::TileBase** neighbours, glm::vec<3, int> pos) {
for(int i = 0; i < std::size(NEIGHBOURS); i++) {
neighbours[i] = get_tile(pos + NEIGHBOURS[i]);
}
}
void Map::get_tile_neighbours(const Tile::TileBase** neighbours, glm::vec<3, int> pos) const {
for(int i = 0; i < std::size(NEIGHBOURS); i++) {
neighbours[i] = get_tile(pos + NEIGHBOURS[i]);
}
}
std::unique_ptr<TileBase> Map::set_tile(glm::vec<3, int> pos, std::unique_ptr<TileBase> tile) {
uint64_t cid = get_chunk_id(pos);
auto it = m_chunks.find(cid);
glm::vec<2, int> pos_h = pos;
if(it == m_chunks.end()) {
it = m_chunks.try_emplace(cid, pos - get_pos_mod(pos)).first;
it = m_chunks.try_emplace(cid, pos_h - get_pos_mod(pos_h)).first;
}
Chunk& c = it->second;
tile = c.set(pos, std::move(tile));
mark_chunk_dirty(pos + glm::vec<2, int>(1, 0));
mark_chunk_dirty(pos + glm::vec<2, int>(0, 1));
mark_chunk_dirty(pos + glm::vec<2, int>(-1, 0));
mark_chunk_dirty(pos + glm::vec<2, int>(0, -1));
mark_chunk_dirty(pos_h + glm::vec<2, int>(1, 0));
mark_chunk_dirty(pos_h + glm::vec<2, int>(0, 1));
mark_chunk_dirty(pos_h + glm::vec<2, int>(-1, 0));
mark_chunk_dirty(pos_h + glm::vec<2, int>(0, -1));
if(c.m_used_tiles <= 0) {
m_chunks.erase(it);

View File

@ -18,14 +18,15 @@ namespace World {
static constexpr int N = 16;
std::map<uint64_t, Chunk> m_chunks;
Tile::TileBase* get_tile(glm::vec<2, int> pos);
const Tile::TileBase* get_tile(glm::vec<2, int> pos) const;
Tile::TileBase* get_tile(glm::vec<3, int> pos);
const Tile::TileBase* get_tile(glm::vec<3, int> pos) const;
void get_tile_neighbours(Tile::TileBase** neighbours, glm::vec<3, int> pos);
void get_tile_neighbours(const Tile::TileBase** neighbours, glm::vec<3, int> pos) const;
std::unique_ptr<Tile::TileBase> set_tile(glm::vec<3, int> pos, std::unique_ptr<Tile::TileBase> tile);
Chunk* get_chunk(glm::vec<2, int> pos);
const Chunk* get_chunk(glm::vec<2, int> pos) const;
Chunk* get_or_generate_chunk(glm::vec<2, int> pos);
std::unique_ptr<Tile::TileBase> set_tile(glm::vec<2, int> pos, std::unique_ptr<Tile::TileBase> tile);
void update();
void render(const Graphics::Context& ctx) const;

View File

@ -5,7 +5,7 @@
using World::State;
State::State() {
m_map.set_tile({0, 0}, std::make_unique<Tile::YellowBrick>());
m_map.set_tile({0, 0, 0}, std::make_unique<Tile::YellowBrick>());
}
void State::update() {