| Index: src/utils/SkPatchUtils.cpp
|
| diff --git a/src/utils/SkPatchUtils.cpp b/src/utils/SkPatchUtils.cpp
|
| index ab15290a346c7e046fdd4e6b64b888a628c73d3c..fe5a19405c2d5e4123f96acd93f2d5abca338239 100644
|
| --- a/src/utils/SkPatchUtils.cpp
|
| +++ b/src/utils/SkPatchUtils.cpp
|
| @@ -7,6 +7,8 @@
|
|
|
| #include "SkPatchUtils.h"
|
|
|
| +#include "SkColorPriv.h"
|
| +
|
| // size in pixels of each partition per axis, adjust this knob
|
| static const int kPartitionSize = 15;
|
|
|
| @@ -24,26 +26,30 @@ static SkScalar approx_arc_length(SkPoint* points, int count) {
|
| return arcLength;
|
| }
|
|
|
| -SkISize SkPatchUtils::GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix) {
|
| -
|
| - SkPoint mapPts[12];
|
| - matrix->mapPoints(mapPts, patch.getControlPoints(), 12);
|
| +static SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
|
| + SkScalar c11) {
|
| + SkScalar a = c00 * (1.f - tx) + c10 * tx;
|
| + SkScalar b = c01 * (1.f - tx) + c11 * tx;
|
| + return a * (1.f - ty) + b * ty;
|
| +}
|
| +
|
| +SkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix) {
|
|
|
| // Approximate length of each cubic.
|
| SkPoint pts[4];
|
| - patch.getTopPoints(pts);
|
| + SkPatchUtils::getTopCubic(cubics, pts);
|
| matrix->mapPoints(pts, 4);
|
| SkScalar topLength = approx_arc_length(pts, 4);
|
|
|
| - patch.getBottomPoints(pts);
|
| + SkPatchUtils::getBottomCubic(cubics, pts);
|
| matrix->mapPoints(pts, 4);
|
| SkScalar bottomLength = approx_arc_length(pts, 4);
|
|
|
| - patch.getLeftPoints(pts);
|
| + SkPatchUtils::getLeftCubic(cubics, pts);
|
| matrix->mapPoints(pts, 4);
|
| SkScalar leftLength = approx_arc_length(pts, 4);
|
|
|
| - patch.getRightPoints(pts);
|
| + SkPatchUtils::getRightCubic(cubics, pts);
|
| matrix->mapPoints(pts, 4);
|
| SkScalar rightLength = approx_arc_length(pts, 4);
|
|
|
| @@ -53,3 +59,167 @@ SkISize SkPatchUtils::GetLevelOfDetail(const SkPatch& patch, const SkMatrix* mat
|
|
|
| return SkISize::Make(SkMax32(4, lodX), SkMax32(4, lodY));
|
| }
|
| +
|
| +void SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) {
|
| + if (NULL == points) {
|
| + return;
|
| + }
|
| + points[0] = cubics[SkPatch::kTopP0_CubicCtrlPts];
|
| + points[1] = cubics[SkPatch::kTopP1_CubicCtrlPts];
|
| + points[2] = cubics[SkPatch::kTopP2_CubicCtrlPts];
|
| + points[3] = cubics[SkPatch::kTopP3_CubicCtrlPts];
|
| +}
|
| +
|
| +void SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) {
|
| + if (NULL == points) {
|
| + return;
|
| + }
|
| + points[0] = cubics[SkPatch::kBottomP0_CubicCtrlPts];
|
| + points[1] = cubics[SkPatch::kBottomP1_CubicCtrlPts];
|
| + points[2] = cubics[SkPatch::kBottomP2_CubicCtrlPts];
|
| + points[3] = cubics[SkPatch::kBottomP3_CubicCtrlPts];
|
| +}
|
| +
|
| +void SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) {
|
| + if (NULL == points) {
|
| + return;
|
| + }
|
| + points[0] = cubics[SkPatch::kLeftP0_CubicCtrlPts];
|
| + points[1] = cubics[SkPatch::kLeftP1_CubicCtrlPts];
|
| + points[2] = cubics[SkPatch::kLeftP2_CubicCtrlPts];
|
| + points[3] = cubics[SkPatch::kLeftP3_CubicCtrlPts];
|
| +}
|
| +
|
| +void SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) {
|
| + if (NULL == points) {
|
| + return;
|
| + }
|
| + points[0] = cubics[SkPatch::kRightP0_CubicCtrlPts];
|
| + points[1] = cubics[SkPatch::kRightP1_CubicCtrlPts];
|
| + points[2] = cubics[SkPatch::kRightP2_CubicCtrlPts];
|
| + points[3] = cubics[SkPatch::kRightP3_CubicCtrlPts];
|
| +}
|
| +
|
| +bool SkPatchUtils::getVertexData(SkPatch::VertexData* data, const SkPoint cubics[12],
|
| + const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) {
|
| + if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) {
|
| + return false;
|
| + }
|
| +
|
| + // number of indices is limited by size of uint16_t, so we clamp it to avoid overflow
|
| + data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536);
|
| + lodX = SkMin32(lodX, 255);
|
| + lodY = SkMin32(lodY, 255);
|
| + data->fIndexCount = lodX * lodY * 6;
|
| +
|
| + data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
|
| + data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
|
| +
|
| + // if colors is not null then create array for colors
|
| + SkPMColor colorsPM[SkPatch::kNumCorners];
|
| + if (NULL != colors) {
|
| + // premultiply colors to avoid color bleeding.
|
| + for (int i = 0; i < SkPatch::kNumCorners; i++) {
|
| + colorsPM[i] = SkPreMultiplyColor(colors[i]);
|
| + }
|
| + data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
|
| + }
|
| +
|
| + // if texture coordinates are not null then create array for them
|
| + if (NULL != texCoords) {
|
| + data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
|
| + }
|
| +
|
| + SkPoint pts[SkPatch::kNumPtsCubic];
|
| + SkPatchUtils::getBottomCubic(cubics, pts);
|
| + FwDCubicEvaluator fBottom(pts);
|
| + SkPatchUtils::getTopCubic(cubics, pts);
|
| + FwDCubicEvaluator fTop(pts);
|
| + SkPatchUtils::getLeftCubic(cubics, pts);
|
| + FwDCubicEvaluator fLeft(pts);
|
| + SkPatchUtils::getRightCubic(cubics, pts);
|
| + FwDCubicEvaluator fRight(pts);
|
| +
|
| + fBottom.restart(lodX);
|
| + fTop.restart(lodX);
|
| +
|
| + SkScalar u = 0.0f;
|
| + int stride = lodY + 1;
|
| + for (int x = 0; x <= lodX; x++) {
|
| + SkPoint bottom = fBottom.next(), top = fTop.next();
|
| + fLeft.restart(lodY);
|
| + fRight.restart(lodY);
|
| + SkScalar v = 0.f;
|
| + for (int y = 0; y <= lodY; y++) {
|
| + int dataIndex = x * (lodY + 1) + y;
|
| +
|
| + SkPoint left = fLeft.next(), right = fRight.next();
|
| +
|
| + SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
|
| + (1.0f - v) * top.y() + v * bottom.y());
|
| + SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
|
| + (1.0f - u) * left.y() + u * right.y());
|
| + SkPoint s2 = SkPoint::Make(
|
| + (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
|
| + + u * fTop.getCtrlPoints()[3].x())
|
| + + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
|
| + + u * fBottom.getCtrlPoints()[3].x()),
|
| + (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
|
| + + u * fTop.getCtrlPoints()[3].y())
|
| + + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
|
| + + u * fBottom.getCtrlPoints()[3].y()));
|
| + data->fPoints[dataIndex] = s0 + s1 - s2;
|
| +
|
| + if (NULL != colors) {
|
| + uint8_t a = uint8_t(bilerp(u, v,
|
| + SkScalar(SkColorGetA(colorsPM[SkPatch::kTopLeft_Corner])),
|
| + SkScalar(SkColorGetA(colorsPM[SkPatch::kTopRight_Corner])),
|
| + SkScalar(SkColorGetA(colorsPM[SkPatch::kBottomLeft_Corner])),
|
| + SkScalar(SkColorGetA(colorsPM[SkPatch::kBottomRight_Corner]))));
|
| + uint8_t r = uint8_t(bilerp(u, v,
|
| + SkScalar(SkColorGetR(colorsPM[SkPatch::kTopLeft_Corner])),
|
| + SkScalar(SkColorGetR(colorsPM[SkPatch::kTopRight_Corner])),
|
| + SkScalar(SkColorGetR(colorsPM[SkPatch::kBottomLeft_Corner])),
|
| + SkScalar(SkColorGetR(colorsPM[SkPatch::kBottomRight_Corner]))));
|
| + uint8_t g = uint8_t(bilerp(u, v,
|
| + SkScalar(SkColorGetG(colorsPM[SkPatch::kTopLeft_Corner])),
|
| + SkScalar(SkColorGetG(colorsPM[SkPatch::kTopRight_Corner])),
|
| + SkScalar(SkColorGetG(colorsPM[SkPatch::kBottomLeft_Corner])),
|
| + SkScalar(SkColorGetG(colorsPM[SkPatch::kBottomRight_Corner]))));
|
| + uint8_t b = uint8_t(bilerp(u, v,
|
| + SkScalar(SkColorGetB(colorsPM[SkPatch::kTopLeft_Corner])),
|
| + SkScalar(SkColorGetB(colorsPM[SkPatch::kTopRight_Corner])),
|
| + SkScalar(SkColorGetB(colorsPM[SkPatch::kBottomLeft_Corner])),
|
| + SkScalar(SkColorGetB(colorsPM[SkPatch::kBottomRight_Corner]))));
|
| + data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
|
| + }
|
| +
|
| + if (NULL != texCoords) {
|
| + data->fTexCoords[dataIndex] = SkPoint::Make(
|
| + bilerp(u, v, texCoords[SkPatch::kTopLeft_Corner].x(),
|
| + texCoords[SkPatch::kTopRight_Corner].x(),
|
| + texCoords[SkPatch::kBottomLeft_Corner].x(),
|
| + texCoords[SkPatch::kBottomRight_Corner].x()),
|
| + bilerp(u, v, texCoords[SkPatch::kTopLeft_Corner].y(),
|
| + texCoords[SkPatch::kTopRight_Corner].y(),
|
| + texCoords[SkPatch::kBottomLeft_Corner].y(),
|
| + texCoords[SkPatch::kBottomRight_Corner].y()));
|
| +
|
| + }
|
| +
|
| + if(x < lodX && y < lodY) {
|
| + int i = 6 * (x * lodY + y);
|
| + data->fIndices[i] = x * stride + y;
|
| + data->fIndices[i + 1] = x * stride + 1 + y;
|
| + data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
|
| + data->fIndices[i + 3] = data->fIndices[i];
|
| + data->fIndices[i + 4] = data->fIndices[i + 2];
|
| + data->fIndices[i + 5] = (x + 1) * stride + y;
|
| + }
|
| + v = SkScalarClampMax(v + 1.f / lodY, 1);
|
| + }
|
| + u = SkScalarClampMax(u + 1.f / lodX, 1);
|
| + }
|
| + return true;
|
| +
|
| +}
|
|
|