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