Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      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 "SkCamera.h"
      9 
     10 static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a,
     11                                const SkScalar b[], int step_b,
     12                                SkScalar denom) {
     13     SkScalar prod = 0;
     14     for (int i = 0; i < count; i++) {
     15         prod += a[0] * b[0];
     16         a += step_a;
     17         b += step_b;
     18     }
     19     return prod / denom;
     20 }
     21 
     22 static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a,
     23                                        const SkScalar b[], int step_b) {
     24     SkScalar prod = 0;
     25     for (int i = 0; i < count; i++) {
     26         prod += a[0] * b[0];
     27         a += step_a;
     28         b += step_b;
     29     }
     30     return prod;
     31 }
     32 
     33 ///////////////////////////////////////////////////////////////////////////////
     34 
     35 SkScalar SkPoint3D::normalize(SkUnit3D* unit) const {
     36     SkScalar mag = SkScalarSqrt(fX*fX + fY*fY + fZ*fZ);
     37     if (mag) {
     38         SkScalar scale = SkScalarInvert(mag);
     39         unit->fX = fX * scale;
     40         unit->fY = fY * scale;
     41         unit->fZ = fZ * scale;
     42     } else {
     43         unit->fX = unit->fY = unit->fZ = 0;
     44     }
     45     return mag;
     46 }
     47 
     48 SkScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b) {
     49     return a.fX * b.fX + a.fY * b.fY + a.fZ * b.fZ;
     50 }
     51 
     52 void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross) {
     53     SkASSERT(cross);
     54 
     55     // use x,y,z, in case &a == cross or &b == cross
     56 
     57     SkScalar x = a.fY * b.fZ - a.fZ * b.fY;
     58     SkScalar y = a.fZ * b.fX - a.fX * b.fY;
     59     SkScalar z = a.fX * b.fY - a.fY * b.fX;
     60 
     61     cross->set(x, y, z);
     62 }
     63 
     64 ///////////////////////////////////////////////////////////////////////////////
     65 
     66 SkPatch3D::SkPatch3D() {
     67     this->reset();
     68 }
     69 
     70 void SkPatch3D::reset() {
     71     fOrigin.set(0, 0, 0);
     72     fU.set(SK_Scalar1, 0, 0);
     73     fV.set(0, -SK_Scalar1, 0);
     74 }
     75 
     76 void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const {
     77     if (dst == nullptr) {
     78         dst = (SkPatch3D*)this;
     79     }
     80     m.mapVector(fU, &dst->fU);
     81     m.mapVector(fV, &dst->fV);
     82     m.mapPoint(fOrigin, &dst->fOrigin);
     83 }
     84 
     85 SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const {
     86     SkScalar cx = SkScalarMul(fU.fY, fV.fZ) - SkScalarMul(fU.fZ, fV.fY);
     87     SkScalar cy = SkScalarMul(fU.fZ, fV.fX) - SkScalarMul(fU.fX, fV.fY);
     88     SkScalar cz = SkScalarMul(fU.fX, fV.fY) - SkScalarMul(fU.fY, fV.fX);
     89 
     90     return SkScalarMul(cx, dx) + SkScalarMul(cy, dy) + SkScalarMul(cz, dz);
     91 }
     92 
     93 ///////////////////////////////////////////////////////////////////////////////
     94 
     95 void SkMatrix3D::reset() {
     96     memset(fMat, 0, sizeof(fMat));
     97     fMat[0][0] = fMat[1][1] = fMat[2][2] = SK_Scalar1;
     98 }
     99 
    100 void SkMatrix3D::setTranslate(SkScalar x, SkScalar y, SkScalar z) {
    101     memset(fMat, 0, sizeof(fMat));
    102     fMat[0][0] = x;
    103     fMat[1][1] = y;
    104     fMat[2][2] = z;
    105 }
    106 
    107 void SkMatrix3D::setRotateX(SkScalar degX) {
    108     SkScalar    s, c;
    109 
    110     s = SkScalarSinCos(SkDegreesToRadians(degX), &c);
    111     this->setRow(0, SK_Scalar1, 0, 0);
    112     this->setRow(1, 0, c, -s);
    113     this->setRow(2, 0, s, c);
    114 }
    115 
    116 void SkMatrix3D::setRotateY(SkScalar degY) {
    117     SkScalar    s, c;
    118 
    119     s = SkScalarSinCos(SkDegreesToRadians(degY), &c);
    120     this->setRow(0, c, 0, -s);
    121     this->setRow(1, 0, SK_Scalar1, 0);
    122     this->setRow(2, s, 0, c);
    123 }
    124 
    125 void SkMatrix3D::setRotateZ(SkScalar degZ) {
    126     SkScalar    s, c;
    127 
    128     s = SkScalarSinCos(SkDegreesToRadians(degZ), &c);
    129     this->setRow(0, c, -s, 0);
    130     this->setRow(1, s, c, 0);
    131     this->setRow(2, 0, 0, SK_Scalar1);
    132 }
    133 
    134 void SkMatrix3D::preTranslate(SkScalar x, SkScalar y, SkScalar z) {
    135     SkScalar col[3] = { x, y, z};
    136 
    137     for (int i = 0; i < 3; i++) {
    138         fMat[i][3] += SkScalarDot(3, &fMat[i][0], 1, col, 1);
    139     }
    140 }
    141 
    142 void SkMatrix3D::preRotateX(SkScalar degX) {
    143     SkMatrix3D m;
    144     m.setRotateX(degX);
    145     this->setConcat(*this, m);
    146 }
    147 
    148 void SkMatrix3D::preRotateY(SkScalar degY) {
    149     SkMatrix3D m;
    150     m.setRotateY(degY);
    151     this->setConcat(*this, m);
    152 }
    153 
    154 void SkMatrix3D::preRotateZ(SkScalar degZ) {
    155     SkMatrix3D m;
    156     m.setRotateZ(degZ);
    157     this->setConcat(*this, m);
    158 }
    159 
    160 void SkMatrix3D::setConcat(const SkMatrix3D& a, const SkMatrix3D& b) {
    161     SkMatrix3D  tmp;
    162     SkMatrix3D* c = this;
    163 
    164     if (this == &a || this == &b) {
    165         c = &tmp;
    166     }
    167     for (int i = 0; i < 3; i++) {
    168         for (int j = 0; j < 3; j++) {
    169             c->fMat[i][j] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][j], 4);
    170         }
    171         c->fMat[i][3] = SkScalarDot(3, &a.fMat[i][0], 1,
    172                                     &b.fMat[0][3], 4) + a.fMat[i][3];
    173     }
    174 
    175     if (c == &tmp) {
    176         *this = tmp;
    177     }
    178 }
    179 
    180 void SkMatrix3D::mapPoint(const SkPoint3D& src, SkPoint3D* dst) const {
    181     SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1) + fMat[0][3];
    182     SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1) + fMat[1][3];
    183     SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1) + fMat[2][3];
    184     dst->set(x, y, z);
    185 }
    186 
    187 void SkMatrix3D::mapVector(const SkVector3D& src, SkVector3D* dst) const {
    188     SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1);
    189     SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1);
    190     SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1);
    191     dst->set(x, y, z);
    192 }
    193 
    194 ///////////////////////////////////////////////////////////////////////////////
    195 
    196 SkCamera3D::SkCamera3D() {
    197     this->reset();
    198 }
    199 
    200 void SkCamera3D::reset() {
    201     fLocation.set(0, 0, -SkIntToScalar(576));   // 8 inches backward
    202     fAxis.set(0, 0, SK_Scalar1);                // forward
    203     fZenith.set(0, -SK_Scalar1, 0);             // up
    204 
    205     fObserver.set(0, 0, fLocation.fZ);
    206 
    207     fNeedToUpdate = true;
    208 }
    209 
    210 void SkCamera3D::update() {
    211     fNeedToUpdate = true;
    212 }
    213 
    214 void SkCamera3D::doUpdate() const {
    215     SkUnit3D    axis, zenith, cross;
    216 
    217     fAxis.normalize(&axis);
    218 
    219     {
    220         SkScalar dot = SkUnit3D::Dot(*SkTCast<const SkUnit3D*>(&fZenith), axis);
    221 
    222         zenith.fX = fZenith.fX - dot * axis.fX;
    223         zenith.fY = fZenith.fY - dot * axis.fY;
    224         zenith.fZ = fZenith.fZ - dot * axis.fZ;
    225 
    226         SkTCast<SkPoint3D*>(&zenith)->normalize(&zenith);
    227     }
    228 
    229     SkUnit3D::Cross(axis, zenith, &cross);
    230 
    231     {
    232         SkMatrix* orien = &fOrientation;
    233         SkScalar x = fObserver.fX;
    234         SkScalar y = fObserver.fY;
    235         SkScalar z = fObserver.fZ;
    236 
    237         orien->set(SkMatrix::kMScaleX, x * axis.fX - z * cross.fX);
    238         orien->set(SkMatrix::kMSkewX,  x * axis.fY - z * cross.fY);
    239         orien->set(SkMatrix::kMTransX, x * axis.fZ - z * cross.fZ);
    240         orien->set(SkMatrix::kMSkewY,  y * axis.fX - z * zenith.fX);
    241         orien->set(SkMatrix::kMScaleY, y * axis.fY - z * zenith.fY);
    242         orien->set(SkMatrix::kMTransY, y * axis.fZ - z * zenith.fZ);
    243         orien->set(SkMatrix::kMPersp0, axis.fX);
    244         orien->set(SkMatrix::kMPersp1, axis.fY);
    245         orien->set(SkMatrix::kMPersp2, axis.fZ);
    246     }
    247 }
    248 
    249 void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const {
    250     if (fNeedToUpdate) {
    251         this->doUpdate();
    252         fNeedToUpdate = false;
    253     }
    254 
    255     const SkScalar* mapPtr = (const SkScalar*)(const void*)&fOrientation;
    256     const SkScalar* patchPtr;
    257     SkPoint3D       diff;
    258     SkScalar        dot;
    259 
    260     diff.fX = quilt.fOrigin.fX - fLocation.fX;
    261     diff.fY = quilt.fOrigin.fY - fLocation.fY;
    262     diff.fZ = quilt.fOrigin.fZ - fLocation.fZ;
    263 
    264     dot = SkUnit3D::Dot(*SkTCast<const SkUnit3D*>(&diff),
    265                         *SkTCast<const SkUnit3D*>(SkTCast<const SkScalar*>(&fOrientation) + 6));
    266 
    267     patchPtr = (const SkScalar*)&quilt;
    268     matrix->set(SkMatrix::kMScaleX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
    269     matrix->set(SkMatrix::kMSkewY,  SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
    270     matrix->set(SkMatrix::kMPersp0, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));
    271 
    272     patchPtr += 3;
    273     matrix->set(SkMatrix::kMSkewX,  SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
    274     matrix->set(SkMatrix::kMScaleY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
    275     matrix->set(SkMatrix::kMPersp1, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));
    276 
    277     patchPtr = (const SkScalar*)(const void*)&diff;
    278     matrix->set(SkMatrix::kMTransX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));
    279     matrix->set(SkMatrix::kMTransY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));
    280     matrix->set(SkMatrix::kMPersp2, SK_Scalar1);
    281 }
    282 
    283 ///////////////////////////////////////////////////////////////////////////////
    284 
    285 Sk3DView::Sk3DView() {
    286     fInitialRec.fMatrix.reset();
    287     fRec = &fInitialRec;
    288 }
    289 
    290 Sk3DView::~Sk3DView() {
    291     Rec* rec = fRec;
    292     while (rec != &fInitialRec) {
    293         Rec* next = rec->fNext;
    294         delete rec;
    295         rec = next;
    296     }
    297 }
    298 
    299 void Sk3DView::save() {
    300     Rec* rec = new Rec;
    301     rec->fNext = fRec;
    302     rec->fMatrix = fRec->fMatrix;
    303     fRec = rec;
    304 }
    305 
    306 void Sk3DView::restore() {
    307     SkASSERT(fRec != &fInitialRec);
    308     Rec* next = fRec->fNext;
    309     delete fRec;
    310     fRec = next;
    311 }
    312 
    313 #ifdef SK_BUILD_FOR_ANDROID
    314 void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) {
    315     // the camera location is passed in inches, set in pt
    316     SkScalar lz = z * 72.0f;
    317     fCamera.fLocation.set(x * 72.0f, y * 72.0f, lz);
    318     fCamera.fObserver.set(0, 0, lz);
    319     fCamera.update();
    320 
    321 }
    322 
    323 SkScalar Sk3DView::getCameraLocationX() {
    324     return fCamera.fLocation.fX / 72.0f;
    325 }
    326 
    327 SkScalar Sk3DView::getCameraLocationY() {
    328     return fCamera.fLocation.fY / 72.0f;
    329 }
    330 
    331 SkScalar Sk3DView::getCameraLocationZ() {
    332     return fCamera.fLocation.fZ / 72.0f;
    333 }
    334 #endif
    335 
    336 void Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z) {
    337     fRec->fMatrix.preTranslate(x, y, z);
    338 }
    339 
    340 void Sk3DView::rotateX(SkScalar deg) {
    341     fRec->fMatrix.preRotateX(deg);
    342 }
    343 
    344 void Sk3DView::rotateY(SkScalar deg) {
    345     fRec->fMatrix.preRotateY(deg);
    346 }
    347 
    348 void Sk3DView::rotateZ(SkScalar deg) {
    349     fRec->fMatrix.preRotateZ(deg);
    350 }
    351 
    352 SkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const {
    353     SkPatch3D   patch;
    354     patch.transform(fRec->fMatrix);
    355     return patch.dotWith(x, y, z);
    356 }
    357 
    358 void Sk3DView::getMatrix(SkMatrix* matrix) const {
    359     if (matrix != nullptr) {
    360         SkPatch3D   patch;
    361         patch.transform(fRec->fMatrix);
    362         fCamera.patchToMatrix(patch, matrix);
    363     }
    364 }
    365 
    366 #include "SkCanvas.h"
    367 
    368 void Sk3DView::applyToCanvas(SkCanvas* canvas) const {
    369     SkMatrix    matrix;
    370 
    371     this->getMatrix(&matrix);
    372     canvas->concat(matrix);
    373 }
    374