AmbientShadow.cpp revision 55bfb4e728fe1db619af5d2c287f4abe711b3343
155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/*
255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Copyright (C) 2013 The Android Open Source Project
355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Licensed under the Apache License, Version 2.0 (the "License");
555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * you may not use this file except in compliance with the License.
655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * You may obtain a copy of the License at
755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *      http://www.apache.org/licenses/LICENSE-2.0
955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
1055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Unless required by applicable law or agreed to in writing, software
1155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * distributed under the License is distributed on an "AS IS" BASIS,
1255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * See the License for the specific language governing permissions and
1455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * limitations under the License.
1555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */
1655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
1755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#define LOG_TAG "OpenGLRenderer"
1855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
1955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include <math.h>
2055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include <utils/Log.h>
2155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
2255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "AmbientShadow.h"
2355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "Vertex.h"
2455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
2555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuinamespace android {
2655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuinamespace uirenderer {
2755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
2855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/**
2955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the shadows as a triangle strips while alpha value as the
3055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * shadow values.
3155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
3255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertices The shadow caster's polygon, which is represented in a Vector3
3355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                  array.
3455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertexCount The length of caster's polygon in terms of number of
3555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                    vertices.
3655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rays The number of rays shooting out from the centroid.
3755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param layers The number of rings outside the polygon.
3855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param strength The darkness of the shadow, the higher, the darker.
3955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param heightFactor The factor showing the higher the object, the lighter the
4055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                     shadow.
4155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param geomFactor The factor scaling the geometry expansion along the normal.
4255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
4355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param shadowVertexBuffer Return an floating point array of (x, y, a)
4455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *               triangle strips mode.
4555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */
4655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount,
4755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        int rays, int layers, float strength, float heightFactor, float geomFactor,
4855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        VertexBuffer& shadowVertexBuffer) {
4955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
5055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Validate the inputs.
5155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    if (strength <= 0 || heightFactor <= 0 || layers <= 0 || rays <= 0
5255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        || geomFactor <= 0) {
5355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#if DEBUG_SHADOW
5455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        ALOGE("Invalid input for createAmbientShadow(), early return!");
5555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#endif
5655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        return;
5755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
5855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int rings = layers + 1;
5955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int size = rays * rings;
6055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    Vector2 centroid;
6155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    calculatePolygonCentroid(vertices, vertexCount, centroid);
6255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
6355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    Vector2 dir[rays];
6455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float rayDist[rays];
6555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float rayHeight[rays];
6655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    calculateRayDirections(rays, dir);
6755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
6855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Calculate the length and height of the points along the edge.
6955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    //
7055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // The math here is:
7155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Intersect each ray (starting from the centroid) with the polygon.
7255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    for (int i = 0; i < rays; i++) {
7355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        int edgeIndex;
7455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float edgeFraction;
7555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float rayDistance;
7655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        calculateIntersection(vertices, vertexCount, centroid, dir[i], edgeIndex,
7755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                edgeFraction, rayDistance);
7855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        rayDist[i] = rayDistance;
7955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        if (edgeIndex < 0 || edgeIndex >= vertexCount) {
8055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#if DEBUG_SHADOW
8155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            ALOGE("Invalid edgeIndex!");
8255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#endif
8355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            edgeIndex = 0;
8455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        }
8555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float h1 = vertices[edgeIndex].z;
8655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float h2 = vertices[((edgeIndex + 1) % vertexCount)].z;
8755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        rayHeight[i] = h1 + edgeFraction * (h2 - h1);
8855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
8955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
9055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // The output buffer length basically is roughly rays * layers, but since we
9155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // need triangle strips, so we need to duplicate vertices to accomplish that.
9255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    const int shadowVertexCount = (2 + rays + ((layers) * 2 * (rays + 1)));
9355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(shadowVertexCount);
9455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
9555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Calculate the vertex of the shadows.
9655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    //
9755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // The math here is:
9855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Along the edges of the polygon, for each intersection point P (generated above),
9955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // calculate the normal N, which should be perpendicular to the edge of the
10055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // polygon (represented by the neighbor intersection points) .
10155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Shadow's vertices will be generated as : P + N * scale.
10255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int currentIndex = 0;
10355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    for (int r = 0; r < layers; r++) {
10455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        int firstInLayer = currentIndex;
10555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        for (int i = 0; i < rays; i++) {
10655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
10755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            Vector2 normal(1.0f, 0.0f);
10855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            calculateNormal(rays, i, dir, rayDist, normal);
10955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
11055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
11155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
11255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            // The vertex should be start from rayDist[i] then scale the
11355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            // normalizeNormal!
11455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            Vector2 intersection = dir[i] * rayDist[i] + centroid;
11555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
11655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            // Use 2 rings' vertices to complete one layer's strip
11755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            for (int j = r; j < (r + 2); j++) {
11855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                float jf = j / (float)(rings - 1);
11955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
12055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                float expansionDist = rayHeight[i] / heightFactor * geomFactor * jf;
12155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                AlphaVertex::set(&shadowVertices[currentIndex],
12255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                        intersection.x + normal.x * expansionDist,
12355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                        intersection.y + normal.y * expansionDist,
12455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                        (1 - jf) * opacity);
12555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                currentIndex++;
12655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            }
12755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        }
12855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
12955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // From one layer to the next, we need to duplicate the vertex to
13055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // continue as a single strip.
13155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        shadowVertices[currentIndex] = shadowVertices[firstInLayer];
13255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        currentIndex++;
13355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        shadowVertices[currentIndex] = shadowVertices[firstInLayer + 1];
13455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        currentIndex++;
13555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
13655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
13755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // After all rings are done, we need to jump into the polygon.
13855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // In order to keep everything in a strip, we need to duplicate the last one
13955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // of the rings and the first one inside the polygon.
14055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int lastInRings = currentIndex - 1;
14155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    shadowVertices[currentIndex] = shadowVertices[lastInRings];
14255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    currentIndex++;
14355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
14455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // We skip one and fill it back after we finish the internal triangles.
14555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    currentIndex++;
14655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int firstInternal = currentIndex;
14755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
14855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Combine the internal area of the polygon into a triangle strip, too.
14955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // The basic idea is zig zag between the intersection points.
15055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // 0 -> (n - 1) -> 1 -> (n - 2) ...
15155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    for (int k = 0; k < rays; k++) {
15255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        int  i = k / 2;
15355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        if ((k & 1) == 1) { // traverse the inside in a zig zag pattern for strips
15455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            i = rays - i - 1;
15555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        }
15655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float cast = rayDist[i] * (1 + rayHeight[i] / heightFactor);
15755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
15855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float t = rayDist[i];
15955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
16055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        AlphaVertex::set(&shadowVertices[currentIndex], dir[i].x * t + centroid.x,
16155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                dir[i].y * t + centroid.y, opacity);
16255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        currentIndex++;
16355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
16455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
16555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    currentIndex = firstInternal - 1;
16655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    shadowVertices[currentIndex] = shadowVertices[firstInternal];
16755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}
16855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
16955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/**
17055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the centroid of a given polygon.
17155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
17255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertices The shadow caster's polygon, which is represented in a
17355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                 straight Vector3 array.
17455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertexCount The length of caster's polygon in terms of number of vertices.
17555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
17655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param centroid Return the centroid of the polygon.
17755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */
17855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculatePolygonCentroid(const Vector3* vertices, int vertexCount,
17955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        Vector2& centroid) {
18055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float sumx = 0;
18155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float sumy = 0;
18255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int p1 = vertexCount - 1;
18355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float area = 0;
18455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    for (int p2 = 0; p2 < vertexCount; p2++) {
18555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float x1 = vertices[p1].x;
18655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float y1 = vertices[p1].y;
18755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float x2 = vertices[p2].x;
18855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float y2 = vertices[p2].y;
18955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float a = (x1 * y2 - x2 * y1);
19055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        sumx += (x1 + x2) * a;
19155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        sumy += (y1 + y2) * a;
19255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        area += a;
19355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        p1 = p2;
19455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
19555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
19655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    if (area == 0) {
19755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#if DEBUG_SHADOW
19855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        ALOGE("Area is 0!");
19955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#endif
20055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        centroid.x = vertices[0].x;
20155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        centroid.y = vertices[0].y;
20255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    } else {
20355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        centroid.x = sumx / (3 * area);
20455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        centroid.y = sumy / (3 * area);
20555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
20655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}
20755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
20855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/**
20955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Generate an array of rays' direction vectors.
21055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
21155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rays The number of rays shooting out from the centroid.
21255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param dir Return the array of ray vectors.
21355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */
21455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculateRayDirections(int rays, Vector2* dir) {
21555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float deltaAngle = 2 * M_PI / rays;
21655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
21755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    for (int i = 0; i < rays; i++) {
21855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        dir[i].x = sinf(deltaAngle * i);
21955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        dir[i].y = cosf(deltaAngle * i);
22055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
22155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}
22255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
22355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/**
22455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the intersection of a ray hitting the polygon.
22555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
22655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertices The shadow caster's polygon, which is represented in a
22755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                 Vector3 array.
22855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param vertexCount The length of caster's polygon in terms of number of vertices.
22955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param start The starting point of the ray.
23055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param dir The direction vector of the ray.
23155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
23255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param outEdgeIndex Return the index of the segment (or index of the starting
23355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                     vertex) that ray intersect with.
23455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param outEdgeFraction Return the fraction offset from the segment starting
23555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *                        index.
23655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param outRayDist Return the ray distance from centroid to the intersection.
23755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */
23855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculateIntersection(const Vector3* vertices, int vertexCount,
23955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        const Vector2& start, const Vector2& dir, int& outEdgeIndex,
24055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float& outEdgeFraction, float& outRayDist) {
24155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float startX = start.x;
24255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float startY = start.y;
24355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float dirX = dir.x;
24455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    float dirY = dir.y;
24555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Start the search from the last edge from poly[len-1] to poly[0].
24655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int p1 = vertexCount - 1;
24755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
24855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    for (int p2 = 0; p2 < vertexCount; p2++) {
24955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float p1x = vertices[p1].x;
25055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float p1y = vertices[p1].y;
25155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float p2x = vertices[p2].x;
25255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float p2y = vertices[p2].y;
25355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
25455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // The math here is derived from:
25555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // f(t, v) = p1x * (1 - t) + p2x * t - (startX + dirX * v) = 0;
25655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // g(t, v) = p1y * (1 - t) + p2y * t - (startY + dirY * v) = 0;
25755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        float div = (dirX * (p1y - p2y) + dirY * p2x - dirY * p1x);
25855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        if (div != 0) {
25955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            float t = (dirX * (p1y - startY) + dirY * startX - dirY * p1x) / (div);
26055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            if (t > 0 && t <= 1) {
26155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                float t2 = (p1x * (startY - p2y)
26255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                            + p2x * (p1y - startY)
26355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                            + startX * (p2y - p1y)) / div;
26455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                if (t2 > 0) {
26555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                    outEdgeIndex = p1;
26655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                    outRayDist = t2;
26755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                    outEdgeFraction = t;
26855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                    return;
26955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui                }
27055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui            }
27155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        }
27255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        p1 = p2;
27355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
27455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    return;
27555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui};
27655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
27755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui/**
27855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * Calculate the normal at the intersection point between a ray and the polygon.
27955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
28055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rays The total number of rays.
28155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param currentRayIndex The index of the ray which the normal is based on.
28255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param dir The array of the all the rays directions.
28355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param rayDist The pre-computed ray distances array.
28455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui *
28555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui * @param normal Return the normal.
28655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui */
28755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuivoid AmbientShadow::calculateNormal(int rays, int currentRayIndex,
28855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        const Vector2* dir, const float* rayDist, Vector2& normal) {
28955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int preIndex = (currentRayIndex - 1 + rays) % rays;
29055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    int postIndex = (currentRayIndex + 1) % rays;
29155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    Vector2 p1 = dir[preIndex] * rayDist[preIndex];
29255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    Vector2 p2 = dir[postIndex] * rayDist[postIndex];
29355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
29455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // Now the V (deltaX, deltaY) is the vector going CW around the poly.
29555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    Vector2 delta = p2 - p1;
29655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    if (delta.length() != 0) {
29755bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        delta.normalize();
29855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // Calculate the normal , which is CCW 90 rotate to the V.
29955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        // 90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z)
30055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        normal.x = -delta.y;
30155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui        normal.y = delta.x;
30255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    }
30355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}
30455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
30555bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; // namespace uirenderer
30655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; // namespace android
307