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"
1887f9df880e4a5bfba65d2ed413b3ead649595129Chris Craik#define ATRACE_TAG ATRACE_TAG_VIEW
1955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
2055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include <math.h>
2155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include <utils/Log.h>
2287f9df880e4a5bfba65d2ed413b3ead649595129Chris Craik#include <utils/Trace.h>
2355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
2455bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "AmbientShadow.h"
25f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik#include "Caches.h"
2655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "ShadowTessellator.h"
277b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui#include "SpotShadow.h"
2855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
2955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuinamespace android {
3055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghuinamespace uirenderer {
3155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
3205f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craikvoid ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
3350ecf849cb7ccc3482517b74d2214b347927791eztenghui        const Vector3* casterPolygon, int casterVertexCount,
34af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui        const Vector3& centroid3d, const Rect& casterBounds,
35af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui        const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer) {
3687f9df880e4a5bfba65d2ed413b3ead649595129Chris Craik    ATRACE_CALL();
3787f9df880e4a5bfba65d2ed413b3ead649595129Chris Craik
3855bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // A bunch of parameters to tweak the shadow.
3955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    // TODO: Allow some of these changable by debug settings or APIs.
408def74de33b197c0c5ec8774576b1d71c7ec4f1bztenghui    float heightFactor = 1.0f / 128;
417b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui    const float geomFactor = 64;
4255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
43f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    Caches& caches = Caches::getInstance();
44f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    if (CC_UNLIKELY(caches.propertyAmbientRatio > 0.0f)) {
45f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik        heightFactor *= caches.propertyAmbientRatio;
46f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    }
47f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik
48af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    Rect ambientShadowBounds(casterBounds);
49af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    ambientShadowBounds.outset(maxZ * geomFactor * heightFactor);
50af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui
51af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    if (!localClip.intersects(ambientShadowBounds)) {
52af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui#if DEBUG_SHADOW
53af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui        ALOGD("Ambient shadow is out of clip rect!");
54af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui#endif
5505f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik        return;
56af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    }
57af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui
5805f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
5950ecf849cb7ccc3482517b74d2214b347927791eztenghui            casterVertexCount, centroid3d, heightFactor, geomFactor,
6050ecf849cb7ccc3482517b74d2214b347927791eztenghui            shadowVertexBuffer);
6155bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}
6255bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui
6305f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craikvoid ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
64c50a03d78aaedd0003377e98710e7038bda330e9ztenghui        const Vector3* casterPolygon, int casterVertexCount, const Vector3& casterCentroid,
65797b95b26bbb7557678af78b9a2a61830158920fChris Craik        const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
66797b95b26bbb7557678af78b9a2a61830158920fChris Craik        const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
6787f9df880e4a5bfba65d2ed413b3ead649595129Chris Craik    ATRACE_CALL();
6887f9df880e4a5bfba65d2ed413b3ead649595129Chris Craik
69f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    Caches& caches = Caches::getInstance();
70f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik
71797b95b26bbb7557678af78b9a2a61830158920fChris Craik    Vector3 adjustedLightCenter(lightCenter);
72f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    if (CC_UNLIKELY(caches.propertyLightPosY > 0)) {
73797b95b26bbb7557678af78b9a2a61830158920fChris Craik        adjustedLightCenter.y = - caches.propertyLightPosY; // negated since this shifts up
74f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    }
75f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    if (CC_UNLIKELY(caches.propertyLightPosZ > 0)) {
76797b95b26bbb7557678af78b9a2a61830158920fChris Craik        adjustedLightCenter.z = caches.propertyLightPosZ;
77f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    }
78f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik
797b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui#if DEBUG_SHADOW
80797b95b26bbb7557678af78b9a2a61830158920fChris Craik    ALOGD("light center %f %f %f",
81797b95b26bbb7557678af78b9a2a61830158920fChris Craik            adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z);
827b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui#endif
833197cded4e265bc99dc82d695bbb7163fe134ed4Chris Craik
843197cded4e265bc99dc82d695bbb7163fe134ed4Chris Craik    // light position (because it's in local space) needs to compensate for receiver transform
853197cded4e265bc99dc82d695bbb7163fe134ed4Chris Craik    // TODO: should apply to light orientation, not just position
863197cded4e265bc99dc82d695bbb7163fe134ed4Chris Craik    Matrix4 reverseReceiverTransform;
873197cded4e265bc99dc82d695bbb7163fe134ed4Chris Craik    reverseReceiverTransform.loadInverse(receiverTransform);
88797b95b26bbb7557678af78b9a2a61830158920fChris Craik    reverseReceiverTransform.mapPoint3d(adjustedLightCenter);
893197cded4e265bc99dc82d695bbb7163fe134ed4Chris Craik
90726118b35240957710d4d85fb5747e2ba8b934f7Chris Craik    const int lightVertexCount = 8;
91f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) {
92797b95b26bbb7557678af78b9a2a61830158920fChris Craik        lightRadius = caches.propertyLightDiameter;
93f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik    }
94f5be3ca5cc5b3a10747b577f60059a99862bb9a8Chris Craik
95af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    // Now light and caster are both in local space, we will check whether
96af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    // the shadow is within the clip area.
97797b95b26bbb7557678af78b9a2a61830158920fChris Craik    Rect lightRect = Rect(adjustedLightCenter.x - lightRadius, adjustedLightCenter.y - lightRadius,
98797b95b26bbb7557678af78b9a2a61830158920fChris Craik            adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
99af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    lightRect.unionWith(localClip);
100af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    if (!lightRect.intersects(casterBounds)) {
101af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui#if DEBUG_SHADOW
102af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui        ALOGD("Spot shadow is out of clip rect!");
103af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui#endif
10405f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik        return;
105af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui    }
106af6f7ed8dd4288a41d0a07a1f0f0be7d6d035b33ztenghui
107c50a03d78aaedd0003377e98710e7038bda330e9ztenghui    SpotShadow::createSpotShadow(isCasterOpaque, adjustedLightCenter, lightRadius,
108c50a03d78aaedd0003377e98710e7038bda330e9ztenghui            casterPolygon, casterVertexCount, casterCentroid, shadowVertexBuffer);
109c50a03d78aaedd0003377e98710e7038bda330e9ztenghui
11050ecf849cb7ccc3482517b74d2214b347927791eztenghui#if DEBUG_SHADOW
11150ecf849cb7ccc3482517b74d2214b347927791eztenghui     if(shadowVertexBuffer.getVertexCount() <= 0) {
11250ecf849cb7ccc3482517b74d2214b347927791eztenghui        ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
11350ecf849cb7ccc3482517b74d2214b347927791eztenghui     }
11450ecf849cb7ccc3482517b74d2214b347927791eztenghui#endif
1157b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui}
11663d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
11763d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghuivoid ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
11863d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    int currentIndex = 0;
11963d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    const int rays = SHADOW_RAY_COUNT;
12063d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    // For the penumbra area.
12150ecf849cb7ccc3482517b74d2214b347927791eztenghui    for (int layer = 0; layer < 2; layer ++) {
12250ecf849cb7ccc3482517b74d2214b347927791eztenghui        int baseIndex = layer * rays;
12350ecf849cb7ccc3482517b74d2214b347927791eztenghui        for (int i = 0; i < rays; i++) {
12450ecf849cb7ccc3482517b74d2214b347927791eztenghui            shadowIndices[currentIndex++] = i + baseIndex;
12550ecf849cb7ccc3482517b74d2214b347927791eztenghui            shadowIndices[currentIndex++] = rays + i + baseIndex;
12650ecf849cb7ccc3482517b74d2214b347927791eztenghui        }
12750ecf849cb7ccc3482517b74d2214b347927791eztenghui        // To close the loop, back to the ray 0.
12850ecf849cb7ccc3482517b74d2214b347927791eztenghui        shadowIndices[currentIndex++] = 0 + baseIndex;
12950ecf849cb7ccc3482517b74d2214b347927791eztenghui         // Note this is the same as the first index of next layer loop.
13050ecf849cb7ccc3482517b74d2214b347927791eztenghui        shadowIndices[currentIndex++] = rays + baseIndex;
13163d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
13263d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
13363d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui#if DEBUG_SHADOW
13450ecf849cb7ccc3482517b74d2214b347927791eztenghui    if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
13550ecf849cb7ccc3482517b74d2214b347927791eztenghui        ALOGW("vertex index count is wrong. current %d, expected %d",
13650ecf849cb7ccc3482517b74d2214b347927791eztenghui                currentIndex, MAX_SHADOW_INDEX_COUNT);
13763d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
13850ecf849cb7ccc3482517b74d2214b347927791eztenghui    for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
13963d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
14063d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
14163d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui#endif
14263d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui}
14363d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
14463d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui/**
14563d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui * Calculate the centroid of a 2d polygon.
14663d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui *
14763d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui * @param poly The polygon, which is represented in a Vector2 array.
14863d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui * @param polyLength The length of the polygon in terms of number of vertices.
14963d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui * @return the centroid of the polygon.
15063d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui */
15163d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghuiVector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
15263d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    double sumx = 0;
15363d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    double sumy = 0;
15463d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    int p1 = polyLength - 1;
15563d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    double area = 0;
15663d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    for (int p2 = 0; p2 < polyLength; p2++) {
15763d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        double x1 = poly[p1].x;
15863d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        double y1 = poly[p1].y;
15963d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        double x2 = poly[p2].x;
16063d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        double y2 = poly[p2].y;
16163d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        double a = (x1 * y2 - x2 * y1);
16263d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        sumx += (x1 + x2) * a;
16363d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        sumy += (y1 + y2) * a;
16463d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        area += a;
16563d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui        p1 = p2;
16663d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
16763d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
16863d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    Vector2 centroid = poly[0];
16963d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    if (area != 0) {
1701aa5d2d7068147ff781cfe911a93f01593a68c79John Reck        centroid = (Vector2){static_cast<float>(sumx / (3 * area)),
1711aa5d2d7068147ff781cfe911a93f01593a68c79John Reck            static_cast<float>(sumy / (3 * area))};
17263d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    } else {
17350ecf849cb7ccc3482517b74d2214b347927791eztenghui        ALOGW("Area is 0 while computing centroid!");
17463d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
17563d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    return centroid;
17663d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui}
17763d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
178c50a03d78aaedd0003377e98710e7038bda330e9ztenghui// Make sure p1 -> p2 is going CW around the poly.
179c50a03d78aaedd0003377e98710e7038bda330e9ztenghuiVector2 ShadowTessellator::calculateNormal(const Vector2& p1, const Vector2& p2) {
180c50a03d78aaedd0003377e98710e7038bda330e9ztenghui    Vector2 result = p2 - p1;
181c50a03d78aaedd0003377e98710e7038bda330e9ztenghui    if (result.x != 0 || result.y != 0) {
182c50a03d78aaedd0003377e98710e7038bda330e9ztenghui        result.normalize();
183c50a03d78aaedd0003377e98710e7038bda330e9ztenghui        // Calculate the normal , which is CCW 90 rotate to the delta.
184c50a03d78aaedd0003377e98710e7038bda330e9ztenghui        float tempy = result.y;
185c50a03d78aaedd0003377e98710e7038bda330e9ztenghui        result.y = result.x;
186c50a03d78aaedd0003377e98710e7038bda330e9ztenghui        result.x = -tempy;
187c50a03d78aaedd0003377e98710e7038bda330e9ztenghui    }
188c50a03d78aaedd0003377e98710e7038bda330e9ztenghui    return result;
189c50a03d78aaedd0003377e98710e7038bda330e9ztenghui}
1902e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui/**
1912e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui * Test whether the polygon is order in clockwise.
1922e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui *
1932e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui * @param polygon the polygon as a Vector2 array
1942e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui * @param len the number of points of the polygon
1952e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui */
1962e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghuibool ShadowTessellator::isClockwise(const Vector2* polygon, int len) {
197f11310f395a135ac7ef204ced5b3d3facf491422ztenghui    if (len < 2 || polygon == NULL) {
198f11310f395a135ac7ef204ced5b3d3facf491422ztenghui        return true;
199f11310f395a135ac7ef204ced5b3d3facf491422ztenghui    }
2002e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    double sum = 0;
2012e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    double p1x = polygon[len - 1].x;
2022e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    double p1y = polygon[len - 1].y;
2032e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    for (int i = 0; i < len; i++) {
2042e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui
2052e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        double p2x = polygon[i].x;
2062e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        double p2y = polygon[i].y;
2072e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        sum += p1x * p2y - p2x * p1y;
2082e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        p1x = p2x;
2092e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        p1y = p2y;
2102e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    }
2112e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    return sum < 0;
2122e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui}
2132e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui
2142e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghuibool ShadowTessellator::isClockwisePath(const SkPath& path) {
2152e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    SkPath::Iter iter(path, false);
2162e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    SkPoint pts[4];
2172e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    SkPath::Verb v;
2182e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui
2192e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    Vector<Vector2> arrayForDirection;
2202e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    while (SkPath::kDone_Verb != (v = iter.next(pts))) {
2212e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            switch (v) {
2222e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            case SkPath::kMove_Verb:
2231aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[0].x(), pts[0].y()});
2242e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui                break;
2252e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            case SkPath::kLine_Verb:
2261aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
2272e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui                break;
2282e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            case SkPath::kQuad_Verb:
2291aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
2301aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
2312e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui                break;
2322e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            case SkPath::kCubic_Verb:
2331aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
2341aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
2351aa5d2d7068147ff781cfe911a93f01593a68c79John Reck                arrayForDirection.add((Vector2){pts[3].x(), pts[3].y()});
2362e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui                break;
2372e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            default:
2382e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui                break;
2392e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui            }
2402e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    }
2412e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui
2422e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    return isClockwise(arrayForDirection.array(), arrayForDirection.size());
2432e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui}
2442e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui
2452e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghuivoid ShadowTessellator::reverseVertexArray(Vertex* polygon, int len) {
2462e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    int n = len / 2;
2472e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    for (int i = 0; i < n; i++) {
2482e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        Vertex tmp = polygon[i];
2492e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        int k = len - 1 - i;
2502e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        polygon[i] = polygon[k];
2512e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui        polygon[k] = tmp;
2522e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui    }
2532e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui}
2542e023f3827dfc0dfc1ed7c3dd54d02b4a993f0b4ztenghui
255512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghuiint ShadowTessellator::getExtraVertexNumber(const Vector2& vector1,
256512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui        const Vector2& vector2, float divisor) {
257512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // When there is no distance difference, there is no need for extra vertices.
258512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    if (vector1.lengthSquared() == 0 || vector2.lengthSquared() == 0) {
259512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui        return 0;
260512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    }
261512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // The formula is :
262512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // extraNumber = floor(acos(dot(n1, n2)) / (M_PI / EXTRA_VERTEX_PER_PI))
263512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // The value ranges for each step are:
264512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // dot( ) --- [-1, 1]
265512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // acos( )     --- [0, M_PI]
266512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // floor(...)  --- [0, EXTRA_VERTEX_PER_PI]
267512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    float dotProduct = vector1.dot(vector2);
268512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // TODO: Use look up table for the dotProduct to extraVerticesNumber
269512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    // computation, if needed.
270512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    float angle = acosf(dotProduct);
271512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    return (int) floor(angle / divisor);
272512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui}
273512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui
274512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghuivoid ShadowTessellator::checkOverflow(int used, int total, const char* bufferName) {
275512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui    LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d",
276512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui            bufferName, used, total);
277512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui}
278512e643ce83b1d48ad9630a3622276f795cf4fb2ztenghui
27955bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; // namespace uirenderer
28055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui}; // namespace android
281