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 "SkDiscretePathEffect.h"
     11 #include "SkReadBuffer.h"
     12 #include "SkWriteBuffer.h"
     13 #include "SkPathMeasure.h"
     14 #include "SkStrokeRec.h"
     15 
     16 static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
     17     SkVector normal = tangent;
     18     normal.rotateCCW();
     19     normal.setLength(scale);
     20     *p += normal;
     21 }
     22 
     23 SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength,
     24                                            SkScalar deviation,
     25                                            uint32_t seedAssist)
     26     : fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
     27 {
     28 }
     29 
     30 /** \class LCGRandom
     31 
     32     Utility class that implements pseudo random 32bit numbers using a fast
     33     linear equation. Unlike rand(), this class holds its own seed (initially
     34     set to 0), so that multiple instances can be used with no side-effects.
     35 
     36     Copied from the original implementation of SkRandom. Only contains the
     37     methods used by SkDiscretePathEffect::filterPath, with methods that were
     38     not called directly moved to private.
     39 */
     40 
     41 class LCGRandom {
     42 public:
     43     LCGRandom(uint32_t seed) : fSeed(seed) {}
     44 
     45     /** Return the next pseudo random number expressed as a SkScalar
     46         in the range (-SK_Scalar1..SK_Scalar1).
     47     */
     48     SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
     49 
     50 private:
     51     /** Return the next pseudo random number as an unsigned 32bit value.
     52     */
     53     uint32_t nextU() { uint32_t r = fSeed * kMul + kAdd; fSeed = r; return r; }
     54 
     55     /** Return the next pseudo random number as a signed 32bit value.
     56      */
     57     int32_t nextS() { return (int32_t)this->nextU(); }
     58 
     59     /** Return the next pseudo random number expressed as a signed SkFixed
     60      in the range (-SK_Fixed1..SK_Fixed1).
     61      */
     62     SkFixed nextSFixed1() { return this->nextS() >> 15; }
     63 
     64     //  See "Numerical Recipes in C", 1992 page 284 for these constants
     65     enum {
     66         kMul = 1664525,
     67         kAdd = 1013904223
     68     };
     69     uint32_t fSeed;
     70 };
     71 
     72 bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
     73                                       SkStrokeRec* rec, const SkRect*) const {
     74     bool doFill = rec->isFillStyle();
     75 
     76     SkPathMeasure   meas(src, doFill);
     77 
     78     /* Caller may supply their own seed assist, which by default is 0 */
     79     uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength());
     80 
     81     LCGRandom   rand(seed ^ ((seed << 16) | (seed >> 16)));
     82     SkScalar    scale = fPerterb;
     83     SkPoint     p;
     84     SkVector    v;
     85 
     86     do {
     87         SkScalar    length = meas.getLength();
     88 
     89         if (fSegLength * (2 + doFill) > length) {
     90             meas.getSegment(0, length, dst, true);  // to short for us to mangle
     91         } else {
     92             int         n = SkScalarRoundToInt(length / fSegLength);
     93             SkScalar    delta = length / n;
     94             SkScalar    distance = 0;
     95 
     96             if (meas.isClosed()) {
     97                 n -= 1;
     98                 distance += delta/2;
     99             }
    100 
    101             if (meas.getPosTan(distance, &p, &v)) {
    102                 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
    103                 dst->moveTo(p);
    104             }
    105             while (--n >= 0) {
    106                 distance += delta;
    107                 if (meas.getPosTan(distance, &p, &v)) {
    108                     Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
    109                     dst->lineTo(p);
    110                 }
    111             }
    112             if (meas.isClosed()) {
    113                 dst->close();
    114             }
    115         }
    116     } while (meas.nextContour());
    117     return true;
    118 }
    119 
    120 SkFlattenable* SkDiscretePathEffect::CreateProc(SkReadBuffer& buffer) {
    121     SkScalar segLength = buffer.readScalar();
    122     SkScalar perterb = buffer.readScalar();
    123     uint32_t seed = buffer.readUInt();
    124     return Create(segLength, perterb, seed);
    125 }
    126 
    127 void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const {
    128     buffer.writeScalar(fSegLength);
    129     buffer.writeScalar(fPerterb);
    130     buffer.writeUInt(fSeedAssist);
    131 }
    132 
    133 #ifndef SK_IGNORE_TO_STRING
    134 void SkDiscretePathEffect::toString(SkString* str) const {
    135     str->appendf("SkDiscretePathEffect: (");
    136     str->appendf("segLength: %.2f deviation: %.2f seed %d", fSegLength, fPerterb, fSeedAssist);
    137     str->append(")");
    138 }
    139 #endif
    140