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