Refactoring

This commit is contained in:
Isaac 2024-05-18 20:23:38 +04:00
parent 6bebe70b4a
commit b6ba0d8f99
17 changed files with 44 additions and 347 deletions

View File

@ -292,13 +292,13 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
namespace { namespace {
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> parentContext, std::shared_ptr<lottie::RenderTreeNodeContentItem> item, double parentAlpha) { static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> parentContext, std::shared_ptr<lottie::RenderTreeNodeContentItem> item, float parentAlpha) {
if (!item->renderData.isValid) { if (!item->renderData.isValid) {
return; return;
} }
float normalizedOpacity = item->renderData.layer.opacity(); float normalizedOpacity = item->renderData.layer.opacity();
double layerAlpha = ((double)normalizedOpacity) * parentAlpha; float layerAlpha = ((float)normalizedOpacity) * parentAlpha;
if (item->renderData.layer.isHidden() || normalizedOpacity == 0.0f) { if (item->renderData.layer.isHidden() || normalizedOpacity == 0.0f) {
return; return;
@ -329,7 +329,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.layer.bounds().x, -item->renderData.layer.bounds().y))); parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.layer.bounds().x, -item->renderData.layer.bounds().y)));
parentContext->concatenate(item->renderData.layer.transform()); parentContext->concatenate(item->renderData.layer.transform());
double renderAlpha = 1.0; float renderAlpha = 1.0;
if (tempContext) { if (tempContext) {
renderAlpha = 1.0; renderAlpha = 1.0;
} else { } else {
@ -530,12 +530,12 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
parentContext->restoreState(); parentContext->restoreState();
} }
static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, double parentAlpha) { static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, float parentAlpha) {
if (!node->renderData.isValid) { if (!node->renderData.isValid) {
return; return;
} }
float normalizedOpacity = node->renderData.layer.opacity(); float normalizedOpacity = node->renderData.layer.opacity();
double layerAlpha = ((double)normalizedOpacity) * parentAlpha; float layerAlpha = ((float)normalizedOpacity) * parentAlpha;
if (node->renderData.layer.isHidden() || normalizedOpacity == 0.0f) { if (node->renderData.layer.isHidden() || normalizedOpacity == 0.0f) {
return; return;
@ -587,7 +587,7 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-node->renderData.layer.bounds().x, -node->renderData.layer.bounds().y))); parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-node->renderData.layer.bounds().x, -node->renderData.layer.bounds().y)));
parentContext->concatenate(node->renderData.layer.transform()); parentContext->concatenate(node->renderData.layer.transform());
double renderAlpha = 1.0; float renderAlpha = 1.0;
if (tempContext) { if (tempContext) {
renderAlpha = 1.0; renderAlpha = 1.0;
} else { } else {
@ -661,7 +661,7 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) {
return nil; return nil;
} }
processRenderTree(renderNode, lottie::Vector2D((int)size.width, (int)size.height), lottie::CATransform3D::identity().scaled(lottie::Vector2D(size.width / (double)animation.size.width, size.height / (double)animation.size.height)), false, *_bezierPathsBoundingBoxContext.get()); processRenderTree(renderNode, lottie::Vector2D((int)size.width, (int)size.height), lottie::CATransform3D::identity().scaled(lottie::Vector2D(size.width / (float)animation.size.width, size.height / (float)animation.size.height)), false, *_bezierPathsBoundingBoxContext.get());
if (useReferenceRendering) { if (useReferenceRendering) {
auto context = std::make_shared<lottieRendering::CanvasImpl>((int)size.width, (int)size.height); auto context = std::make_shared<lottieRendering::CanvasImpl>((int)size.width, (int)size.height);

View File

@ -1,7 +1,5 @@
#include "CompositionLayer.hpp" #include "CompositionLayer.hpp"
#include "Lottie/Public/Primitives/RenderTree.hpp"
namespace lottie { namespace lottie {
InvertedMatteLayer::InvertedMatteLayer(std::shared_ptr<CompositionLayer> inputMatte) : InvertedMatteLayer::InvertedMatteLayer(std::shared_ptr<CompositionLayer> inputMatte) :

View File

@ -90,10 +90,10 @@ public:
} }
} }
AnimationFrameTime startFrame = getDouble(json, "ip"); AnimationFrameTime startFrame = (float)getDouble(json, "ip");
AnimationFrameTime endFrame = getDouble(json, "op"); AnimationFrameTime endFrame = (float)getDouble(json, "op");
float framerate = getDouble(json, "fr"); float framerate = (float)getDouble(json, "fr");
int width = getInt(json, "w"); int width = getInt(json, "w");
int height = getInt(json, "h"); int height = getInt(json, "h");

