Commit 5c6ccd48 authored by Shu's avatar Shu 🍠
Browse files

Multiverse: Areas

No position for now
parent f75afb5e
......@@ -4,10 +4,9 @@
- [x] Generate noise
- [x] Density
- [x] Robin hood map
- [ ] In memory RLE
- [ ] Octree world
- [ ] Remove density
- [x] Serialize
- [ ] Variable length encoding
- [x] Group files
- [x] Zstd + custom grouping
- [~] Find best region size
......@@ -15,13 +14,15 @@
- [x] Low memory: Keep only ifstream
- [x] High memory: Save multiple
- [x] Unload unused
- [ ] In memory RLE
- [x] Edition
- [ ] Entity
- [ ] Planet
- [ ] CubicSphere
- [ ] Healpix
- [ ] Galaxy
- [ ] Area
- [ ] Offset
- [ ] Rotation
- [ ] Planet
- [ ] CubicSphere
- [ ] Healpix
- [ ] Galaxy
- [ ] Biomes
- https://imgur.com/kM8b5Zq
- https://imgur.com/a/bh2iy
......
......@@ -15,13 +15,13 @@ namespace contouring {
/// Each frame ping.
/// Mostly used for cleanup and to flush buffers data using main thread
virtual void update(const voxel_pos &pos) = 0;
virtual void update(const voxel_pos &pos, const world::area_map &areas) = 0;
/// Chunk data change
virtual void onUpdate(const chunk_pos &pos, const world::chunk_map &data, geometry::Faces neighbors) = 0;
virtual void onUpdate(const area_<chunk_pos> &pos, const world::ChunkContainer &data, geometry::Faces neighbors) = 0;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
virtual void onNotify(const chunk_pos &pos, const world::chunk_map &data) = 0;
virtual void onNotify(const area_<chunk_pos> &pos, const world::ChunkContainer &data) = 0;
/// Display ImGui config
virtual void onGui() = 0;
/// Get options
......
......@@ -5,17 +5,30 @@
#include "../world/Chunk.hpp"
namespace contouring {
void AbstractFlat::update(const voxel_pos& pos) {
center = glm::divide(pos, chunk_voxel_pos(CHUNK_LENGTH));
auto it = buffers.begin();
while (it != buffers.end()) { // Remove out of range buffers
if (inKeepRange(it->first)) {
it++;
} else {
if(it->second != NULL)
delete it->second;
void AbstractFlat::update(const voxel_pos& pos, const world::area_map& areas) {
center = glm::divide(pos);
auto it_a = buffers.begin();
while (it_a != buffers.end()) { // Remove out of range buffers
if (const auto area = areas.find(it_a->first); area != areas.end()) {
//Update
auto it = it_a->second.begin();
while(it != it_a->second.end()) {
if (inKeepRange(it->first /*TODO: + area.second->getPosition() */)) {
++it;
} else {
if(it->second != NULL)
delete it->second;
it = buffers.erase(it);
it = it_a->second.erase(it);
}
}
++it_a;
} else {
for(auto& buffer: it_a->second) {
if(buffer.second != NULL)
delete buffer.second;
}
it_a = buffers.erase(it_a);
}
}
}
......@@ -41,10 +54,11 @@ namespace contouring {
void AbstractFlat::getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) {
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density));
for (const auto [pos, buffer] : buffers) {
const glm::vec3 fPos = glm::vec3(glm::llvec3(pos) * glm::llvec3(CHUNK_LENGTH) - offset * glm::llvec3(density)) / glm::vec3(density);
for (const auto [_, bfs] : buffers) {
for (const auto [pos, buffer] : bfs) {
const glm::vec3 fPos = glm::vec3(glm::multiply(pos /*TODO: + area.position*/) - offset * glm::llvec3(density)) / glm::vec3(density);
if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, glm::vec3(CHUNK_LENGTH / (float)density)))))
out.emplace_back(glm::translate(scaling, fPos * (float)density), buffer);
}
}}
}
}
\ No newline at end of file
......@@ -11,7 +11,7 @@ namespace contouring {
virtual ~AbstractFlat() {}
/// Each frame ping. Used to clear out of range
void update(const voxel_pos &) override;
void update(const voxel_pos &, const world::area_map &areas) override;
/// Display ImGui config
void onGui() override;
......@@ -30,7 +30,8 @@ namespace contouring {
return glm::length2(center - point) <= keepDistance * keepDistance;
}
robin_hood::unordered_map<chunk_pos, buffer::Abstract *> buffers;
//MAYBE: store position copy
robin_hood::unordered_flat_map<area_id, robin_hood::unordered_flat_map<chunk_pos, buffer::Abstract *>> buffers;
chunk_pos center = chunk_pos(INT_MAX);
int loadDistance = 3;
......
......@@ -9,9 +9,9 @@ namespace contouring {
Dummy(): Abstract() { }
virtual ~Dummy() { }
void update(const voxel_pos &) override { }
void onUpdate(const chunk_pos &, const world::chunk_map &, geometry::Faces) override {}
void onNotify(const chunk_pos &, const world::chunk_map &) override { }
void update(const voxel_pos &, const world::area_map &) override {}
void onUpdate(const area_<chunk_pos> &, const world::ChunkContainer &, geometry::Faces) override {}
void onNotify(const area_<chunk_pos> &, const world::ChunkContainer &) override {}
void onGui() override { }
std::string getOptions() override { return ""; }
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &, const std::optional<geometry::Frustum>&, const glm::llvec3&, int) override { }
......
......@@ -16,7 +16,7 @@ namespace contouring {
for (size_t i = 1; i <= 2; i++) {
workers.emplace_back([&] {
while (running) {
std::pair<chunk_pos, surrounding::corners> ctx;
std::pair<area_<chunk_pos>, surrounding::corners> ctx;
loadQueue.wait();
if (loadQueue.pop(ctx)) {
rmt_ScopedCPUSample(ProcessContouring, 0);
......@@ -49,51 +49,52 @@ namespace contouring {
return ss.str();
}
void FlatDualMC::enqueue(const chunk_pos &pos, const world::chunk_map &data) {
void FlatDualMC::enqueue(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
const auto dist2 = glm::length2(pos - center);
const auto dist2 = glm::length2(center - pos.second); //TODO: - area.pos
if (dist2 <= loadDistance * loadDistance) {
surrounding::corners surrounding;
if(surrounding::load(surrounding, pos, data)) {
if(surrounding::load(surrounding, pos.second, data)) {
loadQueue.push(pos, surrounding, -dist2);
}
}
}
void FlatDualMC::onUpdate(const chunk_pos &pos, const world::chunk_map &data, geometry::Faces neighbors) {
void FlatDualMC::onUpdate(const area_<chunk_pos> &pos, const world::ChunkContainer &data, geometry::Faces neighbors) {
enqueue(pos, data);
if (neighbors && (geometry::Faces::Left | geometry::Faces::Down | geometry::Faces::Backward)) {
for (size_t i = 1; i < 8; i++) {
enqueue(pos - surrounding::g_corner_offsets[i], data);
enqueue(std::make_pair(pos.first, pos.second - surrounding::g_corner_offsets[i]), data);
}
}
}
void FlatDualMC::onNotify(const chunk_pos &pos, const world::chunk_map &data) {
if (buffers.find(pos) == buffers.end()) {
void FlatDualMC::onNotify(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
const auto it = buffers.find(pos.first);
if(it == buffers.end() || it->second.find(pos.second) == it->second.end()) {
enqueue(pos, data);
}
}
void FlatDualMC::update(const voxel_pos& pos) {
AbstractFlat::update(pos);
std::pair<chunk_pos, buffer::ShortIndexed::Data> out;
void FlatDualMC::update(const voxel_pos& pos, const world::area_map& areas) {
AbstractFlat::update(pos, areas);
std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data> out;
reports.load.push(loadQueue.size());
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
reports.loaded.push(loadedQueue.size());
while(loadedQueue.pop(out)) {
const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second);
const auto it = buffers.find(out.first);
if (it != buffers.end()) {
auto& bfs = buffers[out.first.first];
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
if(it->second != NULL)
delete it->second;
it->second = buffer;
} else {
buffers.emplace(out.first, buffer);
bfs.emplace(out.first.second, buffer);
}
}
reports.count.push(buffers.size());
reports.count.push(buffers.size()); //FIXME: get from AbstractFlat
}
void FlatDualMC::onGui() {
......@@ -116,7 +117,7 @@ namespace contouring {
for (int y = 0; y < SIZE; y++) {
for (int x = 0; x < SIZE; x++) {
const auto &chunk = surrounding[(z >= CHUNK_LENGTH) + (y >= CHUNK_LENGTH)*2 + (x >= CHUNK_LENGTH)*4];
const auto &voxel = chunk->getAt(chunk_voxel_pos(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
const auto &voxel = chunk->get(glm::toIdx(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
grid.emplace_back(voxel.density() * 1.f / world::Voxel::DENSITY_MAX, voxel.material());
}}}
}
......
......@@ -19,21 +19,21 @@ namespace contouring {
FlatDualMC(const std::string&);
virtual ~FlatDualMC();
void update(const voxel_pos&) override;
void update(const voxel_pos&, const world::area_map&) override;
void onGui() override;
std::string getOptions() override;
/// Chunk data change
void onUpdate(const chunk_pos &, const world::chunk_map &, geometry::Faces) override;
void onUpdate(const area_<chunk_pos> &, const world::ChunkContainer &, geometry::Faces) override;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
void onNotify(const chunk_pos &, const world::chunk_map &) override;
void onNotify(const area_<chunk_pos> &, const world::ChunkContainer &) override;
protected:
safe_priority_queue_map<chunk_pos, surrounding::corners, int> loadQueue;
safe_queue<std::pair<chunk_pos, buffer::ShortIndexed::Data>> loadedQueue;
safe_priority_queue_map<area_<chunk_pos>, surrounding::corners, int, area_hash> loadQueue;
safe_queue<std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data>> loadedQueue;
struct report {
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
......@@ -44,7 +44,7 @@ namespace contouring {
bool running = true;
std::vector<std::thread> workers;
void enqueue(const chunk_pos &, const world::chunk_map &);
void enqueue(const area_<chunk_pos> &, const world::ChunkContainer &);
float iso = .1f;
bool manifold = true;
......
......@@ -11,7 +11,7 @@ namespace contouring {
for (size_t i = 1; i <= 4; i++) {
workers.emplace_back([&] {
while (running) {
std::pair<chunk_pos, surrounding::faces> ctx;
std::pair<area_<chunk_pos>, surrounding::faces> ctx;
loadQueue.wait();
if (loadQueue.pop(ctx)) {
rmt_ScopedCPUSample(ProcessContouring, 0);
......@@ -36,63 +36,64 @@ namespace contouring {
}
}
void FlatSurroundingBox::enqueue(const chunk_pos &pos, const world::chunk_map &data) {
void FlatSurroundingBox::enqueue(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
const auto dist2 = glm::length2(pos - center);
const auto dist2 = glm::length2(center - pos.second /*TODO: - area.pos */);
if (dist2 <= loadDistance * loadDistance) {
surrounding::faces surrounding;
if(surrounding::load(surrounding, pos, data)) {
if(surrounding::load(surrounding, pos.second, data)) {
loadQueue.push(pos, surrounding, -dist2);
}
}
}
void FlatSurroundingBox::onUpdate(const chunk_pos &pos, const world::chunk_map &data, Faces neighbors) {
void FlatSurroundingBox::onUpdate(const area_<chunk_pos> &pos, const world::ChunkContainer &data, Faces neighbors) {
enqueue(pos, data);
if (neighbors && Faces::Right)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Right)], data);
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Right)]), data);
if (neighbors && Faces::Left)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Left)], data);
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Left)]), data);
if (neighbors && Faces::Up)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Up)], data);
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Up)]), data);
if (neighbors && Faces::Down)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Down)], data);
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Down)]), data);
if (neighbors && Faces::Forward)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Forward)], data);
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Forward)]), data);
if (neighbors && Faces::Backward)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Backward)], data);
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Backward)]), data);
}
void FlatSurroundingBox::onNotify(const chunk_pos &pos, const world::chunk_map &data) {
if (buffers.find(pos) == buffers.end()) {
void FlatSurroundingBox::onNotify(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
const auto it = buffers.find(pos.first);
if(it == buffers.end() || it->second.find(pos.second) == it->second.end()) {
enqueue(pos, data);
}
}
void FlatSurroundingBox::update(const voxel_pos& pos) {
AbstractFlat::update(pos);
std::pair<chunk_pos, buffer::ShortIndexed::Data> out;
void FlatSurroundingBox::update(const voxel_pos& pos, const world::area_map& areas) {
AbstractFlat::update(pos, areas);
std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data> out;
reports.load.push(loadQueue.size());
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
reports.loaded.push(loadedQueue.size());
while(loadedQueue.pop(out)) {
const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second);
const auto it = buffers.find(out.first);
if (it != buffers.end()) {
auto& bfs = buffers[out.first.first];
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
if(it->second != NULL)
delete it->second;
it->second = buffer;
} else {
buffers.emplace(out.first, buffer);
bfs.emplace(out.first.second, buffer);
}
}
reports.count.push(buffers.size());
reports.count.push(buffers.size()); //FIXME: get from AbstractFlat
}
void FlatSurroundingBox::onGui() {
......@@ -110,7 +111,7 @@ namespace contouring {
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<buffer::VertexData> &vertices) {
const auto center = surrounding[surrounding::CENTER];
vertices.clear();
for (ushort i = 0; i < CHUNK_SIZE; i++) {
for (ushort i = 0; i < world::CHUNK_SIZE; i++) {
if (center->get(i).density() > 0) {
Faces faces = center->get(i).density() < world::Voxel::DENSITY_MAX ? Faces::All :
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Right)) & Faces::Right) |
......@@ -119,7 +120,7 @@ namespace contouring {
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Down)) & Faces::Down) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Forward)) & Faces::Forward) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Backward)) & Faces::Backward);
box::addCube(vertices, world::Chunk::getPosition(i), center->get(i).material(), faces, glm::vec3(center->get(i).density() * 1.f / world::Voxel::DENSITY_MAX));
box::addCube(vertices, glm::fromIdx(i), center->get(i).material(), faces, glm::vec3(center->get(i).density() * 1.f / world::Voxel::DENSITY_MAX));
}
}
}
......
......@@ -19,19 +19,19 @@ namespace contouring {
FlatSurroundingBox(const std::string&);
virtual ~FlatSurroundingBox();
void update(const voxel_pos&) override;
void update(const voxel_pos&, const world::area_map&) override;
void onGui() override;
/// Chunk data change
void onUpdate(const chunk_pos &, const world::chunk_map &, geometry::Faces) override;
void onUpdate(const area_<chunk_pos> &, const world::ChunkContainer &, geometry::Faces) override;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
void onNotify(const chunk_pos &, const world::chunk_map &) override;
void onNotify(const area_<chunk_pos> &, const world::ChunkContainer &) override;
protected:
safe_priority_queue_map<chunk_pos, surrounding::faces, int> loadQueue;
safe_queue<std::pair<chunk_pos, buffer::ShortIndexed::Data>> loadedQueue;
safe_priority_queue_map<area_<chunk_pos>, surrounding::faces, int, area_hash> loadQueue;
safe_queue<std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data>> loadedQueue;
struct report {
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
......@@ -42,7 +42,7 @@ namespace contouring {
bool running = true;
std::vector<std::thread> workers;
void enqueue(const chunk_pos &, const world::chunk_map &);
void enqueue(const area_<chunk_pos> &, const world::ChunkContainer &);
private:
static inline bool isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx);
......
#include "surrounding.hpp"
#include "../world/Chunk.hpp"
#include "../world/Area.hpp"
#include "../data/math.hpp"
using namespace geometry;
namespace contouring::surrounding {
bool load(faces &out, const chunk_pos &chunkPos, const world::chunk_map &chunks) {
bool load(faces &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks) {
{
const auto it = chunks.find(chunkPos);
if (it == chunks.end())
const auto chunk = chunks.findInRange(chunkPos);
if (!chunk.has_value())
return false;
out[CENTER] = it->second;
out[CENTER] = chunk.value();
}
for (size_t i = 0; i < CENTER; i++) {
const auto it = chunks.find(chunkPos + g_face_offsets[i]);
if (it == chunks.end())
const auto chunk = chunks.findOrEmpty(chunkPos + g_face_offsets[i]);
if (!chunk.has_value())
return false;
out[i] = it->second;
out[i] = chunk.value();
}
return true;
}
std::pair<ushort, ushort> getNeighborIdx(ushort idx, Face face) {
std::pair<glm::idx, glm::idx> getNeighborIdx(glm::idx idx, Face face) {
switch (face) {
case Face::Forward:
if (idx % CHUNK_LENGTH >= CHUNK_LENGTH - 1)
return {static_cast<int>(Face::Forward), idx - (CHUNK_LENGTH - 1)};
if (idx % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1)
return {static_cast<int>(Face::Forward), idx - (glm::IDX_LENGTH - 1)};
return {CENTER, idx + 1};
case Face::Backward:
if (idx % CHUNK_LENGTH <= 0)
return {static_cast<int>(Face::Backward), idx + (CHUNK_LENGTH - 1)};
if (idx % glm::IDX_LENGTH <= 0)
return {static_cast<int>(Face::Backward), idx + (glm::IDX_LENGTH - 1)};
return {CENTER, idx - 1};
case Face::Up:
if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH >= CHUNK_LENGTH - 1)
return {static_cast<int>(Face::Up), idx - (CHUNK_LENGTH2 - CHUNK_LENGTH)};
return {CENTER, idx + CHUNK_LENGTH};
if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1)
return {static_cast<int>(Face::Up), idx - (glm::IDX_LENGTH2 - glm::IDX_LENGTH)};
return {CENTER, idx + glm::IDX_LENGTH};
case Face::Down:
if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH <= 0)
return {static_cast<int>(Face::Down), idx + (CHUNK_LENGTH2 - CHUNK_LENGTH)};
return {CENTER, idx - CHUNK_LENGTH};
if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH <= 0)
return {static_cast<int>(Face::Down), idx + (glm::IDX_LENGTH2 - glm::IDX_LENGTH)};
return {CENTER, idx - glm::IDX_LENGTH};
case Face::Right:
if (idx / CHUNK_LENGTH2 >= CHUNK_LENGTH - 1)
return {static_cast<int>(Face::Right), idx - (CHUNK_SIZE - CHUNK_LENGTH2)};
return {CENTER, idx + CHUNK_LENGTH2};
if (idx / glm::IDX_LENGTH2 >= glm::IDX_LENGTH - 1)
return {static_cast<int>(Face::Right), idx - (glm::IDX_SIZE - glm::IDX_LENGTH2)};
return {CENTER, idx + glm::IDX_LENGTH2};
case Face::Left:
if (idx / CHUNK_LENGTH2 <= 0)
return {static_cast<int>(Face::Left), idx + (CHUNK_SIZE - CHUNK_LENGTH2)};
return {CENTER, idx - CHUNK_LENGTH2};
if (idx / glm::IDX_LENGTH2 <= 0)
return {static_cast<int>(Face::Left), idx + (glm::IDX_SIZE - glm::IDX_LENGTH2)};
return {CENTER, idx - glm::IDX_LENGTH2};
default:
return {CENTER, idx};
}
}
bool load(corners &out, const chunk_pos &chunkPos, const world::chunk_map &chunks) {
for (size_t i = 0; i < 8; i++) {
const auto it = chunks.find(chunkPos + g_corner_offsets[i]);
if (it == chunks.end())
bool load(corners &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks) {
{
const auto chunk = chunks.findInRange(chunkPos);
if(!chunk.has_value())
return false;
out[0] = chunk.value();
}
for (size_t i = 1; i < 8; i++) {
const auto chunk = chunks.findOrEmpty(chunkPos + g_corner_offsets[i]);
if (!chunk.has_value())
return false;
out[i] = it->second;
out[i] = chunk.value();
}
return true;
}
......
......@@ -10,7 +10,7 @@ namespace contouring::surrounding {
const auto CENTER = 6;
typedef std::array<std::shared_ptr<const world::Chunk>, CENTER+1> faces;
bool load(faces &out, const chunk_pos &chunkPos, const world::chunk_map &chunks);
bool load(faces &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks);
std::pair<ushort, ushort> getNeighborIdx(ushort idx, geometry::Face face);
......@@ -26,5 +26,5 @@ namespace contouring::surrounding {
chunk_pos(1, 1, 1),
};
bool load(corners &out, const chunk_pos &chunkPos, const world::chunk_map &chunks);
bool load(corners &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks);
}
......@@ -11,7 +11,7 @@ namespace geometry {
};
Box(glm::vec3 min, glm::vec3 max): Min(min), Max(max) {
assert(("Min > Max", max.x >= min.x && max.y >= min.y && max.z >= min.z));
assert((max.x >= min.x && max.y >= min.y && max.z >= min.z) && "Min > Max");
}
inline static Box fromCenter(glm::vec3 center, float radius) { return Box(center - radius, center + radius); }
inline static Box fromMin(glm::vec3 min, glm::vec3 size) { return Box(min, min + size); }
......
......@@ -7,4 +7,9 @@ namespace glm {
typedef vec<3, long> lvec3;
typedef vec<3, ushort> usvec3;
typedef vec<3, unsigned char> ucvec3;
const auto IDX_LENGTH = 32;
const auto IDX_LENGTH2 = IDX_LENGTH * IDX_LENGTH;
const auto IDX_SIZE = IDX_LENGTH2 * IDX_LENGTH;
using idx = glm::u16;
}
......@@ -20,16 +20,32 @@ namespace glm {
constexpr long inline div(long long value, uint m) {
return value < 0 ? ((value+1) / (long long)m) - 1 : value / (long long)m;
}
constexpr ucvec3 inline modulo(const llvec3& value, const ucvec3& m) {
constexpr ucvec3 inline modulo(const llvec3& value, const ucvec3& m = ucvec3(IDX_LENGTH)) {
<