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 #include "SkString.h"
     16 
     17 static inline int pin2byte(int n) {
     18     if (n < 0) {
     19         n = 0;
     20     } else if (n > 0xFF) {
     21         n = 0xFF;
     22     }
     23     return n;
     24 }
     25 
     26 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
     27                                              SkScalar ambient, SkScalar specular,
     28                                              SkScalar blurRadius) {
     29     if (direction == NULL) {
     30         return NULL;
     31     }
     32 
     33     // ambient should be 0...1 as a scalar
     34     int am = pin2byte(SkScalarToFixed(ambient) >> 8);
     35 
     36     // specular should be 0..15.99 as a scalar
     37     int sp = pin2byte(SkScalarToFixed(specular) >> 12);
     38 
     39     SkEmbossMaskFilter::Light   light;
     40 
     41     memcpy(light.fDirection, direction, sizeof(light.fDirection));
     42     light.fAmbient = SkToU8(am);
     43     light.fSpecular = SkToU8(sp);
     44 
     45     return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
     46 }
     47 
     48 ///////////////////////////////////////////////////////////////////////////////
     49 
     50 static void normalize(SkScalar v[3]) {
     51     SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
     52     mag = SkScalarSqrt(mag);
     53 
     54     for (int i = 0; i < 3; i++) {
     55         v[i] = SkScalarDiv(v[i], mag);
     56     }
     57 }
     58 
     59 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
     60         : fLight(light), fBlurRadius(blurRadius) {
     61     normalize(fLight.fDirection);
     62 }
     63 
     64 SkMask::Format SkEmbossMaskFilter::getFormat() const {
     65     return SkMask::k3D_Format;
     66 }
     67 
     68 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
     69                             const SkMatrix& matrix, SkIPoint* margin) const {
     70     SkScalar radius = matrix.mapRadius(fBlurRadius);
     71 
     72     if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style,
     73                           SkBlurMask::kLow_Quality)) {
     74         return false;
     75     }
     76 
     77     dst->fFormat = SkMask::k3D_Format;
     78     if (margin) {
     79         margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
     80     }
     81 
     82     if (src.fImage == NULL) {
     83         return true;
     84     }
     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,
    102                       (SkVector*)(void*)fLight.fDirection, 1);
    103 
    104     // now restore the length of the XY component
    105     // cast to SkVector so we can call setLength (this double cast silences alias warnings)
    106     SkVector* vec = (SkVector*)(void*)light.fDirection;
    107     vec->setLength(light.fDirection[0],
    108                    light.fDirection[1],
    109                    SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
    110 
    111     SkEmbossMask::Emboss(dst, light);
    112 
    113     // restore original alpha
    114     memcpy(dst->fImage, src.fImage, src.computeImageSize());
    115 
    116     return true;
    117 }
    118 
    119 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer)
    120         : SkMaskFilter(buffer) {
    121     SkASSERT(buffer.getArrayCount() == sizeof(Light));
    122     buffer.readByteArray(&fLight);
    123     SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
    124     fBlurRadius = buffer.readScalar();
    125 }
    126 
    127 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
    128     this->INHERITED::flatten(buffer);
    129 
    130     Light tmpLight = fLight;
    131     tmpLight.fPad = 0;    // for the font-cache lookup to be clean
    132     buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
    133     buffer.writeScalar(fBlurRadius);
    134 }
    135 
    136 #ifdef SK_DEVELOPER
    137 void SkEmbossMaskFilter::toString(SkString* str) const {
    138     str->append("SkEmbossMaskFilter: (");
    139 
    140     str->append("direction: (");
    141     str->appendScalar(fLight.fDirection[0]);
    142     str->append(", ");
    143     str->appendScalar(fLight.fDirection[1]);
    144     str->append(", ");
    145     str->appendScalar(fLight.fDirection[2]);
    146     str->append(") ");
    147 
    148     str->appendf("ambient: %d specular: %d ",
    149         fLight.fAmbient, fLight.fSpecular);
    150 
    151     str->append("blurRadius: ");
    152     str->appendScalar(fBlurRadius);
    153     str->append(")");
    154 }
    155 #endif
    156