mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Lottie: refactor trimming
This commit is contained in:
parent
9c0be8d8ee
commit
9a4f4ef280
@ -65,6 +65,14 @@ static void enumeratePaths(std::shared_ptr<lottie::RenderTreeNodeContentItem> it
|
||||
|
||||
size_t maxSubitem = std::min(item->subItems.size(), subItemLimit);
|
||||
|
||||
if (item->trimmedPaths) {
|
||||
for (const auto &path : item->trimmedPaths.value()) {
|
||||
onPath(path, effectiveTransform);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->path) {
|
||||
onPath(item->path->path, effectiveTransform);
|
||||
}
|
||||
@ -234,76 +242,11 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> const
|
||||
|
||||
for (const auto &shading : item->shadings) {
|
||||
lottieRendering::CanvasPathEnumerator iteratePaths;
|
||||
if (shading->explicitPath) {
|
||||
auto itemPaths = shading->explicitPath.value();
|
||||
iteratePaths = [itemPaths = itemPaths](std::function<void(lottieRendering::PathCommand const &)> iterate) -> void {
|
||||
iteratePaths = [&](std::function<void(lottieRendering::PathCommand const &)> iterate) {
|
||||
enumeratePaths(item, shading->subItemLimit, lottie::Transform2D::identity(), true, [&](lottie::BezierPath const &sourcePath, lottie::Transform2D const &transform) {
|
||||
auto path = sourcePath.copyUsingTransform(transform);
|
||||
|
||||
lottieRendering::PathCommand pathCommand;
|
||||
for (const auto &path : itemPaths) {
|
||||
std::optional<lottie::PathElement> previousElement;
|
||||
for (const auto &element : path.elements()) {
|
||||
if (previousElement.has_value()) {
|
||||
if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) {
|
||||
pathCommand.type = lottieRendering::PathCommandType::LineTo;
|
||||
pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||
iterate(pathCommand);
|
||||
} else {
|
||||
pathCommand.type = lottieRendering::PathCommandType::CurveTo;
|
||||
pathCommand.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||
pathCommand.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y);
|
||||
pathCommand.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y);
|
||||
iterate(pathCommand);
|
||||
}
|
||||
} else {
|
||||
pathCommand.type = lottieRendering::PathCommandType::MoveTo;
|
||||
pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||
iterate(pathCommand);
|
||||
}
|
||||
previousElement = element;
|
||||
}
|
||||
if (path.closed().value_or(true)) {
|
||||
pathCommand.type = lottieRendering::PathCommandType::Close;
|
||||
iterate(pathCommand);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
iteratePaths = [&](std::function<void(lottieRendering::PathCommand const &)> iterate) {
|
||||
enumeratePaths(item, shading->subItemLimit, lottie::Transform2D::identity(), true, [&](lottie::BezierPath const &sourcePath, lottie::Transform2D const &transform) {
|
||||
auto path = sourcePath.copyUsingTransform(transform);
|
||||
|
||||
lottieRendering::PathCommand pathCommand;
|
||||
std::optional<lottie::PathElement> previousElement;
|
||||
for (const auto &element : path.elements()) {
|
||||
if (previousElement.has_value()) {
|
||||
if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) {
|
||||
pathCommand.type = lottieRendering::PathCommandType::LineTo;
|
||||
pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||
iterate(pathCommand);
|
||||
} else {
|
||||
pathCommand.type = lottieRendering::PathCommandType::CurveTo;
|
||||
pathCommand.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||
pathCommand.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y);
|
||||
pathCommand.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y);
|
||||
iterate(pathCommand);
|
||||
}
|
||||
} else {
|
||||
pathCommand.type = lottieRendering::PathCommandType::MoveTo;
|
||||
pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||
iterate(pathCommand);
|
||||
}
|
||||
previousElement = element;
|
||||
}
|
||||
if (path.closed().value_or(true)) {
|
||||
pathCommand.type = lottieRendering::PathCommandType::Close;
|
||||
iterate(pathCommand);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/*auto iteratePaths = [&](std::function<void(lottieRendering::PathCommand const &)> iterate) -> void {
|
||||
lottieRendering::PathCommand pathCommand;
|
||||
for (const auto &path : itemPaths) {
|
||||
std::optional<lottie::PathElement> previousElement;
|
||||
for (const auto &element : path.elements()) {
|
||||
if (previousElement.has_value()) {
|
||||
@ -329,8 +272,8 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> const
|
||||
pathCommand.type = lottieRendering::PathCommandType::Close;
|
||||
iterate(pathCommand);
|
||||
}
|
||||
}
|
||||
};*/
|
||||
});
|
||||
};
|
||||
|
||||
if (shading->stroke) {
|
||||
if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) {
|
||||
|
@ -131,6 +131,31 @@ public:
|
||||
std::shared_ptr<BezierPathContents> _contents;
|
||||
};
|
||||
|
||||
class PathContents {
|
||||
public:
|
||||
struct Element {
|
||||
Vector2D point;
|
||||
Vector2D cp1;
|
||||
Vector2D cp2;
|
||||
|
||||
explicit Element(Vector2D const &point_, Vector2D const &cp1_, Vector2D const &cp2_) :
|
||||
point(point_),
|
||||
cp1(cp1_),
|
||||
cp2(cp2_) {
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
PathContents(BezierPathContents const &bezierPath);
|
||||
~PathContents();
|
||||
|
||||
std::shared_ptr<BezierPathContents> bezierPath() const;
|
||||
|
||||
private:
|
||||
std::vector<Element> _elements;
|
||||
bool _isClosed = false;
|
||||
};
|
||||
|
||||
class BezierPathsBoundingBoxContext {
|
||||
public:
|
||||
BezierPathsBoundingBoxContext();
|
||||
|
@ -368,6 +368,7 @@ public:
|
||||
float alpha = 0.0;
|
||||
std::optional<TrimParams> trimParams;
|
||||
std::shared_ptr<RenderTreeNodeContentPath> path;
|
||||
std::optional<std::vector<BezierPath>> trimmedPaths;
|
||||
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
|
||||
std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems;
|
||||
int drawContentCount = 0;
|
||||
@ -383,7 +384,6 @@ public:
|
||||
public:
|
||||
std::shared_ptr<RenderTreeNodeContentItem::Stroke> stroke;
|
||||
std::shared_ptr<RenderTreeNodeContentItem::Fill> fill;
|
||||
std::optional<std::vector<BezierPath>> explicitPath;
|
||||
|
||||
size_t subItemLimit = 0;
|
||||
};
|
||||
|
@ -1080,54 +1080,23 @@ public:
|
||||
_contentItem->transform = containerTransform;
|
||||
_contentItem->alpha = containerOpacity;
|
||||
|
||||
if (trim) {
|
||||
_contentItem->trimParams = trim->trimParams();
|
||||
}
|
||||
|
||||
for (int i = 0; i < shadings.size(); i++) {
|
||||
const auto &shadingVariant = shadings[i];
|
||||
if (parentTrim) {
|
||||
_contentItem->trimParams = parentTrim;
|
||||
|
||||
if (!(shadingVariant.fill || shadingVariant.stroke)) {
|
||||
continue;
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(INT32_MAX, Transform2D::identity(), true);
|
||||
for (const auto &path : paths) {
|
||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
}
|
||||
|
||||
//std::optional<TrimParams> currentTrim = parentTrim;
|
||||
//TODO:investigate
|
||||
/*if (!trims.empty()) {
|
||||
currentTrim = trims[0];
|
||||
}*/
|
||||
compoundPath = trimCompoundPath(compoundPath, parentTrim->start, parentTrim->end, parentTrim->offset, parentTrim->type);
|
||||
|
||||
if (parentTrim) {
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, Transform2D::identity(), true);
|
||||
for (const auto &path : paths) {
|
||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
}
|
||||
|
||||
compoundPath = trimCompoundPath(compoundPath, parentTrim->start, parentTrim->end, parentTrim->offset, parentTrim->type);
|
||||
|
||||
std::vector<BezierPath> resultPaths;
|
||||
for (const auto &path : compoundPath.paths) {
|
||||
resultPaths.push_back(path);
|
||||
}
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
} else {
|
||||
if (hasTrims()) {
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, Transform2D::identity(), true);
|
||||
for (const auto &path : paths) {
|
||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
}
|
||||
std::vector<BezierPath> resultPaths;
|
||||
for (const auto &path : compoundPath.paths) {
|
||||
resultPaths.push_back(path);
|
||||
}
|
||||
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
} else {
|
||||
_contentItem->shadings[i]->explicitPath = std::nullopt;
|
||||
}
|
||||
std::vector<BezierPath> resultPaths;
|
||||
for (const auto &path : compoundPath.paths) {
|
||||
resultPaths.push_back(path);
|
||||
}
|
||||
|
||||
_contentItem->trimmedPaths = resultPaths;
|
||||
}
|
||||
|
||||
if (isGroup && !subItems.empty()) {
|
||||
|
@ -687,4 +687,46 @@ CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths) {
|
||||
return calculateBoundingRectOpt(pointsX, pointsY, pointCount);
|
||||
}
|
||||
|
||||
PathContents::PathContents(BezierPathContents const &bezierPath) {
|
||||
std::optional<PathElement> previousElement;
|
||||
for (const auto &element : bezierPath.elements) {
|
||||
if (previousElement.has_value()) {
|
||||
_elements.emplace_back(element.vertex.point, previousElement->vertex.outTangent, element.vertex.inTangent);
|
||||
} else {
|
||||
_elements.emplace_back(element.vertex.point, Vector2D(0.0, 0.0), Vector2D(0.0, 0.0));
|
||||
}
|
||||
previousElement = element;
|
||||
}
|
||||
|
||||
if (bezierPath.closed.value_or(true)) {
|
||||
_isClosed = true;
|
||||
} else {
|
||||
_isClosed = false;
|
||||
}
|
||||
}
|
||||
|
||||
PathContents::~PathContents() {
|
||||
}
|
||||
|
||||
std::shared_ptr<BezierPathContents> PathContents::bezierPath() const {
|
||||
auto result = std::make_shared<BezierPathContents>();
|
||||
|
||||
bool isFirst = true;
|
||||
for (const auto &element : _elements) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result->elements.push_back(PathElement(CurveVertex::absolute(
|
||||
element.point,
|
||||
element.cp1,
|
||||
element.cp2
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
result->closed = _isClosed;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user