From cd60fd373c4675b1285f520dbe52e49049493d43 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 11 Mar 2021 18:41:43 +0900 Subject: [PATCH 01/16] renderer: code refactoring. keep it in clean and release shape resource properly. --- src/renderer/include/thorvg_renderer.hpp | 12 ++- src/renderer/src/thorvg_renderer.cpp | 123 +++++++++++++------------------ 2 files changed, 58 insertions(+), 77 deletions(-) diff --git a/src/renderer/include/thorvg_renderer.hpp b/src/renderer/include/thorvg_renderer.hpp index 9b86fa6..3b153ac 100644 --- a/src/renderer/include/thorvg_renderer.hpp +++ b/src/renderer/include/thorvg_renderer.hpp @@ -12,14 +12,11 @@ namespace rive { struct TvgPaint { - int fillColor[4]; - int strokeColor[4]; + uint8_t color[4]; float thickness; tvg::StrokeJoin join = tvg::StrokeJoin::Bevel; tvg::StrokeCap cap = tvg::StrokeCap::Butt; RenderPaintStyle style; - bool isFill = false; - bool isStroke = false; }; class TvgRenderPath : public RenderPath @@ -28,13 +25,14 @@ namespace rive Shape *m_Shape; vector m_PathType; vector m_PathPoints; - bool m_Pushed = false; + bool active = false; public: TvgRenderPath(); + ~TvgRenderPath(); Shape* shape() { return m_Shape; } - bool getPushed() { return m_Pushed; } - void setPushed(bool pushed) { m_Pushed = pushed; } + bool onCanvas() { return active; } + void onCanvas(bool active) { this->active = active; } void reset() override; void addRenderPath(RenderPath* path, const Mat2D& transform) override; void fillRule(FillRule value) override; diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index d57de86..e33bd14 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -9,6 +9,11 @@ TvgRenderPath::TvgRenderPath() this->m_Shape = tvg::Shape::gen().release(); } +TvgRenderPath::~TvgRenderPath() +{ + if (!active) delete(m_Shape); +} + void TvgRenderPath::fillRule(FillRule value) { switch (value) @@ -17,13 +22,14 @@ void TvgRenderPath::fillRule(FillRule value) m_Shape->fill(tvg::FillRule::EvenOdd); break; case FillRule::nonZero: + m_Shape->fill(tvg::FillRule::Winding); break; } } -Vec2D applyTransform(const Vec2D &vec, const Mat2D &mat) +Point applyTransform(const Vec2D &vec, const Mat2D &mat) { - tvg::Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; m.e11 = mat[0]; m.e12 = mat[2]; m.e13 = mat[4]; @@ -31,47 +37,51 @@ Vec2D applyTransform(const Vec2D &vec, const Mat2D &mat) m.e22 = mat[3]; m.e23 = mat[5]; - Vec2D ret; - ret[0] = round(vec[0] * m.e11 + vec[1] * m.e12 + m.e13); - ret[1] = round(vec[0] * m.e21 + vec[1] * m.e22 + m.e23); - - return ret; + return {vec[0] * m.e11 + vec[1] * m.e12 + m.e13, vec[0] * m.e21 + vec[1] * m.e22 + m.e23}; } void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) { auto m_PathType = reinterpret_cast(path)->m_PathType; auto m_PathPoints = reinterpret_cast(path)->m_PathPoints; - Vec2D vecOut1, vecOut2, vecOut3; - int index = 0; + + /* OPTIMIZE ME: Should avoid data copy in loop... */ + for (size_t i = 0; i < m_PathType.size(); i++) { - PathCommand type = m_PathType[i]; - switch(type) + /* OPTIMIZE ME: apply transform only when it's not identity */ + switch(m_PathType[i]) { case PathCommand::MoveTo: - vecOut1 = applyTransform(m_PathPoints[index], transform); - m_Shape->moveTo(vecOut1[0], vecOut1[1]); + { + auto pt = applyTransform(m_PathPoints[index], transform); + m_Shape->moveTo(pt.x, pt.y); index += 1; break; + } case PathCommand::LineTo: - vecOut1 = applyTransform(m_PathPoints[index], transform); - m_Shape->lineTo(vecOut1[0], vecOut1[1]); + { + auto pt = applyTransform(m_PathPoints[index], transform); + m_Shape->lineTo(pt.x, pt.y); index += 1; break; + } case PathCommand::CubicTo: - vecOut1 = applyTransform(m_PathPoints[index], transform); - vecOut2 = applyTransform(m_PathPoints[index + 1], transform); - vecOut3 = applyTransform(m_PathPoints[index + 2], transform); - m_Shape->cubicTo(vecOut1[0], vecOut1[1], - vecOut2[0], vecOut2[1], - vecOut3[0], vecOut3[1]); + { + auto pt1 = applyTransform(m_PathPoints[index], transform); + auto pt2 = applyTransform(m_PathPoints[index + 1], transform); + auto pt3 = applyTransform(m_PathPoints[index + 2], transform); + m_Shape->cubicTo(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); index += 3; break; + } case PathCommand::Close: + { m_Shape->close(); + index += 1; break; + } } } } @@ -123,38 +133,35 @@ void TvgRenderer::transform(const Mat2D& transform) void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) { - Matrix m = {m_Transform[0], 0, m_Transform[4], 0, m_Transform[3], m_Transform[5], 0, 0, 1}; - - auto renderPath = reinterpret_cast(path); - auto shape = reinterpret_cast(path)->shape(); - shape->transform(m); + auto renderPath = static_cast(path); + auto shape = static_cast(path)->shape(); + auto tvgPaint = static_cast(paint)->paint(); - auto tvgPaint = reinterpret_cast(paint)->paint(); + /* OPTIMIZE ME: Stroke / Fill Paints required to draw separately. + thorvg doesn't need to handle both, we can avoid one of them rendering... */ - if (tvgPaint->isFill) + if (tvgPaint->style == RenderPaintStyle::fill) { - shape->fill(tvgPaint->fillColor[0], tvgPaint->fillColor[1], tvgPaint->fillColor[2], tvgPaint->fillColor[3]); + shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); } - - if (tvgPaint->isStroke) + else if (tvgPaint->style == RenderPaintStyle::stroke) { - shape->stroke(tvgPaint->strokeColor[0], tvgPaint->strokeColor[1], tvgPaint->strokeColor[2], tvgPaint->strokeColor[3]); + shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); shape->stroke(tvgPaint->cap); shape->stroke(tvgPaint->join); - if (tvgPaint->thickness != 0) - { - shape->stroke(tvgPaint->thickness); - } + shape->stroke(tvgPaint->thickness); } - if (!renderPath->getPushed()) + shape->transform({m_Transform[0], 0, m_Transform[4], 0, m_Transform[3], m_Transform[5], 0, 0, 1}); + + if (renderPath->onCanvas()) { - m_Canvas->push(unique_ptr(shape)); - renderPath->setPushed(true); + m_Canvas->update(shape); } else { - m_Canvas->update(shape); + m_Canvas->push(unique_ptr(shape)); + renderPath->onCanvas(true); } } @@ -170,39 +177,15 @@ TvgRenderPaint::TvgRenderPaint() void TvgRenderPaint::style(RenderPaintStyle style) { - switch (style) - { - case RenderPaintStyle::fill: - m_Paint.style = RenderPaintStyle::fill; - m_Paint.isFill = true; - break; - case RenderPaintStyle::stroke: - m_Paint.style = RenderPaintStyle::stroke; - m_Paint.isStroke = true; - break; - } + m_Paint.style = style; } + void TvgRenderPaint::color(unsigned int value) { - int b = value >> 0 & 255; - int g = value >> 8 & 255; - int r = value >> 16 & 255; - int a = value >> 24 & 255; - - if (m_Paint.style == RenderPaintStyle::fill) - { - m_Paint.fillColor[0] = r; - m_Paint.fillColor[1] = g; - m_Paint.fillColor[2] = b; - m_Paint.fillColor[3] = a; - } - else if (m_Paint.style == RenderPaintStyle::stroke) - { - m_Paint.strokeColor[0] = r; - m_Paint.strokeColor[1] = g; - m_Paint.strokeColor[2] = b; - m_Paint.strokeColor[3] = a; - } + m_Paint.color[0] = value >> 16 & 255; + m_Paint.color[1] = value >> 8 & 255; + m_Paint.color[2] = value >> 0 & 255; + m_Paint.color[3] = value >> 24 & 255; } void TvgRenderPaint::thickness(float value) -- 2.7.4 From 0be5b72a1da2ee183acc5fa5af149868fb97c203 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 11 Mar 2021 18:46:29 +0900 Subject: [PATCH 02/16] renderer: we know the type casting in compile time. Don't use reinterpret_cast unless it's avoidable. --- src/renderer/src/thorvg_renderer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index e33bd14..ee74fc9 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -42,8 +42,8 @@ Point applyTransform(const Vec2D &vec, const Mat2D &mat) void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) { - auto m_PathType = reinterpret_cast(path)->m_PathType; - auto m_PathPoints = reinterpret_cast(path)->m_PathPoints; + auto m_PathType = static_cast(path)->m_PathType; + auto m_PathPoints = static_cast(path)->m_PathPoints; int index = 0; /* OPTIMIZE ME: Should avoid data copy in loop... */ @@ -252,4 +252,4 @@ namespace rive { RenderPath* makeRenderPath() { return new TvgRenderPath();} RenderPaint* makeRenderPaint() { return new TvgRenderPaint();} -} +} \ No newline at end of file -- 2.7.4 From e4d5593229fcf3e9d5a80fd2b22bdd39167eb8d7 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Fri, 12 Mar 2021 13:50:05 +0900 Subject: [PATCH 03/16] renderer: fix wrong transform matrix. --- src/renderer/src/thorvg_renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index ee74fc9..9cf0484 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -152,7 +152,7 @@ void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) shape->stroke(tvgPaint->thickness); } - shape->transform({m_Transform[0], 0, m_Transform[4], 0, m_Transform[3], m_Transform[5], 0, 0, 1}); + shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1}); if (renderPath->onCanvas()) { -- 2.7.4 From 4c0eff630fa462ff6fdf02970724c829f6da35c5 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Fri, 12 Mar 2021 17:48:47 +0900 Subject: [PATCH 04/16] example: upgrade rive viewer for loading rive files in examples/resource directory. --- example/resource/heart.riv | Bin 0 -> 2311 bytes example/resource/juice063.riv | Bin 0 -> 9549 bytes example/resource/knight063.riv | Bin 0 -> 51078 bytes example/resource/marty_v6.riv | Bin 0 -> 31253 bytes example/resource/notification_icon_3.riv | Bin 0 -> 2404 bytes example/resource/poison_loader.riv | Bin 0 -> 9708 bytes example/{ => resource}/shapes.riv | Bin example/rive_viewer.cpp | 154 ++++++++++++++++++++++--------- meson.build | 2 + 9 files changed, 113 insertions(+), 43 deletions(-) create mode 100644 example/resource/heart.riv create mode 100644 example/resource/juice063.riv create mode 100644 example/resource/knight063.riv create mode 100644 example/resource/marty_v6.riv create mode 100644 example/resource/notification_icon_3.riv create mode 100644 example/resource/poison_loader.riv rename example/{ => resource}/shapes.riv (100%) diff --git a/example/resource/heart.riv b/example/resource/heart.riv new file mode 100644 index 0000000000000000000000000000000000000000..7a1c85811872cd65ce41b25fdc074403a177b0bf GIT binary patch literal 2311 zcma)7Yiv_x7=BONZ>43uY___#TURpLjm2rVL)|*Fp0i$#PGTf27jKCYL0#AqV8kD@ znwk(2mPU$Mi1I_{p9zGBKVadac64Zhk%-1i#6*fCA;I8C!mxLi_zQAvRh75Gp=m!hCqfQi14cyjH}A!vqXfsYS|#E16HV>XyN_=*so zj=hPoa8Z0NBwm~NmG-AIxSw7#P4U(7N&4A2FhO1X*ZV`_yNNt)J^I%{`uY8AIs{y6 zFME+LPw+SHK@Lm~o&j?POrUW`GF(&>yI(R7wVnod6xA|0iRFgcPj$E=(YsazcM)N8C_O!7c`tuZwP*+D~(Qx%Zf z`8K_r4b>YCzD3ckRdlD59Z@8cBn#lu84S}zThu>6>dgcudxq&7Ow&;Y$nuLKJ244J zZ|sQ??RA(uAdOFIDM@0|E7g7AqC_5g<@L`)GNZ+ZycE1a_9{cRU-6WO6h`!=AwBPP zk*rE5@G6w91-=*#z7;rUpouOHk?^ZGM}Drik0x{2vTFGjFSU3<<0S_k55v|1cq0Oa z^8ZE$@2fKMaI)jPteT9p_G36fMoxV>Gx)!a?33OP#z_o$5M0VgQsm>lTH4A!X+CsY iwK6CzVI_^(dZKe#GdpTHHT%onFq+x9e9L_`&HNV$TpMfv literal 0 HcmV?d00001 diff --git a/example/resource/juice063.riv b/example/resource/juice063.riv new file mode 100644 index 0000000000000000000000000000000000000000..c212ddc71258f96869986728229a6aa19a7435f5 GIT binary patch literal 9549 zcma)Bd3+Q__OA}AApbM+wihx%{6cCmT?4s_jn%{fXHPbygRQ?G4>V50g`@Z-3 zRdr3?Bv*D+M3Xn-0WyFHZGsTl=k}udWT~cZMpa?Wte%8CmDLOX=*Y<)_GohAq}-dp zzdrbf^o{HtEf>z5T~bpur*f7^NW3VdH66d9okT=N)>Kv1i9}C4x-3Kc4k-)AW>n33 zSnQ!ED!oM8$2sM^phTux}t}Rrq`5}l-7x2Y+m{$OWc8F ziB^5`$Yp**>y1}@BsMa}kXJObuCTJCyeK)hu&z{$(v$ipWWxv38l+@_h+Ti¿Zp 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 literal 0 HcmV?d00001 diff --git a/example/resource/notification_icon_3.riv b/example/resource/notification_icon_3.riv new file mode 100644 index 0000000000000000000000000000000000000000..eff4c79895970dfdc6504ac0ea8143e1785c5f93 GIT binary patch literal 2404 zcmbtVT}&KR6h8ZNX&0DXewKw zd(L;h@18R=+u7cmEO5Zv5>$dMY1;uSi;0~8zJv>4Oe+L9tQ7%(T1*$PGbjOws-<)R zyHkoE86O{*noJF*MkgnjO)5!`#NDaScV{ukwDHNqN12^AGqkDYHy!SUk*=HIaJqPf zV}nyE=JafMR#ghbpoFnHfC5%fg}NZ4p=>v;dS)-5kN0kP+M|86f*{ZEWibPwllWbH z-^$dwDc@jHn!$82233qT1Kf)311Muf4O{q!mLzSGj1RmtlS<*CobJrQ@+>-%>HrvX z8;%y*hN2eKcl9Q?n1mH2Uh#1ouUTf)Y-VLs01N7j9Xn9O+cGdRI59Mh#rbg^tO5mm z?#=60GhC(8P(d6=6@gaPN=e0sDn6@9wW(4)EmVwpfqcE%ZS`uaZk)dymw9y;3t+u~ zwO-Jy7tGfaMxCtD3vfoOpbL6wL~dighmVRLG5{xQ^7chHvl?3Y6O*aY;n%`n+xFW)k`+7H{2>n%1~gB?o@~+48$dvN3_)1$T3P-MK??`Ub*3VS zaqylId6t78uJK3@f@gFQ8Ma1d5$xAR+G!i2oKV_=WW@>0ACkasxM?-raEd_wkQl8V(VihCfZ*{gI%SS0PD#8A3vWbnJOQ@rm011Y$O2j}j>sP>wbtcv zs{7m6yZO2TSb4I-z+o|UK&P(*7ANvg#*z*bHo+?Zqhv&%3PI@T2@+ahO`HCodOec*p42a>qRRXyuXD&#h1-$-%~*OBCtg;9lML6gkAf7tP;LiM~L0%R(tFa3U>s?BjvgEyX|h;Vq4erIzIg$M4CuVuw&e7Z#E z<7R{F`Lnl5gFcRBHT}&a4g#Et?^qOMrJAVCG_*oYNg(wWX;t#$FOs8Ixg!7$J}|q4 zS+epFk*9%~Ke)4|sH-W_f5lso~c-FAD#8!-H~> zczKqWW|tLamrp91CZ&Ay^Y5$t;30eW`kxy48w31PC|5}bkDTc_IfZ#4F;d!hX^fZJ z4<52B*XMKcw4;Ztlmu@(q_A*OaamqSW_I~Rsf&z?U#XVEBY=wcV>`iv>L7KY0wnHk zsgnu|L!vS8mr5f-?>AM6_ZZM_kA*oMIr*d4vi@cdcNw)R8t;K00o1CG)t%sh_iz{Q z;g0w4wC~~Jj_tr^M7P^QCF^FDTSmLv{@o03nfjI6YB@Xt)UV{So#27D@D^|3jkoX- zws66&DlIA(yh&rLJWKQP3-c!M-u3gPsaF|4c*qXFx7R8+UUfKfrRYj~< zD=G6FH9yr-a)w1MW&16{lpE%nuNlRmrm@#8I?dP-W_^5J32R6@<)Jnn&iR?8fTMGp zkwf#>7O=XexOpbM+_aT7*c#H!#%1v%;WUHA_6KA8BcrH*gKVhoP^2}?8g`Eh|20@? z#TIu5(>L1(qXg5*bdT=G7XPIZ86kT;h1SR?79Ftg=JZl*=svg+O|8hp=2U$F=JZme z%9mNtR$C87mJ!}jg4pa;_>T-J!l9~teM`+o_n*WGeWNE!Z|6<8gf4VKMKJjKeR zA8iEBN~Qf3RjyqIp`-7QQYk6lbe5l5pC8SjK7Mt0vAPlD^;cxLcjM5bgsU($Sl}8x zG>}8H+I+EdflIW-onKlwdE9~R!WOZLkfjSPXi4uaW+g?ng1lJ8zAnTdz-7WS!KlWQ&LW9BxQa+OF6ClyRAm->my%IfC6Hu?OFUZRLdz^1uL6BX2! z%M7B-=aO~vC+sxoyA12j8A2mWCgYx@NDix!s8AnF%4=m#SxGoj(`N5&s;>?vk%&wE=Z7V+4(IeUl>v=xFAJA74J|Xs8nX|=FGZ0VuH{femnu#d{@xRl{#pN?oMGSLOD5yI=&qnNULEx< zgT_a`%i_%NE-1_{D;t-WpO4E1_RGM7BN;z<$d)ztvdO(3?ghVe3dm%&x*;hEA??cU zFj>{z(HePGnpVRHLx$qwyty2TxAeB*jWQIg@8J`fzcoQX&((Dt3fPa48>Ur`evd@Ttk9UtN&K8jk)oP-V>My_4fPKsKW47qhx=eNLJ5Pp2H@40yyCUz>DS;D9>? z!R|U3>7N{U2ps8ZBaG}aYz`TW9#(=3lhNbeK7qsk**+^;j@qocgTExI^()qG(O z8R>$qT6KS3N-*mO3<=;2=thRw_{|{~IEV~|u5yhP?SFCCimPjeB2hlfh6bNn&t?tX ze}>UE_n|fX{Fd0KjVO*v(q!FO^k@Z-CiHMlh8MBcovf%2Ra>3VKqn^2=%C4o6b z<>iHWB*p~42fCyS<+RLetHKF z&aimuLzD5f#R!5Nb9CONMt7TLTXlfi$R{;LY`#b;T;S4VlGTcSt zRye6-`lMWZ70s-^8Yl1W+G2$?6lTZemljPcmzIdqFzr50!-_Ry!Cl?DI^6Yl=~&t> z9o?j5iXYBsHRxI*CLVKpLBn_`^ zEFo!F_4zb`V@z4N4ej0GqtV?f?Z@c1-O_M|*+HRZrPJ{;iR4viy-Y^|@XCm&HE*>9i)Q3fMB-M6ujxY)zPp!3A2v28)z`1atH!cbdC-|a3TDv7Qf2S;^ zo#g=g3ZNtRpI7>*^{vD2w$FXc@^{Jq^Uj`(aYXf5DC(HSk^KTRom{~o1$x^oz{f>6 z^Z(duun6#@{vH}MCS3)E0Ixmx#Yzq(o}OaO3VVSo!IlfpiO|tM&SufdprKY_S(qx8 zMb*!1h?JdA@v;X|GtAhNOK9v$$EyiO{?ZL}1Yb*CB=QN_#p6UTO5%3qq&lCG$FA*T z!f#Wqm{0mXEu(f@RPx8C8Jnop-AIexuGDAlTjc6ynsv4qo4~zp(#_bPu77*MsEF&_7RPF9S6=SL2y8=so7Ke2$S?a#3ICl}3G z!M~+3+N&2UlgYke4=`W%C9J^L|H)$xwS2mp&4N2zOQ}Ce7Pee?_AjhKR2Pe`^kEC5 z?{{JhYq+sJ$!uJ+Oa-xz_n@}dGf4eScZ+Vtl;}o%QsV2J;c?n-#^@0rK&-4{db4Q! zx2K^=-_-7WF!GmvL`Qs4)z*f6ESK5KjPP2~&ett3nk{n5<9Or0-*5jELb{$-EXcmb zp=ANDIk(X7teqqFBR&65mGSGKm^0(RcdEb=J>C$O=A@%XZ$n>@pBZPp64<%QvdA1>aqs!XY@xy-ewKn z`MO49;St<$x=AsM$E=6=e9S(qZpjZgBs^StaE8+!EsW6`!#f|dG^lUkPTCp^cPfTy z9k1dQf`c#|cK$4fT$(m=x}r-Tne_Qx_OOPK`zp0@gp79(X4x0KkwpnBH*>nzJiDs& zN2Z<@JBSzRaFDPE^*}#_lZ!eaC;mB?J+!L%FXy* zK5~k0k6-#4(L}#=Nu0puF`GCv#;3-nTh=GutiPSpmor4{?ademWp)6QG0V)uACmr< zhvIe_Q~y`Lj9LCy!;D#=PyTNmvmoWaw#=C2fA!3mMcg!Fc+%@LtG)M!J$BSvkwuQZ zv3zI;wfBEhSP*T3mah#qiV)!!WTU{2RF=R zI&x1N1vd;HQEeV`>^F>*Z#?nka(dnhPX2htCea(-*Fq+KLo2GAZ#r=p9RM7-5k@!> zF$=6gFekiIZKye;7T&2~B(MM#fmq?CikHH_RJD_0bx2|Kb}1$!FQtR@Ry#v6>MZ?< zj(V%&Q!X^Pz|R~ub;f60_(aBq>x=hd@X6i7Cr9yLd4v%;!vOrfki$({L21$SX}MAg zJL~}+F=Lu{8`YKS%51orr&3?KnDrUEA$@_03-g`J;906Zj!`T3tvJSRSd_4;f8_xL)M+B8bwN$kgP#dS18xdg{aCgm39#m`KnlYEjh zR5ay>V*Dst8S6v225Ed!T!uWPQ&)GhHc~;FJ_6cx_P7e83;}gmhi?EBQ%<=kV|A2! zkj6upKXHM4e=@l2CwRb%Kjn^UlfbVgU^sEN_{TIdHyvO+>_WY+!r$wQ&_~SdG z(BWw)W~N}Z8{`X}8nmvP4XY7}hsjHPVF>9lp;s3e#^T|>8p2_if`_f$!eE$#hj(Xt z+OWQeB4T0_{56;aVxCE!3tpj97Y=oYSr9YgtPc!9%%W@j5X30&wQ*RCfueHk*K;Nb%t00|p5WHaPPqiC_T%uFqrJ8V2i6+P*y`Ae4^$)v8KF=KpLy)zt zv?tgW_;L`wQYi&ZNL00~<=sybj;FN`!icj!iefg=^8-;-@wE0qxPIk4lT$kUXn+xs z&ePfl;nUS`3aazjzwUuaF>M8^iuN7e%n+Ue2$X^^ z98RSO8xh8{K|DH@8rQl8)F5)+so7;$ivLLBFpjVhIXoMR;nP(P!pQYDgT|dlkS0jD zZSKB;f1Goid~vxipd^77sN!klq|#s=ikZi|ULhnQ?~D4cdqD6I?G#5l3ZX=&_WhpE z^H@RJlKh@PAO}&9#3Q0Bw^JcXZC>h=02%n3NF72s68v4W1PDZGQ5QKNB6ZLZKKY5% zk_Go5+G}}@4V1(YEGwr3K?oArKh%VY4ujB$2%ZLq;avPb`ukzs5n>VO~GH49V>5ly#a`< zBs5sr5QGWP)HqlA?Eehf7_w*U!atzJAu93Ri>41pfk-yiz zEZEWOc{+~orX(LK3hDe##}@bVJ{E&|F=$pu3`Efp{e9^g59Rh^TYu+%P~yo%qTztleu&>+Dv z>jv-@pO~PU#UBwd;kREI;4Bb0*QSmFL=0j+=4p2S<_{er_}8hQ?vp@p0MT#P%1A&& zzZ(I(?}>l64yXkh(XVG!3?QOkV0I`VqTl~n`T!#OZF<7rIYhse2Y61RU&8h<;I!*^ zr!OWtZki4bwX{!0LgW&)DvRqxZX5V&51RbR1&G+YYxph`M#SDruP*``v3Ja`VL&7H<|y9+8u9t^ zFFt}&Ozho!>lmB>2?bBDJwPMYuS;4jK7od;JIDAFaOzjv_XqF~(eHdstLQxR7H{w* z(Qg6N4~Kp;lA-|-{Y-%zAfn%%;e6ji^b3{v0gdQqIo}x&(Jx{xzk@wO!pixC-$+wZ z(e?Kjmwo(Q8?OQ_pWr6p#D{?VG5VEGjXTGq5R9JEsgnVTZa}=4{~qpGyk}Oj&AE8; zjdVa{ar8{dalF_UI%2pNU}xurgLfv#7Z<=eYx_VD;2Y~d@Gh2(gEIr(H);<6ufM?S z5YrKph(skn#Md2)d7qCr8N3z3B?zDSi5PxJUKxPIfBYAA;D@fXr2Ri(4f$$bibr;9 vX-Ws}qV*}BJIDPl{wJ&e$;;nV=!od(=r)QDj`P${E1!gax6KWSrl|i18V?(_ literal 0 HcmV?d00001 diff --git a/example/shapes.riv b/example/resource/shapes.riv similarity index 100% rename from example/shapes.riv rename to example/resource/shapes.riv diff --git a/example/rive_viewer.cpp b/example/rive_viewer.cpp index 5cae43f..76eb22b 100644 --- a/example/rive_viewer.cpp +++ b/example/rive_viewer.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -9,21 +11,23 @@ using namespace std; -#define WIDTH 700 +#define WIDTH 1000 #define HEIGHT 700 +#define LIST_HEIGHT 200 static unique_ptr canvas; static tvg::Canvas *renderCanvas; -static rive::File* file = nullptr; +static rive::File* currentFile = nullptr; static rive::Artboard* artboard = nullptr; static rive::LinearAnimationInstance* animationInstance = nullptr; static Ecore_Animator *animator = nullptr; static Eo* view = nullptr; +static vector rivefiles; static double lastTime; static void deleteWindow(void *data, Evas_Object *obj, void *ev) { - elm_exit(); + elm_exit(); } static void drawToCanvas(void* data, Eo* obj) @@ -34,43 +38,19 @@ static void drawToCanvas(void* data, Eo* obj) } } -Eina_Bool animationLoop(void *data) +static bool isRiveFile(const char *filename) { - double currentTime = ecore_time_get(); - float elapsed = currentTime - lastTime; - static float animationTime = 0; - lastTime = currentTime; - - if (artboard != nullptr) - { - if (animationInstance != nullptr) - { - animationInstance->advance(elapsed); - animationInstance->apply(artboard); - } - artboard->advance(elapsed); - - rive::TvgRenderer renderer(renderCanvas); - renderer.save(); - artboard->draw(&renderer); - renderer.restore(); - } - - evas_object_image_pixels_dirty_set(view, EINA_TRUE); - evas_object_image_data_update_add(view, 0, 0, WIDTH, HEIGHT); - - return ECORE_CALLBACK_RENEW; + const char *dot = strrchr(filename, '.'); + if(!dot || dot == filename) return false; + return !strcmp(dot + 1, "riv"); } -static void runExample(uint32_t* buffer) +static void loadRiveFile(const char* filename) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); - renderCanvas = canvas.get(); + // Clear Canvas Buffer + renderCanvas->clear(); // Load Rive File - const char* filename = "../../example/shapes.riv"; FILE* fp = fopen(filename, "r"); fseek(fp, 0, SEEK_END); @@ -86,6 +66,7 @@ static void runExample(uint32_t* buffer) } auto reader = rive::BinaryReader(bytes, length); + rive::File* file = nullptr; auto result = rive::File::import(reader, &file); if (result != rive::ImportResult::success) { @@ -98,6 +79,7 @@ static void runExample(uint32_t* buffer) artboard->advance(0.0f); delete animationInstance; + delete currentFile; auto animation = artboard->firstAnimation(); if (animation != nullptr) @@ -109,37 +91,123 @@ static void runExample(uint32_t* buffer) animationInstance = nullptr; } + currentFile = file; + delete[] bytes; +} + +static void fileClickedCb (void *data, Evas_Object *obj, void *event_info) +{ + Elm_Object_Item *item = elm_list_selected_item_get(obj); + int index = 0; + for (Elm_Object_Item *iter = item; iter != NULL; iter = elm_list_item_prev(iter)) + index++; + if (rivefiles.size() > 0) + loadRiveFile(rivefiles[index-1].c_str()); +} + +static std::vector riveFiles(const std::string &dirName) +{ + DIR *d; + struct dirent *dir; + std::vector result; + d = opendir(dirName.c_str()); + if (d) { + while ((dir = readdir(d)) != NULL) { + if (isRiveFile(dir->d_name)) + result.push_back(dirName + dir->d_name); + } + closedir(d); + } + + std::sort(result.begin(), result.end(), [](auto & a, auto &b){return a < b;}); + + return result; +} + +Eina_Bool animationLoop(void *data) +{ + double currentTime = ecore_time_get(); + float elapsed = currentTime - lastTime; + static float animationTime = 0; + lastTime = currentTime; + + if (artboard != nullptr) + { + if (animationInstance != nullptr) + { + animationInstance->advance(elapsed); + animationInstance->apply(artboard); + } + artboard->advance(elapsed); + + rive::TvgRenderer renderer(renderCanvas); + renderer.save(); + artboard->draw(&renderer); + renderer.restore(); + } + + evas_object_image_pixels_dirty_set(view, EINA_TRUE); + evas_object_image_data_update_add(view, 0, 0, WIDTH, HEIGHT); + + return ECORE_CALLBACK_RENEW; +} + +static void runExample(uint32_t* buffer) +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); + renderCanvas = canvas.get(); + lastTime = ecore_time_get(); ecore_animator_frametime_set(1. / 60); animator = ecore_animator_add(animationLoop, nullptr); - - delete[] bytes; } - static void cleanExample() { - delete file; delete animationInstance; } - static void setupScreen(uint32_t* buffer) { Eo* win = elm_win_util_standard_add(NULL, "Rive Viewer"); evas_object_smart_callback_add(win, "delete,request", deleteWindow, 0); - view = evas_object_image_filled_add(evas_object_evas_get(win)); + Eo* box = elm_box_add(win); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, box); + evas_object_show(box); + + view = evas_object_image_filled_add(evas_object_evas_get(box)); evas_object_image_size_set(view, WIDTH, HEIGHT); evas_object_image_data_set(view, buffer); evas_object_image_pixels_get_callback_set(view, drawToCanvas, nullptr); evas_object_image_pixels_dirty_set(view, EINA_TRUE); evas_object_image_data_update_add(view, 0, 0, WIDTH, HEIGHT); - evas_object_size_hint_weight_set(view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_weight_set(view, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_min_set(view, WIDTH, HEIGHT); evas_object_show(view); - elm_win_resize_object_add(win, view); - evas_object_resize(win, WIDTH, HEIGHT); + elm_box_pack_end(box, view); + + Eo *fileList = elm_list_add(box); + evas_object_size_hint_weight_set(fileList, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(fileList, EVAS_HINT_FILL, EVAS_HINT_FILL); + + // Search Rive Files in Resource Dir + rivefiles = riveFiles(RIVE_FILE_DIR); + for (int i = 0; i < rivefiles.size(); i++) + { + const char *ptr = strrchr(rivefiles[i].c_str(), '/'); + Elm_Object_Item *item = elm_list_item_append(fileList, ptr + 1, NULL, NULL, fileClickedCb, NULL); + } + elm_list_go(fileList); + + elm_box_pack_end(box, fileList); + evas_object_show(fileList); + + evas_object_resize(win, WIDTH, HEIGHT + LIST_HEIGHT); evas_object_show(win); } diff --git a/meson.build b/meson.build index 94c5329..952f3d0 100644 --- a/meson.build +++ b/meson.build @@ -4,6 +4,8 @@ project('rive_tizen', version : '0.1.0', license : 'MIT') +add_project_arguments('-DRIVE_FILE_DIR="@0@/example/resource/"'.format(meson.current_source_dir()), language : 'cpp') + thorvg_dep = dependency('thorvg', required : true) run_command('script/install.sh') -- 2.7.4 From 7697e4c2639ed9cb6f064d36e792e258baaa3776 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Mon, 15 Mar 2021 16:48:13 +0900 Subject: [PATCH 05/16] renderer: Implements Skeletone Codes for Gradient --- src/renderer/include/thorvg_renderer.hpp | 46 +++++++++++++++++++++++++++++++- src/renderer/src/thorvg_renderer.cpp | 38 +++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/renderer/include/thorvg_renderer.hpp b/src/renderer/include/thorvg_renderer.hpp index 3b153ac..7709a4e 100644 --- a/src/renderer/include/thorvg_renderer.hpp +++ b/src/renderer/include/thorvg_renderer.hpp @@ -42,14 +42,58 @@ namespace rive virtual void close() override; }; + struct GradientStop + { + unsigned int color; + float stop; + GradientStop(unsigned int color, float stop) : color(color), stop(stop) + { + } + }; + + class TvgGradientBuilder + { + public: + std::vector stops; + float sx, sy, ex, ey; + virtual ~TvgGradientBuilder() {} + TvgGradientBuilder(float sx, float sy, float ex, float ey) : + sx(sx), sy(sy), ex(ex), ey(ey) + { + } + + virtual void make(TvgPaint* paint) = 0; + }; + + class TvgRadialGradientBuilder : public TvgGradientBuilder + { + public: + TvgRadialGradientBuilder(float sx, float sy, float ex, float ey) : + TvgGradientBuilder(sx, sy, ex, ey) + { + } + void make(TvgPaint* paint) override; + }; + + class TvgLinearGradientBuilder : public TvgGradientBuilder + { + public: + TvgLinearGradientBuilder(float sx, float sy, float ex, float ey) : + TvgGradientBuilder(sx, sy, ex, ey) + { + } + void make(TvgPaint* paint) override; + }; + class TvgRenderPaint : public RenderPaint { private: TvgPaint m_Paint; + TvgGradientBuilder* m_GradientBuilder; public: - TvgRenderPaint(); TvgPaint* paint() { return &m_Paint; } + TvgRenderPaint(); void style(RenderPaintStyle style) override; void color(unsigned int value) override; void thickness(float value) override; diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index 9cf0484..03ea5fb 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -225,22 +225,54 @@ void TvgRenderPaint::cap(StrokeCap value) } } -void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey) +void TvgRadialGradientBuilder::make(TvgPaint* paint) { + /* Implements Tvg Radial Gradient Here*/ + int numStops = stops.size(); + if (numStops != 0) + { + unsigned int value = stops[0].color; + paint->color[0] = value >> 16 & 255; + paint->color[1] = value >> 8 & 255; + paint->color[2] = value >> 0 & 255; + paint->color[3] = value >> 24 & 255; + } +} + +void TvgLinearGradientBuilder::make(TvgPaint* paint) +{ + /* Implements Tvg Linear Gradient Here*/ + int numStops = stops.size(); + + if (numStops != 0) + { + unsigned int value = stops[0].color; + paint->color[0] = value >> 16 & 255; + paint->color[1] = value >> 8 & 255; + paint->color[2] = value >> 0 & 255; + paint->color[3] = value >> 24 & 255; + } +} +void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey) +{ + m_GradientBuilder = new TvgLinearGradientBuilder(sx, sy, ex, ey); } void TvgRenderPaint::radialGradient(float sx, float sy, float ex, float ey) { + m_GradientBuilder = new TvgRadialGradientBuilder(sx, sy, ex, ey); } void TvgRenderPaint::addStop(unsigned int color, float stop) { + m_GradientBuilder->stops.emplace_back(GradientStop(color, stop)); } void TvgRenderPaint::completeGradient() { - + m_GradientBuilder->make(&m_Paint); + delete m_GradientBuilder; } void TvgRenderPaint::blendMode(BlendMode value) @@ -252,4 +284,4 @@ namespace rive { RenderPath* makeRenderPath() { return new TvgRenderPath();} RenderPaint* makeRenderPaint() { return new TvgRenderPaint();} -} \ No newline at end of file +} -- 2.7.4 From 1830d7da864c6526a593434afe6157e6abeef532 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Mon, 15 Mar 2021 19:23:03 +0900 Subject: [PATCH 06/16] renderer: code reordering for readability. --- src/renderer/src/thorvg_renderer.cpp | 140 ++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 69 deletions(-) diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index 03ea5fb..455dcf4 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -40,6 +40,13 @@ Point applyTransform(const Vec2D &vec, const Mat2D &mat) return {vec[0] * m.e11 + vec[1] * m.e12 + m.e13, vec[0] * m.e21 + vec[1] * m.e22 + m.e23}; } +void TvgRenderPath::reset() +{ + m_Shape->reset(); + m_PathType.clear(); + m_PathPoints.clear(); +} + void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) { auto m_PathType = static_cast(path)->m_PathType; @@ -86,13 +93,6 @@ void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) } } -void TvgRenderPath::reset() -{ - m_Shape->reset(); - m_PathType.clear(); - m_PathPoints.clear(); -} - void TvgRenderPath::moveTo(float x, float y) { m_PathType.push_back(PathCommand::MoveTo); @@ -118,58 +118,6 @@ void TvgRenderPath::close() m_PathType.push_back(PathCommand::Close); } -void TvgRenderer::save() -{ -} - -void TvgRenderer::restore() -{ -} - -void TvgRenderer::transform(const Mat2D& transform) -{ - m_Transform = transform; -} - -void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) -{ - auto renderPath = static_cast(path); - auto shape = static_cast(path)->shape(); - auto tvgPaint = static_cast(paint)->paint(); - - /* OPTIMIZE ME: Stroke / Fill Paints required to draw separately. - thorvg doesn't need to handle both, we can avoid one of them rendering... */ - - if (tvgPaint->style == RenderPaintStyle::fill) - { - shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); - } - else if (tvgPaint->style == RenderPaintStyle::stroke) - { - shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); - shape->stroke(tvgPaint->cap); - shape->stroke(tvgPaint->join); - shape->stroke(tvgPaint->thickness); - } - - shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1}); - - if (renderPath->onCanvas()) - { - m_Canvas->update(shape); - } - else - { - m_Canvas->push(unique_ptr(shape)); - renderPath->onCanvas(true); - } -} - -void TvgRenderer::clipPath(RenderPath* path) -{ - -} - TvgRenderPaint::TvgRenderPaint() { @@ -225,6 +173,32 @@ void TvgRenderPaint::cap(StrokeCap value) } } +void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey) +{ + m_GradientBuilder = new TvgLinearGradientBuilder(sx, sy, ex, ey); +} + +void TvgRenderPaint::radialGradient(float sx, float sy, float ex, float ey) +{ + m_GradientBuilder = new TvgRadialGradientBuilder(sx, sy, ex, ey); +} + +void TvgRenderPaint::addStop(unsigned int color, float stop) +{ + m_GradientBuilder->stops.emplace_back(GradientStop(color, stop)); +} + +void TvgRenderPaint::completeGradient() +{ + m_GradientBuilder->make(&m_Paint); + delete m_GradientBuilder; +} + +void TvgRenderPaint::blendMode(BlendMode value) +{ + +} + void TvgRadialGradientBuilder::make(TvgPaint* paint) { /* Implements Tvg Radial Gradient Here*/ @@ -254,28 +228,56 @@ void TvgLinearGradientBuilder::make(TvgPaint* paint) } } -void TvgRenderPaint::linearGradient(float sx, float sy, float ex, float ey) +void TvgRenderer::save() { - m_GradientBuilder = new TvgLinearGradientBuilder(sx, sy, ex, ey); + } -void TvgRenderPaint::radialGradient(float sx, float sy, float ex, float ey) +void TvgRenderer::restore() { - m_GradientBuilder = new TvgRadialGradientBuilder(sx, sy, ex, ey); + } -void TvgRenderPaint::addStop(unsigned int color, float stop) +void TvgRenderer::transform(const Mat2D& transform) { - m_GradientBuilder->stops.emplace_back(GradientStop(color, stop)); + m_Transform = transform; } -void TvgRenderPaint::completeGradient() +void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) { - m_GradientBuilder->make(&m_Paint); - delete m_GradientBuilder; + auto renderPath = static_cast(path); + auto shape = static_cast(path)->shape(); + auto tvgPaint = static_cast(paint)->paint(); + + /* OPTIMIZE ME: Stroke / Fill Paints required to draw separately. + thorvg doesn't need to handle both, we can avoid one of them rendering... */ + + if (tvgPaint->style == RenderPaintStyle::fill) + { + shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); + } + else if (tvgPaint->style == RenderPaintStyle::stroke) + { + shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); + shape->stroke(tvgPaint->cap); + shape->stroke(tvgPaint->join); + shape->stroke(tvgPaint->thickness); + } + + shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1}); + + if (renderPath->onCanvas()) + { + m_Canvas->update(shape); + } + else + { + m_Canvas->push(unique_ptr(shape)); + renderPath->onCanvas(true); + } } -void TvgRenderPaint::blendMode(BlendMode value) +void TvgRenderer::clipPath(RenderPath* path) { } -- 2.7.4 From ab0789686c23375ceaca2acff90fddf89d1f87a0 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Tue, 16 Mar 2021 16:13:36 +0900 Subject: [PATCH 07/16] renderer: remove tabs --- src/renderer/src/thorvg_renderer.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index 455dcf4..418a79e 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -6,7 +6,7 @@ using namespace rive; TvgRenderPath::TvgRenderPath() { - this->m_Shape = tvg::Shape::gen().release(); + this->m_Shape = tvg::Shape::gen().release(); } TvgRenderPath::~TvgRenderPath() @@ -16,28 +16,28 @@ TvgRenderPath::~TvgRenderPath() void TvgRenderPath::fillRule(FillRule value) { - switch (value) - { - case FillRule::evenOdd: - m_Shape->fill(tvg::FillRule::EvenOdd); - break; - case FillRule::nonZero: + switch (value) + { + case FillRule::evenOdd: + m_Shape->fill(tvg::FillRule::EvenOdd); + break; + case FillRule::nonZero: m_Shape->fill(tvg::FillRule::Winding); - break; - } + break; + } } Point applyTransform(const Vec2D &vec, const Mat2D &mat) { - Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; - m.e11 = mat[0]; - m.e12 = mat[2]; - m.e13 = mat[4]; - m.e21 = mat[1]; - m.e22 = mat[3]; - m.e23 = mat[5]; - - return {vec[0] * m.e11 + vec[1] * m.e12 + m.e13, vec[0] * m.e21 + vec[1] * m.e22 + m.e23}; + Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + m.e11 = mat[0]; + m.e12 = mat[2]; + m.e13 = mat[4]; + m.e21 = mat[1]; + m.e22 = mat[3]; + m.e23 = mat[5]; + + return {vec[0] * m.e11 + vec[1] * m.e12 + m.e13, vec[0] * m.e21 + vec[1] * m.e22 + m.e23}; } void TvgRenderPath::reset() -- 2.7.4 From 456e3c334e1491f7e9919776572f92eacbdd2fde Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Tue, 16 Mar 2021 16:51:13 +0900 Subject: [PATCH 08/16] add more rive resources. --- example/resource/beach_icon.riv | Bin 0 -> 5675 bytes example/resource/calendar_icon2.riv | Bin 0 -> 5131 bytes example/resource/gradienttest.riv | Bin 0 -> 18385 bytes example/resource/headphones.riv | Bin 0 -> 1820 bytes example/resource/knight_nobackground.riv | Bin 0 -> 50830 bytes example/resource/notebook_demo2.riv | Bin 0 -> 3337 bytes example/resource/phone_drop.riv | Bin 0 -> 15339 bytes example/resource/weather_icon_example.riv | Bin 0 -> 3346 bytes 8 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 example/resource/beach_icon.riv create mode 100644 example/resource/calendar_icon2.riv create mode 100644 example/resource/gradienttest.riv create mode 100644 example/resource/headphones.riv create mode 100644 example/resource/knight_nobackground.riv create mode 100644 example/resource/notebook_demo2.riv create mode 100644 example/resource/phone_drop.riv create mode 100644 example/resource/weather_icon_example.riv diff --git a/example/resource/beach_icon.riv b/example/resource/beach_icon.riv new file mode 100644 index 0000000000000000000000000000000000000000..6a0ffb43bf68f51c072fbc21049bc5300e483c80 GIT binary patch literal 5675 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 EAES$x6951J literal 0 HcmV?d00001 diff --git a/example/resource/gradienttest.riv b/example/resource/gradienttest.riv new file mode 100644 index 0000000000000000000000000000000000000000..0dc6ffc8f898ca4d5869dfb9a83faa4606bf2817 GIT binary patch literal 18385 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 literal 0 HcmV?d00001 diff --git a/example/resource/headphones.riv b/example/resource/headphones.riv new file mode 100644 index 0000000000000000000000000000000000000000..a448b705858c4bd2156b6531c1cdb2e8101ff8f2 GIT binary patch literal 1820 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 literal 0 HcmV?d00001 diff --git a/example/resource/notebook_demo2.riv b/example/resource/notebook_demo2.riv new file mode 100644 index 0000000000000000000000000000000000000000..16384aea2b21c3ee5ff9aa77baf9390ba2402a51 GIT binary patch literal 3337 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 S7D5C{N1q-Qoq`G-qyGmCjDjEl literal 0 HcmV?d00001 -- 2.7.4 From f9ce9e82946b43a6e19cafeb54eff50d350f639e Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Tue, 16 Mar 2021 16:34:15 +0900 Subject: [PATCH 09/16] renderer: Implements Linear Gradient and Radial Gradeint. --- src/renderer/include/thorvg_renderer.hpp | 4 ++ src/renderer/src/thorvg_renderer.cpp | 69 ++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/renderer/include/thorvg_renderer.hpp b/src/renderer/include/thorvg_renderer.hpp index 7709a4e..267f22a 100644 --- a/src/renderer/include/thorvg_renderer.hpp +++ b/src/renderer/include/thorvg_renderer.hpp @@ -14,9 +14,13 @@ namespace rive { uint8_t color[4]; float thickness; + tvg::Fill *gradientFill; tvg::StrokeJoin join = tvg::StrokeJoin::Bevel; tvg::StrokeCap cap = tvg::StrokeCap::Butt; RenderPaintStyle style; + bool isGradient; + bool gradientApplied; + TvgPaint() : isGradient(false), gradientApplied(false) {} }; class TvgRenderPath : public RenderPath diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index 418a79e..fd7d609 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -201,31 +201,49 @@ void TvgRenderPaint::blendMode(BlendMode value) void TvgRadialGradientBuilder::make(TvgPaint* paint) { - /* Implements Tvg Radial Gradient Here*/ + paint->isGradient = true; int numStops = stops.size(); - if (numStops != 0) + + paint->gradientFill = tvg::RadialGradient::gen().release(); + float radius = Vec2D::distance(Vec2D(sx, sy), Vec2D(ex, ey)); + static_cast(paint->gradientFill)->radial(sx, sy, radius); + + tvg::Fill::ColorStop colorStops[numStops]; + for (int i = 0; i < numStops; i++) { - unsigned int value = stops[0].color; - paint->color[0] = value >> 16 & 255; - paint->color[1] = value >> 8 & 255; - paint->color[2] = value >> 0 & 255; - paint->color[3] = value >> 24 & 255; + unsigned int value = stops[i].color; + uint8_t r = value >> 16 & 255; + uint8_t g = value >> 8 & 255; + uint8_t b = value >> 0 & 255; + uint8_t a = value >> 24 & 255; + + colorStops[i] = {stops[i].stop, r, g, b, a}; } + + static_cast(paint->gradientFill)->colorStops(colorStops, numStops); } void TvgLinearGradientBuilder::make(TvgPaint* paint) { - /* Implements Tvg Linear Gradient Here*/ + paint->isGradient = true; int numStops = stops.size(); - if (numStops != 0) + paint->gradientFill = tvg::LinearGradient::gen().release(); + static_cast(paint->gradientFill)->linear(sx, sy, ex, ey); + + tvg::Fill::ColorStop colorStops[numStops]; + for (int i = 0; i < numStops; i++) { - unsigned int value = stops[0].color; - paint->color[0] = value >> 16 & 255; - paint->color[1] = value >> 8 & 255; - paint->color[2] = value >> 0 & 255; - paint->color[3] = value >> 24 & 255; + unsigned int value = stops[i].color; + uint8_t r = value >> 16 & 255; + uint8_t g = value >> 8 & 255; + uint8_t b = value >> 0 & 255; + uint8_t a = value >> 24 & 255; + + colorStops[i] = {stops[i].stop, r, g, b, a}; } + + static_cast(paint->gradientFill)->colorStops(colorStops, numStops); } void TvgRenderer::save() @@ -254,14 +272,33 @@ void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) if (tvgPaint->style == RenderPaintStyle::fill) { - shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); + if (tvgPaint->isGradient == false) + shape->fill(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); + else + { + if (tvgPaint->gradientApplied == false) + { + shape->fill(unique_ptr(tvgPaint->gradientFill)); + tvgPaint->gradientApplied = true; + } + } } else if (tvgPaint->style == RenderPaintStyle::stroke) { - shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); shape->stroke(tvgPaint->cap); shape->stroke(tvgPaint->join); shape->stroke(tvgPaint->thickness); + + if (tvgPaint->isGradient == false) + shape->stroke(tvgPaint->color[0], tvgPaint->color[1], tvgPaint->color[2], tvgPaint->color[3]); + else + { + if (tvgPaint->gradientApplied == false) + { + shape->stroke(unique_ptr(tvgPaint->gradientFill)); + tvgPaint->gradientApplied = true; + } + } } shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1}); -- 2.7.4 From 2909aedeadd3f9371c38e52b88d3e4152c88126e Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Tue, 16 Mar 2021 19:21:23 +0900 Subject: [PATCH 10/16] example: remove unnecessary resource. --- example/resource/shapes.riv | Bin 518 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 example/resource/shapes.riv diff --git a/example/resource/shapes.riv b/example/resource/shapes.riv deleted file mode 100644 index ec610a1276a173b897a0b47e8f87f6aff21d4ab6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 518 zcmZXOKTpC?6vfXgywa-WkAhHQs4*dNaF7tfSi(aMt3ezbO$P^KB8h|38=Z7@^Bd?# zfY3Pb8EoR>=3ty0@jeQr#wPE*+k1ZJ+J=UsyPv~i2#V03`2q{H%^2Z?ViFGM7I?uf^n4LE{Mr6BusA5 z(grP^p{3QEtNPfPQWNyEQLWW#Q)o_8zxDs*mRvso -- 2.7.4 From 14f48163ef2f7e486226392885e5e0cf5bbce93f Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Wed, 17 Mar 2021 17:55:03 +0900 Subject: [PATCH 11/16] example, renderer: implements viewport, save and restore transform matrix function. --- example/rive_viewer.cpp | 4 ++++ src/renderer/include/thorvg_renderer.hpp | 1 + src/renderer/src/thorvg_renderer.cpp | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/example/rive_viewer.cpp b/example/rive_viewer.cpp index 76eb22b..4299da8 100644 --- a/example/rive_viewer.cpp +++ b/example/rive_viewer.cpp @@ -142,6 +142,10 @@ Eina_Bool animationLoop(void *data) rive::TvgRenderer renderer(renderCanvas); renderer.save(); + renderer.align(rive::Fit::contain, + rive::Alignment::center, + rive::AABB(0, 0, WIDTH, HEIGHT), + artboard->bounds()); artboard->draw(&renderer); renderer.restore(); } diff --git a/src/renderer/include/thorvg_renderer.hpp b/src/renderer/include/thorvg_renderer.hpp index 267f22a..32bda53 100644 --- a/src/renderer/include/thorvg_renderer.hpp +++ b/src/renderer/include/thorvg_renderer.hpp @@ -116,6 +116,7 @@ namespace rive private: Canvas* m_Canvas; Mat2D m_Transform; + Mat2D m_SaveTransform; public: TvgRenderer(Canvas* canvas) : m_Canvas(canvas) {} diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index fd7d609..d0eb3f3 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -248,17 +248,17 @@ void TvgLinearGradientBuilder::make(TvgPaint* paint) void TvgRenderer::save() { - + m_SaveTransform = m_Transform; } void TvgRenderer::restore() { - + m_Transform = m_SaveTransform; } void TvgRenderer::transform(const Mat2D& transform) { - m_Transform = transform; + m_Transform = m_Transform * transform; } void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) -- 2.7.4 From 119844bbbcd8b84a4324c9eaa16ab6dc968aaa99 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Wed, 17 Mar 2021 19:08:12 +0900 Subject: [PATCH 12/16] renderer: remove the tab --- src/renderer/src/thorvg_renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index d0eb3f3..300deaf 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -205,7 +205,7 @@ void TvgRadialGradientBuilder::make(TvgPaint* paint) int numStops = stops.size(); paint->gradientFill = tvg::RadialGradient::gen().release(); - float radius = Vec2D::distance(Vec2D(sx, sy), Vec2D(ex, ey)); + float radius = Vec2D::distance(Vec2D(sx, sy), Vec2D(ex, ey)); static_cast(paint->gradientFill)->radial(sx, sy, radius); tvg::Fill::ColorStop colorStops[numStops]; -- 2.7.4 From 48de356a4457ec2b21ef5ded505da3ebfccdbe92 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Wed, 17 Mar 2021 19:10:09 +0900 Subject: [PATCH 13/16] example: remove the unnecessary resources. --- example/resource/gradienttest.riv | Bin 18385 -> 0 bytes example/resource/headphones.riv | Bin 1820 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 example/resource/gradienttest.riv delete mode 100644 example/resource/headphones.riv diff --git a/example/resource/gradienttest.riv b/example/resource/gradienttest.riv deleted file mode 100644 index 0dc6ffc8f898ca4d5869dfb9a83faa4606bf2817..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18385 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 diff --git a/example/resource/headphones.riv b/example/resource/headphones.riv deleted file mode 100644 index a448b705858c4bd2156b6531c1cdb2e8101ff8f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1820 zcmbu9NoW&c6vy989AlFvwlQiZ)-*0vBZ9TDR%@MaI+Kiz+o7(gSj1gXi=uc?5k#%% z!5z)1B8W)EgT090(zv4_ZUw7Qp)Lmxih_b-eeau@reo8C7|2K7|GoGBe)A_xZE8WX zuM1A+!(b3*3T}X!L_a$60M_XqfRye9{N&RCVjoY0M2{D)80=}~~bk}E_eG9B~in2-C~g0}t-ZY-o< zFajqQjX$l+xRIILuw;$Sm(+AHVJ^|Ay_8bTr94T5kR*-=Xw*uDGJt^8uLR9Ik=8wZ z%jRwMbrU230X+q9c?>J0!w=67G6eKS1-vvrG%|C&MP9o5drNI(($O1p@%agc>spu2 zdg@y3qDHUk(76xSZ<>0ZZvd|Jh{+TSv5ykDPI)R{lOlkVG7&9tkh zN=RRQ?~tMn3cuh^FB#Js4i%Fge|uO_&+6|;A9W3Hc=m80pC7SHQIBdUIH2RmPlei!+wlG`qvi6k})oVjWwS8Q+rQUWXa8SBOkC zo@`0BSZ39Bhns0e`-XC@hglF@;qv|ZF`$C49yFoLDvbv#mQAxR>+0~! zx>^=_( Date: Thu, 18 Mar 2021 21:14:05 +0900 Subject: [PATCH 14/16] renderer: Implements ClipPath function. - ClipPath transform matrix is calculated by transform matrix in addRenderPath function. --- src/renderer/include/thorvg_renderer.hpp | 1 + src/renderer/src/thorvg_renderer.cpp | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/renderer/include/thorvg_renderer.hpp b/src/renderer/include/thorvg_renderer.hpp index 32bda53..d3f8101 100644 --- a/src/renderer/include/thorvg_renderer.hpp +++ b/src/renderer/include/thorvg_renderer.hpp @@ -115,6 +115,7 @@ namespace rive { private: Canvas* m_Canvas; + Shape* m_ClipPath; Mat2D m_Transform; Mat2D m_SaveTransform; diff --git a/src/renderer/src/thorvg_renderer.cpp b/src/renderer/src/thorvg_renderer.cpp index 300deaf..020804f 100644 --- a/src/renderer/src/thorvg_renderer.cpp +++ b/src/renderer/src/thorvg_renderer.cpp @@ -49,12 +49,14 @@ void TvgRenderPath::reset() void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) { - auto m_PathType = static_cast(path)->m_PathType; - auto m_PathPoints = static_cast(path)->m_PathPoints; - int index = 0; + m_PathType = static_cast(path)->m_PathType; + /* OPTIMIZE ME: Should avoid data copy here */ + auto srcPathPoints = static_cast(path)->m_PathPoints; + m_PathPoints.resize(srcPathPoints.size()); + std::copy(srcPathPoints.begin(), srcPathPoints.end(), m_PathPoints.begin()); /* OPTIMIZE ME: Should avoid data copy in loop... */ - + int index = 0; for (size_t i = 0; i < m_PathType.size(); i++) { /* OPTIMIZE ME: apply transform only when it's not identity */ @@ -63,6 +65,7 @@ void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) case PathCommand::MoveTo: { auto pt = applyTransform(m_PathPoints[index], transform); + m_PathPoints[index] = {pt.x, pt.y}; m_Shape->moveTo(pt.x, pt.y); index += 1; break; @@ -70,6 +73,7 @@ void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) case PathCommand::LineTo: { auto pt = applyTransform(m_PathPoints[index], transform); + m_PathPoints[index] = {pt.x, pt.y}; m_Shape->lineTo(pt.x, pt.y); index += 1; break; @@ -79,6 +83,9 @@ void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform) auto pt1 = applyTransform(m_PathPoints[index], transform); auto pt2 = applyTransform(m_PathPoints[index + 1], transform); auto pt3 = applyTransform(m_PathPoints[index + 2], transform); + m_PathPoints[index] = {pt1.x, pt1.y}; + m_PathPoints[index + 1] = {pt2.x, pt2.y}; + m_PathPoints[index + 2] = {pt3.x, pt3.y}; m_Shape->cubicTo(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); index += 3; break; @@ -301,6 +308,13 @@ void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) } } + if (m_ClipPath) + { + m_ClipPath->fill(255, 255, 255, 255); + shape->composite(unique_ptr(static_cast(m_ClipPath->duplicate())), tvg::CompositeMethod::ClipPath); + m_ClipPath = nullptr; + } + shape->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1}); if (renderPath->onCanvas()) @@ -316,7 +330,9 @@ void TvgRenderer::drawPath(RenderPath* path, RenderPaint* paint) void TvgRenderer::clipPath(RenderPath* path) { - + //Note: ClipPath transform matrix is calculated by transfrom matrix in addRenderPath function + m_ClipPath = static_cast(path)->shape(); + m_ClipPath->transform({m_Transform[0], m_Transform[2], m_Transform[4], m_Transform[1], m_Transform[3], m_Transform[5], 0, 0, 1}); } namespace rive -- 2.7.4 From c40edc9818dd509e7d5d1e597be474b402068f9f Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Fri, 19 Mar 2021 16:04:54 +0900 Subject: [PATCH 15/16] example: rename resources according to rive feature categories. --- example/resource/{knight063.riv => blend_knight.riv} | Bin ...night_nobackground.riv => blend_knight_nobackground.riv} | Bin example/resource/{juice063.riv => bone_juice.riv} | Bin example/resource/{marty_v6.riv => bone_marty.riv} | Bin example/resource/{notebook_demo2.riv => bone_notebook.riv} | Bin .../resource/{beach_icon.riv => clippath_beach_icon.riv} | Bin ...endar_icon2.riv => clippath_draworder_calendar_icon.riv} | Bin .../{poison_loader.riv => gradation_poision_loader.riv} | Bin ...{weather_icon_example.riv => gradation_weather_icon.riv} | Bin example/resource/{heart.riv => shape_heart.riv} | Bin example/resource/{phone_drop.riv => shape_phone_drop.riv} | Bin ...tification_icon_3.riv => trimpath_notification_icon.riv} | Bin 12 files changed, 0 insertions(+), 0 deletions(-) rename example/resource/{knight063.riv => blend_knight.riv} (100%) rename example/resource/{knight_nobackground.riv => blend_knight_nobackground.riv} (100%) rename example/resource/{juice063.riv => bone_juice.riv} (100%) rename example/resource/{marty_v6.riv => bone_marty.riv} (100%) rename example/resource/{notebook_demo2.riv => bone_notebook.riv} (100%) rename example/resource/{beach_icon.riv => clippath_beach_icon.riv} (100%) rename example/resource/{calendar_icon2.riv => clippath_draworder_calendar_icon.riv} (100%) rename example/resource/{poison_loader.riv => gradation_poision_loader.riv} (100%) rename example/resource/{weather_icon_example.riv => gradation_weather_icon.riv} (100%) rename example/resource/{heart.riv => shape_heart.riv} (100%) rename example/resource/{phone_drop.riv => shape_phone_drop.riv} (100%) rename example/resource/{notification_icon_3.riv => trimpath_notification_icon.riv} (100%) diff --git a/example/resource/knight063.riv b/example/resource/blend_knight.riv similarity index 100% rename from example/resource/knight063.riv rename to example/resource/blend_knight.riv diff --git a/example/resource/knight_nobackground.riv b/example/resource/blend_knight_nobackground.riv similarity index 100% rename from example/resource/knight_nobackground.riv rename to example/resource/blend_knight_nobackground.riv diff --git a/example/resource/juice063.riv b/example/resource/bone_juice.riv similarity index 100% rename from example/resource/juice063.riv rename to example/resource/bone_juice.riv diff --git a/example/resource/marty_v6.riv b/example/resource/bone_marty.riv similarity index 100% rename from example/resource/marty_v6.riv rename to example/resource/bone_marty.riv diff --git a/example/resource/notebook_demo2.riv b/example/resource/bone_notebook.riv similarity index 100% rename from example/resource/notebook_demo2.riv rename to example/resource/bone_notebook.riv diff --git a/example/resource/beach_icon.riv b/example/resource/clippath_beach_icon.riv similarity index 100% rename from example/resource/beach_icon.riv rename to example/resource/clippath_beach_icon.riv diff --git a/example/resource/calendar_icon2.riv b/example/resource/clippath_draworder_calendar_icon.riv similarity index 100% rename from example/resource/calendar_icon2.riv rename to example/resource/clippath_draworder_calendar_icon.riv diff --git a/example/resource/poison_loader.riv b/example/resource/gradation_poision_loader.riv similarity index 100% rename from example/resource/poison_loader.riv rename to example/resource/gradation_poision_loader.riv diff --git a/example/resource/weather_icon_example.riv b/example/resource/gradation_weather_icon.riv similarity index 100% rename from example/resource/weather_icon_example.riv rename to example/resource/gradation_weather_icon.riv diff --git a/example/resource/heart.riv b/example/resource/shape_heart.riv similarity index 100% rename from example/resource/heart.riv rename to example/resource/shape_heart.riv diff --git a/example/resource/phone_drop.riv b/example/resource/shape_phone_drop.riv similarity index 100% rename from example/resource/phone_drop.riv rename to example/resource/shape_phone_drop.riv diff --git a/example/resource/notification_icon_3.riv b/example/resource/trimpath_notification_icon.riv similarity index 100% rename from example/resource/notification_icon_3.riv rename to example/resource/trimpath_notification_icon.riv -- 2.7.4 From 7d272958e104a13d947212457bf4712ed8a7d3d3 Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Mon, 29 Mar 2021 15:07:40 +0900 Subject: [PATCH 16/16] submodule : deinit submodule for gbs build gbs does not support submodule build so deinit submodule Change-Id: I9160bea306317384f66fa7275f18d80230439530 --- .gitmodules | 3 --- submodule | 1 - 2 files changed, 4 deletions(-) delete mode 160000 submodule diff --git a/.gitmodules b/.gitmodules index 9bcccd8..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "submodule"] - path = submodule - url = https://github.com/taehyub/rive-cpp.git diff --git a/submodule b/submodule deleted file mode 160000 index feac2ae..0000000 --- a/submodule +++ /dev/null @@ -1 +0,0 @@ -Subproject commit feac2aee679f1cbf69393a62d5e774337e980d75 -- 2.7.4