1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci* Copyright 2019 Google LLC
3cb93a386Sopenharmony_ci*
4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci* found in the LICENSE file.
6cb93a386Sopenharmony_ci*/
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "modules/particles/include/SkParticleBinding.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkContourMeasure.h"
11cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
12cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTPin.h"
14cb93a386Sopenharmony_ci#include "include/utils/SkParsePath.h"
15cb93a386Sopenharmony_ci#include "include/utils/SkTextUtils.h"
16cb93a386Sopenharmony_ci#include "modules/particles/include/SkReflected.h"
17cb93a386Sopenharmony_ci#include "modules/skresources/include/SkResources.h"
18cb93a386Sopenharmony_ci#include "src/core/SkMatrixProvider.h"
19cb93a386Sopenharmony_ci#include "src/core/SkVM.h"
20cb93a386Sopenharmony_ci#include "src/shaders/SkShaderBase.h"
21cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h"
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_civoid SkParticleBinding::visitFields(SkFieldVisitor* v) {
24cb93a386Sopenharmony_ci    v->visit("Name", fName);
25cb93a386Sopenharmony_ci}
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_cinamespace {
28cb93a386Sopenharmony_ci    struct PosNrm { SkPoint pos; SkVector nrm; };
29cb93a386Sopenharmony_ci    using LinearizedPath = std::vector<PosNrm>;
30cb93a386Sopenharmony_ci}  // namespace
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_cistatic LinearizedPath linearize_path(const SkPath& path) {
33cb93a386Sopenharmony_ci    LinearizedPath lin;
34cb93a386Sopenharmony_ci    SkContourMeasureIter iter(path, false);
35cb93a386Sopenharmony_ci    while (auto contour = iter.next()) {
36cb93a386Sopenharmony_ci        for (SkScalar x = 0; x < contour->length(); x++) {
37cb93a386Sopenharmony_ci            SkPoint pos;
38cb93a386Sopenharmony_ci            SkVector tan;
39cb93a386Sopenharmony_ci            SkAssertResult(contour->getPosTan(x, &pos, &tan));
40cb93a386Sopenharmony_ci            lin.push_back({pos, {tan.fY, -tan.fX}});
41cb93a386Sopenharmony_ci        }
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci    return lin;
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci// Exposes an SkPath as an external, callable function. p(x) returns a float4 { pos.xy, normal.xy }
47cb93a386Sopenharmony_ciclass SkPathExternalFunction : public SkParticleExternalFunction {
48cb93a386Sopenharmony_cipublic:
49cb93a386Sopenharmony_ci    SkPathExternalFunction(const char* name,
50cb93a386Sopenharmony_ci                           SkSL::Compiler& compiler,
51cb93a386Sopenharmony_ci                           const LinearizedPath& path,
52cb93a386Sopenharmony_ci                           skvm::Uniforms* uniforms,
53cb93a386Sopenharmony_ci                           SkArenaAlloc* alloc)
54cb93a386Sopenharmony_ci            : SkParticleExternalFunction(
55cb93a386Sopenharmony_ci                      name, compiler, *compiler.context().fTypes.fFloat4, uniforms, alloc)
56cb93a386Sopenharmony_ci            , fPath(path) {}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    int callParameterCount() const override { return 1; }
59cb93a386Sopenharmony_ci    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
60cb93a386Sopenharmony_ci        outTypes[0] = fCompiler.context().fTypes.fFloat.get();
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    void call(skvm::Builder* builder,
64cb93a386Sopenharmony_ci              skvm::F32* arguments,
65cb93a386Sopenharmony_ci              skvm::F32* outResult,
66cb93a386Sopenharmony_ci              skvm::I32 mask) const override {
67cb93a386Sopenharmony_ci        if (fPath.empty()) {
68cb93a386Sopenharmony_ci            return;
69cb93a386Sopenharmony_ci        }
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci        skvm::Uniform ptr = fUniforms->pushPtr(fPath.data());
72cb93a386Sopenharmony_ci        skvm::I32 index = trunc(clamp(arguments[0] * fPath.size(), 0, fPath.size() - 1));
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci        outResult[0] = builder->gatherF(ptr, (index<<2)+0);
75cb93a386Sopenharmony_ci        outResult[1] = builder->gatherF(ptr, (index<<2)+1);
76cb93a386Sopenharmony_ci        outResult[2] = builder->gatherF(ptr, (index<<2)+2);
77cb93a386Sopenharmony_ci        outResult[3] = builder->gatherF(ptr, (index<<2)+3);
78cb93a386Sopenharmony_ci    }
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ciprivate:
81cb93a386Sopenharmony_ci    const LinearizedPath& fPath;
82cb93a386Sopenharmony_ci};
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ciclass SkPathBinding : public SkParticleBinding {
85cb93a386Sopenharmony_cipublic:
86cb93a386Sopenharmony_ci    SkPathBinding(const char* name = "", const char* pathPath = "", const char* pathName = "")
87cb93a386Sopenharmony_ci            : SkParticleBinding(name)
88cb93a386Sopenharmony_ci            , fPathPath(pathPath)
89cb93a386Sopenharmony_ci            , fPathName(pathName) {}
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci    REFLECTED(SkPathBinding, SkParticleBinding)
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    void visitFields(SkFieldVisitor* v) override {
94cb93a386Sopenharmony_ci        SkParticleBinding::visitFields(v);
95cb93a386Sopenharmony_ci        v->visit("PathPath", fPathPath);
96cb93a386Sopenharmony_ci        v->visit("PathName", fPathName);
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    std::unique_ptr<SkParticleExternalFunction> toFunction(SkSL::Compiler& compiler,
100cb93a386Sopenharmony_ci                                                           skvm::Uniforms* uniforms,
101cb93a386Sopenharmony_ci                                                           SkArenaAlloc* alloc) override {
102cb93a386Sopenharmony_ci        return std::make_unique<SkPathExternalFunction>(fName.c_str(), compiler, fData, uniforms,
103cb93a386Sopenharmony_ci                                                        alloc);
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    void prepare(const skresources::ResourceProvider* resourceProvider) override {
107cb93a386Sopenharmony_ci        if (auto pathData = resourceProvider->load(fPathPath.c_str(), fPathName.c_str())) {
108cb93a386Sopenharmony_ci            SkPath path;
109cb93a386Sopenharmony_ci            if (0 != path.readFromMemory(pathData->data(), pathData->size())) {
110cb93a386Sopenharmony_ci                fData = linearize_path(path);
111cb93a386Sopenharmony_ci            }
112cb93a386Sopenharmony_ci        }
113cb93a386Sopenharmony_ci    }
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ciprivate:
116cb93a386Sopenharmony_ci    SkString fPathPath;
117cb93a386Sopenharmony_ci    SkString fPathName;
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    // Cached
120cb93a386Sopenharmony_ci    LinearizedPath fData;
121cb93a386Sopenharmony_ci};
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ciclass SkTextBinding : public SkParticleBinding {
124cb93a386Sopenharmony_cipublic:
125cb93a386Sopenharmony_ci    SkTextBinding(const char* name = "", const char* text = "", SkScalar fontSize = 96)
126cb93a386Sopenharmony_ci            : SkParticleBinding(name)
127cb93a386Sopenharmony_ci            , fText(text)
128cb93a386Sopenharmony_ci            , fFontSize(fontSize) {}
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci    REFLECTED(SkTextBinding, SkParticleBinding)
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    void visitFields(SkFieldVisitor* v) override {
133cb93a386Sopenharmony_ci        SkParticleBinding::visitFields(v);
134cb93a386Sopenharmony_ci        v->visit("Text", fText);
135cb93a386Sopenharmony_ci        v->visit("FontSize", fFontSize);
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    std::unique_ptr<SkParticleExternalFunction> toFunction(SkSL::Compiler& compiler,
139cb93a386Sopenharmony_ci                                                           skvm::Uniforms* uniforms,
140cb93a386Sopenharmony_ci                                                           SkArenaAlloc* alloc) override {
141cb93a386Sopenharmony_ci        return std::make_unique<SkPathExternalFunction>(fName.c_str(), compiler, fData, uniforms,
142cb93a386Sopenharmony_ci                                                        alloc);
143cb93a386Sopenharmony_ci    }
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci    void prepare(const skresources::ResourceProvider*) override {
146cb93a386Sopenharmony_ci        if (fText.isEmpty()) {
147cb93a386Sopenharmony_ci            return;
148cb93a386Sopenharmony_ci        }
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci        SkFont font(nullptr, fFontSize);
151cb93a386Sopenharmony_ci        SkPath path;
152cb93a386Sopenharmony_ci        SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
153cb93a386Sopenharmony_ci        fData = linearize_path(path);
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ciprivate:
157cb93a386Sopenharmony_ci    SkString fText;
158cb93a386Sopenharmony_ci    SkScalar fFontSize;
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    // Cached
161cb93a386Sopenharmony_ci    LinearizedPath fData;
162cb93a386Sopenharmony_ci};
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci// Exposes an SkShader as an external, callable function. p(xy) returns a float4
165cb93a386Sopenharmony_ciclass SkShaderExternalFunction : public SkParticleExternalFunction {
166cb93a386Sopenharmony_cipublic:
167cb93a386Sopenharmony_ci    SkShaderExternalFunction(const char* name,
168cb93a386Sopenharmony_ci                             SkSL::Compiler& compiler,
169cb93a386Sopenharmony_ci                             sk_sp<SkShader> shader,
170cb93a386Sopenharmony_ci                             skvm::Uniforms* uniforms,
171cb93a386Sopenharmony_ci                             SkArenaAlloc* alloc)
172cb93a386Sopenharmony_ci            : SkParticleExternalFunction(
173cb93a386Sopenharmony_ci                      name, compiler, *compiler.context().fTypes.fFloat4, uniforms, alloc)
174cb93a386Sopenharmony_ci            , fShader(std::move(shader)) {}
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    int callParameterCount() const override { return 1; }
177cb93a386Sopenharmony_ci    void getCallParameterTypes(const SkSL::Type** outTypes) const override {
178cb93a386Sopenharmony_ci        outTypes[0] = fCompiler.context().fTypes.fFloat2.get();
179cb93a386Sopenharmony_ci    }
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_ci    void call(skvm::Builder* builder,
182cb93a386Sopenharmony_ci              skvm::F32* arguments,
183cb93a386Sopenharmony_ci              skvm::F32* outResult,
184cb93a386Sopenharmony_ci              skvm::I32 mask) const override {
185cb93a386Sopenharmony_ci        skvm::Coord coord = {arguments[0], arguments[1]};
186cb93a386Sopenharmony_ci        skvm::F32 zero = builder->splat(0.0f);
187cb93a386Sopenharmony_ci        SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
188cb93a386Sopenharmony_ci        SkColorInfo colorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, /*cs=*/nullptr);
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci        skvm::Color result = as_SB(fShader)->program(
191cb93a386Sopenharmony_ci                builder, /*device=*/coord, /*local=*/coord, /*paint=*/{zero, zero, zero, zero},
192cb93a386Sopenharmony_ci                matrixProvider, /*localM=*/nullptr, colorInfo, fUniforms,
193cb93a386Sopenharmony_ci                fAlloc);
194cb93a386Sopenharmony_ci        SkASSERT(result);
195cb93a386Sopenharmony_ci        outResult[0] = result.r;
196cb93a386Sopenharmony_ci        outResult[1] = result.g;
197cb93a386Sopenharmony_ci        outResult[2] = result.b;
198cb93a386Sopenharmony_ci        outResult[3] = result.a;
199cb93a386Sopenharmony_ci    }
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ciprivate:
202cb93a386Sopenharmony_ci    sk_sp<SkShader> fShader;
203cb93a386Sopenharmony_ci};
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_ciclass SkImageBinding : public SkParticleBinding {
206cb93a386Sopenharmony_cipublic:
207cb93a386Sopenharmony_ci    SkImageBinding(const char* name = "", const char* imagePath = "", const char* imageName = "")
208cb93a386Sopenharmony_ci            : SkParticleBinding(name)
209cb93a386Sopenharmony_ci            , fImagePath(imagePath)
210cb93a386Sopenharmony_ci            , fImageName(imageName) {}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    REFLECTED(SkImageBinding, SkParticleBinding)
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci    void visitFields(SkFieldVisitor* v) override {
215cb93a386Sopenharmony_ci        SkParticleBinding::visitFields(v);
216cb93a386Sopenharmony_ci        v->visit("ImagePath", fImagePath);
217cb93a386Sopenharmony_ci        v->visit("ImageName", fImageName);
218cb93a386Sopenharmony_ci    }
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    std::unique_ptr<SkParticleExternalFunction> toFunction(SkSL::Compiler& compiler,
221cb93a386Sopenharmony_ci                                                           skvm::Uniforms* uniforms,
222cb93a386Sopenharmony_ci                                                           SkArenaAlloc* alloc) override {
223cb93a386Sopenharmony_ci        return std::make_unique<SkShaderExternalFunction>(fName.c_str(), compiler, fShader,
224cb93a386Sopenharmony_ci                                                          uniforms, alloc);
225cb93a386Sopenharmony_ci    }
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    void prepare(const skresources::ResourceProvider* resourceProvider) override {
228cb93a386Sopenharmony_ci        if (auto asset = resourceProvider->loadImageAsset(fImagePath.c_str(), fImageName.c_str(),
229cb93a386Sopenharmony_ci                                                          nullptr)) {
230cb93a386Sopenharmony_ci            if (auto image = asset->getFrame(0)) {
231cb93a386Sopenharmony_ci                SkMatrix normalize = SkMatrix::Scale(1.0f / image->width(), 1.0f / image->height());
232cb93a386Sopenharmony_ci                fShader = image->makeShader(SkSamplingOptions(SkFilterMode::kLinear), &normalize);
233cb93a386Sopenharmony_ci                return;
234cb93a386Sopenharmony_ci            }
235cb93a386Sopenharmony_ci        }
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci        fShader = SkShaders::Color(SK_ColorWHITE);
238cb93a386Sopenharmony_ci    }
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ciprivate:
241cb93a386Sopenharmony_ci    SkString fImagePath;
242cb93a386Sopenharmony_ci    SkString fImageName;
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci    // Cached
245cb93a386Sopenharmony_ci    sk_sp<SkShader> fShader;
246cb93a386Sopenharmony_ci};
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_cisk_sp<SkParticleBinding> SkParticleBinding::MakeImage(const char* name, const char* imagePath,
249cb93a386Sopenharmony_ci                                                      const char* imageName) {
250cb93a386Sopenharmony_ci    return sk_sp<SkParticleBinding>(new SkImageBinding(name, imagePath, imageName));
251cb93a386Sopenharmony_ci}
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_cisk_sp<SkParticleBinding> SkParticleBinding::MakePath(const char* name, const char* pathPath,
254cb93a386Sopenharmony_ci                                                     const char* pathName) {
255cb93a386Sopenharmony_ci    return sk_sp<SkParticleBinding>(new SkPathBinding(name, pathPath, pathName));
256cb93a386Sopenharmony_ci}
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_civoid SkParticleBinding::RegisterBindingTypes() {
259cb93a386Sopenharmony_ci    REGISTER_REFLECTED(SkParticleBinding);
260cb93a386Sopenharmony_ci    REGISTER_REFLECTED(SkImageBinding);
261cb93a386Sopenharmony_ci    REGISTER_REFLECTED(SkPathBinding);
262cb93a386Sopenharmony_ci    REGISTER_REFLECTED(SkTextBinding);
263cb93a386Sopenharmony_ci}
264