added options to enable caching and draw bounds in NIMA slide

Bug: skia:
Change-Id: I30fed2c0587f36aeccd5e366b823a8b044a371ea
Reviewed-on: https://skia-review.googlesource.com/142164
Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/tools/viewer/NIMASlide.cpp b/tools/viewer/NIMASlide.cpp
index 25d023f..e8827cc 100644
--- a/tools/viewer/NIMASlide.cpp
+++ b/tools/viewer/NIMASlide.cpp
@@ -56,7 +56,7 @@
             , fIndices()
             , fBones()
             , fVertices(nullptr)
-            , fRenderMode(kBackend_RenderMode) {
+            , fRenderFlags(0) {
         // Update the vertices and bones.
         this->updateVertices();
         this->updateBones();
@@ -65,46 +65,65 @@
         this->updateVerticesObject(false, false);
     }
 
-    void renderBackend(SkCanvas* canvas) {
-        // Reset vertices if the render mode has changed.
-        if (fRenderMode != kBackend_RenderMode) {
-            fRenderMode = kBackend_RenderMode;
-            this->updateVertices();
-            this->updateVerticesObject(false, false);
-        }
+    void render(SkCanvas* canvas, uint32_t renderFlags) {
+        bool dirty = renderFlags != fRenderFlags;
+        fRenderFlags = renderFlags;
 
-        // Update the vertex data.
-        if (fActorImage->doesAnimationVertexDeform()) {
-            this->updateVertices();
-            this->updateVerticesObject(false, true);
-        }
+        bool useImmediate = renderFlags & kImmediate_RenderFlag;
+        bool useCache = renderFlags & kCache_RenderFlag;
+        bool drawBounds = renderFlags & kBounds_RenderFlag;
 
-        // Update the bones.
-        this->updateBones();
+        if (useImmediate) {
+            // Immediate mode transforms.
+            // Update the vertex data.
+            if (fActorImage->doesAnimationVertexDeform() && fActorImage->isVertexDeformDirty()) {
+                this->updateVertices();
+                fActorImage->isVertexDeformDirty(false);
+            }
+
+            // Update the vertices object.
+            this->updateVerticesObject(true, true); // Immediate mode vertices change every frame,
+                                                    // so they must be volatile.
+        } else {
+            // Backend transformations.
+            if (fActorImage->doesAnimationVertexDeform()) {
+                // These are vertices that transform beyond just bone transforms, so they must be
+                // updated every frame.
+                this->updateVertices();
+                this->updateVerticesObject(false, true);
+            } else if (dirty) {
+                // If the render flags are dirty, reset the vertices object.
+                this->updateVertices();
+                this->updateVerticesObject(false, !useCache);
+            }
+
+            // Update the bones.
+            this->updateBones();
+        }
 
         // Draw the vertices object.
-        this->drawVerticesObject(canvas, true);
-    }
+        this->drawVerticesObject(canvas, !useImmediate);
 
-    void renderImmediate(SkCanvas* canvas) {
-        // Reset vertices if the render mode has changed.
-        if (fRenderMode != kImmediate_RenderMode) {
-            fRenderMode = kImmediate_RenderMode;
-            this->updateVertices();
-            this->updateVerticesObject(true, true);
+        if (drawBounds && fActorImage->renderOpacity() > 0.0f) {
+            // Get the bounds.
+            SkRect bounds = fVertices->bounds();
+
+            // Approximate bounds if not using immediate transforms.
+            if (!useImmediate) {
+                const SkRect originalBounds = fBones[0].mapRect(fVertices->bounds());
+                bounds = originalBounds;
+                for (size_t i = 1; i < fBones.size(); i++) {
+                    const SkMatrix& matrix = fBones[i];
+                    bounds.join(matrix.mapRect(originalBounds));
+                }
+            }
+
+            // Draw the bounds.
+            SkPaint paint;
+            paint.setStyle(SkPaint::kStroke_Style);
+            paint.setColor(0xFFFF0000);
+            canvas->drawRect(bounds, paint);
         }
-
-        // Update the vertex data.
-        if (fActorImage->doesAnimationVertexDeform() && fActorImage->isVertexDeformDirty()) {
-            this->updateVertices();
-            fActorImage->isVertexDeformDirty(false);
-        }
-
-        // Update the vertices object.
-        this->updateVerticesObject(true, true);
-
-        // Draw the vertices object.
-        this->drawVerticesObject(canvas, false);
     }
 
     int drawOrder() const { return fActorImage->drawOrder(); }
@@ -316,7 +335,7 @@
     std::vector<SkMatrix> fBones;
     sk_sp<SkVertices>     fVertices;
 
-    RenderMode fRenderMode;
+    uint32_t fRenderFlags;
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
@@ -359,21 +378,10 @@
         }
     }
 
-    void render(SkCanvas* canvas, RenderMode renderMode) {
+    void render(SkCanvas* canvas, uint32_t renderFlags) {
         // Render the image nodes.
         for (auto& image : fActorImages) {
-            switch (renderMode) {
-            case kBackend_RenderMode: {
-                // Render with Skia backend.
-                image.renderBackend(canvas);
-                break;
-            }
-            case kImmediate_RenderMode: {
-                // Render with immediate backend.
-                image.renderImmediate(canvas);
-                break;
-            }
-            }
+            image.render(canvas, renderFlags);
         }
     }
 
@@ -397,7 +405,7 @@
         , fActor(nullptr)
         , fPlaying(true)
         , fTime(0.0f)
-        , fRenderMode(kBackend_RenderMode)
+        , fRenderFlags(0)
         , fAnimation(nullptr)
         , fAnimationIndex(0) {
     fName = name;
@@ -425,7 +433,7 @@
             canvas->scale(0.5, -0.5);
 
             // Render the actor.
-            fActor->render(canvas, fRenderMode);
+            fActor->render(canvas, fRenderFlags);
 
             canvas->restore();
         }
@@ -476,7 +484,7 @@
 }
 
 void NIMASlide::renderGUI() {
-    ImGui::SetNextWindowSize(ImVec2(300, 220));
+    ImGui::SetNextWindowSize(ImVec2(300, 0));
     ImGui::Begin("NIMA");
 
     // List of animations.
@@ -506,14 +514,34 @@
     ImGui::SliderFloat("Time", &fTime, 0.0f, fAnimation->max(), "Time: %.3f");
 
     // Backend control.
-    int renderMode = fRenderMode;
+    int useImmediate = SkToBool(fRenderFlags & kImmediate_RenderFlag);
     ImGui::Spacing();
-    ImGui::RadioButton("Skia Backend", &renderMode, 0);
-    ImGui::RadioButton("Immediate Backend", &renderMode, 1);
-    if (renderMode == 0) {
-        fRenderMode = kBackend_RenderMode;
+    ImGui::RadioButton("Skia Backend", &useImmediate, 0);
+    ImGui::RadioButton("Immediate Backend", &useImmediate, 1);
+    if (useImmediate) {
+        fRenderFlags |= kImmediate_RenderFlag;
     } else {
-        fRenderMode = kImmediate_RenderMode;
+        fRenderFlags &= ~kImmediate_RenderFlag;
+    }
+
+    // Cache control.
+    bool useCache = SkToBool(fRenderFlags & kCache_RenderFlag);
+    ImGui::Spacing();
+    ImGui::Checkbox("Cache Vertices", &useCache);
+    if (useCache) {
+        fRenderFlags |= kCache_RenderFlag;
+    } else {
+        fRenderFlags &= ~kCache_RenderFlag;
+    }
+
+    // Bounding box toggle.
+    bool drawBounds = SkToBool(fRenderFlags & kBounds_RenderFlag);
+    ImGui::Spacing();
+    ImGui::Checkbox("Draw Bounds", &drawBounds);
+    if (drawBounds) {
+        fRenderFlags |= kBounds_RenderFlag;
+    } else {
+        fRenderFlags &= ~kBounds_RenderFlag;
     }
 
     ImGui::End();
diff --git a/tools/viewer/NIMASlide.h b/tools/viewer/NIMASlide.h
index d19d101..b4d5d2b 100644
--- a/tools/viewer/NIMASlide.h
+++ b/tools/viewer/NIMASlide.h
@@ -20,9 +20,10 @@
 class NIMAActor;
 class NIMAActorImage;
 
-enum RenderMode {
-    kBackend_RenderMode   = 0,
-    kImmediate_RenderMode = 1,
+enum RenderFlags {
+    kImmediate_RenderFlag = 0x1,
+    kCache_RenderFlag     = 0x2,
+    kBounds_RenderFlag    = 0x4,
 };
 
 class NIMASlide : public Slide {
@@ -50,7 +51,7 @@
 
     bool fPlaying;
     float fTime;
-    RenderMode fRenderMode;
+    uint32_t fRenderFlags;
 
     nima::ActorAnimationInstance* fAnimation;
     int                           fAnimationIndex;