| Index: src/effects/gradients/SkMeshGradient.cpp
|
| diff --git a/src/effects/gradients/SkMeshGradient.cpp b/src/effects/gradients/SkMeshGradient.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3755a242a0cb0885bc111270afa43906f698d489
|
| --- /dev/null
|
| +++ b/src/effects/gradients/SkMeshGradient.cpp
|
| @@ -0,0 +1,236 @@
|
| +/*
|
| + * Copyright 2014 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "SkMeshGradient.h"
|
| +#include "SkPatchUtils.h"
|
| +
|
| +SkMeshGradient::SkMeshGradient(int rows, int cols)
|
| + : fRows(rows)
|
| + , fCols(cols)
|
| + , fCornerPts(NULL)
|
| + , fCornerColors(NULL)
|
| + , fHrzCtrlPts(NULL)
|
| + , fVrtCtrlPts(NULL) {
|
| + this->reset(fRows, fCols, NULL, NULL, NULL, NULL);
|
| +}
|
| +
|
| +SkMeshGradient::SkMeshGradient(int rows, int cols, const SkPoint* corners,
|
| + const SkPoint* hrzCtrlPts, const SkPoint* vrtCtrlPts,
|
| + const SkColor* colors)
|
| +: fRows(rows)
|
| +, fCols(cols)
|
| +, fCornerPts(NULL)
|
| +, fCornerColors(NULL)
|
| +, fHrzCtrlPts(NULL)
|
| +, fVrtCtrlPts(NULL) {
|
| + this->reset(fRows, fCols, corners, hrzCtrlPts, vrtCtrlPts, colors);
|
| +}
|
| +
|
| +SkMeshGradient::~SkMeshGradient() {
|
| + SkDELETE_ARRAY(fCornerPts);
|
| + SkDELETE_ARRAY(fCornerColors);
|
| + SkDELETE_ARRAY(fHrzCtrlPts);
|
| + SkDELETE_ARRAY(fVrtCtrlPts);
|
| +}
|
| +
|
| +bool SkMeshGradient::addPatch(int x, int y, const SkPoint ctrlPts[12], const SkColor colors[4]) {
|
| + // Check for the passed paramaters to be within the range of the mesh gradient dimensions.
|
| + if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1) {
|
| + return false;
|
| + }
|
| +
|
| + //setup corners and colors
|
| + int cornerPos = y * (fCols + 1) + x;
|
| + fCornerPts[cornerPos] = ctrlPts[SkPatch::kTopP0_CubicCtrlPts];
|
| + fCornerPts[cornerPos + 1] = ctrlPts[SkPatch::kTopP3_CubicCtrlPts];
|
| + fCornerPts[cornerPos + (fCols + 1)] = ctrlPts[SkPatch::kBottomP0_CubicCtrlPts];
|
| + fCornerPts[cornerPos + (fCols + 1) + 1] = ctrlPts[SkPatch::kBottomP3_CubicCtrlPts];
|
| +
|
| + fCornerColors[cornerPos] = colors[0];
|
| + fCornerColors[cornerPos + 1] = colors[1];
|
| + fCornerColors[cornerPos + (fCols + 1)] = colors[3];
|
| + fCornerColors[cornerPos + (fCols + 1) + 1] = colors[2];
|
| +
|
| + // set horizontal control points
|
| + int hrzPos = y * (fCols * 2) + (x * 2);
|
| + fHrzCtrlPts[hrzPos] = ctrlPts[SkPatch::kTopP1_CubicCtrlPts];
|
| + fHrzCtrlPts[hrzPos + 1] = ctrlPts[SkPatch::kTopP2_CubicCtrlPts];
|
| + fHrzCtrlPts[hrzPos + (fCols * 2)] = ctrlPts[SkPatch::kBottomP1_CubicCtrlPts];
|
| + fHrzCtrlPts[hrzPos + (fCols * 2) + 1] = ctrlPts[SkPatch::kBottomP2_CubicCtrlPts];
|
| +
|
| + int vrtPos = (y*2) * (fCols + 1) + x;
|
| + fVrtCtrlPts[vrtPos] = ctrlPts[SkPatch::kLeftP1_CubicCtrlPts];
|
| + fVrtCtrlPts[vrtPos + 1] = ctrlPts[SkPatch::kRightP1_CubicCtrlPts];
|
| + fVrtCtrlPts[vrtPos + (fCols + 1)] = ctrlPts[SkPatch::kLeftP2_CubicCtrlPts];
|
| + fVrtCtrlPts[vrtPos + (fCols + 1) + 1] = ctrlPts[SkPatch::kRightP2_CubicCtrlPts];
|
| + return true;
|
| +}
|
| +
|
| +bool SkMeshGradient::addPatch(int x, int y, const SkPatch& patch) {
|
| + return this->addPatch(x, y, patch.getControlPoints(), patch.getColors());
|
| +}
|
| +
|
| +void SkMeshGradient::getPatchAt(int x, int y, SkPatch* patch) const {
|
| +
|
| + if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1) {
|
| + return;
|
| + }
|
| +
|
| + if (NULL != patch) {
|
| + //set the patch by building the array of points and colors with the corresponding values.
|
| +
|
| + SkPoint ctrlPts[12];
|
| + SkColor colors[4];
|
| +
|
| + int cornerPos = y * (fCols + 1) + x;
|
| + ctrlPts[SkPatch::kTopP0_CubicCtrlPts] = fCornerPts[cornerPos];
|
| + ctrlPts[SkPatch::kTopP3_CubicCtrlPts] = fCornerPts[cornerPos + 1];
|
| + ctrlPts[SkPatch::kBottomP0_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1)];
|
| + ctrlPts[SkPatch::kBottomP3_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1) + 1];
|
| +
|
| + colors[0] = fCornerColors[cornerPos];
|
| + colors[1] = fCornerColors[cornerPos + 1];
|
| + colors[3] = fCornerColors[cornerPos + (fCols + 1)];
|
| + colors[2] = fCornerColors[cornerPos + (fCols + 1) + 1];
|
| +
|
| + int hrzPos = y * (fCols * 2) + (x * 2);
|
| + ctrlPts[SkPatch::kTopP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos];
|
| + ctrlPts[SkPatch::kTopP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + 1];
|
| + ctrlPts[SkPatch::kBottomP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2)];
|
| + ctrlPts[SkPatch::kBottomP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2) + 1];
|
| +
|
| + int vrtPos = (y*2) * (fCols + 1) + x;
|
| + ctrlPts[SkPatch::kLeftP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos];
|
| + ctrlPts[SkPatch::kRightP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos + 1];
|
| + ctrlPts[SkPatch::kLeftP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1)];
|
| + ctrlPts[SkPatch::kRightP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1) + 1];
|
| +
|
| + patch->reset(ctrlPts, colors);
|
| + }
|
| +}
|
| +
|
| +void SkMeshGradient::resize(int rows, int cols) {
|
| + //save old values
|
| + int oldCols = fCols;
|
| + int oldRows = fRows;
|
| +
|
| + fCols = cols;
|
| + fRows = rows;
|
| +
|
| + SkPoint* pts = fCornerPts;
|
| + SkColor* colors = fCornerColors;
|
| + SkPoint* hzrPts = fHrzCtrlPts;
|
| + SkPoint* vrtPts = fVrtCtrlPts;
|
| +
|
| + fCornerPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
|
| + fCornerColors = SkNEW_ARRAY(SkColor, (fRows + 1) * (fCols + 1));
|
| + fHrzCtrlPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * fCols * 2);
|
| + fVrtCtrlPts = SkNEW_ARRAY(SkPoint, fRows * 2 * (fCols + 1));
|
| +
|
| + //copy previous values that are still within the new range.
|
| + for (int y = 0; y < fRows; y++) {
|
| + for (int x = 0; x < fCols; x++) {
|
| + if (x >= oldCols || y >= oldRows) {
|
| + continue;
|
| + }
|
| +
|
| + int cornerPos = y * (fCols + 1) + x;
|
| + int oldCornerPos = y * (oldCols + 1) + x;
|
| + fCornerPts[cornerPos] = pts[oldCornerPos];
|
| + fCornerPts[cornerPos + 1] = pts[oldCornerPos + 1];
|
| + fCornerPts[cornerPos + (fCols + 1)] = pts[oldCornerPos + (oldCols + 1)];
|
| + fCornerPts[cornerPos + (fCols + 1) + 1] = pts[oldCornerPos + (oldCols + 1) + 1];
|
| + fCornerColors[cornerPos] = colors[oldCornerPos];
|
| + fCornerColors[cornerPos + 1] = colors[oldCornerPos + 1];
|
| + fCornerColors[cornerPos + (fCols + 1)] = colors[oldCornerPos + (oldCols + 1)];
|
| + fCornerColors[cornerPos + (fCols + 1) + 1] =
|
| + colors[oldCornerPos + (oldCols + 1) + 1];
|
| +
|
| + int hrzPos = y * (fCols * 2) + (x * 2);
|
| + int oldHrzPos = y * (oldCols * 2) + (x * 2);
|
| + fHrzCtrlPts[hrzPos] = hzrPts[oldHrzPos];
|
| + fHrzCtrlPts[hrzPos + 1] = hzrPts[oldHrzPos + 1];
|
| + fHrzCtrlPts[hrzPos + (fCols * 2)] = hzrPts[oldHrzPos + (oldCols * 2)];
|
| + fHrzCtrlPts[hrzPos + (fCols * 2) + 1] = hzrPts[oldHrzPos + (oldCols * 2) + 1];
|
| +
|
| + int vrtPos = (y*2) * (fCols + 1) + x;
|
| + int oldVrtPos = (y*2) * (oldCols + 1) + x;
|
| + fVrtCtrlPts[vrtPos] = vrtPts[oldVrtPos];
|
| + fVrtCtrlPts[vrtPos + 1] = vrtPts[oldVrtPos + 1];
|
| + fVrtCtrlPts[vrtPos + (fCols + 1)] = vrtPts[oldVrtPos + (oldCols + 1)];
|
| + fVrtCtrlPts[vrtPos + (fCols + 1) + 1] = vrtPts[oldVrtPos + (oldCols + 1) + 1];
|
| + }
|
| + }
|
| +
|
| + //delete old copies.
|
| + SkDELETE_ARRAY(pts);
|
| + SkDELETE_ARRAY(colors);
|
| + SkDELETE_ARRAY(hzrPts);
|
| + SkDELETE_ARRAY(vrtPts);
|
| +}
|
| +
|
| +void SkMeshGradient::reset(int rows, int cols, const SkPoint* corners, const SkPoint* hrzCtrlPts,
|
| + const SkPoint* vrtCtrlPts, const SkColor* colors) {
|
| + SkDELETE_ARRAY(fCornerPts);
|
| + SkDELETE_ARRAY(fCornerColors);
|
| + SkDELETE_ARRAY(fHrzCtrlPts);
|
| + SkDELETE_ARRAY(fVrtCtrlPts);
|
| +
|
| + fCols = cols;
|
| + fRows = rows;
|
| +
|
| + fCornerPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
|
| + fCornerColors = SkNEW_ARRAY(SkColor, (fRows + 1) * (fCols + 1));
|
| + fHrzCtrlPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * fCols * 2);
|
| + fVrtCtrlPts = SkNEW_ARRAY(SkPoint, fRows * 2 * (fCols + 1));
|
| +
|
| + if (NULL != corners) {
|
| + memcpy(fCornerPts, corners, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
|
| + }
|
| + if (NULL != colors) {
|
| + memcpy(fCornerColors, colors, (fRows + 1) * (fCols + 1) * sizeof(SkColor));
|
| + }
|
| + if (NULL != hrzCtrlPts) {
|
| + memcpy(fHrzCtrlPts, hrzCtrlPts, (fRows + 1) * fCols * 2 * sizeof(SkPoint));
|
| + }
|
| + if (NULL != vrtCtrlPts) {
|
| + memcpy(fVrtCtrlPts, vrtCtrlPts, fRows * 2 * (fCols + 1) * sizeof(SkPoint));
|
| + }
|
| +}
|
| +
|
| +void SkMeshGradient::draw(SkCanvas* canvas, SkPaint& paint) {
|
| + int* maxCols = SkNEW_ARRAY(int, fCols);
|
| + int* maxRows = SkNEW_ARRAY(int, fRows);
|
| + memset(maxCols, 0, fCols*sizeof(int));
|
| + memset(maxRows, 0, fRows*sizeof(int));
|
| +
|
| + // Get the maximum level of detail per axis for each row and column
|
| + for (int y = 0; y < fRows; y++) {
|
| + for (int x = 0; x < fCols; x++) {
|
| + SkPatch patch;
|
| + this->getPatchAt(x, y, &patch);
|
| + SkMatrix matrix = canvas->getTotalMatrix();
|
| + SkISize lod = SkPatchUtils::GetLevelOfDetail(patch, &matrix);
|
| + maxCols[x] = SkMax32(maxCols[x], lod.width());
|
| + maxRows[y] = SkMax32(maxRows[y], lod.height());
|
| + }
|
| + }
|
| + // Draw the patches by generating their mesh with the maximum level of detail per axis.
|
| + for (int y = 0; y < fRows; y++) {
|
| + for (int x = 0; x < fCols; x++) {
|
| + SkPatch patch;
|
| + this->getPatchAt(x, y, &patch);
|
| + SkPatch::VertexData data;
|
| + patch.getVertexData(&data, maxCols[x], maxRows[y]);
|
| + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount,
|
| + data.fPoints, data.fTexCoords, data.fColors, NULL,
|
| + data.fIndices, data.fIndexCount, paint);
|
| + }
|
| + }
|
| + SkDELETE_ARRAY(maxCols);
|
| + SkDELETE_ARRAY(maxRows);
|
| +}
|
|
|