Smooth sphere
This commit is contained in:
parent
3666fc2ed8
commit
53968b611a
|
@ -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)
|
||||
|
|
2
TODO.md
2
TODO.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue