diff --git a/src/DrawComponents/DrawBrushStroke.cpp b/src/DrawComponents/DrawBrushStroke.cpp index 921195a..9535a76 100644 --- a/src/DrawComponents/DrawBrushStroke.cpp +++ b/src/DrawComponents/DrawBrushStroke.cpp @@ -12,6 +12,7 @@ #endif #define AABB_PRECHECK_BVH_LEVELS 2 +#define DEFAULT_SMOOTHNESS 5 void DrawBrushStroke::save(cereal::PortableBinaryOutputArchive& a) const { a(d.points, d.color, d.hasRoundCaps); @@ -50,7 +51,7 @@ Vector2f two_dim_vec_slerp(const Vector2f& v1, const Vector2f& v2) { } void DrawBrushStroke::draw(SkCanvas* canvas, const DrawData& drawData) { - if(drawSetupData.shouldDraw) { + if(drawSetupData.shouldDraw && vertices) { //bool deepPrecheck = false; //for(auto& aabb : precheckAABBLevels) { // if(SCollision::collide(drawData.cam.viewingAreaGenerousCollider, aabb)) { @@ -68,7 +69,10 @@ void DrawBrushStroke::draw(SkCanvas* canvas, const DrawData& drawData) { canvas->saveLayerAlphaf(nullptr, d.color.w()); paint.setColor4f(SkColor4f{d.color.x(), d.color.y(), d.color.z(), 1.0f}); canvas_do_calculated_transform(canvas); - canvas->drawVertices(vertices, SkBlendMode::kClear, paint); + if(drawSetupData.mipmapLevel == 0) + canvas->drawVertices(vertices, SkBlendMode::kClear, paint); + else + canvas->drawVertices(verticesMipMap[drawSetupData.mipmapLevel - 1], SkBlendMode::kClear, paint); //SkPaint p2(SkColor4f{1, 0, 0, 1}); //p2.setStroke(true); //SkPaint p3(SkColor4f{0, 1, 0, 1}); @@ -83,14 +87,38 @@ void DrawBrushStroke::draw(SkCanvas* canvas, const DrawData& drawData) { } void DrawBrushStroke::initialize_draw_data(DrawingProgram& drawP) { - std::vector vertexData; - create_triangles([&](Vector2f a, Vector2f b, Vector2f c) { - vertexData.emplace_back(a.x(), a.y()); - vertexData.emplace_back(b.x(), b.y()); - vertexData.emplace_back(c.x(), c.y()); - return false; - }); - vertices_to_draw_data(vertexData); + if(!d.points.empty()) { + std::vector vertexData; + std::vector points = smooth_points(0, d.points.size() - 1, DEFAULT_SMOOTHNESS); + auto triangleFunc = [&](Vector2f a, Vector2f b, Vector2f c) { + vertexData.emplace_back(a.x(), a.y()); + vertexData.emplace_back(b.x(), b.y()); + vertexData.emplace_back(c.x(), c.y()); + return false; + }; + + create_triangles(triangleFunc, points, 0); + vertices_to_draw_data(vertices, vertexData); + vertexData.clear(); + + create_triangles(triangleFunc, points, 2); + vertices_to_draw_data(verticesMipMap[0], vertexData); + vertexData.clear(); + + create_triangles(triangleFunc, points, 4); + vertices_to_draw_data(verticesMipMap[1], vertexData); + vertexData.clear(); + + create_triangles(triangleFunc, points, 6); + vertices_to_draw_data(verticesMipMap[2], vertexData); + vertexData.clear(); + + create_triangles(triangleFunc, points, 10); + vertices_to_draw_data(verticesMipMap[3], vertexData); + + create_triangles(triangleFunc, points, 30); + vertices_to_draw_data(verticesMipMap[4], vertexData); + } } std::vector DrawBrushStroke::get_wedge_indices(const std::vector& points) { @@ -108,7 +136,7 @@ std::vector DrawBrushStroke::get_wedge_indices(const std::vector DrawBrushStroke::smooth_points(size_t beginIndex, size_t endIndex) { +std::vector DrawBrushStroke::smooth_points(size_t beginIndex, size_t endIndex, unsigned numOfDivisions) { std::vector& points = d.points; size_t pointsSize = endIndex - beginIndex + 1; @@ -134,8 +162,6 @@ std::vector DrawBrushStroke::smooth_points(size_t beginInd toRet.emplace_back(p1); - const unsigned numOfDivisions = 5; // How smooth the stroke should be - float tMove = 1.0 / static_cast(numOfDivisions); for(unsigned d = 1; d < numOfDivisions; d++) { float t = tMove * static_cast(d); @@ -154,7 +180,7 @@ std::vector DrawBrushStroke::smooth_points(size_t beginInd return toRet; } -std::vector DrawBrushStroke::smooth_points_avg(size_t beginIndex, size_t endIndex) { +std::vector DrawBrushStroke::smooth_points_avg(size_t beginIndex, size_t endIndex, unsigned numOfDivisions) { std::vector& points = d.points; size_t pointsSize = endIndex - beginIndex + 1; @@ -167,8 +193,6 @@ std::vector DrawBrushStroke::smooth_points_avg(size_t begi const DrawBrushStrokePoint& p1 = points[i]; const DrawBrushStrokePoint& p2 = points[i + 1]; - const unsigned numOfDivisions = 5; // How smooth the stroke should be - float tMove = 1.0 / static_cast(numOfDivisions); for(unsigned d = 0; d < numOfDivisions; d++) { float t = tMove * static_cast(d); @@ -185,7 +209,7 @@ std::vector DrawBrushStroke::smooth_points_avg(size_t begi return toRet; } -void DrawBrushStroke::create_triangles(const std::function& passTriangleFunc) { +void DrawBrushStroke::create_triangles(const std::function& passTriangleFunc, const std::vector& points, unsigned skipVertexCount) { const int ARC_SMOOTHNESS = 10; const int CIRCLE_SMOOTHNESS = 20; std::vector& pointsN = d.points; @@ -199,9 +223,9 @@ void DrawBrushStroke::create_triangles(const std::function points = smooth_points(0, pointsN.size() - 1); std::vector wedgeIndices = get_wedge_indices(points); for(size_t i = 0; i < wedgeIndices.size() - 1; i++) { + size_t pointsBegin = wedgeIndices[i]; size_t pointsEnd = wedgeIndices[i + 1]; @@ -227,6 +251,10 @@ void DrawBrushStroke::create_triangles(const std::function= pointsEnd) + j = pointsEnd - 1; + Vector2f v1 = points[j - 1].pos - points[j].pos; Vector2f v2 = points[j].pos - points[j + 1].pos; Vector2f perp = perpendicular_vec2((v1 + v2).eval()).normalized(); @@ -318,11 +346,14 @@ void DrawBrushStroke::create_triangles(const std::function strokeObjects; + std::vector points = smooth_points(0, d.points.size() - 1, DEFAULT_SMOOTHNESS); create_triangles([&](Vector2f a, Vector2f b, Vector2f c) { strokeObjects.triangle.emplace_back(a, b, c); return false; - }); + }, points, 0); strokeObjects.recalculate_bounds(); collisionTree.clear(); collisionTree.calculate_bvh_recursive(strokeObjects); @@ -346,11 +377,11 @@ void DrawBrushStroke::add_precheck_aabb_level(size_t level, const std::vector& vertexData) { +void DrawBrushStroke::vertices_to_draw_data(sk_sp& vertexDataPtr, const std::vector& vertexData) { if((d.points.size() == 1 && d.hasRoundCaps) || d.points.size() >= 2) - vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, vertexData.size(), vertexData.data(), nullptr, nullptr); + vertexDataPtr = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, vertexData.size(), vertexData.data(), nullptr, nullptr); else - vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 0, nullptr, nullptr, nullptr); + vertexDataPtr = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 0, nullptr, nullptr, nullptr); } void DrawBrushStroke::update(DrawingProgram& drawP) { @@ -374,10 +405,11 @@ bool DrawBrushStroke::collides_within_coords(const SCollision::ColliderCollectio return false; bool toRet = false; + std::vector points = smooth_points(0, d.points.size() - 1, DEFAULT_SMOOTHNESS); create_triangles([&](Vector2f a, Vector2f b, Vector2f c) { toRet = SCollision::collide(checkAgainst, SCollision::Triangle{a, b, c}); return toRet; - }); + }, points, 0); return toRet; } diff --git a/src/DrawComponents/DrawBrushStroke.hpp b/src/DrawComponents/DrawBrushStroke.hpp index fa2d647..878a2e7 100644 --- a/src/DrawComponents/DrawBrushStroke.hpp +++ b/src/DrawComponents/DrawBrushStroke.hpp @@ -47,16 +47,17 @@ class DrawBrushStroke : public DrawComponent { virtual SCollision::AABB get_obj_coord_bounds() const override; sk_sp vertices; + std::array, 5> verticesMipMap; SCollision::BVHContainer collisionTree; private: void add_precheck_aabb_level(size_t level, const std::vector>& levelArray); std::vector> precheckAABBLevels; - void create_triangles(const std::function& passTriangleFunc); - void vertices_to_draw_data(const std::vector& vertexData); + void create_triangles(const std::function& passTriangleFunc, const std::vector& points, unsigned skipVertexCount); + void vertices_to_draw_data(sk_sp& vertexDataPtr, const std::vector& vertexData); std::vector get_wedge_indices(const std::vector& points); - std::vector smooth_points(size_t beginIndex, size_t endIndex); - std::vector smooth_points_avg(size_t beginIndex, size_t endIndex); + std::vector smooth_points(size_t beginIndex, size_t endIndex, unsigned numOfDivisions); + std::vector smooth_points_avg(size_t beginIndex, size_t endIndex, unsigned numOfDivisions); #endif }; diff --git a/src/DrawComponents/DrawComponent.cpp b/src/DrawComponents/DrawComponent.cpp index 7818469..a358bc2 100644 --- a/src/DrawComponents/DrawComponent.cpp +++ b/src/DrawComponents/DrawComponent.cpp @@ -188,6 +188,18 @@ void DrawComponent::calculate_draw_transform(const DrawData& drawData) { if(drawSetupData.shouldDraw) { drawSetupData.shouldDraw = updateDraw || !worldAABB || SCollision::collide(*worldAABB, drawData.cam.viewingAreaGenerousCollider); if(drawSetupData.shouldDraw) { + if(drawData.mipMapLevelFive > coords.inverseScale) + drawSetupData.mipmapLevel = 5; + if(drawData.mipMapLevelFour > coords.inverseScale) + drawSetupData.mipmapLevel = 4; + else if(drawData.mipMapLevelThree > coords.inverseScale) + drawSetupData.mipmapLevel = 3; + else if(drawData.mipMapLevelTwo > coords.inverseScale) + drawSetupData.mipmapLevel = 2; + else if(drawData.mipMapLevelOne > coords.inverseScale) + drawSetupData.mipmapLevel = 1; + else + drawSetupData.mipmapLevel = 0; drawSetupData.transformData.translation = -coords.to_space(drawData.cam.c.pos); drawSetupData.transformData.rotation = (coords.rotation - drawData.cam.c.rotation) * 180.0 / std::numbers::pi; drawSetupData.transformData.scale = static_cast(coords.inverseScale / drawData.cam.c.inverseScale); diff --git a/src/DrawComponents/DrawComponent.hpp b/src/DrawComponents/DrawComponent.hpp index 6d03619..668ee55 100644 --- a/src/DrawComponents/DrawComponent.hpp +++ b/src/DrawComponents/DrawComponent.hpp @@ -16,7 +16,12 @@ #define CLIENT_DRAWCOMP_DELAY_TIMER_DURATION 5.0f #define DRAWCOMP_MAX_SHIFT_BEFORE_DISAPPEAR 20 -#define DRAWCOMP_MIN_SHIFT_BEFORE_DISAPPEAR 9 +#define DRAWCOMP_MIN_SHIFT_BEFORE_DISAPPEAR 11 +#define DRAWCOMP_MIPMAP_LEVEL_ONE 1 +#define DRAWCOMP_MIPMAP_LEVEL_TWO 2 +#define DRAWCOMP_MIPMAP_LEVEL_THREE 3 +#define DRAWCOMP_MIPMAP_LEVEL_FOUR 4 +#define DRAWCOMP_MIPMAP_LEVEL_FIVE 5 class DrawingProgram; @@ -40,6 +45,7 @@ class DrawComponent { float scale; } transformData; bool shouldDraw = true; + unsigned mipmapLevel = 0; } drawSetupData; void canvas_do_calculated_transform(SkCanvas* canvas); diff --git a/src/DrawData.hpp b/src/DrawData.hpp index f6f5678..98d3063 100644 --- a/src/DrawData.hpp +++ b/src/DrawData.hpp @@ -16,4 +16,9 @@ struct DrawData { bool clampDrawBetween = true; WorldScalar clampDrawMinimum; WorldScalar clampDrawMaximum; + WorldScalar mipMapLevelOne; + WorldScalar mipMapLevelTwo; + WorldScalar mipMapLevelThree; + WorldScalar mipMapLevelFour; + WorldScalar mipMapLevelFive; }; diff --git a/src/DrawingProgram/BrushTool.cpp b/src/DrawingProgram/BrushTool.cpp index fa918d5..5d2f754 100644 --- a/src/DrawingProgram/BrushTool.cpp +++ b/src/DrawingProgram/BrushTool.cpp @@ -173,9 +173,11 @@ void BrushTool::gui_toolbox() { void BrushTool::commit_stroke() { if(controls.intermediateItem) { - controls.intermediateItem->client_send_update_final(drawP, controls.intermediateID); - controls.intermediateItem->final_update(drawP); - controls.intermediateItem = nullptr; + if(!controls.intermediateItem->d.points.empty()) { + controls.intermediateItem->client_send_update_final(drawP, controls.intermediateID); + controls.intermediateItem->final_update(drawP); + controls.intermediateItem = nullptr; + } } } diff --git a/src/World.cpp b/src/World.cpp index 9b772e8..e20c0dc 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -320,8 +320,15 @@ WorldScalar World::calculate_zoom_from_uniform_zoom(WorldScalar uniformZoom, Wor void World::draw(SkCanvas* canvas) { drawData.clampDrawBetween = true; + drawData.clampDrawMinimum = drawData.cam.c.inverseScale >> DRAWCOMP_MIN_SHIFT_BEFORE_DISAPPEAR; + drawData.mipMapLevelOne = drawData.cam.c.inverseScale >> DRAWCOMP_MIPMAP_LEVEL_ONE; + drawData.mipMapLevelTwo = drawData.cam.c.inverseScale >> DRAWCOMP_MIPMAP_LEVEL_TWO; + drawData.mipMapLevelThree = drawData.cam.c.inverseScale >> DRAWCOMP_MIPMAP_LEVEL_THREE; + drawData.mipMapLevelFour = drawData.cam.c.inverseScale >> DRAWCOMP_MIPMAP_LEVEL_FOUR; + drawData.mipMapLevelFive = drawData.cam.c.inverseScale >> DRAWCOMP_MIPMAP_LEVEL_FOUR; drawData.clampDrawMaximum = drawData.cam.c.inverseScale << DRAWCOMP_MAX_SHIFT_BEFORE_DISAPPEAR; + drawProg.draw(canvas, drawData); for(auto& [id, data] : clients) {