summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libs/hwui/AmbientShadow.cpp6
-rw-r--r--libs/hwui/SpotShadow.cpp910
-rw-r--r--libs/hwui/SpotShadow.h34
-rw-r--r--libs/hwui/Vector.h4
4 files changed, 303 insertions, 651 deletions
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index cb3a002..21c869b 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -326,9 +326,9 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
shadowVertexBuffer.updateVertexCount(vertexBufferIndex);
shadowVertexBuffer.updateIndexCount(indexBufferIndex);
- ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Vertex Buffer");
- ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Index Buffer");
- ShadowTessellator::checkOverflow(umbraIndex, totalUmbraCount, "Umbra Buffer");
+ ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Ambient Vertex Buffer");
+ ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Ambient Index Buffer");
+ ShadowTessellator::checkOverflow(umbraIndex, totalUmbraCount, "Ambient Umbra Buffer");
#if DEBUG_SHADOW
for (int i = 0; i < vertexBufferIndex; i++) {
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index df28ae8..e8f1b9a 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -618,68 +618,6 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCente
}
/**
- * Converts a polygon specified with CW vertices into an array of distance-from-centroid values.
- *
- * Returns false in error conditions
- *
- * @param poly Array of vertices. Note that these *must* be CW.
- * @param polyLength The number of vertices in the polygon.
- * @param polyCentroid The centroid of the polygon, from which rays will be cast
- * @param rayDist The output array for the calculated distances, must be SHADOW_RAY_COUNT in size
- */
-bool convertPolyToRayDist(const Vector2* poly, int polyLength, const Vector2& polyCentroid,
- float* rayDist) {
- const int rays = SHADOW_RAY_COUNT;
- const float step = M_PI * 2 / rays;
-
- const Vector2* lastVertex = &(poly[polyLength - 1]);
- float startAngle = angle(*lastVertex, polyCentroid);
-
- // Start with the ray that's closest to and less than startAngle
- int rayIndex = floor((startAngle - EPSILON) / step);
- rayIndex = (rayIndex + rays) % rays; // ensure positive
-
- for (int polyIndex = 0; polyIndex < polyLength; polyIndex++) {
- /*
- * For a given pair of vertices on the polygon, poly[i-1] and poly[i], the rays that
- * intersect these will be those that are between the two angles from the centroid that the
- * vertices define.
- *
- * Because the polygon vertices are stored clockwise, the closest ray with an angle
- * *smaller* than that defined by angle(poly[i], centroid) will be the first ray that does
- * not intersect with poly[i-1], poly[i].
- */
- float currentAngle = angle(poly[polyIndex], polyCentroid);
-
- // find first ray that will not intersect the line segment poly[i-1] & poly[i]
- int firstRayIndexOnNextSegment = floor((currentAngle - EPSILON) / step);
- firstRayIndexOnNextSegment = (firstRayIndexOnNextSegment + rays) % rays; // ensure positive
-
- // Iterate through all rays that intersect with poly[i-1], poly[i] line segment.
- // This may be 0 rays.
- while (rayIndex != firstRayIndexOnNextSegment) {
- float distanceToIntersect = rayIntersectPoints(polyCentroid,
- cos(rayIndex * step),
- sin(rayIndex * step),
- *lastVertex, poly[polyIndex]);
- if (distanceToIntersect < 0) {
-#if DEBUG_SHADOW
- ALOGW("ERROR: convertPolyToRayDist failed");
-#endif
- return false; // error case, abort
- }
-
- rayDist[rayIndex] = distanceToIntersect;
-
- rayIndex = (rayIndex - 1 + rays) % rays;
- }
- lastVertex = &poly[polyIndex];
- }
-
- return true;
-}
-
-/**
* This is only for experimental purpose.
* After intersections are calculated, we could smooth the polygon if needed.
* So far, we don't think it is more appealing yet.
@@ -700,490 +638,223 @@ void SpotShadow::smoothPolygon(int level, int rays, float* rayDist) {
}
}
-/**
- * Generate a array of the angleData for either umbra or penumbra vertices.
- *
- * This array will be merged and used to guide where to shoot the rays, in clockwise order.
- *
- * @param angleDataList The result array of angle data.
- *
- * @return int The maximum angle's index in the array.
- */
-int SpotShadow::setupAngleList(VertexAngleData* angleDataList,
- int polyLength, const Vector2* polygon, const Vector2& centroid,
- bool isPenumbra, const char* name) {
- float maxAngle = FLT_MIN;
- int maxAngleIndex = 0;
- for (int i = 0; i < polyLength; i++) {
- float currentAngle = angle(polygon[i], centroid);
- if (currentAngle > maxAngle) {
- maxAngle = currentAngle;
- maxAngleIndex = i;
- }
- angleDataList[i].set(currentAngle, isPenumbra, i);
-#if DEBUG_SHADOW
- ALOGD("%s AngleList i %d %f", name, i, currentAngle);
-#endif
- }
- return maxAngleIndex;
-}
+// Index pair is meant for storing the tessellation information for the penumbra
+// area. One index must come from exterior tangent of the circles, the other one
+// must come from the interior tangent of the circles.
+struct IndexPair {
+ int outerIndex;
+ int innerIndex;
+};
-/**
- * Make sure the polygons are indeed in clockwise order.
- *
- * Possible reasons to return false: 1. The input polygon is not setup properly. 2. The hull
- * algorithm is not able to generate it properly.
- *
- * Anyway, since the algorithm depends on the clockwise, when these kind of unexpected error
- * situation is found, we need to detect it and early return without corrupting the memory.
- *
- * @return bool True if the angle list is actually from big to small.
- */
-bool SpotShadow::checkClockwise(int indexOfMaxAngle, int listLength, VertexAngleData* angleList,
- const char* name) {
- int currentIndex = indexOfMaxAngle;
-#if DEBUG_SHADOW
- ALOGD("max index %d", currentIndex);
-#endif
- for (int i = 0; i < listLength - 1; i++) {
- // TODO: Cache the last angle.
- float currentAngle = angleList[currentIndex].mAngle;
- float nextAngle = angleList[(currentIndex + 1) % listLength].mAngle;
- if (currentAngle < nextAngle) {
-#if DEBUG_SHADOW
- ALOGE("%s, is not CW, at index %d", name, currentIndex);
-#endif
- return false;
+// For one penumbra vertex, find the cloest umbra vertex and return its index.
+inline int getClosestUmbraIndex(const Vector2& pivot, const Vector2* polygon, int polygonLength) {
+ float minLengthSquared = FLT_MAX;
+ int resultIndex = -1;
+ bool hasDecreased = false;
+ // Starting with some negative offset, assuming both umbra and penumbra are starting
+ // at the same angle, this can help to find the result faster.
+ // Normally, loop 3 times, we can find the closest point.
+ int offset = polygonLength - 2;
+ for (int i = 0; i < polygonLength; i++) {
+ int currentIndex = (i + offset) % polygonLength;
+ float currentLengthSquared = (pivot - polygon[currentIndex]).lengthSquared();
+ if (currentLengthSquared < minLengthSquared) {
+ if (minLengthSquared != FLT_MAX) {
+ hasDecreased = true;
+ }
+ minLengthSquared = currentLengthSquared;
+ resultIndex = currentIndex;
+ } else if (currentLengthSquared > minLengthSquared && hasDecreased) {
+ // Early break b/c we have found the closet one and now the length
+ // is increasing again.
+ break;
}
- currentIndex = (currentIndex + 1) % listLength;
}
- return true;
+ if(resultIndex == -1) {
+ ALOGE("resultIndex is -1, the polygon must be invalid!");
+ resultIndex = 0;
+ }
+ return resultIndex;
}
-/**
- * Check the polygon is clockwise.
- *
- * @return bool True is the polygon is clockwise.
- */
-bool SpotShadow::checkPolyClockwise(int polyAngleLength, int maxPolyAngleIndex,
- const float* polyAngleList) {
- bool isPolyCW = true;
- // Starting from maxPolyAngleIndex , check around to make sure angle decrease.
- for (int i = 0; i < polyAngleLength - 1; i++) {
- float currentAngle = polyAngleList[(i + maxPolyAngleIndex) % polyAngleLength];
- float nextAngle = polyAngleList[(i + maxPolyAngleIndex + 1) % polyAngleLength];
- if (currentAngle < nextAngle) {
- isPolyCW = false;
- }
+inline bool sameDirections(bool isPositiveCross, float a, float b) {
+ if (isPositiveCross) {
+ return a >= 0 && b >= 0;
+ } else {
+ return a <= 0 && b <= 0;
}
- return isPolyCW;
}
-/**
- * Given the sorted array of all the vertices angle data, calculate for each
- * vertices, the offset value to array element which represent the start edge
- * of the polygon we need to shoot the ray at.
- *
- * TODO: Calculate this for umbra and penumbra in one loop using one single array.
- *
- * @param distances The result of the array distance counter.
- */
-void SpotShadow::calculateDistanceCounter(bool needsOffsetToUmbra, int angleLength,
- const VertexAngleData* allVerticesAngleData, int* distances) {
-
- bool firstVertexIsPenumbra = allVerticesAngleData[0].mIsPenumbra;
- // If we want distance to inner, then we just set to 0 when we see inner.
- bool needsSearch = needsOffsetToUmbra ? firstVertexIsPenumbra : !firstVertexIsPenumbra;
- int distanceCounter = 0;
- if (needsSearch) {
- int foundIndex = -1;
- for (int i = (angleLength - 1); i >= 0; i--) {
- bool currentIsOuter = allVerticesAngleData[i].mIsPenumbra;
- // If we need distance to inner, then we need to find a inner vertex.
- if (currentIsOuter != firstVertexIsPenumbra) {
- foundIndex = i;
- break;
- }
- }
- LOG_ALWAYS_FATAL_IF(foundIndex == -1, "Wrong index found, means either"
- " umbra or penumbra's length is 0");
- distanceCounter = angleLength - foundIndex;
- }
+// Find the right polygon edge to shoot the ray at.
+inline int findPolyIndex(bool isPositiveCross, int startPolyIndex, const Vector2& umbraDir,
+ const Vector2* polyToCentroid, int polyLength) {
+ // Make sure we loop with a bound.
+ for (int i = 0; i < polyLength; i++) {
+ int currentIndex = (i + startPolyIndex) % polyLength;
+ const Vector2& currentToCentroid = polyToCentroid[currentIndex];
+ const Vector2& nextToCentroid = polyToCentroid[(currentIndex + 1) % polyLength];
+
+ float currentCrossUmbra = currentToCentroid.cross(umbraDir);
+ float umbraCrossNext = umbraDir.cross(nextToCentroid);
+ if (sameDirections(isPositiveCross, currentCrossUmbra, umbraCrossNext)) {
#if DEBUG_SHADOW
- ALOGD("distances[0] is %d", distanceCounter);
+ ALOGD("findPolyIndex loop %d times , index %d", i, currentIndex );
#endif
-
- distances[0] = distanceCounter; // means never see a target poly
-
- for (int i = 1; i < angleLength; i++) {
- bool firstVertexIsPenumbra = allVerticesAngleData[i].mIsPenumbra;
- // When we needs for distance for each outer vertex to inner, then we
- // increase the distance when seeing outer vertices. Otherwise, we clear
- // to 0.
- bool needsIncrement = needsOffsetToUmbra ? firstVertexIsPenumbra : !firstVertexIsPenumbra;
- // If counter is not -1, that means we have seen an other polygon's vertex.
- if (needsIncrement && distanceCounter != -1) {
- distanceCounter++;
- } else {
- distanceCounter = 0;
+ return currentIndex;
}
- distances[i] = distanceCounter;
}
+ LOG_ALWAYS_FATAL("Can't find the right polygon's edge from startPolyIndex %d", startPolyIndex);
+ return -1;
}
-/**
- * Given umbra and penumbra angle data list, merge them by sorting the angle
- * from the biggest to smallest.
- *
- * @param allVerticesAngleData The result array of merged angle data.
- */
-void SpotShadow::mergeAngleList(int maxUmbraAngleIndex, int maxPenumbraAngleIndex,
- const VertexAngleData* umbraAngleList, int umbraLength,
- const VertexAngleData* penumbraAngleList, int penumbraLength,
- VertexAngleData* allVerticesAngleData) {
-
- int totalRayNumber = umbraLength + penumbraLength;
- int umbraIndex = maxUmbraAngleIndex;
- int penumbraIndex = maxPenumbraAngleIndex;
-
- float currentUmbraAngle = umbraAngleList[umbraIndex].mAngle;
- float currentPenumbraAngle = penumbraAngleList[penumbraIndex].mAngle;
-
- // TODO: Clean this up using a while loop with 2 iterators.
- for (int i = 0; i < totalRayNumber; i++) {
- if (currentUmbraAngle > currentPenumbraAngle) {
- allVerticesAngleData[i] = umbraAngleList[umbraIndex];
- umbraIndex = (umbraIndex + 1) % umbraLength;
-
- // If umbraIndex round back, that means we are running out of
- // umbra vertices to merge, so just copy all the penumbra leftover.
- // Otherwise, we update the currentUmbraAngle.
- if (umbraIndex != maxUmbraAngleIndex) {
- currentUmbraAngle = umbraAngleList[umbraIndex].mAngle;
- } else {
- for (int j = i + 1; j < totalRayNumber; j++) {
- allVerticesAngleData[j] = penumbraAngleList[penumbraIndex];
- penumbraIndex = (penumbraIndex + 1) % penumbraLength;
- }
+// Generate the index pair for penumbra / umbra vertices, and more penumbra vertices
+// if needed.
+inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbraLength,
+ const Vector2* umbra, int umbraLength, Vector2* newPenumbra, int& newPenumbraIndex,
+ IndexPair* verticesPair, int& verticesPairIndex) {
+ // In order to keep everything in just one loop, we need to pre-compute the
+ // closest umbra vertex for the last penumbra vertex.
+ int previousClosestUmbraIndex = getClosestUmbraIndex(penumbra[penumbraLength - 1],
+ umbra, umbraLength);
+ for (int i = 0; i < penumbraLength; i++) {
+ const Vector2& currentPenumbraVertex = penumbra[i];
+ // For current penumbra vertex, starting from previousClosestUmbraIndex,
+ // then check the next one until the distance increase.
+ // The last one before the increase is the umbra vertex we need to pair with.
+ int currentUmbraIndex = previousClosestUmbraIndex;
+ float currentLengthSquared = (currentPenumbraVertex - umbra[currentUmbraIndex]).lengthSquared();
+ int currentClosestUmbraIndex = -1;
+ int indexDelta = 0;
+ for (int j = 1; j < umbraLength; j++) {
+ int newUmbraIndex = (previousClosestUmbraIndex + j) % umbraLength;
+ float newLengthSquared = (currentPenumbraVertex - umbra[newUmbraIndex]).lengthSquared();
+ if (newLengthSquared > currentLengthSquared) {
+ currentClosestUmbraIndex = (previousClosestUmbraIndex + j - 1) % umbraLength;
break;
- }
- } else {
- allVerticesAngleData[i] = penumbraAngleList[penumbraIndex];
- penumbraIndex = (penumbraIndex + 1) % penumbraLength;
- // If penumbraIndex round back, that means we are running out of
- // penumbra vertices to merge, so just copy all the umbra leftover.
- // Otherwise, we update the currentPenumbraAngle.
- if (penumbraIndex != maxPenumbraAngleIndex) {
- currentPenumbraAngle = penumbraAngleList[penumbraIndex].mAngle;
} else {
- for (int j = i + 1; j < totalRayNumber; j++) {
- allVerticesAngleData[j] = umbraAngleList[umbraIndex];
- umbraIndex = (umbraIndex + 1) % umbraLength;
- }
- break;
+ currentLengthSquared = newLengthSquared;
+ indexDelta++;
}
}
- }
-}
-
-#if DEBUG_SHADOW
-/**
- * DEBUG ONLY: Verify all the offset compuation is correctly done by examining
- * each vertex and its neighbor.
- */
-static void verifyDistanceCounter(const VertexAngleData* allVerticesAngleData,
- const int* distances, int angleLength, const char* name) {
- int currentDistance = distances[0];
- for (int i = 1; i < angleLength; i++) {
- if (distances[i] != INT_MIN) {
- if (!((currentDistance + 1) == distances[i]
- || distances[i] == 0)) {
- ALOGE("Wrong distance found at i %d name %s", i, name);
+ LOG_ALWAYS_FATAL_IF(currentClosestUmbraIndex == -1, "Can't find a closet umbra vertext at all");
+
+ if (indexDelta > 1) {
+ // For those umbra don't have penumbra, generate new penumbra vertices by interpolation.
+ //
+ // Assuming Pi for penumbra vertices, and Ui for umbra vertices.
+ // In the case like below P1 paired with U1 and P2 paired with U5.
+ // U2 to U4 are unpaired umbra vertices.
+ //
+ // P1 P2
+ // | |
+ // U1 U2 U3 U4 U5
+ //
+ // We will need to generate 3 more penumbra vertices P1.1, P1.2, P1.3
+ // to pair with U2 to U4.
+ //
+ // P1 P1.1 P1.2 P1.3 P2
+ // | | | | |
+ // U1 U2 U3 U4 U5
+ //
+ // That distance ratio b/t Ui to U1 and Ui to U5 decides its paired penumbra
+ // vertex's location.
+ int newPenumbraNumber = indexDelta - 1;
+
+ float accumulatedDeltaLength[newPenumbraNumber];
+ float totalDeltaLength = 0;
+
+ // To save time, cache the previous umbra vertex info outside the loop
+ // and update each loop.
+ Vector2 previousClosestUmbra = umbra[previousClosestUmbraIndex];
+ Vector2 skippedUmbra;
+ // Use umbra data to precompute the length b/t unpaired umbra vertices,
+ // and its ratio against the total length.
+ for (int k = 0; k < indexDelta; k++) {
+ int skippedUmbraIndex = (previousClosestUmbraIndex + k + 1) % umbraLength;
+ skippedUmbra = umbra[skippedUmbraIndex];
+ float currentDeltaLength = (skippedUmbra - previousClosestUmbra).length();
+
+ totalDeltaLength += currentDeltaLength;
+ accumulatedDeltaLength[k] = totalDeltaLength;
+
+ previousClosestUmbra = skippedUmbra;
}
- currentDistance = distances[i];
- if (currentDistance != 0) {
- bool currentOuter = allVerticesAngleData[i].mIsPenumbra;
- for (int j = 1; j <= (currentDistance - 1); j++) {
- bool neigborOuter =
- allVerticesAngleData[(i + angleLength - j) % angleLength].mIsPenumbra;
- if (neigborOuter != currentOuter) {
- ALOGE("Wrong distance found at i %d name %s", i, name);
- }
- }
- bool oppositeOuter =
- allVerticesAngleData[(i + angleLength - currentDistance) % angleLength].mIsPenumbra;
- if (oppositeOuter == currentOuter) {
- ALOGE("Wrong distance found at i %d name %s", i, name);
- }
- }
- }
- }
-}
-/**
- * DEBUG ONLY: Verify all the angle data compuated are is correctly done
- */
-static void verifyAngleData(int totalRayNumber, const VertexAngleData* allVerticesAngleData,
- const int* distancesToInner, const int* distancesToOuter,
- const VertexAngleData* umbraAngleList, int maxUmbraAngleIndex, int umbraLength,
- const VertexAngleData* penumbraAngleList, int maxPenumbraAngleIndex,
- int penumbraLength) {
- for (int i = 0; i < totalRayNumber; i++) {
- ALOGD("currentAngleList i %d, angle %f, isInner %d, index %d distancesToInner"
- " %d distancesToOuter %d", i, allVerticesAngleData[i].mAngle,
- !allVerticesAngleData[i].mIsPenumbra,
- allVerticesAngleData[i].mVertexIndex, distancesToInner[i], distancesToOuter[i]);
- }
+ const Vector2& previousPenumbra = penumbra[(i + penumbraLength - 1) % penumbraLength];
+ // Then for each unpaired umbra vertex, create a new penumbra by the ratio,
+ // and pair them togehter.
+ for (int k = 0; k < newPenumbraNumber; k++) {
+ float weightForCurrentPenumbra = 1.0f;
+ if (totalDeltaLength != 0.0f) {
+ weightForCurrentPenumbra = accumulatedDeltaLength[k] / totalDeltaLength;
+ }
+ float weightForPreviousPenumbra = 1.0f - weightForCurrentPenumbra;
- verifyDistanceCounter(allVerticesAngleData, distancesToInner, totalRayNumber, "distancesToInner");
- verifyDistanceCounter(allVerticesAngleData, distancesToOuter, totalRayNumber, "distancesToOuter");
+ Vector2 interpolatedPenumbra = currentPenumbraVertex * weightForCurrentPenumbra +
+ previousPenumbra * weightForPreviousPenumbra;
- for (int i = 0; i < totalRayNumber; i++) {
- if ((distancesToInner[i] * distancesToOuter[i]) != 0) {
- ALOGE("distancesToInner wrong at index %d distancesToInner[i] %d,"
- " distancesToOuter[i] %d", i, distancesToInner[i], distancesToOuter[i]);
- }
- }
- int currentUmbraVertexIndex =
- umbraAngleList[maxUmbraAngleIndex].mVertexIndex;
- int currentPenumbraVertexIndex =
- penumbraAngleList[maxPenumbraAngleIndex].mVertexIndex;
- for (int i = 0; i < totalRayNumber; i++) {
- if (allVerticesAngleData[i].mIsPenumbra == true) {
- if (allVerticesAngleData[i].mVertexIndex != currentPenumbraVertexIndex) {
- ALOGW("wrong penumbra indexing i %d allVerticesAngleData[i].mVertexIndex %d "
- "currentpenumbraVertexIndex %d", i,
- allVerticesAngleData[i].mVertexIndex, currentPenumbraVertexIndex);
- }
- currentPenumbraVertexIndex = (currentPenumbraVertexIndex + 1) % penumbraLength;
- } else {
- if (allVerticesAngleData[i].mVertexIndex != currentUmbraVertexIndex) {
- ALOGW("wrong umbra indexing i %d allVerticesAngleData[i].mVertexIndex %d "
- "currentUmbraVertexIndex %d", i,
- allVerticesAngleData[i].mVertexIndex, currentUmbraVertexIndex);
+ int skippedUmbraIndex = (previousClosestUmbraIndex + k + 1) % umbraLength;
+ verticesPair[verticesPairIndex++] = {newPenumbraIndex, skippedUmbraIndex};
+ newPenumbra[newPenumbraIndex++] = interpolatedPenumbra;
}
- currentUmbraVertexIndex = (currentUmbraVertexIndex + 1) % umbraLength;
}
- }
- for (int i = 0; i < totalRayNumber - 1; i++) {
- float currentAngle = allVerticesAngleData[i].mAngle;
- float nextAngle = allVerticesAngleData[(i + 1) % totalRayNumber].mAngle;
- if (currentAngle < nextAngle) {
- ALOGE("Unexpected angle values!, currentAngle nextAngle %f %f", currentAngle, nextAngle);
- }
- }
-}
-#endif
+ verticesPair[verticesPairIndex++] = {newPenumbraIndex, currentClosestUmbraIndex};
+ newPenumbra[newPenumbraIndex++] = currentPenumbraVertex;
-/**
- * In order to compute the occluded umbra, we need to setup the angle data list
- * for the polygon data. Since we only store one poly vertex per polygon vertex,
- * this array only needs to be a float array which are the angles for each vertex.
- *
- * @param polyAngleList The result list
- *
- * @return int The index for the maximum angle in this array.
- */
-int SpotShadow::setupPolyAngleList(float* polyAngleList, int polyAngleLength,
- const Vector2* poly2d, const Vector2& centroid) {
- int maxPolyAngleIndex = -1;
- float maxPolyAngle = -FLT_MAX;
- for (int i = 0; i < polyAngleLength; i++) {
- polyAngleList[i] = angle(poly2d[i], centroid);
- if (polyAngleList[i] > maxPolyAngle) {
- maxPolyAngle = polyAngleList[i];
- maxPolyAngleIndex = i;
- }
+ previousClosestUmbraIndex = currentClosestUmbraIndex;
}
- return maxPolyAngleIndex;
-}
-
-/**
- * For umbra and penumbra, given the offset info and the current ray number,
- * find the right edge index (the (starting vertex) for the ray to shoot at.
- *
- * @return int The index of the starting vertex of the edge.
- */
-inline int SpotShadow::getEdgeStartIndex(const int* offsets, int rayIndex, int totalRayNumber,
- const VertexAngleData* allVerticesAngleData) {
- int tempOffset = offsets[rayIndex];
- int targetRayIndex = (rayIndex - tempOffset + totalRayNumber) % totalRayNumber;
- return allVerticesAngleData[targetRayIndex].mVertexIndex;
}
-/**
- * For the occluded umbra, given the array of angles, find the index of the
- * starting vertex of the edge, for the ray to shoo at.
- *
- * TODO: Save the last result to shorten the search distance.
- *
- * @return int The index of the starting vertex of the edge.
- */
-inline int SpotShadow::getPolyEdgeStartIndex(int maxPolyAngleIndex, int polyLength,
- const float* polyAngleList, float rayAngle) {
- int minPolyAngleIndex = (maxPolyAngleIndex + polyLength - 1) % polyLength;
- int resultIndex = -1;
- if (rayAngle > polyAngleList[maxPolyAngleIndex]
- || rayAngle <= polyAngleList[minPolyAngleIndex]) {
- resultIndex = minPolyAngleIndex;
- } else {
- for (int i = 0; i < polyLength - 1; i++) {
- int currentIndex = (maxPolyAngleIndex + i) % polyLength;
- int nextIndex = (maxPolyAngleIndex + i + 1) % polyLength;
- if (rayAngle <= polyAngleList[currentIndex]
- && rayAngle > polyAngleList[nextIndex]) {
- resultIndex = currentIndex;
- }
- }
+// Precompute all the polygon's vector, return true if the reference cross product is positive.
+inline bool genPolyToCentroid(const Vector2* poly2d, int polyLength,
+ const Vector2& centroid, Vector2* polyToCentroid) {
+ for (int j = 0; j < polyLength; j++) {
+ polyToCentroid[j] = poly2d[j] - centroid;
}
- if (CC_UNLIKELY(resultIndex == -1)) {
- // TODO: Add more error handling here.
- ALOGE("Wrong index found, means no edge can't be found for rayAngle %f", rayAngle);
+ float refCrossProduct = 0;
+ for (int j = 0; j < polyLength; j++) {
+ refCrossProduct = polyToCentroid[j].cross(polyToCentroid[(j + 1) % polyLength]);
+ if (refCrossProduct != 0) {
+ break;
+ }
}
- return resultIndex;
+
+ return refCrossProduct > 0;
}
-/**
- * Convert the incoming polygons into arrays of vertices, for each ray.
- * Ray only shoots when there is one vertex either on penumbra on umbra.
- *
- * Finally, it will generate vertices per ray for umbra, penumbra and optionally
- * occludedUmbra.
- *
- * Return true (success) when all vertices are generated
- */
-int SpotShadow::convertPolysToVerticesPerRay(
- bool hasOccludedUmbraArea, const Vector2* poly2d, int polyLength,
- const Vector2* umbra, int umbraLength, const Vector2* penumbra,
- int penumbraLength, const Vector2& centroid,
- Vector2* umbraVerticesPerRay, Vector2* penumbraVerticesPerRay,
- Vector2* occludedUmbraVerticesPerRay) {
- int totalRayNumber = umbraLength + penumbraLength;
-
- // For incoming umbra / penumbra polygons, we will build an intermediate data
- // structure to help us sort all the vertices according to the vertices.
- // Using this data structure, we can tell where (the angle) to shoot the ray,
- // whether we shoot at penumbra edge or umbra edge, and which edge to shoot at.
- //
- // We first parse each vertices and generate a table of VertexAngleData.
- // Based on that, we create 2 arrays telling us which edge to shoot at.
- VertexAngleData allVerticesAngleData[totalRayNumber];
- VertexAngleData umbraAngleList[umbraLength];
- VertexAngleData penumbraAngleList[penumbraLength];
-
- int polyAngleLength = hasOccludedUmbraArea ? polyLength : 0;
- float polyAngleList[polyAngleLength];
-
- const int maxUmbraAngleIndex =
- setupAngleList(umbraAngleList, umbraLength, umbra, centroid, false, "umbra");
- const int maxPenumbraAngleIndex =
- setupAngleList(penumbraAngleList, penumbraLength, penumbra, centroid, true, "penumbra");
- const int maxPolyAngleIndex = setupPolyAngleList(polyAngleList, polyAngleLength, poly2d, centroid);
-
- // Check all the polygons here are CW.
- bool isPolyCW = checkPolyClockwise(polyAngleLength, maxPolyAngleIndex, polyAngleList);
- bool isUmbraCW = checkClockwise(maxUmbraAngleIndex, umbraLength,
- umbraAngleList, "umbra");
- bool isPenumbraCW = checkClockwise(maxPenumbraAngleIndex, penumbraLength,
- penumbraAngleList, "penumbra");
-
- if (!isUmbraCW || !isPenumbraCW || !isPolyCW) {
-#if DEBUG_SHADOW
- ALOGE("One polygon is not CW isUmbraCW %d isPenumbraCW %d isPolyCW %d",
- isUmbraCW, isPenumbraCW, isPolyCW);
-#endif
- return false;
+// For one umbra vertex, shoot an ray from centroid to it.
+// If the ray hit the polygon first, then return the intersection point as the
+// closer vertex.
+inline Vector2 getCloserVertex(const Vector2& umbraVertex, const Vector2& centroid,
+ const Vector2* poly2d, int polyLength, const Vector2* polyToCentroid,
+ bool isPositiveCross, int& previousPolyIndex) {
+ Vector2 umbraToCentroid = umbraVertex - centroid;
+ float distanceToUmbra = umbraToCentroid.length();
+ umbraToCentroid = umbraToCentroid / distanceToUmbra;
+
+ // previousPolyIndex is updated for each item such that we can minimize the
+ // looping inside findPolyIndex();
+ previousPolyIndex = findPolyIndex(isPositiveCross, previousPolyIndex,
+ umbraToCentroid, polyToCentroid, polyLength);
+
+ float dx = umbraToCentroid.x;
+ float dy = umbraToCentroid.y;
+ float distanceToIntersectPoly = rayIntersectPoints(centroid, dx, dy,
+ poly2d[previousPolyIndex], poly2d[(previousPolyIndex + 1) % polyLength]);
+ if (distanceToIntersectPoly < 0) {
+ distanceToIntersectPoly = 0;
}
- mergeAngleList(maxUmbraAngleIndex, maxPenumbraAngleIndex,
- umbraAngleList, umbraLength, penumbraAngleList, penumbraLength,
- allVerticesAngleData);
-
- // Calculate the offset to the left most Inner vertex for each outerVertex.
- // Then the offset to the left most Outer vertex for each innerVertex.
- int offsetToInner[totalRayNumber];
- int offsetToOuter[totalRayNumber];
- calculateDistanceCounter(true, totalRayNumber, allVerticesAngleData, offsetToInner);
- calculateDistanceCounter(false, totalRayNumber, allVerticesAngleData, offsetToOuter);
-
- // Generate both umbraVerticesPerRay and penumbraVerticesPerRay
- for (int i = 0; i < totalRayNumber; i++) {
- float rayAngle = allVerticesAngleData[i].mAngle;
- bool isUmbraVertex = !allVerticesAngleData[i].mIsPenumbra;
-
- float dx = cosf(rayAngle);
- float dy = sinf(rayAngle);
- float distanceToIntersectUmbra = -1;
-
- if (isUmbraVertex) {
- // We can just copy umbra easily, and calculate the distance for the
- // occluded umbra computation.
- int startUmbraIndex = allVerticesAngleData[i].mVertexIndex;
- umbraVerticesPerRay[i] = umbra[startUmbraIndex];
- if (hasOccludedUmbraArea) {
- distanceToIntersectUmbra = (umbraVerticesPerRay[i] - centroid).length();
- }
-
- //shoot ray to penumbra only
- int startPenumbraIndex = getEdgeStartIndex(offsetToOuter, i, totalRayNumber,
- allVerticesAngleData);
- float distanceToIntersectPenumbra = rayIntersectPoints(centroid, dx, dy,
- penumbra[startPenumbraIndex],
- penumbra[(startPenumbraIndex + 1) % penumbraLength]);
- if (distanceToIntersectPenumbra < 0) {
-#if DEBUG_SHADOW
- ALOGW("convertPolyToRayDist for penumbra failed rayAngle %f dx %f dy %f",
- rayAngle, dx, dy);
-#endif
- distanceToIntersectPenumbra = 0;
- }
- penumbraVerticesPerRay[i].x = centroid.x + dx * distanceToIntersectPenumbra;
- penumbraVerticesPerRay[i].y = centroid.y + dy * distanceToIntersectPenumbra;
- } else {
- // We can just copy the penumbra
- int startPenumbraIndex = allVerticesAngleData[i].mVertexIndex;
- penumbraVerticesPerRay[i] = penumbra[startPenumbraIndex];
-
- // And shoot ray to umbra only
- int startUmbraIndex = getEdgeStartIndex(offsetToInner, i, totalRayNumber,
- allVerticesAngleData);
-
- distanceToIntersectUmbra = rayIntersectPoints(centroid, dx, dy,
- umbra[startUmbraIndex], umbra[(startUmbraIndex + 1) % umbraLength]);
- if (distanceToIntersectUmbra < 0) {
-#if DEBUG_SHADOW
- ALOGW("convertPolyToRayDist for umbra failed rayAngle %f dx %f dy %f",
- rayAngle, dx, dy);
-#endif
- distanceToIntersectUmbra = 0;
- }
- umbraVerticesPerRay[i].x = centroid.x + dx * distanceToIntersectUmbra;
- umbraVerticesPerRay[i].y = centroid.y + dy * distanceToIntersectUmbra;
- }
-
- if (hasOccludedUmbraArea) {
- // Shoot the same ray to the poly2d, and get the distance.
- int startPolyIndex = getPolyEdgeStartIndex(maxPolyAngleIndex, polyLength,
- polyAngleList, rayAngle);
-
- float distanceToIntersectPoly = rayIntersectPoints(centroid, dx, dy,
- poly2d[startPolyIndex], poly2d[(startPolyIndex + 1) % polyLength]);
- if (distanceToIntersectPoly < 0) {
- distanceToIntersectPoly = 0;
- }
- distanceToIntersectPoly = MathUtils::min(distanceToIntersectUmbra, distanceToIntersectPoly);
- occludedUmbraVerticesPerRay[i].x = centroid.x + dx * distanceToIntersectPoly;
- occludedUmbraVerticesPerRay[i].y = centroid.y + dy * distanceToIntersectPoly;
- }
+ // Pick the closer one as the occluded area vertex.
+ Vector2 closerVertex;
+ if (distanceToIntersectPoly < distanceToUmbra) {
+ closerVertex.x = centroid.x + dx * distanceToIntersectPoly;
+ closerVertex.y = centroid.y + dy * distanceToIntersectPoly;
+ } else {
+ closerVertex = umbraVertex;
}
-#if DEBUG_SHADOW
- verifyAngleData(totalRayNumber, allVerticesAngleData, offsetToInner,
- offsetToOuter, umbraAngleList, maxUmbraAngleIndex, umbraLength,
- penumbraAngleList, maxPenumbraAngleIndex, penumbraLength);
-#endif
- return true; // success
-
+ return closerVertex;
}
/**
@@ -1193,7 +864,6 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
const Vector3* poly, int polyLength, VertexBuffer& shadowTriangleStrip,
const Vector2& centroid) {
-
bool hasOccludedUmbraArea = false;
Vector2 poly2d[polyLength];
@@ -1209,128 +879,140 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
}
}
- int totalRayNum = umbraLength + penumbraLength;
- Vector2 umbraVertices[totalRayNum];
- Vector2 penumbraVertices[totalRayNum];
- Vector2 occludedUmbraVertices[totalRayNum];
- bool convertSuccess = convertPolysToVerticesPerRay(hasOccludedUmbraArea, poly2d,
- polyLength, umbra, umbraLength, penumbra, penumbraLength,
- centroid, umbraVertices, penumbraVertices, occludedUmbraVertices);
- if (!convertSuccess) {
- return;
+ // For each penumbra vertex, find its corresponding closest umbra vertex index.
+ //
+ // Penumbra Vertices marked as Pi
+ // Umbra Vertices marked as Ui
+ // (P3)
+ // (P2) | ' (P4)
+ // (P1)' | | '
+ // ' | | '
+ // (P0) ------------------------------------------------(P5)
+ // | (U0) |(U1)
+ // | |
+ // | |(U2) (P5.1)
+ // | |
+ // | |
+ // | |
+ // | |
+ // | |
+ // | |
+ // (U4)-----------------------------------(U3) (P6)
+ //
+ // At least, like P0, P1, P2, they will find the matching umbra as U0.
+ // If we jump over some umbra vertex without matching penumbra vertex, then
+ // we will generate some new penumbra vertex by interpolation. Like P6 is
+ // matching U3, but U2 is not matched with any penumbra vertex.
+ // So interpolate P5.1 out and match U2.
+ // In this way, every umbra vertex will have a matching penumbra vertex.
+ //
+ // The total pair number can be as high as umbraLength + penumbraLength.
+ const int maxNewPenumbraLength = umbraLength + penumbraLength;
+ IndexPair verticesPair[maxNewPenumbraLength];
+ int verticesPairIndex = 0;
+
+ // Cache all the existing penumbra vertices and newly interpolated vertices into a
+ // a new array.
+ Vector2 newPenumbra[maxNewPenumbraLength];
+ int newPenumbraIndex = 0;
+
+ // For each penumbra vertex, find its closet umbra vertex by comparing the
+ // neighbor umbra vertices.
+ genNewPenumbraAndPairWithUmbra(penumbra, penumbraLength, umbra, umbraLength, newPenumbra,
+ newPenumbraIndex, verticesPair, verticesPairIndex);
+ ShadowTessellator::checkOverflow(verticesPairIndex, maxNewPenumbraLength, "Spot pair");
+ ShadowTessellator::checkOverflow(newPenumbraIndex, maxNewPenumbraLength, "Spot new penumbra");
+#if DEBUG_SHADOW
+ for (int i = 0; i < umbraLength; i++) {
+ ALOGD("umbra i %d, [%f, %f]", i, umbra[i].x, umbra[i].y);
+ }
+ for (int i = 0; i < newPenumbraIndex; i++) {
+ ALOGD("new penumbra i %d, [%f, %f]", i, newPenumbra[i].x, newPenumbra[i].y);
+ }
+ for (int i = 0; i < verticesPairIndex; i++) {
+ ALOGD("index i %d, [%d, %d]", i, verticesPair[i].outerIndex, verticesPair[i].innerIndex);
}
+#endif
- // Minimal value is 1, for each vertex show up once.
- // The bigger this value is , the smoother the look is, but more memory
- // is consumed.
- // When the ray number is high, that means the polygon has been fine
- // tessellated, we don't need this extra slice, just keep it as 1.
- int sliceNumberPerEdge = (totalRayNum > FINE_TESSELLATED_POLYGON_RAY_NUMBER) ? 1 : 2;
-
- // For each polygon, we at most add (totalRayNum * sliceNumberPerEdge) vertices.
- int slicedVertexCountPerPolygon = totalRayNum * sliceNumberPerEdge;
- int totalVertexCount = slicedVertexCountPerPolygon * 2 + totalRayNum;
- int totalIndexCount = 2 * (slicedVertexCountPerPolygon * 2 + 2);
+ // For the size of vertex buffer, we need 3 rings, one has newPenumbraSize,
+ // one has umbraLength, the last one has at most umbraLength.
+ //
+ // For the size of index buffer, the umbra area needs (2 * umbraLength + 2).
+ // The penumbra one can vary a bit, but it is bounded by (2 * verticesPairIndex + 2).
+ // And 2 more for jumping between penumbra to umbra.
+ const int newPenumbraLength = newPenumbraIndex;
+ const int totalVertexCount = newPenumbraLength + umbraLength * 2;
+ const int totalIndexCount = 2 * umbraLength + 2 * verticesPairIndex + 6;
AlphaVertex* shadowVertices =
shadowTriangleStrip.alloc<AlphaVertex>(totalVertexCount);
uint16_t* indexBuffer =
shadowTriangleStrip.allocIndices<uint16_t>(totalIndexCount);
-
- int indexBufferIndex = 0;
int vertexBufferIndex = 0;
+ int indexBufferIndex = 0;
- uint16_t slicedUmbraVertexIndex[totalRayNum * sliceNumberPerEdge];
- // Should be something like 0 0 0 1 1 1 2 3 3 3...
- int rayNumberPerSlicedUmbra[totalRayNum * sliceNumberPerEdge];
- int realUmbraVertexCount = 0;
- for (int i = 0; i < totalRayNum; i++) {
- Vector2 currentPenumbra = penumbraVertices[i];
- Vector2 currentUmbra = umbraVertices[i];
-
- Vector2 nextPenumbra = penumbraVertices[(i + 1) % totalRayNum];
- Vector2 nextUmbra = umbraVertices[(i + 1) % totalRayNum];
- // NextUmbra/Penumbra will be done in the next loop!!
- for (int weight = 0; weight < sliceNumberPerEdge; weight++) {
- const Vector2& slicedPenumbra = (currentPenumbra * (sliceNumberPerEdge - weight)
- + nextPenumbra * weight) / sliceNumberPerEdge;
-
- const Vector2& slicedUmbra = (currentUmbra * (sliceNumberPerEdge - weight)
- + nextUmbra * weight) / sliceNumberPerEdge;
-
- // In the vertex buffer, we fill the Penumbra first, then umbra.
- indexBuffer[indexBufferIndex++] = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], slicedPenumbra.x,
- slicedPenumbra.y, 0.0f);
-
- // When we add umbra vertex, we need to remember its current ray number.
- // And its own vertexBufferIndex. This is for occluded umbra usage.
- indexBuffer[indexBufferIndex++] = vertexBufferIndex;
- rayNumberPerSlicedUmbra[realUmbraVertexCount] = i;
- slicedUmbraVertexIndex[realUmbraVertexCount] = vertexBufferIndex;
- realUmbraVertexCount++;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], slicedUmbra.x,
- slicedUmbra.y, M_PI);
- }
+ // Fill the IB and VB for the penumbra area.
+ for (int i = 0; i < newPenumbraLength; i++) {
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
+ newPenumbra[i].y, 0.0f);
+ }
+ for (int i = 0; i < umbraLength; i++) {
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
+ M_PI);
}
- indexBuffer[indexBufferIndex++] = 0;
- //RealUmbraVertexIndex[0] must be 1, so we connect back well at the
- //beginning of occluded area.
- indexBuffer[indexBufferIndex++] = 1;
+ for (int i = 0; i < verticesPairIndex; i++) {
+ indexBuffer[indexBufferIndex++] = verticesPair[i].outerIndex;
+ // All umbra index need to be offseted by newPenumbraSize.
+ indexBuffer[indexBufferIndex++] = verticesPair[i].innerIndex + newPenumbraLength;
+ }
+ indexBuffer[indexBufferIndex++] = verticesPair[0].outerIndex;
+ indexBuffer[indexBufferIndex++] = verticesPair[0].innerIndex + newPenumbraLength;
+
+ // Now fill the IB and VB for the umbra area.
+ // First duplicated the index from previous strip and the first one for the
+ // degenerated triangles.
+ indexBuffer[indexBufferIndex] = indexBuffer[indexBufferIndex - 1];
+ indexBufferIndex++;
+ indexBuffer[indexBufferIndex++] = newPenumbraLength + 0;
+ // Save the first VB index for umbra area in order to close the loop.
+ int savedStartIndex = vertexBufferIndex;
- float occludedUmbraAlpha = M_PI;
if (hasOccludedUmbraArea) {
- // Now the occludedUmbra area;
- int currentRayNumber = -1;
- int firstOccludedUmbraIndex = -1;
- for (int i = 0; i < realUmbraVertexCount; i++) {
- indexBuffer[indexBufferIndex++] = slicedUmbraVertexIndex[i];
-
- // If the occludedUmbra vertex has not been added yet, then add it.
- // Otherwise, just use the previously added occludedUmbra vertices.
- if (rayNumberPerSlicedUmbra[i] != currentRayNumber) {
- currentRayNumber++;
- indexBuffer[indexBufferIndex++] = vertexBufferIndex;
- // We need to remember the begining of the occludedUmbra vertices
- // to close this loop.
- if (currentRayNumber == 0) {
- firstOccludedUmbraIndex = vertexBufferIndex;
- }
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
- occludedUmbraVertices[currentRayNumber].x,
- occludedUmbraVertices[currentRayNumber].y,
- occludedUmbraAlpha);
- } else {
- indexBuffer[indexBufferIndex++] = (vertexBufferIndex - 1);
- }
+ // Precompute all the polygon's vector, and the reference cross product,
+ // in order to find the right polygon edge for the ray to intersect.
+ Vector2 polyToCentroid[polyLength];
+ bool isPositiveCross = genPolyToCentroid(poly2d, polyLength, centroid, polyToCentroid);
+
+ // Because both the umbra and polygon are going in the same direction,
+ // we can save the previous polygon index to make sure we have less polygon
+ // vertex to compute for each ray.
+ int previousPolyIndex = 0;
+ for (int i = 0; i < umbraLength; i++) {
+ // Shoot a ray from centroid to each umbra vertices and pick the one with
+ // shorter distance to the centroid, b/t the umbra vertex or the intersection point.
+ Vector2 closerVertex = getCloserVertex(umbra[i], centroid, poly2d, polyLength,
+ polyToCentroid, isPositiveCross, previousPolyIndex);
+
+ // We already stored the umbra vertices, just need to add the occlued umbra's ones.
+ indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
+ indexBuffer[indexBufferIndex++] = vertexBufferIndex;
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
+ closerVertex.x, closerVertex.y, M_PI);
}
- // Close the loop here!
- indexBuffer[indexBufferIndex++] = slicedUmbraVertexIndex[0];
- indexBuffer[indexBufferIndex++] = firstOccludedUmbraIndex;
} else {
+ // If there is no occluded umbra at all, then draw the triangle fan
+ // starting from the centroid to all umbra vertices.
int lastCentroidIndex = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
- centroid.y, occludedUmbraAlpha);
- for (int i = 0; i < realUmbraVertexCount; i++) {
- indexBuffer[indexBufferIndex++] = slicedUmbraVertexIndex[i];
+ centroid.y, M_PI);
+ for (int i = 0; i < umbraLength; i++) {
+ indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = lastCentroidIndex;
}
- // Close the loop here!
- indexBuffer[indexBufferIndex++] = slicedUmbraVertexIndex[0];
- indexBuffer[indexBufferIndex++] = lastCentroidIndex;
}
-
-#if DEBUG_SHADOW
- ALOGD("allocated IB %d allocated VB is %d", totalIndexCount, totalVertexCount);
- ALOGD("IB index %d VB index is %d", indexBufferIndex, vertexBufferIndex);
- for (int i = 0; i < vertexBufferIndex; i++) {
- ALOGD("vertexBuffer i %d, (%f, %f %f)", i, shadowVertices[i].x, shadowVertices[i].y,
- shadowVertices[i].alpha);
- }
- for (int i = 0; i < indexBufferIndex; i++) {
- ALOGD("indexBuffer i %d, indexBuffer[i] %d", i, indexBuffer[i]);
- }
-#endif
+ // Closing the umbra area triangle's loop here.
+ indexBuffer[indexBufferIndex++] = newPenumbraLength;
+ indexBuffer[indexBufferIndex++] = savedStartIndex;
// At the end, update the real index and vertex buffer size.
shadowTriangleStrip.updateVertexCount(vertexBufferIndex);
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index 6fa2028..e2d94f7 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -36,40 +36,6 @@ private:
static float projectCasterToOutline(Vector2& outline,
const Vector3& lightCenter, const Vector3& polyVertex);
- static int setupAngleList(VertexAngleData* angleDataList,
- int polyLength, const Vector2* polygon, const Vector2& centroid,
- bool isPenumbra, const char* name);
-
- static int convertPolysToVerticesPerRay(
- bool hasOccludedUmbraArea, const Vector2* poly2d, int polyLength,
- const Vector2* umbra, int umbraLength, const Vector2* penumbra,
- int penumbraLength, const Vector2& centroid,
- Vector2* umbraVerticesPerRay, Vector2* penumbraVerticesPerRay,
- Vector2* occludedUmbraVerticesPerRay);
-
- static bool checkClockwise(int maxIndex, int listLength,
- VertexAngleData* angleList, const char* name);
-
- static void calculateDistanceCounter(bool needsOffsetToUmbra, int angleLength,
- const VertexAngleData* allVerticesAngleData, int* distances);
-
- static void mergeAngleList(int maxUmbraAngleIndex, int maxPenumbraAngleIndex,
- const VertexAngleData* umbraAngleList, int umbraLength,
- const VertexAngleData* penumbraAngleList, int penumbraLength,
- VertexAngleData* allVerticesAngleData);
-
- static int setupPolyAngleList(float* polyAngleList, int polyAngleLength,
- const Vector2* poly2d, const Vector2& centroid);
-
- static bool checkPolyClockwise(int polyAngleLength, int maxPolyAngleIndex,
- const float* polyAngleList);
-
- static int getEdgeStartIndex(const int* offsets, int rayIndex, int totalRayNumber,
- const VertexAngleData* allVerticesAngleData);
-
- static int getPolyEdgeStartIndex(int maxPolyAngleIndex, int polyLength,
- const float* polyAngleList, float rayAngle);
-
static void computeLightPolygon(int points, const Vector3& lightCenter,
float size, Vector3* ret);
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index d033ed9..aa6acc9 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -99,6 +99,10 @@ struct Vector2 {
return x * v.x + y * v.y;
}
+ float cross(const Vector2& v) const {
+ return x * v.y - y * v.x;
+ }
+
void dump() {
ALOGD("Vector2[%.2f, %.2f]", x, y);
}