From 90577029f2490089a54643654f4832fedd2fe18a Mon Sep 17 00:00:00 2001 From: subhransu mohanty Date: Thu, 15 Nov 2018 17:19:13 +0900 Subject: [PATCH] lottie/feature: Added 3D layer support in lottie player. Change-Id: I1f37f299761570d08ef9bda39a66df757b215e5a --- example/resource/3d.json | 1 + src/lottie/lottiemodel.cpp | 21 ++++++++++++++++----- src/lottie/lottiemodel.h | 33 +++++++++++++++++++++------------ src/lottie/lottieparser.cpp | 23 ++++++++++++++++++++--- 4 files changed, 58 insertions(+), 20 deletions(-) create mode 100755 example/resource/3d.json diff --git a/example/resource/3d.json b/example/resource/3d.json new file mode 100755 index 0000000..a5babf8 --- /dev/null +++ b/example/resource/3d.json @@ -0,0 +1 @@ +{"v":"5.2.1","fr":60,"ip":0,"op":60,"w":500,"h":500,"nm":"Comp 1","ddd":1,"assets":[],"layers":[{"ddd":1,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":55}],"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[75,384,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.075893886387,0.175385013223,0.921568632126,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":1,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":55}],"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[76,234,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.025943866,0.945098042488,0.134079754353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":1,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":55}],"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[76,72,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index e5283be..1b5cd98 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -75,11 +75,22 @@ VMatrix LOTTransformData::computeMatrix(int frameNo, bool autoOrient) const } float angle = autoOrient ? mPosition.angle(frameNo) : 0; - m.translate(position) - .rotate(mRotation.value(frameNo)) - .rotate(angle) - .scale(mScale.value(frameNo) / 100.f) - .translate(-mAnchor.value(frameNo)); + if (ddd()) { + m.translate(position) + .rotate(mRotation.value(frameNo)) + .rotate(angle) + .rotate(m3D->mRz.value(frameNo)) + .rotate(m3D->mRy.value(frameNo), VMatrix::Axis::Y) + .rotate(m3D->mRx.value(frameNo), VMatrix::Axis::X) + .scale(mScale.value(frameNo) / 100.f) + .translate(-mAnchor.value(frameNo)); + } else { + m.translate(position) + .rotate(mRotation.value(frameNo)) + .rotate(angle) + .scale(mScale.value(frameNo) / 100.f) + .translate(-mAnchor.value(frameNo)); + } return m; } diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 73034eb..226cee5 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -417,6 +417,13 @@ inline int LOTLayerData::timeRemap(int frameNo) const return frameNo / mTimeStreatch; } +struct LOT3DData +{ + LOTAnimatable mRx{0}; + LOTAnimatable mRy{0}; + LOTAnimatable mRz{0}; +}; + class LOTTransformData : public LOTData { public: @@ -425,21 +432,23 @@ public: float opacity(int frameNo) const; void cacheMatrix(); bool staticMatrix() const {return mStaticMatrix;} + bool ddd() const {return m3D ? true : false;} private: VMatrix computeMatrix(int frameNo, bool autoOrient = false) const; public: - LOTAnimatable mRotation{0}; /* "r" */ - LOTAnimatable mScale; /* "s" */ - LOTAnimatable mPosition; /* "p" */ - LOTAnimatable mX{0}; - LOTAnimatable mY{0}; - LOTAnimatable mAnchor; /* "a" */ - LOTAnimatable mOpacity{100}; /* "o" */ - LOTAnimatable mSkew{0}; /* "sk" */ - LOTAnimatable mSkewAxis{0}; /* "sa" */ - bool mStaticMatrix{true}; - bool mSeparate{false}; - VMatrix mCachedMatrix; + std::unique_ptr m3D; + LOTAnimatable mRotation{0}; /* "r" */ + LOTAnimatable mScale; /* "s" */ + LOTAnimatable mPosition; /* "p" */ + LOTAnimatable mX{0}; + LOTAnimatable mY{0}; + LOTAnimatable mAnchor; /* "a" */ + LOTAnimatable mOpacity{100}; /* "o" */ + LOTAnimatable mSkew{0}; /* "sk" */ + LOTAnimatable mSkewAxis{0}; /* "sa" */ + bool mStaticMatrix{true}; + bool mSeparate{false}; + VMatrix mCachedMatrix; }; class LOTFillData : public LOTData diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 18e576b..3f42d11 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -208,7 +208,7 @@ public: std::shared_ptr parseShapeObject(); std::shared_ptr parsePolystarObject(); - std::shared_ptr parseTransformObject(); + std::shared_ptr parseTransformObject(bool ddd = false); std::shared_ptr parseFillObject(); std::shared_ptr parseGFillObject(); std::shared_ptr parseStrokeObject(); @@ -738,6 +738,7 @@ std::shared_ptr LottieParserImpl::parseLayer() LOTLayerData *layer = sharedLayer.get(); curLayerRef = layer; bool hasLayerRef = false; + bool ddd = true; EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "ty")) { /* Type of layer*/ @@ -746,6 +747,9 @@ std::shared_ptr LottieParserImpl::parseLayer() parenting and expressions.*/ RAPIDJSON_ASSERT(PeekType() == kNumberType); layer->mId = GetInt(); + } else if (0 == strcmp(key, "ddd")) { /*3d layer */ + RAPIDJSON_ASSERT(PeekType() == kNumberType); + ddd = GetInt(); } else if (0 == strcmp(key, "parent")) { /*Layer Parent. Uses "ind" of parent.*/ RAPIDJSON_ASSERT(PeekType() == kNumberType); layer->mParentId = GetInt(); @@ -776,7 +780,7 @@ std::shared_ptr LottieParserImpl::parseLayer() } else if (0 == strcmp(key, "ks")) { RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); - layer->mTransform = parseTransformObject(); + layer->mTransform = parseTransformObject(ddd); } else if (0 == strcmp(key, "shapes")) { parseShapesAttr(layer); } else if (0 == strcmp(key, "sw")) { @@ -1174,12 +1178,14 @@ std::shared_ptr LottieParserImpl::parseReapeaterObject() /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/transform.json */ -std::shared_ptr LottieParserImpl::parseTransformObject() +std::shared_ptr LottieParserImpl::parseTransformObject(bool ddd) { std::shared_ptr sharedTransform = std::make_shared(); LOTTransformData *obj = sharedTransform.get(); + if (ddd) obj->m3D = std::make_unique(); + while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "a")) { parseProperty(obj->mAnchor); @@ -1210,6 +1216,12 @@ std::shared_ptr LottieParserImpl::parseTransformObject() parseProperty(obj->mOpacity); } else if (0 == strcmp(key, "hd")) { obj->mHidden = GetBool(); + } else if (0 == strcmp(key, "rx")) { + parseProperty(obj->m3D->mRx); + } else if (0 == strcmp(key, "ry")) { + parseProperty(obj->m3D->mRy); + } else if (0 == strcmp(key, "rz")) { + parseProperty(obj->m3D->mRz); } else { Skip(key); } @@ -1218,6 +1230,10 @@ std::shared_ptr LottieParserImpl::parseTransformObject() obj->mRotation.isStatic() && obj->mScale.isStatic() && obj->mSkew.isStatic() && obj->mSkewAxis.isStatic() && obj->mX.isStatic() && obj->mY.isStatic(); + if (obj->m3D) { + obj->mStaticMatrix = obj->mStaticMatrix && obj->m3D->mRx.isStatic() && + obj->m3D->mRy.isStatic() && obj->m3D->mRz.isStatic(); + } obj->setStatic(obj->mStaticMatrix && obj->mOpacity.isStatic()); @@ -1919,6 +1935,7 @@ public: << ", stFm:" << obj->mStartFrame << ", ts:" << obj->mTimeStreatch << ", ao:" << obj->autoOrient() + << ", ddd:" << obj->mTransform->ddd() << "\n"; visitChildren(static_cast(obj), level); vDebug << level -- 2.34.1