1
0
Fork 0

Edit shape iterators

sphinx
May B. 2020-10-25 13:21:40 +01:00
parent ec467ca037
commit 3666fc2ed8
8 changed files with 131 additions and 116 deletions

15
TODO.md
View File

@ -25,10 +25,8 @@
- [ ] Local prediction
- [ ] Contouring service
- [~] Edit
- [ ] Shape iterators
- Cube
- Sphere
- [ ] More types
- [x] Shape iterators
- [ ] More shapes
- [ ] Anchor
- [x] Prevent suffocation
- [ ] Local prediction
@ -37,11 +35,14 @@
- [ ] Cast from chunk center
- [x] Transparency
- [~] Entities
- Get models
- [ ] Collide
- [ ] Get models
## Hello universe
- [ ] CI build
- CMake package
- GitLab / Drone pipeline
- [ ] Universe
- [ ] Galaxy
- [ ] Rotation
@ -57,7 +58,8 @@
- https://imgur.com/kM8b5Zq
- https://imgur.com/a/bh2iy
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
- Curvature
- [ ] Planet scale LOD
- [~] Curvature
- [~] CubeSphere
- [ ] Area corrected CubeSphere
- [ ] Corrected Normals
@ -68,6 +70,7 @@
## Hello industry
- [ ] Multiblock
- [ ] Inventory
## Hello darkness

View File

@ -1,27 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <vector>
/// Interger sphere fill
struct SphereIterator {
SphereIterator(const glm::ivec3 &center, int radius): center(center), radius(radius) { }
glm::ivec3 center;
int radius;
void vector(std::vector<glm::ivec3>& out) {
int top = center.y - radius, bottom = center.y + radius;
for (int y = top; y <= bottom; y++) {
int dy = y - center.y, dxz = floor(sqrt(radius * radius - dy * dy));
int minx = center.x - dxz, maxx = center.x + dxz;
int minz = center.z - dxz, maxz = center.z + dxz;
out.reserve(out.size() + dxz * dxz);
for (int z = minz; z <= maxz; z++) {
for (int x = minx; x <= maxx; x++) {
out.emplace_back(x, y, z);
}}
}
}
};

View File

