1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/utils/SkCamera.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_cistatic SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a, 11cb93a386Sopenharmony_ci const SkScalar b[], int step_b, 12cb93a386Sopenharmony_ci SkScalar denom) { 13cb93a386Sopenharmony_ci SkScalar prod = 0; 14cb93a386Sopenharmony_ci for (int i = 0; i < count; i++) { 15cb93a386Sopenharmony_ci prod += a[0] * b[0]; 16cb93a386Sopenharmony_ci a += step_a; 17cb93a386Sopenharmony_ci b += step_b; 18cb93a386Sopenharmony_ci } 19cb93a386Sopenharmony_ci return prod / denom; 20cb93a386Sopenharmony_ci} 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ciSkPatch3D::SkPatch3D() { 25cb93a386Sopenharmony_ci this->reset(); 26cb93a386Sopenharmony_ci} 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_civoid SkPatch3D::reset() { 29cb93a386Sopenharmony_ci fOrigin = {0, 0, 0}; 30cb93a386Sopenharmony_ci fU = {SK_Scalar1, 0, 0}; 31cb93a386Sopenharmony_ci fV = {0, -SK_Scalar1, 0}; 32cb93a386Sopenharmony_ci} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_civoid SkPatch3D::transform(const SkM44& m, SkPatch3D* dst) const { 35cb93a386Sopenharmony_ci if (dst == nullptr) { 36cb93a386Sopenharmony_ci dst = (SkPatch3D*)this; 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci dst->fU = m * fU; 39cb93a386Sopenharmony_ci dst->fV = m * fV; 40cb93a386Sopenharmony_ci auto [x,y,z,_] = m.map(fOrigin.x, fOrigin.y, fOrigin.z, 1); 41cb93a386Sopenharmony_ci dst->fOrigin = {x, y, z}; 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ciSkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const { 45cb93a386Sopenharmony_ci SkScalar cx = fU.y * fV.z - fU.z * fV.y; 46cb93a386Sopenharmony_ci SkScalar cy = fU.z * fV.x - fU.x * fV.y; 47cb93a386Sopenharmony_ci SkScalar cz = fU.x * fV.y - fU.y * fV.x; 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci return cx * dx + cy * dy + cz * dz; 50cb93a386Sopenharmony_ci} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ciSkCamera3D::SkCamera3D() { 55cb93a386Sopenharmony_ci this->reset(); 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_civoid SkCamera3D::reset() { 59cb93a386Sopenharmony_ci fLocation = {0, 0, -SkIntToScalar(576)}; // 8 inches backward 60cb93a386Sopenharmony_ci fAxis = {0, 0, SK_Scalar1}; // forward 61cb93a386Sopenharmony_ci fZenith = {0, -SK_Scalar1, 0}; // up 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci fObserver = {0, 0, fLocation.z}; 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci fNeedToUpdate = true; 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_civoid SkCamera3D::update() { 69cb93a386Sopenharmony_ci fNeedToUpdate = true; 70cb93a386Sopenharmony_ci} 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_civoid SkCamera3D::doUpdate() const { 73cb93a386Sopenharmony_ci SkV3 axis, zenith, cross; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci // construct a orthonormal basis of cross (x), zenith (y), and axis (z) 76cb93a386Sopenharmony_ci axis = fAxis.normalize(); 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci zenith = fZenith - (axis * fZenith) * axis; 79cb93a386Sopenharmony_ci zenith = zenith.normalize(); 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci cross = axis.cross(zenith); 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci { 84cb93a386Sopenharmony_ci SkMatrix* orien = &fOrientation; 85cb93a386Sopenharmony_ci auto [x, y, z] = fObserver; 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci // Looking along the view axis we have: 88cb93a386Sopenharmony_ci // 89cb93a386Sopenharmony_ci // /|\ zenith 90cb93a386Sopenharmony_ci // | 91cb93a386Sopenharmony_ci // | 92cb93a386Sopenharmony_ci // | * observer (projected on XY plane) 93cb93a386Sopenharmony_ci // | 94cb93a386Sopenharmony_ci // |____________\ cross 95cb93a386Sopenharmony_ci // / 96cb93a386Sopenharmony_ci // 97cb93a386Sopenharmony_ci // So this does a z-shear along the view axis based on the observer's x and y values, 98cb93a386Sopenharmony_ci // and scales in x and y relative to the negative of the observer's z value 99cb93a386Sopenharmony_ci // (the observer is in the negative z direction). 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci orien->set(SkMatrix::kMScaleX, x * axis.x - z * cross.x); 102cb93a386Sopenharmony_ci orien->set(SkMatrix::kMSkewX, x * axis.y - z * cross.y); 103cb93a386Sopenharmony_ci orien->set(SkMatrix::kMTransX, x * axis.z - z * cross.z); 104cb93a386Sopenharmony_ci orien->set(SkMatrix::kMSkewY, y * axis.x - z * zenith.x); 105cb93a386Sopenharmony_ci orien->set(SkMatrix::kMScaleY, y * axis.y - z * zenith.y); 106cb93a386Sopenharmony_ci orien->set(SkMatrix::kMTransY, y * axis.z - z * zenith.z); 107cb93a386Sopenharmony_ci orien->set(SkMatrix::kMPersp0, axis.x); 108cb93a386Sopenharmony_ci orien->set(SkMatrix::kMPersp1, axis.y); 109cb93a386Sopenharmony_ci orien->set(SkMatrix::kMPersp2, axis.z); 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_civoid SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const { 114cb93a386Sopenharmony_ci if (fNeedToUpdate) { 115cb93a386Sopenharmony_ci this->doUpdate(); 116cb93a386Sopenharmony_ci fNeedToUpdate = false; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci const SkScalar* mapPtr = (const SkScalar*)(const void*)&fOrientation; 120cb93a386Sopenharmony_ci const SkScalar* patchPtr; 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci SkV3 diff = quilt.fOrigin - fLocation; 123cb93a386Sopenharmony_ci SkScalar dot = diff.dot({mapPtr[6], mapPtr[7], mapPtr[8]}); 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci // This multiplies fOrientation by the matrix [quilt.fU quilt.fV diff] -- U, V, and diff are 126cb93a386Sopenharmony_ci // column vectors in the matrix -- then divides by the length of the projection of diff onto 127cb93a386Sopenharmony_ci // the view axis (which is 'dot'). This transforms the patch (which transforms from local path 128cb93a386Sopenharmony_ci // space to world space) into view space (since fOrientation transforms from world space to 129cb93a386Sopenharmony_ci // view space). 130cb93a386Sopenharmony_ci // 131cb93a386Sopenharmony_ci // The divide by 'dot' isn't strictly necessary as the homogeneous divide would do much the 132cb93a386Sopenharmony_ci // same thing (it's just scaling the entire matrix by 1/dot). It looks like it's normalizing 133cb93a386Sopenharmony_ci // the matrix into some canonical space. 134cb93a386Sopenharmony_ci patchPtr = (const SkScalar*)&quilt; 135cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMScaleX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot)); 136cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMSkewY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot)); 137cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMPersp0, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot)); 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci patchPtr += 3; 140cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMSkewX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot)); 141cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMScaleY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot)); 142cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMPersp1, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot)); 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci patchPtr = (const SkScalar*)(const void*)&diff; 145cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMTransX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot)); 146cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMTransY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot)); 147cb93a386Sopenharmony_ci matrix->set(SkMatrix::kMPersp2, SK_Scalar1); 148cb93a386Sopenharmony_ci} 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ciSk3DView::Sk3DView() { 153cb93a386Sopenharmony_ci fRec = &fInitialRec; 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ciSk3DView::~Sk3DView() { 157cb93a386Sopenharmony_ci Rec* rec = fRec; 158cb93a386Sopenharmony_ci while (rec != &fInitialRec) { 159cb93a386Sopenharmony_ci Rec* next = rec->fNext; 160cb93a386Sopenharmony_ci delete rec; 161cb93a386Sopenharmony_ci rec = next; 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci} 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_civoid Sk3DView::save() { 166cb93a386Sopenharmony_ci Rec* rec = new Rec; 167cb93a386Sopenharmony_ci rec->fNext = fRec; 168cb93a386Sopenharmony_ci rec->fMatrix = fRec->fMatrix; 169cb93a386Sopenharmony_ci fRec = rec; 170cb93a386Sopenharmony_ci} 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_civoid Sk3DView::restore() { 173cb93a386Sopenharmony_ci SkASSERT(fRec != &fInitialRec); 174cb93a386Sopenharmony_ci Rec* next = fRec->fNext; 175cb93a386Sopenharmony_ci delete fRec; 176cb93a386Sopenharmony_ci fRec = next; 177cb93a386Sopenharmony_ci} 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_civoid Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) { 180cb93a386Sopenharmony_ci // the camera location is passed in inches, set in pt 181cb93a386Sopenharmony_ci SkScalar lz = z * 72.0f; 182cb93a386Sopenharmony_ci fCamera.fLocation = {x * 72.0f, y * 72.0f, lz}; 183cb93a386Sopenharmony_ci fCamera.fObserver = {0, 0, lz}; 184cb93a386Sopenharmony_ci fCamera.update(); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci} 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ciSkScalar Sk3DView::getCameraLocationX() const { 189cb93a386Sopenharmony_ci return fCamera.fLocation.x / 72.0f; 190cb93a386Sopenharmony_ci} 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ciSkScalar Sk3DView::getCameraLocationY() const { 193cb93a386Sopenharmony_ci return fCamera.fLocation.y / 72.0f; 194cb93a386Sopenharmony_ci} 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ciSkScalar Sk3DView::getCameraLocationZ() const { 197cb93a386Sopenharmony_ci return fCamera.fLocation.z / 72.0f; 198cb93a386Sopenharmony_ci} 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_civoid Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z) { 201cb93a386Sopenharmony_ci fRec->fMatrix.preTranslate(x, y, z); 202cb93a386Sopenharmony_ci} 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_civoid Sk3DView::rotateX(SkScalar deg) { 205cb93a386Sopenharmony_ci fRec->fMatrix.preConcat(SkM44::Rotate({1, 0, 0}, deg * SK_ScalarPI / 180)); 206cb93a386Sopenharmony_ci} 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_civoid Sk3DView::rotateY(SkScalar deg) { 209cb93a386Sopenharmony_ci fRec->fMatrix.preConcat(SkM44::Rotate({0,-1, 0}, deg * SK_ScalarPI / 180)); 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_civoid Sk3DView::rotateZ(SkScalar deg) { 213cb93a386Sopenharmony_ci fRec->fMatrix.preConcat(SkM44::Rotate({0, 0, 1}, deg * SK_ScalarPI / 180)); 214cb93a386Sopenharmony_ci} 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ciSkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const { 217cb93a386Sopenharmony_ci SkPatch3D patch; 218cb93a386Sopenharmony_ci patch.transform(fRec->fMatrix); 219cb93a386Sopenharmony_ci return patch.dotWith(x, y, z); 220cb93a386Sopenharmony_ci} 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_civoid Sk3DView::getMatrix(SkMatrix* matrix) const { 223cb93a386Sopenharmony_ci if (matrix != nullptr) { 224cb93a386Sopenharmony_ci SkPatch3D patch; 225cb93a386Sopenharmony_ci patch.transform(fRec->fMatrix); 226cb93a386Sopenharmony_ci fCamera.patchToMatrix(patch, matrix); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci} 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_civoid Sk3DView::applyToCanvas(SkCanvas* canvas) const { 233cb93a386Sopenharmony_ci SkMatrix matrix; 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ci this->getMatrix(&matrix); 236cb93a386Sopenharmony_ci canvas->concat(matrix); 237cb93a386Sopenharmony_ci} 238