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