renderer, example: implments shape animation
authorTaehyub Kim <taehyub.kim@samsung.com>
Thu, 11 Mar 2021 08:25:47 +0000 (17:25 +0900)
committerHermet Park <hermetpark@gmail.com>
Thu, 11 Mar 2021 08:36:29 +0000 (17:36 +0900)
example/rive_viewer.cpp
example/shapes.riv
src/renderer/include/thorvg_renderer.hpp
src/renderer/src/thorvg_renderer.cpp

index f879228..5cae43f 100644 (file)
@@ -13,8 +13,13 @@ using namespace std;
 #define HEIGHT 700
 
 static unique_ptr<tvg::SwCanvas> canvas;
+static tvg::Canvas *renderCanvas;
+static rive::File* file = nullptr;
 static rive::Artboard* artboard = nullptr;
 static rive::LinearAnimationInstance* animationInstance = nullptr;
+static Ecore_Animator *animator = nullptr;
+static Eo* view = nullptr;
+static double lastTime;
 
 static void deleteWindow(void *data, Evas_Object *obj, void *ev)
 {
@@ -29,11 +34,40 @@ static void drawToCanvas(void* data, Eo* obj)
     }
 }
 
+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();
 
     // Load Rive File
     const char* filename = "../../example/shapes.riv";
@@ -52,7 +86,6 @@ 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)
     {
@@ -62,6 +95,7 @@ static void runExample(uint32_t* buffer)
     }
 
     artboard = file->artboard();
+    artboard->advance(0.0f);
 
     delete animationInstance;
 
@@ -69,27 +103,23 @@ static void runExample(uint32_t* buffer)
     if (animation != nullptr)
     {
        animationInstance = new rive::LinearAnimationInstance(animation);
-       animationInstance->advance(0);
     }
     else
     {
        animationInstance = nullptr;
     }
 
-    rive::TvgRenderer renderer(canvas.get());
-
-    renderer.save();
-    artboard->advance(0);
-    artboard->draw(&renderer);
-    renderer.restore();
+    lastTime = ecore_time_get();
+    ecore_animator_frametime_set(1. / 60);
+    animator = ecore_animator_add(animationLoop, nullptr);
 
     delete[] bytes;
-    delete file;
 }
 
 
 static void cleanExample()
 {
+    delete file;
     delete animationInstance;
 }
 
@@ -99,7 +129,7 @@ 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);
 
-    Eo* view = evas_object_image_filled_add(evas_object_evas_get(win));
+    view = evas_object_image_filled_add(evas_object_evas_get(win));
     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);
index 73e0d73..ec610a1 100644 (file)
Binary files a/example/shapes.riv and b/example/shapes.riv differ
index 1fc1c4c..9b86fa6 100644 (file)
@@ -10,11 +10,6 @@ using namespace std;
 
 namespace rive
 {
-   struct TvgPoint
-   {
-      float x, y;
-   };
-
    struct TvgPaint
    {
       int fillColor[4];
@@ -32,7 +27,7 @@ namespace rive
    private:
       Shape *m_Shape;
       vector<PathCommand> m_PathType;
-      vector<TvgPoint> m_PathPoints;
+      vector<Vec2D> m_PathPoints;
       bool m_Pushed = false;
 
    public:
index e72076d..a2ad0b9 100644 (file)
@@ -21,10 +21,28 @@ void TvgRenderPath::fillRule(FillRule value)
        }
 }
 
+Vec2D applyTransform(const Vec2D &vec, const Mat2D &mat)
+{
+       tvg::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];
+
+       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;
+}
+
 void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform)
 {
    auto m_PathType = reinterpret_cast<TvgRenderPath*>(path)->m_PathType;
    auto m_PathPoints = reinterpret_cast<TvgRenderPath*>(path)->m_PathPoints;
+   Vec2D vec1, vec2, vec3, vecOut1, vecOut2, vecOut3;
 
    int index = 0;
    for (size_t i = 0; i < m_PathType.size(); i++)
@@ -33,17 +51,22 @@ void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform)
       switch(type)
       {
          case PathCommand::MoveTo:
-            m_Shape->moveTo(m_PathPoints[index].x, m_PathPoints[index].y);
+            vecOut1 = applyTransform(m_PathPoints[index], transform);
+            m_Shape->moveTo(vecOut1[0], vecOut1[1]);
             index += 1;
             break;
          case PathCommand::LineTo:
-            m_Shape->lineTo(m_PathPoints[index].x, m_PathPoints[index].y);
+            vecOut1 = applyTransform(m_PathPoints[index], transform);
+            m_Shape->lineTo(vecOut1[0], vecOut1[1]);
             index += 1;
             break;
          case PathCommand::CubicTo:
-            m_Shape->cubicTo(m_PathPoints[index].x, m_PathPoints[index].y,
-                             m_PathPoints[index+1].x, m_PathPoints[index+1].y,
-                             m_PathPoints[index+2].x, m_PathPoints[index+2].y);
+            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]);
             index += 3;
             break;
          case PathCommand::Close:
@@ -55,6 +78,7 @@ void TvgRenderPath::addRenderPath(RenderPath* path, const Mat2D& transform)
 
 void TvgRenderPath::reset()
 {
+   m_Shape->reset();
    m_PathType.clear();
    m_PathPoints.clear();
 }
@@ -245,4 +269,4 @@ namespace rive
 {
    RenderPath* makeRenderPath() { return new TvgRenderPath();}
    RenderPaint* makeRenderPaint() { return new TvgRenderPaint();}
-}
\ No newline at end of file
+}