blob: abc51ee9513970a4be6be79ef45fc6f6e8bc1236 [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 Lubick269fe892019-03-06 09:32:55 -050014
15#include <string>
16
17#include <emscripten.h>
18#include <emscripten/bind.h>
19
20using namespace emscripten;
21
Brian Osmand12f2782019-11-27 10:34:18 -050022namespace {
23
24class ParticleAssetProvider : public skresources::ResourceProvider {
25public:
26 ~ParticleAssetProvider() override = default;
27
28 // Tried using a map, but that gave strange errors like
29 // https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
30 // Not entirely sure why, but perhaps the iterator in the map was
31 // confusing enscripten.
32 using AssetVec = std::vector<std::pair<SkString, sk_sp<SkData>>>;
33
34 static sk_sp<ParticleAssetProvider> Make(AssetVec assets) {
35 if (assets.empty()) {
36 return nullptr;
37 }
38
39 return sk_sp<ParticleAssetProvider>(new ParticleAssetProvider(std::move(assets)));
40 }
41
42 sk_sp<skresources::ImageAsset> loadImageAsset(const char[] /* path */,
43 const char name[],
44 const char[] /* id */) const override {
45 // For CK we ignore paths & IDs, and identify images based solely on name.
46 if (auto data = this->findAsset(name)) {
47 return skresources::MultiFrameImageAsset::Make(std::move(data));
48 }
49
50 return nullptr;
51 }
52
53 sk_sp<SkData> loadFont(const char name[], const char[] /* url */) const override {
54 // Same as images paths, we ignore font URLs.
55 return this->findAsset(name);
56 }
57
58private:
59 explicit ParticleAssetProvider(AssetVec assets) : fAssets(std::move(assets)) {}
60
61 sk_sp<SkData> findAsset(const char name[]) const {
62 for (const auto& asset : fAssets) {
63 if (asset.first.equals(name)) {
64 return asset.second;
65 }
66 }
67
68 SkDebugf("Could not find %s\n", name);
69 return nullptr;
70 }
71
72 const AssetVec fAssets;
73};
74
75}
76
Kevin Lubick269fe892019-03-06 09:32:55 -050077EMSCRIPTEN_BINDINGS(Particles) {
78 class_<SkParticleEffect>("SkParticleEffect")
79 .smart_ptr<sk_sp<SkParticleEffect>>("sk_sp<SkParticleEffect>")
80 .function("draw", &SkParticleEffect::draw, allow_raw_pointers())
81 .function("start", select_overload<void (double, bool)>(&SkParticleEffect::start))
Brian Osman4beafa62019-10-15 13:35:04 -040082 .function("update", select_overload<void (double)>(&SkParticleEffect::update))
83 .function("setPosition", select_overload<void (SkPoint)>(&SkParticleEffect::setPosition))
84 .function("setRate", select_overload<void (float)>(&SkParticleEffect::setRate));
Kevin Lubick269fe892019-03-06 09:32:55 -050085
Brian Osmand12f2782019-11-27 10:34:18 -050086 function("_MakeParticles", optional_override([](std::string json,
87 size_t assetCount,
88 uintptr_t /* char** */ nptr,
89 uintptr_t /* uint8_t** */ dptr,
90 uintptr_t /* size_t* */ sptr)
91 ->sk_sp<SkParticleEffect> {
92 // See the comment in canvaskit_bindings.cpp about the use of uintptr_t
Kevin Lubick269fe892019-03-06 09:32:55 -050093 static bool didInit = false;
94 if (!didInit) {
Brian Osman2aa85df2019-08-30 10:59:47 -040095 SkParticleEffect::RegisterParticleTypes();
Kevin Lubick269fe892019-03-06 09:32:55 -050096 didInit = true;
97 }
Brian Osmand12f2782019-11-27 10:34:18 -050098
99 const auto assetNames = reinterpret_cast<char** >(nptr);
100 const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
101 const auto assetSizes = reinterpret_cast<size_t* >(sptr);
102
103 ParticleAssetProvider::AssetVec assets;
104 assets.reserve(assetCount);
105
106 for (size_t i = 0; i < assetCount; i++) {
107 auto name = SkString(assetNames[i]);
108 auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
109 assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
110 }
111
Kevin Lubick269fe892019-03-06 09:32:55 -0500112 SkRandom r;
113 sk_sp<SkParticleEffectParams> params(new SkParticleEffectParams());
114 skjson::DOM dom(json.c_str(), json.length());
115 SkFromJsonVisitor fromJson(dom.root());
116 params->visitFields(&fromJson);
Brian Osman9dac0d82019-12-02 16:52:51 -0500117 params->prepare(skresources::DataURIResourceProviderProxy::Make(
118 ParticleAssetProvider::Make(std::move(assets))).get());
119 return sk_sp<SkParticleEffect>(new SkParticleEffect(std::move(params), r));
Kevin Lubick269fe892019-03-06 09:32:55 -0500120 }));
121 constant("particles", true);
122
123}