Home | History | Annotate | Download | only in shadow
      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 
     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      */
     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 
    130     public int[] getIndex() {
    131         return mIndex;
    132     }
    133 
    134     /**
    135      * @return list of vertices in 2d in format : {x1, y1, x2, y2 ...}
    136      */
    137     public float[] getVertex() {
    138         return mVertex;
    139     }
    140 
    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 
    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