• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 "include/core/SkCanvas.h"
9 #include "include/core/SkTypes.h"
10 #include "include/utils/SkRandom.h"
11 #include "modules/particles/include/SkParticleEffect.h"
12 #include "modules/particles/include/SkParticleSerialization.h"
13 #include "modules/skresources/include/SkResources.h"
14 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
15 
16 #include <string>
17 
18 #include "modules/canvaskit/WasmCommon.h"
19 
20 #include <emscripten.h>
21 #include <emscripten/bind.h>
22 
23 using namespace emscripten;
24 
25 namespace {
26 
27 class ParticleAssetProvider : public skresources::ResourceProvider {
28 public:
29     ~ParticleAssetProvider() override = default;
30 
31     // Tried using a map, but that gave strange errors like
32     // https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
33     // Not entirely sure why, but perhaps the iterator in the map was
34     // confusing enscripten.
35     using AssetVec = std::vector<std::pair<SkString, sk_sp<SkData>>>;
36 
Make(AssetVec assets)37     static sk_sp<ParticleAssetProvider> Make(AssetVec assets) {
38         if (assets.empty()) {
39             return nullptr;
40         }
41 
42         return sk_sp<ParticleAssetProvider>(new ParticleAssetProvider(std::move(assets)));
43     }
44 
loadImageAsset(const char[],const char name[],const char[]) const45     sk_sp<skresources::ImageAsset> loadImageAsset(const char[] /* path */,
46                                                   const char name[],
47                                                   const char[] /* id */) const override {
48         // For CK we ignore paths & IDs, and identify images based solely on name.
49         if (auto data = this->findAsset(name)) {
50             return skresources::MultiFrameImageAsset::Make(std::move(data));
51         }
52 
53         return nullptr;
54     }
55 
loadFont(const char name[],const char[]) const56     sk_sp<SkData> loadFont(const char name[], const char[] /* url */) const override {
57         // Same as images paths, we ignore font URLs.
58         return this->findAsset(name);
59     }
60 
61 private:
ParticleAssetProvider(AssetVec assets)62     explicit ParticleAssetProvider(AssetVec assets) : fAssets(std::move(assets)) {}
63 
findAsset(const char name[]) const64     sk_sp<SkData> findAsset(const char name[]) const {
65         for (const auto& asset : fAssets) {
66             if (asset.first.equals(name)) {
67                 return asset.second;
68             }
69         }
70 
71         SkDebugf("Could not find %s\n", name);
72         return nullptr;
73     }
74 
75     const AssetVec fAssets;
76 };
77 
78 }
79 
80 struct ParticleUniform {
81     int columns;
82     int rows;
83     int slot; // the index into the uniforms array that this uniform begins.
84 };
85 
fromUniform(const SkSL::UniformInfo::Uniform & u)86 ParticleUniform fromUniform(const SkSL::UniformInfo::Uniform& u) {
87     ParticleUniform su;
88     su.columns = u.fColumns;
89     su.rows = u.fRows;
90     su.slot = u.fSlot;
91     return su;
92 }
93 
EMSCRIPTEN_BINDINGS(Particles)94 EMSCRIPTEN_BINDINGS(Particles) {
95     class_<SkParticleEffect>("ParticleEffect")
96         .smart_ptr<sk_sp<SkParticleEffect>>("sk_sp<SkParticleEffect>")
97         .function("draw", &SkParticleEffect::draw, allow_raw_pointers())
98         .function("_uniformPtr", optional_override([](SkParticleEffect& self)->WASMPointerF32 {
99             return reinterpret_cast<WASMPointerF32>(self.uniformData());
100         }))
101         .function("getUniformCount", optional_override([](SkParticleEffect& self)->int {
102             auto info = self.uniformInfo();
103             if (!info) {
104                 return -1;
105             }
106             return info->fUniforms.size();
107         }))
108         .function("getUniformFloatCount", optional_override([](SkParticleEffect& self)->int {
109             auto info = self.uniformInfo();
110             if (!info) {
111                 return -1;
112             }
113             return info->fUniformSlotCount;
114         }))
115         .function("getUniformName", optional_override([](SkParticleEffect& self, int i)->JSString {
116             auto info = self.uniformInfo();
117             if (!info) {
118                 return emscripten::val::null();
119             }
120             return emscripten::val(info->fUniforms[i].fName.c_str());
121         }))
122         .function("getUniform", optional_override([](SkParticleEffect& self, int i)->ParticleUniform {
123             ParticleUniform su;
124             auto info = self.uniformInfo();
125             if (!info) {
126                 return su;
127             }
128             su = fromUniform(info->fUniforms[i]);
129             return su;
130         }))
131         .function("_setPosition", optional_override([](SkParticleEffect& self,
132                                                        SkScalar x, SkScalar y)->void {
133             self.setPosition({x, y});
134         }))
135         .function("setRate", select_overload<void (float)>(&SkParticleEffect::setRate))
136         .function("start", select_overload<void (double, bool)>(&SkParticleEffect::start))
137         .function("update", select_overload<void (double)>(&SkParticleEffect::update));
138 
139     value_object<ParticleUniform>("ParticleUniform")
140         .field("columns", &ParticleUniform::columns)
141         .field("rows",    &ParticleUniform::rows)
142         .field("slot",    &ParticleUniform::slot);
143 
144     function("_MakeParticles", optional_override([](std::string json,
145                                                    size_t assetCount,
146                                                    WASMPointerU32 nptr,
147                                                    WASMPointerU32 dptr,
148                                                    WASMPointerU32 sptr)
149                                                 ->sk_sp<SkParticleEffect> {
150         static bool didInit = false;
151         if (!didInit) {
152             SkParticleEffect::RegisterParticleTypes();
153             didInit = true;
154         }
155 
156         const auto assetNames = reinterpret_cast<char**   >(nptr);
157         const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
158         const auto assetSizes = reinterpret_cast<size_t*  >(sptr);
159 
160         ParticleAssetProvider::AssetVec assets;
161         assets.reserve(assetCount);
162 
163         for (size_t i = 0; i < assetCount; i++) {
164             auto name  = SkString(assetNames[i]);
165             auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
166             assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
167         }
168 
169         sk_sp<SkParticleEffectParams> params(new SkParticleEffectParams());
170         skjson::DOM dom(json.c_str(), json.length());
171         SkFromJsonVisitor fromJson(dom.root());
172         params->visitFields(&fromJson);
173         params->prepare(skresources::DataURIResourceProviderProxy::Make(
174                             ParticleAssetProvider::Make(std::move(assets))).get());
175         return sk_sp<SkParticleEffect>(new SkParticleEffect(std::move(params)));
176     }));
177     constant("particles", true);
178 
179 }
180