View File

@ -33,8 +33,8 @@ public:
Asset(json) { Asset(json) {
name = getString(json, "p"); name = getString(json, "p");
directory = getString(json, "u"); directory = getString(json, "u");
width = getDouble(json, "w"); width = (float)getDouble(json, "w");
height = getDouble(json, "h"); height = (float)getDouble(json, "h");
_e = getOptionalInt(json, "e"); _e = getOptionalInt(json, "e");
_t = getOptionalString(json, "t"); _t = getOptionalString(json, "t");

View File

@ -23,7 +23,9 @@ public:
explicit PrecompAsset(lottiejson11::Json::object const &json) noexcept(false) : explicit PrecompAsset(lottiejson11::Json::object const &json) noexcept(false) :
Asset(json) { Asset(json) {
frameRate = getOptionalDouble(json, "fr"); if (const auto frameRateValue = getOptionalDouble(json, "fr")) {
frameRate = (float)frameRateValue.value();
}
auto layerDictionaries = getObjectArray(json, "layers"); auto layerDictionaries = getObjectArray(json, "layers");
for (size_t i = 0; i < layerDictionaries.size(); i++) { for (size_t i = 0; i < layerDictionaries.size(); i++) {

View File

@ -71,9 +71,9 @@ public:
coordinateSpace = std::nullopt; coordinateSpace = std::nullopt;
} }
inFrame = getDouble(json, "ip"); inFrame = (float)getDouble(json, "ip");
outFrame = getDouble(json, "op"); outFrame = (float)getDouble(json, "op");
startTime = getDouble(json, "st"); startTime = (float)getDouble(json, "st");
transform = std::make_shared<Transform>(getObject(json, "ks")); transform = std::make_shared<Transform>(getObject(json, "ks"));
parent = getOptionalInt(json, "parent"); parent = getOptionalInt(json, "parent");
@ -141,7 +141,7 @@ public:
} }
if (const auto timeStretchData = getOptionalDouble(json, "sr")) { if (const auto timeStretchData = getOptionalDouble(json, "sr")) {
_timeStretch = timeStretchData.value(); _timeStretch = (float)timeStretchData.value();
} }
if (const auto matteRawValue = getOptionalInt(json, "tt")) { if (const auto matteRawValue = getOptionalInt(json, "tt")) {

View File

@ -19,8 +19,8 @@ public:
if (const auto timeRemappingData = getOptionalObject(json, "tm")) { if (const auto timeRemappingData = getOptionalObject(json, "tm")) {
timeRemapping = KeyframeGroup<Vector1D>(timeRemappingData.value()); timeRemapping = KeyframeGroup<Vector1D>(timeRemappingData.value());
} }
width = getDouble(json, "w"); width = (float)getDouble(json, "w");
height = getDouble(json, "h"); height = (float)getDouble(json, "h");
} }
virtual ~PreCompLayerModel() = default; virtual ~PreCompLayerModel() = default;

View File

@ -12,8 +12,8 @@ public:
explicit SolidLayerModel(lottiejson11::Json::object const &json) noexcept(false) : explicit SolidLayerModel(lottiejson11::Json::object const &json) noexcept(false) :
LayerModel(json) { LayerModel(json) {
colorHex = getString(json, "sc"); colorHex = getString(json, "sc");
width = getDouble(json, "sw"); width = (float)getDouble(json, "sw");
height = getDouble(json, "sh"); height = (float)getDouble(json, "sh");
} }
virtual ~SolidLayerModel() = default; virtual ~SolidLayerModel() = default;

View File

@ -20,7 +20,7 @@ public:
explicit Marker(lottiejson11::Json::object const &json) noexcept(false) { explicit Marker(lottiejson11::Json::object const &json) noexcept(false) {
name = getString(json, "cm"); name = getString(json, "cm");
frameTime = getDouble(json, "tm"); frameTime = (float)getDouble(json, "tm");
dr = getOptionalInt(json, "dr"); dr = getOptionalInt(json, "dr");
} }

View File

@ -91,7 +91,7 @@ public:
} }
if (const auto miterLimitData = getOptionalDouble(json, "ml")) { if (const auto miterLimitData = getOptionalDouble(json, "ml")) {
miterLimit = miterLimitData.value(); miterLimit = (float)miterLimitData.value();
} }
auto colorsContainer = getObject(json, "g"); auto colorsContainer = getObject(json, "g");

