160 lines
6.1 KiB
C++
160 lines
6.1 KiB
C++
#include "FlatDualMC.hpp"
|
|
|
|
#include "../world/Chunk.hpp"
|
|
#include "../world/materials.hpp"
|
|
#include <Remotery.h>
|
|
#include <imgui.h>
|
|
#include "dualmc.h"
|
|
|
|
namespace contouring {
|
|
FlatDualMC::FlatDualMC(const std::string &str) : AbstractFlat(str) {
|
|
auto opt = toml::parse(str);
|
|
iso = opt["iso"].value_or(iso);
|
|
manifold = opt["manifold"].value_or(manifold);
|
|
|
|
for (size_t i = 1; i <= 2; i++) {
|
|
workers.push_back(std::thread([&] {
|
|
while (running) {
|
|
std::pair<chunk_pos, surrounding::corners> ctx;
|
|
loadQueue.wait();
|
|
if (loadQueue.pop(ctx)) {
|
|
rmt_ScopedCPUSample(ProcessContouring, 0);
|
|
buffer::ShortIndexed::Data data;
|
|
render(ctx.second, data);
|
|
loadedQueue.push({ctx.first, data});
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
FlatDualMC::~FlatDualMC() {
|
|
running = false;
|
|
loadQueue.notify();
|
|
|
|
for(auto& worker: workers) {
|
|
if (worker.joinable())
|
|
worker.join();
|
|
}
|
|
}
|
|
|
|
std::string FlatDualMC::getOptions() {
|
|
std::ostringstream ss;
|
|
ss << toml::table({
|
|
{"load_distance", loadDistance},
|
|
{"keep_distance", keepDistance},
|
|
{"iso", iso},
|
|
{"manifold", manifold}
|
|
});
|
|
return ss.str();
|
|
}
|
|
|
|
void FlatDualMC::enqueue(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) {
|
|
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
|
|
const auto dist2 = glm::length2(pos - center);
|
|
if (dist2 <= loadDistance * loadDistance) {
|
|
surrounding::corners surrounding;
|
|
if(surrounding::load(surrounding, pos, data)) {
|
|
loadQueue.push(pos, surrounding, -dist2);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FlatDualMC::onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &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);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FlatDualMC::onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) {
|
|
if (buffers.find(pos) == buffers.end()) {
|
|
enqueue(pos, data);
|
|
}
|
|
}
|
|
|
|
void FlatDualMC::update(const camera_pos& pos) {
|
|
AbstractFlat::update(pos);
|
|
std::pair<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()) {
|
|
if(it->second != NULL)
|
|
delete it->second;
|
|
|
|
it->second = buffer;
|
|
} else {
|
|
buffers.emplace(out.first, buffer);
|
|
}
|
|
}
|
|
reports.count.push(buffers.size());
|
|
}
|
|
|
|
void FlatDualMC::onGui() {
|
|
ImGui::PlotHistogram("Count", reports.count.buffer.get(), reports.count.size, 0, std::to_string(reports.count.current()).c_str(), 0);
|
|
ImGui::PlotHistogram("Loading", reports.load.buffer.get(), reports.load.size, 0, std::to_string(reports.load.current()).c_str(), 0);
|
|
ImGui::PlotHistogram("Waiting", reports.loaded.buffer.get(), reports.loaded.size, 0, std::to_string(reports.loaded.current()).c_str(), 0);
|
|
ImGui::Separator();
|
|
AbstractFlat::onGui();
|
|
ImGui::Separator();
|
|
ImGui::SliderFloat("Iso", &iso, 0, 1);
|
|
ImGui::Checkbox("Manifold", &manifold);
|
|
}
|
|
|
|
void FlatDualMC::render(const surrounding::corners &surrounding, buffer::ShortIndexed::Data &out) const {
|
|
const int SIZE = CHUNK_LENGTH + 3;
|
|
std::vector<dualmc::DualMC<float>::Point> grid;
|
|
grid.reserve(SIZE * SIZE * SIZE);
|
|
{
|
|
for (int z = 0; z < SIZE; z++) {
|
|
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];
|
|
// MAYBE: area copy
|
|
const auto voxel = chunk->getAt(chunk_voxel_pos(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
|
|
grid.push_back({voxel.Density * 1.f / UCHAR_MAX, voxel.Material});
|
|
}}}
|
|
}
|
|
{
|
|
std::vector<dualmc::Vertex> dmc_vertices;
|
|
std::vector<dualmc::Tri> dmc_tris;
|
|
|
|
dualmc::DualMC<float> builder;
|
|
builder.buildTris(&grid.front(), SIZE, SIZE, SIZE, iso, world::materials::roughness.cbegin(), manifold, dmc_vertices, dmc_tris);
|
|
|
|
out.vertices.reserve(dmc_vertices.size());
|
|
out.materials.reserve(dmc_vertices.size());
|
|
out.normals.reserve(dmc_vertices.size());
|
|
for (const auto& v: dmc_vertices) {
|
|
out.vertices.push_back(glm::vec3(v.x, v.y, v.z));
|
|
out.materials.push_back(v.w);
|
|
out.normals.push_back(glm::vec3(0));
|
|
}
|
|
|
|
out.indices.reserve(dmc_tris.size());
|
|
for (const auto& t: dmc_tris) {
|
|
out.indices.push_back(t.i0);
|
|
out.indices.push_back(t.i1);
|
|
out.indices.push_back(t.i2);
|
|
|
|
glm::vec3 edge1 = out.vertices[t.i1] - out.vertices[t.i0];
|
|
glm::vec3 edge2 = out.vertices[t.i2] - out.vertices[t.i0];
|
|
glm::vec3 normal = glm::normalize(glm::cross(edge1, edge2));
|
|
|
|
out.normals[t.i0] += normal;
|
|
out.normals[t.i1] += normal;
|
|
out.normals[t.i2] += normal;
|
|
}
|
|
|
|
for (auto &n : out.normals) {
|
|
n = glm::normalize(n);
|
|
}
|
|
}
|
|
}
|
|
}
|