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