Refactor and further generalization of particle model

- Collapsed the per-particle data into a single struct, and
  use that to communicate with drawables, too. Let the drawables
  manage allocation of xforms, colors, etc. Helpful for non-atlas
  drawables, and just to keep the effect code simpler.
- Having all of the params in a single struct allows us to move
  the remaining animated behaviors into affectors (color/frame).
- Added SkColorCurve, which works like SkCurve for SkColor4f.
  Use that to create a color affector (rather than simple
  start/end colors in the effect params).
- Also put the stable random in SkParticleState. This is going
  to be necessary if/when we change affectors to operate on all
  particles (rather than one at a time). Still need to move t
  value into the particle struct (or eval it from the lifetime
  params on demand).

Change-Id: Icf39116acbfd5d6e8eb91e9affbd8898d106211d
Reviewed-on: https://skia-review.googlesource.com/c/193473
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/modules/particles/src/SkParticleDrawable.cpp b/modules/particles/src/SkParticleDrawable.cpp
index fb0c150..0adc87d 100644
--- a/modules/particles/src/SkParticleDrawable.cpp
+++ b/modules/particles/src/SkParticleDrawable.cpp
@@ -12,6 +12,7 @@
 #include "SkCanvas.h"
 #include "SkImage.h"
 #include "SkPaint.h"
+#include "SkParticleData.h"
 #include "SkRect.h"
 #include "SkSurface.h"
 #include "SkString.h"
@@ -27,6 +28,22 @@
     return surface->makeImageSnapshot();
 }
 
+struct DrawAtlasArrays {
+    DrawAtlasArrays(const SkParticleState particles[], int count, SkPoint center)
+            : fXforms(count)
+            , fRects(count)
+            , fColors(count) {
+        for (int i = 0; i < count; ++i) {
+            fXforms[i] = particles[i].fPose.asRSXform(center);
+            fColors[i] = particles[i].fColor.toSkColor();
+        }
+    }
+
+    SkAutoTMalloc<SkRSXform> fXforms;
+    SkAutoTMalloc<SkRect>    fRects;
+    SkAutoTMalloc<SkColor>   fColors;
+};
+
 class SkCircleDrawable : public SkParticleDrawable {
 public:
     SkCircleDrawable(int radius = 1)
@@ -36,18 +53,15 @@
 
     REFLECTED(SkCircleDrawable, SkParticleDrawable)
 
-    void draw(SkCanvas* canvas, const SkRSXform xform[], const float tex[], const SkColor colors[],
-              int count, const SkPaint* paint) override {
-        SkAutoTMalloc<SkRect> texRects(count);
+    void draw(SkCanvas* canvas, const SkParticleState particles[], int count,
+              const SkPaint* paint) override {
+        SkPoint center = { SkIntToScalar(fRadius), SkIntToScalar(fRadius) };
+        DrawAtlasArrays arrays(particles, count, center);
         for (int i = 0; i < count; ++i) {
-            texRects[i].set(0.0f, 0.0f, fImage->width(), fImage->height());
+            arrays.fRects[i].set(0.0f, 0.0f, fImage->width(), fImage->height());
         }
-        canvas->drawAtlas(fImage, xform, texRects.get(), colors, count,
-                          SkBlendMode::kModulate, nullptr, paint);
-    }
-
-    SkPoint center() const override {
-        return { SkIntToScalar(fRadius), SkIntToScalar(fRadius) };
+        canvas->drawAtlas(fImage, arrays.fXforms.get(), arrays.fRects.get(), arrays.fColors.get(),
+                          count, SkBlendMode::kModulate, nullptr, paint);
     }
 
     void visitFields(SkFieldVisitor* v) override {
@@ -80,27 +94,22 @@
 
     REFLECTED(SkImageDrawable, SkParticleDrawable)
 
-    void draw(SkCanvas* canvas, const SkRSXform xform[], const float tex[], const SkColor colors[],
-              int count, const SkPaint* paint) override {
-        SkAutoTMalloc<SkRect> texRects(count);
-
+    void draw(SkCanvas* canvas, const SkParticleState particles[], int count,
+              const SkPaint* paint) override {
         SkRect baseRect = getBaseRect();
-        int frameCount = fCols * fRows;
+        SkPoint center = { baseRect.width() * 0.5f, baseRect.height() * 0.5f };
+        DrawAtlasArrays arrays(particles, count, center);
 
+        int frameCount = fCols * fRows;
         for (int i = 0; i < count; ++i) {
-            int frame = static_cast<int>(tex[i] * frameCount + 0.5f);
+            int frame = static_cast<int>(particles[i].fFrame * frameCount + 0.5f);
             frame = SkTPin(frame, 0, frameCount - 1);
             int row = frame / fCols;
             int col = frame % fCols;
-            texRects[i] = baseRect.makeOffset(col * baseRect.width(), row * baseRect.height());
+            arrays.fRects[i] = baseRect.makeOffset(col * baseRect.width(), row * baseRect.height());
         }
-        canvas->drawAtlas(fImage, xform, texRects.get(), colors, count,
-                          SkBlendMode::kModulate, nullptr, paint);
-    }
-
-    SkPoint center() const override {
-        SkRect baseRect = getBaseRect();
-        return { baseRect.width() * 0.5f, baseRect.height() * 0.5f };
+        canvas->drawAtlas(fImage, arrays.fXforms.get(), arrays.fRects.get(), arrays.fColors.get(),
+                          count, SkBlendMode::kModulate, nullptr, paint);
     }
 
     void visitFields(SkFieldVisitor* v) override {