ShadowTessellator.cpp revision 50ecf849cb7ccc3482517b74d2214b347927791e
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "OpenGLRenderer"
18#define ATRACE_TAG ATRACE_TAG_VIEW
19
20#include <math.h>
21#include <utils/Log.h>
22#include <utils/Trace.h>
23
24#include "AmbientShadow.h"
25#include "ShadowTessellator.h"
26#include "SpotShadow.h"
27
28namespace android {
29namespace uirenderer {
30
31template<typename T>
32static inline T max(T a, T b) {
33    return a > b ? a : b;
34}
35
36VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
37        const Vector3* casterPolygon, int casterVertexCount,
38        const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer) {
39    ATRACE_CALL();
40
41    // A bunch of parameters to tweak the shadow.
42    // TODO: Allow some of these changable by debug settings or APIs.
43    const float heightFactor = 1.0f / 128;
44    const float geomFactor = 64;
45
46    return AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
47            casterVertexCount, centroid3d, heightFactor, geomFactor,
48            shadowVertexBuffer);
49
50}
51
52VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
53        const Vector3* casterPolygon, int casterVertexCount,
54        const Vector3& lightPosScale, const mat4& receiverTransform,
55        int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
56    ATRACE_CALL();
57
58    // A bunch of parameters to tweak the shadow.
59    // TODO: Allow some of these changable by debug settings or APIs.
60    int maximal = max(screenWidth, screenHeight);
61    Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
62            maximal * lightPosScale.z);
63#if DEBUG_SHADOW
64    ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
65#endif
66
67    // light position (because it's in local space) needs to compensate for receiver transform
68    // TODO: should apply to light orientation, not just position
69    Matrix4 reverseReceiverTransform;
70    reverseReceiverTransform.loadInverse(receiverTransform);
71    reverseReceiverTransform.mapPoint3d(lightCenter);
72
73    const float lightSize = maximal / 4;
74    const int lightVertexCount = 8;
75
76    VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
77            casterPolygon, casterVertexCount, lightCenter, lightSize,
78            lightVertexCount, shadowVertexBuffer);
79
80#if DEBUG_SHADOW
81     if(shadowVertexBuffer.getVertexCount() <= 0) {
82        ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
83     }
84#endif
85     return mode;
86}
87
88void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
89    int currentIndex = 0;
90    const int rays = SHADOW_RAY_COUNT;
91    // For the penumbra area.
92    for (int layer = 0; layer < 2; layer ++) {
93        int baseIndex = layer * rays;
94        for (int i = 0; i < rays; i++) {
95            shadowIndices[currentIndex++] = i + baseIndex;
96            shadowIndices[currentIndex++] = rays + i + baseIndex;
97        }
98        // To close the loop, back to the ray 0.
99        shadowIndices[currentIndex++] = 0 + baseIndex;
100         // Note this is the same as the first index of next layer loop.
101        shadowIndices[currentIndex++] = rays + baseIndex;
102    }
103
104#if DEBUG_SHADOW
105    if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
106        ALOGW("vertex index count is wrong. current %d, expected %d",
107                currentIndex, MAX_SHADOW_INDEX_COUNT);
108    }
109    for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
110        ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
111    }
112#endif
113}
114
115/**
116 * Calculate the centroid of a 2d polygon.
117 *
118 * @param poly The polygon, which is represented in a Vector2 array.
119 * @param polyLength The length of the polygon in terms of number of vertices.
120 * @return the centroid of the polygon.
121 */
122Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
123    double sumx = 0;
124    double sumy = 0;
125    int p1 = polyLength - 1;
126    double area = 0;
127    for (int p2 = 0; p2 < polyLength; p2++) {
128        double x1 = poly[p1].x;
129        double y1 = poly[p1].y;
130        double x2 = poly[p2].x;
131        double y2 = poly[p2].y;
132        double a = (x1 * y2 - x2 * y1);
133        sumx += (x1 + x2) * a;
134        sumy += (y1 + y2) * a;
135        area += a;
136        p1 = p2;
137    }
138
139    Vector2 centroid = poly[0];
140    if (area != 0) {
141        centroid = Vector2(sumx / (3 * area), sumy / (3 * area));
142    } else {
143        ALOGW("Area is 0 while computing centroid!");
144    }
145    return centroid;
146}
147
148}; // namespace uirenderer
149}; // namespace android
150