Home | History | Annotate | Download | only in effects
      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 "SkEmbossMaskFilter.h"
     11 #include "SkBlurMaskFilter.h"
     12 #include "SkBlurMask.h"
     13 #include "SkEmbossMask.h"
     14 #include "SkFlattenableBuffers.h"
     15 
     16 static inline int pin2byte(int n) {
     17     if (n < 0) {
     18         n = 0;
     19     } else if (n > 0xFF) {
     20         n = 0xFF;
     21     }
     22     return n;
     23 }
     24 
     25 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
     26                                              SkScalar ambient, SkScalar specular,
     27                                              SkScalar blurRadius) {
     28     if (direction == NULL) {
     29         return NULL;
     30     }
     31 
     32     // ambient should be 0...1 as a scalar
     33     int am = pin2byte(SkScalarToFixed(ambient) >> 8);
     34 
     35     // specular should be 0..15.99 as a scalar
     36     int sp = pin2byte(SkScalarToFixed(specular) >> 12);
     37 
     38     SkEmbossMaskFilter::Light   light;
     39 
     40     memcpy(light.fDirection, direction, sizeof(light.fDirection));
     41     light.fAmbient = SkToU8(am);
     42     light.fSpecular = SkToU8(sp);
     43 
     44     return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
     45 }
     46 
     47 ///////////////////////////////////////////////////////////////////////////////
     48 
     49 static void normalize(SkScalar v[3]) {
     50     SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
     51     mag = SkScalarSqrt(mag);
     52 
     53     for (int i = 0; i < 3; i++) {
     54         v[i] = SkScalarDiv(v[i], mag);
     55     }
     56 }
     57 
     58 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
     59         : fLight(light), fBlurRadius(blurRadius) {
     60     normalize(fLight.fDirection);
     61 }
     62 
     63 SkMask::Format SkEmbossMaskFilter::getFormat() const {
     64     return SkMask::k3D_Format;
     65 }
     66 
     67 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
     68                             const SkMatrix& matrix, SkIPoint* margin) const {
     69     SkScalar radius = matrix.mapRadius(fBlurRadius);
     70 
     71     if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style,
     72                           SkBlurMask::kLow_Quality)) {
     73         return false;
     74     }
     75 
     76     dst->fFormat = SkMask::k3D_Format;
     77     if (margin) {
     78         margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
     79     }
     80 
     81     if (src.fImage == NULL) {
     82         return true;
     83     }
     84 
     85     // create a larger buffer for the other two channels (should force fBlur to do this for us)
     86 
     87     {
     88         uint8_t* alphaPlane = dst->fImage;
     89         size_t   planeSize = dst->computeImageSize();
     90         if (0 == planeSize) {
     91             return false;   // too big to allocate, abort
     92         }
     93         dst->fImage = SkMask::AllocImage(planeSize * 3);
     94         memcpy(dst->fImage, alphaPlane, planeSize);
     95         SkMask::FreeImage(alphaPlane);
     96     }
     97 
     98     // run the light direction through the matrix...
     99     Light   light = fLight;
    100     matrix.mapVectors((SkVector*)(void*)light.fDirection,
    101                       (SkVector*)(void*)fLight.fDirection, 1);
    102 
    103     // now restore the length of the XY component
    104     // cast to SkVector so we can call setLength (this double cast silences alias warnings)
    105     SkVector* vec = (SkVector*)(void*)light.fDirection;
    106     vec->setLength(light.fDirection[0],
    107                    light.fDirection[1],
    108                    SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
    109 
    110     SkEmbossMask::Emboss(dst, light);
    111 
    112     // restore original alpha
    113     memcpy(dst->fImage, src.fImage, src.computeImageSize());
    114 
    115     return true;
    116 }
    117 
    118 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer)
    119         : SkMaskFilter(buffer) {
    120     SkASSERT(buffer.getArrayCount() == sizeof(Light));
    121     buffer.readByteArray(&fLight);
    122     SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
    123     fBlurRadius = buffer.readScalar();
    124 }
    125 
    126 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
    127     this->INHERITED::flatten(buffer);
    128 
    129     Light tmpLight = fLight;
    130     tmpLight.fPad = 0;    // for the font-cache lookup to be clean
    131     buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
    132     buffer.writeScalar(fBlurRadius);
    133 }
    134