6104ba0dca
For clients not using JSON, the factories were inconsistent. Change-Id: Ifd920fa1e18f5edffa12de238af8488406951e5b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/257683 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
293 lines
9.9 KiB
C++
293 lines
9.9 KiB
C++
/*
|
|
* Copyright 2019 Google LLC
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "modules/particles/include/SkParticleBinding.h"
|
|
|
|
#include "include/core/SkBitmap.h"
|
|
#include "include/core/SkContourMeasure.h"
|
|
#include "include/core/SkImage.h"
|
|
#include "include/core/SkPath.h"
|
|
#include "include/utils/SkParsePath.h"
|
|
#include "include/utils/SkRandom.h"
|
|
#include "include/utils/SkTextUtils.h"
|
|
#include "modules/particles/include/SkParticleEffect.h"
|
|
#include "modules/particles/include/SkReflected.h"
|
|
#include "modules/skresources/include/SkResources.h"
|
|
#include "src/sksl/SkSLCompiler.h"
|
|
|
|
void SkParticleBinding::visitFields(SkFieldVisitor* v) {
|
|
v->visit("Name", fName);
|
|
}
|
|
|
|
class SkEffectExternalValue : public SkParticleExternalValue {
|
|
public:
|
|
SkEffectExternalValue(const char* name, SkSL::Compiler& compiler,
|
|
sk_sp<SkParticleEffectParams> params)
|
|
: SkParticleExternalValue(name, compiler, *compiler.context().fVoid_Type)
|
|
, fParams(std::move(params)) {}
|
|
|
|
bool canCall() const override { return true; }
|
|
int callParameterCount() const override { return 1; }
|
|
void getCallParameterTypes(const SkSL::Type** outTypes) const override {
|
|
outTypes[0] = fCompiler.context().fBool_Type.get();
|
|
}
|
|
|
|
void call(int index, float* arguments, float* outReturn) override {
|
|
bool loop = ((int*)arguments)[0] != 0;
|
|
fEffect->addSpawnRequest(index, loop, fParams);
|
|
}
|
|
|
|
private:
|
|
sk_sp<SkParticleEffectParams> fParams;
|
|
};
|
|
|
|
class SkEffectBinding : public SkParticleBinding {
|
|
public:
|
|
SkEffectBinding(const char* name = "", sk_sp<SkParticleEffectParams> params = nullptr)
|
|
: SkParticleBinding(name)
|
|
, fParams(std::move(params)) {
|
|
if (!fParams) {
|
|
fParams.reset(new SkParticleEffectParams());
|
|
}
|
|
}
|
|
|
|
REFLECTED(SkEffectBinding, SkParticleBinding)
|
|
|
|
void visitFields(SkFieldVisitor* v) override {
|
|
SkParticleBinding::visitFields(v);
|
|
fParams->visitFields(v);
|
|
}
|
|
|
|
std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
|
|
return std::unique_ptr<SkParticleExternalValue>(
|
|
new SkEffectExternalValue(fName.c_str(), compiler, fParams));
|
|
}
|
|
|
|
void prepare(const skresources::ResourceProvider* resourceProvider) override {
|
|
fParams->prepare(resourceProvider);
|
|
}
|
|
|
|
private:
|
|
sk_sp<SkParticleEffectParams> fParams;
|
|
};
|
|
|
|
struct SkPathContours {
|
|
SkScalar fTotalLength;
|
|
SkTArray<sk_sp<SkContourMeasure>> fContours;
|
|
|
|
void rebuild(const SkPath& path) {
|
|
fTotalLength = 0;
|
|
fContours.reset();
|
|
|
|
SkContourMeasureIter iter(path, false);
|
|
while (auto contour = iter.next()) {
|
|
fContours.push_back(contour);
|
|
fTotalLength += contour->length();
|
|
}
|
|
}
|
|
};
|
|
|
|
// Exposes an SkPath as an external, callable value. p(x) returns a float4 { pos.xy, normal.xy }
|
|
class SkPathExternalValue : public SkParticleExternalValue {
|
|
public:
|
|
SkPathExternalValue(const char* name, SkSL::Compiler& compiler, const SkPathContours* path)
|
|
: SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
|
|
, fPath(path) { }
|
|
|
|
bool canCall() const override { return true; }
|
|
int callParameterCount() const override { return 1; }
|
|
void getCallParameterTypes(const SkSL::Type** outTypes) const override {
|
|
outTypes[0] = fCompiler.context().fFloat_Type.get();
|
|
}
|
|
|
|
void call(int index, float* arguments, float* outReturn) override {
|
|
SkScalar len = fPath->fTotalLength * arguments[0];
|
|
int idx = 0;
|
|
while (idx < fPath->fContours.count() - 1 && len > fPath->fContours[idx]->length()) {
|
|
len -= fPath->fContours[idx++]->length();
|
|
}
|
|
SkVector localXAxis;
|
|
if (idx >= fPath->fContours.count() ||
|
|
!fPath->fContours[idx]->getPosTan(len, (SkPoint*)outReturn, &localXAxis)) {
|
|
outReturn[0] = outReturn[1] = 0.0f;
|
|
localXAxis = { 1, 0 };
|
|
}
|
|
outReturn[2] = localXAxis.fY;
|
|
outReturn[3] = -localXAxis.fX;
|
|
}
|
|
|
|
private:
|
|
const SkPathContours* fPath;
|
|
};
|
|
|
|
class SkPathBinding : public SkParticleBinding {
|
|
public:
|
|
SkPathBinding(const char* name = "", const char* pathPath = "", const char* pathName = "")
|
|
: SkParticleBinding(name)
|
|
, fPathPath(pathPath)
|
|
, fPathName(pathName) {}
|
|
|
|
REFLECTED(SkPathBinding, SkParticleBinding)
|
|
|
|
void visitFields(SkFieldVisitor* v) override {
|
|
SkParticleBinding::visitFields(v);
|
|
v->visit("PathPath", fPathPath);
|
|
v->visit("PathName", fPathName);
|
|
}
|
|
|
|
std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
|
|
return std::unique_ptr<SkParticleExternalValue>(
|
|
new SkPathExternalValue(fName.c_str(), compiler, &fContours));
|
|
}
|
|
|
|
void prepare(const skresources::ResourceProvider* resourceProvider) override {
|
|
if (auto pathData = resourceProvider->load(fPathPath.c_str(), fPathName.c_str())) {
|
|
SkPath path;
|
|
if (0 != path.readFromMemory(pathData->data(), pathData->size())) {
|
|
fContours.rebuild(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
SkString fPathPath;
|
|
SkString fPathName;
|
|
|
|
// Cached
|
|
SkPathContours fContours;
|
|
};
|
|
|
|
class SkTextBinding : public SkParticleBinding {
|
|
public:
|
|
SkTextBinding(const char* name = "", const char* text = "", SkScalar fontSize = 96)
|
|
: SkParticleBinding(name)
|
|
, fText(text)
|
|
, fFontSize(fontSize) {}
|
|
|
|
REFLECTED(SkTextBinding, SkParticleBinding)
|
|
|
|
void visitFields(SkFieldVisitor* v) override {
|
|
SkParticleBinding::visitFields(v);
|
|
v->visit("Text", fText);
|
|
v->visit("FontSize", fFontSize);
|
|
}
|
|
|
|
std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
|
|
return std::unique_ptr<SkParticleExternalValue>(
|
|
new SkPathExternalValue(fName.c_str(), compiler, &fContours));
|
|
}
|
|
|
|
void prepare(const skresources::ResourceProvider*) override {
|
|
if (fText.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
SkFont font(nullptr, fFontSize);
|
|
SkPath path;
|
|
SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
|
|
fContours.rebuild(path);
|
|
}
|
|
|
|
private:
|
|
SkString fText;
|
|
SkScalar fFontSize;
|
|
|
|
// Cached
|
|
SkPathContours fContours;
|
|
};
|
|
|
|
// Exposes an SkBitmap as an external, callable value. p(xy) returns a float4
|
|
class SkBitmapExternalValue : public SkParticleExternalValue {
|
|
public:
|
|
SkBitmapExternalValue(const char* name, SkSL::Compiler& compiler, const SkBitmap& bitmap)
|
|
: SkParticleExternalValue(name, compiler, *compiler.context().fFloat4_Type)
|
|
, fBitmap(bitmap) {
|
|
SkASSERT(bitmap.colorType() == kRGBA_F32_SkColorType);
|
|
}
|
|
|
|
bool canCall() const override { return true; }
|
|
int callParameterCount() const override { return 1; }
|
|
void getCallParameterTypes(const SkSL::Type** outTypes) const override {
|
|
outTypes[0] = fCompiler.context().fFloat2_Type.get();
|
|
}
|
|
|
|
void call(int index, float* arguments, float* outReturn) override {
|
|
int x = SkTPin(static_cast<int>(arguments[0] * fBitmap.width()), 0, fBitmap.width() - 1);
|
|
int y = SkTPin(static_cast<int>(arguments[1] * fBitmap.height()), 0, fBitmap.height() - 1);
|
|
float* p = static_cast<float*>(fBitmap.getAddr(x, y));
|
|
memcpy(outReturn, p, 4 * sizeof(float));
|
|
}
|
|
|
|
private:
|
|
SkBitmap fBitmap;
|
|
};
|
|
|
|
class SkImageBinding : public SkParticleBinding {
|
|
public:
|
|
SkImageBinding(const char* name = "", const char* imagePath = "", const char* imageName = "")
|
|
: SkParticleBinding(name)
|
|
, fImagePath(imagePath)
|
|
, fImageName(imageName) {}
|
|
|
|
REFLECTED(SkImageBinding, SkParticleBinding)
|
|
|
|
void visitFields(SkFieldVisitor* v) override {
|
|
SkParticleBinding::visitFields(v);
|
|
v->visit("ImagePath", fImagePath);
|
|
v->visit("ImageName", fImageName);
|
|
}
|
|
|
|
std::unique_ptr<SkParticleExternalValue> toValue(SkSL::Compiler& compiler) override {
|
|
return std::unique_ptr<SkParticleExternalValue>(
|
|
new SkBitmapExternalValue(fName.c_str(), compiler, fBitmap));
|
|
}
|
|
|
|
void prepare(const skresources::ResourceProvider* resourceProvider) override {
|
|
if (auto asset = resourceProvider->loadImageAsset(fImagePath.c_str(), fImageName.c_str(),
|
|
nullptr)) {
|
|
if (auto image = asset->getFrame(0)) {
|
|
fBitmap.allocPixels(image->imageInfo().makeColorType(kRGBA_F32_SkColorType));
|
|
image->readPixels(fBitmap.pixmap(), 0, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
fBitmap.allocPixels(SkImageInfo::Make(1, 1, kRGBA_F32_SkColorType, kPremul_SkAlphaType));
|
|
fBitmap.eraseColor(SK_ColorWHITE);
|
|
}
|
|
|
|
private:
|
|
SkString fImagePath;
|
|
SkString fImageName;
|
|
|
|
// Cached
|
|
SkBitmap fBitmap;
|
|
};
|
|
|
|
sk_sp<SkParticleBinding> SkParticleBinding::MakeEffect(const char* name,
|
|
sk_sp<SkParticleEffectParams> params) {
|
|
return sk_sp<SkParticleBinding>(new SkEffectBinding(name, std::move(params)));
|
|
}
|
|
|
|
sk_sp<SkParticleBinding> SkParticleBinding::MakeImage(const char* name, const char* imagePath,
|
|
const char* imageName) {
|
|
return sk_sp<SkParticleBinding>(new SkImageBinding(name, imagePath, imageName));
|
|
}
|
|
|
|
sk_sp<SkParticleBinding> SkParticleBinding::MakePath(const char* name, const char* pathPath,
|
|
const char* pathName) {
|
|
return sk_sp<SkParticleBinding>(new SkPathBinding(name, pathPath, pathName));
|
|
}
|
|
|
|
void SkParticleBinding::RegisterBindingTypes() {
|
|
REGISTER_REFLECTED(SkParticleBinding);
|
|
REGISTER_REFLECTED(SkEffectBinding);
|
|
REGISTER_REFLECTED(SkImageBinding);
|
|
REGISTER_REFLECTED(SkPathBinding);
|
|
REGISTER_REFLECTED(SkTextBinding);
|
|
}
|