Refactoring

This commit is contained in:
Isaac 2024-05-18 20:51:38 +04:00
parent b6ba0d8f99
commit 7f88fb6ffa
3 changed files with 63 additions and 79 deletions

View File

@ -18,7 +18,7 @@ struct TransformedPath {
}
};
static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) {
static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
//TODO:remove skipApplyTransform
lottie::CATransform3D effectiveTransform = parentTransform;
if (!skipApplyTransform && item->isGroup) {
@ -29,13 +29,17 @@ static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr<lottie::RenderTre
lottie::CGRect boundingBox(0.0, 0.0, 0.0, 0.0);
if (item->path) {
boundingBox = item->pathBoundingBox.applyingTransform(effectiveTransform);
if (item->path->needsBoundsRecalculation) {
item->path->bounds = lottie::bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, item->path->path);
item->path->needsBoundsRecalculation = false;
}
boundingBox = item->path->bounds.applyingTransform(effectiveTransform);
}
for (size_t i = 0; i < maxSubitem; i++) {
auto &subItem = item->subItems[i];
lottie::CGRect subItemBoundingBox = collectPathBoundingBoxes(subItem, INT32_MAX, effectiveTransform, false);
lottie::CGRect subItemBoundingBox = collectPathBoundingBoxes(subItem, INT32_MAX, effectiveTransform, false, bezierPathsBoundingBoxContext);
if (boundingBox.empty()) {
boundingBox = subItemBoundingBox;
@ -59,7 +63,7 @@ static std::vector<TransformedPath> collectPaths(std::shared_ptr<lottie::RenderT
size_t maxSubitem = std::min(item->subItems.size(), subItemLimit);
if (item->path) {
mappedPaths.emplace_back(item->path.value(), effectiveTransform);
mappedPaths.emplace_back(item->path->path, effectiveTransform);
}
assert(!item->trimParams);
@ -96,7 +100,7 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
int drawContentDescendants = 0;
for (const auto &shadingVariant : contentItem->shadings) {
lottie::CGRect shapeBounds = collectPathBoundingBoxes(contentItem, shadingVariant->subItemLimit, lottie::CATransform3D::identity(), true);
lottie::CGRect shapeBounds = collectPathBoundingBoxes(contentItem, shadingVariant->subItemLimit, lottie::CATransform3D::identity(), true, bezierPathsBoundingBoxContext);
if (shadingVariant->stroke) {
shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0);

View File

@ -309,6 +309,17 @@ public:
class RenderTreeNodeContentShadingVariant;
struct RenderTreeNodeContentPath {
public:
explicit RenderTreeNodeContentPath(BezierPath path_) :
path(path_) {
}
BezierPath path;
CGRect bounds = CGRect(0.0, 0.0, 0.0, 0.0);
bool needsBoundsRecalculation = true;
};
class RenderTreeNodeContentItem {
public:
enum class ShadingType {
@ -423,8 +434,7 @@ public:
CATransform3D transform = CATransform3D::identity();
float alpha = 0.0;
std::optional<TrimParams> trimParams;
std::optional<BezierPath> path;
CGRect pathBoundingBox = CGRect(0.0, 0.0, 0.0, 0.0);
std::shared_ptr<RenderTreeNodeContentPath> path;
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems;

View File

@ -506,60 +506,44 @@ public:
}
virtual ~PathOutput() = default;
virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) = 0;
virtual BezierPath const *currentPath() = 0;
virtual CGRect const &currentPathBounds() = 0;
virtual void update(AnimationFrameTime frameTime) = 0;
virtual std::shared_ptr<RenderTreeNodeContentPath> &currentPath() = 0;
};
class StaticPathOutput : public PathOutput {
public:
explicit StaticPathOutput(BezierPath const &path) :
resolvedPath(path) {
resolvedPath(std::make_shared<RenderTreeNodeContentPath>(path)) {
}
virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
if (!isPathBoundsResolved) {
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
isPathBoundsResolved = true;
}
virtual void update(AnimationFrameTime frameTime) override {
}
virtual BezierPath const *currentPath() override {
return &resolvedPath;
}
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
virtual std::shared_ptr<RenderTreeNodeContentPath> &currentPath() override {
return resolvedPath;
}
private:
BezierPath resolvedPath;
bool isPathBoundsResolved = false;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
std::shared_ptr<RenderTreeNodeContentPath> resolvedPath;
};
class ShapePathOutput : public PathOutput {
public:
explicit ShapePathOutput(Shape const &shape) :
path(shape.path.keyframes) {
path(shape.path.keyframes),
resolvedPath(std::make_shared<RenderTreeNodeContentPath>(BezierPath())) {
}
virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
virtual void update(AnimationFrameTime frameTime) override {
if (!hasValidData || path.hasUpdate(frameTime)) {
path.update(frameTime, resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
path.update(frameTime, resolvedPath->path);
resolvedPath->needsBoundsRecalculation = true;
}
hasValidData = true;
}
virtual BezierPath const *currentPath() override {
return &resolvedPath;
}
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
virtual std::shared_ptr<RenderTreeNodeContentPath> &currentPath() override {
return resolvedPath;
}
private:
@ -567,8 +551,7 @@ public:
BezierPathKeyframeInterpolator path;
BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
std::shared_ptr<RenderTreeNodeContentPath> resolvedPath;
};
class RectanglePathOutput : public PathOutput {
@ -577,10 +560,11 @@ public:
direction(rectangle.direction.value_or(PathDirection::Clockwise)),
position(rectangle.position.keyframes),
size(rectangle.size.keyframes),
cornerRadius(rectangle.cornerRadius.keyframes) {
cornerRadius(rectangle.cornerRadius.keyframes),
resolvedPath(std::make_shared<RenderTreeNodeContentPath>(BezierPath())) {
}
virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
virtual void update(AnimationFrameTime frameTime) override {
bool hasUpdates = false;
if (!hasValidData || position.hasUpdate(frameTime)) {
@ -597,19 +581,15 @@ public:
}
if (hasUpdates) {
ValueInterpolator<BezierPath>::setInplace(makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction), resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
ValueInterpolator<BezierPath>::setInplace(makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction), resolvedPath->path);
resolvedPath->needsBoundsRecalculation = true;
}
hasValidData = true;
}
virtual BezierPath const *currentPath() override {
return &resolvedPath;
}
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
virtual std::shared_ptr<RenderTreeNodeContentPath> &currentPath() override {
return resolvedPath;
}
private:
@ -626,8 +606,7 @@ public:
KeyframeInterpolator<Vector1D> cornerRadius;
float cornerRadiusValue = 0.0;
BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
std::shared_ptr<RenderTreeNodeContentPath> resolvedPath;
};
class EllipsePathOutput : public PathOutput {
@ -635,10 +614,11 @@ public:
explicit EllipsePathOutput(Ellipse const &ellipse) :
direction(ellipse.direction.value_or(PathDirection::Clockwise)),
position(ellipse.position.keyframes),
size(ellipse.size.keyframes) {
size(ellipse.size.keyframes),
resolvedPath(std::make_shared<RenderTreeNodeContentPath>(BezierPath())) {
}
virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
virtual void update(AnimationFrameTime frameTime) override {
bool hasUpdates = false;
if (!hasValidData || position.hasUpdate(frameTime)) {
@ -651,19 +631,15 @@ public:
}
if (hasUpdates) {
ValueInterpolator<BezierPath>::setInplace(makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction), resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
ValueInterpolator<BezierPath>::setInplace(makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction), resolvedPath->path);
resolvedPath->needsBoundsRecalculation = true;
}
hasValidData = true;
}
virtual BezierPath const *currentPath() override {
return &resolvedPath;
}
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
virtual std::shared_ptr<RenderTreeNodeContentPath> &currentPath() override {
return resolvedPath;
}
private:
@ -677,8 +653,7 @@ public:
KeyframeInterpolator<Vector3D> size;
Vector3D sizeValue = Vector3D(0.0, 0.0, 0.0);
BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
std::shared_ptr<RenderTreeNodeContentPath> resolvedPath;
};
class StarPathOutput : public PathOutput {
@ -689,7 +664,8 @@ public:
outerRadius(star.outerRadius.keyframes),
outerRoundedness(star.outerRoundness.keyframes),
rotation(star.rotation.keyframes),
points(star.points.keyframes) {
points(star.points.keyframes),
resolvedPath(std::make_shared<RenderTreeNodeContentPath>(BezierPath())) {
if (star.innerRadius.has_value()) {
innerRadius = std::make_unique<NodeProperty<Vector1D>>(std::make_shared<KeyframeInterpolator<Vector1D>>(star.innerRadius->keyframes));
} else {
@ -703,7 +679,7 @@ public:
}
}
virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
virtual void update(AnimationFrameTime frameTime) override {
bool hasUpdates = false;
if (!hasValidData || position.hasUpdate(frameTime)) {
@ -744,19 +720,15 @@ public:
}
if (hasUpdates) {
ValueInterpolator<BezierPath>::setInplace(makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction), resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
ValueInterpolator<BezierPath>::setInplace(makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction), resolvedPath->path);
resolvedPath->needsBoundsRecalculation = true;
}
hasValidData = true;
}
virtual BezierPath const *currentPath() override {
return &resolvedPath;
}
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
virtual std::shared_ptr<RenderTreeNodeContentPath> &currentPath() override {
return resolvedPath;
}
private:
@ -785,8 +757,7 @@ public:
KeyframeInterpolator<Vector1D> points;
float pointsValue = 0.0;
BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
std::shared_ptr<RenderTreeNodeContentPath> resolvedPath;
};
class TransformOutput {
@ -951,7 +922,7 @@ public:
size_t maxSubitem = std::min(subItems.size(), subItemLimit);
if (_contentItem->path) {
mappedPaths.emplace_back(_contentItem->path.value(), effectiveTransform);
mappedPaths.emplace_back(_contentItem->path->path, effectiveTransform);
}
for (size_t i = 0; i < maxSubitem; i++) {
@ -1012,7 +983,7 @@ public:
_contentItem->isGroup = isGroup;
if (path) {
_contentItem->path = *path->currentPath();
_contentItem->path = path->currentPath();
}
if (!shadings.empty()) {
@ -1052,8 +1023,7 @@ public:
}
if (path) {
path->update(frameTime, boundingBoxContext);
_contentItem->pathBoundingBox = path->currentPathBounds();
path->update(frameTime);
}
for (const auto &trim : trims) {
trim->update(frameTime);