blob: 2e2031e386cc4d33e9b9f21aa491b9aabb974229 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkCamera.h"
11
12static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a,
13 const SkScalar b[], int step_b,
reed@google.com91408cc2011-04-18 18:47:46 +000014 SkScalar denom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000015 float prod = 0;
reed@google.com91408cc2011-04-18 18:47:46 +000016 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000017 prod += a[0] * b[0];
18 a += step_a;
19 b += step_b;
20 }
21 return prod / denom;
reed@android.com8a1c16f2008-12-17 15:59:43 +000022}
23
24static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a,
reed@google.com91408cc2011-04-18 18:47:46 +000025 const SkScalar b[], int step_b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 float prod = 0;
reed@google.com91408cc2011-04-18 18:47:46 +000027 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 prod += a[0] * b[0];
29 a += step_a;
30 b += step_b;
31 }
32 return prod;
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
reed@google.com91408cc2011-04-18 18:47:46 +000035///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000036
reed@google.com91408cc2011-04-18 18:47:46 +000037SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 float mag = sk_float_sqrt(fX*fX + fY*fY + fZ*fZ);
reed@google.com91408cc2011-04-18 18:47:46 +000039 if (mag) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 float scale = 1.0f / mag;
41 unit->fX = fX * scale;
42 unit->fY = fY * scale;
43 unit->fZ = fZ * scale;
reed@google.com91408cc2011-04-18 18:47:46 +000044 } else {
45 unit->fX = unit->fY = unit->fZ = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 return mag;
48}
49
reed@google.com91408cc2011-04-18 18:47:46 +000050SkUnitScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 return SkUnitScalarMul(a.fX, b.fX) +
52 SkUnitScalarMul(a.fY, b.fY) +
53 SkUnitScalarMul(a.fZ, b.fZ);
54}
55
reed@google.com91408cc2011-04-18 18:47:46 +000056void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 SkASSERT(cross);
58
59 // use x,y,z, in case &a == cross or &b == cross
60
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 SkScalar x = SkUnitScalarMul(a.fY, b.fZ) - SkUnitScalarMul(a.fZ, b.fY);
62 SkScalar y = SkUnitScalarMul(a.fZ, b.fX) - SkUnitScalarMul(a.fX, b.fY);
63 SkScalar z = SkUnitScalarMul(a.fX, b.fY) - SkUnitScalarMul(a.fY, b.fX);
64
65 cross->set(x, y, z);
66}
67
reed@google.com91408cc2011-04-18 18:47:46 +000068///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000069
reed@google.com91408cc2011-04-18 18:47:46 +000070SkPatch3D::SkPatch3D() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 this->reset();
72}
73
reed@google.com91408cc2011-04-18 18:47:46 +000074void SkPatch3D::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 fOrigin.set(0, 0, 0);
76 fU.set(SK_Scalar1, 0, 0);
77 fV.set(0, -SK_Scalar1, 0);
78}
79
reed@google.com91408cc2011-04-18 18:47:46 +000080void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const {
81 if (dst == NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 dst = (SkPatch3D*)this;
reed@google.com91408cc2011-04-18 18:47:46 +000083 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 m.mapVector(fU, &dst->fU);
85 m.mapVector(fV, &dst->fV);
86 m.mapPoint(fOrigin, &dst->fOrigin);
87}
88
reed@google.com91408cc2011-04-18 18:47:46 +000089SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 SkScalar cx = SkScalarMul(fU.fY, fV.fZ) - SkScalarMul(fU.fZ, fV.fY);
91 SkScalar cy = SkScalarMul(fU.fZ, fV.fX) - SkScalarMul(fU.fX, fV.fY);
92 SkScalar cz = SkScalarMul(fU.fX, fV.fY) - SkScalarMul(fU.fY, fV.fX);
93
94 return SkScalarMul(cx, dx) + SkScalarMul(cy, dy) + SkScalarMul(cz, dz);
95}
96
reed@google.com91408cc2011-04-18 18:47:46 +000097///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000098
reed@google.com91408cc2011-04-18 18:47:46 +000099void SkMatrix3D::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 memset(fMat, 0, sizeof(fMat));
101 fMat[0][0] = fMat[1][1] = fMat[2][2] = SK_Scalar1;
102}
103
reed@google.com91408cc2011-04-18 18:47:46 +0000104void SkMatrix3D::setTranslate(SkScalar x, SkScalar y, SkScalar z) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 memset(fMat, 0, sizeof(fMat));
106 fMat[0][0] = x;
107 fMat[1][1] = y;
108 fMat[2][2] = z;
109}
110
reed@google.com91408cc2011-04-18 18:47:46 +0000111void SkMatrix3D::setRotateX(SkScalar degX) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 SkScalar s, c;
113
114 s = SkScalarSinCos(SkDegreesToRadians(degX), &c);
115 this->setRow(0, SK_Scalar1, 0, 0);
116 this->setRow(1, 0, c, -s);
117 this->setRow(2, 0, s, c);
118}
119
reed@google.com91408cc2011-04-18 18:47:46 +0000120void SkMatrix3D::setRotateY(SkScalar degY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 SkScalar s, c;
122
123 s = SkScalarSinCos(SkDegreesToRadians(degY), &c);
124 this->setRow(0, c, 0, -s);
125 this->setRow(1, 0, SK_Scalar1, 0);
126 this->setRow(2, s, 0, c);
127}
128
reed@google.com91408cc2011-04-18 18:47:46 +0000129void SkMatrix3D::setRotateZ(SkScalar degZ) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 SkScalar s, c;
131
132 s = SkScalarSinCos(SkDegreesToRadians(degZ), &c);
133 this->setRow(0, c, -s, 0);
134 this->setRow(1, s, c, 0);
135 this->setRow(2, 0, 0, SK_Scalar1);
136}
137
reed@google.com91408cc2011-04-18 18:47:46 +0000138void SkMatrix3D::preTranslate(SkScalar x, SkScalar y, SkScalar z) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 SkScalar col[3] = { x, y, z};
140
reed@google.com91408cc2011-04-18 18:47:46 +0000141 for (int i = 0; i < 3; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 fMat[i][3] += SkScalarDot(3, &fMat[i][0], 1, col, 1);
reed@google.com91408cc2011-04-18 18:47:46 +0000143 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144}
145
reed@google.com91408cc2011-04-18 18:47:46 +0000146void SkMatrix3D::preRotateX(SkScalar degX) {
147 SkMatrix3D m;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 m.setRotateX(degX);
149 this->setConcat(*this, m);
150}
151
reed@google.com91408cc2011-04-18 18:47:46 +0000152void SkMatrix3D::preRotateY(SkScalar degY) {
153 SkMatrix3D m;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 m.setRotateY(degY);
155 this->setConcat(*this, m);
156}
157
reed@google.com91408cc2011-04-18 18:47:46 +0000158void SkMatrix3D::preRotateZ(SkScalar degZ) {
159 SkMatrix3D m;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 m.setRotateZ(degZ);
161 this->setConcat(*this, m);
162}
163
reed@google.com91408cc2011-04-18 18:47:46 +0000164void SkMatrix3D::setConcat(const SkMatrix3D& a, const SkMatrix3D& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 SkMatrix3D tmp;
166 SkMatrix3D* c = this;
167
reed@google.com91408cc2011-04-18 18:47:46 +0000168 if (this == &a || this == &b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 c = &tmp;
reed@google.com91408cc2011-04-18 18:47:46 +0000170 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 for (int i = 0; i < 3; i++) {
reed@google.com91408cc2011-04-18 18:47:46 +0000172 for (int j = 0; j < 3; j++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 c->fMat[i][j] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][j], 4);
reed@google.com91408cc2011-04-18 18:47:46 +0000174 }
175 c->fMat[i][3] = SkScalarDot(3, &a.fMat[i][0], 1,
176 &b.fMat[0][3], 4) + a.fMat[i][3];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 }
178
reed@google.com91408cc2011-04-18 18:47:46 +0000179 if (c == &tmp) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 *this = tmp;
reed@google.com91408cc2011-04-18 18:47:46 +0000181 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182}
183
reed@google.com91408cc2011-04-18 18:47:46 +0000184void SkMatrix3D::mapPoint(const SkPoint3D& src, SkPoint3D* dst) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1) + fMat[0][3];
186 SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1) + fMat[1][3];
187 SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1) + fMat[2][3];
188 dst->set(x, y, z);
189}
190
reed@google.com91408cc2011-04-18 18:47:46 +0000191void SkMatrix3D::mapVector(const SkVector3D& src, SkVector3D* dst) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1);
193 SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1);
194 SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1);
195 dst->set(x, y, z);
196}
197
reed@google.com91408cc2011-04-18 18:47:46 +0000198///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
reed@google.com91408cc2011-04-18 18:47:46 +0000200SkCamera3D::SkCamera3D() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 this->reset();
202}
203
reed@google.com91408cc2011-04-18 18:47:46 +0000204void SkCamera3D::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 fLocation.set(0, 0, -SkIntToScalar(576)); // 8 inches backward
206 fAxis.set(0, 0, SK_Scalar1); // forward
207 fZenith.set(0, -SK_Scalar1, 0); // up
208
209 fObserver.set(0, 0, fLocation.fZ);
210
211 fNeedToUpdate = true;
212}
213
reed@google.com91408cc2011-04-18 18:47:46 +0000214void SkCamera3D::update() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 fNeedToUpdate = true;
216}
217
reed@google.com91408cc2011-04-18 18:47:46 +0000218void SkCamera3D::doUpdate() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 SkUnit3D axis, zenith, cross;
220
221 fAxis.normalize(&axis);
222
223 {
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000224 SkScalar dot = SkUnit3D::Dot(*SkTCast<const SkUnit3D*>(&fZenith), axis);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225
226 zenith.fX = fZenith.fX - SkUnitScalarMul(dot, axis.fX);
227 zenith.fY = fZenith.fY - SkUnitScalarMul(dot, axis.fY);
228 zenith.fZ = fZenith.fZ - SkUnitScalarMul(dot, axis.fZ);
229
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000230 SkTCast<SkPoint3D*>(&zenith)->normalize(&zenith);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 }
232
233 SkUnit3D::Cross(axis, zenith, &cross);
234
235 {
236 SkMatrix* orien = &fOrientation;
237 SkScalar x = fObserver.fX;
238 SkScalar y = fObserver.fY;
239 SkScalar z = fObserver.fZ;
240
241 orien->set(SkMatrix::kMScaleX, SkUnitScalarMul(x, axis.fX) - SkUnitScalarMul(z, cross.fX));
242 orien->set(SkMatrix::kMSkewX, SkUnitScalarMul(x, axis.fY) - SkUnitScalarMul(z, cross.fY));
243 orien->set(SkMatrix::kMTransX, SkUnitScalarMul(x, axis.fZ) - SkUnitScalarMul(z, cross.fZ));
244 orien->set(SkMatrix::kMSkewY, SkUnitScalarMul(y, axis.fX) - SkUnitScalarMul(z, zenith.fX));
245 orien->set(SkMatrix::kMScaleY, SkUnitScalarMul(y, axis.fY) - SkUnitScalarMul(z, zenith.fY));
246 orien->set(SkMatrix::kMTransY, SkUnitScalarMul(y, axis.fZ) - SkUnitScalarMul(z, zenith.fZ));
247 orien->set(SkMatrix::kMPersp0, axis.fX);
248 orien->set(SkMatrix::kMPersp1, axis.fY);
249 orien->set(SkMatrix::kMPersp2, axis.fZ);
250 }
251}
252
reed@google.com91408cc2011-04-18 18:47:46 +0000253void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const {
254 if (fNeedToUpdate) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 this->doUpdate();
256 fNeedToUpdate = false;
257 }
258
259 const SkScalar* mapPtr = (const SkScalar*)(const void*)&fOrientation;
260 const SkScalar* patchPtr;
261 SkPoint3D diff;
262 SkScalar dot;
263
264 diff.fX = quilt.fOrigin.fX - fLocation.fX;
265 diff.fY = quilt.fOrigin.fY - fLocation.fY;
266 diff.fZ = quilt.fOrigin.fZ - fLocation.fZ;
267
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000268 dot = SkUnit3D::Dot(*SkTCast<const SkUnit3D*>(&diff),
269 *SkTCast<const SkUnit3D*>(SkTCast<const SkScalar*>(&fOrientation) + 6));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270
271 patchPtr = (const SkScalar*)&quilt;
272 matrix->set(SkMatrix::kMScaleX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
273 matrix->set(SkMatrix::kMSkewY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
274 matrix->set(SkMatrix::kMPersp0, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));
275
276 patchPtr += 3;
277 matrix->set(SkMatrix::kMSkewX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
278 matrix->set(SkMatrix::kMScaleY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
279 matrix->set(SkMatrix::kMPersp1, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));
280
281 patchPtr = (const SkScalar*)(const void*)&diff;
282 matrix->set(SkMatrix::kMTransX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
283 matrix->set(SkMatrix::kMTransY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
284 matrix->set(SkMatrix::kMPersp2, SK_UnitScalar1);
285}
286
reed@google.com91408cc2011-04-18 18:47:46 +0000287///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288
reed@google.com91408cc2011-04-18 18:47:46 +0000289Sk3DView::Sk3DView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 fInitialRec.fMatrix.reset();
291 fRec = &fInitialRec;
292}
293
reed@google.com91408cc2011-04-18 18:47:46 +0000294Sk3DView::~Sk3DView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 Rec* rec = fRec;
296 while (rec != &fInitialRec) {
297 Rec* next = rec->fNext;
298 SkDELETE(rec);
299 rec = next;
300 }
301}
302
reed@google.com91408cc2011-04-18 18:47:46 +0000303void Sk3DView::save() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 Rec* rec = SkNEW(Rec);
305 rec->fNext = fRec;
306 rec->fMatrix = fRec->fMatrix;
307 fRec = rec;
308}
309
reed@google.com91408cc2011-04-18 18:47:46 +0000310void Sk3DView::restore() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311 SkASSERT(fRec != &fInitialRec);
312 Rec* next = fRec->fNext;
313 SkDELETE(fRec);
314 fRec = next;
315}
316
djsollen@google.com56c69772011-11-08 19:00:26 +0000317#ifdef SK_BUILD_FOR_ANDROID
reed@google.com91408cc2011-04-18 18:47:46 +0000318void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000319 // the camera location is passed in inches, set in pt
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000320 SkScalar lz = z * 72.0f;
321 fCamera.fLocation.set(x * 72.0f, y * 72.0f, lz);
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000322 fCamera.fObserver.set(0, 0, lz);
323 fCamera.update();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000324
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000325}
djsollen@google.come63793a2012-03-21 15:39:03 +0000326
327SkScalar Sk3DView::getCameraLocationX() {
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000328 return fCamera.fLocation.fX / 72.0f;
djsollen@google.come63793a2012-03-21 15:39:03 +0000329}
330
331SkScalar Sk3DView::getCameraLocationY() {
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000332 return fCamera.fLocation.fY / 72.0f;
djsollen@google.come63793a2012-03-21 15:39:03 +0000333}
334
335SkScalar Sk3DView::getCameraLocationZ() {
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000336 return fCamera.fLocation.fZ / 72.0f;
djsollen@google.come63793a2012-03-21 15:39:03 +0000337}
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000338#endif
339
reed@google.com91408cc2011-04-18 18:47:46 +0000340void Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 fRec->fMatrix.preTranslate(x, y, z);
342}
343
reed@google.com91408cc2011-04-18 18:47:46 +0000344void Sk3DView::rotateX(SkScalar deg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 fRec->fMatrix.preRotateX(deg);
346}
347
reed@google.com91408cc2011-04-18 18:47:46 +0000348void Sk3DView::rotateY(SkScalar deg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 fRec->fMatrix.preRotateY(deg);
350}
351
reed@google.com91408cc2011-04-18 18:47:46 +0000352void Sk3DView::rotateZ(SkScalar deg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fRec->fMatrix.preRotateZ(deg);
354}
355
reed@google.com91408cc2011-04-18 18:47:46 +0000356SkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 SkPatch3D patch;
358 patch.transform(fRec->fMatrix);
359 return patch.dotWith(x, y, z);
360}
361
reed@google.com91408cc2011-04-18 18:47:46 +0000362void Sk3DView::getMatrix(SkMatrix* matrix) const {
363 if (matrix != NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 SkPatch3D patch;
365 patch.transform(fRec->fMatrix);
366 fCamera.patchToMatrix(patch, matrix);
367 }
368}
369
370#include "SkCanvas.h"
371
reed@google.com91408cc2011-04-18 18:47:46 +0000372void Sk3DView::applyToCanvas(SkCanvas* canvas) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373 SkMatrix matrix;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000374
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 this->getMatrix(&matrix);
376 canvas->concat(matrix);
377}