@ -19,9 +19,10 @@ struct Fill: part::Ping {
const area_<voxel_pos> pos;
const Voxel val;
};
enum class Shape: uint8_t {
Cube,
Sphere,
RawSphere,
/*SmoothSphere,
CylinderX,
CylinderY,
@ -34,16 +35,16 @@ enum class Shape: uint8_t {
ConeNZ,
*/
};
constexpr auto SHAPES = "Cube\0RawSphere\0";
static _FORCE_INLINE_ geometry::Shape ToGeometry(Shape shape) {
switch (shape) {
case Shape::Sphere:
case Shape::RawSphere:
return geometry::Shape::Sphere;
default:
return geometry::Shape::Cube;
}
}
constexpr auto SHAPES = "Cube\0Sphere\0";
struct FillShape: Fill {
FillShape(const area_<voxel_pos> &pos, const Voxel &val, Shape shape, uint8_t radius):
Fill(pos, val), shape(shape), radius(radius) {}

View File

@ -0,0 +1,59 @@
#include "iterators.hpp"
using namespace world::iterator;
std::unique_ptr<Abstract> world::iterator::Get(world::action::Shape shape, uint16_t radius) {
switch (shape) {
case world::action::Shape::Cube:
return std::make_unique<Cube>(radius);
case world::action::Shape::RawSphere:
return std::make_unique<RawSphere>(radius);
default:
return std::unique_ptr<Abstract>(nullptr);
}
}
bool Cube::next(pair& out) {
if (pos.z > radius)
return false;
out.first = pos;
out.second = 1;
// MAYBE: use linear idx to make branch less
if (pos.x < radius) {
pos.x++;
} else {
pos.x = -radius;
if (pos.y < radius) {
pos.y++;
} else {
pos.y = -radius;
pos.z++;
}
}
return true;
}
bool RawSphere::next(pair& out) {
if (pos.x > radius)
return false;
out.first = pos;
out.second = 1;
if (pos.z < dz) {
pos.z++;
} else {
if (pos.y < dy) {
pos.y++;
} else {
pos.x++;
dy = floor(sqrt(radius * radius - pos.x * pos.x));
pos.y = -dy;
}
dz = floor(sqrt(dy * dy - pos.y * pos.y));
pos.z = -dz;
}
return true;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "position.h"
#include "actions.hpp"
namespace world::iterator {
using pair = std::pair<glm::ivec3, float>;
class Abstract {
public:
virtual bool next(pair&) = 0;
protected:
static constexpr uint32_t Diam(uint16_t radius) { return radius * 2 + 1; }
};
/// From -radius to radius
std::unique_ptr<Abstract> Get(action::Shape, uint16_t radius);
class Cube final: public Abstract {
public:
bool next(pair&) override;
Cube(uint16_t radius): radius(radius), pos(-radius, -radius, -radius) { }
private:
const uint16_t radius;
glm::ivec3 pos;
};
/// Interger sphere
class RawSphere final: public Abstract {
public:
bool next(pair&) override;
RawSphere(uint16_t radius): radius(radius), pos(-radius, 0, 0), dy(0), dz(0) { }
private:
const uint16_t radius;
glm::ivec3 pos;
int dy;
int dz;
};
}

View File

@ -16,10 +16,7 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl
localHandle->emit = std::function([&](const world::action::packet &packet) {
if(const auto fill = std::get_if<world::action::FillShape>(&packet)) {
//NOTE: LocalUniverse had already check for entities
if (fill->shape == world::action::Shape::Cube)
this->setCube(fill->pos, fill->val, fill->radius);
else
this->setSphere(fill->pos, fill->val, fill->radius);
this->set(fill->pos, fill->radius, fill->shape, fill->val);
} else if(const auto message = std::get_if<world::action::Message>(&packet)) {
this->broadcastMessage("Player" + std::to_string(id.index) + ": " + message->text);
} else if(const auto move = std::get_if<world::action::Move>(&packet)) {

View File

@ -7,6 +7,7 @@
#include "Chunk.hpp"
#include "../../core/world/raycast.hpp"
#include "../../core/world/iterators.hpp"
#include "../../core/world/actions.hpp"
#include "../../core/net/PacketView.hpp"
@ -458,11 +459,8 @@ void Universe::pullNetwork() {
LOG_T("Entity in solid fill area");
break;
}
set(fill->pos, fill->radius, fill->shape, fill->val);
//TODO: handle inventory
if (fill->shape == world::action::Shape::Cube)
setCube(fill->pos, fill->val, fill->radius);
else
setSphere(fill->pos, fill->val, fill->radius);
} else {
LOG_T("Bad fill");
}
@ -557,30 +555,20 @@ bool Universe::isAreaFree(const area_<voxel_pos> &pos, const geometry::Shape sha
return false;
}
std::optional<world::Item> Universe::set(const area_<voxel_pos>& pos, const Voxel& val) {
if(const auto it = areas.find(pos.first); it != areas.end()) {
auto &chunks = it->second->setChunks();
const auto split = glm::splitIdx(pos.second);
if(chunks.inRange(split.first))
if(const auto chunk = chunks.findInRange(split.first))
return {std::dynamic_pointer_cast<Chunk>(chunk.value())->replace(split.second, val)};
}
return {};
}
world::ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val, int radius) {
world::ItemList Universe::set(const area_<voxel_pos>& pos, int radius, action::Shape shape, const Voxel& val) {
ZoneScopedN("Fill");
ItemList list;
if(const auto it = areas.find(pos.first); it != areas.end()) {
robin_hood::unordered_map<chunk_pos, std::vector<Chunk::Edit>> edits;
auto &chunks = it->second->setChunks();
for (int z = -radius; z <= radius; z++) {
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
//TODO: list.pop(val)
const auto offset = voxel_pos(x, y, z);
auto iterator = world::iterator::Get(shape, radius);
world::iterator::pair point;
while (iterator->next(point)) {
const voxel_pos offset = point.first;
const auto split = glm::splitIdx(pos.second + offset);
if(chunks.inRange(split.first))
if(chunks.inRange(split.first)) {
if(const auto chunk = it->second->setChunks().findInRange(split.first)) {
//TODO: use ratio in point.second
auto ck = std::dynamic_pointer_cast<Chunk>(chunk.value());
auto prev = ck->get(split.second);
if(prev.value != val.value) {
@ -591,56 +579,9 @@ world::ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val,
ck->replace(split.second, val, delay);
}
}
}}}
ZoneScopedN("Packet");
size_t size = sizeof(area_id);
for(const auto& part: edits) {
size += sizeof(chunk_pos);
size += sizeof(chunk_voxel_idx);
size += sizeof(Chunk::Edit) * part.second.size();
}
auto packet = net::Server::makePacket(net::server_packet_type::EDITS, NULL, size, 0);
packet.write(pos.first);
for(const auto& part: edits) {
packet.write(part.first);
packet.write<chunk_voxel_idx>(part.second.size());
packet.write(part.second.data(), part.second.size() * sizeof(Chunk::Edit));
}
}
assert(packet.isFull());
host.broadcast(packet.get(), net::channel_type::NOTIFY);
}
return list;
}
world::ItemList Universe::setSphere(const area_<voxel_pos>& pos, const Voxel& val, int radius) {
ZoneScopedN("FillSphere");
ItemList list;
if(const auto it = areas.find(pos.first); it != areas.end()) {
robin_hood::unordered_map<chunk_pos, std::vector<Chunk::Edit>> edits;
auto &chunks = it->second->setChunks();
for (int z = -radius; z <= radius; z++) {
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
const auto offset = voxel_pos(x, y, z);
//FIXME: refactor with voxel_pos iterator
if (glm::length2(offset) > glm::pow2(radius))
continue;
//TODO: list.pop(val)
const auto split = glm::splitIdx(pos.second + offset);
if(chunks.inRange(split.first))
if(const auto chunk = it->second->setChunks().findInRange(split.first)) {
auto ck = std::dynamic_pointer_cast<Chunk>(chunk.value());
auto prev = ck->get(split.second);
if(prev.value != val.value) {
//TODO: apply break table
//TODO: inventory
const auto delay = glm::length2(offset) / radius * .05f;
edits[split.first].push_back(Chunk::Edit{split.second, val, delay});
ck->replace(split.second, val, delay);
}
}
}}}
ZoneScopedN("Packet");
size_t size = sizeof(area_id);
for(const auto& part: edits) {

View File

@ -3,6 +3,7 @@
#include <string>
#include <thread>
#include "../../core/world/Universe.hpp"
#include "../../core/world/actions.hpp"
#include "../../core/data/math.hpp"
#include "../../core/data/safe_queue.hpp"
#include "../../core/data/safe_priority_queue.hpp"
@ -39,14 +40,9 @@ namespace world::server {
/// Apply new options
void setOptions(const options &);
/// Set voxel at pos
std::optional<Item> set(const area_<voxel_pos> &pos, const Voxel &val);
/// Set cube of voxel with pos as center
/// Set volume of voxel with pos as center
/// MAYBE: allow set multi area
ItemList setCube(const area_<voxel_pos> &pos, const Voxel &val, int radius);
/// Set sphere of voxel with pos as center
/// MAYBE: allow set multi area
ItemList setSphere(const area_<voxel_pos> &pos, const Voxel &val, int radius);
ItemList set(const area_<voxel_pos> &pos, int radius, action::Shape shape, const Voxel &val);
/// Instante entity
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);