blob: 526772b8858cba6a393ac17e83ec75970e2bb393 [file] [log] [blame]
ztenghui55bfb4e2013-12-03 10:38:55 -08001/*
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"
ztenghui7b4516e2014-01-07 10:42:55 -080024#include "SpotShadow.h"
ztenghui55bfb4e2013-12-03 10:38:55 -080025
26namespace android {
27namespace uirenderer {
28
ztenghui7b4516e2014-01-07 10:42:55 -080029template<typename T>
30static inline T max(T a, T b) {
31 return a > b ? a : b;
32}
33
ztenghui63d41ab2014-02-14 13:13:41 -080034void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
35 int casterVertexCount, const Vector3& centroid3d,
Chris Craik15a07a22014-01-26 13:43:53 -080036 VertexBuffer& shadowVertexBuffer) {
ztenghui55bfb4e2013-12-03 10:38:55 -080037 // A bunch of parameters to tweak the shadow.
38 // TODO: Allow some of these changable by debug settings or APIs.
ztenghui7b4516e2014-01-07 10:42:55 -080039 const float heightFactor = 128;
40 const float geomFactor = 64;
ztenghui55bfb4e2013-12-03 10:38:55 -080041
ztenghui63d41ab2014-02-14 13:13:41 -080042 AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount,
43 centroid3d, heightFactor, geomFactor, shadowVertexBuffer);
ztenghui55bfb4e2013-12-03 10:38:55 -080044
45}
46
Chris Craik15a07a22014-01-26 13:43:53 -080047void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
ztenghuicc3c2562014-01-17 10:34:10 -080048 const Vector3& lightPosScale, const mat4& receiverTransform,
Chris Craik15a07a22014-01-26 13:43:53 -080049 int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
ztenghui7b4516e2014-01-07 10:42:55 -080050 // A bunch of parameters to tweak the shadow.
51 // TODO: Allow some of these changable by debug settings or APIs.
ztenghui7b4516e2014-01-07 10:42:55 -080052 int maximal = max(screenWidth, screenHeight);
ztenghuicc3c2562014-01-17 10:34:10 -080053 Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
54 maximal * lightPosScale.z);
ztenghui7b4516e2014-01-07 10:42:55 -080055#if DEBUG_SHADOW
56 ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
57#endif
Chris Craik3197cde2014-01-16 14:03:39 -080058
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
ztenghuicc3c2562014-01-17 10:34:10 -080065 const float lightSize = maximal / 4;
ztenghui7b4516e2014-01-07 10:42:55 -080066 const int lightVertexCount = 16;
67
ztenghui63d41ab2014-02-14 13:13:41 -080068 SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter,
69 lightSize, lightVertexCount, shadowVertexBuffer);
ztenghui7b4516e2014-01-07 10:42:55 -080070
71}
ztenghui63d41ab2014-02-14 13:13:41 -080072
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
ztenghui55bfb4e2013-12-03 10:38:55 -0800140}; // namespace uirenderer
141}; // namespace android