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 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
     25                                              SkScalar ambient, SkScalar specular,
     26                                              SkScalar blurRadius)
     27 {
     28     if (direction == NULL)
     29         return NULL;
     30 
     31     // ambient should be 0...1 as a scalar
     32     int am = SkScalarToFixed(ambient) >> 8;
     33     if (am < 0) am = 0;
     34     else if (am > 0xFF) am = 0xFF;
     35 
     36     // specular should be 0..15.99 as a scalar
     37     int sp = SkScalarToFixed(specular) >> 12;
     38     if (sp < 0) sp = 0;
     39     else if (sp > 0xFF) sp = 0xFF;
     40 
     41     SkEmbossMaskFilter::Light   light;
     42 
     43     memcpy(light.fDirection, direction, sizeof(light.fDirection));
     44     light.fAmbient = SkToU8(am);
     45     light.fSpecular = SkToU8(sp);
     46 
     47     return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
     48 }
     49 
     50 /////////////////////////////////////////////////////////////////////////////////////////////
     51 
     52 static void normalize(SkScalar v[3])
     53 {
     54     SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
     55     mag = SkScalarSqrt(mag);
     56 
     57     for (int i = 0; i < 3; i++)
     58         v[i] = SkScalarDiv(v[i], mag);
     59 }
     60 
     61 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
     62         : fLight(light), fBlurRadius(blurRadius)
     63 {
     64     normalize(fLight.fDirection);
     65 }
     66 
     67 SkMask::Format SkEmbossMaskFilter::getFormat()
     68 {
     69     return SkMask::k3D_Format;
     70 }
     71 
     72 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin)
     73 {
     74     SkScalar radius = matrix.mapRadius(fBlurRadius);
     75 
     76     if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style))
     77         return false;
     78 
     79     dst->fFormat = SkMask::k3D_Format;
     80     if (margin)
     81         margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
     82 
     83     if (src.fImage == NULL)
     84         return true;
     85 
     86     // create a larger buffer for the other two channels (should force fBlur to do this for us)
     87 
     88     {
     89         uint8_t* alphaPlane = dst->fImage;
     90         size_t   planeSize = dst->computeImageSize();
     91         if (0 == planeSize) {
     92             return false;   // too big to allocate, abort
     93         }
     94         dst->fImage = SkMask::AllocImage(planeSize * 3);
     95         memcpy(dst->fImage, alphaPlane, planeSize);
     96         SkMask::FreeImage(alphaPlane);
     97     }
     98 
     99     // run the light direction through the matrix...
    100     Light   light = fLight;
    101     matrix.mapVectors((SkVector*)(void*)light.fDirection, (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 SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer)
    119 {
    120     return SkNEW_ARGS(SkEmbossMaskFilter, (buffer));
    121 }
    122 
    123 SkFlattenable::Factory SkEmbossMaskFilter::getFactory()
    124 {
    125     return CreateProc;
    126 }
    127 
    128 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) : SkMaskFilter(buffer)
    129 {
    130     buffer.read(&fLight, sizeof(fLight));
    131     SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
    132     fBlurRadius = buffer.readScalar();
    133 }
    134 
    135 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer)
    136 {
    137     this->INHERITED::flatten(buffer);
    138 
    139     fLight.fPad = 0;    // for the font-cache lookup to be clean
    140     buffer.writeMul4(&fLight, sizeof(fLight));
    141     buffer.writeScalar(fBlurRadius);
    142 }
    143 
    144