2020-01-11 20:57:14 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2020 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "include/core/SkCanvas.h"
|
2020-02-20 20:42:29 +00:00
|
|
|
#include "include/core/SkM44.h"
|
2020-01-11 20:57:14 +00:00
|
|
|
#include "include/core/SkPaint.h"
|
|
|
|
#include "include/core/SkRRect.h"
|
2020-04-02 20:49:59 +00:00
|
|
|
#include "include/core/SkVertices.h"
|
2020-01-11 20:57:14 +00:00
|
|
|
#include "include/utils/SkRandom.h"
|
|
|
|
#include "samplecode/Sample.h"
|
|
|
|
#include "tools/Resources.h"
|
|
|
|
|
2020-01-26 01:42:51 +00:00
|
|
|
struct VSphere {
|
2020-02-21 17:03:49 +00:00
|
|
|
SkV2 fCenter;
|
2020-01-26 01:42:51 +00:00
|
|
|
SkScalar fRadius;
|
|
|
|
|
2020-02-21 17:03:49 +00:00
|
|
|
VSphere(SkV2 center, SkScalar radius) : fCenter(center), fRadius(radius) {}
|
2020-01-26 01:42:51 +00:00
|
|
|
|
2020-02-21 17:03:49 +00:00
|
|
|
bool contains(SkV2 v) const {
|
2020-01-26 01:42:51 +00:00
|
|
|
return (v - fCenter).length() <= fRadius;
|
|
|
|
}
|
|
|
|
|
2020-02-21 17:03:49 +00:00
|
|
|
SkV2 pinLoc(SkV2 p) const {
|
2020-01-26 03:39:43 +00:00
|
|
|
auto v = p - fCenter;
|
|
|
|
if (v.length() > fRadius) {
|
|
|
|
v *= (fRadius / v.length());
|
|
|
|
}
|
|
|
|
return fCenter + v;
|
|
|
|
}
|
|
|
|
|
2020-02-21 17:03:49 +00:00
|
|
|
SkV3 computeUnitV3(SkV2 v) const {
|
2020-01-26 01:42:51 +00:00
|
|
|
v = (v - fCenter) * (1 / fRadius);
|
|
|
|
SkScalar len2 = v.lengthSquared();
|
|
|
|
if (len2 > 1) {
|
2020-02-19 22:40:32 +00:00
|
|
|
v = v.normalize();
|
2020-01-26 01:42:51 +00:00
|
|
|
len2 = 1;
|
|
|
|
}
|
|
|
|
SkScalar z = SkScalarSqrt(1 - len2);
|
|
|
|
return {v.x, v.y, z};
|
|
|
|
}
|
|
|
|
|
2020-02-19 18:30:06 +00:00
|
|
|
struct RotateInfo {
|
|
|
|
SkV3 fAxis;
|
|
|
|
SkScalar fAngle;
|
|
|
|
};
|
|
|
|
|
2020-02-21 17:03:49 +00:00
|
|
|
RotateInfo computeRotationInfo(SkV2 a, SkV2 b) const {
|
2020-01-26 01:42:51 +00:00
|
|
|
SkV3 u = this->computeUnitV3(a);
|
|
|
|
SkV3 v = this->computeUnitV3(b);
|
|
|
|
SkV3 axis = u.cross(v);
|
2020-02-19 22:07:04 +00:00
|
|
|
SkScalar length = axis.length();
|
|
|
|
|
|
|
|
if (!SkScalarNearlyZero(length)) {
|
|
|
|
return {axis * (1.0f / length), acos(u.dot(v))};
|
2020-01-26 01:42:51 +00:00
|
|
|
}
|
2020-02-19 18:30:06 +00:00
|
|
|
return {{0, 0, 0}, 0};
|
|
|
|
}
|
|
|
|
|
2020-02-21 17:03:49 +00:00
|
|
|
SkM44 computeRotation(SkV2 a, SkV2 b) const {
|
2020-02-19 18:30:06 +00:00
|
|
|
auto [axis, angle] = this->computeRotationInfo(a, b);
|
|
|
|
return SkM44::Rotate(axis, angle);
|
2020-01-26 01:42:51 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-01-17 22:35:04 +00:00
|
|
|
static SkM44 inv(const SkM44& m) {
|
|
|
|
SkM44 inverse;
|
|
|
|
SkAssertResult(m.invert(&inverse));
|
|
|
|
return inverse;
|
|
|
|
}
|
|
|
|
|
2020-01-11 20:57:14 +00:00
|
|
|
class Sample3DView : public Sample {
|
|
|
|
protected:
|
|
|
|
float fNear = 0.05f;
|
|
|
|
float fFar = 4;
|
|
|
|
float fAngle = SK_ScalarPI / 12;
|
|
|
|
|
2020-01-25 23:42:23 +00:00
|
|
|
SkV3 fEye { 0, 0, 1.0f/tan(fAngle/2) - 1 };
|
|
|
|
SkV3 fCOA { 0, 0, 0 };
|
|
|
|
SkV3 fUp { 0, 1, 0 };
|
2020-01-11 20:57:14 +00:00
|
|
|
|
2020-04-24 16:02:25 +00:00
|
|
|
const char* kLocalToWorld = "local_to_world";
|
2020-04-09 16:35:09 +00:00
|
|
|
|
2020-01-11 20:57:14 +00:00
|
|
|
public:
|
2020-04-21 18:47:07 +00:00
|
|
|
void concatCamera(SkCanvas* canvas, const SkRect& area, SkScalar zscale) {
|
2020-01-25 23:42:23 +00:00
|
|
|
SkM44 camera = Sk3LookAt(fEye, fCOA, fUp),
|
|
|
|
perspective = Sk3Perspective(fNear, fFar, fAngle),
|
|
|
|
viewport = SkM44::Translate(area.centerX(), area.centerY(), 0) *
|
|
|
|
SkM44::Scale(area.width()*0.5f, area.height()*0.5f, zscale);
|
2020-01-11 20:57:14 +00:00
|
|
|
|
2020-04-09 16:35:09 +00:00
|
|
|
canvas->concat(viewport * perspective * camera * inv(viewport));
|
|
|
|
}
|
2020-01-11 20:57:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Face {
|
|
|
|
SkScalar fRx, fRy;
|
2020-01-17 22:35:04 +00:00
|
|
|
SkColor fColor;
|
2020-01-11 20:57:14 +00:00
|
|
|
|
2020-01-25 23:42:23 +00:00
|
|
|
static SkM44 T(SkScalar x, SkScalar y, SkScalar z) {
|
|
|
|
return SkM44::Translate(x, y, z);
|
2020-01-25 03:20:18 +00:00
|
|
|
}
|
|
|
|
|
2020-01-25 23:42:23 +00:00
|
|
|
static SkM44 R(SkV3 axis, SkScalar rad) {
|
|
|
|
return SkM44::Rotate(axis, rad);
|
2020-01-25 03:20:18 +00:00
|
|
|
}
|
|
|
|
|
2020-01-25 23:42:23 +00:00
|
|
|
SkM44 asM44(SkScalar scale) const {
|
|
|
|
return R({0,1,0}, fRy) * R({1,0,0}, fRx) * T(0, 0, scale);
|
2020-01-11 20:57:14 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-01-14 02:15:06 +00:00
|
|
|
static bool front(const SkM44& m) {
|
2020-02-04 15:06:24 +00:00
|
|
|
SkM44 m2(SkM44::kUninitialized_Constructor);
|
|
|
|
if (!m.invert(&m2)) {
|
|
|
|
m2.setIdentity();
|
|
|
|
}
|
2020-01-14 02:15:06 +00:00
|
|
|
/*
|
|
|
|
* Classically we want to dot the transpose(inverse(ctm)) with our surface normal.
|
|
|
|
* In this case, the normal is known to be {0, 0, 1}, so we only actually need to look
|
|
|
|
* at the z-scale of the inverse (the transpose doesn't change the main diagonal, so
|
|
|
|
* no need to actually transpose).
|
|
|
|
*/
|
2020-01-23 16:06:20 +00:00
|
|
|
return m2.rc(2,2) > 0;
|
2020-01-11 20:57:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const Face faces[] = {
|
2020-01-17 22:35:04 +00:00
|
|
|
{ 0, 0, SK_ColorRED }, // front
|
|
|
|
{ 0, SK_ScalarPI, SK_ColorGREEN }, // back
|
2020-01-11 20:57:14 +00:00
|
|
|
|
2020-01-17 22:35:04 +00:00
|
|
|
{ SK_ScalarPI/2, 0, SK_ColorBLUE }, // top
|
|
|
|
{-SK_ScalarPI/2, 0, SK_ColorCYAN }, // bottom
|
2020-01-11 20:57:14 +00:00
|
|
|
|
2020-01-17 22:35:04 +00:00
|
|
|
{ 0, SK_ScalarPI/2, SK_ColorMAGENTA }, // left
|
|
|
|
{ 0,-SK_ScalarPI/2, SK_ColorYELLOW }, // right
|
2020-01-11 20:57:14 +00:00
|
|
|
};
|
|
|
|
|
2020-01-17 22:35:04 +00:00
|
|
|
#include "include/effects/SkRuntimeEffect.h"
|
|
|
|
|
2020-01-26 03:39:43 +00:00
|
|
|
struct LightOnSphere {
|
2020-02-21 17:03:49 +00:00
|
|
|
SkV2 fLoc;
|
2020-01-26 03:39:43 +00:00
|
|
|
SkScalar fDistance;
|
|
|
|
SkScalar fRadius;
|
|
|
|
|
|
|
|
SkV3 computeWorldPos(const VSphere& s) const {
|
|
|
|
return s.computeUnitV3(fLoc) * fDistance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void draw(SkCanvas* canvas) const {
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setAntiAlias(true);
|
|
|
|
paint.setColor(SK_ColorWHITE);
|
|
|
|
canvas->drawCircle(fLoc.x, fLoc.y, fRadius + 2, paint);
|
|
|
|
paint.setColor(SK_ColorBLACK);
|
|
|
|
canvas->drawCircle(fLoc.x, fLoc.y, fRadius, paint);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-02-19 18:30:06 +00:00
|
|
|
#include "include/core/SkTime.h"
|
|
|
|
|
|
|
|
class RotateAnimator {
|
|
|
|
SkV3 fAxis = {0, 0, 0};
|
|
|
|
SkScalar fAngle = 0,
|
|
|
|
fPrevAngle = 1234567;
|
|
|
|
double fNow = 0,
|
|
|
|
fPrevNow = 0;
|
|
|
|
|
|
|
|
SkScalar fAngleSpeed = 0,
|
|
|
|
fAngleSign = 1;
|
|
|
|
|
|
|
|
static constexpr double kSlowDown = 4;
|
|
|
|
static constexpr SkScalar kMaxSpeed = 16;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void update(SkV3 axis, SkScalar angle) {
|
|
|
|
if (angle != fPrevAngle) {
|
|
|
|
fPrevAngle = fAngle;
|
|
|
|
fAngle = angle;
|
|
|
|
|
|
|
|
fPrevNow = fNow;
|
|
|
|
fNow = SkTime::GetSecs();
|
|
|
|
|
|
|
|
fAxis = axis;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SkM44 rotation() {
|
|
|
|
if (fAngleSpeed > 0) {
|
|
|
|
double now = SkTime::GetSecs();
|
|
|
|
double dtime = now - fPrevNow;
|
|
|
|
fPrevNow = now;
|
|
|
|
double delta = fAngleSign * fAngleSpeed * dtime;
|
|
|
|
fAngle += delta;
|
|
|
|
fAngleSpeed -= kSlowDown * dtime;
|
|
|
|
if (fAngleSpeed < 0) {
|
|
|
|
fAngleSpeed = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SkM44::Rotate(fAxis, fAngle);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void start() {
|
|
|
|
if (fPrevNow != fNow) {
|
|
|
|
fAngleSpeed = (fAngle - fPrevAngle) / (fNow - fPrevNow);
|
|
|
|
fAngleSign = fAngleSpeed < 0 ? -1 : 1;
|
|
|
|
fAngleSpeed = std::min(kMaxSpeed, std::abs(fAngleSpeed));
|
|
|
|
} else {
|
|
|
|
fAngleSpeed = 0;
|
|
|
|
}
|
|
|
|
fPrevNow = SkTime::GetSecs();
|
|
|
|
fAngle = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset() {
|
|
|
|
fAngleSpeed = 0;
|
|
|
|
fAngle = 0;
|
|
|
|
fPrevAngle = 1234567;
|
|
|
|
}
|
2020-02-21 18:25:12 +00:00
|
|
|
|
|
|
|
bool isAnimating() const { return fAngleSpeed != 0; }
|
2020-02-19 18:30:06 +00:00
|
|
|
};
|
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
class SampleCubeBase : public Sample3DView {
|
2020-01-26 03:39:43 +00:00
|
|
|
enum {
|
|
|
|
DX = 400,
|
|
|
|
DY = 300
|
|
|
|
};
|
|
|
|
|
2020-02-19 18:30:06 +00:00
|
|
|
SkM44 fRotation; // part of model
|
|
|
|
|
|
|
|
RotateAnimator fRotateAnimator;
|
2020-02-18 18:05:45 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
enum Flags {
|
|
|
|
kCanRunOnCPU = 1 << 0,
|
|
|
|
kShowLightDome = 1 << 1,
|
|
|
|
};
|
|
|
|
|
2020-01-26 03:39:43 +00:00
|
|
|
LightOnSphere fLight = {{200 + DX, 200 + DY}, 800, 12};
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-01-26 01:42:51 +00:00
|
|
|
VSphere fSphere;
|
2020-02-18 18:05:45 +00:00
|
|
|
Flags fFlags;
|
2020-01-26 01:42:51 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
public:
|
|
|
|
SampleCubeBase(Flags flags)
|
|
|
|
: fSphere({200 + DX, 200 + DY}, 400)
|
|
|
|
, fFlags(flags)
|
|
|
|
{}
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
bool onChar(SkUnichar uni) override {
|
|
|
|
switch (uni) {
|
|
|
|
case 'Z': fLight.fDistance += 10; return true;
|
|
|
|
case 'z': fLight.fDistance -= 10; return true;
|
|
|
|
}
|
|
|
|
return this->Sample3DView::onChar(uni);
|
|
|
|
}
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
virtual void drawContent(SkCanvas* canvas, SkColor, int index, bool drawFront) = 0;
|
|
|
|
|
|
|
|
void onDrawContent(SkCanvas* canvas) override {
|
2020-07-09 17:25:17 +00:00
|
|
|
if (!canvas->recordingContext() && !(fFlags & kCanRunOnCPU)) {
|
2020-02-18 18:05:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas->save();
|
|
|
|
canvas->translate(DX, DY);
|
|
|
|
|
2020-04-21 18:47:07 +00:00
|
|
|
this->concatCamera(canvas, {0, 0, 400, 400}, 200);
|
2020-02-18 18:05:45 +00:00
|
|
|
|
|
|
|
for (bool drawFront : {false, true}) {
|
|
|
|
int index = 0;
|
|
|
|
for (auto f : faces) {
|
|
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
|
|
|
|
SkM44 trans = SkM44::Translate(200, 200, 0); // center of the rotation
|
2020-02-19 18:30:06 +00:00
|
|
|
SkM44 m = fRotateAnimator.rotation() * fRotation * f.asM44(200);
|
2020-02-18 18:05:45 +00:00
|
|
|
|
2020-04-21 18:47:07 +00:00
|
|
|
canvas->concat(trans);
|
|
|
|
|
|
|
|
// "World" space - content is centered at the origin, in device scale (+-200)
|
2020-04-24 16:02:25 +00:00
|
|
|
canvas->markCTM(kLocalToWorld);
|
2020-04-21 18:47:07 +00:00
|
|
|
|
|
|
|
canvas->concat(m * inv(trans));
|
2020-02-18 18:05:45 +00:00
|
|
|
this->drawContent(canvas, f.fColor, index++, drawFront);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:47:07 +00:00
|
|
|
canvas->restore(); // camera & center the content in the window
|
2020-02-18 18:05:45 +00:00
|
|
|
|
|
|
|
if (fFlags & kShowLightDome){
|
|
|
|
fLight.draw(canvas);
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setAntiAlias(true);
|
|
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
paint.setColor(0x40FF0000);
|
|
|
|
canvas->drawCircle(fSphere.fCenter.x, fSphere.fCenter.y, fSphere.fRadius, paint);
|
|
|
|
canvas->drawLine(fSphere.fCenter.x, fSphere.fCenter.y - fSphere.fRadius,
|
|
|
|
fSphere.fCenter.x, fSphere.fCenter.y + fSphere.fRadius, paint);
|
|
|
|
canvas->drawLine(fSphere.fCenter.x - fSphere.fRadius, fSphere.fCenter.y,
|
|
|
|
fSphere.fCenter.x + fSphere.fRadius, fSphere.fCenter.y, paint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
|
2020-02-21 17:03:49 +00:00
|
|
|
SkV2 p = fLight.fLoc - SkV2{x, y};
|
2020-02-18 18:05:45 +00:00
|
|
|
if (p.length() <= fLight.fRadius) {
|
|
|
|
Click* c = new Click();
|
|
|
|
c->fMeta.setS32("type", 0);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
if (fSphere.contains({x, y})) {
|
|
|
|
Click* c = new Click();
|
|
|
|
c->fMeta.setS32("type", 1);
|
2020-02-19 18:30:06 +00:00
|
|
|
|
|
|
|
fRotation = fRotateAnimator.rotation() * fRotation;
|
|
|
|
fRotateAnimator.reset();
|
2020-02-18 18:05:45 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
bool onClick(Click* click) override {
|
|
|
|
if (click->fMeta.hasS32("type", 0)) {
|
|
|
|
fLight.fLoc = fSphere.pinLoc({click->fCurr.fX, click->fCurr.fY});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (click->fMeta.hasS32("type", 1)) {
|
|
|
|
if (click->fState == skui::InputState::kUp) {
|
2020-02-19 18:30:06 +00:00
|
|
|
fRotation = fRotateAnimator.rotation() * fRotation;
|
|
|
|
fRotateAnimator.start();
|
2020-02-18 18:05:45 +00:00
|
|
|
} else {
|
2020-02-19 18:30:06 +00:00
|
|
|
auto [axis, angle] = fSphere.computeRotationInfo(
|
|
|
|
{click->fOrig.fX, click->fOrig.fY},
|
|
|
|
{click->fCurr.fX, click->fCurr.fY});
|
|
|
|
fRotateAnimator.update(axis, angle);
|
2020-02-18 18:05:45 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-02-19 18:30:06 +00:00
|
|
|
|
|
|
|
bool onAnimate(double nanos) override {
|
2020-02-21 18:25:12 +00:00
|
|
|
return fRotateAnimator.isAnimating();
|
2020-02-19 18:30:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = Sample3DView;
|
2020-02-18 18:05:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class SampleBump3D : public SampleCubeBase {
|
|
|
|
sk_sp<SkShader> fBmpShader, fImgShader;
|
|
|
|
sk_sp<SkRuntimeEffect> fEffect;
|
|
|
|
SkRRect fRR;
|
2020-01-26 01:42:51 +00:00
|
|
|
|
|
|
|
public:
|
2020-06-19 19:02:35 +00:00
|
|
|
SampleBump3D() : SampleCubeBase(Flags(kCanRunOnCPU | kShowLightDome)) {}
|
2020-01-26 01:42:51 +00:00
|
|
|
|
2020-01-18 19:21:12 +00:00
|
|
|
SkString name() override { return SkString("bump3d"); }
|
|
|
|
|
|
|
|
void onOnceBeforeDraw() override {
|
|
|
|
fRR = SkRRect::MakeRectXY({20, 20, 380, 380}, 50, 50);
|
|
|
|
auto img = GetResourceAsImage("images/brickwork-texture.jpg");
|
2020-12-08 18:16:56 +00:00
|
|
|
fImgShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
|
2020-01-21 14:50:56 +00:00
|
|
|
img = GetResourceAsImage("images/brickwork_normal-map.jpg");
|
2020-12-08 18:16:56 +00:00
|
|
|
fBmpShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
|
2020-01-18 19:21:12 +00:00
|
|
|
|
|
|
|
const char code[] = R"(
|
2020-11-04 20:40:50 +00:00
|
|
|
uniform shader color_map;
|
|
|
|
uniform shader normal_map;
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-04-15 18:18:13 +00:00
|
|
|
layout (marker=local_to_world) uniform float4x4 localToWorld;
|
|
|
|
layout (marker=normals(local_to_world)) uniform float4x4 localToWorldAdjInv;
|
2020-01-18 19:21:12 +00:00
|
|
|
uniform float3 lightPos;
|
|
|
|
|
2020-01-21 14:50:56 +00:00
|
|
|
float3 convert_normal_sample(half4 c) {
|
|
|
|
float3 n = 2 * c.rgb - 1;
|
|
|
|
n.y = -n.y;
|
|
|
|
return n;
|
2020-01-18 19:21:12 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 20:59:48 +00:00
|
|
|
half4 main(float2 p) {
|
2020-02-07 18:37:12 +00:00
|
|
|
float3 norm = convert_normal_sample(sample(normal_map, p));
|
2020-09-14 18:44:42 +00:00
|
|
|
float3 plane_norm = normalize(localToWorldAdjInv * norm.xyz0).xyz;
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-09-14 18:44:42 +00:00
|
|
|
float3 plane_pos = (localToWorld * p.xy01).xyz;
|
2020-01-18 19:21:12 +00:00
|
|
|
float3 light_dir = normalize(lightPos - plane_pos);
|
2020-01-21 14:50:56 +00:00
|
|
|
|
|
|
|
float ambient = 0.2;
|
2020-01-18 19:21:12 +00:00
|
|
|
float dp = dot(plane_norm, light_dir);
|
2020-01-21 14:50:56 +00:00
|
|
|
float scale = min(ambient + max(dp, 0), 1);
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-09-14 18:44:42 +00:00
|
|
|
return sample(color_map, p) * scale.xxx1;
|
2020-01-18 19:21:12 +00:00
|
|
|
}
|
|
|
|
)";
|
|
|
|
auto [effect, error] = SkRuntimeEffect::Make(SkString(code));
|
|
|
|
if (!effect) {
|
|
|
|
SkDebugf("runtime error %s\n", error.c_str());
|
|
|
|
}
|
|
|
|
fEffect = effect;
|
|
|
|
}
|
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
void drawContent(SkCanvas* canvas, SkColor color, int index, bool drawFront) override {
|
2020-02-20 20:42:29 +00:00
|
|
|
if (!drawFront || !front(canvas->getLocalToDevice())) {
|
2020-01-18 19:21:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-15 18:18:13 +00:00
|
|
|
SkRuntimeShaderBuilder builder(fEffect);
|
Remove 'in' variables from SkRuntimeEffect
Runtime effects previously allowed two kinds of global input variables:
'in' variables could be bool, int, or float. 'uniform' could be float,
vector, or matrix. Uniform variables worked like you'd expect, but 'in'
variables were baked into the program statically. There was a large
amount of machinery to make this work, and it meant that 'in' variables
needed to have values before we could make decisions about program
caching, and before we could catch some errors. It was also essentially
syntactic sugar over the client just inserting the value into their SkSL
as a string. Finally: No one was using the feature.
To simplify the mental model, and make the API much more predictable,
this CL removes 'in' variables entirely. We no longer need to
"specialize" runtime effect programs, which means we can catch more
errors up front (those not detected until optimization). All of the API
that referred to "inputs" (the previous term that unified 'in' and
'uniform') now just refers to "uniforms".
Bug: skia:10593
Change-Id: I971f620d868b259e652b3114f0b497c2620f4b0c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/309050
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2020-08-10 18:26:16 +00:00
|
|
|
builder.uniform("lightPos") = fLight.computeWorldPos(fSphere);
|
2020-04-15 18:18:13 +00:00
|
|
|
// localToWorld matrices are automatically populated, via layout(marker)
|
2020-01-26 03:39:43 +00:00
|
|
|
|
2020-04-15 18:18:13 +00:00
|
|
|
builder.child("color_map") = fImgShader;
|
|
|
|
builder.child("normal_map") = fBmpShader;
|
2020-01-18 19:21:12 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(color);
|
2020-04-15 18:18:13 +00:00
|
|
|
paint.setShader(builder.makeShader(nullptr, true));
|
2020-01-18 19:21:12 +00:00
|
|
|
|
|
|
|
canvas->drawRRect(fRR, paint);
|
|
|
|
}
|
2020-02-18 18:05:45 +00:00
|
|
|
};
|
|
|
|
DEF_SAMPLE( return new SampleBump3D; )
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-04-02 20:49:59 +00:00
|
|
|
class SampleVerts3D : public SampleCubeBase {
|
|
|
|
sk_sp<SkRuntimeEffect> fEffect;
|
|
|
|
sk_sp<SkVertices> fVertices;
|
|
|
|
|
|
|
|
public:
|
|
|
|
SampleVerts3D() : SampleCubeBase(kShowLightDome) {}
|
|
|
|
|
|
|
|
SkString name() override { return SkString("verts3d"); }
|
|
|
|
|
|
|
|
void onOnceBeforeDraw() override {
|
|
|
|
using Attr = SkVertices::Attribute;
|
|
|
|
Attr attrs[] = {
|
|
|
|
Attr(Attr::Type::kFloat3, Attr::Usage::kNormalVector),
|
|
|
|
};
|
|
|
|
|
|
|
|
SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 66, 0, attrs, 1);
|
|
|
|
|
|
|
|
SkPoint* pos = builder.positions();
|
|
|
|
SkV3* nrm = (SkV3*)builder.customData();
|
|
|
|
|
|
|
|
SkPoint center = { 200, 200 };
|
|
|
|
SkScalar radius = 200;
|
|
|
|
|
|
|
|
pos[0] = center;
|
|
|
|
nrm[0] = { 0, 0, 1 };
|
|
|
|
|
|
|
|
for (int i = 0; i < 65; ++i) {
|
|
|
|
SkScalar t = (i / 64.0f) * 2 * SK_ScalarPI;
|
|
|
|
SkScalar s = SkScalarSin(t),
|
|
|
|
c = SkScalarCos(t);
|
|
|
|
pos[i + 1] = center + SkPoint { c * radius, s * radius };
|
|
|
|
nrm[i + 1] = { c, s, 0 };
|
|
|
|
}
|
|
|
|
|
|
|
|
fVertices = builder.detach();
|
|
|
|
|
|
|
|
const char code[] = R"(
|
|
|
|
varying float3 vtx_normal;
|
2020-04-15 18:18:13 +00:00
|
|
|
|
|
|
|
layout (marker=local_to_world) uniform float4x4 localToWorld;
|
|
|
|
layout (marker=normals(local_to_world)) uniform float4x4 localToWorldAdjInv;
|
2020-04-02 20:49:59 +00:00
|
|
|
uniform float3 lightPos;
|
|
|
|
|
2020-08-13 20:59:48 +00:00
|
|
|
half4 main(float2 p) {
|
2020-04-02 20:49:59 +00:00
|
|
|
float3 norm = normalize(vtx_normal);
|
2020-09-14 18:44:42 +00:00
|
|
|
float3 plane_norm = normalize(localToWorldAdjInv * norm.xyz0).xyz;
|
2020-04-02 20:49:59 +00:00
|
|
|
|
2020-09-14 18:44:42 +00:00
|
|
|
float3 plane_pos = (localToWorld * p.xy01).xyz;
|
2020-04-02 20:49:59 +00:00
|
|
|
float3 light_dir = normalize(lightPos - plane_pos);
|
|
|
|
|
|
|
|
float ambient = 0.2;
|
|
|
|
float dp = dot(plane_norm, light_dir);
|
|
|
|
float scale = min(ambient + max(dp, 0), 1);
|
|
|
|
|
2020-09-14 18:44:42 +00:00
|
|
|
return half4(0.7, 0.9, 0.3, 1) * scale.xxx1;
|
2020-04-02 20:49:59 +00:00
|
|
|
}
|
|
|
|
)";
|
|
|
|
auto [effect, error] = SkRuntimeEffect::Make(SkString(code));
|
|
|
|
if (!effect) {
|
|
|
|
SkDebugf("runtime error %s\n", error.c_str());
|
|
|
|
}
|
|
|
|
fEffect = effect;
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawContent(SkCanvas* canvas, SkColor color, int index, bool drawFront) override {
|
|
|
|
if (!drawFront || !front(canvas->getLocalToDevice())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-15 18:18:13 +00:00
|
|
|
SkRuntimeShaderBuilder builder(fEffect);
|
Remove 'in' variables from SkRuntimeEffect
Runtime effects previously allowed two kinds of global input variables:
'in' variables could be bool, int, or float. 'uniform' could be float,
vector, or matrix. Uniform variables worked like you'd expect, but 'in'
variables were baked into the program statically. There was a large
amount of machinery to make this work, and it meant that 'in' variables
needed to have values before we could make decisions about program
caching, and before we could catch some errors. It was also essentially
syntactic sugar over the client just inserting the value into their SkSL
as a string. Finally: No one was using the feature.
To simplify the mental model, and make the API much more predictable,
this CL removes 'in' variables entirely. We no longer need to
"specialize" runtime effect programs, which means we can catch more
errors up front (those not detected until optimization). All of the API
that referred to "inputs" (the previous term that unified 'in' and
'uniform') now just refers to "uniforms".
Bug: skia:10593
Change-Id: I971f620d868b259e652b3114f0b497c2620f4b0c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/309050
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2020-08-10 18:26:16 +00:00
|
|
|
builder.uniform("lightPos") = fLight.computeWorldPos(fSphere);
|
2020-04-02 20:49:59 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(color);
|
2020-04-15 18:18:13 +00:00
|
|
|
paint.setShader(builder.makeShader(nullptr, true));
|
2020-04-02 20:49:59 +00:00
|
|
|
|
|
|
|
canvas->drawVertices(fVertices, paint);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
DEF_SAMPLE( return new SampleVerts3D; )
|
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
#include "modules/skottie/include/Skottie.h"
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
class SampleSkottieCube : public SampleCubeBase {
|
|
|
|
sk_sp<skottie::Animation> fAnim[6];
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
public:
|
|
|
|
SampleSkottieCube() : SampleCubeBase(kCanRunOnCPU) {}
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
SkString name() override { return SkString("skottie3d"); }
|
2020-01-18 19:21:12 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
void onOnceBeforeDraw() override {
|
|
|
|
const char* files[] = {
|
|
|
|
"skottie/skottie-chained-mattes.json",
|
|
|
|
"skottie/skottie-gradient-ramp.json",
|
|
|
|
"skottie/skottie_sample_2.json",
|
|
|
|
"skottie/skottie-3d-3planes.json",
|
|
|
|
"skottie/skottie-text-animator-4.json",
|
|
|
|
"skottie/skottie-motiontile-effect-phase.json",
|
2020-01-26 01:42:51 +00:00
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
};
|
|
|
|
for (unsigned i = 0; i < SK_ARRAY_COUNT(files); ++i) {
|
|
|
|
if (auto stream = GetResourceAsStream(files[i])) {
|
|
|
|
fAnim[i] = skottie::Animation::Make(stream.get());
|
|
|
|
}
|
2020-01-26 01:42:51 +00:00
|
|
|
}
|
2020-01-18 19:21:12 +00:00
|
|
|
}
|
|
|
|
|
2020-02-18 18:05:45 +00:00
|
|
|
void drawContent(SkCanvas* canvas, SkColor color, int index, bool drawFront) override {
|
2020-02-20 20:42:29 +00:00
|
|
|
if (!drawFront || !front(canvas->getLocalToDevice())) {
|
2020-02-18 18:05:45 +00:00
|
|
|
return;
|
2020-01-18 19:21:12 +00:00
|
|
|
}
|
2020-02-18 18:05:45 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(color);
|
|
|
|
SkRect r = {0, 0, 400, 400};
|
|
|
|
canvas->drawRect(r, paint);
|
|
|
|
fAnim[index]->render(canvas, &r);
|
2020-01-18 19:21:12 +00:00
|
|
|
}
|
2020-02-18 18:05:45 +00:00
|
|
|
|
|
|
|
bool onAnimate(double nanos) override {
|
|
|
|
for (auto& anim : fAnim) {
|
|
|
|
SkScalar dur = anim->duration();
|
|
|
|
SkScalar t = fmod(1e-9 * nanos, dur) / dur;
|
|
|
|
anim->seek(t);
|
2020-01-26 01:42:51 +00:00
|
|
|
}
|
2020-01-18 19:21:12 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
2020-02-18 18:05:45 +00:00
|
|
|
DEF_SAMPLE( return new SampleSkottieCube; )
|