Calculate accurate brush stroke data in parallel before drawing
This commit is contained in:
parent
fd1f76520b
commit
89925763cd
15 changed files with 86 additions and 50 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include "../TimePoint.hpp"
|
||||
#include <include/core/SkVertices.h>
|
||||
#include <include/pathops/SkPathOps.h>
|
||||
#include <memory>
|
||||
#include "../DrawCollision.hpp"
|
||||
#include "CanvasComponentContainer.hpp"
|
||||
#include "Helpers/SCollision.hpp"
|
||||
|
|
@ -49,7 +50,7 @@ std::optional<Vector4f> BrushStrokeCanvasComponent::get_stroke_color() const {
|
|||
return d.color;
|
||||
}
|
||||
|
||||
void BrushStrokeCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData) const {
|
||||
void BrushStrokeCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const {
|
||||
SkPaint paint;
|
||||
paint.setColor4f(SkColor4f{d.color.x(), d.color.y(), d.color.z(), d.color.w()});
|
||||
|
||||
|
|
@ -73,10 +74,10 @@ void BrushStrokeCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData
|
|||
//draw_collider(canvas, drawData, strokeObjects, paint2);
|
||||
}
|
||||
|
||||
bool BrushStrokeCanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords) const {
|
||||
std::shared_ptr<void> BrushStrokeCanvasComponent::get_predraw_data_accurate(const DrawData& drawData, const CoordSpaceHelper& coords) const {
|
||||
std::vector<BrushStrokeCanvasComponentPoint> points = smooth_points(0, d.points->size() - 1, DEFAULT_SMOOTHNESS);
|
||||
|
||||
std::vector<SkPath> pathsToDraw;
|
||||
auto pathsToDraw = std::make_shared<std::vector<SkPath>>();
|
||||
|
||||
auto triangleFunc = [&](Vector2f a, Vector2f b, Vector2f c) {
|
||||
SCollision::Triangle worldTri = {
|
||||
|
|
@ -111,7 +112,7 @@ bool BrushStrokeCanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData&
|
|||
SkPathBuilder pathBuilder;
|
||||
std::vector<SkPoint> triSkPoints = {convert_vec2<SkPoint>(c.to_space(tri[0])), convert_vec2<SkPoint>(c.to_space(tri[1])), convert_vec2<SkPoint>(c.to_space(tri[2]))};
|
||||
pathBuilder.addPolygon({triSkPoints.data(), triSkPoints.size()}, true);
|
||||
pathsToDraw.emplace_back(pathBuilder.detach());
|
||||
pathsToDraw->emplace_back(pathBuilder.detach());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -119,19 +120,27 @@ bool BrushStrokeCanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData&
|
|||
|
||||
create_triangles(triangleFunc, points, 0, nullptr);
|
||||
|
||||
if(d.color.w() == 1.0f) {
|
||||
SkPaint paint;
|
||||
paint.setColor4f(SkColor4f{d.color.x(), d.color.y(), d.color.z(), d.color.w()});
|
||||
for(const SkPath& p : pathsToDraw)
|
||||
canvas->drawPath(p, paint);
|
||||
}
|
||||
else {
|
||||
canvas->saveLayerAlphaf(nullptr, d.color.w());
|
||||
SkPaint paint;
|
||||
paint.setColor4f(SkColor4f{d.color.x(), d.color.y(), d.color.z(), 1.0f});
|
||||
for(const SkPath& p : pathsToDraw)
|
||||
canvas->drawPath(p, paint);
|
||||
canvas->restore();
|
||||
return pathsToDraw;
|
||||
}
|
||||
|
||||
bool BrushStrokeCanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords, const std::shared_ptr<void>& predrawData) const {
|
||||
auto pathsToDraw = std::static_pointer_cast<std::vector<SkPath>>(predrawData);
|
||||
|
||||
if(!pathsToDraw->empty()) {
|
||||
if(d.color.w() == 1.0f) {
|
||||
SkPaint paint;
|
||||
paint.setColor4f(SkColor4f{d.color.x(), d.color.y(), d.color.z(), d.color.w()});
|
||||
for(const SkPath& p : *pathsToDraw)
|
||||
canvas->drawPath(p, paint);
|
||||
}
|
||||
else {
|
||||
canvas->saveLayerAlphaf(nullptr, d.color.w());
|
||||
SkPaint paint;
|
||||
paint.setColor4f(SkColor4f{d.color.x(), d.color.y(), d.color.z(), 1.0f});
|
||||
for(const SkPath& p : *pathsToDraw)
|
||||
canvas->drawPath(p, paint);
|
||||
canvas->restore();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@ class BrushStrokeCanvasComponent : public CanvasComponent {
|
|||
|
||||
virtual void set_data_from(const CanvasComponent& other) override;
|
||||
private:
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData) const override;
|
||||
virtual bool accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords) const override;
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const override;
|
||||
virtual bool accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords, const std::shared_ptr<void>& predrawData) const override;
|
||||
virtual std::shared_ptr<void> get_predraw_data_accurate(const DrawData& drawData, const CoordSpaceHelper& coords) const override;
|
||||
|
||||
virtual void initialize_draw_data(DrawingProgram& drawP) override;
|
||||
virtual bool collides_within_coords(const SCollision::ColliderCollection<float>& checkAgainst) const override;
|
||||
void create_collider();
|
||||
|
|
|
|||
|
|
@ -37,8 +37,16 @@ std::optional<Vector4f> CanvasComponent::get_stroke_color() const {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool CanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords) const {
|
||||
bool CanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords, const std::shared_ptr<void>& predrawData) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<void> CanvasComponent::get_predraw_data(const DrawData& drawData) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<void> CanvasComponent::get_predraw_data_accurate(const DrawData& drawData, const CoordSpaceHelper& coords) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CanvasComponent::~CanvasComponent() {}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@ class CanvasComponent {
|
|||
friend class CanvasComponentContainer;
|
||||
friend class CanvasComponentAllocator;
|
||||
|
||||
virtual bool accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords) const;
|
||||
virtual bool accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords, const std::shared_ptr<void>& predrawData) const;
|
||||
virtual std::shared_ptr<void> get_predraw_data(const DrawData& drawData) const;
|
||||
virtual std::shared_ptr<void> get_predraw_data_accurate(const DrawData& drawData, const CoordSpaceHelper& coords) const;
|
||||
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData) const = 0;
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const = 0;
|
||||
virtual void initialize_draw_data(DrawingProgram& drawP) = 0;
|
||||
virtual bool collides_within_coords(const SCollision::ColliderCollection<float>& checkAgainst) const = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,14 +89,14 @@ void CanvasComponentContainer::load_file(cereal::PortableBinaryInputArchive& a,
|
|||
|
||||
void CanvasComponentContainer::draw(SkCanvas* canvas, const DrawData& drawData) const {
|
||||
if(should_draw(drawData))
|
||||
draw_with_transform(canvas, drawData, calculate_draw_transform(drawData));
|
||||
draw_with_predraw_data(canvas, drawData, calculate_predraw_data(drawData));
|
||||
}
|
||||
|
||||
void CanvasComponentContainer::draw_with_transform(SkCanvas* canvas, const DrawData& drawData, const TransformDrawData& transformDrawData) const {
|
||||
if(transformDrawData.scale < COMP_MAX_BEFORE_STOP_SCALING || !get_comp().accurate_draw(canvas, drawData, coords)) {
|
||||
void CanvasComponentContainer::draw_with_predraw_data(SkCanvas* canvas, const DrawData& drawData, const PreDrawData& preDrawData) const {
|
||||
if(preDrawData.transformData.scale < COMP_MAX_BEFORE_STOP_SCALING || !get_comp().accurate_draw(canvas, drawData, coords, preDrawData.extraData)) {
|
||||
canvas->save();
|
||||
canvas_do_transform(canvas, transformDrawData);
|
||||
get_comp().draw(canvas, drawData);
|
||||
canvas_do_transform(canvas, preDrawData.transformData);
|
||||
get_comp().draw(canvas, drawData, preDrawData.extraData);
|
||||
canvas->restore();
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ bool CanvasComponentContainer::collides_with(const CoordSpaceHelper& camCoords,
|
|||
}
|
||||
}
|
||||
|
||||
void CanvasComponentContainer::canvas_do_transform(SkCanvas* canvas, const TransformDrawData& transformData) const {
|
||||
void CanvasComponentContainer::canvas_do_transform(SkCanvas* canvas, const TransformData& transformData) const {
|
||||
canvas->scale(transformData.scale, transformData.scale);
|
||||
canvas->rotate(transformData.rotation);
|
||||
canvas->translate(transformData.translation.x(), transformData.translation.y());
|
||||
|
|
@ -161,8 +161,18 @@ bool CanvasComponentContainer::should_draw(const DrawData& drawData) const {
|
|||
return (!drawData.clampDrawBetween || (drawData.clampDrawMinimum < coords.inverseScale)) && SCollision::collide(worldAABB.value(), drawData.cam.viewingAreaGenerousCollider);
|
||||
}
|
||||
|
||||
CanvasComponentContainer::TransformDrawData CanvasComponentContainer::calculate_draw_transform(const DrawData& drawData) const {
|
||||
TransformDrawData toRet;
|
||||
CanvasComponentContainer::PreDrawData CanvasComponentContainer::calculate_predraw_data(const DrawData& drawData) const {
|
||||
PreDrawData toRet;
|
||||
toRet.transformData = calculate_draw_transform(drawData);
|
||||
if(toRet.transformData.scale < COMP_MAX_BEFORE_STOP_SCALING)
|
||||
toRet.extraData = get_comp().get_predraw_data(drawData);
|
||||
else
|
||||
toRet.extraData = get_comp().get_predraw_data_accurate(drawData, coords);
|
||||
return toRet;
|
||||
}
|
||||
|
||||
CanvasComponentContainer::TransformData CanvasComponentContainer::calculate_draw_transform(const DrawData& drawData) const {
|
||||
TransformData toRet;
|
||||
toRet.translation = -coords.to_space(drawData.cam.c.pos);
|
||||
toRet.rotation = (coords.rotation - drawData.cam.c.rotation) * 180.0 / std::numbers::pi;
|
||||
toRet.scale = std::min(static_cast<float>(coords.inverseScale / drawData.cam.c.inverseScale), COMP_MAX_BEFORE_STOP_SCALING);
|
||||
|
|
|
|||
|
|
@ -34,12 +34,16 @@ class CanvasComponentContainer {
|
|||
void scale_up(const WorldScalar& scaleUpAmount);
|
||||
};
|
||||
|
||||
struct TransformDrawData {
|
||||
struct TransformData {
|
||||
Vector2f translation;
|
||||
float rotation;
|
||||
float scale;
|
||||
};
|
||||
std::optional<TransformDrawData> transformHolder; // Can be used to store transforms when calculating transforms in parallel
|
||||
struct PreDrawData {
|
||||
TransformData transformData;
|
||||
std::shared_ptr<void> extraData;
|
||||
};
|
||||
std::optional<PreDrawData> preDrawDataHolder; // Can be used to store transforms when calculating transforms in parallel (and other predraw data)
|
||||
|
||||
CanvasComponentContainer();
|
||||
CanvasComponentContainer(NetworkingObjects::NetObjManager& objMan, CanvasComponentType type);
|
||||
|
|
@ -53,8 +57,9 @@ class CanvasComponentContainer {
|
|||
CanvasComponent& get_comp() const;
|
||||
SCollision::AABB<WorldScalar> get_world_bounds() const;
|
||||
void draw(SkCanvas* canvas, const DrawData& drawData) const;
|
||||
void draw_with_transform(SkCanvas* canvas, const DrawData& drawData, const TransformDrawData& transformDrawData) const;
|
||||
TransformDrawData calculate_draw_transform(const DrawData& drawData) const;
|
||||
void draw_with_predraw_data(SkCanvas* canvas, const DrawData& drawData, const PreDrawData& preDrawData) const;
|
||||
PreDrawData calculate_predraw_data(const DrawData& drawData) const;
|
||||
TransformData calculate_draw_transform(const DrawData& drawData) const;
|
||||
void commit_update(DrawingProgram& drawP);
|
||||
void commit_transform_dont_invalidate_cache(); // Must be thread safe
|
||||
void commit_transform(DrawingProgram& drawP);
|
||||
|
|
@ -78,7 +83,7 @@ class CanvasComponentContainer {
|
|||
|
||||
unsigned get_mipmap_level(const DrawData& drawData) const;
|
||||
CanvasComponent* allocate_comp(CanvasComponentType type);
|
||||
void canvas_do_transform(SkCanvas* canvas, const TransformDrawData& transformData) const;
|
||||
void canvas_do_transform(SkCanvas* canvas, const TransformData& transformData) const;
|
||||
void calculate_world_bounds();
|
||||
|
||||
std::optional<SCollision::AABB<WorldScalar>> worldAABB;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ std::optional<Vector4f> EllipseCanvasComponent::get_stroke_color() const {
|
|||
return d.strokeColor;
|
||||
}
|
||||
|
||||
void EllipseCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData) const {
|
||||
void EllipseCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const {
|
||||
SkPaint p;
|
||||
if(d.fillStrokeMode == 0 || d.fillStrokeMode == 2) {
|
||||
p.setStyle(SkPaint::kFill_Style);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class EllipseCanvasComponent : public CanvasComponent {
|
|||
private:
|
||||
void create_draw_data();
|
||||
void create_collider();
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData) const override;
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const override;
|
||||
virtual void initialize_draw_data(DrawingProgram& drawP) override;
|
||||
virtual bool collides_within_coords(const SCollision::ColliderCollection<float>& checkAgainst) const override;
|
||||
virtual SCollision::AABB<float> get_obj_coord_bounds() const override;
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ void ImageCanvasComponent::get_used_resources(std::unordered_set<NetworkingObjec
|
|||
resourceSet.emplace(d.imageID);
|
||||
}
|
||||
|
||||
void ImageCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData) const {
|
||||
void ImageCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const {
|
||||
ResourceDisplay* display = drawData.rMan->get_display_data(d.imageID);
|
||||
if(d.editing) {
|
||||
canvas->saveLayerAlphaf(nullptr, 1.0f);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class ImageCanvasComponent : public CanvasComponent {
|
|||
bool contains_actual_image();
|
||||
|
||||
private:
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData) const override;
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const override;
|
||||
virtual void initialize_draw_data(DrawingProgram& drawP) override;
|
||||
virtual bool collides_within_coords(const SCollision::ColliderCollection<float>& checkAgainst) const override;
|
||||
void create_collider();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ std::unique_ptr<CanvasComponent> RectangleCanvasComponent::get_data_copy() const
|
|||
return toRet;
|
||||
}
|
||||
|
||||
void RectangleCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData) const {
|
||||
void RectangleCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const {
|
||||
if(d.fillStrokeMode == 0 || d.fillStrokeMode == 2) {
|
||||
SkPaint p;
|
||||
p.setStyle(SkPaint::kFill_Style);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class RectangleCanvasComponent : public CanvasComponent {
|
|||
} d;
|
||||
|
||||
private:
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData) const override;
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const override;
|
||||
virtual void initialize_draw_data(DrawingProgram& drawP) override;
|
||||
virtual bool collides_within_coords(const SCollision::ColliderCollection<float>& checkAgainst) const override;
|
||||
void create_draw_data();
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ void TextBoxCanvasComponent::init_text_box(DrawingProgram& drawP) {
|
|||
textBox->set_width(d.p2.x() - d.p1.x() - TEXTBOX_PADDING * 2.0f);
|
||||
}
|
||||
|
||||
void TextBoxCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData) const {
|
||||
void TextBoxCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const {
|
||||
SkRect clipR = SkRect::MakeLTRB(d.p1.x(), d.p1.y(), d.p2.x(), d.p2.y());
|
||||
if(d.editing) {
|
||||
SkPaint p;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class TextBoxCanvasComponent : public CanvasComponent {
|
|||
private:
|
||||
friend class TextBoxEditTool;
|
||||
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData) const override;
|
||||
virtual void draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const override;
|
||||
virtual void initialize_draw_data(DrawingProgram& drawP) override;
|
||||
virtual bool collides_within_coords(const SCollision::ColliderCollection<float>& checkAgainst) const override;
|
||||
void create_collider();
|
||||
|
|
|
|||
|
|
@ -449,32 +449,32 @@ void DrawingProgramCache::recursive_draw_layer_item_to_canvas(const DrawingProgr
|
|||
parallel_loop_container(nodesToDraw, [&](auto& node) {
|
||||
std::for_each(node->components.begin(), node->components.end(), [&](auto& c) {
|
||||
if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds())) && c->obj->should_draw(drawData))
|
||||
c->obj->transformHolder = c->obj->calculate_draw_transform(drawData);
|
||||
c->obj->preDrawDataHolder = c->obj->calculate_predraw_data(drawData);
|
||||
else
|
||||
c->obj->transformHolder = std::nullopt;
|
||||
c->obj->preDrawDataHolder = std::nullopt;
|
||||
});
|
||||
});
|
||||
parallel_loop_container(unsortedComponents, [&](auto& c) {
|
||||
if(c->obj->parentLayer == &layerListItem && (!drawBounds.has_value() || SCollision::collide(drawBounds.value(), c->obj->get_world_bounds())) && c->obj->should_draw(drawData))
|
||||
c->obj->transformHolder = c->obj->calculate_draw_transform(drawData);
|
||||
c->obj->preDrawDataHolder = c->obj->calculate_predraw_data(drawData);
|
||||
else
|
||||
c->obj->transformHolder = std::nullopt;
|
||||
c->obj->preDrawDataHolder = std::nullopt;
|
||||
});
|
||||
for(auto& node : nodesToDraw) {
|
||||
for(auto& c : node->components) {
|
||||
if(c->obj->transformHolder.has_value())
|
||||
if(c->obj->preDrawDataHolder.has_value())
|
||||
compsToDraw.emplace_back(c);
|
||||
}
|
||||
}
|
||||
for(auto& c : unsortedComponents) {
|
||||
if(c->obj->transformHolder.has_value())
|
||||
if(c->obj->preDrawDataHolder.has_value())
|
||||
compsToDraw.emplace_back(c);
|
||||
}
|
||||
std::sort(compsToDraw.begin(), compsToDraw.end(), [](auto& a, auto& b) {
|
||||
return a->pos < b->pos;
|
||||
});
|
||||
for(auto& c : compsToDraw)
|
||||
c->obj->draw_with_transform(canvas, drawData, c->obj->transformHolder.value());
|
||||
c->obj->draw_with_predraw_data(canvas, drawData, c->obj->preDrawDataHolder.value());
|
||||
}
|
||||
canvas->restore();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue