Particles: SkImageBinding to allow sampling an image from script
Provides functionality similar to AE property maps
Change-Id: I1705706a6b7e25fbab55465f2e20d0b145330b0b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/255977
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/modules/particles/src/SkParticleBinding.cpp b/modules/particles/src/SkParticleBinding.cpp
index e0d3328..e654e05 100644
--- a/modules/particles/src/SkParticleBinding.cpp
+++ b/modules/particles/src/SkParticleBinding.cpp
@@ -7,7 +7,9 @@
#include "modules/particles/include/SkParticleBinding.h"
+#include "include/core/SkBitmap.h"
#include "include/core/SkContourMeasure.h"
+#include "include/core/SkImage.h"
#include "include/core/SkPath.h"
#include "include/utils/SkParsePath.h"
#include "include/utils/SkRandom.h"
@@ -193,6 +195,74 @@
SkPathContours fContours;
};
+// Exposes an SkBitmap as an external, callable value. p(xy) returns a float4
+class SkBitmapExternalValue : public SkParticleExternalValue {
+public:
+ SkBitmapExternalValue(const char* name, SkSL::Compiler& compiler, const SkBitmap& bitmap)
+ : SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
+ , fBitmap(bitmap) {
+ SkASSERT(bitmap.colorType() == kRGBA_F32_SkColorType);
+ }
+
+ bool canCall() const override { return true; }
+ int callParameterCount() const override { return 1; }
+ void getCallParameterTypes(const SkSL::Type** outTypes) const override {
+ outTypes[0] = fCompiler.context().fFloat2_Type.get();
+ }
+
+ void call(int index, float* arguments, float* outReturn) override {
+ int x = SkTPin(static_cast<int>(arguments[0] * fBitmap.width()), 0, fBitmap.width() - 1);
+ int y = SkTPin(static_cast<int>(arguments[1] * fBitmap.height()), 0, fBitmap.height() - 1);
+ float* p = static_cast<float*>(fBitmap.getAddr(x, y));
+ memcpy(outReturn, p, 4 * sizeof(float));
+ }
+
+private:
+ SkBitmap fBitmap;
+};
+
+class SkImageBinding : public SkParticleBinding {
+public:
+ SkImageBinding(const char* name = "", const char* imagePath = "", const char* imageName = "")
+ : SkParticleBinding(name)
+ , fImagePath(imagePath)
+ , fImageName(imageName) {}
+
+ REFLECTED(SkImageBinding, SkParticleBinding)
+
+ void visitFields(SkFieldVisitor* v) override {
+ SkParticleBinding::visitFields(v);
+ v->visit("ImagePath", fImagePath);
+ v->visit("ImageName", fImageName);
+ }
+
+ std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
+ return std::unique_ptr<SkParticleExternalValue>(
+ new SkBitmapExternalValue(fName.c_str(), compiler, fBitmap));
+ }
+
+ void prepare(const skresources::ResourceProvider* resourceProvider) override {
+ if (auto asset = resourceProvider->loadImageAsset(fImagePath.c_str(), fImageName.c_str(),
+ nullptr)) {
+ if (auto image = asset->getFrame(0)) {
+ fBitmap.allocPixels(image->imageInfo().makeColorType(kRGBA_F32_SkColorType));
+ image->readPixels(fBitmap.pixmap(), 0, 0);
+ return;
+ }
+ }
+
+ fBitmap.allocPixels(SkImageInfo::Make(1, 1, kRGBA_F32_SkColorType, kPremul_SkAlphaType));
+ fBitmap.eraseColor(SK_ColorWHITE);
+ }
+
+private:
+ SkString fImagePath;
+ SkString fImageName;
+
+ // Cached
+ SkBitmap fBitmap;
+};
+
sk_sp<SkParticleBinding> SkParticleBinding::MakeEffectBinding(
const char* name, sk_sp<SkParticleEffectParams> params) {
return sk_sp<SkParticleBinding>(new SkEffectBinding(name, params));
@@ -205,6 +275,7 @@
void SkParticleBinding::RegisterBindingTypes() {
REGISTER_REFLECTED(SkParticleBinding);
REGISTER_REFLECTED(SkEffectBinding);
+ REGISTER_REFLECTED(SkImageBinding);
REGISTER_REFLECTED(SkPathBinding);
REGISTER_REFLECTED(SkTextBinding);
}
diff --git a/resources/particles/mandrill.json b/resources/particles/mandrill.json
new file mode 100644
index 0000000..a53efb8
--- /dev/null
+++ b/resources/particles/mandrill.json
@@ -0,0 +1,38 @@
+{
+ "MaxCount": 4000,
+ "Drawable": {
+ "Type": "SkCircleDrawable",
+ "Radius": 3
+ },
+ "EffectCode": [
+ "void effectSpawn(inout Effect effect) {",
+ " effect.rate = 4000;",
+ "}",
+ "",
+ "void effectUpdate(inout Effect effect) {",
+ "}",
+ ""
+ ],
+ "Code": [
+ "void spawn(inout Particle p) {",
+ " p.lifetime = 1;",
+ " p.pos = float2(rand, rand) * 200;",
+ " p.vel = float2(rand, rand) * 2 - 1;",
+ " p.vel *= 20;",
+ " p.scale = mix(0.25, 1, rand);",
+ "}",
+ "",
+ "void update(inout Particle p) {",
+ " p.color = img(p.pos / 200);",
+ "}",
+ ""
+ ],
+ "Bindings": [
+ {
+ "Type": "SkImageBinding",
+ "Name": "img",
+ "ImagePath": "images",
+ "ImageName": "mandrill_128.png"
+ }
+ ]
+}
\ No newline at end of file