blob: 771904ac3e59b91bddc15b470952d8e19f295b39 [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
ztenghui50ecf842014-03-11 16:52:30 -070036VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
37 const Vector3* casterPolygon, int casterVertexCount,
38 const Vector3& centroid3d, 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
ztenghui50ecf842014-03-11 16:52:30 -070046 return AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
47 casterVertexCount, centroid3d, heightFactor, geomFactor,
48 shadowVertexBuffer);
ztenghui55bfb4e2013-12-03 10:38:55 -080049
50}
51
ztenghui50ecf842014-03-11 16:52:30 -070052VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
53 const Vector3* casterPolygon, int casterVertexCount,
ztenghuicc3c2562014-01-17 10:34:10 -080054 const Vector3& lightPosScale, const mat4& receiverTransform,
Chris Craik15a07a22014-01-26 13:43:53 -080055 int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
Chris Craik87f9df82014-03-07 14:34:42 -080056 ATRACE_CALL();
57
ztenghui7b4516e2014-01-07 10:42:55 -080058 // A bunch of parameters to tweak the shadow.
59 // TODO: Allow some of these changable by debug settings or APIs.
ztenghui7b4516e2014-01-07 10:42:55 -080060 int maximal = max(screenWidth, screenHeight);
ztenghuicc3c2562014-01-17 10:34:10 -080061 Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
62 maximal * lightPosScale.z);
ztenghui7b4516e2014-01-07 10:42:55 -080063#if DEBUG_SHADOW
64 ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
65#endif
Chris Craik3197cde2014-01-16 14:03:39 -080066
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
ztenghuicc3c2562014-01-17 10:34:10 -080073 const float lightSize = maximal / 4;
Chris Craik726118b2014-03-07 18:27:49 -080074 const int lightVertexCount = 8;
ztenghui7b4516e2014-01-07 10:42:55 -080075
ztenghui50ecf842014-03-11 16:52:30 -070076 VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
77 casterPolygon, casterVertexCount, lightCenter, lightSize,
78 lightVertexCount, shadowVertexBuffer);
ztenghui7b4516e2014-01-07 10:42:55 -080079
ztenghui50ecf842014-03-11 16:52:30 -070080#if DEBUG_SHADOW
81 if(shadowVertexBuffer.getVertexCount() <= 0) {
82 ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
83 }
84#endif
85 return mode;
ztenghui7b4516e2014-01-07 10:42:55 -080086}
ztenghui63d41ab2014-02-14 13:13:41 -080087
88void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
89 int currentIndex = 0;
ztenghui63d41ab2014-02-14 13:13:41 -080090 const int rays = SHADOW_RAY_COUNT;
91 // For the penumbra area.
ztenghui50ecf842014-03-11 16:52:30 -070092 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;
ztenghui63d41ab2014-02-14 13:13:41 -0800102 }
ztenghui63d41ab2014-02-14 13:13:41 -0800103
104#if DEBUG_SHADOW
ztenghui50ecf842014-03-11 16:52:30 -0700105 if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
106 ALOGW("vertex index count is wrong. current %d, expected %d",
107 currentIndex, MAX_SHADOW_INDEX_COUNT);
ztenghui63d41ab2014-02-14 13:13:41 -0800108 }
ztenghui50ecf842014-03-11 16:52:30 -0700109 for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
ztenghui63d41ab2014-02-14 13:13:41 -0800110 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 {
ztenghui50ecf842014-03-11 16:52:30 -0700143 ALOGW("Area is 0 while computing centroid!");
ztenghui63d41ab2014-02-14 13:13:41 -0800144 }
145 return centroid;
146}
147
ztenghui55bfb4e2013-12-03 10:38:55 -0800148}; // namespace uirenderer
149}; // namespace android