Flutter Engine
The Flutter Engine
3DSlide.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 Google Inc.
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
14#include "src/base/SkRandom.h"
15#include "tools/DecodeUtils.h"
16#include "tools/Resources.h"
18
19struct VSphere {
22
24
25 bool contains(SkV2 v) const {
26 return (v - fCenter).length() <= fRadius;
27 }
28
29 SkV2 pinLoc(SkV2 p) const {
30 auto v = p - fCenter;
31 if (v.length() > fRadius) {
32 v *= (fRadius / v.length());
33 }
34 return fCenter + v;
35 }
36
38 v = (v - fCenter) * (1 / fRadius);
39 SkScalar len2 = v.lengthSquared();
40 if (len2 > 1) {
41 v = v.normalize();
42 len2 = 1;
43 }
44 SkScalar z = SkScalarSqrt(1 - len2);
45 return {v.x, v.y, z};
46 }
47
48 struct RotateInfo {
51 };
52
54 SkV3 u = this->computeUnitV3(a);
55 SkV3 v = this->computeUnitV3(b);
56 SkV3 axis = u.cross(v);
57 SkScalar length = axis.length();
58
60 return {axis * (1.0f / length), std::acos(u.dot(v))};
61 }
62 return {{0, 0, 0}, 0};
63 }
64
66 auto [axis, angle] = this->computeRotationInfo(a, b);
67 return SkM44::Rotate(axis, angle);
68 }
69};
70
71static SkM44 inv(const SkM44& m) {
72 SkM44 inverse;
73 SkAssertResult(m.invert(&inverse));
74 return inverse;
75}
76
77// Compute the inverse transpose (of the upper-left 3x3) of a matrix, used to transform vectors
79 m.setRow(3, {0, 0, 0, 1});
80 m.setCol(3, {0, 0, 0, 1});
81 SkAssertResult(m.invert(&m));
82 return m.transpose();
83}
84
86protected:
87 float fNear = 0.05f;
88 float fFar = 4;
89 float fAngle = SK_ScalarPI / 12;
90
91 SkV3 fEye { 0, 0, 1.0f/std::tan(fAngle/2) - 1 };
92 SkV3 fCOA { 0, 0, 0 };
93 SkV3 fUp { 0, 1, 0 };
94
95public:
96 void concatCamera(SkCanvas* canvas, const SkRect& area, SkScalar zscale) {
97 SkM44 camera = SkM44::LookAt(fEye, fCOA, fUp),
98 perspective = SkM44::Perspective(fNear, fFar, fAngle),
99 viewport = SkM44::Translate(area.centerX(), area.centerY(), 0) *
100 SkM44::Scale(area.width()*0.5f, area.height()*0.5f, zscale);
101
102 canvas->concat(viewport * perspective * camera * inv(viewport));
103 }
104};
105
106struct Face {
109
111 return SkM44::Translate(x, y, z);
112 }
113
114 static SkM44 R(SkV3 axis, SkScalar rad) {
115 return SkM44::Rotate(axis, rad);
116 }
117
119 return R({0,1,0}, fRy) * R({1,0,0}, fRx) * T(0, 0, scale);
120 }
121};
122
123static bool isFrontFacing(const SkM44& m) {
125 if (!m.invert(&m2)) {
126 m2.setIdentity();
127 }
128 /*
129 * Classically we want to dot the transpose(inverse(ctm)) with our surface normal.
130 * In this case, the normal is known to be {0, 0, 1}, so we only actually need to look
131 * at the z-scale of the inverse (the transpose doesn't change the main diagonal, so
132 * no need to actually transpose).
133 */
134 return m2.rc(2,2) > 0;
135}
136
137const Face faces[] = {
138 { 0, 0, SK_ColorRED }, // front
139 { 0, SK_ScalarPI, SK_ColorGREEN }, // back
140
141 { SK_ScalarPI/2, 0, SK_ColorBLUE }, // top
142 {-SK_ScalarPI/2, 0, SK_ColorCYAN }, // bottom
143
144 { 0, SK_ScalarPI/2, SK_ColorMAGENTA }, // left
145 { 0,-SK_ScalarPI/2, SK_ColorYELLOW }, // right
146};
147
149
154
156 return s.computeUnitV3(fLoc) * fDistance;
157 }
158
159 void draw(SkCanvas* canvas) const {
161 paint.setAntiAlias(true);
162 paint.setColor(SK_ColorWHITE);
163 canvas->drawCircle(fLoc.x, fLoc.y, fRadius + 2, paint);
164 paint.setColor(SK_ColorBLACK);
165 canvas->drawCircle(fLoc.x, fLoc.y, fRadius, paint);
166 }
167};
168
169#include "src/base/SkTime.h"
170
172 SkV3 fAxis = {0, 0, 0};
173 SkScalar fAngle = 0,
174 fPrevAngle = 1234567;
175 double fNow = 0,
176 fPrevNow = 0;
177
178 SkScalar fAngleSpeed = 0,
179 fAngleSign = 1;
180
181 inline static constexpr double kSlowDown = 4;
182 inline static constexpr SkScalar kMaxSpeed = 16;
183
184public:
185 void update(SkV3 axis, SkScalar angle) {
186 if (angle != fPrevAngle) {
187 fPrevAngle = fAngle;
188 fAngle = angle;
189
190 fPrevNow = fNow;
191 fNow = SkTime::GetSecs();
192
193 fAxis = axis;
194 }
195 }
196
198 if (fAngleSpeed > 0) {
199 double now = SkTime::GetSecs();
200 double dtime = now - fPrevNow;
201 fPrevNow = now;
202 double delta = fAngleSign * fAngleSpeed * dtime;
203 fAngle += delta;
204 fAngleSpeed -= kSlowDown * dtime;
205 if (fAngleSpeed < 0) {
206 fAngleSpeed = 0;
207 }
208 }
209 return SkM44::Rotate(fAxis, fAngle);
210
211 }
212
213 void start() {
214 if (fPrevNow != fNow) {
215 fAngleSpeed = (fAngle - fPrevAngle) / (fNow - fPrevNow);
216 fAngleSign = fAngleSpeed < 0 ? -1 : 1;
217 fAngleSpeed = std::min(kMaxSpeed, std::abs(fAngleSpeed));
218 } else {
219 fAngleSpeed = 0;
220 }
221 fPrevNow = SkTime::GetSecs();
222 fAngle = 0;
223 }
224
225 void reset() {
226 fAngleSpeed = 0;
227 fAngle = 0;
228 fPrevAngle = 1234567;
229 }
230
231 bool isAnimating() const { return fAngleSpeed != 0; }
232};
233
235 enum {
236 DX = 400,
237 DY = 300
238 };
239
240 SkM44 fRotation; // part of model
241
242 RotateAnimator fRotateAnimator;
243
244protected:
245 enum Flags {
246 kCanRunOnCPU = 1 << 0,
248 };
249
250 LightOnSphere fLight = {{200 + DX, 200 + DY}, 800, 12};
251
254
255public:
257 : fSphere({200 + DX, 200 + DY}, 400)
258 , fFlags(flags)
259 {}
260
261 bool onChar(SkUnichar uni) override {
262 switch (uni) {
263 case 'Z': fLight.fDistance += 10; return true;
264 case 'z': fLight.fDistance -= 10; return true;
265 }
266 return this->ThreeDSlide::onChar(uni);
267 }
268
269 virtual void drawFace(SkCanvas*, SkColor, int face, bool front, const SkM44& localToWorld) = 0;
270
271 void draw(SkCanvas* canvas) override {
272 if (!canvas->recordingContext() && !(fFlags & kCanRunOnCPU)) {
273 return;
274 }
275
276 canvas->save();
277 canvas->translate(DX, DY);
278
279 this->concatCamera(canvas, {0, 0, 400, 400}, 200);
280
281 SkM44 m = fRotateAnimator.rotation() * fRotation;
282 for (bool front : {false, true}) {
283 int index = 0;
284 for (auto f : faces) {
285 SkAutoCanvasRestore acr(canvas, true);
286
287 SkM44 trans = SkM44::Translate(200, 200, 0); // center of the rotation
288
289 canvas->concat(trans);
290
291 // "World" space - content is centered at the origin, in device scale (+-200)
292 SkM44 localToWorld = m * f.asM44(200) * inv(trans);
293
294 canvas->concat(localToWorld);
295 this->drawFace(canvas, f.fColor, index++, front, localToWorld);
296 }
297 }
298
299 canvas->restore(); // camera & center the content in the window
300
301 if (fFlags & kShowLightDome){
302 fLight.draw(canvas);
303
305 paint.setAntiAlias(true);
307 paint.setColor(0x40FF0000);
313 }
314 }
315
317 SkV2 p = fLight.fLoc - SkV2{x, y};
318 if (p.length() <= fLight.fRadius) {
319 Click* c = new Click();
320 c->fMeta.setS32("type", 0);
321 return c;
322 }
323 if (fSphere.contains({x, y})) {
324 Click* c = new Click();
325 c->fMeta.setS32("type", 1);
326
327 fRotation = fRotateAnimator.rotation() * fRotation;
328 fRotateAnimator.reset();
329 return c;
330 }
331 return nullptr;
332 }
333 bool onClick(Click* click) override {
334 if (click->fMeta.hasS32("type", 0)) {
335 fLight.fLoc = fSphere.pinLoc({click->fCurr.fX, click->fCurr.fY});
336 return true;
337 }
338 if (click->fMeta.hasS32("type", 1)) {
339 if (click->fState == skui::InputState::kUp) {
340 fRotation = fRotateAnimator.rotation() * fRotation;
341 fRotateAnimator.start();
342 } else {
343 auto [axis, angle] = fSphere.computeRotationInfo(
344 {click->fOrig.fX, click->fOrig.fY},
345 {click->fCurr.fX, click->fCurr.fY});
346 fRotateAnimator.update(axis, angle);
347 }
348 return true;
349 }
350 return true;
351 }
352
353 bool animate(double nanos) override {
354 return fRotateAnimator.isAnimating();
355 }
356};
357
359 sk_sp<SkShader> fBmpShader, fImgShader;
361 SkRRect fRR;
362
363public:
365
366 void load(SkScalar w, SkScalar h) override {
367 fRR = SkRRect::MakeRectXY({20, 20, 380, 380}, 50, 50);
368 auto img = ToolUtils::GetResourceAsImage("images/brickwork-texture.jpg");
369 fImgShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
370 img = ToolUtils::GetResourceAsImage("images/brickwork_normal-map.jpg");
371 fBmpShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
372
373 const char code[] = R"(
374 uniform shader color_map;
375 uniform shader normal_map;
376
377 uniform float4x4 localToWorld;
378 uniform float4x4 localToWorldAdjInv;
379 uniform float3 lightPos;
380
381 float3 convert_normal_sample(half4 c) {
382 float3 n = 2 * c.rgb - 1;
383 n.y = -n.y;
384 return n;
385 }
386
387 half4 main(float2 p) {
388 float3 norm = convert_normal_sample(normal_map.eval(p));
389 float3 plane_norm = normalize(localToWorldAdjInv * norm.xyz0).xyz;
390
391 float3 plane_pos = (localToWorld * p.xy01).xyz;
392 float3 light_dir = normalize(lightPos - plane_pos);
393
394 float ambient = 0.2;
395 float dp = dot(plane_norm, light_dir);
396 float scale = min(ambient + max(dp, 0), 1);
397
398 return color_map.eval(p) * scale.xxx1;
399 }
400 )";
402 if (!effect) {
403 SkDebugf("runtime error %s\n", error.c_str());
404 }
405 fEffect = effect;
406 }
407
408 void drawFace(SkCanvas* canvas, SkColor color, int face, bool front,
409 const SkM44& localToWorld) override {
410 if (!front || !isFrontFacing(canvas->getLocalToDevice())) {
411 return;
412 }
413
415 builder.uniform("lightPos") = fLight.computeWorldPos(fSphere);
416 builder.uniform("localToWorld") = localToWorld;
417 builder.uniform("localToWorldAdjInv") = normals(localToWorld);
418
419 builder.child("color_map") = fImgShader;
420 builder.child("normal_map") = fBmpShader;
421
423 paint.setColor(color);
424 paint.setShader(builder.makeShader());
425
426 canvas->drawRRect(fRR, paint);
427 }
428};
429DEF_SLIDE( return new Bump3DSlide; )
430
431#include "modules/skottie/include/Skottie.h"
432
435
436public:
437 SkottieCubeSlide() : CubeBaseSlide(kCanRunOnCPU) { fName = "skottie3d"; }
438
439 void load(SkScalar w, SkScalar h) override {
440 const char* files[] = {
441 "skottie/skottie-chained-mattes.json",
442 "skottie/skottie-gradient-ramp.json",
443 "skottie/skottie_sample_2.json",
444 "skottie/skottie-3d-3planes.json",
445 "skottie/skottie-text-animator-4.json",
446 "skottie/skottie-motiontile-effect-phase.json",
447
448 };
449 for (unsigned i = 0; i < std::size(files); ++i) {
450 if (auto stream = GetResourceAsStream(files[i])) {
451 fAnim[i] = skottie::Animation::Make(stream.get());
452 }
453 }
454 }
455
456 void drawFace(SkCanvas* canvas, SkColor color, int face, bool front, const SkM44&) override {
457 if (!front || !isFrontFacing(canvas->getLocalToDevice())) {
458 return;
459 }
460
462 paint.setColor(color);
463 SkRect r = {0, 0, 400, 400};
464 canvas->drawRect(r, paint);
465 fAnim[face]->render(canvas, &r);
466 }
467
468 bool animate(double nanos) override {
469 for (auto& anim : fAnim) {
470 SkScalar dur = anim->duration();
471 SkScalar t = fmod(1e-9 * nanos, dur) / dur;
472 anim->seek(t);
473 }
474 return true;
475 }
476};
477DEF_SLIDE( return new SkottieCubeSlide; )
const Face faces[]
Definition: 3DSlide.cpp:137
static SkM44 normals(SkM44 m)
Definition: 3DSlide.cpp:78
static SkM44 inv(const SkM44 &m)
Definition: 3DSlide.cpp:71
static bool isFrontFacing(const SkM44 &m)
Definition: 3DSlide.cpp:123
const char * fName
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition: Resources.cpp:31
constexpr SkColor SK_ColorYELLOW
Definition: SkColor.h:139
constexpr SkColor SK_ColorMAGENTA
Definition: SkColor.h:147
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition: SkColor.h:143
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:101
#define SkScalarSqrt(x)
Definition: SkScalar.h:42
#define SK_ScalarPI
Definition: SkScalar.h:21
int32_t SkUnichar
Definition: SkTypes.h:175
#define DEF_SLIDE(code)
Definition: Slide.h:25
static SkScalar center(float pos0, float pos1)
void drawFace(SkCanvas *canvas, SkColor color, int face, bool front, const SkM44 &localToWorld) override
Definition: 3DSlide.cpp:408
void load(SkScalar w, SkScalar h) override
Definition: 3DSlide.cpp:366
virtual void drawFace(SkCanvas *, SkColor, int face, bool front, const SkM44 &localToWorld)=0
bool animate(double nanos) override
Definition: 3DSlide.cpp:353
void draw(SkCanvas *canvas) override
Definition: 3DSlide.cpp:271
Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override
Definition: 3DSlide.cpp:316
bool onChar(SkUnichar uni) override
Definition: 3DSlide.cpp:261
Flags fFlags
Definition: 3DSlide.cpp:253
LightOnSphere fLight
Definition: 3DSlide.cpp:250
VSphere fSphere
Definition: 3DSlide.cpp:252
CubeBaseSlide(Flags flags)
Definition: 3DSlide.cpp:256
bool onClick(Click *click) override
Definition: 3DSlide.cpp:333
void update(SkV3 axis, SkScalar angle)
Definition: 3DSlide.cpp:185
bool isAnimating() const
Definition: 3DSlide.cpp:231
void reset()
Definition: 3DSlide.cpp:225
SkM44 rotation()
Definition: 3DSlide.cpp:197
void start()
Definition: 3DSlide.cpp:213
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
SkM44 getLocalToDevice() const
Definition: SkCanvas.cpp:1633
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:1705
int save()
Definition: SkCanvas.cpp:447
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
Definition: SkCanvas.cpp:2707
Definition: SkM44.h:150
static SkM44 LookAt(const SkV3 &eye, const SkV3 &center, const SkV3 &up)
Definition: SkM44.cpp:331
SkScalar rc(int r, int c) const
Definition: SkM44.h:261
static SkM44 Rotate(SkV3 axis, SkScalar radians)
Definition: SkM44.h:239
@ kUninitialized_Constructor
Definition: SkM44.h:167
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z=0)
Definition: SkM44.h:225
static SkM44 Perspective(float near, float far, float angle)
Definition: SkM44.cpp:343
static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z=1)
Definition: SkM44.h:232
SkM44 & setIdentity()
Definition: SkM44.h:293
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
void setS32(const char name[], int32_t value)
Definition: SkMetaData.cpp:24
bool hasS32(const char name[], int32_t value) const
Definition: SkMetaData.h:28
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.h:180
static Result MakeForShader(SkString sksl, const Options &)
void drawFace(SkCanvas *canvas, SkColor color, int face, bool front, const SkM44 &) override
Definition: 3DSlide.cpp:456
bool animate(double nanos) override
Definition: 3DSlide.cpp:468
void load(SkScalar w, SkScalar h) override
Definition: 3DSlide.cpp:439
virtual bool onChar(SkUnichar c)
Definition: Slide.h:44
SkString fName
Definition: Slide.h:54
float fNear
Definition: 3DSlide.cpp:87
void concatCamera(SkCanvas *canvas, const SkRect &area, SkScalar zscale)
Definition: 3DSlide.cpp:96
float fFar
Definition: 3DSlide.cpp:88
SkV3 fUp
Definition: 3DSlide.cpp:93
SkV3 fEye
Definition: 3DSlide.cpp:91
SkV3 fCOA
Definition: 3DSlide.cpp:92
float fAngle
Definition: 3DSlide.cpp:89
static sk_sp< Animation > Make(const char *data, size_t length)
Definition: Skottie.cpp:534
void render(SkCanvas *canvas, const SkRect *dst=nullptr) const
Definition: Skottie.cpp:482
const Paint & paint
Definition: color_source.cc:38
DlColor color
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct s
struct MyStruct a[10]
FlutterSemanticsFlag flags
const uint8_t uint32_t uint32_t GError ** error
static float min(float r, float g, float b)
Definition: hsl.cpp:48
size_t length
double y
double x
double GetSecs()
Definition: SkTime.h:16
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkSamplingOptions(SkFilterMode::kLinear))
ModifierKey
Definition: ModifierKey.h:9
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
SkScalar w
SkScalar h
const Scalar scale
static SkM44 T(SkScalar x, SkScalar y, SkScalar z)
Definition: 3DSlide.cpp:110
SkScalar fRy
Definition: 3DSlide.cpp:107
static SkM44 R(SkV3 axis, SkScalar rad)
Definition: 3DSlide.cpp:114
SkM44 asM44(SkScalar scale) const
Definition: 3DSlide.cpp:118
SkColor fColor
Definition: 3DSlide.cpp:108
SkScalar fRx
Definition: 3DSlide.cpp:107
SkScalar fDistance
Definition: 3DSlide.cpp:152
SkV3 computeWorldPos(const VSphere &s) const
Definition: 3DSlide.cpp:155
SkScalar fRadius
Definition: 3DSlide.cpp:153
void draw(SkCanvas *canvas) const
Definition: 3DSlide.cpp:159
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float centerX() const
Definition: SkRect.h:776
constexpr float height() const
Definition: SkRect.h:769
constexpr float centerY() const
Definition: SkRect.h:785
constexpr float width() const
Definition: SkRect.h:762
Definition: SkM44.h:19
SkV2 normalize() const
Definition: SkM44.h:50
float x
Definition: SkM44.h:20
SkScalar lengthSquared() const
Definition: SkM44.h:45
float y
Definition: SkM44.h:20
Definition: SkM44.h:56
SkV3 cross(const SkV3 &v) const
Definition: SkM44.h:91
SkScalar dot(const SkV3 &v) const
Definition: SkM44.h:90
SkScalar length() const
Definition: SkM44.h:88
SkScalar fRadius
Definition: 3DSlide.cpp:21
SkM44 computeRotation(SkV2 a, SkV2 b) const
Definition: 3DSlide.cpp:65
RotateInfo computeRotationInfo(SkV2 a, SkV2 b) const
Definition: 3DSlide.cpp:53
VSphere(SkV2 center, SkScalar radius)
Definition: 3DSlide.cpp:23
SkV2 fCenter
Definition: 3DSlide.cpp:20
SkV3 computeUnitV3(SkV2 v) const
Definition: 3DSlide.cpp:37
bool contains(SkV2 v) const
Definition: 3DSlide.cpp:25
SkV2 pinLoc(SkV2 p) const
Definition: 3DSlide.cpp:29