1 /*
2  * Copyright 2021 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 "gm/gm.h"
9 
10 #if !defined(SK_BUILD_FOR_GOOGLE3)  // Google3 doesn't build particles module
11 
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkColor.h"
14 #include "modules/particles/include/SkParticleEffect.h"
15 #include "modules/particles/include/SkParticleSerialization.h"
16 #include "modules/skresources/include/SkResources.h"
17 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
18 #include "tools/Resources.h"
19 
20 struct UniformValue {
21     const char*        fName;
22     std::vector<float> fData;
23 };
24 
25 class ParticlesGM : public skiagm::GM {
26 public:
ParticlesGM(const char * name,double startTime,SkISize size,SkPoint origin,std::vector<UniformValue> uniforms={})27     ParticlesGM(const char* name,
28                 double startTime,
29                 SkISize size,
30                 SkPoint origin,
31                 std::vector<UniformValue> uniforms = {})
32             : GM(SK_ColorBLACK)
33             , fName(name)
34             , fStartTime(startTime)
35             , fSize(size)
36             , fOrigin(origin)
37             , fUniforms(std::move(uniforms)) {}
38 
onShortName()39     SkString onShortName() override { return SkStringPrintf("particles_%s", fName); }
onISize()40     SkISize onISize() override { return fSize; }
41 
onOnceBeforeDraw()42     void onOnceBeforeDraw() override {
43         SkParticleEffect::RegisterParticleTypes();
44 
45         auto jsonData = GetResourceAsData(SkStringPrintf("particles/%s.json", fName).c_str());
46         skjson::DOM dom(static_cast<const char*>(jsonData->data()), jsonData->size());
47         SkFromJsonVisitor fromJson(dom.root());
48 
49         auto resourceProvider = skresources::FileResourceProvider::Make(GetResourcePath());
50         auto effectParams = sk_make_sp<SkParticleEffectParams>();
51         effectParams->visitFields(&fromJson);
52         effectParams->prepare(resourceProvider.get());
53 
54         fEffect = sk_make_sp<SkParticleEffect>(effectParams);
55         for (const auto& val : fUniforms) {
56             SkAssertResult(fEffect->setUniform(val.fName, val.fData.data(), val.fData.size()));
57         }
58 
59         fEffect->start(/*now=*/0.0, /*looping=*/true);
60 
61         // Fast-forward (in 30 fps time-slices) to the requested time
62         for (double time = 0; time < fStartTime; time += 1.0 / 30) {
63             fEffect->update(/*now=*/std::min(time, fStartTime));
64         }
65     }
66 
onAnimate(double nanos)67     bool onAnimate(double nanos) override {
68         if (fEffect) {
69             fEffect->update(fStartTime + (nanos * 1E-9));
70         }
71         return true;
72     }
73 
onDraw(SkCanvas * canvas)74     void onDraw(SkCanvas* canvas) override {
75         canvas->save();
76         canvas->translate(fOrigin.fX, fOrigin.fY);
77         fEffect->draw(canvas);
78         canvas->restore();
79     }
80 
81 protected:
82     const char*               fName;
83     const double              fStartTime;
84     const SkISize             fSize;
85     const SkPoint             fOrigin;
86     sk_sp<SkParticleEffect>   fEffect;
87     std::vector<UniformValue> fUniforms;
88 };
89 
90 DEF_GM(return new ParticlesGM("confetti",     1.0, {400, 400}, {200, 200});)
91 DEF_GM(return new ParticlesGM("cube",         1.0, {400, 400}, {200, 200});)
92 DEF_GM(return new ParticlesGM("curves",       4.0, {100, 200}, { 50, 190});)
93 DEF_GM(return new ParticlesGM("mandrill",     1.0, {250, 250}, { 25,  25});)
94 DEF_GM(return new ParticlesGM("spiral",       2.0, {250, 250}, {125, 125});)
95 DEF_GM(return new ParticlesGM("sprite_frame", 1.0, {200, 200}, {100, 100});)
96 DEF_GM(return new ParticlesGM("text",         1.0, {250, 110}, { 10, 100});)
97 DEF_GM(return new ParticlesGM("uniforms",     2.0, {250, 250}, {125, 125},
98                                               {{"rate",  {2.0f}},
99                                                {"spin",  {4.0f}},
100                                                {"color", {0.25f, 0.75f, 0.75f}}});)
101 
102 #endif  // SK_BUILD_FOR_GOOGLE3
103