blob: a206e76ed09c6f4709059bd62e756d8272643e31 [file] [log] [blame]
Brian Osman7c979f52019-02-12 13:27:51 -05001/*
2* Copyright 2019 Google LLC
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 "SkCurve.h"
9
10#include "SkRandom.h"
11#include "SkReflected.h"
12
Brian Osman8b6283f2019-02-14 16:55:21 -050013static SkScalar eval_cubic(const SkScalar* pts, SkScalar x) {
14 SkScalar ix = (1 - x);
15 return pts[0]*ix*ix*ix + pts[1]*3*ix*ix*x + pts[2]*3*ix*x*x + pts[3]*x*x*x;
Brian Osman7c979f52019-02-12 13:27:51 -050016}
17
Brian Osman8b6283f2019-02-14 16:55:21 -050018SkScalar SkCurveSegment::eval(SkScalar x, SkRandom& random) const {
19 SkScalar result = fConstant ? fMin[0] : eval_cubic(fMin, x);
20 if (fRanged) {
21 result += ((fConstant ? fMax[0] : eval_cubic(fMax, x)) - result) * random.nextF();
22 }
23 if (fBidirectional && random.nextBool()) {
24 result = -result;
25 }
26 return result;
27}
28
29void SkCurveSegment::visitFields(SkFieldVisitor* v) {
30 v->visit("Constant", fConstant);
Brian Osman7c979f52019-02-12 13:27:51 -050031 v->visit("Ranged", fRanged);
Brian Osman8b6283f2019-02-14 16:55:21 -050032 v->visit("Bidirectional", fBidirectional);
Brian Osman7c979f52019-02-12 13:27:51 -050033 v->visit("A0", fMin[0]);
34 v->visit("B0", fMin[1]);
35 v->visit("C0", fMin[2]);
36 v->visit("D0", fMin[3]);
37 v->visit("A1", fMax[0]);
38 v->visit("B1", fMax[1]);
39 v->visit("C1", fMax[2]);
40 v->visit("D1", fMax[3]);
41}
42
Brian Osman8b6283f2019-02-14 16:55:21 -050043SkScalar SkCurve::eval(SkScalar x, SkRandom& random) const {
44 SkASSERT(fSegments.count() == fXValues.count() + 1);
45
46 int i = 0;
47 for (; i < fXValues.count(); ++i) {
48 if (x <= fXValues[i]) {
49 break;
50 }
51 }
52
53 SkScalar rangeMin = (i == 0) ? 0.0f : fXValues[i - 1];
54 SkScalar rangeMax = (i == fXValues.count()) ? 1.0f : fXValues[i];
55 SkScalar segmentX = (x - rangeMin) / (rangeMax - rangeMin);
56 SkASSERT(0.0f <= segmentX && segmentX <= 1.0f);
57 return fSegments[i].eval(segmentX, random);
Brian Osman7c979f52019-02-12 13:27:51 -050058}
59
Brian Osman8b6283f2019-02-14 16:55:21 -050060void SkCurve::visitFields(SkFieldVisitor* v) {
61 v->visit("XValues", fXValues);
62 v->visit("Segments", fSegments);
63
64 // Validate and fixup
65 if (fSegments.empty()) {
66 fSegments.push_back().setConstant(0.0f);
67 }
68 fXValues.resize_back(fSegments.count() - 1);
69 for (int i = 0; i < fXValues.count(); ++i) {
70 fXValues[i] = SkTPin(fXValues[i], i > 0 ? fXValues[i - 1] : 0.0f, 1.0f);
71 }
Brian Osman7c979f52019-02-12 13:27:51 -050072}