Home | History | Annotate | Download | only in effects
      1 /* libs/graphics/effects/SkEmbossMaskFilter.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include "SkEmbossMaskFilter.h"
     19 #include "SkBlurMaskFilter.h"
     20 #include "SkBlurMask.h"
     21 #include "SkEmbossMask.h"
     22 #include "SkBuffer.h"
     23 
     24 static inline int pin2byte(int n) {
     25     if (n < 0) {
     26         n = 0;
     27     } else if (n > 0xFF) {
     28         n = 0xFF;
     29     }
     30     return n;
     31 }
     32 
     33 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
     34                                              SkScalar ambient, SkScalar specular,
     35                                              SkScalar blurRadius) {
     36     if (direction == NULL) {
     37         return NULL;
     38     }
     39 
     40     // ambient should be 0...1 as a scalar
     41     int am = pin2byte(SkScalarToFixed(ambient) >> 8);
     42 
     43     // specular should be 0..15.99 as a scalar
     44     int sp = pin2byte(SkScalarToFixed(specular) >> 12);
     45 
     46     SkEmbossMaskFilter::Light   light;
     47 
     48     memcpy(light.fDirection, direction, sizeof(light.fDirection));
     49     light.fAmbient = SkToU8(am);
     50     light.fSpecular = SkToU8(sp);
     51 
     52     return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
     53 }
     54 
     55 ///////////////////////////////////////////////////////////////////////////////
     56 
     57 static void normalize(SkScalar v[3]) {
     58     SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
     59     mag = SkScalarSqrt(mag);
     60 
     61     for (int i = 0; i < 3; i++) {
     62         v[i] = SkScalarDiv(v[i], mag);
     63     }
     64 }
     65 
     66 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
     67         : fLight(light), fBlurRadius(blurRadius) {
     68     normalize(fLight.fDirection);
     69 }
     70 
     71 SkMask::Format SkEmbossMaskFilter::getFormat() {
     72     return SkMask::k3D_Format;
     73 }
     74 
     75 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
     76                                     const SkMatrix& matrix, SkIPoint* margin) {
     77     SkScalar radius = matrix.mapRadius(fBlurRadius);
     78 
     79     if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style,
     80                           SkBlurMask::kLow_Quality)) {
     81         return false;
     82     }
     83 
     84     dst->fFormat = SkMask::k3D_Format;
     85     if (margin) {
     86         margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
     87     }
     88 
     89     if (src.fImage == NULL) {
     90         return true;
     91     }
     92 
     93     // create a larger buffer for the other two channels (should force fBlur to do this for us)
     94 
     95     {
     96         uint8_t* alphaPlane = dst->fImage;
     97         size_t   planeSize = dst->computeImageSize();
     98         if (0 == planeSize) {
     99             return false;   // too big to allocate, abort
    100         }
    101         dst->fImage = SkMask::AllocImage(planeSize * 3);
    102         memcpy(dst->fImage, alphaPlane, planeSize);
    103         SkMask::FreeImage(alphaPlane);
    104     }
    105 
    106     // run the light direction through the matrix...
    107     Light   light = fLight;
    108     matrix.mapVectors((SkVector*)(void*)light.fDirection,
    109                       (SkVector*)(void*)fLight.fDirection, 1);
    110 
    111     // now restore the length of the XY component
    112     // cast to SkVector so we can call setLength (this double cast silences alias warnings)
    113     SkVector* vec = (SkVector*)(void*)light.fDirection;
    114     vec->setLength(light.fDirection[0],
    115                    light.fDirection[1],
    116                    SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
    117 
    118     SkEmbossMask::Emboss(dst, light);
    119 
    120     // restore original alpha
    121     memcpy(dst->fImage, src.fImage, src.computeImageSize());
    122 
    123     return true;
    124 }
    125 
    126 SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) {
    127     return SkNEW_ARGS(SkEmbossMaskFilter, (buffer));
    128 }
    129 
    130 SkFlattenable::Factory SkEmbossMaskFilter::getFactory() {
    131     return CreateProc;
    132 }
    133 
    134 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer)
    135         : SkMaskFilter(buffer) {
    136     buffer.read(&fLight, sizeof(fLight));
    137     SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
    138     fBlurRadius = buffer.readScalar();
    139 }
    140 
    141 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) {
    142     this->INHERITED::flatten(buffer);
    143 
    144     fLight.fPad = 0;    // for the font-cache lookup to be clean
    145     buffer.writeMul4(&fLight, sizeof(fLight));
    146     buffer.writeScalar(fBlurRadius);
    147 }
    148 
    149