Chromium Code Reviews| Index: src/core/SkPatch.cpp |
| diff --git a/src/core/SkPatch.cpp b/src/core/SkPatch.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8814addae37bb8d6630d8a53b12b1817b9651ba9 |
| --- /dev/null |
| +++ b/src/core/SkPatch.cpp |
| @@ -0,0 +1,385 @@ |
| +/* |
| + * 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 "SkPatch.h" |
| +#include "SkGr.h" |
| +#include <stdio.h> |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +CubicEvaluator::CubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d){ |
|
egdaniel
2014/07/21 21:16:03
There are already some of the eval and coeff calcu
dandov
2014/07/22 13:55:14
I removed the eval function since we already have
|
| + fPoints[0] = a; |
| + fPoints[1] = b; |
| + fPoints[2] = c; |
| + fPoints[3] = d; |
| + |
| + // save coefficients |
| + fCoefs[0].set(-a.x() + 3.0f*b.x() - 3.0f*c.x() + d.x(), |
| + -a.y() + 3.0f*b.y() - 3.0f*c.y() + d.y()); |
| + fCoefs[1].set(3.0f*a.x() - 6.0f*b.x() + 3.0f*c.x(), |
| + 3.0f*a.y() - 6.0f*b.y() + 3.0f*c.y()); |
| + fCoefs[2].set(-3.0f*a.x() + 3.0f*b.x(), |
| + -3.0f*a.y() + 3.0f*b.y()); |
| + fCoefs[3].set(a.x(), a.y()); |
| +} |
| + |
| +SkPoint CubicEvaluator::eval(SkScalar t){ |
| + return SkPoint::Make(fCoefs[0].x()*t*t*t + fCoefs[1].x()*t*t + fCoefs[2].x()*t + |
| + fCoefs[3].x(), |
| + fCoefs[0].y()*t*t*t + fCoefs[1].y()*t*t + fCoefs[2].y()*t + |
| + fCoefs[3].y()); |
| +} |
| + |
| +bool CubicEvaluator::hasNext(){ |
|
jvanverth1
2014/07/21 22:10:10
This and next() are simple enough, they could be p
dandov
2014/07/22 13:55:14
I substituted this ones with the operator* and ope
|
| + return fCurrent <= fMax; |
| +} |
| + |
| +SkPoint CubicEvaluator::next(){ |
| + SkPoint point = fFwDiff[0]; |
| + fFwDiff[0] += fFwDiff[1]; |
| + fFwDiff[1] += fFwDiff[2]; |
| + fFwDiff[2] += fFwDiff[3]; |
| + fCurrent++; |
| + |
| + return point; |
| +} |
| + |
| +void CubicEvaluator::reset(int res){ |
| + fRes = res; |
|
jvanverth1
2014/07/21 22:10:10
Indent
dandov
2014/07/22 13:55:14
Also is ok in my files, I don't know what happened
|
| + SkScalar h = 1.f/res; |
| + fCurrent = 0; |
| + fMax = res + 1; |
| + fFwDiff[0] = fCoefs[3]; |
| + SkScalar h2 = h*h; |
| + SkScalar h3 = h2*h; |
| + |
| + fFwDiff[3].set(6.f*fCoefs[0].x()*h3, 6.f*fCoefs[0].y()*h3); //6ah^3 |
| + fFwDiff[2].set(fFwDiff[3].x() + 2.f*fCoefs[1].x()*h2, //6ah^3 + 2bh^2 |
| + fFwDiff[3].y() + 2.f*fCoefs[1].y()*h2); |
| + fFwDiff[1].set(fCoefs[0].x()*h3 + fCoefs[1].x()*h2 + fCoefs[2].x()*h, //ah^3 + bh^2 + ch |
| + fCoefs[0].y()*h3 + fCoefs[1].y()*h2 + fCoefs[2].y()*h); |
| +} |
| + |
| +const SkPoint* CubicEvaluator::getPoints() { |
| + return fPoints; |
| +} |
| + |
| +const SkPoint* CubicEvaluator::getCoefs() { |
| + return fCoefs; |
| +} |
| + |
| +int CubicEvaluator::getResolution() { |
| + return fRes; |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +SkPatchMesh::SkPatchMesh() |
| + : fVertCount(0) |
| + , fIndexCount(0) |
| + , fData(NULL) |
| + , fIndices(NULL) |
| + , fUseColors(false) |
| + , fUseTexCoords(false) |
| + , fIntercalate(false) |
| + , fColorFormat(kSkColor_ColorFormat) { } |
| + |
| +void SkPatchMesh::init(int vertCount, int indexCount, SkColorFormat format, bool useTexCoords, |
| + bool intercalate) { |
| + |
| + this->reset(); |
| + |
| + fUseColors = format != kNoColor_ColorFormat; |
| + fUseTexCoords = useTexCoords; |
| + fIntercalate = intercalate; |
|
jvanverth1
2014/07/21 22:10:09
I don't know this term. Should this be fInterpolat
dandov
2014/07/22 13:55:14
I couldn't find a nice word to say that the data i
|
| + fColorFormat = format; |
| + |
| + int colorSize = 0; |
| + switch (format) { |
| + case SkPatchMesh::kNoColor_ColorFormat: |
| + colorSize = 0; |
| + break; |
| + case SkPatchMesh::kSkColor_ColorFormat: |
| + colorSize = sizeof(SkColor); |
| + break; |
| + //case SkPatchMesh::kSkPMColor_ColorFormat: |
| + // colorSize = sizeof(SkPMColor); |
| + // break; |
| + case SkPatchMesh::kGrColor_ColorFormat: |
| + colorSize = sizeof(GrColor); |
| + break; |
| + } |
| + |
| + fVertCount = vertCount; |
| + fIndexCount = indexCount; |
| + int totalBytes = fVertCount*sizeof(SkPoint) + (fUseColors ? fVertCount*colorSize : 0) |
| + + (fUseTexCoords*sizeof(SkPoint) ? fVertCount : 0); |
| + |
| + fData = SkNEW_ARRAY(uint8_t, totalBytes); |
| + fIndices = SkNEW_ARRAY(uint16_t, fIndexCount); |
| + |
| + if (fIntercalate) { |
| + //here the offset represents the offset inside an intercalated object; |
| + // if using colors then the offset is the size of the vertex |
| + fColorOffset = fUseColors ? sizeof(SkPoint) : 0; |
| + //if using colors then it is the size of the vertex + the size of the color |
| + //else is the size of the vertex only |
| + fTexOffset = fUseColors ? (fUseTexCoords ? sizeof(SkPoint)+colorSize : 0) |
| + : (fUseTexCoords ? sizeof(SkPoint) : 0); |
| + fDataSize = sizeof(SkPoint) + (fUseColors ? colorSize : 0) + |
| + (fUseTexCoords ? sizeof(SkPoint) : 0); |
| + } else { |
| + //here the offset is when the array of colors or uv's starts based on fData in bytes |
| + fColorOffset = fUseColors ? fVertCount*sizeof(SkPoint) : 0; |
| + fTexOffset = fUseTexCoords ? |
| + (fUseColors ? fVertCount*sizeof(SkPoint) + fVertCount*colorSize : |
| + fVertCount*sizeof(SkPoint)) |
| + : 0; |
| + fDataSize = 0; |
| + } |
| +} |
| + |
| +void SkPatchMesh::reset() { |
| + SkDELETE_ARRAY (fData); |
| + SkDELETE_ARRAY (fIndices); |
| + fVertCount = 0; |
| + fIndexCount = 0; |
| + fData = NULL; |
| + fIndices = NULL; |
| + fUseColors = false; |
| + fUseTexCoords = false; |
| + fIntercalate = false; |
| + fColorFormat = kSkColor_ColorFormat; |
| +} |
| + |
| +SkPatchMesh::~SkPatchMesh() { |
| + this->reset(); |
| +} |
| + |
| +const SkPoint* SkPatchMesh::getPoints() { |
| + if (fIntercalate) { |
| + return NULL; |
| + } else { |
| + return reinterpret_cast<SkPoint*>(fData); |
| + } |
| +} |
| + |
| +const uint16_t* SkPatchMesh::getIndices() { |
| + return fIndices; |
| +} |
| + |
| +const SkColor* SkPatchMesh::getColors() { |
| + if (fIntercalate || !fUseColors) { |
| + return NULL; |
| + } else { |
| + return reinterpret_cast<SkColor*>(fData + fColorOffset); |
| + } |
| +} |
| + |
| +const SkPoint* SkPatchMesh::getTexCoords() { |
| + if (fIntercalate || !fUseTexCoords) { |
| + return NULL; |
| + } else { |
| + return reinterpret_cast<SkPoint*>(fData + fTexOffset); |
| + } |
| +} |
| + |
| +const uint8_t* SkPatchMesh::getData() { |
| + return reinterpret_cast<uint8_t*>(fData); |
| +} |
| + |
| +SkPoint& SkPatchMesh::pointAt(int index) { |
| + if (fIntercalate) { |
| + index *= fDataSize; |
| + }else { |
| + index *= sizeof(SkPoint); |
| + } |
| + return *reinterpret_cast<SkPoint*>(fData + index); |
| +} |
| + |
| +uint32_t& SkPatchMesh::colorAt(int index) { |
| + SkASSERT(fUseColors); |
| + |
| + if (fIntercalate) { |
| + //getting the address of object with fDatasize in position index, move to color in that obj |
| + index = index * fDataSize + fColorOffset; |
| + } else { |
| + //starting in the colors array, move to the indexth color |
| + index = fColorOffset + index * sizeof(SkColor); |
| + } |
| + return *reinterpret_cast<SkColor*>(fData + index); |
| +} |
| + |
| +bool SkPatchMesh::setColorAt(int index, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { |
| + if (!fUseColors) { |
| + return false; |
| + } |
| + SkColor& colorRef = this->colorAt(index); |
| + |
| + switch (fColorFormat) { |
| + case SkPatchMesh::kSkColor_ColorFormat: |
| + colorRef = SkColorSetARGB(a,r,g,b); |
| + break; |
| + //case SkPatchMesh::kSkPMColor_ColorFormat: |
| + // colorSize = sizeof(SkPMColor); |
| + // break; |
| + case SkPatchMesh::kGrColor_ColorFormat: |
| + colorRef = SkColor2GrColor(SkPreMultiplyARGB(a,r,g,b));//GrColorPackRGBA(r,g,b,a); |
| + break; |
| + default: |
| + break; |
| + } |
| + return true; |
| +} |
| + |
| +SkPoint& SkPatchMesh::texCoordAt(int index) { |
| + SkASSERT(fUseTexCoords); |
| + |
| + if (fIntercalate) { |
| + index = index * fDataSize + fTexOffset; |
| + } else { |
| + index = fTexOffset + index * sizeof(SkPoint); |
| + } |
| + return *reinterpret_cast<SkPoint*>(fData + index); |
| +} |
| + |
| +void SkPatchMesh::setIndices(int index, uint16_t* indices, int size) { |
| + for (int i = 0; i < size; ++i) { |
| + fIndices[index + i] = indices[i]; |
| + } |
| +} |
| + |
| +int SkPatchMesh::getVertexCount() { |
| + return fVertCount; |
| +} |
| + |
| +int SkPatchMesh::getIndexCount() { |
| + return fIndexCount; |
| +} |
| + |
| +bool SkPatchMesh::useColors() { |
| + return fUseColors; |
| +} |
| + |
| +bool SkPatchMesh::useTexCoords() { |
| + return fUseTexCoords; |
| +} |
| + |
| +bool SkPatchMesh::isIntercalated() { |
| + return fIntercalate; |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +SkCoonsPatch::SkCoonsPatch(SkPoint points[12], SkColor (*colors)[4], int res) |
| + : fPoints(points) |
| + , fBottom(points[0], points[1], points[2], points[3]) |
| + , fTop(points[4], points[5], points[6], points[7]) |
| + , fLeft(points[0], points[8], points[9], points[4]) |
| + , fRight(points[3], points[10], points[11], points[7]) |
| + , fResX(res) |
| + , fResY(res) { |
| + fColors[0] = ((*colors)[0]); |
| + fColors[1] = ((*colors)[1]); |
| + fColors[2] = ((*colors)[2]); |
| + fColors[3] = ((*colors)[3]); |
| +} |
| + |
| +uint8_t bilinear(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 uint8_t(a * (1.f - ty) + b * ty); |
| +} |
| + |
| +// Each patch has the responsability to generate its mesh and the meshpatch handles the type of data |
| +// This method first initializes the mesh by providing the number of vertices, indices, the format |
| +// of the colors, if it needs texture coordinates and if the data should be intercalated. |
| +bool SkCoonsPatch::genMesh(SkPatchMesh* mesh, SkPatchMesh::SkColorFormat format, bool useTexCoords, |
| + bool intercalate) const { |
| + |
| + //setup how we are going to use the data based on the client preferences and how the patch |
| + //behaves, the derived class could just hardcode this parameters or take into account the |
| + //preferences of the caller like we do in this example |
| + if (!this->usesColors()) { |
| + format = SkPatchMesh::kNoColor_ColorFormat; |
| + } |
| + mesh->init((fResX + 1) * (fResY + 1), fResX * fResY * 6, format, |
| + this->usesTexCoords() && useTexCoords, intercalate); |
| + |
| + fBottom.reset(fResX); |
| + fTop.reset(fResX); |
| + |
| + SkScalar u = 0.0f; |
| + int stride = fResY+1; |
| + for (int x = 0; x <= fResX; x++) { |
| + SkPoint bottom = fBottom.next(), top = fTop.next(); |
| + fLeft.reset(fResY); |
| + fRight.reset(fResY); |
| + SkScalar v = 0.f; |
| + for (int y = 0; y <= fResY; y++) { |
| + int dataIndex = x*(fResX + 1) + y; |
| + |
| + SkPoint left = fLeft.next(), right = fRight.next(); |
| + |
| + SkPoint s0 = SkPoint::Make((1.0f - v)*bottom.x() + v*top.x(), |
| + (1.0f - v)*bottom.y() + v*top.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)*fBottom.getPoints()[0].x() |
| + + u*fBottom.getPoints()[3].x()) |
| + + v*((1.0f - u)*fTop.getPoints()[0].x() + u*fTop.getPoints()[3].x()), |
| + (1.0f - v)*((1.0f - u)*fBottom.getPoints()[0].y() |
| + + u*fBottom.getPoints()[3].y()) |
| + + v*((1.0f - u)*fTop.getPoints()[0].y() + u*fTop.getPoints()[3].y())); |
| + //always set the point |
| + mesh->pointAt(dataIndex) = s0 + s1 - s2; |
| + |
| + //check if we should set the color |
| + if(mesh->useColors()) { |
| + //these colors should be premultiplied for the bilerp but currently drawVertices |
| + //premultiplies them, so here they will be darker |
| + uint8_t a = bilinear(u, v, SkScalar(SkColorGetA(fColors[0])), |
| + SkScalar(SkColorGetA(fColors[1])), SkScalar(SkColorGetA(fColors[2])), |
| + SkScalar(SkColorGetA(fColors[3]))); |
| + uint8_t r = bilinear(u, v, SkScalar(SkColorGetR(fColors[0])), |
| + SkScalar(SkColorGetR(fColors[1])), SkScalar(SkColorGetR(fColors[2])), |
| + SkScalar(SkColorGetR(fColors[3]))); |
| + uint8_t g = bilinear(u, v, SkScalar(SkColorGetG(fColors[0])), |
| + SkScalar(SkColorGetG(fColors[1])), SkScalar(SkColorGetG(fColors[2])), |
| + SkScalar(SkColorGetG(fColors[3]))); |
| + uint8_t b = bilinear(u, v, SkScalar(SkColorGetB(fColors[0])), |
| + SkScalar(SkColorGetB(fColors[1])), SkScalar(SkColorGetB(fColors[2])), |
| + SkScalar(SkColorGetB(fColors[3]))); |
| + //mesh->colorAt(dataIndex) = SkColorSetARGB(a, r, g, b); |
| + mesh->setColorAt(dataIndex, r,g,b,a); |
| + } |
| + |
| + //check if we should set the texture coordinates |
| + if (mesh->useTexCoords()) { |
| + mesh->texCoordAt(dataIndex) = SkPoint::Make(u, v); |
| + } |
| + |
| + //set the indices |
| + if(x < fResX && y < fResY) { |
| + uint16_t indices[6]; |
| + int i = 6*(x*fResY + y); |
| + indices[0] = x*stride+y; |
| + indices[1] = x*stride+1+y; |
| + indices[2] = (x+1)*stride+1+y; |
| + indices[3] = indices[0]; |
| + indices[4] = indices[2]; |
| + indices[5] = (x+1)*stride+y; |
| + mesh->setIndices(i, indices, 6); |
| + } |
| + |
| + v+=1.f/fResY; |
| + } |
| + u+=1.f/fResX; |
| + } |
| + return true; |
| +} |