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; |
+} |