summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorztenghui <ztenghui@google.com>2014-04-29 16:21:51 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-04-29 16:21:51 +0000
commit0d575b084fe5a691c2a99163515de0dc54f66e18 (patch)
treee07fac82ad6a2fbf805d62877865e2a84c07dee6 /libs
parentecdc6fdb64a41dd3bd5867308cb0c8a5b941146f (diff)
parent2e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4 (diff)
downloadframeworks_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.cpp43
-rw-r--r--libs/hwui/OpenGLRenderer.cpp4
-rw-r--r--libs/hwui/ShadowTessellator.cpp62
-rw-r--r--libs/hwui/ShadowTessellator.h21
-rw-r--r--libs/hwui/SpotShadow.cpp27
-rw-r--r--libs/hwui/SpotShadow.h1
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);