summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorztenghui <ztenghui@google.com>2014-03-17 21:12:48 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-03-17 21:12:48 +0000
commit630c0abaea1b35b4626a1d752bd04f28529801e1 (patch)
treeaa03deb658513a418a8d4c1e1b9b9dc573556408
parentdb62c232b953fd882a8f55daf736ae4098e8f278 (diff)
parent50ecf849cb7ccc3482517b74d2214b347927791e (diff)
downloadframeworks_base-630c0abaea1b35b4626a1d752bd04f28529801e1.zip
frameworks_base-630c0abaea1b35b4626a1d752bd04f28529801e1.tar.gz
frameworks_base-630c0abaea1b35b4626a1d752bd04f28529801e1.tar.bz2
Merge "Create one hole inside the umbra area to avoid overdraw."
-rw-r--r--libs/hwui/AmbientShadow.cpp42
-rw-r--r--libs/hwui/AmbientShadow.h7
-rw-r--r--libs/hwui/Caches.cpp4
-rw-r--r--libs/hwui/OpenGLRenderer.cpp24
-rw-r--r--libs/hwui/OpenGLRenderer.h3
-rw-r--r--libs/hwui/ShadowTessellator.cpp59
-rw-r--r--libs/hwui/ShadowTessellator.h27
-rw-r--r--libs/hwui/SpotShadow.cpp165
-rw-r--r--libs/hwui/SpotShadow.h24
9 files changed, 215 insertions, 140 deletions
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 8327ef7..c0b5402 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -31,6 +31,7 @@ namespace uirenderer {
* Calculate the shadows as a triangle strips while alpha value as the
* shadow values.
*
+ * @param isCasterOpaque Whether the caster is opaque.
* @param vertices The shadow caster's polygon, which is represented in a Vector3
* array.
* @param vertexCount The length of caster's polygon in terms of number of
@@ -43,17 +44,18 @@ namespace uirenderer {
* @param shadowVertexBuffer Return an floating point array of (x, y, a)
* triangle strips mode.
*/
-void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount,
- const Vector3& centroid3d, float heightFactor, float geomFactor,
- VertexBuffer& shadowVertexBuffer) {
+VertexBufferMode AmbientShadow::createAmbientShadow(bool isCasterOpaque,
+ const Vector3* vertices, int vertexCount, const Vector3& centroid3d,
+ float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
const int rays = SHADOW_RAY_COUNT;
+ VertexBufferMode mode = kVertexBufferMode_OnePolyRingShadow;
// Validate the inputs.
if (vertexCount < 3 || heightFactor <= 0 || rays <= 0
|| geomFactor <= 0) {
#if DEBUG_SHADOW
- ALOGE("Invalid input for createAmbientShadow(), early return!");
+ ALOGW("Invalid input for createAmbientShadow(), early return!");
#endif
- return;
+ return mode; // vertex buffer is empty, so any mode doesn't matter.
}
Vector<Vector2> dir; // TODO: use C++11 unique_ptr
@@ -75,7 +77,7 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount
rayDist[i] = rayDistance;
if (edgeIndex < 0 || edgeIndex >= vertexCount) {
#if DEBUG_SHADOW
- ALOGE("Invalid edgeIndex!");
+ ALOGW("Invalid edgeIndex!");
#endif
edgeIndex = 0;
}
@@ -86,7 +88,8 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount
// The output buffer length basically is roughly rays * layers, but since we
// need triangle strips, so we need to duplicate vertices to accomplish that.
- AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(SHADOW_VERTEX_COUNT);
+ AlphaVertex* shadowVertices =
+ shadowVertexBuffer.alloc<AlphaVertex>(SHADOW_VERTEX_COUNT);
// Calculate the vertex of the shadows.
//
@@ -95,6 +98,7 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount
// calculate the normal N, which should be perpendicular to the edge of the
// polygon (represented by the neighbor intersection points) .
// Shadow's vertices will be generated as : P + N * scale.
+ const Vector2 centroid2d = Vector2(centroid3d.x, centroid3d.y);
for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
Vector2 normal(1.0f, 0.0f);
calculateNormal(rays, rayIndex, dir.array(), rayDist, normal);
@@ -102,7 +106,7 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount
// The vertex should be start from rayDist[i] then scale the
// normalizeNormal!
Vector2 intersection = dir[rayIndex] * rayDist[rayIndex] +
- Vector2(centroid3d.x, centroid3d.y);
+ centroid2d;
// outer ring of points, expanded based upon height of each ray intersection
float expansionDist = rayHeight[rayIndex] * heightFactor *
@@ -114,25 +118,31 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount
// inner ring of points
float opacity = 1.0 / (1 + rayHeight[rayIndex] * heightFactor);
- AlphaVertex::set(&shadowVertices[rayIndex + rays],
+ AlphaVertex::set(&shadowVertices[rays + rayIndex],
intersection.x,
intersection.y,
opacity);
}
- float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor);
- AlphaVertex::set(&shadowVertices[SHADOW_VERTEX_COUNT - 1],
- centroid3d.x, centroid3d.y, centroidAlpha);
-#if DEBUG_SHADOW
- if (currentVertexIndex != SHADOW_VERTEX_COUNT) {
- ALOGE("number of vertex generated for ambient shadow is wrong! "
- "current: %d , expected: %d", currentVertexIndex, SHADOW_VERTEX_COUNT);
+ // If caster isn't opaque, we need to to fill the umbra by storing the umbra's
+ // centroid in the innermost ring of vertices.
+ if (!isCasterOpaque) {
+ mode = kVertexBufferMode_TwoPolyRingShadow;
+ float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor);
+ AlphaVertex centroidXYA;
+ AlphaVertex::set(&centroidXYA, centroid2d.x, centroid2d.y, centroidAlpha);
+ for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
+ shadowVertices[2 * rays + rayIndex] = centroidXYA;
+ }
}
+
+#if DEBUG_SHADOW
for (int i = 0; i < SHADOW_VERTEX_COUNT; i++) {
ALOGD("ambient shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
shadowVertices[i].y, shadowVertices[i].alpha);
}
#endif
+ return mode;
}
/**
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 20d1384..45b8bef 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -19,6 +19,7 @@
#define ANDROID_HWUI_AMBIENT_SHADOW_H
#include "Debug.h"
+#include "OpenGLRenderer.h"
#include "Vector.h"
#include "VertexBuffer.h"
@@ -34,9 +35,9 @@ namespace uirenderer {
*/
class AmbientShadow {
public:
- static void createAmbientShadow(const Vector3* poly, int polyLength,
- const Vector3& centroid3d, float heightFactor, float geomFactor,
- VertexBuffer& shadowVertexBuffer);
+ static VertexBufferMode createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
+ int polyLength, const Vector3& centroid3d, float heightFactor,
+ float geomFactor, VertexBuffer& shadowVertexBuffer);
private:
static void calculateRayDirections(int rays, Vector2* dir);
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 2dfc873..477d691 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -445,11 +445,11 @@ bool Caches::bindQuadIndicesBuffer() {
bool Caches::bindShadowIndicesBuffer() {
if (!mShadowStripsIndices) {
- uint16_t* shadowIndices = new uint16_t[SHADOW_INDEX_COUNT];
+ uint16_t* shadowIndices = new uint16_t[MAX_SHADOW_INDEX_COUNT];
ShadowTessellator::generateShadowIndices(shadowIndices);
glGenBuffers(1, &mShadowStripsIndices);
bool force = bindIndicesBufferInternal(mShadowStripsIndices);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, SHADOW_INDEX_COUNT * sizeof(uint16_t),
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
shadowIndices, GL_STATIC_DRAW);
delete[] shadowIndices;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1475953..cb8155b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2414,9 +2414,12 @@ status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode,
if (mode == kVertexBufferMode_Standard) {
mCaches.unbindIndicesBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
- } else {
+ } else if (mode == kVertexBufferMode_OnePolyRingShadow) {
+ mCaches.bindShadowIndicesBuffer();
+ glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
+ } else if (mode == kVertexBufferMode_TwoPolyRingShadow) {
mCaches.bindShadowIndicesBuffer();
- glDrawElements(GL_TRIANGLE_STRIP, SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
+ glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
}
if (isAA) {
@@ -3245,14 +3248,15 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
}
centroid3d.z += casterLift;
}
-
+ bool isCasterOpaque = (casterAlpha == 1.0f);
// draw caster's shadows
if (mCaches.propertyAmbientShadowStrength > 0) {
paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
VertexBuffer ambientShadowVertexBuffer;
- ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
- centroid3d, ambientShadowVertexBuffer);
- drawVertexBuffer(kVertexBufferMode_Shadow, ambientShadowVertexBuffer, &paint);
+ VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateAmbientShadow(
+ isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
+ ambientShadowVertexBuffer);
+ drawVertexBuffer(vertexBufferMode, ambientShadowVertexBuffer, &paint);
}
if (mCaches.propertySpotShadowStrength > 0) {
@@ -3260,10 +3264,10 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
VertexBuffer spotShadowVertexBuffer;
Vector3 lightPosScale(mCaches.propertyLightPosXScale,
mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
- ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount,
- lightPosScale, *currentTransform(), getWidth(), getHeight(),
- spotShadowVertexBuffer);
- drawVertexBuffer(kVertexBufferMode_Shadow, spotShadowVertexBuffer, &paint);
+ VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
+ isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale,
+ *currentTransform(), getWidth(), getHeight(), spotShadowVertexBuffer);
+ drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
}
return DrawGlInfo::kStatusDrew;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 94abfa7..059c64f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -119,7 +119,8 @@ enum ModelViewMode {
enum VertexBufferMode {
kVertexBufferMode_Standard = 0,
- kVertexBufferMode_Shadow = 1
+ kVertexBufferMode_OnePolyRingShadow = 1,
+ kVertexBufferMode_TwoPolyRingShadow = 2
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index f138222..771904a 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -33,9 +33,9 @@ static inline T max(T a, T b) {
return a > b ? a : b;
}
-void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
- int casterVertexCount, const Vector3& centroid3d,
- VertexBuffer& shadowVertexBuffer) {
+VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
+ const Vector3* casterPolygon, int casterVertexCount,
+ const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
// A bunch of parameters to tweak the shadow.
@@ -43,12 +43,14 @@ void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
const float heightFactor = 1.0f / 128;
const float geomFactor = 64;
- AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount,
- centroid3d, heightFactor, geomFactor, shadowVertexBuffer);
+ return AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
+ casterVertexCount, centroid3d, heightFactor, geomFactor,
+ shadowVertexBuffer);
}
-void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
+VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
+ const Vector3* casterPolygon, int casterVertexCount,
const Vector3& lightPosScale, const mat4& receiverTransform,
int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
@@ -71,37 +73,40 @@ void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int c
const float lightSize = maximal / 4;
const int lightVertexCount = 8;
- SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter,
- lightSize, lightVertexCount, shadowVertexBuffer);
+ VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
+ casterPolygon, casterVertexCount, lightCenter, lightSize,
+ lightVertexCount, shadowVertexBuffer);
+#if DEBUG_SHADOW
+ if(shadowVertexBuffer.getVertexCount() <= 0) {
+ ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
+ }
+#endif
+ return mode;
}
void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
int currentIndex = 0;
const int rays = SHADOW_RAY_COUNT;
// For the penumbra area.
- for (int i = 0; i < rays; i++) {
- shadowIndices[currentIndex++] = i;
- shadowIndices[currentIndex++] = rays + i;
- }
- // To close the loop, back to the ray 0.
- shadowIndices[currentIndex++] = 0;
- shadowIndices[currentIndex++] = rays;
-
- uint16_t centroidIndex = 2 * rays;
- // For the umbra area, using strips to simulate the fans.
- for (int i = 0; i < rays; i++) {
- shadowIndices[currentIndex++] = rays + i;
- shadowIndices[currentIndex++] = centroidIndex;
+ for (int layer = 0; layer < 2; layer ++) {
+ int baseIndex = layer * rays;
+ for (int i = 0; i < rays; i++) {
+ shadowIndices[currentIndex++] = i + baseIndex;
+ shadowIndices[currentIndex++] = rays + i + baseIndex;
+ }
+ // To close the loop, back to the ray 0.
+ shadowIndices[currentIndex++] = 0 + baseIndex;
+ // Note this is the same as the first index of next layer loop.
+ shadowIndices[currentIndex++] = rays + baseIndex;
}
- shadowIndices[currentIndex++] = rays;
#if DEBUG_SHADOW
- if (currentIndex != SHADOW_INDEX_COUNT) {
- ALOGE("vertex index count is wrong. current %d, expected %d",
- currentIndex, SHADOW_INDEX_COUNT);
+ if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
+ ALOGW("vertex index count is wrong. current %d, expected %d",
+ currentIndex, MAX_SHADOW_INDEX_COUNT);
}
- for (int i = 0; i < SHADOW_INDEX_COUNT; i++) {
+ for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
}
#endif
@@ -135,7 +140,7 @@ Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
if (area != 0) {
centroid = Vector2(sumx / (3 * area), sumy / (3 * area));
} else {
- ALOGE("Area is 0 while computing centroid!");
+ ALOGW("Area is 0 while computing centroid!");
}
return centroid;
}
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index c558460..ab039fa 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -20,6 +20,7 @@
#include "Debug.h"
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "VertexBuffer.h"
namespace android {
@@ -30,15 +31,14 @@ namespace uirenderer {
// Assuming we use 6 rays and only 1 layer, Then we will have 2 hexagons, which
// are 0 to 5 and 6 to 11. The area between them will be the penumbra area, and
// the area inside the 2nd hexagon is the umbra.
-// Also, we need to add the centroid "12" to draw the umbra area as triangle fans.
-//
+// Ambient shadow is using only 1 layer for opaque caster, otherwise, spot
+// shadow and ambient shadow are using 2 layers.
// Triange strip indices for penumbra area: (0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11, 0, 6)
-// Triange strip indices for numbra area: (6, 12, 7, 12, 8, 12, 9, 12, 10, 12, 11, 12, 6)
// 0
//
// 5 6 1
// 11 7
-// 12
+//
// 10 8
// 4 9 2
//
@@ -49,20 +49,27 @@ namespace uirenderer {
#define SHADOW_RAY_COUNT 128
// The total number of all the vertices representing the shadow.
-#define SHADOW_VERTEX_COUNT (2 * SHADOW_RAY_COUNT + 1)
+// For the case we only have 1 layer, then we will just fill only 2/3 of it.
+#define SHADOW_VERTEX_COUNT (3 * SHADOW_RAY_COUNT)
// The total number of indices used for drawing the shadow geometry as triangle strips.
-#define SHADOW_INDEX_COUNT (2 * SHADOW_RAY_COUNT + 1 + 2 * (SHADOW_RAY_COUNT + 1))
+// Depending on the mode we are drawing, we can have 1 layer or 2 layers.
+// Therefore, we only build the longer index buffer.
+#define TWO_POLY_RING_SHADOW_INDEX_COUNT (4 * (SHADOW_RAY_COUNT + 1))
+#define ONE_POLY_RING_SHADOW_INDEX_COUNT (2 * (SHADOW_RAY_COUNT + 1))
+
+#define MAX_SHADOW_INDEX_COUNT TWO_POLY_RING_SHADOW_INDEX_COUNT
#define SHADOW_MIN_CASTER_Z 0.001f
class ShadowTessellator {
public:
- static void tessellateAmbientShadow(const Vector3* casterPolygon,
- int casterVertexCount, const Vector3& centroid3d,
- VertexBuffer& shadowVertexBuffer);
+ static VertexBufferMode tessellateAmbientShadow(bool isCasterOpaque,
+ const Vector3* casterPolygon, int casterVertexCount,
+ const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer);
- static void tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
+ static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
+ const Vector3* casterPolygon, int casterVertexCount,
const Vector3& lightPosScale, const mat4& receiverTransform,
int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer);
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 8538b29..1b49083 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -161,7 +161,7 @@ bool SpotShadow::ccw(double ax, double ay, double bx, double by,
/**
* Calculates the intersection of poly1 with poly2 and put in poly2.
- *
+ * Note that both poly1 and poly2 must be in CW order already!
*
* @param poly1 The 1st polygon, as a Vector2 array.
* @param poly1Length The number of vertices of 1st polygon.
@@ -169,11 +169,16 @@ bool SpotShadow::ccw(double ax, double ay, double bx, double by,
* @param poly2Length The number of vertices of 2nd polygon.
* @return number of vertices in output polygon as poly2.
*/
-int SpotShadow::intersection(Vector2* poly1, int poly1Length,
+int SpotShadow::intersection(const Vector2* poly1, int poly1Length,
Vector2* poly2, int poly2Length) {
- makeClockwise(poly1, poly1Length);
- makeClockwise(poly2, poly2Length);
-
+#if DEBUG_SHADOW
+ if (!isClockwise(poly1, poly1Length)) {
+ ALOGW("Poly1 is not clockwise! Intersection is wrong!");
+ }
+ if (!isClockwise(poly2, poly2Length)) {
+ ALOGW("Poly2 is not clockwise! Intersection is wrong!");
+ }
+#endif
Vector2 poly[poly1Length * poly2Length + 2];
int count = 0;
int pcount = 0;
@@ -411,7 +416,7 @@ void SpotShadow::makeClockwise(Vector2* polygon, int len) {
* @param polygon the polygon as a Vector2 array
* @param len the number of points of the polygon
*/
-bool SpotShadow::isClockwise(Vector2* polygon, int len) {
+bool SpotShadow::isClockwise(const Vector2* polygon, int len) {
double sum = 0;
double p1x = polygon[len - 1].x;
double p1y = polygon[len - 1].y;
@@ -514,13 +519,14 @@ void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter,
* empty strip if error.
*
*/
-void SpotShadow::createSpotShadow(const Vector3* poly, int polyLength,
- const Vector3& lightCenter, float lightSize, int lightVertexCount,
- VertexBuffer& retStrips) {
+VertexBufferMode SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3* poly,
+ int polyLength, const Vector3& lightCenter, float lightSize,
+ int lightVertexCount, VertexBuffer& retStrips) {
Vector3 light[lightVertexCount * 3];
computeLightPolygon(lightVertexCount, lightCenter, lightSize, light);
- computeSpotShadow(light, lightVertexCount, lightCenter, poly, polyLength,
- retStrips);
+ computeSpotShadow(isCasterOpaque, light, lightVertexCount, lightCenter, poly,
+ polyLength, retStrips);
+ return kVertexBufferMode_TwoPolyRingShadow;
}
/**
@@ -533,9 +539,9 @@ void SpotShadow::createSpotShadow(const Vector3* poly, int polyLength,
* @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
* empty strip if error.
*/
-void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength,
- const Vector3& lightCenter, const Vector3* poly, int polyLength,
- VertexBuffer& shadowTriangleStrip) {
+void SpotShadow::computeSpotShadow(bool isCasterOpaque, const Vector3* lightPoly,
+ int lightPolyLength, const Vector3& lightCenter, const Vector3* poly,
+ int polyLength, VertexBuffer& shadowTriangleStrip) {
// Point clouds for all the shadowed vertices
Vector2 shadowRegion[lightPolyLength * polyLength];
// Shadow polygon from one point light.
@@ -565,13 +571,13 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength
for (int j = 0; j < lightPolyLength; j++) {
int m = 0;
for (int i = 0; i < polyLength; i++) {
- float t = lightPoly[j].z - poly[i].z;
- if (t == 0) {
+ float deltaZ = lightPoly[j].z - poly[i].z;
+ if (deltaZ == 0) {
return;
}
- t = lightPoly[j].z / t;
- float x = lightPoly[j].x - t * (lightPoly[j].x - poly[i].x);
- float y = lightPoly[j].y - t * (lightPoly[j].y - poly[i].y);
+ float ratioZ = lightPoly[j].z / deltaZ;
+ float x = lightPoly[j].x - ratioZ * (lightPoly[j].x - poly[i].x);
+ float y = lightPoly[j].y - ratioZ * (lightPoly[j].y - poly[i].y);
Vector2 newPoint = Vector2(x, y);
shadowRegion[k] = newPoint;
@@ -606,13 +612,13 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength
if (umbraLength < 3) {
// If there is no real umbra, make a fake one.
for (int i = 0; i < polyLength; i++) {
- float t = lightCenter.z - poly[i].z;
- if (t == 0) {
+ float deltaZ = lightCenter.z - poly[i].z;
+ if (deltaZ == 0) {
return;
}
- t = lightCenter.z / t;
- float x = lightCenter.x - t * (lightCenter.x - poly[i].x);
- float y = lightCenter.y - t * (lightCenter.y - poly[i].y);
+ float ratioZ = lightCenter.z / deltaZ;
+ float x = lightCenter.x - ratioZ * (lightCenter.x - poly[i].x);
+ float y = lightCenter.y - ratioZ * (lightCenter.y - poly[i].y);
fakeUmbra[i].x = x;
fakeUmbra[i].y = y;
@@ -635,8 +641,8 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength
umbraLength = polyLength;
}
- generateTriangleStrip(penumbra, penumbraLength, umbra, umbraLength,
- shadowTriangleStrip);
+ generateTriangleStrip(isCasterOpaque, penumbra, penumbraLength, umbra,
+ umbraLength, poly, polyLength, shadowTriangleStrip);
}
/**
@@ -684,7 +690,12 @@ bool convertPolyToRayDist(const Vector2* poly, int polyLength, const Vector2& po
cos(rayIndex * step),
sin(rayIndex * step),
*lastVertex, poly[polyIndex]);
- if (distanceToIntersect < 0) return false; // error case, abort
+ if (distanceToIntersect < 0) {
+#if DEBUG_SHADOW
+ ALOGW("ERROR: convertPolyToRayDist failed");
+#endif
+ return false; // error case, abort
+ }
rayDist[rayIndex] = distanceToIntersect;
@@ -696,6 +707,22 @@ bool convertPolyToRayDist(const Vector2* poly, int polyLength, const Vector2& po
return true;
}
+int SpotShadow::calculateOccludedUmbra(const Vector2* umbra, int umbraLength,
+ const Vector3* poly, int polyLength, Vector2* occludedUmbra) {
+ // Occluded umbra area is computed as the intersection of the projected 2D
+ // poly and umbra.
+ for (int i = 0; i < polyLength; i++) {
+ occludedUmbra[i].x = poly[i].x;
+ occludedUmbra[i].y = poly[i].y;
+ }
+
+ // Both umbra and incoming polygon are guaranteed to be CW, so we can call
+ // intersection() directly.
+ return intersection(umbra, umbraLength,
+ occludedUmbra, polyLength);
+}
+
+#define OCLLUDED_UMBRA_SHRINK_FACTOR 0.95f
/**
* Generate a triangle strip given two convex polygons
*
@@ -706,10 +733,10 @@ bool convertPolyToRayDist(const Vector2* poly, int polyLength, const Vector2& po
* @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
* empty strip if error.
**/
-void SpotShadow::generateTriangleStrip(const Vector2* penumbra, int penumbraLength,
- const Vector2* umbra, int umbraLength, VertexBuffer& shadowTriangleStrip) {
+void SpotShadow::generateTriangleStrip(bool isCasterOpaque, const Vector2* penumbra,
+ int penumbraLength, const Vector2* umbra, int umbraLength,
+ const Vector3* poly, int polyLength, VertexBuffer& shadowTriangleStrip) {
const int rays = SHADOW_RAY_COUNT;
-
const int size = 2 * rays;
const float step = M_PI * 2 / rays;
// Centroid of the umbra.
@@ -721,37 +748,66 @@ void SpotShadow::generateTriangleStrip(const Vector2* penumbra, int penumbraLeng
float penumbraDistPerRay[rays];
// Intersection to the umbra.
float umbraDistPerRay[rays];
+ // Intersection to the occluded umbra area.
+ float occludedUmbraDistPerRay[rays];
// convert CW polygons to ray distance encoding, aborting on conversion failure
if (!convertPolyToRayDist(umbra, umbraLength, centroid, umbraDistPerRay)) return;
if (!convertPolyToRayDist(penumbra, penumbraLength, centroid, penumbraDistPerRay)) return;
- AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(getStripSize(rays));
+ bool hasOccludedUmbraArea = false;
+ if (isCasterOpaque) {
+ Vector2 occludedUmbra[polyLength + umbraLength];
+ int occludedUmbraLength = calculateOccludedUmbra(umbra, umbraLength, poly, polyLength,
+ occludedUmbra);
+ // Make sure the centroid is inside the umbra, otherwise, fall back to the
+ // approach as if there is no occluded umbra area.
+ if (testPointInsidePolygon(centroid, occludedUmbra, occludedUmbraLength)) {
+ hasOccludedUmbraArea = true;
+ // Shrink the occluded umbra area to avoid pixel level artifacts.
+ for (int i = 0; i < occludedUmbraLength; i ++) {
+ occludedUmbra[i] = centroid + (occludedUmbra[i] - centroid) *
+ OCLLUDED_UMBRA_SHRINK_FACTOR;
+ }
+ if (!convertPolyToRayDist(occludedUmbra, occludedUmbraLength, centroid,
+ occludedUmbraDistPerRay)) {
+ return;
+ }
+ }
+ }
+
+ AlphaVertex* shadowVertices =
+ shadowTriangleStrip.alloc<AlphaVertex>(SHADOW_VERTEX_COUNT);
// Calculate the vertices (x, y, alpha) in the shadow area.
+ AlphaVertex centroidXYA;
+ AlphaVertex::set(&centroidXYA, centroid.x, centroid.y, 1.0f);
for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
float dx = cosf(step * rayIndex);
float dy = sinf(step * rayIndex);
- // outer ring
- float currentDist = penumbraDistPerRay[rayIndex];
+ // penumbra ring
+ float penumbraDistance = penumbraDistPerRay[rayIndex];
AlphaVertex::set(&shadowVertices[rayIndex],
- dx * currentDist + centroid.x, dy * currentDist + centroid.y, 0.0f);
+ dx * penumbraDistance + centroid.x,
+ dy * penumbraDistance + centroid.y, 0.0f);
- // inner ring
- float deltaDist = umbraDistPerRay[rayIndex] - penumbraDistPerRay[rayIndex];
- currentDist += deltaDist;
+ // umbra ring
+ float umbraDistance = umbraDistPerRay[rayIndex];
AlphaVertex::set(&shadowVertices[rays + rayIndex],
- dx * currentDist + centroid.x, dy * currentDist + centroid.y, 1.0f);
- }
- // The centroid is in the umbra area, so the opacity is considered as 1.0.
- AlphaVertex::set(&shadowVertices[SHADOW_VERTEX_COUNT - 1], centroid.x, centroid.y, 1.0f);
-#if DEBUG_SHADOW
- for (int i = 0; i < currentIndex; i++) {
- ALOGD("spot shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
- shadowVertices[i].y, shadowVertices[i].alpha);
+ dx * umbraDistance + centroid.x, dy * umbraDistance + centroid.y, 1.0f);
+
+ // occluded umbra ring
+ if (hasOccludedUmbraArea) {
+ float occludedUmbraDistance = occludedUmbraDistPerRay[rayIndex];
+ AlphaVertex::set(&shadowVertices[2 * rays + rayIndex],
+ dx * occludedUmbraDistance + centroid.x,
+ dy * occludedUmbraDistance + centroid.y, 1.0f);
+ } else {
+ // Put all vertices of the occluded umbra ring at the centroid.
+ shadowVertices[2 * rays + rayIndex] = centroidXYA;
+ }
}
-#endif
}
/**
@@ -775,17 +831,6 @@ void SpotShadow::smoothPolygon(int level, int rays, float* rayDist) {
}
}
-/**
- * Calculate the number of vertex we will create given a number of rays and layers
- *
- * @param rays number of points around the polygons you want
- * @param layers number of layers of triangle strips you need
- * @return number of vertex (multiply by 3 for number of floats)
- */
-int SpotShadow::getStripSize(int rays) {
- return (2 + rays + (2 * (rays + 1)));
-}
-
#if DEBUG_SHADOW
#define TEST_POINT_NUMBER 128
@@ -837,7 +882,7 @@ bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength,
bool isCCWOrCoLinear = (delta >= EPSILON);
if (isCCWOrCoLinear) {
- ALOGE("(Error Type 2): polygon (%s) is not a convex b/c start (x %f, y %f),"
+ ALOGW("(Error Type 2): polygon (%s) is not a convex b/c start (x %f, y %f),"
"middle (x %f, y %f) and end (x %f, y %f) , delta is %f !!!",
name, start.x, start.y, middle.x, middle.y, end.x, end.y, delta);
isConvex = false;
@@ -879,14 +924,14 @@ void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length,
if (testPointInsidePolygon(testPoint, intersection, intersectionLength)) {
if (!testPointInsidePolygon(testPoint, poly1, poly1Length)) {
dumpPoly = true;
- ALOGE("(Error Type 1): one point (%f, %f) in the intersection is"
+ ALOGW("(Error Type 1): one point (%f, %f) in the intersection is"
" not in the poly1",
testPoint.x, testPoint.y);
}
if (!testPointInsidePolygon(testPoint, poly2, poly2Length)) {
dumpPoly = true;
- ALOGE("(Error Type 1): one point (%f, %f) in the intersection is"
+ ALOGW("(Error Type 1): one point (%f, %f) in the intersection is"
" not in the poly2",
testPoint.x, testPoint.y);
}
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index 7839dc3..599d37e 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -26,19 +26,20 @@ namespace uirenderer {
class SpotShadow {
public:
- static void createSpotShadow(const Vector3* poly, int polyLength,
- const Vector3& lightCenter, float lightSize, int lightVertexCount,
- VertexBuffer& retStrips);
+ static VertexBufferMode createSpotShadow(bool isCasterOpaque, const Vector3* poly,
+ int polyLength, const Vector3& lightCenter, float lightSize,
+ int lightVertexCount, VertexBuffer& retStrips);
private:
- static void computeSpotShadow(const Vector3* lightPoly, int lightPolyLength,
- const Vector3& lightCenter, const Vector3* poly, int polyLength,
- VertexBuffer& retstrips);
+ static int calculateOccludedUmbra(const Vector2* umbra, int umbraLength,
+ const Vector3* poly, int polyLength, Vector2* occludedUmbra);
+ static void computeSpotShadow(bool isCasterOpaque, const Vector3* lightPoly,
+ int lightPolyLength, const Vector3& lightCenter, const Vector3* poly,
+ int polyLength, VertexBuffer& retstrips);
static void computeLightPolygon(int points, const Vector3& lightCenter,
float size, Vector3* ret);
- static int getStripSize(int rays);
static void smoothPolygon(int level, int rays, float* rayDist);
static float rayIntersectPoly(const Vector2* poly, int polyLength,
const Vector2& point, float dx, float dy);
@@ -46,7 +47,7 @@ private:
static void xsort(Vector2* points, int pointsLength);
static int hull(Vector2* points, int pointsLength, Vector2* retPoly);
static bool ccw(double ax, double ay, double bx, double by, double cx, double cy);
- static int intersection(Vector2* poly1, int poly1length, Vector2* poly2, int poly2length);
+ static int intersection(const Vector2* poly1, int poly1length, Vector2* poly2, int poly2length);
static void sort(Vector2* poly, int polyLength, const Vector2& center);
static void swap(Vector2* points, int i, int j);
@@ -55,13 +56,14 @@ private:
static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len);
static void makeClockwise(Vector2* polygon, int len);
- static bool isClockwise(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);
- static void generateTriangleStrip(const Vector2* penumbra, int penumbraLength,
- const Vector2* umbra, int umbraLength, VertexBuffer& retstrips);
+ static void generateTriangleStrip(bool isCasterOpaque, const Vector2* penumbra,
+ int penumbraLength, const Vector2* umbra, int umbraLength,
+ const Vector3* poly, int polyLength, VertexBuffer& retstrips);
#if DEBUG_SHADOW
// Verification utility function.