1
0
Fork 0

Smooth sphere

This commit is contained in:
May B. 2020-10-25 15:50:12 +01:00
parent 3666fc2ed8
commit 53968b611a
7 changed files with 99 additions and 22 deletions

View File

@ -78,7 +78,7 @@ To get a local copy up and running, follow these simple steps.
1. Clone the project repo
```sh
git lfs clone --recursive https://git.wadza.fr/me/univerxel.git
git lfs clone --recursive https://framagit.org/univerxel/univerxel.git
```
2. Create build folder and move
```sh
@ -147,5 +147,4 @@ Distributed under the MIT License. See [LICENSE](LICENSE) for more information.
Shu - [/me](https://git.wadza.fr/me) - me@wadza.fr
Public releases: [https://framagit.org/univerxel/univerxel](https://framagit.org/univerxel/univerxel)
Working repo: [https://git.wadza.fr/me/univerxel](https://git.wadza.fr/me/univerxel)
[Public releases](https://framagit.org/univerxel/univerxel) - [Working repo](https://git.wadza.fr/me/univerxel)

View File

@ -26,7 +26,6 @@
- [ ] Contouring service
- [~] Edit
- [x] Shape iterators
- [ ] More shapes
- [ ] Anchor
- [x] Prevent suffocation
- [ ] Local prediction
@ -37,6 +36,7 @@
- [~] Entities
- [ ] Collide
- [ ] Get models
- [ ] Review documentation
## Hello universe

View File

@ -227,7 +227,19 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
ImGui::EndCombo();
}
ImGui::SliderInt("Radius", &options.editor.tool.radius, 0, 10);
ImGui::Combo("Shape", (int*)&options.editor.tool.shape, world::action::SHAPES);
const auto shapeId = (size_t)options.editor.tool.shape;
if (ImGui::BeginCombo("Shape", world::action::SHAPES[shapeId].c_str())) {
for (size_t i = 0; i < world::action::SHAPES.size(); i++) {
const bool is_selected = (shapeId == i);
if (ImGui::Selectable(world::action::SHAPES[i].c_str(), is_selected))
options.editor.tool.shape = (world::action::Shape)i;
if (is_selected)
ImGui::SetItemDefaultFocus();
if (i == (size_t)world::action::Shape::SmoothSphere && ImGui::IsItemHovered())
ImGui::SetTooltip("Asymmetrical with small radius");
}
ImGui::EndCombo();
}
ImGui::Checkbox("Empty air", &options.editor.tool.emptyAir);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Is cleaned area breathable");

View File

@ -23,8 +23,8 @@ struct Fill: part::Ping {
enum class Shape: uint8_t {
Cube,
RawSphere,
/*SmoothSphere,
CylinderX,
SmoothSphere,
/*CylinderX,
CylinderY,
CylinderZ,
ConePX,
@ -35,11 +35,13 @@ enum class Shape: uint8_t {
ConeNZ,
*/
};
constexpr auto SHAPES = "Cube\0RawSphere\0";
static const std::array<std::string, 3> SHAPES = {"Cube", "Raw Sphere", "Smooth Sphere"};
static _FORCE_INLINE_ geometry::Shape ToGeometry(Shape shape) {
switch (shape) {
case Shape::RawSphere:
return geometry::Shape::Sphere;
case Shape::SmoothSphere:
return geometry::Shape::Sphere;
default:
return geometry::Shape::Cube;
}

View File

@ -8,6 +8,8 @@ std::unique_ptr<Abstract> world::iterator::Get(world::action::Shape shape, uint1
return std::make_unique<Cube>(radius);
case world::action::Shape::RawSphere:
return std::make_unique<RawSphere>(radius);
case world::action::Shape::SmoothSphere:
return std::make_unique<SmoothSphere>(radius);
default:
return std::unique_ptr<Abstract>(nullptr);
}
@ -36,11 +38,10 @@ bool Cube::next(pair& out) {
}
bool RawSphere::next(pair& out) {
if (pos.x > radius)
return false;
out.first = pos;
out.second = 1;
const auto delta = [](int radius, int pos) -> int {
const auto rad = radius + .5;
return floor(sqrt(rad * rad - pos * pos));
};
if (pos.z < dz) {
pos.z++;
@ -48,12 +49,49 @@ bool RawSphere::next(pair& out) {
if (pos.y < dy) {
pos.y++;
} else {
pos.x++;
dy = floor(sqrt(radius * radius - pos.x * pos.x));
pos.y = -dy;
if (pos.x < radius) {
pos.x++;
dy = delta(radius, pos.x);
pos.y = -dy;
} else {
return false;
}
}
dz = floor(sqrt(dy * dy - pos.y * pos.y));
dz = delta(dy, pos.y);
pos.z = -dz;
}
out.first = pos;
out.second = 1;
return true;
}
bool SmoothSphere::next(pair& out) {
const auto delta = [](double radius, int pos) {
return sqrt(radius * radius - pos * pos);
};
if (pos.z < dz) {
const int idz = floor(dz);
out.second = pos.z < idz ? 1 : dz - idz;
pos.z++;
} else {
if (pos.y < dy) {
pos.y++;
} else {
if (pos.x < radius) {
pos.x++;
dy = delta(radius, pos.x);
pos.y = -ceil(dy);
} else {
return false;
}
}
dz = delta(dy, pos.y);
out.second = dz - floor(dz);
pos.z = -ceil(dz);
}
out.first = pos;
return true;
}

View File

@ -34,7 +34,7 @@ class RawSphere final: public Abstract {
public:
bool next(pair&) override;
RawSphere(uint16_t radius): radius(radius), pos(-radius, 0, 0), dy(0), dz(0) { }
RawSphere(uint16_t radius): radius(radius), pos(-radius-1, 0, 0), dy(0), dz(0) { }
private:
const uint16_t radius;
@ -42,4 +42,18 @@ private:
int dy;
int dz;
};
/// Anti-aliased sphere
class SmoothSphere final: public Abstract {
public:
bool next(pair&) override;
SmoothSphere(uint16_t radius): radius(radius), pos(-radius-1, 0, 0), dy(0), dz(0) { }
private:
const uint16_t radius;
glm::ivec3 pos;
double dy;
double dz;
};
}

View File

@ -568,15 +568,27 @@ world::ItemList Universe::set(const area_<voxel_pos>& pos, int radius, action::S
const auto split = glm::splitIdx(pos.second + offset);
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) {
const auto next = [&] {
if (point.second == 1)
return val;
const world::Voxel::density_t density = val.density() * point.second;
if (!val.is_material())
return world::Voxel(prev.material(), world::Voxel::DENSITY_MAX-density);
if (prev.is_material() && prev.density() > density)
return prev;
return world::Voxel(val.material(), density);
}();
if(prev.value != next.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);
edits[split.first].push_back(Chunk::Edit{split.second, next, delay});
ck->replace(split.second, next, delay);
}
}
}