summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorztenghui <ztenghui@google.com>2014-02-25 23:20:06 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-02-25 23:20:06 +0000
commit8198c3a8f525c07e2b848852f6ad3e351e3b5461 (patch)
tree342d10b2f40fd3db65e41cb98b7ee29412b34683 /libs
parenta1f1a3c573acd91024fda0ceb3b921c73b186963 (diff)
parent63d41abb40b3ce40d8b9bccb1cf186e8158a3687 (diff)
downloadframeworks_base-8198c3a8f525c07e2b848852f6ad3e351e3b5461.zip
frameworks_base-8198c3a8f525c07e2b848852f6ad3e351e3b5461.tar.gz
frameworks_base-8198c3a8f525c07e2b848852f6ad3e351e3b5461.tar.bz2
Merge "Use pre-computed index to draw the shadow."
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/AmbientShadow.cpp140
-rw-r--r--libs/hwui/AmbientShadow.h8
-rw-r--r--libs/hwui/Caches.cpp30
-rw-r--r--libs/hwui/Caches.h7
-rw-r--r--libs/hwui/FontRenderer.cpp2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp39
-rw-r--r--libs/hwui/OpenGLRenderer.h9
-rw-r--r--libs/hwui/ShadowTessellator.cpp85
-rw-r--r--libs/hwui/ShadowTessellator.h41
-rw-r--r--libs/hwui/SpotShadow.cpp141
-rw-r--r--libs/hwui/SpotShadow.h11
11 files changed, 256 insertions, 257 deletions
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 1f5d26c..4935b34 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -21,6 +21,7 @@
#include <utils/Vector.h>
#include "AmbientShadow.h"
+#include "ShadowTessellator.h"
#include "Vertex.h"
namespace android {
@@ -34,9 +35,7 @@ namespace uirenderer {
* array.
* @param vertexCount The length of caster's polygon in terms of number of
* vertices.
- * @param rays The number of rays shooting out from the centroid.
- * @param layers The number of rings outside the polygon.
- * @param strength The darkness of the shadow, the higher, the darker.
+ * @param centroid3d The centroid of the shadow caster.
* @param heightFactor The factor showing the higher the object, the lighter the
* shadow.
* @param geomFactor The factor scaling the geometry expansion along the normal.
@@ -45,21 +44,18 @@ namespace uirenderer {
* triangle strips mode.
*/
void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount,
- int rays, int layers, float strength, float heightFactor, float geomFactor,
+ const Vector3& centroid3d, float heightFactor, float geomFactor,
VertexBuffer& shadowVertexBuffer) {
-
+ const int rays = SHADOW_RAY_COUNT;
+ const int layers = SHADOW_LAYER_COUNT;
// Validate the inputs.
- if (strength <= 0 || heightFactor <= 0 || layers <= 0 || rays <= 0
+ if (vertexCount < 3 || heightFactor <= 0 || layers <= 0 || rays <= 0
|| geomFactor <= 0) {
#if DEBUG_SHADOW
ALOGE("Invalid input for createAmbientShadow(), early return!");
#endif
return;
}
- int rings = layers + 1;
- int size = rays * rings;
- Vector2 centroid;
- calculatePolygonCentroid(vertices, vertexCount, centroid);
Vector<Vector2> dir; // TODO: use C++11 unique_ptr
dir.setCapacity(rays);
@@ -75,7 +71,7 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount
int edgeIndex;
float edgeFraction;
float rayDistance;
- calculateIntersection(vertices, vertexCount, centroid, dir[i], edgeIndex,
+ calculateIntersection(vertices, vertexCount, centroid3d, dir[i], edgeIndex,
edgeFraction, rayDistance);
rayDist[i] = rayDistance;
if (edgeIndex < 0 || edgeIndex >= vertexCount) {
@@ -91,8 +87,7 @@ 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.
- const int shadowVertexCount = (2 + rays + ((layers) * 2 * (rays + 1)));
- AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(shadowVertexCount);
+ AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(SHADOW_VERTEX_COUNT);
// Calculate the vertex of the shadows.
//
@@ -101,110 +96,45 @@ 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.
- int currentIndex = 0;
- for (int r = 0; r < layers; r++) {
- int firstInLayer = currentIndex;
- for (int i = 0; i < rays; i++) {
+ int currentVertexIndex = 0;
+ for (int layerIndex = 0; layerIndex <= layers; layerIndex++) {
+ for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
Vector2 normal(1.0f, 0.0f);
- calculateNormal(rays, i, dir.array(), rayDist, normal);
+ calculateNormal(rays, rayIndex, dir.array(), rayDist, normal);
- float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
+ float opacity = 1.0 / (1 + rayHeight[rayIndex] / heightFactor);
// The vertex should be start from rayDist[i] then scale the
// normalizeNormal!
- Vector2 intersection = dir[i] * rayDist[i] + centroid;
-
- // Use 2 rings' vertices to complete one layer's strip
- for (int j = r; j < (r + 2); j++) {
- float jf = j / (float)(rings - 1);
-
- float expansionDist = rayHeight[i] / heightFactor * geomFactor * jf;
- AlphaVertex::set(&shadowVertices[currentIndex],
- intersection.x + normal.x * expansionDist,
- intersection.y + normal.y * expansionDist,
- (1 - jf) * opacity);
- currentIndex++;
- }
+ Vector2 intersection = dir[rayIndex] * rayDist[rayIndex] +
+ Vector2(centroid3d.x, centroid3d.y);
+
+ float layerRatio = layerIndex / (float)(layers);
+ // The higher the intersection is, the further the ambient shadow expanded.
+ float expansionDist = rayHeight[rayIndex] / heightFactor *
+ geomFactor * (1 - layerRatio);
+ AlphaVertex::set(&shadowVertices[currentVertexIndex++],
+ intersection.x + normal.x * expansionDist,
+ intersection.y + normal.y * expansionDist,
+ layerRatio * opacity);
}
- // From one layer to the next, we need to duplicate the vertex to
- // continue as a single strip.
- shadowVertices[currentIndex] = shadowVertices[firstInLayer];
- currentIndex++;
- shadowVertices[currentIndex] = shadowVertices[firstInLayer + 1];
- currentIndex++;
}
+ float centroidAlpha = 1.0 / (1 + centroid3d.z / heightFactor);
+ AlphaVertex::set(&shadowVertices[currentVertexIndex++],
+ centroid3d.x, centroid3d.y, centroidAlpha);
- // After all rings are done, we need to jump into the polygon.
- // In order to keep everything in a strip, we need to duplicate the last one
- // of the rings and the first one inside the polygon.
- int lastInRings = currentIndex - 1;
- shadowVertices[currentIndex] = shadowVertices[lastInRings];
- currentIndex++;
-
- // We skip one and fill it back after we finish the internal triangles.
- currentIndex++;
- int firstInternal = currentIndex;
-
- // Combine the internal area of the polygon into a triangle strip, too.
- // The basic idea is zig zag between the intersection points.
- // 0 -> (n - 1) -> 1 -> (n - 2) ...
- for (int k = 0; k < rays; k++) {
- int i = k / 2;
- if ((k & 1) == 1) { // traverse the inside in a zig zag pattern for strips
- i = rays - i - 1;
- }
- float cast = rayDist[i] * (1 + rayHeight[i] / heightFactor);
- float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
- float t = rayDist[i];
-
- AlphaVertex::set(&shadowVertices[currentIndex], dir[i].x * t + centroid.x,
- dir[i].y * t + centroid.y, opacity);
- currentIndex++;
+#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);
}
-
- currentIndex = firstInternal - 1;
- shadowVertices[currentIndex] = shadowVertices[firstInternal];
-}
-
-/**
- * Calculate the centroid of a given polygon.
- *
- * @param vertices The shadow caster's polygon, which is represented in a
- * straight Vector3 array.
- * @param vertexCount The length of caster's polygon in terms of number of vertices.
- *
- * @param centroid Return the centroid of the polygon.
- */
-void AmbientShadow::calculatePolygonCentroid(const Vector3* vertices, int vertexCount,
- Vector2& centroid) {
- float sumx = 0;
- float sumy = 0;
- int p1 = vertexCount - 1;
- float area = 0;
- for (int p2 = 0; p2 < vertexCount; p2++) {
- float x1 = vertices[p1].x;
- float y1 = vertices[p1].y;
- float x2 = vertices[p2].x;
- float y2 = vertices[p2].y;
- float a = (x1 * y2 - x2 * y1);
- sumx += (x1 + x2) * a;
- sumy += (y1 + y2) * a;
- area += a;
- p1 = p2;
+ 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);
}
-
- if (area == 0) {
-#if DEBUG_SHADOW
- ALOGE("Area is 0!");
#endif
- centroid.x = vertices[0].x;
- centroid.y = vertices[0].y;
- } else {
- centroid.x = sumx / (3 * area);
- centroid.y = sumy / (3 * area);
- }
}
/**
@@ -238,7 +168,7 @@ void AmbientShadow::calculateRayDirections(int rays, Vector2* dir) {
* @param outRayDist Return the ray distance from centroid to the intersection.
*/
void AmbientShadow::calculateIntersection(const Vector3* vertices, int vertexCount,
- const Vector2& start, const Vector2& dir, int& outEdgeIndex,
+ const Vector3& start, const Vector2& dir, int& outEdgeIndex,
float& outEdgeFraction, float& outRayDist) {
float startX = start.x;
float startY = start.y;
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 079bdb7..20d1384 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -34,17 +34,15 @@ namespace uirenderer {
*/
class AmbientShadow {
public:
- static void createAmbientShadow(const Vector3* poly, int polyLength, int rays,
- int layers, float strength, float heightFactor, float geomFactor,
+ static void createAmbientShadow(const Vector3* poly, int polyLength,
+ const Vector3& centroid3d, float heightFactor, float geomFactor,
VertexBuffer& shadowVertexBuffer);
private:
- static void calculatePolygonCentroid(const Vector3* poly, int len, Vector2& centroid);
-
static void calculateRayDirections(int rays, Vector2* dir);
static void calculateIntersection(const Vector3* poly, int nbVertices,
- const Vector2& start, const Vector2& dir, int& outEdgeIndex,
+ const Vector3& start, const Vector2& dir, int& outEdgeIndex,
float& outEdgeFraction, float& outRayDist);
static void calculateNormal(int rays, int currentRayIndex, const Vector2* dir,
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 21cf658..1d58d96 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -23,6 +23,7 @@
#include "DisplayListRenderer.h"
#include "Properties.h"
#include "LayerRenderer.h"
+#include "ShadowTessellator.h"
namespace android {
@@ -86,7 +87,7 @@ bool Caches::init() {
mRegionMesh = NULL;
mMeshIndices = 0;
-
+ mShadowStripsIndices = 0;
blend = false;
lastSrcMode = GL_ZERO;
lastDstMode = GL_ZERO;
@@ -223,6 +224,9 @@ void Caches::terminate() {
mMeshIndices = 0;
mRegionMesh = NULL;
+ glDeleteBuffers(1, &mShadowStripsIndices);
+ mShadowStripsIndices = 0;
+
fboCache.clear();
programCache.clear();
@@ -404,7 +408,7 @@ bool Caches::unbindMeshBuffer() {
return false;
}
-bool Caches::bindIndicesBuffer(const GLuint buffer) {
+bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
if (mCurrentIndicesBuffer != buffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
mCurrentIndicesBuffer = buffer;
@@ -413,7 +417,7 @@ bool Caches::bindIndicesBuffer(const GLuint buffer) {
return false;
}
-bool Caches::bindIndicesBuffer() {
+bool Caches::bindQuadIndicesBuffer() {
if (!mMeshIndices) {
uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
@@ -428,7 +432,7 @@ bool Caches::bindIndicesBuffer() {
}
glGenBuffers(1, &mMeshIndices);
- bool force = bindIndicesBuffer(mMeshIndices);
+ bool force = bindIndicesBufferInternal(mMeshIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
regionIndices, GL_STATIC_DRAW);
@@ -436,7 +440,23 @@ bool Caches::bindIndicesBuffer() {
return force;
}
- return bindIndicesBuffer(mMeshIndices);
+ return bindIndicesBufferInternal(mMeshIndices);
+}
+
+bool Caches::bindShadowIndicesBuffer() {
+ if (!mShadowStripsIndices) {
+ uint16_t* shadowIndices = new uint16_t[SHADOW_INDEX_COUNT];
+ ShadowTessellator::generateShadowIndices(shadowIndices);
+ glGenBuffers(1, &mShadowStripsIndices);
+ bool force = bindIndicesBufferInternal(mShadowStripsIndices);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, SHADOW_INDEX_COUNT * sizeof(uint16_t),
+ shadowIndices, GL_STATIC_DRAW);
+
+ delete[] shadowIndices;
+ return force;
+ }
+
+ return bindIndicesBufferInternal(mShadowStripsIndices);
}
bool Caches::unbindIndicesBuffer() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 2cc15cc..8c0c508 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -190,8 +190,8 @@ public:
* Binds a global indices buffer that can draw up to
* gMaxNumberOfQuads quads.
*/
- bool bindIndicesBuffer();
- bool bindIndicesBuffer(const GLuint buffer);
+ bool bindQuadIndicesBuffer();
+ bool bindShadowIndicesBuffer();
bool unbindIndicesBuffer();
/**
@@ -381,6 +381,8 @@ private:
void initConstraints();
void initStaticProperties();
+ bool bindIndicesBufferInternal(const GLuint buffer);
+
static void eventMarkNull(GLsizei length, const GLchar* marker) { }
static void startMarkNull(GLsizei length, const GLchar* marker) { }
static void endMarkNull() { }
@@ -417,6 +419,7 @@ private:
// Global index buffer
GLuint mMeshIndices;
+ GLuint mShadowStripsIndices;
mutable Mutex mGarbageLock;
Vector<Layer*> mLayerGarbage;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index b79a3b0..b52003c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -498,7 +498,7 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
}
checkTextureUpdate();
- caches.bindIndicesBuffer();
+ caches.bindQuadIndicesBuffer();
if (!mDrawn) {
// If returns true, a VBO was bound and we must
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 75bf716..9ac2792 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1902,7 +1902,7 @@ void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
} else {
force = mCaches.unbindMeshBuffer();
}
- mCaches.bindIndicesBuffer();
+ mCaches.bindQuadIndicesBuffer();
mCaches.bindPositionVertexPointer(force, vertices);
if (mCaches.currentProgram->texCoords >= 0) {
@@ -1912,7 +1912,7 @@ void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
bool force = mCaches.unbindMeshBuffer();
- mCaches.bindIndicesBuffer();
+ mCaches.bindQuadIndicesBuffer();
mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
}
@@ -2387,10 +2387,9 @@ status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry*
return DrawGlInfo::kStatusDrew;
}
-status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, const SkPaint* paint,
- bool useOffset) {
+status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode,
+ const VertexBuffer& vertexBuffer, const SkPaint* paint, bool useOffset) {
// not missing call to quickReject/dirtyLayer, always done at a higher level
-
if (!vertexBuffer.getVertexCount()) {
// no vertices to draw
return DrawGlInfo::kStatusDone;
@@ -2416,19 +2415,24 @@ status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, cons
bool force = mCaches.unbindMeshBuffer();
mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
mCaches.resetTexCoordsVertexPointer();
- mCaches.unbindIndicesBuffer();
+
int alphaSlot = -1;
if (isAA) {
void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
-
// TODO: avoid enable/disable in back to back uses of the alpha attribute
glEnableVertexAttribArray(alphaSlot);
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
}
- glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
+ if (mode == kVertexBufferMode_Standard) {
+ mCaches.unbindIndicesBuffer();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
+ } else {
+ mCaches.bindShadowIndicesBuffer();
+ glDrawElements(GL_TRIANGLE_STRIP, SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
+ }
if (isAA) {
glDisableVertexAttribArray(alphaSlot);
@@ -2457,7 +2461,7 @@ status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint
dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
}
- return drawVertexBuffer(vertexBuffer, paint);
+ return drawVertexBuffer(kVertexBufferMode_Standard, vertexBuffer, paint);
}
/**
@@ -2488,7 +2492,7 @@ status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint
dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
bool useOffset = !paint->isAntiAlias();
- return drawVertexBuffer(buffer, paint, useOffset);
+ return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
}
status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
@@ -2508,7 +2512,7 @@ status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPain
dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
bool useOffset = !paint->isAntiAlias();
- return drawVertexBuffer(buffer, paint, useOffset);
+ return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
}
status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -3231,13 +3235,20 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp
casterTransform.mapPoint3d(casterPolygon[i]);
}
+ // map the centroid of the caster into 3d
+ Vector2 centroid = ShadowTessellator::centroid2d(
+ reinterpret_cast<const Vector2*>(casterVertices2d.array()),
+ casterVertexCount);
+ Vector3 centroid3d(centroid.x, centroid.y, 0);
+ casterTransform.mapPoint3d(centroid3d);
+
// draw caster's shadows
if (mCaches.propertyAmbientShadowStrength > 0) {
paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
VertexBuffer ambientShadowVertexBuffer;
ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
- ambientShadowVertexBuffer);
- drawVertexBuffer(ambientShadowVertexBuffer, &paint);
+ centroid3d, ambientShadowVertexBuffer);
+ drawVertexBuffer(kVertexBufferMode_Shadow, ambientShadowVertexBuffer, &paint);
}
if (mCaches.propertySpotShadowStrength > 0) {
@@ -3249,7 +3260,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp
lightPosScale, *currentTransform(), getWidth(), getHeight(),
spotShadowVertexBuffer);
- drawVertexBuffer(spotShadowVertexBuffer, &paint);
+ drawVertexBuffer(kVertexBufferMode_Shadow, spotShadowVertexBuffer, &paint);
}
return DrawGlInfo::kStatusDrew;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e4d133d..03beae3 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -117,6 +117,11 @@ enum ModelViewMode {
kModelViewMode_TranslateAndScale = 1,
};
+enum VertexBufferMode {
+ kVertexBufferMode_Standard = 0,
+ kVertexBufferMode_Shadow = 1
+};
+
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
@@ -629,8 +634,8 @@ private:
* @param paint The paint to render with
* @param useOffset Offset the vertexBuffer (used in drawing non-AA lines)
*/
- status_t drawVertexBuffer(const VertexBuffer& vertexBuffer, const SkPaint* paint,
- bool useOffset = false);
+ status_t drawVertexBuffer(VertexBufferMode mode, const VertexBuffer& vertexBuffer,
+ const SkPaint* paint, bool useOffset = false);
/**
* Renders the convex hull defined by the specified path as a strip of polygons.
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 7700ea0..526772b 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -31,18 +31,16 @@ static inline T max(T a, T b) {
return a > b ? a : b;
}
-void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount,
+void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& centroid3d,
VertexBuffer& shadowVertexBuffer) {
// A bunch of parameters to tweak the shadow.
// TODO: Allow some of these changable by debug settings or APIs.
- const int rays = 128;
- const int layers = 2;
- const float strength = 0.5;
const float heightFactor = 128;
const float geomFactor = 64;
- AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount, rays, layers, strength,
- heightFactor, geomFactor, shadowVertexBuffer);
+ AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount,
+ centroid3d, heightFactor, geomFactor, shadowVertexBuffer);
}
@@ -51,9 +49,6 @@ void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int c
int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
// A bunch of parameters to tweak the shadow.
// TODO: Allow some of these changable by debug settings or APIs.
- const int rays = 256;
- const int layers = 2;
- const float strength = 0.5;
int maximal = max(screenWidth, screenHeight);
Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
maximal * lightPosScale.z);
@@ -70,9 +65,77 @@ void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int c
const float lightSize = maximal / 4;
const int lightVertexCount = 16;
- SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter, lightSize,
- lightVertexCount, rays, layers, strength, shadowVertexBuffer);
+ SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter,
+ lightSize, lightVertexCount, shadowVertexBuffer);
}
+
+void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
+ int currentIndex = 0;
+ const int layers = SHADOW_LAYER_COUNT;
+ const int rays = SHADOW_RAY_COUNT;
+ // For the penumbra area.
+ for (int i = 0; i < layers; i++) {
+ for (int j = 0; j < rays; j++) {
+ shadowIndices[currentIndex++] = i * rays + j;
+ shadowIndices[currentIndex++] = (i + 1) * rays + j;
+ }
+ // To close the loop, back to the ray 0.
+ shadowIndices[currentIndex++] = i * rays;
+ shadowIndices[currentIndex++] = (i + 1) * rays;
+ }
+ uint16_t base = layers * rays;
+ uint16_t centroidIndex = (layers + 1) * rays;
+ // For the umbra area, using strips to simulate the fans.
+ for (int k = 0; k < rays; k++) {
+ shadowIndices[currentIndex++] = base + k;
+ shadowIndices[currentIndex++] = centroidIndex;
+ }
+ shadowIndices[currentIndex++] = base;
+
+#if DEBUG_SHADOW
+ if (currentIndex != SHADOW_INDEX_COUNT) {
+ ALOGE("vertex index count is wrong. current %d, expected %d",
+ currentIndex, SHADOW_INDEX_COUNT);
+ }
+ for (int i = 0; i < SHADOW_INDEX_COUNT; i++) {
+ ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
+ }
+#endif
+}
+
+/**
+ * Calculate the centroid of a 2d polygon.
+ *
+ * @param poly The polygon, which is represented in a Vector2 array.
+ * @param polyLength The length of the polygon in terms of number of vertices.
+ * @return the centroid of the polygon.
+ */
+Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
+ double sumx = 0;
+ double sumy = 0;
+ int p1 = polyLength - 1;
+ double area = 0;
+ for (int p2 = 0; p2 < polyLength; p2++) {
+ double x1 = poly[p1].x;
+ double y1 = poly[p1].y;
+ double x2 = poly[p2].x;
+ double y2 = poly[p2].y;
+ double a = (x1 * y2 - x2 * y1);
+ sumx += (x1 + x2) * a;
+ sumy += (y1 + y2) * a;
+ area += a;
+ p1 = p2;
+ }
+
+ Vector2 centroid = poly[0];
+ if (area != 0) {
+ centroid = Vector2(sumx / (3 * area), sumy / (3 * area));
+ } else {
+ ALOGE("Area is 0 while computing centroid!");
+ }
+ return centroid;
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index ef95609..c49fdcb 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -20,18 +20,57 @@
#include "Debug.h"
#include "Matrix.h"
+#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
+// All SHADOW_* are used to define all the geometry property of shadows.
+// Use a simplified example to illustrate the geometry setup here.
+// 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.
+//
+// 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
+//
+// 3
+
+// The total number of rays starting from the centroid of shadow area, in order
+// to generate the shadow geometry.
+#define SHADOW_RAY_COUNT 256
+
+// The total number of layers in the outer shadow area, 1 being the minimum.
+#define SHADOW_LAYER_COUNT 2
+
+// The total number of all the vertices representing the shadow.
+#define SHADOW_VERTEX_COUNT ((SHADOW_LAYER_COUNT + 1) * SHADOW_RAY_COUNT + 1)
+
+// 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) * \
+ SHADOW_LAYER_COUNT)
+
class ShadowTessellator {
public:
- static void tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount,
+ static void tessellateAmbientShadow(const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& centroid3d,
VertexBuffer& shadowVertexBuffer);
static void tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
const Vector3& lightPosScale, const mat4& receiverTransform,
int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer);
+
+ static void generateShadowIndices(uint16_t* shadowIndices);
+
+ static Vector2 centroid2d(const Vector2* poly, int polyLength);
}; // ShadowTessellator
}; // namespace uirenderer
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 4c2299e..22d735b 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <utils/Log.h>
+#include "ShadowTessellator.h"
#include "SpotShadow.h"
#include "Vertex.h"
@@ -70,35 +71,6 @@ float SpotShadow::rayIntersectPoly(const Vector2* poly, int polyLength,
}
/**
- * Calculate the centroid of a 2d polygon.
- *
- * @param poly The polygon, which is represented in a Vector2 array.
- * @param polyLength The length of the polygon in terms of number of vertices.
- * @return the centroid of the polygon.
- */
-Vector2 SpotShadow::centroid2d(const Vector2* poly, int polyLength) {
- double sumx = 0;
- double sumy = 0;
- int p1 = polyLength - 1;
- double area = 0;
- for (int p2 = 0; p2 < polyLength; p2++) {
- double x1 = poly[p1].x;
- double y1 = poly[p1].y;
- double x2 = poly[p2].x;
- double y2 = poly[p2].y;
- double a = (x1 * y2 - x2 * y1);
- sumx += (x1 + x2) * a;
- sumy += (y1 + y2) * a;
- area += a;
- p1 = p2;
- }
-
- double centroidx = sumx / (3 * area);
- double centroidy = sumy / (3 * area);
- return Vector2((float)centroidx, (float)centroidy);
-}
-
-/**
* Sort points by their X coordinates
*
* @param points the points as a Vector2 array.
@@ -550,20 +522,17 @@ void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter,
* @param lightCenter the center of the light
* @param lightSize the radius of the light source
* @param lightVertexCount the vertex counter for the light polygon
-* @param rays the number of vertexes to create along the edges of the shadow
-* @param layers the number of layers of triangles strips to create
-* @param strength the "darkness" of the shadow
* @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
* empty strip if error.
*
*/
void SpotShadow::createSpotShadow(const Vector3* poly, int polyLength,
const Vector3& lightCenter, float lightSize, int lightVertexCount,
- int rays, int layers, float strength, VertexBuffer& retStrips) {
+ VertexBuffer& retStrips) {
Vector3 light[lightVertexCount * 3];
computeLightPolygon(lightVertexCount, lightCenter, lightSize, light);
- computeSpotShadow(light, lightVertexCount, lightCenter,
- poly, polyLength, rays, layers, strength, retStrips);
+ computeSpotShadow(light, lightVertexCount, lightCenter, poly, polyLength,
+ retStrips);
}
/**
@@ -573,15 +542,12 @@ void SpotShadow::createSpotShadow(const Vector3* poly, int polyLength,
* @param lightPolyLength number of vertexes of the light source polygon
* @param poly x,y,z vertexes of a convex polygon that occludes the light source
* @param polyLength number of vertexes of the occluding polygon
- * @param rays the number of vertexes to create along the edges of the shadow
- * @param layers the number of layers of triangles strips to create
- * @param strength the "darkness" of the shadow
* @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,
- int rays, int layers, float strength, VertexBuffer& shadowTriangleStrip) {
+ VertexBuffer& shadowTriangleStrip) {
// Point clouds for all the shadowed vertices
Vector2 shadowRegion[lightPolyLength * polyLength];
// Shadow polygon from one point light.
@@ -671,7 +637,8 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength
// Shrink the centroid's shadow by 10%.
// TODO: Study the magic number of 10%.
- Vector2 shadowCentroid = centroid2d(fakeUmbra, polyLength);
+ Vector2 shadowCentroid =
+ ShadowTessellator::centroid2d(fakeUmbra, polyLength);
for (int i = 0; i < polyLength; i++) {
fakeUmbra[i] = shadowCentroid * (1.0f - SHADOW_SHRINK_SCALE) +
fakeUmbra[i] * SHADOW_SHRINK_SCALE;
@@ -686,7 +653,7 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength
}
generateTriangleStrip(penumbra, penumbraLength, umbra, umbraLength,
- rays, layers, strength, shadowTriangleStrip);
+ shadowTriangleStrip);
}
/**
@@ -696,22 +663,18 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength
* @param penumbraLength The number of vertexes in the outer polygon
* @param umbra The inner outer polygon x,y vertexes
* @param umbraLength The number of vertexes in the inner polygon
- * @param rays The number of points along the polygons to create
- * @param layers The number of layers of triangle strips between the umbra and penumbra
- * @param strength The max alpha of the umbra
* @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, int rays, int layers,
- float strength, VertexBuffer& shadowTriangleStrip) {
-
- int rings = layers + 1;
- int size = rays * rings;
+ const Vector2* umbra, int umbraLength, VertexBuffer& shadowTriangleStrip) {
+ const int rays = SHADOW_RAY_COUNT;
+ const int layers = SHADOW_LAYER_COUNT;
+ int size = rays * (layers + 1);
float step = M_PI * 2 / rays;
// Centroid of the umbra.
- Vector2 centroid = centroid2d(umbra, umbraLength);
+ Vector2 centroid = ShadowTessellator::centroid2d(umbra, umbraLength);
#if DEBUG_SHADOW
ALOGD("centroid2d = %f , %f", centroid.x, centroid.y);
#endif
@@ -741,57 +704,29 @@ void SpotShadow::generateTriangleStrip(const Vector2* penumbra, int penumbraLeng
int stripSize = getStripSize(rays, layers);
AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(stripSize);
int currentIndex = 0;
- int firstInLayer = 0;
- // Calculate the vertex values in the penumbra area.
- for (int r = 0; r < layers; r++) {
- firstInLayer = currentIndex;
- for (int i = 0; i < rays; i++) {
- float dx = sinf(step * i);
- float dy = cosf(step * i);
-
- for (int j = r; j < (r + 2); j++) {
- float layerRatio = j / (float)(rings - 1);
- float deltaDist = layerRatio * (umbraDistPerRay[i] - penumbraDistPerRay[i]);
- float currentDist = penumbraDistPerRay[i] + deltaDist;
- float op = calculateOpacity(layerRatio, deltaDist);
- AlphaVertex::set(&shadowVertices[currentIndex++],
- dx * currentDist + centroid.x,
- dy * currentDist + centroid.y,
- layerRatio * op * strength);
- }
- }
-
- // Duplicate the vertices from one layer to another one to make triangle
- // strip.
- shadowVertices[currentIndex++] = shadowVertices[firstInLayer + 0];
- shadowVertices[currentIndex++] = shadowVertices[firstInLayer + 1];
- }
- int lastInPenumbra = currentIndex - 1;
- shadowVertices[currentIndex++] = shadowVertices[lastInPenumbra];
-
- // Preallocate the vertices (index as [firstInUmbra - 1]) for jumping from
- // the penumbra to umbra.
- currentIndex++;
- int firstInUmbra = currentIndex;
-
- // traverse the umbra area in a zig zag pattern for strips.
- const int innerRingStartIndex = firstInLayer + 1;
- for (int k = 0; k < rays; k++) {
- int i = k / 2;
- if ((k & 1) == 1) {
- i = rays - i - 1;
+ // Calculate the vertices (x, y, alpha) in the shadow area.
+ for (int layerIndex = 0; layerIndex <= layers; layerIndex++) {
+ for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
+ float dx = sinf(step * rayIndex);
+ float dy = cosf(step * rayIndex);
+ float layerRatio = layerIndex / (float) layers;
+ float deltaDist = layerRatio *
+ (umbraDistPerRay[rayIndex] - penumbraDistPerRay[rayIndex]);
+ float currentDist = penumbraDistPerRay[rayIndex] + deltaDist;
+ float op = calculateOpacity(layerRatio);
+ AlphaVertex::set(&shadowVertices[currentIndex++],
+ dx * currentDist + centroid.x, dy * currentDist + centroid.y, op);
}
- // copy already computed values for umbra vertices
- shadowVertices[currentIndex++] = shadowVertices[innerRingStartIndex + i * 2];
}
-
- // Back fill the one vertex for jumping from penumbra to umbra.
- shadowVertices[firstInUmbra - 1] = shadowVertices[firstInUmbra];
-
+ // The centroid is in the umbra area, so the opacity is considered as 1.0.
+ AlphaVertex::set(&shadowVertices[currentIndex++], centroid.x, centroid.y, 1.0);
#if DEBUG_SHADOW
+ if (currentIndex != SHADOW_VERTEX_COUNT) {
+ ALOGE("number of vertex generated for spot shadow is wrong!");
+ }
for (int i = 0; i < currentIndex; i++) {
- ALOGD("shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
+ ALOGD("spot shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
shadowVertices[i].y, shadowVertices[i].alpha);
}
#endif
@@ -819,17 +754,15 @@ void SpotShadow::smoothPolygon(int level, int rays, float* rayDist) {
}
/**
- * Calculate the opacity according to the distance and falloff ratio.
+ * Calculate the opacity according to the distance. Ideally, the opacity is 1.0
+ * in the umbra area, and fall off to 0.0 till the edge of penumbra area.
*
- * @param distRatio The distance ratio of current sample between umbra and
- * penumbra area.
- * @param deltaDist The distance between current sample to the penumbra area.
+ * @param layerRatio The distance ratio of current sample between umbra and penumbra area.
+ * Penumbra edge is 0 and umbra edge is 1.
* @return The opacity according to the distance between umbra and penumbra.
*/
-float SpotShadow::calculateOpacity(float distRatio, float deltaDist) {
- // TODO: Experiment on the opacity calculation.
- float falloffRatio = 1 + deltaDist * deltaDist;
- return (distRatio + 1 - 1 / falloffRatio) / 2;
+float SpotShadow::calculateOpacity(float layerRatio) {
+ return (layerRatio * layerRatio + layerRatio) / 2.0;
}
/**
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index a50d110..6727eac 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -28,24 +28,22 @@ class SpotShadow {
public:
static void createSpotShadow(const Vector3* poly, int polyLength,
const Vector3& lightCenter, float lightSize, int lightVertexCount,
- int rays, int layers, float strength, VertexBuffer& retStrips);
+ VertexBuffer& retStrips);
private:
static void computeSpotShadow(const Vector3* lightPoly, int lightPolyLength,
const Vector3& lightCenter, const Vector3* poly, int polyLength,
- int rays, int layers, float strength, VertexBuffer& retstrips);
+ VertexBuffer& retstrips);
static void computeLightPolygon(int points, const Vector3& lightCenter,
float size, Vector3* ret);
static int getStripSize(int rays, int layers);
static void smoothPolygon(int level, int rays, float* rayDist);
- static float calculateOpacity(float jf, float deltaDist);
+ static float calculateOpacity(float jf);
static float rayIntersectPoly(const Vector2* poly, int polyLength,
const Vector2& point, float dx, float dy);
- static Vector2 centroid2d(const Vector2* poly, int polyLength);
-
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);
@@ -65,8 +63,7 @@ private:
double x3, double y3, double x4, double y4, Vector2& ret);
static void generateTriangleStrip(const Vector2* penumbra, int penumbraLength,
- const Vector2* umbra, int umbraLength, int rays, int layers,
- float strength, VertexBuffer& retstrips);
+ const Vector2* umbra, int umbraLength, VertexBuffer& retstrips);
static const double EPSILON = 1e-7;