1/*
2 * Copyright (C) 2017 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
17package com.android.layoutlib.bridge.shadowutil;
18
19import android.annotation.NonNull;
20import android.graphics.Bitmap;
21import android.graphics.Bitmap.Config;
22import android.graphics.Canvas;
23
24public class ShadowBuffer {
25
26    private int mWidth;
27    private int mHeight;
28    private Bitmap mBitmap;
29    private int[] mData;
30
31    public ShadowBuffer(int width, int height) {
32        mWidth = width;
33        mHeight = height;
34        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
35        mData = new int[mBitmap.getWidth() * mBitmap.getHeight()];
36        mBitmap.getPixels(mData, 0, mBitmap.getWidth(), 0, 0, mBitmap.getWidth(),
37                mBitmap.getHeight());
38    }
39
40    public void generateTriangles(@NonNull float[] strip, float scale) {
41        for (int i = 0; i < strip.length - 8; i += 3) {
42            float fx3 = strip[i];
43            float fy3 = strip[i + 1];
44            float fz3 = scale * strip[i + 2];
45
46            float fx2 = strip[i + 3];
47            float fy2 = strip[i + 4];
48            float fz2 = scale * strip[i + 5];
49
50            float fx1 = strip[i + 6];
51            float fy1 = strip[i + 7];
52            float fz1 = scale * strip[i + 8];
53
54            if (fx1 * (fy2 - fy3) + fx2 * (fy3 - fy1) + fx3 * (fy1 - fy2) == 0) {
55                continue;
56            }
57
58            triangleZBuffMin(mData, mWidth, mHeight, fx3, fy3, fz3, fx2, fy2, fz2, fx1, fy1, fz1);
59            triangleZBuffMin(mData, mWidth, mHeight, fx1, fy1, fz1, fx2, fy2, fz2, fx3, fy3, fz3);
60        }
61        mBitmap.setPixels(mData, 0, mBitmap.getWidth(), 0, 0, mBitmap.getWidth(),
62                mBitmap.getHeight());
63    }
64
65    private void triangleZBuffMin(@NonNull int[] buff, int w, int h, float fx3, float fy3,
66            float fz3, float fx2, float fy2, float fz2, float fx1, float fy1, float fz1) {
67        if (((fx1 - fx2) * (fy3 - fy2) - (fy1 - fy2) * (fx3 - fx2)) < 0) {
68            float tmpX = fx1;
69            float tmpY = fy1;
70            float tmpZ = fz1;
71            fx1 = fx2;
72            fy1 = fy2;
73            fz1 = fz2;
74            fx2 = tmpX;
75            fy2 = tmpY;
76            fz2 = tmpZ;
77        }
78        double d = (fx1 * (fy3 - fy2) - fx2 * fy3 + fx3 * fy2 + (fx2 - fx3) * fy1);
79
80        if (d == 0) {
81            return;
82        }
83        float dx = (float) (-(fy1 * (fz3 - fz2) - fy2 * fz3 + fy3 * fz2 + (fy2 - fy3) * fz1) / d);
84        float dy = (float) ((fx1 * (fz3 - fz2) - fx2 * fz3 + fx3 * fz2 + (fx2 - fx3) * fz1) / d);
85        float zOff = (float) ((fx1 * (fy3 * fz2 - fy2 * fz3) + fy1 * (fx2 * fz3 - fx3 * fz2) +
86                (fx3 * fy2 - fx2 * fy3) * fz1) / d);
87
88        int Y1 = (int) (16.0f * fy1 + .5f);
89        int Y2 = (int) (16.0f * fy2 + .5f);
90        int Y3 = (int) (16.0f * fy3 + .5f);
91
92        int X1 = (int) (16.0f * fx1 + .5f);
93        int X2 = (int) (16.0f * fx2 + .5f);
94        int X3 = (int) (16.0f * fx3 + .5f);
95
96        int DX12 = X1 - X2;
97        int DX23 = X2 - X3;
98        int DX31 = X3 - X1;
99
100        int DY12 = Y1 - Y2;
101        int DY23 = Y2 - Y3;
102        int DY31 = Y3 - Y1;
103
104        int FDX12 = DX12 << 4;
105        int FDX23 = DX23 << 4;
106        int FDX31 = DX31 << 4;
107
108        int FDY12 = DY12 << 4;
109        int FDY23 = DY23 << 4;
110        int FDY31 = DY31 << 4;
111
112        int minX = (min(X1, X2, X3) + 0xF) >> 4;
113        int maxX = (max(X1, X2, X3) + 0xF) >> 4;
114        int minY = (min(Y1, Y2, Y3) + 0xF) >> 4;
115        int maxY = (max(Y1, Y2, Y3) + 0xF) >> 4;
116
117        if (minY < 0) {
118            minY = 0;
119        }
120        if (minX < 0) {
121            minX = 0;
122        }
123        if (maxX > w) {
124            maxX = w;
125        }
126        if (maxY > h) {
127            maxY = h;
128        }
129        int off = minY * w;
130
131        int C1 = DY12 * X1 - DX12 * Y1;
132        int C2 = DY23 * X2 - DX23 * Y2;
133        int C3 = DY31 * X3 - DX31 * Y3;
134
135        if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) {
136            C1++;
137        }
138        if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) {
139            C2++;
140        }
141        if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) {
142            C3++;
143        }
144        int CY1 = C1 + DX12 * (minY << 4) - DY12 * (minX << 4);
145        int CY2 = C2 + DX23 * (minY << 4) - DY23 * (minX << 4);
146        int CY3 = C3 + DX31 * (minY << 4) - DY31 * (minX << 4);
147
148        for (int y = minY; y < maxY; y++) {
149            int CX1 = CY1;
150            int CX2 = CY2;
151            int CX3 = CY3;
152            float p = zOff + dy * y;
153            for (int x = minX; x < maxX; x++) {
154                if (CX1 > 0 && CX2 > 0 && CX3 > 0) {
155                    int point = x + off;
156                    float zVal = p + dx * x;
157                    buff[point] |= ((int) (zVal * 255)) << 24;
158                }
159                CX1 -= FDY12;
160                CX2 -= FDY23;
161                CX3 -= FDY31;
162            }
163            CY1 += FDX12;
164            CY2 += FDX23;
165            CY3 += FDX31;
166            off += w;
167        }
168    }
169
170    private int min(int x1, int x2, int x3) {
171        return (x1 > x2) ? ((x2 > x3) ? x3 : x2) : ((x1 > x3) ? x3 : x1);
172    }
173
174    private int max(int x1, int x2, int x3) {
175        return (x1 < x2) ? ((x2 < x3) ? x3 : x2) : ((x1 < x3) ? x3 : x1);
176    }
177
178    public void draw(@NonNull Canvas c) {
179        c.drawBitmap(mBitmap, 0, 0, null);
180    }
181}
182