mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Refactor trims
This commit is contained in:
parent
ebb7798cff
commit
c9e42893e0
@ -6,6 +6,48 @@
|
||||
|
||||
#include <LottieCpp/RenderTreeNode.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct TransformedPath {
|
||||
lottie::BezierPath path;
|
||||
lottie::CATransform3D transform;
|
||||
|
||||
TransformedPath(lottie::BezierPath const &path_, lottie::CATransform3D const &transform_) :
|
||||
path(path_),
|
||||
transform(transform_) {
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<TransformedPath> collectPaths(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) {
|
||||
std::vector<TransformedPath> mappedPaths;
|
||||
|
||||
//TODO:remove skipApplyTransform
|
||||
lottie::CATransform3D effectiveTransform = parentTransform;
|
||||
if (!skipApplyTransform && item->isGroup) {
|
||||
effectiveTransform = item->transform * effectiveTransform;
|
||||
}
|
||||
|
||||
size_t maxSubitem = std::min(item->subItems.size(), subItemLimit);
|
||||
|
||||
if (item->path) {
|
||||
mappedPaths.emplace_back(item->path.value(), effectiveTransform);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < maxSubitem; i++) {
|
||||
auto &subItem = item->subItems[i];
|
||||
|
||||
auto subItemPaths = collectPaths(subItem, INT32_MAX, effectiveTransform, false);
|
||||
|
||||
for (auto &path : subItemPaths) {
|
||||
mappedPaths.emplace_back(path.path, path.transform);
|
||||
}
|
||||
}
|
||||
|
||||
return mappedPaths;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace lottie {
|
||||
|
||||
static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem> const &contentItem, Vector2D const &globalSize, CATransform3D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
|
||||
@ -24,7 +66,17 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
|
||||
int drawContentDescendants = 0;
|
||||
|
||||
for (const auto &shadingVariant : contentItem->shadings) {
|
||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shadingVariant->explicitPath.value());
|
||||
std::vector<lottie::BezierPath> itemPaths;
|
||||
if (shadingVariant->explicitPath) {
|
||||
itemPaths = shadingVariant->explicitPath.value();
|
||||
} else {
|
||||
auto rawPaths = collectPaths(contentItem, shadingVariant->subItemLimit, lottie::CATransform3D::identity(), true);
|
||||
for (const auto &rawPath : rawPaths) {
|
||||
itemPaths.push_back(rawPath.path.copyUsingTransform(rawPath.transform));
|
||||
}
|
||||
}
|
||||
|
||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, itemPaths);
|
||||
if (shadingVariant->stroke) {
|
||||
shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0);
|
||||
} else if (shadingVariant->fill) {
|
||||
@ -42,6 +94,7 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
|
||||
}
|
||||
}
|
||||
|
||||
if (contentItem->isGroup) {
|
||||
for (const auto &subItem : contentItem->subItems) {
|
||||
processRenderContentItem(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
||||
|
||||
@ -54,6 +107,11 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &subItem : contentItem->subItems) {
|
||||
subItem->renderData.isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalRect) {
|
||||
contentItem->renderData.isValid = false;
|
||||
@ -257,7 +315,17 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
|
||||
}
|
||||
|
||||
for (const auto &shading : item->shadings) {
|
||||
if (shading->explicitPath->empty()) {
|
||||
std::vector<lottie::BezierPath> itemPaths;
|
||||
if (shading->explicitPath) {
|
||||
itemPaths = shading->explicitPath.value();
|
||||
} else {
|
||||
auto rawPaths = collectPaths(item, shading->subItemLimit, lottie::CATransform3D::identity(), true);
|
||||
for (const auto &rawPath : rawPaths) {
|
||||
itemPaths.push_back(rawPath.path.copyUsingTransform(rawPath.transform));
|
||||
}
|
||||
}
|
||||
|
||||
if (itemPaths.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -288,7 +356,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
|
||||
};
|
||||
|
||||
LottiePathItem pathItem;
|
||||
for (const auto &path : shading->explicitPath.value()) {
|
||||
for (const auto &path : itemPaths) {
|
||||
std::optional<lottie::PathElement> previousElement;
|
||||
for (const auto &element : path.elements()) {
|
||||
if (previousElement.has_value()) {
|
||||
|
@ -78,7 +78,7 @@ private final class ReferenceCompareTest {
|
||||
}
|
||||
|
||||
var continueFromName: String?
|
||||
//continueFromName = "1391391008142393362.json"
|
||||
//continueFromName = "778160933443732778.json"
|
||||
|
||||
let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in
|
||||
if let continueFromNameValue = continueFromName {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <LottieCpp/CurveVertex.h>
|
||||
#include <LottieCpp/PathElement.h>
|
||||
#include <LottieCpp/CGPath.h>
|
||||
#include <LottieCpp/ShapeAttributes.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -126,7 +127,7 @@ public:
|
||||
public:
|
||||
BezierPath(std::shared_ptr<BezierPathContents> contents);
|
||||
|
||||
private:
|
||||
public:
|
||||
std::shared_ptr<BezierPathContents> _contents;
|
||||
};
|
||||
|
||||
@ -144,6 +145,8 @@ public:
|
||||
CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths);
|
||||
CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, std::vector<BezierPath> const &paths);
|
||||
|
||||
std::vector<BezierPath> trimBezierPaths(std::vector<BezierPath> &sourcePaths, double start, double end, double offset, TrimType type);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -422,6 +422,8 @@ public:
|
||||
bool isGroup = false;
|
||||
CATransform3D transform = CATransform3D::identity();
|
||||
double alpha = 0.0;
|
||||
std::optional<TrimParams> trimParams;
|
||||
std::optional<BezierPath> path;
|
||||
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
|
||||
std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems;
|
||||
|
||||
|
@ -31,6 +31,27 @@ enum class GradientType: int {
|
||||
Radial = 2
|
||||
};
|
||||
|
||||
enum class TrimType: int {
|
||||
Simultaneously = 1,
|
||||
Individually = 2
|
||||
};
|
||||
|
||||
struct TrimParams {
|
||||
double start = 0.0;
|
||||
double end = 0.0;
|
||||
double offset = 0.0;
|
||||
TrimType type = TrimType::Simultaneously;
|
||||
size_t subItemLimit = 0;
|
||||
|
||||
TrimParams(double start_, double end_, double offset_, TrimType type_, size_t subItemLimit_) :
|
||||
start(start_),
|
||||
end(end_),
|
||||
offset(offset_),
|
||||
type(type_),
|
||||
subItemLimit(subItemLimit_) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -437,22 +437,6 @@ public:
|
||||
std::shared_ptr<RenderTreeNodeContentItem::Stroke> _stroke;
|
||||
};
|
||||
|
||||
struct TrimParams {
|
||||
double start = 0.0;
|
||||
double end = 0.0;
|
||||
double offset = 0.0;
|
||||
TrimType type = TrimType::Simultaneously;
|
||||
size_t subItemLimit = 0;
|
||||
|
||||
TrimParams(double start_, double end_, double offset_, TrimType type_, size_t subItemLimit_) :
|
||||
start(start_),
|
||||
end(end_),
|
||||
offset(offset_),
|
||||
type(type_),
|
||||
subItemLimit(subItemLimit_) {
|
||||
}
|
||||
};
|
||||
|
||||
class TrimParamsOutput {
|
||||
public:
|
||||
TrimParamsOutput(Trim const &trim, size_t subItemLimit) :
|
||||
@ -597,7 +581,7 @@ public:
|
||||
}
|
||||
|
||||
if (hasUpdates) {
|
||||
resolvedPath = makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction);
|
||||
ValueInterpolator<BezierPath>::setInplace(makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction), resolvedPath);
|
||||
}
|
||||
|
||||
hasValidData = true;
|
||||
@ -645,7 +629,7 @@ public:
|
||||
}
|
||||
|
||||
if (hasUpdates) {
|
||||
resolvedPath = makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction);
|
||||
ValueInterpolator<BezierPath>::setInplace(makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction), resolvedPath);
|
||||
}
|
||||
|
||||
hasValidData = true;
|
||||
@ -732,7 +716,7 @@ public:
|
||||
}
|
||||
|
||||
if (hasUpdates) {
|
||||
resolvedPath = makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction);
|
||||
ValueInterpolator<BezierPath>::setInplace(makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction), resolvedPath);
|
||||
}
|
||||
|
||||
hasValidData = true;
|
||||
@ -916,15 +900,19 @@ public:
|
||||
std::vector<ShadingVariant> shadings;
|
||||
std::vector<std::shared_ptr<TrimParamsOutput>> trims;
|
||||
|
||||
std::vector<std::shared_ptr<ContentItem>> subItems;
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<ContentItem>> subItems;
|
||||
std::shared_ptr<RenderTreeNodeContentItem> _contentItem;
|
||||
|
||||
private:
|
||||
std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D const &parentTransform, bool skipApplyTransform) {
|
||||
bool hasTrims(size_t subItemLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D const &parentTransform, bool skipApplyTransform, bool &hasTrims) {
|
||||
std::vector<TransformedPath> mappedPaths;
|
||||
|
||||
//TODO:remove skipApplyTransform
|
||||
CATransform3D effectiveTransform = parentTransform;
|
||||
if (!skipApplyTransform && isGroup && transform) {
|
||||
effectiveTransform = transform->transform() * effectiveTransform;
|
||||
@ -932,8 +920,8 @@ public:
|
||||
|
||||
size_t maxSubitem = std::min(subItems.size(), subItemLimit);
|
||||
|
||||
if (path) {
|
||||
mappedPaths.emplace_back(*(path->currentPath()), effectiveTransform);
|
||||
if (_contentItem->path) {
|
||||
mappedPaths.emplace_back(_contentItem->path.value(), effectiveTransform);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < maxSubitem; i++) {
|
||||
@ -944,9 +932,10 @@ public:
|
||||
currentTrim = trims[0]->trimParams();
|
||||
}
|
||||
|
||||
auto subItemPaths = subItem->collectPaths(INT32_MAX, effectiveTransform, false);
|
||||
auto subItemPaths = subItem->collectPaths(INT32_MAX, effectiveTransform, false, hasTrims);
|
||||
|
||||
if (currentTrim) {
|
||||
hasTrims = true;
|
||||
CompoundBezierPath tempPath;
|
||||
for (auto &path : subItemPaths) {
|
||||
tempPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
@ -993,6 +982,10 @@ public:
|
||||
_contentItem = std::make_shared<RenderTreeNodeContentItem>();
|
||||
_contentItem->isGroup = isGroup;
|
||||
|
||||
if (path) {
|
||||
_contentItem->path = *path->currentPath();
|
||||
}
|
||||
|
||||
if (!shadings.empty()) {
|
||||
for (int i = 0; i < shadings.size(); i++) {
|
||||
auto &shadingVariant = shadings[i];
|
||||
@ -1031,6 +1024,8 @@ public:
|
||||
|
||||
if (path) {
|
||||
path->update(frameTime);
|
||||
} else {
|
||||
_contentItem->path = std::nullopt;
|
||||
}
|
||||
for (const auto &trim : trims) {
|
||||
trim->update(frameTime);
|
||||
@ -1067,28 +1062,46 @@ public:
|
||||
continue;
|
||||
}
|
||||
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::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];
|
||||
}*/
|
||||
|
||||
bool hasTrims = false;
|
||||
if (parentTrim) {
|
||||
compoundPath = trimCompoundPath(compoundPath, parentTrim->start, parentTrim->end, parentTrim->offset, parentTrim->type);
|
||||
CompoundBezierPath compoundPath;
|
||||
hasTrims = true;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true, hasTrims);
|
||||
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 {
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true, hasTrims);
|
||||
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);
|
||||
}
|
||||
|
||||
if (hasTrims) {
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
} else {
|
||||
_contentItem->shadings[i]->explicitPath = std::nullopt;
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isGroup && !subItems.empty()) {
|
||||
@ -1199,7 +1212,16 @@ private:
|
||||
case ShapeType::Trim: {
|
||||
Trim const &trim = *((Trim *)item.get());
|
||||
|
||||
itemTree->addTrim(trim);
|
||||
auto groupItem = std::make_shared<ContentItem>();
|
||||
groupItem->isGroup = true;
|
||||
for (const auto &subItem : itemTree->subItems) {
|
||||
groupItem->addSubItem(subItem);
|
||||
}
|
||||
groupItem->addTrim(trim);
|
||||
itemTree->subItems.clear();
|
||||
itemTree->addSubItem(groupItem);
|
||||
|
||||
//itemTree->addTrim(trim);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -8,11 +8,6 @@
|
||||
|
||||
namespace lottie {
|
||||
|
||||
enum class TrimType: int {
|
||||
Simultaneously = 1,
|
||||
Individually = 2
|
||||
};
|
||||
|
||||
/// An item that defines trim
|
||||
class Trim: public ShapeItem {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user