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/SkParticleDrawable.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkImage.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 13cb93a386Sopenharmony_ci#include "include/core/SkRSXform.h" 14cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 15cb93a386Sopenharmony_ci#include "include/core/SkString.h" 16cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 17cb93a386Sopenharmony_ci#include "include/private/SkTPin.h" 18cb93a386Sopenharmony_ci#include "modules/particles/include/SkParticleData.h" 19cb93a386Sopenharmony_ci#include "modules/skresources/include/SkResources.h" 20cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_cistatic sk_sp<SkImage> make_circle_image(int radius) { 23cb93a386Sopenharmony_ci auto surface = SkSurface::MakeRasterN32Premul(radius * 2, radius * 2); 24cb93a386Sopenharmony_ci surface->getCanvas()->clear(SK_ColorTRANSPARENT); 25cb93a386Sopenharmony_ci SkPaint paint; 26cb93a386Sopenharmony_ci paint.setAntiAlias(true); 27cb93a386Sopenharmony_ci paint.setColor(SK_ColorWHITE); 28cb93a386Sopenharmony_ci surface->getCanvas()->drawCircle(radius, radius, radius, paint); 29cb93a386Sopenharmony_ci return surface->makeImageSnapshot(); 30cb93a386Sopenharmony_ci} 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_cistatic inline SkRSXform make_rsxform(SkPoint ofs, 33cb93a386Sopenharmony_ci float posX, float posY, float dirX, float dirY, float scale) { 34cb93a386Sopenharmony_ci const float s = dirX * scale; 35cb93a386Sopenharmony_ci const float c = -dirY * scale; 36cb93a386Sopenharmony_ci return SkRSXform::Make(c, s, 37cb93a386Sopenharmony_ci posX + -c * ofs.fX + s * ofs.fY, 38cb93a386Sopenharmony_ci posY + -s * ofs.fX + -c * ofs.fY); 39cb93a386Sopenharmony_ci} 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_cistruct DrawAtlasArrays { 42cb93a386Sopenharmony_ci DrawAtlasArrays(const SkParticles& particles, int count, SkPoint center) 43cb93a386Sopenharmony_ci : fXforms(count) 44cb93a386Sopenharmony_ci , fRects(count) 45cb93a386Sopenharmony_ci , fColors(count) { 46cb93a386Sopenharmony_ci float* c[] = { 47cb93a386Sopenharmony_ci particles.fData[SkParticles::kColorR].get(), 48cb93a386Sopenharmony_ci particles.fData[SkParticles::kColorG].get(), 49cb93a386Sopenharmony_ci particles.fData[SkParticles::kColorB].get(), 50cb93a386Sopenharmony_ci particles.fData[SkParticles::kColorA].get(), 51cb93a386Sopenharmony_ci }; 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci float* pos[] = { 54cb93a386Sopenharmony_ci particles.fData[SkParticles::kPositionX].get(), 55cb93a386Sopenharmony_ci particles.fData[SkParticles::kPositionY].get(), 56cb93a386Sopenharmony_ci }; 57cb93a386Sopenharmony_ci float* dir[] = { 58cb93a386Sopenharmony_ci particles.fData[SkParticles::kHeadingX].get(), 59cb93a386Sopenharmony_ci particles.fData[SkParticles::kHeadingY].get(), 60cb93a386Sopenharmony_ci }; 61cb93a386Sopenharmony_ci float* scale = particles.fData[SkParticles::kScale].get(); 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 64cb93a386Sopenharmony_ci fXforms[i] = make_rsxform(center, pos[0][i], pos[1][i], dir[0][i], dir[1][i], scale[i]); 65cb93a386Sopenharmony_ci fColors[i] = SkColor4f{ c[0][i], c[1][i], c[2][i], c[3][i] }.toSkColor(); 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci SkAutoTMalloc<SkRSXform> fXforms; 70cb93a386Sopenharmony_ci SkAutoTMalloc<SkRect> fRects; 71cb93a386Sopenharmony_ci SkAutoTMalloc<SkColor> fColors; 72cb93a386Sopenharmony_ci}; 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ciclass SkCircleDrawable : public SkParticleDrawable { 75cb93a386Sopenharmony_cipublic: 76cb93a386Sopenharmony_ci SkCircleDrawable(int radius = 1) : fRadius(radius) {} 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci REFLECTED(SkCircleDrawable, SkParticleDrawable) 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci void draw(SkCanvas* canvas, const SkParticles& particles, int count, 81cb93a386Sopenharmony_ci const SkPaint& paint) override { 82cb93a386Sopenharmony_ci int r = std::max(fRadius, 1); 83cb93a386Sopenharmony_ci SkPoint center = { SkIntToScalar(r), SkIntToScalar(r) }; 84cb93a386Sopenharmony_ci DrawAtlasArrays arrays(particles, count, center); 85cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 86cb93a386Sopenharmony_ci arrays.fRects[i].setIWH(fImage->width(), fImage->height()); 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci SkSamplingOptions sampling(SkFilterMode::kLinear); 89cb93a386Sopenharmony_ci canvas->drawAtlas(fImage.get(), arrays.fXforms.get(), arrays.fRects.get(), 90cb93a386Sopenharmony_ci arrays.fColors.get(), count, SkBlendMode::kModulate, sampling, 91cb93a386Sopenharmony_ci nullptr, &paint); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci void prepare(const skresources::ResourceProvider*) override { 95cb93a386Sopenharmony_ci int r = std::max(fRadius, 1); 96cb93a386Sopenharmony_ci if (!fImage || fImage->width() != 2 * r) { 97cb93a386Sopenharmony_ci fImage = make_circle_image(r); 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci void visitFields(SkFieldVisitor* v) override { 102cb93a386Sopenharmony_ci v->visit("Radius", fRadius); 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ciprivate: 106cb93a386Sopenharmony_ci int fRadius; 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci // Cached 109cb93a386Sopenharmony_ci sk_sp<SkImage> fImage; 110cb93a386Sopenharmony_ci}; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ciclass SkImageDrawable : public SkParticleDrawable { 113cb93a386Sopenharmony_cipublic: 114cb93a386Sopenharmony_ci SkImageDrawable(const char* imagePath = "", const char* imageName = "", 115cb93a386Sopenharmony_ci int cols = 1, int rows = 1) 116cb93a386Sopenharmony_ci : fPath(imagePath) 117cb93a386Sopenharmony_ci , fName(imageName) 118cb93a386Sopenharmony_ci , fCols(cols) 119cb93a386Sopenharmony_ci , fRows(rows) {} 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci REFLECTED(SkImageDrawable, SkParticleDrawable) 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci void draw(SkCanvas* canvas, const SkParticles& particles, int count, 124cb93a386Sopenharmony_ci const SkPaint& paint) override { 125cb93a386Sopenharmony_ci int cols = std::max(fCols, 1), 126cb93a386Sopenharmony_ci rows = std::max(fRows, 1); 127cb93a386Sopenharmony_ci SkRect baseRect = SkRect::MakeWH(static_cast<float>(fImage->width()) / cols, 128cb93a386Sopenharmony_ci static_cast<float>(fImage->height()) / rows); 129cb93a386Sopenharmony_ci SkPoint center = { baseRect.width() * 0.5f, baseRect.height() * 0.5f }; 130cb93a386Sopenharmony_ci DrawAtlasArrays arrays(particles, count, center); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci int frameCount = cols * rows; 133cb93a386Sopenharmony_ci float* spriteFrames = particles.fData[SkParticles::kSpriteFrame].get(); 134cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 135cb93a386Sopenharmony_ci int frame = static_cast<int>(spriteFrames[i] * frameCount + 0.5f); 136cb93a386Sopenharmony_ci frame = SkTPin(frame, 0, frameCount - 1); 137cb93a386Sopenharmony_ci int row = frame / cols; 138cb93a386Sopenharmony_ci int col = frame % cols; 139cb93a386Sopenharmony_ci arrays.fRects[i] = baseRect.makeOffset(col * baseRect.width(), row * baseRect.height()); 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci canvas->drawAtlas(fImage.get(), arrays.fXforms.get(), arrays.fRects.get(), 142cb93a386Sopenharmony_ci arrays.fColors.get(), count, SkBlendMode::kModulate, 143cb93a386Sopenharmony_ci SkSamplingOptions(SkFilterMode::kLinear), nullptr, &paint); 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci void prepare(const skresources::ResourceProvider* resourceProvider) override { 147cb93a386Sopenharmony_ci fImage.reset(); 148cb93a386Sopenharmony_ci if (auto asset = resourceProvider->loadImageAsset(fPath.c_str(), fName.c_str(), nullptr)) { 149cb93a386Sopenharmony_ci fImage = asset->getFrame(0); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci if (!fImage) { 152cb93a386Sopenharmony_ci SkDebugf("Could not load image \"%s:%s\"\n", fPath.c_str(), fName.c_str()); 153cb93a386Sopenharmony_ci fImage = make_circle_image(1); 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci void visitFields(SkFieldVisitor* v) override { 158cb93a386Sopenharmony_ci v->visit("Path", fPath); 159cb93a386Sopenharmony_ci v->visit("Name", fName); 160cb93a386Sopenharmony_ci v->visit("Columns", fCols); 161cb93a386Sopenharmony_ci v->visit("Rows", fRows); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ciprivate: 165cb93a386Sopenharmony_ci SkString fPath; 166cb93a386Sopenharmony_ci SkString fName; 167cb93a386Sopenharmony_ci int fCols; 168cb93a386Sopenharmony_ci int fRows; 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci // Cached 171cb93a386Sopenharmony_ci sk_sp<SkImage> fImage; 172cb93a386Sopenharmony_ci}; 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_civoid SkParticleDrawable::RegisterDrawableTypes() { 175cb93a386Sopenharmony_ci REGISTER_REFLECTED(SkParticleDrawable); 176cb93a386Sopenharmony_ci REGISTER_REFLECTED(SkCircleDrawable); 177cb93a386Sopenharmony_ci REGISTER_REFLECTED(SkImageDrawable); 178cb93a386Sopenharmony_ci} 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_cisk_sp<SkParticleDrawable> SkParticleDrawable::MakeCircle(int radius) { 181cb93a386Sopenharmony_ci return sk_sp<SkParticleDrawable>(new SkCircleDrawable(radius)); 182cb93a386Sopenharmony_ci} 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_cisk_sp<SkParticleDrawable> SkParticleDrawable::MakeImage(const char* imagePath, 185cb93a386Sopenharmony_ci const char* imageName, 186cb93a386Sopenharmony_ci int cols, int rows) { 187cb93a386Sopenharmony_ci return sk_sp<SkParticleDrawable>(new SkImageDrawable(imagePath, imageName, cols, rows)); 188cb93a386Sopenharmony_ci} 189