blob: f138222c27254e88e5d966a669d5fed9ae67539e [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"
Chris Craik87f9df82014-03-07 14:34:42 -080018#define ATRACE_TAG ATRACE_TAG_VIEW
ztenghui55bfb4e2013-12-03 10:38:55 -080019
20#include <math.h>
21#include <utils/Log.h>
Chris Craik87f9df82014-03-07 14:34:42 -080022#include <utils/Trace.h>
ztenghui55bfb4e2013-12-03 10:38:55 -080023
24#include "AmbientShadow.h"
25#include "ShadowTessellator.h"
ztenghui7b4516e2014-01-07 10:42:55 -080026#include "SpotShadow.h"
ztenghui55bfb4e2013-12-03 10:38:55 -080027
28namespace android {
29namespace uirenderer {
30
ztenghui7b4516e2014-01-07 10:42:55 -080031template<typename T>
32static inline T max(T a, T b) {
33 return a > b ? a : b;
34}
35
ztenghui63d41ab2014-02-14 13:13:41 -080036void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
37 int casterVertexCount, const Vector3& centroid3d,
Chris Craik15a07a22014-01-26 13:43:53 -080038 VertexBuffer& shadowVertexBuffer) {
Chris Craik87f9df82014-03-07 14:34:42 -080039 ATRACE_CALL();
40
ztenghui55bfb4e2013-12-03 10:38:55 -080041 // A bunch of parameters to tweak the shadow.
42 // TODO: Allow some of these changable by debug settings or APIs.
Chris Craik726118b2014-03-07 18:27:49 -080043 const float heightFactor = 1.0f / 128;
ztenghui7b4516e2014-01-07 10:42:55 -080044 const float geomFactor = 64;
ztenghui55bfb4e2013-12-03 10:38:55 -080045
ztenghui63d41ab2014-02-14 13:13:41 -080046 AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount,
47 centroid3d, heightFactor, geomFactor, shadowVertexBuffer);
ztenghui55bfb4e2013-12-03 10:38:55 -080048
49}
50
Chris Craik15a07a22014-01-26 13:43:53 -080051void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
ztenghuicc3c2562014-01-17 10:34:10 -080052 const Vector3& lightPosScale, const mat4& receiverTransform,
Chris Craik15a07a22014-01-26 13:43:53 -080053 int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
Chris Craik87f9df82014-03-07 14:34:42 -080054 ATRACE_CALL();
55
ztenghui7b4516e2014-01-07 10:42:55 -080056 // A bunch of parameters to tweak the shadow.
57 // TODO: Allow some of these changable by debug settings or APIs.
ztenghui7b4516e2014-01-07 10:42:55 -080058 int maximal = max(screenWidth, screenHeight);
ztenghuicc3c2562014-01-17 10:34:10 -080059 Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
60 maximal * lightPosScale.z);
ztenghui7b4516e2014-01-07 10:42:55 -080061#if DEBUG_SHADOW
62 ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
63#endif
Chris Craik3197cde2014-01-16 14:03:39 -080064
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
ztenghuicc3c2562014-01-17 10:34:10 -080071 const float lightSize = maximal / 4;
Chris Craik726118b2014-03-07 18:27:49 -080072 const int lightVertexCount = 8;
ztenghui7b4516e2014-01-07 10:42:55 -080073
ztenghui63d41ab2014-02-14 13:13:41 -080074 SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter,
75 lightSize, lightVertexCount, shadowVertexBuffer);
ztenghui7b4516e2014-01-07 10:42:55 -080076
77}
ztenghui63d41ab2014-02-14 13:13:41 -080078
79void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
80 int currentIndex = 0;
ztenghui63d41ab2014-02-14 13:13:41 -080081 const int rays = SHADOW_RAY_COUNT;
82 // For the penumbra area.
Chris Craik726118b2014-03-07 18:27:49 -080083 for (int i = 0; i < rays; i++) {
84 shadowIndices[currentIndex++] = i;
85 shadowIndices[currentIndex++] = rays + i;
ztenghui63d41ab2014-02-14 13:13:41 -080086 }
Chris Craik726118b2014-03-07 18:27:49 -080087 // To close the loop, back to the ray 0.
88 shadowIndices[currentIndex++] = 0;
89 shadowIndices[currentIndex++] = rays;
90
91 uint16_t centroidIndex = 2 * rays;
ztenghui63d41ab2014-02-14 13:13:41 -080092 // For the umbra area, using strips to simulate the fans.
Chris Craik726118b2014-03-07 18:27:49 -080093 for (int i = 0; i < rays; i++) {
94 shadowIndices[currentIndex++] = rays + i;
ztenghui63d41ab2014-02-14 13:13:41 -080095 shadowIndices[currentIndex++] = centroidIndex;
96 }
Chris Craik726118b2014-03-07 18:27:49 -080097 shadowIndices[currentIndex++] = rays;
ztenghui63d41ab2014-02-14 13:13:41 -080098
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
ztenghui55bfb4e2013-12-03 10:38:55 -0800143}; // namespace uirenderer
144}; // namespace android