diff options
author | ztenghui <ztenghui@google.com> | 2014-04-29 16:21:51 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-04-29 16:21:51 +0000 |
commit | 0d575b084fe5a691c2a99163515de0dc54f66e18 (patch) | |
tree | e07fac82ad6a2fbf805d62877865e2a84c07dee6 /libs | |
parent | ecdc6fdb64a41dd3bd5867308cb0c8a5b941146f (diff) | |
parent | 2e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4 (diff) | |
download | frameworks_base-0d575b084fe5a691c2a99163515de0dc54f66e18.zip frameworks_base-0d575b084fe5a691c2a99163515de0dc54f66e18.tar.gz frameworks_base-0d575b084fe5a691c2a99163515de0dc54f66e18.tar.bz2 |
Merge "Make sure the theta is correctly represented and incoming polygon is CW for shadow."
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/AmbientShadow.cpp | 43 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/ShadowTessellator.cpp | 62 | ||||
-rw-r--r-- | libs/hwui/ShadowTessellator.h | 21 | ||||
-rw-r--r-- | libs/hwui/SpotShadow.cpp | 27 | ||||
-rw-r--r-- | libs/hwui/SpotShadow.h | 1 |
6 files changed, 113 insertions, 45 deletions
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index 904ec8c..c1af5f5 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -147,6 +147,8 @@ VertexBufferMode AmbientShadow::createAmbientShadow(bool isCasterOpaque, /** * Generate an array of rays' direction vectors. + * To make sure the vertices generated are clockwise, the directions are from PI + * to -PI. * * @param rays The number of rays shooting out from the centroid. * @param vertices Vertices of the polygon. @@ -160,8 +162,8 @@ void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertic if (vertexCount * 2 > rays) { float deltaAngle = 2 * M_PI / rays; for (int i = 0; i < rays; i++) { - dir[i].x = sinf(deltaAngle * i); - dir[i].y = cosf(deltaAngle * i); + dir[i].x = cosf(M_PI - deltaAngle * i); + dir[i].y = sinf(M_PI - deltaAngle * i); } return; } @@ -178,50 +180,52 @@ void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertic // Since the incoming polygon is clockwise, we can find the dip to identify // the minimal theta. float polyThetas[vertexCount]; - int minimalPolyThetaIndex = 0; + int maxPolyThetaIndex = 0; for (int i = 0; i < vertexCount; i++) { polyThetas[i] = atan2(vertices[i].y - centroid3d.y, vertices[i].x - centroid3d.x); - if (i > 0 && polyThetas[i] < polyThetas[i - 1]) { - minimalPolyThetaIndex = i; + if (i > 0 && polyThetas[i] > polyThetas[i - 1]) { + maxPolyThetaIndex = i; } } - int polyThetaIndex = minimalPolyThetaIndex; - float polyTheta = polyThetas[minimalPolyThetaIndex]; + // Both poly's thetas and uniform thetas are in decrease order(clockwise) + // from PI to -PI. + int polyThetaIndex = maxPolyThetaIndex; + float polyTheta = polyThetas[maxPolyThetaIndex]; int uniformThetaIndex = 0; - float uniformTheta = - M_PI; + float uniformTheta = M_PI; for (int i = 0; i < rays; i++) { // Compare both thetas and pick the smaller one and move on. bool hasThetaCollision = abs(polyTheta - uniformTheta) < MINIMAL_DELTA_THETA; - if (polyTheta < uniformTheta || hasThetaCollision) { + if (polyTheta > uniformTheta || hasThetaCollision) { if (hasThetaCollision) { // Shift the uniformTheta to middle way between current polyTheta // and next uniform theta. The next uniform theta can wrap around // to exactly PI safely here. // Note that neither polyTheta nor uniformTheta can be FLT_MAX // due to the hasThetaCollision is true. - uniformTheta = (polyTheta + deltaAngle * (uniformThetaIndex + 1) - M_PI) / 2; + uniformTheta = (polyTheta + M_PI - deltaAngle * (uniformThetaIndex + 1)) / 2; #if DEBUG_SHADOW ALOGD("Shifted uniformTheta to %f", uniformTheta); #endif } rayThetas[i] = polyTheta; polyThetaIndex = (polyThetaIndex + 1) % vertexCount; - if (polyThetaIndex != minimalPolyThetaIndex) { + if (polyThetaIndex != maxPolyThetaIndex) { polyTheta = polyThetas[polyThetaIndex]; } else { // out of poly points. - polyTheta = FLT_MAX; + polyTheta = - FLT_MAX; } } else { rayThetas[i] = uniformTheta; uniformThetaIndex++; if (uniformThetaIndex < uniformRayCount) { - uniformTheta = deltaAngle * uniformThetaIndex - M_PI; + uniformTheta = M_PI - deltaAngle * uniformThetaIndex; } else { // out of uniform points. - uniformTheta = FLT_MAX; + uniformTheta = - FLT_MAX; } } } @@ -232,8 +236,8 @@ void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertic #endif // TODO: Fix the intersection precision problem and remvoe the delta added // here. - dir[i].x = sinf(rayThetas[i] + MINIMAL_DELTA_THETA); - dir[i].y = cosf(rayThetas[i] + MINIMAL_DELTA_THETA); + dir[i].x = cosf(rayThetas[i] + MINIMAL_DELTA_THETA); + dir[i].y = sinf(rayThetas[i] + MINIMAL_DELTA_THETA); } } @@ -308,13 +312,12 @@ void AmbientShadow::calculateNormal(int rays, int currentRayIndex, Vector2 p1 = dir[preIndex] * rayDist[preIndex]; Vector2 p2 = dir[postIndex] * rayDist[postIndex]; - // Now the V (deltaX, deltaY) is the vector going CW around the poly. + // Now the rays are going CW around the poly. Vector2 delta = p2 - p1; if (delta.length() != 0) { delta.normalize(); - // Calculate the normal , which is CCW 90 rotate to the V. - // 90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z) - normal.x = -delta.y; + // Calculate the normal , which is CCW 90 rotate to the delta. + normal.x = - delta.y; normal.y = delta.x; } } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 1f5389c..4569152 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -3230,6 +3230,10 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThresholdSquared, casterVertices2d); + if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) { + ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(), + casterVertices2d.size()); + } if (casterVertices2d.size() == 0) { // empty caster polygon computed from path diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index 4d0edfb..ee60a63 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -169,5 +169,67 @@ Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) { return centroid; } +/** + * Test whether the polygon is order in clockwise. + * + * @param polygon the polygon as a Vector2 array + * @param len the number of points of the polygon + */ +bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) { + double sum = 0; + double p1x = polygon[len - 1].x; + double p1y = polygon[len - 1].y; + for (int i = 0; i < len; i++) { + + double p2x = polygon[i].x; + double p2y = polygon[i].y; + sum += p1x * p2y - p2x * p1y; + p1x = p2x; + p1y = p2y; + } + return sum < 0; +} + +bool ShadowTessellator::isClockwisePath(const SkPath& path) { + SkPath::Iter iter(path, false); + SkPoint pts[4]; + SkPath::Verb v; + + Vector<Vector2> arrayForDirection; + while (SkPath::kDone_Verb != (v = iter.next(pts))) { + switch (v) { + case SkPath::kMove_Verb: + arrayForDirection.add(Vector2(pts[0].x(), pts[0].y())); + break; + case SkPath::kLine_Verb: + arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + break; + case SkPath::kQuad_Verb: + arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + arrayForDirection.add(Vector2(pts[2].x(), pts[2].y())); + break; + case SkPath::kCubic_Verb: + arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + arrayForDirection.add(Vector2(pts[2].x(), pts[2].y())); + arrayForDirection.add(Vector2(pts[3].x(), pts[3].y())); + break; + default: + break; + } + } + + return isClockwise(arrayForDirection.array(), arrayForDirection.size()); +} + +void ShadowTessellator::reverseVertexArray(Vertex* polygon, int len) { + int n = len / 2; + for (int i = 0; i < n; i++) { + Vertex tmp = polygon[i]; + int k = len - 1 - i; + polygon[i] = polygon[k]; + polygon[k] = tmp; + } +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h index 05370dd..64e69bc 100644 --- a/libs/hwui/ShadowTessellator.h +++ b/libs/hwui/ShadowTessellator.h @@ -80,6 +80,27 @@ public: static void generateShadowIndices(uint16_t* shadowIndices); static Vector2 centroid2d(const Vector2* poly, int polyLength); + + static bool isClockwise(const Vector2* polygon, int len); + + /** + * Determine whether the path is clockwise, using the control points. + * + * TODO: Given the skia is using inverted Y coordinate, shadow system needs + * to convert to the same coordinate to avoid the extra reverse. + * + * @param path The path to be examined. + */ + static bool isClockwisePath(const SkPath &path); + + /** + * Reverse the vertex array. + * + * @param polygon The vertex array to be reversed. + * @param len The length of the vertex array. + */ + static void reverseVertexArray(Vertex* polygon, int len); + }; // ShadowTessellator }; // namespace uirenderer diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 5fa0ba5..3ebe7b4 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -174,10 +174,10 @@ bool SpotShadow::ccw(double ax, double ay, double bx, double by, int SpotShadow::intersection(const Vector2* poly1, int poly1Length, Vector2* poly2, int poly2Length) { #if DEBUG_SHADOW - if (!isClockwise(poly1, poly1Length)) { + if (!ShadowTessellator::isClockwise(poly1, poly1Length)) { ALOGW("Poly1 is not clockwise! Intersection is wrong!"); } - if (!isClockwise(poly2, poly2Length)) { + if (!ShadowTessellator::isClockwise(poly2, poly2Length)) { ALOGW("Poly2 is not clockwise! Intersection is wrong!"); } #endif @@ -407,33 +407,12 @@ void SpotShadow::makeClockwise(Vector2* polygon, int len) { if (polygon == 0 || len == 0) { return; } - if (!isClockwise(polygon, len)) { + if (!ShadowTessellator::isClockwise(polygon, len)) { reverse(polygon, len); } } /** - * Test whether the polygon is order in clockwise. - * - * @param polygon the polygon as a Vector2 array - * @param len the number of points of the polygon - */ -bool SpotShadow::isClockwise(const Vector2* polygon, int len) { - double sum = 0; - double p1x = polygon[len - 1].x; - double p1y = polygon[len - 1].y; - for (int i = 0; i < len; i++) { - - double p2x = polygon[i].x; - double p2y = polygon[i].y; - sum += p1x * p2y - p2x * p1y; - p1x = p2x; - p1y = p2y; - } - return sum < 0; -} - -/** * Reverse the polygon * * @param polygon the polygon as a Vector2 array diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h index 599d37e..fb3e6d5 100644 --- a/libs/hwui/SpotShadow.h +++ b/libs/hwui/SpotShadow.h @@ -56,7 +56,6 @@ private: static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len); static void makeClockwise(Vector2* polygon, int len); - static bool isClockwise(const Vector2* polygon, int len); static void reverse(Vector2* polygon, int len); static inline bool lineIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, Vector2& ret); |