blob: ab64b8a7ba98ac84f0db5594d82efeff70fe1909 [file] [log] [blame]
Kevin Lubick269fe892019-03-06 09:32:55 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
9#include "include/core/SkTypes.h"
10#include "include/utils/SkRandom.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "modules/particles/include/SkParticleEffect.h"
12#include "modules/particles/include/SkParticleSerialization.h"
Brian Osmand12f2782019-11-27 10:34:18 -050013#include "modules/skresources/include/SkResources.h"
Kevin Lubickf8f9cd82020-02-21 08:26:59 -050014#include "src/sksl/SkSLByteCode.h"
Kevin Lubick269fe892019-03-06 09:32:55 -050015
16#include <string>
17
Nathaniel Nifonge5d32542020-03-26 09:27:48 -040018#include "modules/canvaskit/WasmCommon.h"
Kevin Lubickf8f9cd82020-02-21 08:26:59 -050019
Kevin Lubick269fe892019-03-06 09:32:55 -050020#include <emscripten.h>
21#include <emscripten/bind.h>
22
23using namespace emscripten;
24
Brian Osmand12f2782019-11-27 10:34:18 -050025namespace {
26
27class ParticleAssetProvider : public skresources::ResourceProvider {
28public:
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
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
45 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
56 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
61private:
62 explicit ParticleAssetProvider(AssetVec assets) : fAssets(std::move(assets)) {}
63
64 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
Kevin Lubickf8f9cd82020-02-21 08:26:59 -050080struct SimpleUniform {
81 int columns;
82 int rows;
83 int slot; // the index into the uniforms array that this uniform begins.
84};
85
86SimpleUniform fromUniform(SkSL::ByteCode::Uniform u) {
87 SimpleUniform su;
88 su.columns = u.fColumns;
89 su.rows = u.fRows;
90 su.slot = u.fSlot;
91 return su;
92}
93
Kevin Lubick269fe892019-03-06 09:32:55 -050094EMSCRIPTEN_BINDINGS(Particles) {
95 class_<SkParticleEffect>("SkParticleEffect")
96 .smart_ptr<sk_sp<SkParticleEffect>>("sk_sp<SkParticleEffect>")
97 .function("draw", &SkParticleEffect::draw, allow_raw_pointers())
Kevin Lubickf8f9cd82020-02-21 08:26:59 -050098 .function("_effectUniformPtr", optional_override([](SkParticleEffect& self)->uintptr_t {
99 return reinterpret_cast<uintptr_t>(self.effectUniforms());
100 }))
101 .function("_particleUniformPtr", optional_override([](SkParticleEffect& self)->uintptr_t {
102 return reinterpret_cast<uintptr_t>(self.particleUniforms());
103 }))
104 .function("getEffectUniformCount", optional_override([](SkParticleEffect& self)->int {
105 auto ec = self.effectCode();
106 if (!ec) {
107 return -1;
108 }
109 return ec->getUniformCount();
110 }))
111 .function("getEffectUniformFloatCount", optional_override([](SkParticleEffect& self)->int {
112 auto ec = self.effectCode();
113 if (!ec) {
114 return -1;
115 }
116 return ec->getUniformSlotCount();
117 }))
118 .function("getEffectUniformName", optional_override([](SkParticleEffect& self, int i)->JSString {
119 auto ec = self.effectCode();
120 if (!ec) {
121 return emscripten::val::null();
122 }
123 return emscripten::val(ec->getUniform(i).fName.c_str());
124 }))
125 .function("getEffectUniform", optional_override([](SkParticleEffect& self, int i)->SimpleUniform {
126 SimpleUniform su;
127 auto ec = self.effectCode();
128 if (!ec) {
129 return su;
130 }
131 su = fromUniform(ec->getUniform(i));
132 return su;
133 }))
134 .function("getParticleUniformCount", optional_override([](SkParticleEffect& self)->int {
135 auto ec = self.particleCode();
136 if (!ec) {
137 return -1;
138 }
139 return ec->getUniformCount();
140 }))
141 .function("getParticleUniformFloatCount", optional_override([](SkParticleEffect& self)->int {
142 auto ec = self.particleCode();
143 if (!ec) {
144 return -1;
145 }
146 return ec->getUniformSlotCount();
147 }))
148 .function("getParticleUniformName", optional_override([](SkParticleEffect& self, int i)->JSString {
149 auto ec = self.particleCode();
150 if (!ec) {
151 return emscripten::val::null();
152 }
153 return emscripten::val(ec->getUniform(i).fName.c_str());
154 }))
155 .function("getParticleUniform", optional_override([](SkParticleEffect& self, int i)->SimpleUniform {
156 SimpleUniform su;
157 auto ec = self.particleCode();
158 if (!ec) {
159 return su;
160 }
161 su = fromUniform(ec->getUniform(i));
162 return su;
163 }))
Brian Osman4beafa62019-10-15 13:35:04 -0400164 .function("setPosition", select_overload<void (SkPoint)>(&SkParticleEffect::setPosition))
Kevin Lubickf8f9cd82020-02-21 08:26:59 -0500165 .function("setRate", select_overload<void (float)>(&SkParticleEffect::setRate))
166 .function("start", select_overload<void (double, bool)>(&SkParticleEffect::start))
167 .function("update", select_overload<void (double)>(&SkParticleEffect::update));
168
169 value_object<SimpleUniform>("SimpleUniform")
170 .field("columns", &SimpleUniform::columns)
171 .field("rows", &SimpleUniform::rows)
172 .field("slot", &SimpleUniform::slot);
Kevin Lubick269fe892019-03-06 09:32:55 -0500173
Brian Osmand12f2782019-11-27 10:34:18 -0500174 function("_MakeParticles", optional_override([](std::string json,
175 size_t assetCount,
176 uintptr_t /* char** */ nptr,
177 uintptr_t /* uint8_t** */ dptr,
178 uintptr_t /* size_t* */ sptr)
179 ->sk_sp<SkParticleEffect> {
180 // See the comment in canvaskit_bindings.cpp about the use of uintptr_t
Kevin Lubick269fe892019-03-06 09:32:55 -0500181 static bool didInit = false;
182 if (!didInit) {
Brian Osman2aa85df2019-08-30 10:59:47 -0400183 SkParticleEffect::RegisterParticleTypes();
Kevin Lubick269fe892019-03-06 09:32:55 -0500184 didInit = true;
185 }
Brian Osmand12f2782019-11-27 10:34:18 -0500186
187 const auto assetNames = reinterpret_cast<char** >(nptr);
188 const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
189 const auto assetSizes = reinterpret_cast<size_t* >(sptr);
190
191 ParticleAssetProvider::AssetVec assets;
192 assets.reserve(assetCount);
193
194 for (size_t i = 0; i < assetCount; i++) {
195 auto name = SkString(assetNames[i]);
196 auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
197 assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
198 }
199
Kevin Lubick269fe892019-03-06 09:32:55 -0500200 sk_sp<SkParticleEffectParams> params(new SkParticleEffectParams());
201 skjson::DOM dom(json.c_str(), json.length());
202 SkFromJsonVisitor fromJson(dom.root());
203 params->visitFields(&fromJson);
Brian Osman9dac0d82019-12-02 16:52:51 -0500204 params->prepare(skresources::DataURIResourceProviderProxy::Make(
205 ParticleAssetProvider::Make(std::move(assets))).get());
Brian Osman95c26ef2020-02-10 13:45:22 -0500206 return sk_sp<SkParticleEffect>(new SkParticleEffect(std::move(params)));
Kevin Lubick269fe892019-03-06 09:32:55 -0500207 }));
208 constant("particles", true);
209
210}