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 vertices, colours, and indices required for ambient shadow. Ambient shadows are 23 * assumed to be raycasted from the centroid of the polygon, and reaches upto a ratio based on 24 * the polygon's z-height. 25 */ 26 class AmbientShadowVertexCalculator { 27 28 private final float[] mVertex; 29 private final float[] mColor; 30 private final int[] mIndex; 31 private final AmbientShadowConfig mConfig; 32 AmbientShadowVertexCalculator(AmbientShadowConfig config)33 public AmbientShadowVertexCalculator(AmbientShadowConfig config) { 34 mConfig = config; 35 36 int rings = mConfig.getLayers() + 1; 37 int size = mConfig.getRays() * rings; 38 39 mVertex = new float[size * 2]; 40 mColor = new float[size * 4]; 41 mIndex = new int[(size * 2 + (mConfig.getRays() - 2)) * 3]; 42 } 43 44 /** 45 * Generates vertex using the polygon info 46 * @param polygon 3d polygon info in format : {x1, y1, z1, x2, y2, z2 ...} 47 * @return true if vertices are generated with right colour/index. False otherwise. 48 */ generateVertex(float[] polygon)49 public boolean generateVertex(float[] polygon) { 50 // Despite us not using z coord, we want calculations in 3d space as our polygon is using 51 // 3d coord system. 52 float[] centroidxy = new float[3]; 53 int polygonLength = polygon.length/3; 54 55 Math3DHelper.centroid3d(polygon, polygonLength, centroidxy); 56 57 float cx = centroidxy[0]; 58 float cy = centroidxy[1]; 59 60 Rays rays = new Rays(mConfig.getRays()); 61 int raysLength = rays.dx.length; 62 float rayDist[] = new float[mConfig.getRays()]; 63 64 float[] rayHeights = new float[mConfig.getRays()]; 65 66 for (int i = 0; i < raysLength; i++) { 67 float dx = rays.dx[i]; 68 float dy = rays.dy[i]; 69 70 float[] intersection = Math3DHelper.rayIntersectPoly(polygon, polygonLength, cx, cy, 71 dx, dy, 3); 72 if (intersection.length == 1) { 73 return false; 74 } 75 rayDist[i] = intersection[0]; 76 int index = (int) (intersection[2] * 3); 77 int index2 = (int) (((intersection[2] + 1) % polygonLength) * 3); 78 float h1 = polygon[index + 2] * mConfig.getShadowBoundRatio(); 79 float h2 = polygon[index2 + 2] * mConfig.getShadowBoundRatio(); 80 rayHeights[i] = h1 + intersection[1] * (h2 - h1); 81 } 82 83 int rings = mConfig.getLayers() + 1; 84 for (int i = 0; i < raysLength; i++) { 85 float dx = rays.dx[i]; 86 float dy = rays.dy[i]; 87 float cast = rayDist[i] * rayHeights[i]; 88 89 float opacity = .8f * (0.5f / (mConfig.getEdgeScale() / 10f)); 90 for (int j = 0; j < rings; j++) { 91 int p = i * rings + j; 92 float jf = j / (float) (rings - 1); 93 float t = rayDist[i] + jf * (cast - rayDist[i]); 94 95 mVertex[p * 2 + 0] = dx * t + cx; 96 mVertex[p * 2 + 1] = dy * t + cy; 97 // TODO: we might be able to optimize this in the future. 98 mColor[p * 4 + 0] = 0; 99 mColor[p * 4 + 1] = 0; 100 mColor[p * 4 + 2] = 0; 101 mColor[p * 4 + 3] = (1 - jf) * opacity; 102 } 103 } 104 105 int k = 0; 106 for (int i = 0; i < mConfig.getRays(); i++) { 107 for (int j = 0; j < mConfig.getLayers(); j++) { 108 int r1 = j + rings * i; 109 int r2 = j + rings * ((i + 1) % mConfig.getRays()); 110 111 mIndex[k * 3 + 0] = r1; 112 mIndex[k * 3 + 1] = r1 + 1; 113 mIndex[k * 3 + 2] = r2; 114 k++; 115 mIndex[k * 3 + 0] = r2; 116 mIndex[k * 3 + 1] = r1 + 1; 117 mIndex[k * 3 + 2] = r2 + 1; 118 k++; 119 } 120 } 121 int ringOffset = 0; 122 for (int i = 1; i < mConfig.getRays() - 1; i++, k++) { 123 mIndex[k * 3 + 0] = ringOffset; 124 mIndex[k * 3 + 1] = ringOffset + rings * i; 125 mIndex[k * 3 + 2] = ringOffset + rings * (1 + i); 126 } 127 return true; 128 } 129 getIndex()130 public int[] getIndex() { 131 return mIndex; 132 } 133 134 /** 135 * @return list of vertices in 2d in format : {x1, y1, x2, y2 ...} 136 */ getVertex()137 public float[] getVertex() { 138 return mVertex; 139 } 140 getColor()141 public float[] getColor() { 142 return mColor; 143 } 144 145 private static class Rays { 146 public final float[] dx; 147 public final float[] dy; 148 public final double deltaAngle; 149 Rays(int rays)150 public Rays(int rays) { 151 dx = new float[rays]; 152 dy = new float[rays]; 153 deltaAngle = 2 * Math.PI / rays; 154 155 for (int i = 0; i < rays; i++) { 156 dx[i] = (float) Math.sin(deltaAngle * i); 157 dy[i] = (float) Math.cos(deltaAngle * i); 158 } 159 } 160 } 161 162 } 163