nuclear-plant-sim/src/world/chunk.cpp

140 lines
3.4 KiB
C++

#include <GL/glew.h>
#include "chunk.hpp"
#include "tile/tile_base.hpp"
#include <glm/detail/qualifier.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/quaternion_transform.hpp>
#include <glm/ext/scalar_constants.hpp>
#include <iterator>
#include <memory>
#include <utility>
using World::Chunk;
using World::Tile::TileBase;
constexpr Graphics::Primitive<4, 6> PRIMITIVE_B = {
.m_vertices = {
{.m_pos = {-0.5, -0.5, 0, 1}, .m_colour = {1, 0, 0, 1}},
{.m_pos = {-0.5, +0.5, 0, 1}, .m_colour = {1, 1, 0, 1}},
{.m_pos = {+0.5, -0.5, 0, 1}, .m_colour = {0, 1, 0, 1}},
{.m_pos = {+0.5, +0.5, 0, 1}, .m_colour = {0, 0, 1, 1}},
},
.m_indices = {
0, 2, 3,
0, 3, 1,
},
};
constexpr Graphics::Primitive<4, 6> PRIMITIVE_0 = {
.m_vertices = {
{.m_pos = {-0.5, -0.5, 0.5, 1}, .m_colour = {1, 0, 0, 1}},
{.m_pos = {-0.5, -0.5, 0, 1}, .m_colour = {1, 1, 0, 1}},
{.m_pos = {+0.5, -0.5, 0.5, 1}, .m_colour = {0, 1, 0, 1}},
{.m_pos = {+0.5, -0.5, 0, 1}, .m_colour = {0, 0, 1, 1}},
},
.m_indices = {
0, 2, 3,
0, 3, 1,
},
};
static const Graphics::Primitive<4, 6> PRIMITIVE_S[4] = {
PRIMITIVE_0.with_matrix(glm::rotate(glm::mat4(1), glm::pi<float>() * 0.5f, {0, 0, 1})),
PRIMITIVE_0.with_matrix(glm::rotate(glm::mat4(1), glm::pi<float>() * 1.0f, {0, 0, 1})),
PRIMITIVE_0.with_matrix(glm::rotate(glm::mat4(1), glm::pi<float>() * 1.5f, {0, 0, 1})),
PRIMITIVE_0,
};
constexpr glm::vec<2, int> get_pos_mod(glm::vec<2, int> pos) {
return (pos % Chunk::N + Chunk::N) % Chunk::N;
}
Chunk::Chunk(glm::vec<2, int> pos) {
m_pos = pos;
}
TileBase* Chunk::get(glm::vec<2, int> p) {
p = get_pos_mod(p);
return m_tiles[p.x * N + p.y].get();
}
const TileBase* Chunk::get(glm::vec<2, int> p) const {
p = get_pos_mod(p);
return m_tiles[p.x * N + p.y].get();
}
TileBase* Chunk::set(glm::vec<2, int> p, std::unique_ptr<TileBase> v) {
TileBase* r = v.get();
p = get_pos_mod(p);
m_tiles[p.x * N + p.y] = std::move(v);
m_dirty = true;
return r;
}
void Chunk::update(Map& map) {
for(auto& tile : m_tiles) {
if(tile) {
tile->update();
}
}
if(!m_dirty) {
return;
}
Graphics::Mesh mesh;
const Chunk* chunks[4] = {
map.get_chunk(m_pos + glm::vec<2, int>(N, 0)),
map.get_chunk(m_pos + glm::vec<2, int>(0, N)),
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},
};
for(int x = 0; x < N; x++) {
for(int y = 0; y < N; y++) {
if(!get({x, y})) {
continue;
}
glm::vec<2, int> t_off(m_pos.x + x, m_pos.y + y);
mesh.add_primitive(PRIMITIVE_B.with_translation({t_off, 0}));
for(int i = 0; i < std::size(neighbours); i++) {
glm::vec<2, int> n_off = neighbours[i] + glm::vec<2, int>(x, y);
const Chunk* chunk_check = this;
if(n_off.x == N) {
chunk_check = chunks[0];
} else if(n_off.y == N) {
chunk_check = chunks[1];
} else if(n_off.x == -1) {
chunk_check = chunks[2];
} else if(n_off.y == -1) {
chunk_check = chunks[3];
}
if(!chunk_check || !chunk_check->get(n_off)) {
mesh.add_primitive(PRIMITIVE_S[i].with_translation({t_off, 0}));
}
}
}
}
m_model.bind();
m_model.set(mesh, GL_DYNAMIC_DRAW);
Graphics::Vertex::set_vertex_attribs();
m_dirty = false;
}
void Chunk::render(Graphics::Context& ctx) const {
m_model.bind();
m_model.render(GL_TRIANGLES);
for(auto& tile : m_tiles) {
if(tile) {
tile->render();
}
}
}