diff --git a/src/CanvasComponents/BrushComponentCode.cpp b/src/CanvasComponents/BrushComponentCode.cpp index ca4057c..eb9dcc3 100644 --- a/src/CanvasComponents/BrushComponentCode.cpp +++ b/src/CanvasComponents/BrushComponentCode.cpp @@ -34,7 +34,7 @@ namespace BrushComponentCode { void skpath_to_clipper2_pathsd(Clipper2Lib::PathsD& clipperPath, const SkPath& skPath) { - SkPath::Iter iter(skPath, false); + SkPath::Iter iter(skPath, true); for(;;) { std::optional rec = iter.next(); diff --git a/src/CanvasComponents/MeshCanvasComponent.cpp b/src/CanvasComponents/MeshCanvasComponent.cpp index 31b95dc..1a82aa5 100644 --- a/src/CanvasComponents/MeshCanvasComponent.cpp +++ b/src/CanvasComponents/MeshCanvasComponent.cpp @@ -150,35 +150,73 @@ std::shared_ptr MeshCanvasComponent::get_predraw_data_accurate(const DrawD viewGenerousColliderInObjSpace.min -= Vector2f{1.0f, 1.0f}; viewGenerousColliderInObjSpace.max += Vector2f{1.0f, 1.0f}; + SkPath::Iter iter(d.meshPath, true); + std::vector> points; + std::vector edges; + + for(;;) { + std::optional rec = iter.next(); + if(!rec.has_value()) + break; + + switch(rec->fVerb) { + case SkPathVerb::kClose: + break; + case SkPathVerb::kLine: + points.emplace_back(rec->fPoints[1].x(), rec->fPoints[1].y()); + edges.emplace_back(points.size() - 2, points.size() - 1); + break; + case SkPathVerb::kMove: + points.emplace_back(rec->fPoints[0].x(), rec->fPoints[0].y()); + break; + default: + throw std::runtime_error("[get_predraw_data_accurate] Illegal verb " + std::to_string(static_cast(rec->fVerb))); + break; + } + } + + CDT::RemoveDuplicatesAndRemapEdges( + points, + edges + ); + + CDT::Triangulation cdt(CDT::VertexInsertionOrder::Auto, CDT::IntersectingConstraintEdges::TryResolve, 0.001f); + cdt.insertVertices(points); + cdt.insertEdges(edges); + cdt.eraseOuterTrianglesAndHoles(); + std::vector> finalTrianglePoints; - collisionTree.is_collide_triangle_bounds_func(viewGenerousColliderInObjSpace, [&](const SCollision::Triangle& triCollider) { - auto clipListFunc = [](const std::vector>& clipList, const std::array& axisLineSegment, const std::function& isInClippingAreaFunc) { - std::vector> resultList; - for(auto& t : clipList) - clip_triangle_against_axis(resultList, t, axisLineSegment, isInClippingAreaFunc); - return resultList; - }; + auto clipListFunc = [](const std::vector>& clipList, const std::array& axisLineSegment, const std::function& isInClippingAreaFunc) { + std::vector> resultList; + for(auto& t : clipList) + clip_triangle_against_axis(resultList, t, axisLineSegment, isInClippingAreaFunc); + return resultList; + }; - std::vector> clipList; - clipList.emplace_back(std::array{coords.from_space(triCollider.p[0]), coords.from_space(triCollider.p[1]), coords.from_space(triCollider.p[2])}); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { - return p.y() > drawData.cam.viewingAreaGenerousCollider.min.y(); - }); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { - return p.y() < drawData.cam.viewingAreaGenerousCollider.max.y(); - }); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { - return p.x() > drawData.cam.viewingAreaGenerousCollider.min.x(); - }); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { - return p.x() < drawData.cam.viewingAreaGenerousCollider.max.x(); - }); - for(auto& tri : clipList) { - auto& c = drawData.cam.c; - finalTrianglePoints.emplace_back(std::array{convert_vec2(c.to_space(tri[0])), convert_vec2(c.to_space(tri[1])), convert_vec2(c.to_space(tri[2]))}); + for(auto& tri : cdt.triangles) { + SCollision::Triangle triCollider(Vector2f{points[tri.vertices[0]].x, points[tri.vertices[0]].y}, Vector2f{points[tri.vertices[1]].x, points[tri.vertices[1]].y}, Vector2f{points[tri.vertices[2]].x, points[tri.vertices[2]].y}); + if(SCollision::collide(triCollider.bounds, viewGenerousColliderInObjSpace)) { + std::vector> clipList; + clipList.emplace_back(std::array{coords.from_space(triCollider.p[0]), coords.from_space(triCollider.p[1]), coords.from_space(triCollider.p[2])}); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { + return p.y() > drawData.cam.viewingAreaGenerousCollider.min.y(); + }); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { + return p.y() < drawData.cam.viewingAreaGenerousCollider.max.y(); + }); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { + return p.x() > drawData.cam.viewingAreaGenerousCollider.min.x(); + }); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { + return p.x() < drawData.cam.viewingAreaGenerousCollider.max.x(); + }); + for(auto& tri : clipList) { + auto& c = drawData.cam.c; + finalTrianglePoints.emplace_back(std::array{convert_vec2(c.to_space(tri[0])), convert_vec2(c.to_space(tri[1])), convert_vec2(c.to_space(tri[2]))}); + } } - }); + } // Match points that are close enough. I don't think this is required. //if(!finalTrianglePoints.empty()) { @@ -263,11 +301,7 @@ bool MeshCanvasComponent::collides_within_coords_skpath(const SkPath& checkAgain } bool MeshCanvasComponent::should_draw_extra(const DrawData& drawData, const CoordSpaceHelper& coords) const { - SCollision::AABB viewGenerousColliderInObjSpace = coords.world_collider_to_coords>(drawData.cam.viewingAreaGenerousCollider); - viewGenerousColliderInObjSpace.min -= Vector2f{1.0f, 1.0f}; - viewGenerousColliderInObjSpace.max += Vector2f{1.0f, 1.0f}; return true; - //return collisionTree.is_collide(viewGenerousColliderInObjSpace); } bool MeshCanvasComponent::can_erase_detail() const {