1ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov/*
2ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * Copyright 2014 Google Inc.
3ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov *
4ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * Use of this source code is governed by a BSD-style license that can be
5ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * found in the LICENSE file.
6ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov */
7ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
8ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov#include "SkPatchUtils.h"
9ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
10b3c9d1c33caf325aada244204215eb790c228c12dandov#include "SkColorPriv.h"
11b3c9d1c33caf325aada244204215eb790c228c12dandov#include "SkGeometry.h"
12b3c9d1c33caf325aada244204215eb790c228c12dandov
13b3c9d1c33caf325aada244204215eb790c228c12dandov/**
14b3c9d1c33caf325aada244204215eb790c228c12dandov * Evaluator to sample the values of a cubic bezier using forward differences.
15b3c9d1c33caf325aada244204215eb790c228c12dandov * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only
16b3c9d1c33caf325aada244204215eb790c228c12dandov * adding precalculated values.
17b3c9d1c33caf325aada244204215eb790c228c12dandov * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h
18b3c9d1c33caf325aada244204215eb790c228c12dandov * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first
19b3c9d1c33caf325aada244204215eb790c228c12dandov * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After
20b3c9d1c33caf325aada244204215eb790c228c12dandov * obtaining this value (mh) we could just add this constant step to our first sampled point
21b3c9d1c33caf325aada244204215eb790c228c12dandov * to compute the next one.
22b3c9d1c33caf325aada244204215eb790c228c12dandov *
23b3c9d1c33caf325aada244204215eb790c228c12dandov * For the cubic case the first difference gives as a result a quadratic polynomial to which we can
24b3c9d1c33caf325aada244204215eb790c228c12dandov * apply again forward differences and get linear function to which we can apply again forward
25b3c9d1c33caf325aada244204215eb790c228c12dandov * differences to get a constant difference. This is why we keep an array of size 4, the 0th
26b3c9d1c33caf325aada244204215eb790c228c12dandov * position keeps the sampled value while the next ones keep the quadratic, linear and constant
27b3c9d1c33caf325aada244204215eb790c228c12dandov * difference values.
28b3c9d1c33caf325aada244204215eb790c228c12dandov */
29b3c9d1c33caf325aada244204215eb790c228c12dandov
30b3c9d1c33caf325aada244204215eb790c228c12dandovclass FwDCubicEvaluator {
31b3c9d1c33caf325aada244204215eb790c228c12dandov
32b3c9d1c33caf325aada244204215eb790c228c12dandovpublic:
33b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator()
34b3c9d1c33caf325aada244204215eb790c228c12dandov    : fMax(0)
35b3c9d1c33caf325aada244204215eb790c228c12dandov    , fCurrent(0)
36b3c9d1c33caf325aada244204215eb790c228c12dandov    , fDivisions(0) {
37b3c9d1c33caf325aada244204215eb790c228c12dandov        memset(fPoints, 0, 4 * sizeof(SkPoint));
38b3c9d1c33caf325aada244204215eb790c228c12dandov        memset(fPoints, 0, 4 * sizeof(SkPoint));
39b3c9d1c33caf325aada244204215eb790c228c12dandov        memset(fPoints, 0, 4 * sizeof(SkPoint));
40b3c9d1c33caf325aada244204215eb790c228c12dandov    }
41b3c9d1c33caf325aada244204215eb790c228c12dandov
42b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
43b3c9d1c33caf325aada244204215eb790c228c12dandov     * Receives the 4 control points of the cubic bezier.
44b3c9d1c33caf325aada244204215eb790c228c12dandov     */
45b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d) {
46b3c9d1c33caf325aada244204215eb790c228c12dandov        fPoints[0] = a;
47b3c9d1c33caf325aada244204215eb790c228c12dandov        fPoints[1] = b;
48b3c9d1c33caf325aada244204215eb790c228c12dandov        fPoints[2] = c;
49b3c9d1c33caf325aada244204215eb790c228c12dandov        fPoints[3] = d;
50b3c9d1c33caf325aada244204215eb790c228c12dandov
51b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar cx[4], cy[4];
52b3c9d1c33caf325aada244204215eb790c228c12dandov        SkGetCubicCoeff(fPoints, cx, cy);
53b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[0].set(cx[0], cy[0]);
54b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[1].set(cx[1], cy[1]);
55b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[2].set(cx[2], cy[2]);
56b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[3].set(cx[3], cy[3]);
57b3c9d1c33caf325aada244204215eb790c228c12dandov
58b3c9d1c33caf325aada244204215eb790c228c12dandov        this->restart(1);
59b3c9d1c33caf325aada244204215eb790c228c12dandov    }
60b3c9d1c33caf325aada244204215eb790c228c12dandov
61b3c9d1c33caf325aada244204215eb790c228c12dandov    explicit FwDCubicEvaluator(const SkPoint points[4])  {
62b3c9d1c33caf325aada244204215eb790c228c12dandov        memcpy(fPoints, points, 4 * sizeof(SkPoint));
63b3c9d1c33caf325aada244204215eb790c228c12dandov
64b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar cx[4], cy[4];
65b3c9d1c33caf325aada244204215eb790c228c12dandov        SkGetCubicCoeff(fPoints, cx, cy);
66b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[0].set(cx[0], cy[0]);
67b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[1].set(cx[1], cy[1]);
68b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[2].set(cx[2], cy[2]);
69b3c9d1c33caf325aada244204215eb790c228c12dandov        fCoefs[3].set(cx[3], cy[3]);
70b3c9d1c33caf325aada244204215eb790c228c12dandov
71b3c9d1c33caf325aada244204215eb790c228c12dandov        this->restart(1);
72b3c9d1c33caf325aada244204215eb790c228c12dandov    }
73b3c9d1c33caf325aada244204215eb790c228c12dandov
74b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
75b3c9d1c33caf325aada244204215eb790c228c12dandov     * Restarts the forward differences evaluator to the first value of t = 0.
76b3c9d1c33caf325aada244204215eb790c228c12dandov     */
77b3c9d1c33caf325aada244204215eb790c228c12dandov    void restart(int divisions)  {
78b3c9d1c33caf325aada244204215eb790c228c12dandov        fDivisions = divisions;
79b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar h  = 1.f / fDivisions;
80b3c9d1c33caf325aada244204215eb790c228c12dandov        fCurrent    = 0;
81b3c9d1c33caf325aada244204215eb790c228c12dandov        fMax        = fDivisions + 1;
82b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[0]  = fCoefs[3];
83b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar h2 = h * h;
84b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar h3 = h2 * h;
85b3c9d1c33caf325aada244204215eb790c228c12dandov
86b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[3].set(6.f * fCoefs[0].x() * h3, 6.f * fCoefs[0].y() * h3); //6ah^3
87b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[2].set(fFwDiff[3].x() + 2.f * fCoefs[1].x() * h2, //6ah^3 + 2bh^2
88b3c9d1c33caf325aada244204215eb790c228c12dandov                       fFwDiff[3].y() + 2.f * fCoefs[1].y() * h2);
89b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[1].set(fCoefs[0].x() * h3 + fCoefs[1].x() * h2 + fCoefs[2].x() * h,//ah^3 + bh^2 +ch
90b3c9d1c33caf325aada244204215eb790c228c12dandov                       fCoefs[0].y() * h3 + fCoefs[1].y() * h2 + fCoefs[2].y() * h);
91b3c9d1c33caf325aada244204215eb790c228c12dandov    }
92b3c9d1c33caf325aada244204215eb790c228c12dandov
93b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
94b3c9d1c33caf325aada244204215eb790c228c12dandov     * Check if the evaluator is still within the range of 0<=t<=1
95b3c9d1c33caf325aada244204215eb790c228c12dandov     */
96b3c9d1c33caf325aada244204215eb790c228c12dandov    bool done() const {
97b3c9d1c33caf325aada244204215eb790c228c12dandov        return fCurrent > fMax;
98b3c9d1c33caf325aada244204215eb790c228c12dandov    }
99b3c9d1c33caf325aada244204215eb790c228c12dandov
100b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
101b3c9d1c33caf325aada244204215eb790c228c12dandov     * Call next to obtain the SkPoint sampled and move to the next one.
102b3c9d1c33caf325aada244204215eb790c228c12dandov     */
103b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint next() {
104b3c9d1c33caf325aada244204215eb790c228c12dandov        SkPoint point = fFwDiff[0];
105b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[0]    += fFwDiff[1];
106b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[1]    += fFwDiff[2];
107b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[2]    += fFwDiff[3];
108b3c9d1c33caf325aada244204215eb790c228c12dandov        fCurrent++;
109b3c9d1c33caf325aada244204215eb790c228c12dandov        return point;
110b3c9d1c33caf325aada244204215eb790c228c12dandov    }
111b3c9d1c33caf325aada244204215eb790c228c12dandov
112b3c9d1c33caf325aada244204215eb790c228c12dandov    const SkPoint* getCtrlPoints() const {
113b3c9d1c33caf325aada244204215eb790c228c12dandov        return fPoints;
114b3c9d1c33caf325aada244204215eb790c228c12dandov    }
115b3c9d1c33caf325aada244204215eb790c228c12dandov
116b3c9d1c33caf325aada244204215eb790c228c12dandovprivate:
117b3c9d1c33caf325aada244204215eb790c228c12dandov    int fMax, fCurrent, fDivisions;
118b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint fFwDiff[4], fCoefs[4], fPoints[4];
119b3c9d1c33caf325aada244204215eb790c228c12dandov};
120b3c9d1c33caf325aada244204215eb790c228c12dandov
121b3c9d1c33caf325aada244204215eb790c228c12dandov////////////////////////////////////////////////////////////////////////////////
122b3c9d1c33caf325aada244204215eb790c228c12dandov
123ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov// size in pixels of each partition per axis, adjust this knob
124b3c9d1c33caf325aada244204215eb790c228c12dandovstatic const int kPartitionSize = 10;
125ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
126ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov/**
127ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * Calculate the approximate arc length given a bezier curve's control points.
128ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov */
129ecfff21bde1f0ca3c36533eded325066b5f2d42ddandovstatic SkScalar approx_arc_length(SkPoint* points, int count) {
130ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    if (count < 2) {
131ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov        return 0;
132ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    }
133ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    SkScalar arcLength = 0;
134ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    for (int i = 0; i < count - 1; i++) {
135ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov        arcLength += SkPoint::Distance(points[i], points[i + 1]);
136ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    }
137ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    return arcLength;
138ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov}
139ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
140b3c9d1c33caf325aada244204215eb790c228c12dandovstatic SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
141b3c9d1c33caf325aada244204215eb790c228c12dandov                      SkScalar c11) {
142b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar a = c00 * (1.f - tx) + c10 * tx;
143b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar b = c01 * (1.f - tx) + c11 * tx;
144b3c9d1c33caf325aada244204215eb790c228c12dandov    return a * (1.f - ty) + b * ty;
145b3c9d1c33caf325aada244204215eb790c228c12dandov}
146b3c9d1c33caf325aada244204215eb790c228c12dandov
147b3c9d1c33caf325aada244204215eb790c228c12dandovSkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix) {
148ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
149ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    // Approximate length of each cubic.
150b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint pts[kNumPtsCubic];
151b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getTopCubic(cubics, pts);
152b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
153b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar topLength = approx_arc_length(pts, kNumPtsCubic);
154ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
155b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getBottomCubic(cubics, pts);
156b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
157b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar bottomLength = approx_arc_length(pts, kNumPtsCubic);
158ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
159b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getLeftCubic(cubics, pts);
160b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
161b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar leftLength = approx_arc_length(pts, kNumPtsCubic);
162ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
163b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getRightCubic(cubics, pts);
164b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
165b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar rightLength = approx_arc_length(pts, kNumPtsCubic);
166ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
167ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    // Level of detail per axis, based on the larger side between top and bottom or left and right
168ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitionSize);
169ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitionSize);
170ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
171b3c9d1c33caf325aada244204215eb790c228c12dandov    return SkISize::Make(SkMax32(8, lodX), SkMax32(8, lodY));
172b3c9d1c33caf325aada244204215eb790c228c12dandov}
173b3c9d1c33caf325aada244204215eb790c228c12dandov
174b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) {
175b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kTopP0_CubicCtrlPts];
176b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kTopP1_CubicCtrlPts];
177b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kTopP2_CubicCtrlPts];
178b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kTopP3_CubicCtrlPts];
179b3c9d1c33caf325aada244204215eb790c228c12dandov}
180b3c9d1c33caf325aada244204215eb790c228c12dandov
181b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) {
182b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kBottomP0_CubicCtrlPts];
183b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kBottomP1_CubicCtrlPts];
184b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kBottomP2_CubicCtrlPts];
185b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kBottomP3_CubicCtrlPts];
186b3c9d1c33caf325aada244204215eb790c228c12dandov}
187b3c9d1c33caf325aada244204215eb790c228c12dandov
188b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) {
189b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kLeftP0_CubicCtrlPts];
190b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kLeftP1_CubicCtrlPts];
191b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kLeftP2_CubicCtrlPts];
192b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kLeftP3_CubicCtrlPts];
193b3c9d1c33caf325aada244204215eb790c228c12dandov}
194b3c9d1c33caf325aada244204215eb790c228c12dandov
195b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) {
196b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kRightP0_CubicCtrlPts];
197b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kRightP1_CubicCtrlPts];
198b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kRightP2_CubicCtrlPts];
199b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kRightP3_CubicCtrlPts];
200b3c9d1c33caf325aada244204215eb790c228c12dandov}
201b3c9d1c33caf325aada244204215eb790c228c12dandov
202b3c9d1c33caf325aada244204215eb790c228c12dandovbool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12],
203b3c9d1c33caf325aada244204215eb790c228c12dandov                   const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) {
204b3c9d1c33caf325aada244204215eb790c228c12dandov    if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) {
205b3c9d1c33caf325aada244204215eb790c228c12dandov        return false;
206b3c9d1c33caf325aada244204215eb790c228c12dandov    }
20745f7842de7148a544008483a7829071d3dffba51dandov
20845f7842de7148a544008483a7829071d3dffba51dandov    // check for overflow in multiplication
20945f7842de7148a544008483a7829071d3dffba51dandov    const int64_t lodX64 = (lodX + 1),
21045f7842de7148a544008483a7829071d3dffba51dandov                   lodY64 = (lodY + 1),
21145f7842de7148a544008483a7829071d3dffba51dandov                   mult64 = lodX64 * lodY64;
21245f7842de7148a544008483a7829071d3dffba51dandov    if (mult64 > SK_MaxS32) {
21345f7842de7148a544008483a7829071d3dffba51dandov        return false;
21445f7842de7148a544008483a7829071d3dffba51dandov    }
21545f7842de7148a544008483a7829071d3dffba51dandov    data->fVertexCount = SkToS32(mult64);
21645f7842de7148a544008483a7829071d3dffba51dandov
21745f7842de7148a544008483a7829071d3dffba51dandov    // it is recommended to generate draw calls of no more than 65536 indices, so we never generate
21845f7842de7148a544008483a7829071d3dffba51dandov    // more than 60000 indices. To accomplish that we resize the LOD and vertex count
21945f7842de7148a544008483a7829071d3dffba51dandov    if (data->fVertexCount > 10000 || lodX > 200 || lodY > 200) {
22045f7842de7148a544008483a7829071d3dffba51dandov        SkScalar weightX = static_cast<SkScalar>(lodX) / (lodX + lodY);
22145f7842de7148a544008483a7829071d3dffba51dandov        SkScalar weightY = static_cast<SkScalar>(lodY) / (lodX + lodY);
22245f7842de7148a544008483a7829071d3dffba51dandov
22345f7842de7148a544008483a7829071d3dffba51dandov        // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of
22445f7842de7148a544008483a7829071d3dffba51dandov        // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6)
22545f7842de7148a544008483a7829071d3dffba51dandov        lodX = static_cast<int>(weightX * 200);
22645f7842de7148a544008483a7829071d3dffba51dandov        lodY = static_cast<int>(weightY * 200);
22745f7842de7148a544008483a7829071d3dffba51dandov        data->fVertexCount = (lodX + 1) * (lodY + 1);
22845f7842de7148a544008483a7829071d3dffba51dandov    }
229b3c9d1c33caf325aada244204215eb790c228c12dandov    data->fIndexCount = lodX * lodY * 6;
230b3c9d1c33caf325aada244204215eb790c228c12dandov
231b3c9d1c33caf325aada244204215eb790c228c12dandov    data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
232b3c9d1c33caf325aada244204215eb790c228c12dandov    data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
233b3c9d1c33caf325aada244204215eb790c228c12dandov
234b3c9d1c33caf325aada244204215eb790c228c12dandov    // if colors is not null then create array for colors
235b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPMColor colorsPM[kNumCorners];
23649f085dddff10473b6ebf832a974288300224e60bsalomon    if (colors) {
237b3c9d1c33caf325aada244204215eb790c228c12dandov        // premultiply colors to avoid color bleeding.
238b3c9d1c33caf325aada244204215eb790c228c12dandov        for (int i = 0; i < kNumCorners; i++) {
239b3c9d1c33caf325aada244204215eb790c228c12dandov            colorsPM[i] = SkPreMultiplyColor(colors[i]);
240b3c9d1c33caf325aada244204215eb790c228c12dandov        }
241b3c9d1c33caf325aada244204215eb790c228c12dandov        data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
242b3c9d1c33caf325aada244204215eb790c228c12dandov    }
243b3c9d1c33caf325aada244204215eb790c228c12dandov
244b3c9d1c33caf325aada244204215eb790c228c12dandov    // if texture coordinates are not null then create array for them
24549f085dddff10473b6ebf832a974288300224e60bsalomon    if (texCoords) {
246b3c9d1c33caf325aada244204215eb790c228c12dandov        data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
247b3c9d1c33caf325aada244204215eb790c228c12dandov    }
248b3c9d1c33caf325aada244204215eb790c228c12dandov
249b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint pts[kNumPtsCubic];
250b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getBottomCubic(cubics, pts);
251b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fBottom(pts);
252b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getTopCubic(cubics, pts);
253b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fTop(pts);
254b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getLeftCubic(cubics, pts);
255b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fLeft(pts);
256b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getRightCubic(cubics, pts);
257b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fRight(pts);
258b3c9d1c33caf325aada244204215eb790c228c12dandov
259b3c9d1c33caf325aada244204215eb790c228c12dandov    fBottom.restart(lodX);
260b3c9d1c33caf325aada244204215eb790c228c12dandov    fTop.restart(lodX);
261b3c9d1c33caf325aada244204215eb790c228c12dandov
262b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar u = 0.0f;
263b3c9d1c33caf325aada244204215eb790c228c12dandov    int stride = lodY + 1;
264b3c9d1c33caf325aada244204215eb790c228c12dandov    for (int x = 0; x <= lodX; x++) {
265b3c9d1c33caf325aada244204215eb790c228c12dandov        SkPoint bottom = fBottom.next(), top = fTop.next();
266b3c9d1c33caf325aada244204215eb790c228c12dandov        fLeft.restart(lodY);
267b3c9d1c33caf325aada244204215eb790c228c12dandov        fRight.restart(lodY);
268b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar v = 0.f;
269b3c9d1c33caf325aada244204215eb790c228c12dandov        for (int y = 0; y <= lodY; y++) {
270b3c9d1c33caf325aada244204215eb790c228c12dandov            int dataIndex = x * (lodY + 1) + y;
271b3c9d1c33caf325aada244204215eb790c228c12dandov
272b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint left = fLeft.next(), right = fRight.next();
273b3c9d1c33caf325aada244204215eb790c228c12dandov
274b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
275b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - v) * top.y() + v * bottom.y());
276b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
277b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - u) * left.y() + u * right.y());
278b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint s2 = SkPoint::Make(
279b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
280b3c9d1c33caf325aada244204215eb790c228c12dandov                                                     + u * fTop.getCtrlPoints()[3].x())
281b3c9d1c33caf325aada244204215eb790c228c12dandov                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
282b3c9d1c33caf325aada244204215eb790c228c12dandov                                              + u * fBottom.getCtrlPoints()[3].x()),
283b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
284b3c9d1c33caf325aada244204215eb790c228c12dandov                                                     + u * fTop.getCtrlPoints()[3].y())
285b3c9d1c33caf325aada244204215eb790c228c12dandov                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
286b3c9d1c33caf325aada244204215eb790c228c12dandov                                              + u * fBottom.getCtrlPoints()[3].y()));
287b3c9d1c33caf325aada244204215eb790c228c12dandov            data->fPoints[dataIndex] = s0 + s1 - s2;
288b3c9d1c33caf325aada244204215eb790c228c12dandov
28949f085dddff10473b6ebf832a974288300224e60bsalomon            if (colors) {
290b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t a = uint8_t(bilerp(u, v,
291b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])),
292b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])),
293b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])),
294b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner]))));
295b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t r = uint8_t(bilerp(u, v,
296b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])),
297b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])),
298b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])),
299b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner]))));
300b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t g = uint8_t(bilerp(u, v,
301b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])),
302b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])),
303b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])),
304b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner]))));
305b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t b = uint8_t(bilerp(u, v,
306b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])),
307b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])),
308b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])),
309b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner]))));
310b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
311b3c9d1c33caf325aada244204215eb790c228c12dandov            }
312b3c9d1c33caf325aada244204215eb790c228c12dandov
31349f085dddff10473b6ebf832a974288300224e60bsalomon            if (texCoords) {
314b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fTexCoords[dataIndex] = SkPoint::Make(
315b3c9d1c33caf325aada244204215eb790c228c12dandov                                            bilerp(u, v, texCoords[kTopLeft_Corner].x(),
316b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kTopRight_Corner].x(),
317b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomLeft_Corner].x(),
318b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomRight_Corner].x()),
319b3c9d1c33caf325aada244204215eb790c228c12dandov                                            bilerp(u, v, texCoords[kTopLeft_Corner].y(),
320b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kTopRight_Corner].y(),
321b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomLeft_Corner].y(),
322b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomRight_Corner].y()));
323b3c9d1c33caf325aada244204215eb790c228c12dandov
324b3c9d1c33caf325aada244204215eb790c228c12dandov            }
325b3c9d1c33caf325aada244204215eb790c228c12dandov
326b3c9d1c33caf325aada244204215eb790c228c12dandov            if(x < lodX && y < lodY) {
327b3c9d1c33caf325aada244204215eb790c228c12dandov                int i = 6 * (x * lodY + y);
328b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i] = x * stride + y;
329b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 1] = x * stride + 1 + y;
330b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
331b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 3] = data->fIndices[i];
332b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 4] = data->fIndices[i + 2];
333b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 5] = (x + 1) * stride + y;
334b3c9d1c33caf325aada244204215eb790c228c12dandov            }
335b3c9d1c33caf325aada244204215eb790c228c12dandov            v = SkScalarClampMax(v + 1.f / lodY, 1);
336b3c9d1c33caf325aada244204215eb790c228c12dandov        }
337b3c9d1c33caf325aada244204215eb790c228c12dandov        u = SkScalarClampMax(u + 1.f / lodX, 1);
338b3c9d1c33caf325aada244204215eb790c228c12dandov    }
339b3c9d1c33caf325aada244204215eb790c228c12dandov    return true;
340b3c9d1c33caf325aada244204215eb790c228c12dandov
341ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov}
342