Working on detail eraser

This commit is contained in:
Yousef Khadadeh 2026-05-24 20:32:21 +03:00
parent 60ab8f3c73
commit c54fef383c
15 changed files with 255 additions and 58 deletions

View file

@ -71,4 +71,12 @@ bool CanvasComponent::should_draw_extra(const DrawData& drawData, const CoordSpa
return true;
}
bool CanvasComponent::can_erase_detail() const {
return false;
}
CanvasComponentEraseDetailResult CanvasComponent::erase_detail(const SkPath& eraseAgainst) {
return CanvasComponentEraseDetailResult::NO_CHANGE;
}
CanvasComponent::~CanvasComponent() {}

View file

@ -29,6 +29,7 @@ class DrawingProgram;
class CanvasComponent {
public:
virtual CanvasComponentType get_type() const = 0;
virtual ~CanvasComponent();
static CanvasComponent* allocate_comp(CanvasComponentType type);
@ -59,6 +60,9 @@ class CanvasComponent {
virtual bool collides_within_coords_point(const Vector2f& checkAgainst) const = 0;
virtual bool collides_within_coords_skpath(const SkPath& checkAgainst) const = 0;
virtual bool can_erase_detail() const;
virtual CanvasComponentEraseDetailResult erase_detail(const SkPath& eraseAgainst);
virtual SCollision::AABB<float> get_obj_coord_bounds() const = 0;
CanvasComponentContainer* compContainer = nullptr;

View file

@ -142,6 +142,28 @@ void CanvasComponentContainer::commit_transform_dont_invalidate_cache() {
calculate_world_bounds();
}
CanvasComponentEraseDetailResult CanvasComponentContainer::collides_with_erase_detail(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const {
if(!worldAABB.has_value())
return CanvasComponentEraseDetailResult::NO_CHANGE;
if((camCoords.inverseScale << COMP_MAX_SHIFT_BEFORE_STOP_COLLISIONS) < coords.inverseScale) // Object is too large, just dismiss the collision
return CanvasComponentEraseDetailResult::NO_CHANGE;
else if(coords.inverseScale < (camCoords.inverseScale >> COMP_COLLIDE_MIN_SHIFT_TINY)) {
if(checkAgainstCam.contains(convert_vec2<SkPoint>(camCoords.to_space(worldAABB.value().min))))
return CanvasComponentEraseDetailResult::REMOVED;
return CanvasComponentEraseDetailResult::NO_CHANGE;
}
else if(get_comp().can_erase_detail()) {
TransformData drawTransform = calculate_draw_transform(camCoords);
SkMatrix m = SkMatrix::I();
m.postScale(1.0 / drawTransform.scale, 1.0 / drawTransform.scale).postRotate(-drawTransform.rotation).postTranslate(-drawTransform.translation.x(), -drawTransform.translation.y());
std::optional<SkPath> transformedPath = checkAgainstCam.tryMakeTransform(m);
if(!transformedPath.has_value())
return CanvasComponentEraseDetailResult::NO_CHANGE;
return get_comp().erase_detail(transformedPath.value());
}
return CanvasComponentEraseDetailResult::NO_CHANGE;
}
// We could just send one of the checkAgainst colliders, since they represent the same thing, but sending both saves on redundant transformations, since we can save both of the versions on the executor side
bool CanvasComponentContainer::collides_with(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const {
if(!worldAABB.has_value())

View file

@ -30,6 +30,12 @@ class DrawingProgram;
class DrawingProgramLayerListItem;
struct DrawingProgramCacheBVHNode;
enum class CanvasComponentEraseDetailResult {
NO_CHANGE,
CHANGED,
REMOVED
};
class CanvasComponentContainer {
public:
typedef NetworkingObjects::NetObjOrderedList<CanvasComponentContainer> NetList;
@ -83,6 +89,7 @@ class CanvasComponentContainer {
void commit_transform(DrawingProgram& drawP);
void commit_update_dont_invalidate_cache(DrawingProgram& drawP); // Must be thread safe
bool should_draw(const DrawData& drawData) const;
CanvasComponentEraseDetailResult collides_with_erase_detail(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const;
bool collides_with(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const;
bool collides_with_point(const CoordSpaceHelper& camCoords, const Vector2f& checkAgainstCam) const;
void send_comp_update(DrawingProgram& drawP, bool finalUpdate);

View file

@ -23,6 +23,7 @@
#include <limits>
#include <Eigen/Geometry>
#include "BrushComponentCode.hpp"
#include "CanvasComponent.hpp"
#include "Eigen/Core"
#include "Helpers/MathExtras.hpp"
#include "../TimePoint.hpp"
@ -263,6 +264,24 @@ bool MeshCanvasComponent::should_draw_extra(const DrawData& drawData, const Coor
//return collisionTree.is_collide(viewGenerousColliderInObjSpace);
}
bool MeshCanvasComponent::can_erase_detail() const {
return true;
}
CanvasComponentEraseDetailResult MeshCanvasComponent::erase_detail(const SkPath& eraseAgainst) {
bool intersectsAABB = d.meshPath.getBounds().intersects(eraseAgainst.getBounds());
if(!intersectsAABB)
return CanvasComponentEraseDetailResult::NO_CHANGE;
std::optional<SkPath> newPath = Op(d.meshPath, eraseAgainst, SkPathOp::kDifference_SkPathOp);
if(newPath.has_value()) {
d.meshPath = newPath.value();
if(d.meshPath.isEmpty())
return CanvasComponentEraseDetailResult::REMOVED;
return CanvasComponentEraseDetailResult::CHANGED;
}
return CanvasComponentEraseDetailResult::NO_CHANGE;
}
SCollision::AABB<float> MeshCanvasComponent::get_obj_coord_bounds() const {
return d.meshPath.getBounds();
}

View file

@ -47,6 +47,8 @@ class MeshCanvasComponent : public CanvasComponent {
virtual void initialize_draw_data(DrawingProgram& drawP) override;
virtual bool collides_within_coords_point(const Vector2f& checkAgainst) const override;
virtual bool collides_within_coords_skpath(const SkPath& checkAgainst) const override;
virtual bool can_erase_detail() const override;
virtual CanvasComponentEraseDetailResult erase_detail(const SkPath& eraseAgainst) override;
bool should_draw_extra(const DrawData& drawData, const CoordSpaceHelper& coords) const override;
virtual SCollision::AABB<float> get_obj_coord_bounds() const override;
SCollision::BVHContainer<float> collisionTree;