ShadowTessellator.cpp revision 726118b35240957710d4d85fb5747e2ba8b934f7
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
36void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
37        int casterVertexCount, const Vector3& centroid3d,
38        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    AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount,
47            centroid3d, heightFactor, geomFactor, shadowVertexBuffer);
48
49}
50
51void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
52        const Vector3& lightPosScale, const mat4& receiverTransform,
53        int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
54    ATRACE_CALL();
55
56    // A bunch of parameters to tweak the shadow.
57    // TODO: Allow some of these changable by debug settings or APIs.
58    int maximal = max(screenWidth, screenHeight);
59    Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
60            maximal * lightPosScale.z);
61#if DEBUG_SHADOW
62    ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
63#endif
64
65    // light position (because it's in local space) needs to compensate for receiver transform
66    // TODO: should apply to light orientation, not just position
67    Matrix4 reverseReceiverTransform;
68    reverseReceiverTransform.loadInverse(receiverTransform);
69    reverseReceiverTransform.mapPoint3d(lightCenter);
70
71    const float lightSize = maximal / 4;
72    const int lightVertexCount = 8;
73
74    SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter,
75            lightSize, lightVertexCount, shadowVertexBuffer);
76
77}
78
79void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
80    int currentIndex = 0;
81    const int rays = SHADOW_RAY_COUNT;
82    // For the penumbra area.
83    for (int i = 0; i < rays; i++) {
84        shadowIndices[currentIndex++] = i;
85        shadowIndices[currentIndex++] = rays + i;
86    }
87    // To close the loop, back to the ray 0.
88    shadowIndices[currentIndex++] = 0;
89    shadowIndices[currentIndex++] = rays;
90
91    uint16_t centroidIndex = 2 * rays;
92    // For the umbra area, using strips to simulate the fans.
93    for (int i = 0; i < rays; i++) {
94        shadowIndices[currentIndex++] = rays + i;
95        shadowIndices[currentIndex++] = centroidIndex;
96    }
97    shadowIndices[currentIndex++] = rays;
98
99#if DEBUG_SHADOW
100    if (currentIndex != SHADOW_INDEX_COUNT) {
101        ALOGE("vertex index count is wrong. current %d, expected %d",
102                currentIndex, SHADOW_INDEX_COUNT);
103    }
104    for (int i = 0; i < SHADOW_INDEX_COUNT; i++) {
105        ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
106    }
107#endif
108}
109
110/**
111 * Calculate the centroid of a 2d polygon.
112 *
113 * @param poly The polygon, which is represented in a Vector2 array.
114 * @param polyLength The length of the polygon in terms of number of vertices.
115 * @return the centroid of the polygon.
116 */
117Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
118    double sumx = 0;
119    double sumy = 0;
120    int p1 = polyLength - 1;
121    double area = 0;
122    for (int p2 = 0; p2 < polyLength; p2++) {
123        double x1 = poly[p1].x;
124        double y1 = poly[p1].y;
125        double x2 = poly[p2].x;
126        double y2 = poly[p2].y;
127        double a = (x1 * y2 - x2 * y1);
128        sumx += (x1 + x2) * a;
129        sumy += (y1 + y2) * a;
130        area += a;
131        p1 = p2;
132    }
133
134    Vector2 centroid = poly[0];
135    if (area != 0) {
136        centroid = Vector2(sumx / (3 * area), sumy / (3 * area));
137    } else {
138        ALOGE("Area is 0 while computing centroid!");
139    }
140    return centroid;
141}
142
143}; // namespace uirenderer
144}; // namespace android
145