Merge "remove shadow related references"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2214272f1c
@@ -1,329 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extra vertices for the corner for smoother corner.
|
||||
* Only for outer vertices.
|
||||
* Note that we use such extra memory to avoid an extra loop.
|
||||
*/
|
||||
// For half circle, we could add EXTRA_VERTEX_PER_PI vertices.
|
||||
// Set to 1 if we don't want to have any.
|
||||
#define EXTRA_CORNER_VERTEX_PER_PI 12
|
||||
|
||||
// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
|
||||
// therefore, the maximum number of extra vertices will be twice bigger.
|
||||
#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
|
||||
|
||||
// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
|
||||
#define CORNER_RADIANS_DIVISOR (M_PI / EXTRA_CORNER_VERTEX_PER_PI)
|
||||
|
||||
/**
|
||||
* Extra vertices for the Edge for interpolation artifacts.
|
||||
* Same value for both inner and outer vertices.
|
||||
*/
|
||||
#define EXTRA_EDGE_VERTEX_PER_PI 50
|
||||
|
||||
#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
|
||||
|
||||
#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
|
||||
|
||||
/**
|
||||
* Other constants:
|
||||
*/
|
||||
#define OUTER_ALPHA (0.0f)
|
||||
|
||||
// Once the alpha difference is greater than this threshold, we will allocate extra
|
||||
// edge vertices.
|
||||
// If this is set to negative value, then all the edge will be tessellated.
|
||||
#define ALPHA_THRESHOLD (0.1f / 255.0f)
|
||||
|
||||
#include "AmbientShadow.h"
|
||||
|
||||
#include "ShadowTessellator.h"
|
||||
#include "Vertex.h"
|
||||
#include "VertexBuffer.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
/**
|
||||
* Local utility functions.
|
||||
*/
|
||||
inline Vector2 getNormalFromVertices(const Vector3* vertices, int current, int next) {
|
||||
// Convert from Vector3 to Vector2 first.
|
||||
Vector2 currentVertex = {vertices[current].x, vertices[current].y};
|
||||
Vector2 nextVertex = {vertices[next].x, vertices[next].y};
|
||||
|
||||
return ShadowTessellator::calculateNormal(currentVertex, nextVertex);
|
||||
}
|
||||
|
||||
// The input z value will be converted to be non-negative inside.
|
||||
// The output must be ranged from 0 to 1.
|
||||
inline float getAlphaFromFactoredZ(float factoredZ) {
|
||||
return 1.0 / (1 + std::max(factoredZ, 0.0f));
|
||||
}
|
||||
|
||||
inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike, const Vector3& secondVertex,
|
||||
const Vector3& centroid) {
|
||||
Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
|
||||
secondSpike.normalize();
|
||||
|
||||
int result = ShadowTessellator::getExtraVertexNumber(secondSpike, *currentSpike,
|
||||
EDGE_RADIANS_DIVISOR);
|
||||
*currentSpike = secondSpike;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Given the caster's vertex count, compute all the buffers size depending on
|
||||
// whether or not the caster is opaque.
|
||||
inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount, int* totalUmbraCount,
|
||||
int casterVertexCount, bool isCasterOpaque) {
|
||||
// Compute the size of the vertex buffer.
|
||||
int outerVertexCount =
|
||||
casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER + MAX_EXTRA_EDGE_VERTEX_NUMBER;
|
||||
int innerVertexCount = casterVertexCount + MAX_EXTRA_EDGE_VERTEX_NUMBER;
|
||||
*totalVertexCount = outerVertexCount + innerVertexCount;
|
||||
|
||||
// Compute the size of the index buffer.
|
||||
*totalIndexCount = 2 * outerVertexCount + 2;
|
||||
|
||||
// Compute the size of the umber buffer.
|
||||
// For translucent object, keep track of the umbra(inner) vertex in order to draw
|
||||
// inside. We only need to store the index information.
|
||||
*totalUmbraCount = 0;
|
||||
if (!isCasterOpaque) {
|
||||
// Add the centroid if occluder is translucent.
|
||||
(*totalVertexCount)++;
|
||||
*totalIndexCount += 2 * innerVertexCount + 1;
|
||||
*totalUmbraCount = innerVertexCount;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
|
||||
return fabsf(firstAlpha - secondAlpha) > ALPHA_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* vertices.
|
||||
* @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.
|
||||
*
|
||||
* @param shadowVertexBuffer Return an floating point array of (x, y, a)
|
||||
* triangle strips mode.
|
||||
*
|
||||
* An simple illustration:
|
||||
* For now let's mark the outer vertex as Pi, the inner as Vi, the centroid as C.
|
||||
*
|
||||
* First project the occluder to the Z=0 surface.
|
||||
* Then we got all the inner vertices. And we compute the normal for each edge.
|
||||
* According to the normal, we generate outer vertices. E.g: We generate P1 / P4
|
||||
* as extra corner vertices to make the corner looks round and smoother.
|
||||
*
|
||||
* Due to the fact that the alpha is not linear interpolated along the inner
|
||||
* edge, when the alpha is different, we may add extra vertices such as P2.1, P2.2,
|
||||
* V0.1, V0.2 to avoid the visual artifacts.
|
||||
*
|
||||
* (P3)
|
||||
* (P2) (P2.1) (P2.2) | ' (P4)
|
||||
* (P1)' | | | | '
|
||||
* ' | | | | '
|
||||
* (P0) ------------------------------------------------(P5)
|
||||
* | (V0) (V0.1) (V0.2) |(V1)
|
||||
* | |
|
||||
* | |
|
||||
* | (C) |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* (V3)-----------------------------------(V2)
|
||||
*/
|
||||
void AmbientShadow::createAmbientShadow(bool isCasterOpaque, const Vector3* casterVertices,
|
||||
int casterVertexCount, const Vector3& centroid3d,
|
||||
float heightFactor, float geomFactor,
|
||||
VertexBuffer& shadowVertexBuffer) {
|
||||
shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
|
||||
|
||||
// In order to computer the outer vertices in one loop, we need pre-compute
|
||||
// the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
|
||||
// for vertex 0.
|
||||
Vector2 previousNormal = getNormalFromVertices(casterVertices, casterVertexCount - 1, 0);
|
||||
Vector2 currentSpike = {casterVertices[0].x - centroid3d.x, casterVertices[0].y - centroid3d.y};
|
||||
currentSpike.normalize();
|
||||
float currentAlpha = getAlphaFromFactoredZ(casterVertices[0].z * heightFactor);
|
||||
|
||||
// Preparing all the output data.
|
||||
int totalVertexCount, totalIndexCount, totalUmbraCount;
|
||||
computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount, casterVertexCount,
|
||||
isCasterOpaque);
|
||||
AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
|
||||
int vertexBufferIndex = 0;
|
||||
uint16_t* indexBuffer = shadowVertexBuffer.allocIndices<uint16_t>(totalIndexCount);
|
||||
int indexBufferIndex = 0;
|
||||
uint16_t umbraVertices[totalUmbraCount];
|
||||
int umbraIndex = 0;
|
||||
|
||||
for (int i = 0; i < casterVertexCount; i++) {
|
||||
// Corner: first figure out the extra vertices we need for the corner.
|
||||
const Vector3& innerVertex = casterVertices[i];
|
||||
Vector2 currentNormal =
|
||||
getNormalFromVertices(casterVertices, i, (i + 1) % casterVertexCount);
|
||||
|
||||
int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(
|
||||
currentNormal, previousNormal, CORNER_RADIANS_DIVISOR);
|
||||
|
||||
float expansionDist = innerVertex.z * heightFactor * geomFactor;
|
||||
const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("cornerSlicesNumber is %d", cornerSlicesNumber);
|
||||
#endif
|
||||
|
||||
// Corner: fill the corner Vertex Buffer(VB) and Index Buffer(IB).
|
||||
// We fill the inner vertex first, such that we can fill the index buffer
|
||||
// inside the loop.
|
||||
int currentInnerVertexIndex = vertexBufferIndex;
|
||||
if (!isCasterOpaque) {
|
||||
umbraVertices[umbraIndex++] = vertexBufferIndex;
|
||||
}
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], casterVertices[i].x,
|
||||
casterVertices[i].y, currentAlpha);
|
||||
|
||||
const Vector3& innerStart = casterVertices[i];
|
||||
|
||||
// outerStart is the first outer vertex for this inner vertex.
|
||||
// outerLast is the last outer vertex for this inner vertex.
|
||||
Vector2 outerStart = {0, 0};
|
||||
Vector2 outerLast = {0, 0};
|
||||
// This will create vertices from [0, cornerSlicesNumber] inclusively,
|
||||
// which means minimally 2 vertices even without the extra ones.
|
||||
for (int j = 0; j <= cornerSlicesNumber; j++) {
|
||||
Vector2 averageNormal = previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
|
||||
averageNormal /= cornerSlicesNumber;
|
||||
averageNormal.normalize();
|
||||
Vector2 outerVertex;
|
||||
outerVertex.x = innerVertex.x + averageNormal.x * expansionDist;
|
||||
outerVertex.y = innerVertex.y + averageNormal.y * expansionDist;
|
||||
|
||||
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
|
||||
indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x, outerVertex.y,
|
||||
OUTER_ALPHA);
|
||||
|
||||
if (j == 0) {
|
||||
outerStart = outerVertex;
|
||||
} else if (j == cornerSlicesNumber) {
|
||||
outerLast = outerVertex;
|
||||
}
|
||||
}
|
||||
previousNormal = currentNormal;
|
||||
|
||||
// Edge: first figure out the extra vertices needed for the edge.
|
||||
const Vector3& innerNext = casterVertices[(i + 1) % casterVertexCount];
|
||||
float nextAlpha = getAlphaFromFactoredZ(innerNext.z * heightFactor);
|
||||
if (needsExtraForEdge(currentAlpha, nextAlpha)) {
|
||||
// TODO: See if we can / should cache this outer vertex across the loop.
|
||||
Vector2 outerNext;
|
||||
float expansionDist = innerNext.z * heightFactor * geomFactor;
|
||||
outerNext.x = innerNext.x + currentNormal.x * expansionDist;
|
||||
outerNext.y = innerNext.y + currentNormal.y * expansionDist;
|
||||
|
||||
// Compute the angle and see how many extra points we need.
|
||||
int extraVerticesNumber =
|
||||
getEdgeExtraAndUpdateSpike(¤tSpike, innerNext, centroid3d);
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("extraVerticesNumber %d for edge %d", extraVerticesNumber, i);
|
||||
#endif
|
||||
// Edge: fill the edge's VB and IB.
|
||||
// This will create vertices pair from [1, extraVerticesNumber - 1].
|
||||
// If there is no extra vertices created here, the edge will be drawn
|
||||
// as just 2 triangles.
|
||||
for (int k = 1; k < extraVerticesNumber; k++) {
|
||||
int startWeight = extraVerticesNumber - k;
|
||||
Vector2 currentOuter =
|
||||
(outerLast * startWeight + outerNext * k) / extraVerticesNumber;
|
||||
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
|
||||
currentOuter.y, OUTER_ALPHA);
|
||||
|
||||
if (!isCasterOpaque) {
|
||||
umbraVertices[umbraIndex++] = vertexBufferIndex;
|
||||
}
|
||||
Vector3 currentInner =
|
||||
(innerStart * startWeight + innerNext * k) / extraVerticesNumber;
|
||||
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentInner.x,
|
||||
currentInner.y,
|
||||
getAlphaFromFactoredZ(currentInner.z * heightFactor));
|
||||
}
|
||||
}
|
||||
currentAlpha = nextAlpha;
|
||||
}
|
||||
|
||||
indexBuffer[indexBufferIndex++] = 1;
|
||||
indexBuffer[indexBufferIndex++] = 0;
|
||||
|
||||
if (!isCasterOpaque) {
|
||||
// Add the centroid as the last one in the vertex buffer.
|
||||
float centroidOpacity = getAlphaFromFactoredZ(centroid3d.z * heightFactor);
|
||||
int centroidIndex = vertexBufferIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x, centroid3d.y,
|
||||
centroidOpacity);
|
||||
|
||||
for (int i = 0; i < umbraIndex; i++) {
|
||||
// Note that umbraVertices[0] is always 0.
|
||||
// So the start and the end of the umbra are using the "0".
|
||||
// And penumbra ended with 0, so a degenerated triangle is formed b/t
|
||||
// the umbra and penumbra.
|
||||
indexBuffer[indexBufferIndex++] = umbraVertices[i];
|
||||
indexBuffer[indexBufferIndex++] = centroidIndex;
|
||||
}
|
||||
indexBuffer[indexBufferIndex++] = 0;
|
||||
}
|
||||
|
||||
// At the end, update the real index and vertex buffer size.
|
||||
shadowVertexBuffer.updateVertexCount(vertexBufferIndex);
|
||||
shadowVertexBuffer.updateIndexCount(indexBufferIndex);
|
||||
shadowVertexBuffer.computeBounds<AlphaVertex>();
|
||||
|
||||
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++) {
|
||||
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
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
@@ -1,42 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HWUI_AMBIENT_SHADOW_H
|
||||
#define ANDROID_HWUI_AMBIENT_SHADOW_H
|
||||
|
||||
#include "Debug.h"
|
||||
#include "Vector.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class VertexBuffer;
|
||||
|
||||
/**
|
||||
* AmbientShadow is used to calculate the ambient shadow value around a polygon.
|
||||
*/
|
||||
class AmbientShadow {
|
||||
public:
|
||||
static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly, int polyLength,
|
||||
const Vector3& centroid3d, float heightFactor, float geomFactor,
|
||||
VertexBuffer& shadowVertexBuffer);
|
||||
}; // AmbientShadow
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
|
||||
@@ -197,7 +197,6 @@ cc_defaults {
|
||||
"utils/StringUtils.cpp",
|
||||
"utils/TestWindowContext.cpp",
|
||||
"utils/VectorDrawableUtils.cpp",
|
||||
"AmbientShadow.cpp",
|
||||
"AnimationContext.cpp",
|
||||
"Animator.cpp",
|
||||
"AnimatorManager.cpp",
|
||||
@@ -238,12 +237,10 @@ cc_defaults {
|
||||
"RenderNode.cpp",
|
||||
"RenderProperties.cpp",
|
||||
"ResourceCache.cpp",
|
||||
"ShadowTessellator.cpp",
|
||||
"SkiaCanvas.cpp",
|
||||
"SkiaCanvasProxy.cpp",
|
||||
"SkiaShader.cpp",
|
||||
"Snapshot.cpp",
|
||||
"SpotShadow.cpp",
|
||||
"Texture.cpp",
|
||||
"VectorDrawable.cpp",
|
||||
"VkLayer.cpp",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "GlLayer.h"
|
||||
#include "Properties.h"
|
||||
#include "ShadowTessellator.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/GLUtils.h"
|
||||
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/MathUtils.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "AmbientShadow.h"
|
||||
#include "Properties.h"
|
||||
#include "ShadowTessellator.h"
|
||||
#include "SpotShadow.h"
|
||||
#include "Vector.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque, const Vector3* casterPolygon,
|
||||
int casterVertexCount, const Vector3& centroid3d,
|
||||
const Rect& casterBounds, const Rect& localClip,
|
||||
float maxZ, VertexBuffer& shadowVertexBuffer) {
|
||||
ATRACE_CALL();
|
||||
|
||||
// A bunch of parameters to tweak the shadow.
|
||||
// TODO: Allow some of these changable by debug settings or APIs.
|
||||
float heightFactor = 1.0f / 128;
|
||||
const float geomFactor = 64;
|
||||
|
||||
if (CC_UNLIKELY(Properties::overrideAmbientRatio > 0.0f)) {
|
||||
heightFactor *= Properties::overrideAmbientRatio;
|
||||
}
|
||||
|
||||
Rect ambientShadowBounds(casterBounds);
|
||||
ambientShadowBounds.outset(maxZ * geomFactor * heightFactor);
|
||||
|
||||
if (!localClip.intersects(ambientShadowBounds)) {
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("Ambient shadow is out of clip rect!");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
|
||||
heightFactor, geomFactor, shadowVertexBuffer);
|
||||
}
|
||||
|
||||
void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon,
|
||||
int casterVertexCount, const Vector3& casterCentroid,
|
||||
const mat4& receiverTransform,
|
||||
const Vector3& lightCenter, int lightRadius,
|
||||
const Rect& casterBounds, const Rect& localClip,
|
||||
VertexBuffer& shadowVertexBuffer) {
|
||||
ATRACE_CALL();
|
||||
|
||||
Vector3 adjustedLightCenter(lightCenter);
|
||||
if (CC_UNLIKELY(Properties::overrideLightPosY > 0)) {
|
||||
adjustedLightCenter.y = -Properties::overrideLightPosY; // negated since this shifts up
|
||||
}
|
||||
if (CC_UNLIKELY(Properties::overrideLightPosZ > 0)) {
|
||||
adjustedLightCenter.z = Properties::overrideLightPosZ;
|
||||
}
|
||||
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("light center %f %f %f %d", adjustedLightCenter.x, adjustedLightCenter.y,
|
||||
adjustedLightCenter.z, lightRadius);
|
||||
#endif
|
||||
if (isnan(adjustedLightCenter.x) || isnan(adjustedLightCenter.y) ||
|
||||
isnan(adjustedLightCenter.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// light position (because it's in local space) needs to compensate for receiver transform
|
||||
// TODO: should apply to light orientation, not just position
|
||||
Matrix4 reverseReceiverTransform;
|
||||
reverseReceiverTransform.loadInverse(receiverTransform);
|
||||
reverseReceiverTransform.mapPoint3d(adjustedLightCenter);
|
||||
|
||||
if (CC_UNLIKELY(Properties::overrideLightRadius > 0)) {
|
||||
lightRadius = Properties::overrideLightRadius;
|
||||
}
|
||||
|
||||
// Now light and caster are both in local space, we will check whether
|
||||
// the shadow is within the clip area.
|
||||
Rect lightRect = Rect(adjustedLightCenter.x - lightRadius, adjustedLightCenter.y - lightRadius,
|
||||
adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
|
||||
lightRect.unionWith(localClip);
|
||||
if (!lightRect.intersects(casterBounds)) {
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("Spot shadow is out of clip rect!");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
SpotShadow::createSpotShadow(isCasterOpaque, adjustedLightCenter, lightRadius, casterPolygon,
|
||||
casterVertexCount, casterCentroid, shadowVertexBuffer);
|
||||
|
||||
#if DEBUG_SHADOW
|
||||
if (shadowVertexBuffer.getVertexCount() <= 0) {
|
||||
ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
|
||||
}
|
||||
#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){static_cast<float>(sumx / (3 * area)),
|
||||
static_cast<float>(sumy / (3 * area))};
|
||||
} else {
|
||||
ALOGW("Area is 0 while computing centroid!");
|
||||
}
|
||||
return centroid;
|
||||
}
|
||||
|
||||
// Make sure p1 -> p2 is going CW around the poly.
|
||||
Vector2 ShadowTessellator::calculateNormal(const Vector2& p1, const Vector2& p2) {
|
||||
Vector2 result = p2 - p1;
|
||||
if (result.x != 0 || result.y != 0) {
|
||||
result.normalize();
|
||||
// Calculate the normal , which is CCW 90 rotate to the delta.
|
||||
float tempy = result.y;
|
||||
result.y = result.x;
|
||||
result.x = -tempy;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
|
||||
float divisor) {
|
||||
// When there is no distance difference, there is no need for extra vertices.
|
||||
if (vector1.lengthSquared() == 0 || vector2.lengthSquared() == 0) {
|
||||
return 0;
|
||||
}
|
||||
// The formula is :
|
||||
// extraNumber = floor(acos(dot(n1, n2)) / (M_PI / EXTRA_VERTEX_PER_PI))
|
||||
// The value ranges for each step are:
|
||||
// dot( ) --- [-1, 1]
|
||||
// acos( ) --- [0, M_PI]
|
||||
// floor(...) --- [0, EXTRA_VERTEX_PER_PI]
|
||||
float dotProduct = vector1.dot(vector2);
|
||||
// make sure that dotProduct value is in acsof input range [-1, 1]
|
||||
dotProduct = MathUtils::clamp(dotProduct, -1.0f, 1.0f);
|
||||
// TODO: Use look up table for the dotProduct to extraVerticesNumber
|
||||
// computation, if needed.
|
||||
float angle = acosf(dotProduct);
|
||||
return (int)floor(angle / divisor);
|
||||
}
|
||||
|
||||
void ShadowTessellator::checkOverflow(int used, int total, const char* bufferName) {
|
||||
LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d", bufferName, used,
|
||||
total);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
@@ -1,94 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HWUI_SHADOW_TESSELLATOR_H
|
||||
#define ANDROID_HWUI_SHADOW_TESSELLATOR_H
|
||||
|
||||
#include <SkPath.h>
|
||||
|
||||
#include "Debug.h"
|
||||
#include "Matrix.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class VertexBuffer;
|
||||
|
||||
// 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.
|
||||
// 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)
|
||||
// 0
|
||||
//
|
||||
// 5 6 1
|
||||
// 11 7
|
||||
//
|
||||
// 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 128
|
||||
|
||||
// The total number of all the vertices representing the shadow.
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
#define MINIMAL_DELTA_THETA (M_PI / 180 / 1000)
|
||||
|
||||
class ShadowTessellator {
|
||||
public:
|
||||
static void tessellateAmbientShadow(bool isCasterOpaque, const Vector3* casterPolygon,
|
||||
int casterVertexCount, const Vector3& centroid3d,
|
||||
const Rect& casterBounds, const Rect& localClip, float maxZ,
|
||||
VertexBuffer& shadowVertexBuffer);
|
||||
|
||||
static void tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon,
|
||||
int casterVertexCount, const Vector3& casterCentroid,
|
||||
const mat4& receiverTransform, const Vector3& lightCenter,
|
||||
int lightRadius, const Rect& casterBounds,
|
||||
const Rect& localClip, VertexBuffer& shadowVertexBuffer);
|
||||
|
||||
static Vector2 centroid2d(const Vector2* poly, int polyLength);
|
||||
|
||||
static Vector2 calculateNormal(const Vector2& p1, const Vector2& p2);
|
||||
|
||||
static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2, float divisor);
|
||||
|
||||
static void checkOverflow(int used, int total, const char* bufferName);
|
||||
}; // ShadowTessellator
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_SHADOW_TESSELLATOR_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HWUI_SPOT_SHADOW_H
|
||||
#define ANDROID_HWUI_SPOT_SHADOW_H
|
||||
|
||||
#include "Debug.h"
|
||||
#include "Vector.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class VertexBuffer;
|
||||
|
||||
class SpotShadow {
|
||||
public:
|
||||
static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter, float lightSize,
|
||||
const Vector3* poly, int polyLength, const Vector3& polyCentroid,
|
||||
VertexBuffer& retstrips);
|
||||
|
||||
private:
|
||||
struct VertexAngleData;
|
||||
|
||||
static float projectCasterToOutline(Vector2& outline, const Vector3& lightCenter,
|
||||
const Vector3& polyVertex);
|
||||
|
||||
static void computeLightPolygon(int points, const Vector3& lightCenter, float size,
|
||||
Vector3* ret);
|
||||
|
||||
static void smoothPolygon(int level, int rays, float* rayDist);
|
||||
static float rayIntersectPoly(const Vector2* poly, int polyLength, const Vector2& point,
|
||||
float dx, float dy);
|
||||
|
||||
static void xsort(Vector2* points, int pointsLength);
|
||||
static int hull(Vector2* points, int pointsLength, Vector2* retPoly);
|
||||
static bool ccw(float ax, float ay, float bx, float by, float cx, float cy);
|
||||
static void sort(Vector2* poly, int polyLength, const Vector2& center);
|
||||
|
||||
static void swap(Vector2* points, int i, int j);
|
||||
static void quicksortCirc(Vector2* points, int low, int high, const Vector2& center);
|
||||
static void quicksortX(Vector2* points, int low, int high);
|
||||
|
||||
static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len);
|
||||
static void reverse(Vector2* polygon, int len);
|
||||
|
||||
static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
|
||||
Vector2* penumbra, int penumbraLength, Vector2* umbra,
|
||||
int umbraLength, const Vector3* poly, int polyLength,
|
||||
VertexBuffer& retstrips, const Vector2& centroid);
|
||||
|
||||
#if DEBUG_SHADOW
|
||||
static bool testConvex(const Vector2* polygon, int polygonLength, const char* name);
|
||||
static void testIntersection(const Vector2* poly1, int poly1Length, const Vector2* poly2,
|
||||
int poly2Length, const Vector2* intersection,
|
||||
int intersectionLength);
|
||||
static void updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound);
|
||||
static void dumpPolygon(const Vector2* poly, int polyLength, const char* polyName);
|
||||
static void dumpPolygon(const Vector3* poly, int polyLength, const char* polyName);
|
||||
#endif
|
||||
|
||||
}; // SpotShadow
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_SPOT_SHADOW_H
|
||||
@@ -16,8 +16,6 @@
|
||||
#include <renderstate/Blend.h>
|
||||
#include "Program.h"
|
||||
|
||||
#include "ShadowTessellator.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user