Commit 01f62985 authored by TheNumbat's avatar TheNumbat
Browse files

upstream changes

parent 750af030
......@@ -35,6 +35,9 @@ void Halfedge_Mesh::copy_to(Halfedge_Mesh &mesh) { copy_to(mesh, 0); }
Halfedge_Mesh::ElementRef Halfedge_Mesh::copy_to(Halfedge_Mesh &mesh, unsigned int eid) {
// Erase erase lists
do_erase();
// Clear any existing elements.
mesh.clear();
ElementRef ret = vertices_begin();
......@@ -329,89 +332,156 @@ void Halfedge_Mesh::to_mesh(GL::Mesh &mesh, bool split_faces) const {
void Halfedge_Mesh::mark_dirty() { render_dirty_flag = true; }
std::string Halfedge_Mesh::validate() const {
std::string Halfedge_Mesh::validate() {
if (!check_finite())
return "A vertex position was set to a non-finite value.";
std::set<HalfedgeCRef> permutation;
std::set<HalfedgeRef> permutation;
// Check valid halfedge permutation
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
for (HalfedgeRef h = halfedges_begin(); h != halfedges_end(); h++) {
if (herased.find(h) != herased.end()) continue;
if (herased.find(h->next()) != herased.end()) {
return "A halfedge's next is erased!";
}
if (herased.find(h->twin()) != herased.end()) {
return "A halfedge's twin is erased!";
}
if (verased.find(h->vertex()) != verased.end()) {
return "A halfedge's vertex is erased!";
}
if (ferased.find(h->face()) != ferased.end()) {
return "A halfedge's face is erased!";
}
if (eerased.find(h->edge()) != eerased.end()) {
return "A halfedge's edge is erased!";
}
// Check whether each halfedge's next points to a unique halfedge
if (permutation.find(h->next()) == permutation.end()) {
permutation.insert(h->next());
} else {
return "A halfedge is the next of more than one halfedge!";
return "A halfedge is the next of multiple halfedge!";
}
}
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
for (HalfedgeRef h = halfedges_begin(); h != halfedges_end(); h++) {
if (herased.find(h) != herased.end()) continue;
// Check whether each halfedge was pointed to by a halfedge
if (permutation.find(h) == permutation.end()) {
return "A halfedge is the next of zero halfedges!";
}
}
// Check twin relationships
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
if (h->twin() == h) {
return "A halfedge's twin points to itself!";
return "A halfedge's twin is itself!";
}
if (h->twin()->twin() != h) {
return "A halfedge's twin's twin does not point to itself!";
return "A halfedge's twin's twin is not itself!";
}
}
// Check whether each halfedge incident on a vertex points to that vertex
for (VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
HalfedgeCRef h = v->halfedge();
for (VertexRef v = vertices_begin(); v != vertices_end(); v++) {
if (verased.find(v) != verased.end()) continue;
HalfedgeRef h = v->halfedge();
if (herased.find(h) != herased.end()) {
return "A vertex's halfedge is erased!";
}
do {
if (h->vertex() != v) {
return "A halfedge does not point to its vertex!";
return "A vertex's halfedge does not point to that vertex!";
}
h = h->twin()->next();
} while (h != v->halfedge());
}
// Check whether each halfedge incident on an edge points to that edge
for (EdgeCRef e = edges_begin(); e != edges_end(); e++) {
HalfedgeCRef h = e->halfedge();
for (EdgeRef e = edges_begin(); e != edges_end(); e++) {
if (eerased.find(e) != eerased.end()) continue;
HalfedgeRef h = e->halfedge();
if (herased.find(h) != herased.end()) {
return "An edge's halfedge is erased!";
}
do {
if (h->edge() != e) {
return "A halfedge does not point to its edge!";
return "An edge's halfedge does not point to that edge!";
}
h = h->twin();
} while (h != e->halfedge());
}
// Check whether each halfedge incident on a face points to that face
for (FaceCRef f = faces_begin(); f != faces_end(); f++) {
HalfedgeCRef h = f->halfedge();
for (FaceRef f = faces_begin(); f != faces_end(); f++) {
if (ferased.find(f) != ferased.end()) continue;
HalfedgeRef h = f->halfedge();
if(herased.find(h) != herased.end()) {
return "A face's halfedge is erased!";
}
do {
if (h->face() != f) {
return "A halfedge does not point to its face!";
return "A face's halfedge does not point to that face!";
}
h = h->next();
} while (h != f->halfedge());
}
// Check whether each halfedge incident on a boundary loop points to that boundary loop
for (FaceCRef b = boundaries_begin(); b != boundaries_end(); b++) {
HalfedgeCRef h = b->halfedge();
for (FaceRef b = boundaries_begin(); b != boundaries_end(); b++) {
if (ferased.find(b) != ferased.end()) continue;
HalfedgeRef h = b->halfedge();
if (herased.find(h) != herased.end()) {
return "A boundary's halfedge is erased!";
}
do {
if (h->face() != b) {
return "A halfedge does not point to its boundary loop!";
return "A boundary halfedge does not point to its boundary loop!";
}
h = h->next();
} while (h != b->halfedge());
}
do_erase();
return {};
}
void Halfedge_Mesh::do_erase() {
for (auto& v : verased) {
vertices.erase(v);
}
for (auto& e : eerased) {
edges.erase(e);
}
for (auto& f : ferased) {
if(f->is_boundary()) boundaries.erase(f);
else faces.erase(f);
}
for (auto& h : herased) {
halfedges.erase(h);
}
verased.clear();
eerased.clear();
ferased.clear();
herased.clear();
}
std::string Halfedge_Mesh::from_mesh(const GL::Mesh &mesh) {
auto idx = mesh.indices();
......
......@@ -132,6 +132,7 @@
#include <list>
#include <optional>
#include <string>
#include <set>
#include <variant>
#include <vector>
......@@ -447,12 +448,14 @@ public:
iterating over a linked list, and want to delete some of the elements as you go. How do you
do this without causing any problems? For instance, if you delete the current element, will
you be able to iterate to the next element? Etc.
Note: the elements are not actually deleted until validate() is called in order to facilitate
checking for dangling references.
*/
void erase(HalfedgeRef h) { halfedges.erase(h); }
void erase(VertexRef v) { vertices.erase(v); }
void erase(EdgeRef e) { edges.erase(e); }
void erase(FaceRef f) { faces.erase(f); }
void erase_boundary(FaceRef f) { boundaries.erase(f); }
void erase(VertexRef v) { verased.insert(v); }
void erase(EdgeRef e) { eerased.insert(e); }
void erase(FaceRef f) { ferased.insert(f); }
void erase(HalfedgeRef h) { herased.insert(h); }
/*
These methods allocate new mesh elements, returning a pointer (i.e., iterator) to the
......@@ -512,7 +515,7 @@ public:
Size n_halfedges() const { return halfedges.size(); };
/// Check if half-edge mesh is valid
std::string validate() const;
std::string validate();
//////////////////////////////////////////////////////////////////////////////////////////
// End methods students should use, begin internal methods - you don't need to use these
......@@ -545,11 +548,14 @@ public:
/// vertices)
std::string from_mesh(const GL::Mesh &mesh);
/// For rendering
bool render_dirty_flag = false;
/// WARNING: erased elements stay in the element lists until do_erase()
/// or validate() are called
void do_erase();
void mark_dirty();
bool flipped() const { return flip_orientation; }
void flip() { flip_orientation = !flip_orientation; };
bool render_dirty_flag = false;
Vec3 normal_of(ElementRef elem);
static Vec3 center_of(ElementRef elem);
......@@ -560,9 +566,15 @@ private:
std::list<Edge> edges;
std::list<Face> faces, boundaries;
std::list<Halfedge> halfedges;
bool check_finite() const;
unsigned int next_id;
bool flip_orientation = false;
bool check_finite() const;
std::set<VertexRef> verased;
std::set<EdgeRef> eerased;
std::set<FaceRef> ferased;
std::set<HalfedgeRef> herased;
};
/*
......
......@@ -53,7 +53,9 @@ bool Manager::keydown(Undo &undo, SDL_Keysym key, Scene &scene, Camera &cam) {
Uint16 mod = KMOD_CTRL;
if (key.sym == SDLK_DELETE && layout.selected()) {
#endif
if (mode != Mode::model && mode != Mode::rig && mode != Mode::animate) {
if (mode == Mode::model) {
model.erase_selected(undo, scene.get(layout.selected()));
} else if (mode != Mode::rig && mode != Mode::animate) {
undo.del_obj(layout.selected());
return true;
}
......@@ -90,7 +92,7 @@ bool Manager::keydown(Undo &undo, SDL_Keysym key, Scene &scene, Camera &cam) {
if (mode == Mode::rig) {
cam.look_at(Vec3{}, -cam.front() * cam.dist());
return true;
} else if (layout.selected()) {
} else if (mode != Mode::model && layout.selected()) {
frame(scene, cam);
return true;
}
......@@ -463,10 +465,9 @@ void Manager::UIsidebar(Scene &scene, Undo &undo, float menu_height, Camera &cam
new_light_focus = true;
}
}
if (!scene.empty()) {
ImGui::Separator();
ImGui::Text("Select an Object");
}
scene.for_items([&](Scene_Item &obj) {
if ((mode == Mode::model || mode == Mode::rig) &&
......
......@@ -572,30 +572,39 @@ void Model::zoom_to(Halfedge_Mesh::ElementRef ref, Camera &cam) {
cam.look_at(center, pos);
}
std::string Model::UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj_opt, Camera &camera) {
if(ImGui::CollapsingHeader("Edit Colors")) {
ImGui::ColorEdit3("Face", f_col.data);
ImGui::ColorEdit3("Vertex", v_col.data);
ImGui::ColorEdit3("Edge", e_col.data);
ImGui::ColorEdit3("Halfedge", he_col.data);
}
ImGui::Separator();
std::optional<std::reference_wrapper<Scene_Object>> Model::is_my_obj(Scene_Maybe obj_opt) {
if (!obj_opt.has_value())
return {};
return std::nullopt;
Scene_Item &item = obj_opt.value();
if (!item.is<Scene_Object>())
return {};
return std::nullopt;
Scene_Object &obj = item.get<Scene_Object>();
if (obj.opt.shape_type != PT::Shape_Type::none)
return {};
return std::nullopt;
if (!my_mesh || !obj.is_editable())
return {};
return std::nullopt;
assert(my_mesh == &obj.get_mesh());
return obj;
}
std::string Model::UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj_opt, Camera &camera) {
if(ImGui::CollapsingHeader("Edit Colors")) {
ImGui::ColorEdit3("Face", f_col.data);
ImGui::ColorEdit3("Vertex", v_col.data);
ImGui::ColorEdit3("Edge", e_col.data);
ImGui::ColorEdit3("Halfedge", he_col.data);
}
ImGui::Separator();
auto opt = is_my_obj(obj_opt);
if(!opt.has_value()) return {};
Scene_Object& obj = opt.value();
Halfedge_Mesh &mesh = *my_mesh;
Halfedge_Mesh before;
......@@ -648,7 +657,7 @@ std::string Model::UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj_opt,
std::string err = std::visit(
overloaded{
[&](Halfedge_Mesh::VertexRef vert) -> std::string {
if (ImGui::Button("Erase")) {
if (ImGui::Button("Erase [del]")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), vert,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef vert) {
......@@ -659,7 +668,7 @@ std::string Model::UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj_opt,
return {};
},
[&](Halfedge_Mesh::EdgeRef edge) -> std::string {
if (ImGui::Button("Erase")) {
if (ImGui::Button("Erase [del]")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), edge,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef edge) {
......@@ -754,6 +763,40 @@ std::string Model::UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj_opt,
return {};
}
void Model::erase_selected(Undo& undo, Scene_Maybe obj_opt) {
auto opt = is_my_obj(obj_opt);
if(!opt.has_value()) return;
Scene_Object& obj = opt.value();
auto sel_ = selected_element();
if(!sel_.has_value()) return;
Halfedge_Mesh::ElementRef sel = sel_.value();
Halfedge_Mesh &mesh = *my_mesh;
Halfedge_Mesh before;
mesh.copy_to(before);
std::visit(overloaded{
[&](Halfedge_Mesh::VertexRef vert) {
return update_mesh(undo, obj, std::move(before), vert,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef vert) {
return m.erase_vertex(
std::get<Halfedge_Mesh::VertexRef>(vert));
});
},
[&](Halfedge_Mesh::EdgeRef edge) {
return update_mesh(undo, obj, std::move(before), edge,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef edge) {
return m.erase_edge(
std::get<Halfedge_Mesh::EdgeRef>(edge));
});
},
[](auto) { return std::string{}; }
}, sel);
}
void Model::clear_select() { selected_elem_id = 0; }
void Model::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam) {
......
......@@ -27,6 +27,7 @@ public:
Vec3 selected_pos();
void clear_select();
void erase_selected(Undo& undo, Scene_Maybe obj_opt);
std::string end_transform(Widgets &widgets, Undo &undo, Scene_Object &obj);
void apply_transform(Widgets &widgets);
std::string select(Widgets &widgets, Scene_ID click, Vec3 cam, Vec2 spos, Vec3 dir);
......@@ -48,6 +49,7 @@ private:
void begin_transform();
bool begin_bevel(std::string &err);
void set_selected(Halfedge_Mesh::ElementRef elem);
std::optional<std::reference_wrapper<Scene_Object>> is_my_obj(Scene_Maybe obj_opt);
std::optional<Halfedge_Mesh::ElementRef> selected_element();
void rebuild();
......
......@@ -22,7 +22,8 @@ public:
virtual ~Action_Base() = default;
};
template <typename T> class MeshOp : public Action_Base {
template <typename T>
class MeshOp : public Action_Base {
void undo() {
Scene_Object &obj = scene.get_obj(id);
obj.set_mesh(mesh);
......@@ -31,6 +32,7 @@ template <typename T> class MeshOp : public Action_Base {
Scene_Object &obj = scene.get_obj(id);
auto sel = obj.set_mesh(mesh, eid);
op(obj.get_mesh(), sel);
obj.get_mesh().do_erase();
}
Scene &scene;
Scene_ID id;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment