Loading libs/hwui/AmbientShadow.cpp +23 −20 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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; } Loading @@ -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; } } } Loading @@ -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); } } Loading Loading @@ -308,12 +312,11 @@ 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) // Calculate the normal , which is CCW 90 rotate to the delta. normal.x = - delta.y; normal.y = delta.x; } Loading libs/hwui/OpenGLRenderer.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading libs/hwui/ShadowTessellator.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -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 libs/hwui/ShadowTessellator.h +21 −0 Original line number Diff line number Diff line Loading @@ -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 Loading libs/hwui/SpotShadow.cpp +3 −24 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -407,32 +407,11 @@ 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 * Loading Loading
libs/hwui/AmbientShadow.cpp +23 −20 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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; } Loading @@ -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; } } } Loading @@ -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); } } Loading Loading @@ -308,12 +312,11 @@ 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) // Calculate the normal , which is CCW 90 rotate to the delta. normal.x = - delta.y; normal.y = delta.x; } Loading
libs/hwui/OpenGLRenderer.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
libs/hwui/ShadowTessellator.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -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
libs/hwui/ShadowTessellator.h +21 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
libs/hwui/SpotShadow.cpp +3 −24 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -407,32 +407,11 @@ 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 * Loading