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