• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package android.view.shadow;
18 
19 import android.view.math.Math3DHelper;
20 
21 /**
22  * Generates the vertices required for spot shadow and all other shadow-related rendering.
23  */
24 class SpotShadowVertexCalculator {
25 
SpotShadowVertexCalculator()26     private SpotShadowVertexCalculator() { }
27 
28     /**
29      * Create evenly distributed circular light source points from x and y (on flat z plane).
30      * This is useful for ray tracing the shadow points later. Format : (x1,y1,z1,x2,y2,z2 ...)
31      *
32      * @param radius - radius of the light source
33      * @param points - how many light source points to generate
34      * @param x - center X of the light source
35      * @param y - center Y of the light source
36      * @param height - how high (z depth) the light should be
37      * @return float points (x,y,z) of light source points.
38      */
calculateLight(float radius, int points, float x, float y, float height)39     public static float[] calculateLight(float radius, int points, float x, float y, float height) {
40         float[] ret = new float[points * 3];
41         for (int i = 0; i < points; i++) {
42             double angle = 2 * i * Math.PI / points;
43             ret[i * 3] = (float) Math.sin(angle) * radius + x;
44             ret[i * 3 + 1] = (float) Math.cos(angle) * radius + y;
45             ret[i * 3 + 2] = (height);
46         }
47 
48         return ret;
49     }
50 
51     /**
52      * @param rays - Number of rays to use for tracing
53      * @param layers - Number of layers for shadow rendering.
54      * @return size required for shadow vertices mData array based on # of rays and layers
55      */
getStripSize(int rays, int layers)56     public static int getStripSize(int rays, int layers){
57         return  (2 + rays + ((layers) * 2 * (rays + 1)));
58     }
59 
60     /**
61      * Generate shadow vertices based on params. Format : (x1,y1,z1,x2,y2,z2 ...)
62      * Precondition : Light poly must be evenly distributed on a flat surface
63      * Precondition : Poly vertices must be a convex
64      * Precondition : Light height must be higher than any poly vertices
65      *
66      * @param lightPoly - Vertices of a light source.
67      * @param lightPolyLength - Size of the vertices (usually lightPoly.length/3 unless w is
68      * included)
69      * @param poly - Vertices of opaque object casting shadow
70      * @param polyLength - Size of the vertices
71      * @param rays - Number of rays to use for tracing. It determines accuracy of the outline
72      * (bounds) of the shadow
73      * @param layers - Number of layers for shadow. It determines intensity of pen-umbra
74      * @param strength - Strength of the shadow overall [0-1]
75      * @param retstrips - Array mData to be filled in format : {x1, y1, z1, x2, y2, z2}
76      * @return 1 if successful, error code otherwise.
77      */
calculateShadow( float[] lightPoly, int lightPolyLength, float[] poly, int polyLength, int rays, int layers, float strength, float[] retstrips)78     public static int calculateShadow(
79             float[] lightPoly,
80             int lightPolyLength,
81             float[] poly,
82             int polyLength,
83             int rays,
84             int layers,
85             float strength,
86             float[] retstrips) {
87         float[] shadowRegion = new float[lightPolyLength * polyLength * 2];
88         float[] outline = new float[polyLength * 2];
89         float[] umbra = new float[polyLength * lightPolyLength * 2];
90         int umbraLength = 0;
91 
92         int k = 0;
93         for (int j = 0; j < lightPolyLength; j++) {
94             int m = 0;
95             for (int i = 0; i < polyLength; i++) {
96                 float t = lightPoly[j * 3 + 2] - poly[i * 3 + 2];
97                 if (t == 0) {
98                     return 0;
99                 }
100                 t = lightPoly[j * 3 + 2] / t;
101                 float x = lightPoly[j * 3] - t * (lightPoly[j * 3] - poly[i * 3]);
102                 float y = lightPoly[j * 3 + 1] - t * (lightPoly[j * 3 + 1] - poly[i * 3 + 1]);
103 
104                 shadowRegion[k * 2] = x;
105                 shadowRegion[k * 2 + 1] = y;
106                 outline[m * 2] = x;
107                 outline[m * 2 + 1] = y;
108 
109                 k++;
110                 m++;
111             }
112 
113             if (umbraLength == 0) {
114                 for (int i = 0; i < polyLength * 2; i++) {
115                     umbra[i] = outline[i];
116                 }
117                 umbraLength = polyLength;
118             } else {
119                 umbraLength = Math3DHelper.intersection(outline, polyLength, umbra, umbraLength);
120                 if (umbraLength == 0) {
121                     break;
122                 }
123 
124             }
125         }
126         int shadowRegionLength = k;
127 
128         float[] penumbra = new float[k * 2];
129         int penumbraLength = Math3DHelper.hull(shadowRegion, shadowRegionLength, penumbra);
130         if (umbraLength < 3) {// no real umbra make a fake one
131             float[] p = new float[3];
132             Math3DHelper.centroid3d(lightPoly, lightPolyLength, p);
133             float[] centShadow = new float[polyLength * 2];
134             for (int i = 0; i < polyLength; i++) {
135                 float t = p[2] - poly[i * 3 + 2];
136                 if (t == 0) {
137                     return 0;
138                 }
139                 t = p[2] / t;
140                 float x = p[0] - t * (p[0] - poly[i * 3]);
141                 float y = p[1] - t * (p[1] - poly[i * 3 + 1]);
142 
143                 centShadow[i * 2] = x;
144                 centShadow[i * 2 + 1] = y;
145             }
146             float[] c = new float[2];
147             Math3DHelper.centroid2d(centShadow, polyLength, c);
148             for (int i = 0; i < polyLength; i++) {
149                 centShadow[i * 2] = (c[0] * 9 + centShadow[i * 2]) / 10;
150                 centShadow[i * 2 + 1] = (c[1] * 9 + centShadow[i * 2 + 1]) / 10;
151             }
152             umbra = centShadow; // fake umbra
153             umbraLength = polyLength; // same size as the original polygon
154         }
155 
156         Math3DHelper.donutPie2(penumbra, penumbraLength, umbra, umbraLength, rays,
157                 layers, strength, retstrips);
158         return 1;
159     }
160 }