View File

@ -65,7 +65,7 @@ public:
} }
if (const auto miterLimitData = getOptionalDouble(json, "ml")) { if (const auto miterLimitData = getOptionalDouble(json, "ml")) {
miterLimit = miterLimitData.value(); miterLimit = (float)miterLimitData.value();
} }
if (const auto dashElementsData = getOptionalObjectArray(json, "d")) { if (const auto dashElementsData = getOptionalObjectArray(json, "d")) {

View File

@ -29,7 +29,7 @@ public:
weight = getOptionalString(json, "fWeight"); weight = getOptionalString(json, "fWeight");
fontClass = getOptionalString(json, "fClass"); fontClass = getOptionalString(json, "fClass");
style = getString(json, "fStyle"); style = getString(json, "fStyle");
ascent = getDouble(json, "ascent"); ascent = (float)getDouble(json, "ascent");
origin = getOptionalInt(json, "origin"); origin = getOptionalInt(json, "origin");
} }

View File

@ -34,10 +34,10 @@ public:
fontStyle(""), fontStyle(""),
width(0.0) { width(0.0) {
character = getString(json, "ch"); character = getString(json, "ch");
fontSize = getDouble(json, "size"); fontSize = (float)getDouble(json, "size");
fontFamily = getString(json, "fFamily"); fontFamily = getString(json, "fFamily");
fontStyle = getString(json, "style"); fontStyle = getString(json, "style");
width = getDouble(json, "w"); width = (float)getDouble(json, "w");
if (const auto shapeContainer = getOptionalObject(json, "data")) { if (const auto shapeContainer = getOptionalObject(json, "data")) {
internalHasData = true; internalHasData = true;

View File

@ -62,7 +62,7 @@ public:
lottiejson11::Json::object const &json = jsonAny.object_items(); lottiejson11::Json::object const &json = jsonAny.object_items();
text = getString(json, "t"); text = getString(json, "t");
fontSize = getDouble(json, "s"); fontSize = (float)getDouble(json, "s");
fontFamily = getString(json, "f"); fontFamily = getString(json, "f");
auto justificationRawValue = getInt(json, "j"); auto justificationRawValue = getInt(json, "j");
@ -81,8 +81,10 @@ public:
} }
tracking = getInt(json, "tr"); tracking = getInt(json, "tr");
lineHeight = getDouble(json, "lh"); lineHeight = (float)getDouble(json, "lh");
baseline = getOptionalDouble(json, "ls"); if (const auto baselineValue = getOptionalDouble(json, "ls")) {
baseline = (float)baselineValue.value();
}
if (const auto fillColorDataValue = getOptionalAny(json, "fc")) { if (const auto fillColorDataValue = getOptionalAny(json, "fc")) {
fillColorData = Color(fillColorDataValue.value()); fillColorData = Color(fillColorDataValue.value());
@ -92,8 +94,12 @@ public:
strokeColorData = Color(strokeColorDataValue.value()); strokeColorData = Color(strokeColorDataValue.value());
} }
strokeWidth = getOptionalDouble(json, "sw"); if (const auto strokeWidthValue = getOptionalDouble(json, "sw")) {
strokeOverFill = getOptionalBool(json, "of"); strokeWidth = (float)strokeWidthValue.value();
}
if (const auto strokeOverFillValue = getOptionalBool(json, "of")) {
strokeOverFill = (float)strokeOverFillValue.value();
}
if (const auto textFramePositionData = getOptionalAny(json, "ps")) { if (const auto textFramePositionData = getOptionalAny(json, "ps")) {
textFramePosition = Vector3D(textFramePositionData.value()); textFramePosition = Vector3D(textFramePositionData.value());

View File

@ -162,7 +162,10 @@ public:
endValue = T(endValueData.value()); endValue = T(endValueData.value());
} }
time = getOptionalDouble(json.object_items(), "t"); if (const auto timeValue = getOptionalDouble(json.object_items(), "t")) {
time = (float)timeValue.value();
}
hold = getOptionalInt(json.object_items(), "h"); hold = getOptionalInt(json.object_items(), "h");
if (const auto inTangentData = getOptionalObject(json.object_items(), "i")) { if (const auto inTangentData = getOptionalObject(json.object_items(), "i")) {

View File

@ -1,140 +0,0 @@
#include "RenderTree.hpp"
namespace lottie {
BoundingBoxNode::BoundingBoxNode(
LayerParams const &layer_,
CGRect const &globalRect_,
CGRect const &localRect_,
CATransform3D const &globalTransform_,
bool drawsContent_,
std::shared_ptr<RenderableItem> renderableItem_,
bool isInvertedMatte_,
std::vector<std::shared_ptr<BoundingBoxNode>> const &subnodes_,
std::shared_ptr<BoundingBoxNode> const &mask_
) :
layer(layer_),
globalRect(globalRect_),
localRect(localRect_),
globalTransform(globalTransform_),
drawsContent(drawsContent_),
renderableItem(renderableItem_),
isInvertedMatte(isInvertedMatte_),
subnodes(subnodes_),
mask(mask_) {
}
std::shared_ptr<BoundingBoxNode> boundingBoxTree(std::shared_ptr<CALayer> const &layer, Vector2D const &globalSize, CATransform3D const &parentTransform) {
if (layer->isHidden() || layer->opacity() == 0.0f) {
return nullptr;
}
if (layer->masksToBounds()) {
if (layer->bounds().empty()) {
return nullptr;
}
}
auto currentTransform = parentTransform;
currentTransform = currentTransform.translated(Vector2D(layer->position().x, layer->position().y));
currentTransform = currentTransform.translated(Vector2D(-layer->bounds().x, -layer->bounds().y));
currentTransform = layer->transform() * currentTransform;
if (!currentTransform.isInvertible()) {
return nullptr;
}
std::optional<CGRect> effectiveLocalBounds;
auto renderableItem = layer->renderableItem();
if (renderableItem) {
effectiveLocalBounds = renderableItem->boundingRect();
} else if (layer->implementsDraw()) {
effectiveLocalBounds = layer->bounds();
}
bool isInvertedMatte = layer->isInvertedMatte();
if (isInvertedMatte) {
effectiveLocalBounds = layer->bounds();
}
if (effectiveLocalBounds && effectiveLocalBounds->empty()) {
effectiveLocalBounds = std::nullopt;
}
std::vector<std::shared_ptr<BoundingBoxNode>> subnodes;
std::optional<CGRect> subnodesGlobalRect;
for (const auto &sublayer : layer->sublayers()) {
if (const auto subnode = boundingBoxTree(sublayer, globalSize, currentTransform)) {
subnodes.push_back(subnode);
if (subnodesGlobalRect) {
subnodesGlobalRect = subnodesGlobalRect->unionWith(subnode->globalRect);
} else {
subnodesGlobalRect = subnode->globalRect;
}
}
}
std::optional<CGRect> fuzzyGlobalRect;
if (effectiveLocalBounds) {
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
if (fuzzyGlobalRect) {
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(effectiveGlobalBounds);
} else {
fuzzyGlobalRect = effectiveGlobalBounds;
}
}
if (subnodesGlobalRect) {
if (fuzzyGlobalRect) {
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(subnodesGlobalRect.value());
} else {
fuzzyGlobalRect = subnodesGlobalRect;
}
}
if (!fuzzyGlobalRect) {
return nullptr;
}
CGRect globalRect(
std::floor(fuzzyGlobalRect->x),
std::floor(fuzzyGlobalRect->y),
std::ceil(fuzzyGlobalRect->width + fuzzyGlobalRect->x - floor(fuzzyGlobalRect->x)),
std::ceil(fuzzyGlobalRect->height + fuzzyGlobalRect->y - floor(fuzzyGlobalRect->y))
);
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(globalRect)) {
return nullptr;
}
std::shared_ptr<BoundingBoxNode> maskNode;
if (layer->mask()) {
if (const auto maskNodeValue = boundingBoxTree(layer->mask(), globalSize, currentTransform)) {
if (!maskNodeValue->globalRect.intersects(globalRect)) {
return nullptr;
}
maskNode = maskNodeValue;
} else {
return nullptr;
}
}
return std::make_shared<BoundingBoxNode>(
layer,
globalRect,
CGRect(0.0, 0.0, 0.0, 0.0),
currentTransform,
effectiveLocalBounds.has_value(),
renderableItem,
isInvertedMatte,
subnodes,
maskNode
);
}
}

View File

@ -1,172 +0,0 @@
#ifndef RenderTree_hpp
#define RenderTree_hpp
#include <memory>
#include <LottieCpp/Vectors.h>
#include "Lottie/Public/Primitives/CALayer.hpp"
namespace lottie {
struct BoundingBoxNode {
struct LayerParams {
CGRect _bounds;
Vector2D _position;
CATransform3D _transform;
double _opacity;
bool _masksToBounds;
bool _isHidden;
LayerParams(
CGRect bounds_,
Vector2D position_,
CATransform3D transform_,
double opacity_,
bool masksToBounds_,
bool isHidden_
) :
_bounds(bounds_),
_position(position_),
_transform(transform_),
_opacity(opacity_),
_masksToBounds(masksToBounds_),
_isHidden(isHidden_) {
}
LayerParams(std::shared_ptr<CALayer> const &layer) :
_bounds(layer->bounds()),
_position(layer->position()),
_transform(layer->transform()),
_opacity(layer->opacity()),
_masksToBounds(layer->masksToBounds()),
_isHidden(layer->isHidden()) {
}
bool operator==(LayerParams const &rhs) const {
if (_bounds != rhs._bounds) {
return false;
}
if (_position != rhs._position) {
return false;
}
if (_transform != rhs._transform) {
return false;
}
if (_opacity != rhs._opacity) {
return false;
}
if (_masksToBounds != rhs._masksToBounds) {
return false;
}
if (_isHidden != rhs._isHidden) {
return false;
}
return true;
}
bool operator!=(LayerParams const &rhs) const {
return !(*this == rhs);
}
CGRect bounds() const {
return _bounds;
}
Vector2D position() const {
return _position;
}
CATransform3D transform() const {
return _transform;
}
double opacity() const {
return _opacity;
}
bool masksToBounds() const {
return _masksToBounds;
}
bool isHidden() const {
return _isHidden;
}
};
LayerParams layer;
CGRect globalRect;
CGRect localRect;
CATransform3D globalTransform;
bool drawsContent;
std::shared_ptr<RenderableItem> renderableItem;
bool isInvertedMatte;
std::vector<std::shared_ptr<BoundingBoxNode>> subnodes;
std::shared_ptr<BoundingBoxNode> mask;
explicit BoundingBoxNode(
LayerParams const &layer_,
CGRect const &globalRect_,
CGRect const &localRect_,
CATransform3D const &globalTransform_,
bool drawsContent_,
std::shared_ptr<RenderableItem> renderableItem_,
bool isInvertedMatte_,
std::vector<std::shared_ptr<BoundingBoxNode>> const &subnodes_,
std::shared_ptr<BoundingBoxNode> const &mask_
);
bool operator==(BoundingBoxNode const &rhs) const {
if (layer != rhs.layer) {
return false;
}
if (globalRect != rhs.globalRect) {
return false;
}
if (localRect != rhs.localRect) {
return false;
}
if (globalTransform != rhs.globalTransform) {
return false;
}
if (drawsContent != rhs.drawsContent) {
return false;
}
if ((renderableItem == nullptr) != (rhs.renderableItem == nullptr)) {
return false;
} else if (renderableItem) {
if (!renderableItem->isEqual(rhs.renderableItem)) {
return false;
}
}
if (isInvertedMatte != rhs.isInvertedMatte) {
return false;
}
if (subnodes.size() != rhs.subnodes.size()) {
return false;
} else {
for (size_t i = 0; i < subnodes.size(); i++) {
if ((*subnodes[i].get()) != (*rhs.subnodes[i].get())) {
return false;
}
}
}
if ((mask == nullptr) != (rhs.mask == nullptr)) {
return false;
} else if (mask) {
if ((*mask.get()) != *(rhs.mask.get())) {
return false;
}
}
return true;
}
bool operator!=(BoundingBoxNode const &rhs) const {
return !(*this == rhs);
}
};
std::shared_ptr<BoundingBoxNode> boundingBoxTree(std::shared_ptr<CALayer> const &layer, Vector2D const &globalSize, CATransform3D const &parentTransform);
}
#endif /* RenderTree_hpp */