1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "modules/particles/include/SkParticleBinding.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkContourMeasure.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkPath.h"
14 #include "include/private/SkTPin.h"
15 #include "include/utils/SkParsePath.h"
16 #include "include/utils/SkTextUtils.h"
17 #include "modules/particles/include/SkParticleEffect.h"
18 #include "modules/particles/include/SkReflected.h"
19 #include "modules/skresources/include/SkResources.h"
20 #include "src/sksl/SkSLCompiler.h"
21
visitFields(SkFieldVisitor * v)22 void SkParticleBinding::visitFields(SkFieldVisitor* v) {
23 v->visit("Name", fName);
24 }
25
26 class SkEffectExternalValue : public SkParticleExternalValue {
27 public:
SkEffectExternalValue(const char * name,SkSL::Compiler & compiler,sk_sp<SkParticleEffectParams> params)28 SkEffectExternalValue(const char* name, SkSL::Compiler& compiler,
29 sk_sp<SkParticleEffectParams> params)
30 : SkParticleExternalValue(name, compiler, *compiler.context().fVoid_Type)
31 , fParams(std::move(params)) {}
32
canCall() const33 bool canCall() const override { return true; }
callParameterCount() const34 int callParameterCount() const override { return 1; }
getCallParameterTypes(const SkSL::Type ** outTypes) const35 void getCallParameterTypes(const SkSL::Type** outTypes) const override {
36 outTypes[0] = fCompiler.context().fBool_Type.get();
37 }
38
call(int index,float * arguments,float * outReturn) const39 void call(int index, float* arguments, float* outReturn) const override {
40 bool loop = ((int*)arguments)[0] != 0;
41 fEffect->addSpawnRequest(index, loop, fParams);
42 }
43
44 private:
45 sk_sp<SkParticleEffectParams> fParams;
46 };
47
48 class SkEffectBinding : public SkParticleBinding {
49 public:
SkEffectBinding(const char * name="",sk_sp<SkParticleEffectParams> params=nullptr)50 SkEffectBinding(const char* name = "", sk_sp<SkParticleEffectParams> params = nullptr)
51 : SkParticleBinding(name)
52 , fParams(std::move(params)) {
53 if (!fParams) {
54 fParams.reset(new SkParticleEffectParams());
55 }
56 }
57
REFLECTED(SkEffectBinding,SkParticleBinding)58 REFLECTED(SkEffectBinding, SkParticleBinding)
59
60 void visitFields(SkFieldVisitor* v) override {
61 SkParticleBinding::visitFields(v);
62 fParams->visitFields(v);
63 }
64
toValue(SkSL::Compiler & compiler)65 std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
66 return std::unique_ptr<SkParticleExternalValue>(
67 new SkEffectExternalValue(fName.c_str(), compiler, fParams));
68 }
69
prepare(const skresources::ResourceProvider * resourceProvider)70 void prepare(const skresources::ResourceProvider* resourceProvider) override {
71 fParams->prepare(resourceProvider);
72 }
73
74 private:
75 sk_sp<SkParticleEffectParams> fParams;
76 };
77
78 struct SkPathContours {
79 SkScalar fTotalLength;
80 SkTArray<sk_sp<SkContourMeasure>> fContours;
81
rebuildSkPathContours82 void rebuild(const SkPath& path) {
83 fTotalLength = 0;
84 fContours.reset();
85
86 SkContourMeasureIter iter(path, false);
87 while (auto contour = iter.next()) {
88 fContours.push_back(contour);
89 fTotalLength += contour->length();
90 }
91 }
92 };
93
94 // Exposes an SkPath as an external, callable value. p(x) returns a float4 { pos.xy, normal.xy }
95 class SkPathExternalValue : public SkParticleExternalValue {
96 public:
SkPathExternalValue(const char * name,SkSL::Compiler & compiler,const SkPathContours * path)97 SkPathExternalValue(const char* name, SkSL::Compiler& compiler, const SkPathContours* path)
98 : SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
99 , fPath(path) { }
100
canCall() const101 bool canCall() const override { return true; }
callParameterCount() const102 int callParameterCount() const override { return 1; }
getCallParameterTypes(const SkSL::Type ** outTypes) const103 void getCallParameterTypes(const SkSL::Type** outTypes) const override {
104 outTypes[0] = fCompiler.context().fFloat_Type.get();
105 }
106
call(int index,float * arguments,float * outReturn) const107 void call(int index, float* arguments, float* outReturn) const override {
108 SkScalar len = fPath->fTotalLength * arguments[0];
109 int idx = 0;
110 while (idx < fPath->fContours.count() - 1 && len > fPath->fContours[idx]->length()) {
111 len -= fPath->fContours[idx++]->length();
112 }
113 SkVector localXAxis;
114 if (idx >= fPath->fContours.count() ||
115 !fPath->fContours[idx]->getPosTan(len, (SkPoint*)outReturn, &localXAxis)) {
116 outReturn[0] = outReturn[1] = 0.0f;
117 localXAxis = { 1, 0 };
118 }
119 outReturn[2] = localXAxis.fY;
120 outReturn[3] = -localXAxis.fX;
121 }
122
123 private:
124 const SkPathContours* fPath;
125 };
126
127 class SkPathBinding : public SkParticleBinding {
128 public:
SkPathBinding(const char * name="",const char * pathPath="",const char * pathName="")129 SkPathBinding(const char* name = "", const char* pathPath = "", const char* pathName = "")
130 : SkParticleBinding(name)
131 , fPathPath(pathPath)
132 , fPathName(pathName) {}
133
REFLECTED(SkPathBinding,SkParticleBinding)134 REFLECTED(SkPathBinding, SkParticleBinding)
135
136 void visitFields(SkFieldVisitor* v) override {
137 SkParticleBinding::visitFields(v);
138 v->visit("PathPath", fPathPath);
139 v->visit("PathName", fPathName);
140 }
141
toValue(SkSL::Compiler & compiler)142 std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
143 return std::unique_ptr<SkParticleExternalValue>(
144 new SkPathExternalValue(fName.c_str(), compiler, &fContours));
145 }
146
prepare(const skresources::ResourceProvider * resourceProvider)147 void prepare(const skresources::ResourceProvider* resourceProvider) override {
148 if (auto pathData = resourceProvider->load(fPathPath.c_str(), fPathName.c_str())) {
149 SkPath path;
150 if (0 != path.readFromMemory(pathData->data(), pathData->size())) {
151 fContours.rebuild(path);
152 }
153 }
154 }
155
156 private:
157 SkString fPathPath;
158 SkString fPathName;
159
160 // Cached
161 SkPathContours fContours;
162 };
163
164 class SkTextBinding : public SkParticleBinding {
165 public:
SkTextBinding(const char * name="",const char * text="",SkScalar fontSize=96)166 SkTextBinding(const char* name = "", const char* text = "", SkScalar fontSize = 96)
167 : SkParticleBinding(name)
168 , fText(text)
169 , fFontSize(fontSize) {}
170
REFLECTED(SkTextBinding,SkParticleBinding)171 REFLECTED(SkTextBinding, SkParticleBinding)
172
173 void visitFields(SkFieldVisitor* v) override {
174 SkParticleBinding::visitFields(v);
175 v->visit("Text", fText);
176 v->visit("FontSize", fFontSize);
177 }
178
toValue(SkSL::Compiler & compiler)179 std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
180 return std::unique_ptr<SkParticleExternalValue>(
181 new SkPathExternalValue(fName.c_str(), compiler, &fContours));
182 }
183
prepare(const skresources::ResourceProvider *)184 void prepare(const skresources::ResourceProvider*) override {
185 if (fText.isEmpty()) {
186 return;
187 }
188
189 SkFont font(nullptr, fFontSize);
190 SkPath path;
191 SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
192 fContours.rebuild(path);
193 }
194
195 private:
196 SkString fText;
197 SkScalar fFontSize;
198
199 // Cached
200 SkPathContours fContours;
201 };
202
203 // Exposes an SkBitmap as an external, callable value. p(xy) returns a float4
204 class SkBitmapExternalValue : public SkParticleExternalValue {
205 public:
SkBitmapExternalValue(const char * name,SkSL::Compiler & compiler,const SkBitmap & bitmap)206 SkBitmapExternalValue(const char* name, SkSL::Compiler& compiler, const SkBitmap& bitmap)
207 : SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
208 , fBitmap(bitmap) {
209 SkASSERT(bitmap.colorType() == kRGBA_F32_SkColorType);
210 }
211
canCall() const212 bool canCall() const override { return true; }
callParameterCount() const213 int callParameterCount() const override { return 1; }
getCallParameterTypes(const SkSL::Type ** outTypes) const214 void getCallParameterTypes(const SkSL::Type** outTypes) const override {
215 outTypes[0] = fCompiler.context().fFloat2_Type.get();
216 }
217
call(int index,float * arguments,float * outReturn) const218 void call(int index, float* arguments, float* outReturn) const override {
219 int x = SkTPin(static_cast<int>(arguments[0] * fBitmap.width()), 0, fBitmap.width() - 1);
220 int y = SkTPin(static_cast<int>(arguments[1] * fBitmap.height()), 0, fBitmap.height() - 1);
221 float* p = static_cast<float*>(fBitmap.getAddr(x, y));
222 memcpy(outReturn, p, 4 * sizeof(float));
223 }
224
225 private:
226 SkBitmap fBitmap;
227 };
228
229 class SkImageBinding : public SkParticleBinding {
230 public:
SkImageBinding(const char * name="",const char * imagePath="",const char * imageName="")231 SkImageBinding(const char* name = "", const char* imagePath = "", const char* imageName = "")
232 : SkParticleBinding(name)
233 , fImagePath(imagePath)
234 , fImageName(imageName) {}
235
REFLECTED(SkImageBinding,SkParticleBinding)236 REFLECTED(SkImageBinding, SkParticleBinding)
237
238 void visitFields(SkFieldVisitor* v) override {
239 SkParticleBinding::visitFields(v);
240 v->visit("ImagePath", fImagePath);
241 v->visit("ImageName", fImageName);
242 }
243
toValue(SkSL::Compiler & compiler)244 std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
245 return std::unique_ptr<SkParticleExternalValue>(
246 new SkBitmapExternalValue(fName.c_str(), compiler, fBitmap));
247 }
248
prepare(const skresources::ResourceProvider * resourceProvider)249 void prepare(const skresources::ResourceProvider* resourceProvider) override {
250 if (auto asset = resourceProvider->loadImageAsset(fImagePath.c_str(), fImageName.c_str(),
251 nullptr)) {
252 if (auto image = asset->getFrame(0)) {
253 fBitmap.allocPixels(image->imageInfo().makeColorType(kRGBA_F32_SkColorType));
254 image->readPixels(nullptr, fBitmap.pixmap(), 0, 0);
255 return;
256 }
257 }
258
259 fBitmap.allocPixels(SkImageInfo::Make(1, 1, kRGBA_F32_SkColorType, kPremul_SkAlphaType));
260 fBitmap.eraseColor(SK_ColorWHITE);
261 }
262
263 private:
264 SkString fImagePath;
265 SkString fImageName;
266
267 // Cached
268 SkBitmap fBitmap;
269 };
270
MakeEffect(const char * name,sk_sp<SkParticleEffectParams> params)271 sk_sp<SkParticleBinding> SkParticleBinding::MakeEffect(const char* name,
272 sk_sp<SkParticleEffectParams> params) {
273 return sk_sp<SkParticleBinding>(new SkEffectBinding(name, std::move(params)));
274 }
275
MakeImage(const char * name,const char * imagePath,const char * imageName)276 sk_sp<SkParticleBinding> SkParticleBinding::MakeImage(const char* name, const char* imagePath,
277 const char* imageName) {
278 return sk_sp<SkParticleBinding>(new SkImageBinding(name, imagePath, imageName));
279 }
280
MakePath(const char * name,const char * pathPath,const char * pathName)281 sk_sp<SkParticleBinding> SkParticleBinding::MakePath(const char* name, const char* pathPath,
282 const char* pathName) {
283 return sk_sp<SkParticleBinding>(new SkPathBinding(name, pathPath, pathName));
284 }
285
RegisterBindingTypes()286 void SkParticleBinding::RegisterBindingTypes() {
287 REGISTER_REFLECTED(SkParticleBinding);
288 REGISTER_REFLECTED(SkEffectBinding);
289 REGISTER_REFLECTED(SkImageBinding);
290 REGISTER_REFLECTED(SkPathBinding);
291 REGISTER_REFLECTED(SkTextBinding);
292 }
293