2024-06-14 11:49:48 +04:00

225 lines
7.7 KiB
C++

#include "ThorVGCanvasImpl.h"
namespace lottie {
namespace {
void tvgPath(CanvasPathEnumerator const &enumeratePath, tvg::Shape *shape) {
enumeratePath([&](PathCommand const &command) {
switch (command.type) {
case PathCommandType::MoveTo: {
shape->moveTo(command.points[0].x, command.points[0].y);
break;
}
case PathCommandType::LineTo: {
shape->lineTo(command.points[0].x, command.points[0].y);
break;
}
case PathCommandType::CurveTo: {
shape->cubicTo(command.points[0].x, command.points[0].y, command.points[1].x, command.points[1].y, command.points[2].x, command.points[2].y);
break;
}
case PathCommandType::Close: {
shape->close();
break;
}
}
});
}
tvg::Matrix tvgTransform(lottie::Transform2D const &transform) {
tvg::Matrix result;
result.e11 = transform.rows().columns[0][0];
result.e21 = transform.rows().columns[0][1];
result.e31 = transform.rows().columns[0][2];
result.e12 = transform.rows().columns[1][0];
result.e22 = transform.rows().columns[1][1];
result.e32 = transform.rows().columns[1][2];
result.e13 = transform.rows().columns[2][0];
result.e23 = transform.rows().columns[2][1];
result.e33 = transform.rows().columns[2][2];
return result;
}
}
void ThorVGCanvasImpl::initializeOnce() {
tvg::Initializer::init(0);
}
ThorVGCanvasImpl::ThorVGCanvasImpl(int width, int height, int bytesPerRow) :
_transform(lottie::Transform2D::identity()) {
_canvas = tvg::SwCanvas::gen();
_bytesPerRow = bytesPerRow;
_backingData = (uint32_t *)malloc(_bytesPerRow * height);
memset(_backingData, 0, _bytesPerRow * height);
_canvas->target(_backingData, _bytesPerRow / 4, width, height, tvg::SwCanvas::ARGB8888);
}
ThorVGCanvasImpl::~ThorVGCanvasImpl() {
}
void ThorVGCanvasImpl::saveState() {
_stateStack.push_back(_transform);
}
void ThorVGCanvasImpl::restoreState() {
if (_stateStack.empty()) {
assert(false);
return;
}
_transform = _stateStack[_stateStack.size() - 1];
_stateStack.pop_back();
}
void ThorVGCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) {
auto shape = tvg::Shape::gen();
tvgPath(enumeratePath, shape.get());
shape->transform(tvgTransform(_transform));
shape->fill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0));
shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding);
_canvas->push(std::move(shape));
}
void ThorVGCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
auto shape = tvg::Shape::gen();
tvgPath(enumeratePath, shape.get());
shape->transform(tvgTransform(_transform));
auto fill = tvg::LinearGradient::gen();
fill->linear(start.x, start.y, end.x, end.y);
std::vector<tvg::Fill::ColorStop> colors;
for (size_t i = 0; i < gradient.colors().size(); i++) {
const auto &color = gradient.colors()[i];
tvg::Fill::ColorStop colorStop;
colorStop.offset = gradient.locations()[i];
colorStop.r = (int)(color.r * 255.0);
colorStop.g = (int)(color.g * 255.0);
colorStop.b = (int)(color.b * 255.0);
colorStop.a = (int)(color.a * 255.0);
colors.push_back(colorStop);
}
fill->colorStops(colors.data(), (uint32_t)colors.size());
shape->fill(std::move(fill));
shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding);
_canvas->push(std::move(shape));
}
void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, Vector2D const &center, float radius) {
auto shape = tvg::Shape::gen();
tvgPath(enumeratePath, shape.get());
shape->transform(tvgTransform(_transform));
auto fill = tvg::RadialGradient::gen();
fill->radial(center.x, center.y, radius);
std::vector<tvg::Fill::ColorStop> colors;
for (size_t i = 0; i < gradient.colors().size(); i++) {
const auto &color = gradient.colors()[i];
tvg::Fill::ColorStop colorStop;
colorStop.offset = gradient.locations()[i];
colorStop.r = (int)(color.r * 255.0);
colorStop.g = (int)(color.g * 255.0);
colorStop.b = (int)(color.b * 255.0);
colorStop.a = (int)(color.a * 255.0);
colors.push_back(colorStop);
}
fill->colorStops(colors.data(), (uint32_t)colors.size());
shape->fill(std::move(fill));
shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding);
_canvas->push(std::move(shape));
}
void ThorVGCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) {
auto shape = tvg::Shape::gen();
tvgPath(enumeratePath, shape.get());
shape->transform(tvgTransform(_transform));
shape->strokeFill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0));
shape->strokeWidth(lineWidth);
switch (lineJoin) {
case lottie::LineJoin::Miter: {
shape->strokeJoin(tvg::StrokeJoin::Miter);
break;
}
case lottie::LineJoin::Round: {
shape->strokeJoin(tvg::StrokeJoin::Round);
break;
}
case lottie::LineJoin::Bevel: {
shape->strokeJoin(tvg::StrokeJoin::Bevel);
break;
}
default: {
shape->strokeJoin(tvg::StrokeJoin::Bevel);
break;
}
}
switch (lineCap) {
case lottie::LineCap::Butt: {
shape->strokeCap(tvg::StrokeCap::Butt);
break;
}
case lottie::LineCap::Round: {
shape->strokeCap(tvg::StrokeCap::Round);
break;
}
case lottie::LineCap::Square: {
shape->strokeCap(tvg::StrokeCap::Square);
break;
}
default: {
shape->strokeCap(tvg::StrokeCap::Square);
break;
}
}
if (!dashPattern.empty()) {
std::vector<float> intervals;
intervals.reserve(dashPattern.size());
for (auto value : dashPattern) {
intervals.push_back(value);
}
shape->strokeDash(intervals.data(), (uint32_t)intervals.size());
//TODO:phase
}
_canvas->push(std::move(shape));
}
void ThorVGCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
}
void ThorVGCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
}
void ThorVGCanvasImpl::concatenate(lottie::Transform2D const &transform) {
_transform = transform * _transform;
}
void ThorVGCanvasImpl::flush() {
_canvas->draw();
_canvas->sync();
_statsNumStrokes = 0;
}
}