OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkPatchUtils.h" | 8 #include "SkPatchUtils.h" |
9 | 9 |
| 10 #include "SkColorPriv.h" |
| 11 |
10 // size in pixels of each partition per axis, adjust this knob | 12 // size in pixels of each partition per axis, adjust this knob |
11 static const int kPartitionSize = 15; | 13 static const int kPartitionSize = 15; |
12 | 14 |
13 /** | 15 /** |
14 * Calculate the approximate arc length given a bezier curve's control points. | 16 * Calculate the approximate arc length given a bezier curve's control points. |
15 */ | 17 */ |
16 static SkScalar approx_arc_length(SkPoint* points, int count) { | 18 static SkScalar approx_arc_length(SkPoint* points, int count) { |
17 if (count < 2) { | 19 if (count < 2) { |
18 return 0; | 20 return 0; |
19 } | 21 } |
20 SkScalar arcLength = 0; | 22 SkScalar arcLength = 0; |
21 for (int i = 0; i < count - 1; i++) { | 23 for (int i = 0; i < count - 1; i++) { |
22 arcLength += SkPoint::Distance(points[i], points[i + 1]); | 24 arcLength += SkPoint::Distance(points[i], points[i + 1]); |
23 } | 25 } |
24 return arcLength; | 26 return arcLength; |
25 } | 27 } |
26 | 28 |
27 SkISize SkPatchUtils::GetLevelOfDetail(const SkPatch& patch, const SkMatrix* mat
rix) { | 29 static SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkS
calar c01, |
28 | 30 SkScalar c11) { |
29 SkPoint mapPts[12]; | 31 SkScalar a = c00 * (1.f - tx) + c10 * tx; |
30 matrix->mapPoints(mapPts, patch.getControlPoints(), 12); | 32 SkScalar b = c01 * (1.f - tx) + c11 * tx; |
| 33 return a * (1.f - ty) + b * ty; |
| 34 } |
| 35 |
| 36 SkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix*
matrix) { |
31 | 37 |
32 // Approximate length of each cubic. | 38 // Approximate length of each cubic. |
33 SkPoint pts[4]; | 39 SkPoint pts[4]; |
34 patch.getTopPoints(pts); | 40 SkPatchUtils::getTopCubic(cubics, pts); |
35 matrix->mapPoints(pts, 4); | 41 matrix->mapPoints(pts, 4); |
36 SkScalar topLength = approx_arc_length(pts, 4); | 42 SkScalar topLength = approx_arc_length(pts, 4); |
37 | 43 |
38 patch.getBottomPoints(pts); | 44 SkPatchUtils::getBottomCubic(cubics, pts); |
39 matrix->mapPoints(pts, 4); | 45 matrix->mapPoints(pts, 4); |
40 SkScalar bottomLength = approx_arc_length(pts, 4); | 46 SkScalar bottomLength = approx_arc_length(pts, 4); |
41 | 47 |
42 patch.getLeftPoints(pts); | 48 SkPatchUtils::getLeftCubic(cubics, pts); |
43 matrix->mapPoints(pts, 4); | 49 matrix->mapPoints(pts, 4); |
44 SkScalar leftLength = approx_arc_length(pts, 4); | 50 SkScalar leftLength = approx_arc_length(pts, 4); |
45 | 51 |
46 patch.getRightPoints(pts); | 52 SkPatchUtils::getRightCubic(cubics, pts); |
47 matrix->mapPoints(pts, 4); | 53 matrix->mapPoints(pts, 4); |
48 SkScalar rightLength = approx_arc_length(pts, 4); | 54 SkScalar rightLength = approx_arc_length(pts, 4); |
49 | 55 |
50 // Level of detail per axis, based on the larger side between top and bottom
or left and right | 56 // Level of detail per axis, based on the larger side between top and bottom
or left and right |
51 int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitio
nSize); | 57 int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitio
nSize); |
52 int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitio
nSize); | 58 int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitio
nSize); |
53 | 59 |
54 return SkISize::Make(SkMax32(4, lodX), SkMax32(4, lodY)); | 60 return SkISize::Make(SkMax32(4, lodX), SkMax32(4, lodY)); |
55 } | 61 } |
| 62 |
| 63 void SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) { |
| 64 if (NULL == points) { |
| 65 return; |
| 66 } |
| 67 points[0] = cubics[SkPatch::kTopP0_CubicCtrlPts]; |
| 68 points[1] = cubics[SkPatch::kTopP1_CubicCtrlPts]; |
| 69 points[2] = cubics[SkPatch::kTopP2_CubicCtrlPts]; |
| 70 points[3] = cubics[SkPatch::kTopP3_CubicCtrlPts]; |
| 71 } |
| 72 |
| 73 void SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) { |
| 74 if (NULL == points) { |
| 75 return; |
| 76 } |
| 77 points[0] = cubics[SkPatch::kBottomP0_CubicCtrlPts]; |
| 78 points[1] = cubics[SkPatch::kBottomP1_CubicCtrlPts]; |
| 79 points[2] = cubics[SkPatch::kBottomP2_CubicCtrlPts]; |
| 80 points[3] = cubics[SkPatch::kBottomP3_CubicCtrlPts]; |
| 81 } |
| 82 |
| 83 void SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) { |
| 84 if (NULL == points) { |
| 85 return; |
| 86 } |
| 87 points[0] = cubics[SkPatch::kLeftP0_CubicCtrlPts]; |
| 88 points[1] = cubics[SkPatch::kLeftP1_CubicCtrlPts]; |
| 89 points[2] = cubics[SkPatch::kLeftP2_CubicCtrlPts]; |
| 90 points[3] = cubics[SkPatch::kLeftP3_CubicCtrlPts]; |
| 91 } |
| 92 |
| 93 void SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) { |
| 94 if (NULL == points) { |
| 95 return; |
| 96 } |
| 97 points[0] = cubics[SkPatch::kRightP0_CubicCtrlPts]; |
| 98 points[1] = cubics[SkPatch::kRightP1_CubicCtrlPts]; |
| 99 points[2] = cubics[SkPatch::kRightP2_CubicCtrlPts]; |
| 100 points[3] = cubics[SkPatch::kRightP3_CubicCtrlPts]; |
| 101 } |
| 102 |
| 103 bool SkPatchUtils::getVertexData(SkPatch::VertexData* data, const SkPoint cubics
[12], |
| 104 const SkColor colors[4], const SkPoint texCoords[4], int lodX
, int lodY) { |
| 105 if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) { |
| 106 return false; |
| 107 } |
| 108 |
| 109 // number of indices is limited by size of uint16_t, so we clamp it to avoid
overflow |
| 110 data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536); |
| 111 lodX = SkMin32(lodX, 255); |
| 112 lodY = SkMin32(lodY, 255); |
| 113 data->fIndexCount = lodX * lodY * 6; |
| 114 |
| 115 data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount); |
| 116 data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount); |
| 117 |
| 118 // if colors is not null then create array for colors |
| 119 SkPMColor colorsPM[SkPatch::kNumCorners]; |
| 120 if (NULL != colors) { |
| 121 // premultiply colors to avoid color bleeding. |
| 122 for (int i = 0; i < SkPatch::kNumCorners; i++) { |
| 123 colorsPM[i] = SkPreMultiplyColor(colors[i]); |
| 124 } |
| 125 data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount); |
| 126 } |
| 127 |
| 128 // if texture coordinates are not null then create array for them |
| 129 if (NULL != texCoords) { |
| 130 data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount); |
| 131 } |
| 132 |
| 133 SkPoint pts[SkPatch::kNumPtsCubic]; |
| 134 SkPatchUtils::getBottomCubic(cubics, pts); |
| 135 FwDCubicEvaluator fBottom(pts); |
| 136 SkPatchUtils::getTopCubic(cubics, pts); |
| 137 FwDCubicEvaluator fTop(pts); |
| 138 SkPatchUtils::getLeftCubic(cubics, pts); |
| 139 FwDCubicEvaluator fLeft(pts); |
| 140 SkPatchUtils::getRightCubic(cubics, pts); |
| 141 FwDCubicEvaluator fRight(pts); |
| 142 |
| 143 fBottom.restart(lodX); |
| 144 fTop.restart(lodX); |
| 145 |
| 146 SkScalar u = 0.0f; |
| 147 int stride = lodY + 1; |
| 148 for (int x = 0; x <= lodX; x++) { |
| 149 SkPoint bottom = fBottom.next(), top = fTop.next(); |
| 150 fLeft.restart(lodY); |
| 151 fRight.restart(lodY); |
| 152 SkScalar v = 0.f; |
| 153 for (int y = 0; y <= lodY; y++) { |
| 154 int dataIndex = x * (lodY + 1) + y; |
| 155 |
| 156 SkPoint left = fLeft.next(), right = fRight.next(); |
| 157 |
| 158 SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(), |
| 159 (1.0f - v) * top.y() + v * bottom.y()); |
| 160 SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(), |
| 161 (1.0f - u) * left.y() + u * right.y()); |
| 162 SkPoint s2 = SkPoint::Make( |
| 163 (1.0f - v) * ((1.0f - u) * fTop.getCtrlPo
ints()[0].x() |
| 164 + u * fTop.getCtrlPoints()[
3].x()) |
| 165 + v * ((1.0f - u) * fBottom.getCtrlPoints
()[0].x() |
| 166 + u * fBottom.getCtrlPoints()[3].x
()), |
| 167 (1.0f - v) * ((1.0f - u) * fTop.getCtrlPo
ints()[0].y() |
| 168 + u * fTop.getCtrlPoints()[
3].y()) |
| 169 + v * ((1.0f - u) * fBottom.getCtrlPoints
()[0].y() |
| 170 + u * fBottom.getCtrlPoints()[3].y
())); |
| 171 data->fPoints[dataIndex] = s0 + s1 - s2; |
| 172 |
| 173 if (NULL != colors) { |
| 174 uint8_t a = uint8_t(bilerp(u, v, |
| 175 SkScalar(SkColorGetA(colorsPM[SkPatch::kTopLe
ft_Corner])), |
| 176 SkScalar(SkColorGetA(colorsPM[SkPatch::kTopRi
ght_Corner])), |
| 177 SkScalar(SkColorGetA(colorsPM[SkPatch::kBotto
mLeft_Corner])), |
| 178 SkScalar(SkColorGetA(colorsPM[SkPatch::kBotto
mRight_Corner])))); |
| 179 uint8_t r = uint8_t(bilerp(u, v, |
| 180 SkScalar(SkColorGetR(colorsPM[SkPatch::kTopLe
ft_Corner])), |
| 181 SkScalar(SkColorGetR(colorsPM[SkPatch::kTopRi
ght_Corner])), |
| 182 SkScalar(SkColorGetR(colorsPM[SkPatch::kBotto
mLeft_Corner])), |
| 183 SkScalar(SkColorGetR(colorsPM[SkPatch::kBotto
mRight_Corner])))); |
| 184 uint8_t g = uint8_t(bilerp(u, v, |
| 185 SkScalar(SkColorGetG(colorsPM[SkPatch::kTopLe
ft_Corner])), |
| 186 SkScalar(SkColorGetG(colorsPM[SkPatch::kTopRi
ght_Corner])), |
| 187 SkScalar(SkColorGetG(colorsPM[SkPatch::kBotto
mLeft_Corner])), |
| 188 SkScalar(SkColorGetG(colorsPM[SkPatch::kBotto
mRight_Corner])))); |
| 189 uint8_t b = uint8_t(bilerp(u, v, |
| 190 SkScalar(SkColorGetB(colorsPM[SkPatch::kTopLe
ft_Corner])), |
| 191 SkScalar(SkColorGetB(colorsPM[SkPatch::kTopRi
ght_Corner])), |
| 192 SkScalar(SkColorGetB(colorsPM[SkPatch::kBotto
mLeft_Corner])), |
| 193 SkScalar(SkColorGetB(colorsPM[SkPatch::kBotto
mRight_Corner])))); |
| 194 data->fColors[dataIndex] = SkPackARGB32(a,r,g,b); |
| 195 } |
| 196 |
| 197 if (NULL != texCoords) { |
| 198 data->fTexCoords[dataIndex] = SkPoint::Make( |
| 199 bilerp(u, v, texCoords[SkPatch::kTop
Left_Corner].x(), |
| 200 texCoords[SkPatch::kTopRight_
Corner].x(), |
| 201 texCoords[SkPatch::kBottomLef
t_Corner].x(), |
| 202 texCoords[SkPatch::kBottomRig
ht_Corner].x()), |
| 203 bilerp(u, v, texCoords[SkPatch::kTop
Left_Corner].y(), |
| 204 texCoords[SkPatch::kTopRight_
Corner].y(), |
| 205 texCoords[SkPatch::kBottomLef
t_Corner].y(), |
| 206 texCoords[SkPatch::kBottomRig
ht_Corner].y())); |
| 207 |
| 208 } |
| 209 |
| 210 if(x < lodX && y < lodY) { |
| 211 int i = 6 * (x * lodY + y); |
| 212 data->fIndices[i] = x * stride + y; |
| 213 data->fIndices[i + 1] = x * stride + 1 + y; |
| 214 data->fIndices[i + 2] = (x + 1) * stride + 1 + y; |
| 215 data->fIndices[i + 3] = data->fIndices[i]; |
| 216 data->fIndices[i + 4] = data->fIndices[i + 2]; |
| 217 data->fIndices[i + 5] = (x + 1) * stride + y; |
| 218 } |
| 219 v = SkScalarClampMax(v + 1.f / lodY, 1); |
| 220 } |
| 221 u = SkScalarClampMax(u + 1.f / lodX, 1); |
| 222 } |
| 223 return true; |
| 224 |
| 225 } |
OLD | NEW |