1 /*
2 * Copyright 2018 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
8 #include "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkMatrix44.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPath.h"
16 #include "include/core/SkPoint.h"
17 #include "include/core/SkPoint3.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkSize.h"
22 #include "include/core/SkStream.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTypes.h"
25 #include "include/utils/Sk3D.h"
26 #include "modules/skottie/include/Skottie.h"
27 #include "tools/Resources.h"
28
29 #include <math.h>
30 #include <algorithm>
31 #include <memory>
32
33 class SkMetaData;
34
operator *(const SkMatrix & a,const SkMatrix & b)35 static SkMatrix operator*(const SkMatrix& a, const SkMatrix& b) {
36 SkMatrix44 c;
37 c.setConcat(a, b);
38 return c;
39 }
40
41 class GM3d : public skiagm::GM {
42 float fNear = 0.5;
43 float fFar = 4;
44 float fAngle = SK_ScalarPI / 4;
45
46 SkPoint3 fEye { 0, 0, 4 };
47 SkPoint3 fCOA {0,0,0};//{ 0.5f, 0.5f, 0.5f };
48 SkPoint3 fUp { 0, 1, 0 };
49
50 SkPoint3 fP3[8];
51
52 sk_sp<skottie::Animation> fAnim;
53 SkScalar fAnimT = 0;
54
55 public:
GM3d()56 GM3d() {}
~GM3d()57 ~GM3d() override {}
58
59 protected:
onOnceBeforeDraw()60 void onOnceBeforeDraw() override {
61 if (auto stream = GetResourceAsStream("skottie/skottie_sample_2.json")) {
62 fAnim = skottie::Animation::Make(stream.get());
63 }
64
65 int index = 0;
66 for (float x = 0; x <= 1; ++x) {
67 for (float y = 0; y <= 1; ++y) {
68 for (float z = 0; z <= 1; ++z) {
69 fP3[index++] = { x, y, z };
70 }
71 }
72 }
73 }
74
draw_viewport(SkCanvas * canvas,const SkMatrix & viewport)75 static void draw_viewport(SkCanvas* canvas, const SkMatrix& viewport) {
76 SkPaint p;
77 p.setColor(0x10FF0000);
78
79 canvas->save();
80 canvas->concat(viewport);
81 canvas->drawRect({-1, -1, 1, 1}, p);
82
83 p.setColor(0x80FF0000);
84 canvas->drawLine({-1, -1}, {1, 1}, p);
85 canvas->drawLine({1, -1}, {-1, 1}, p);
86 canvas->restore();
87 }
88
draw_skia(SkCanvas * canvas,const SkMatrix44 & m4,const SkMatrix & vp,skottie::Animation * anim)89 static void draw_skia(SkCanvas* canvas, const SkMatrix44& m4, const SkMatrix& vp,
90 skottie::Animation* anim) {
91 auto proc = [canvas, vp, anim](SkColor c, const SkMatrix44& m4) {
92 SkPaint p;
93 p.setColor(c);
94 SkRect r = { 0, 0, 1, 1 };
95 canvas->save();
96 canvas->concat(vp * SkMatrix(m4));
97 anim->render(canvas, &r);
98 // canvas->drawRect({0, 0, 1, 1}, p);
99 canvas->restore();
100 };
101
102 SkMatrix44 tmp;
103
104 proc(0x400000FF, m4);
105 tmp.setTranslate(0, 0, 1);
106 proc(0xC00000FF, m4 * tmp);
107 tmp.setRotateAboutUnit(1, 0, 0, SK_ScalarPI/2);
108 proc(0x4000FF00, m4 * tmp);
109 tmp.postTranslate(0, 1, 0);
110 proc(0xC000FF00, m4 * tmp);
111 tmp.setRotateAboutUnit(0, 1, 0, -SK_ScalarPI/2);
112 proc(0x40FF0000, m4 * tmp);
113 tmp.postTranslate(1, 0, 0);
114 proc(0xC0FF0000, m4 * tmp);
115 }
116
onDraw(SkCanvas * canvas,SkString * errorMsg)117 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
118 if (!fAnim) {
119 *errorMsg = "No animation.";
120 return DrawResult::kFail;
121 }
122 SkMatrix44 camera,
123 perspective,
124 mv;
125 SkMatrix viewport;
126
127 {
128 float w = this->width();
129 float h = this->height();
130 float s = std::min(w, h);
131 viewport.setTranslate(1, -1);
132 viewport.postScale(s/2, -s/2);
133
134 draw_viewport(canvas, viewport);
135 }
136
137 Sk3Perspective(&perspective, fNear, fFar, fAngle);
138 Sk3LookAt(&camera, fEye, fCOA, fUp);
139 mv.postConcat(camera);
140 mv.postConcat(perspective);
141 SkPoint pts[8];
142 Sk3MapPts(pts, mv, fP3, 8);
143 viewport.mapPoints(pts, 8);
144
145 SkPaint paint;
146 paint.setStyle(SkPaint::kStroke_Style);
147 SkFont font;
148 font.setEdging(SkFont::Edging::kAlias);
149
150 SkPath cube;
151
152 cube.moveTo(pts[0]);
153 cube.lineTo(pts[2]);
154 cube.lineTo(pts[6]);
155 cube.lineTo(pts[4]);
156 cube.close();
157
158 cube.moveTo(pts[1]);
159 cube.lineTo(pts[3]);
160 cube.lineTo(pts[7]);
161 cube.lineTo(pts[5]);
162 cube.close();
163
164 cube.moveTo(pts[0]); cube.lineTo(pts[1]);
165 cube.moveTo(pts[2]); cube.lineTo(pts[3]);
166 cube.moveTo(pts[4]); cube.lineTo(pts[5]);
167 cube.moveTo(pts[6]); cube.lineTo(pts[7]);
168
169 canvas->drawPath(cube, paint);
170
171 {
172 SkPoint3 src[4] = {
173 { 0, 0, 0 }, { 2, 0, 0 }, { 0, 2, 0 }, { 0, 0, 2 },
174 };
175 SkPoint dst[4];
176 mv.setConcat(perspective, camera);
177 Sk3MapPts(dst, mv, src, 4);
178 viewport.mapPoints(dst, 4);
179 const char* str[3] = { "X", "Y", "Z" };
180 for (int i = 1; i <= 3; ++i) {
181 canvas->drawLine(dst[0], dst[i], paint);
182 }
183
184 for (int i = 0; i < 3; ++i) {
185 canvas->drawString(str[i], dst[i + 1].fX, dst[i + 1].fY, font, paint);
186 }
187 }
188
189 fAnim->seek(fAnimT);
190 draw_skia(canvas, mv, viewport, fAnim.get());
191 return DrawResult::kOk;
192 }
193
onISize()194 SkISize onISize() override { return { 1024, 768 }; }
195
onShortName()196 SkString onShortName() override { return SkString("3dgm"); }
197
onAnimate(double nanos)198 bool onAnimate(double nanos) override {
199 if (!fAnim) {
200 return false;
201 }
202 SkScalar dur = fAnim->duration();
203 fAnimT = fmod(1e-9 * nanos, dur) / dur;
204 return true;
205 }
onChar(SkUnichar uni)206 bool onChar(SkUnichar uni) override {
207 switch (uni) {
208 case 'a': fEye.fX += 0.125f; return true;
209 case 'd': fEye.fX -= 0.125f; return true;
210 case 'w': fEye.fY += 0.125f; return true;
211 case 's': fEye.fY -= 0.125f; return true;
212 case 'q': fEye.fZ += 0.125f; return true;
213 case 'z': fEye.fZ -= 0.125f; return true;
214 default: break;
215 }
216 return false;
217 }
218
onGetControls(SkMetaData *)219 bool onGetControls(SkMetaData*) override { return false; }
onSetControls(const SkMetaData &)220 void onSetControls(const SkMetaData&) override {
221
222 }
223 };
224
225 DEF_GM(return new GM3d;)
226
227