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.graphics.Bitmap;
20 import android.graphics.Bitmap.Config;
21 import android.view.math.Math3DHelper;
22 
23 import java.util.Arrays;
24 
25 import static java.lang.Math.max;
26 import static java.lang.Math.min;
27 
28 /**
29  * 2D Triangle buffer element that colours using z value. (z scale set).
30  */
31 class TriangleBuffer {
32     int mWidth;
33     int mHeight;
34     int mImgWidth;
35     int mImgHeight;
36     int mBorder;
37     Bitmap mBitmap;
38     int mData[];
39 
setSize(int width, int height, int border)40     public void setSize(int width, int height, int border) {
41         if (mWidth == width && mHeight == height) {
42             return;
43         }
44         mWidth = width-2*border;
45         mHeight = height-2*border;
46         mBorder = border;
47         mImgWidth = width;
48         mImgHeight = height;
49 
50         mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
51         mData = new int[width * height];
52     }
53 
drawTriangles(int[] index, float[] vert, float[] color,float scale)54     public void drawTriangles(int[] index, float[] vert, float[] color,float scale) {
55         int indexSize = index.length / 3;
56         for (int i = 0; i < indexSize; i++) {
57             int vIndex = index[i * 3 + 0];
58             float vx = vert[vIndex * 2 + 0];
59             float vy = vert[vIndex * 2 + 1];
60             float c =  scale*color[vIndex * 4 + 3];
61             float fx3 = vx, fy3 = vy, fz3 = c;
62 
63             vIndex = index[i * 3 + 1];
64             vx = vert[vIndex * 2 + 0];
65             vy = vert[vIndex * 2 + 1];
66             c =  scale*color[vIndex * 4 + 3];
67             float fx2 = vx, fy2 = vy, fz2 = c;
68 
69             vIndex = index[i * 3 + 2];
70             vx = vert[vIndex * 2 + 0];
71             vy = vert[vIndex * 2 + 1];
72             c =  scale*color[vIndex * 4 + 3];
73             float fx1 = vx, fy1 = vy, fz1 = c;
74 
75             triangleZBuffMin(mData, mImgWidth, mImgHeight, fx1, fy1, fz1, fx2, fy2,
76                     fz2, fx3, fy3, fz3);
77         }
78     }
79 
drawTriangles(float[] strip,float scale)80     public void drawTriangles(float[] strip,float scale) {
81         for (int i = 0; i < strip.length-8; i+=3) {
82             float fx3 = strip[i], fy3 = strip[i+1], fz3 = scale* strip[i+2];
83             float fx2 = strip[i+3], fy2 = strip[i+4], fz2 = scale* strip[i+5];
84             float fx1 = strip[i+6], fy1 = strip[i+7], fz1 = scale* strip[i+8];
85 
86             if (fx1*(fy2-fy3)+fx2*(fy3-fy1)+fx3*(fy1-fy2) ==0) {
87                 continue;
88             }
89             triangleZBuffMin(mData, mImgWidth, mImgHeight, fx3, fy3, fz3, fx2, fy2,
90                     fz2, fx1, fy1, fz1);
91         }
92     }
93 
createImage()94     public Bitmap createImage() {
95         mBitmap.setPixels(mData, 0, mWidth, 0, 0, mWidth, mHeight);
96         return mBitmap;
97     }
98 
triangleZBuffMin(int[] buff, int w, int h, float fx3, float fy3, float fz3, float fx2, float fy2, float fz2, float fx1, float fy1, float fz1)99     private static void triangleZBuffMin(int[] buff, int w, int h, float fx3,
100             float fy3, float fz3, float fx2, float fy2, float fz2, float fx1,
101             float fy1, float fz1) {
102         if (((fx1 - fx2) * (fy3 - fy2) - (fy1 - fy2) * (fx3 - fx2)) < 0) {
103             float tmpx = fx1;
104             float tmpy = fy1;
105             float tmpz = fz1;
106             fx1 = fx2;
107             fy1 = fy2;
108             fz1 = fz2;
109             fx2 = tmpx;
110             fy2 = tmpy;
111             fz2 = tmpz;
112         }
113         // using maxmima
114         // solve([x1*dx+y1*dy+zoff=z1,x2*dx+y2*dy+zoff=z2,x3*dx+y3*dy+zoff=z3],[dx,dy,zoff]);
115         double d = (fx1 * (fy3 - fy2) - fx2 * fy3 + fx3 * fy2 + (fx2 - fx3) * fy1);
116         if (d == 0) {
117             return;
118         }
119         float dx = (float) (-(fy1 * (fz3 - fz2) - fy2 * fz3 + fy3 * fz2 + (fy2 - fy3)
120                 * fz1) / d);
121         float dy = (float) ((fx1 * (fz3 - fz2) - fx2 * fz3 + fx3 * fz2 + (fx2 - fx3)
122                 * fz1) / d);
123         float zoff = (float) ((fx1 * (fy3 * fz2 - fy2 * fz3) + fy1
124                 * (fx2 * fz3 - fx3 * fz2) + (fx3 * fy2 - fx2 * fy3) * fz1) / d);
125 
126         // 28.4 fixed-point coordinates
127         int y1 = (int) (16.0f * fy1 + .5f);
128         int y2 = (int) (16.0f * fy2 + .5f);
129         int y3 = (int) (16.0f * fy3 + .5f);
130 
131         int x1 = (int) (16.0f * fx1 + .5f);
132         int x2 = (int) (16.0f * fx2 + .5f);
133         int x3 = (int) (16.0f * fx3 + .5f);
134 
135         int dx12 = x1 - x2;
136         int dx23 = x2 - x3;
137         int dx31 = x3 - x1;
138 
139         int dy12 = y1 - y2;
140         int dy23 = y2 - y3;
141         int dy31 = y3 - y1;
142 
143         int fdx12 = dx12 << 4;
144         int fdx23 = dx23 << 4;
145         int fdx31 = dx31 << 4;
146 
147         int fdy12 = dy12 << 4;
148         int fdy23 = dy23 << 4;
149         int fdy31 = dy31 << 4;
150 
151         int minx = (Math3DHelper.min(x1, x2, x3) + 0xF) >> 4;
152         int maxx = (Math3DHelper.max(x1, x2, x3) + 0xF) >> 4;
153         int miny = (Math3DHelper.min(y1, y2, y3) + 0xF) >> 4;
154         int maxy = (Math3DHelper.max(y1, y2, y3) + 0xF) >> 4;
155 
156         if (miny < 0) {
157             miny = 0;
158         }
159         if (minx < 0) {
160             minx = 0;
161         }
162         if (maxx > w) {
163             maxx = w;
164         }
165         if (maxy > h) {
166             maxy = h;
167         }
168         int off = miny * w;
169 
170         int c1 = dy12 * x1 - dx12 * y1;
171         int c2 = dy23 * x2 - dx23 * y2;
172         int c3 = dy31 * x3 - dx31 * y3;
173 
174         if (dy12 < 0 || (dy12 == 0 && dx12 > 0)) {
175             c1++;
176         }
177         if (dy23 < 0 || (dy23 == 0 && dx23 > 0)) {
178             c2++;
179         }
180         if (dy31 < 0 || (dy31 == 0 && dx31 > 0)) {
181             c3++;
182         }
183         int cy1 = c1 + dx12 * (miny << 4) - dy12 * (minx << 4);
184         int cy2 = c2 + dx23 * (miny << 4) - dy23 * (minx << 4);
185         int cy3 = c3 + dx31 * (miny << 4) - dy31 * (minx << 4);
186 
187         for (int y = miny; y < maxy; y++) {
188             int cx1 = cy1;
189             int cx2 = cy2;
190             int cx3 = cy3;
191             float p = zoff + dy * y;
192 
193             int startx = start(cx1, fdy12, minx, minx, maxx);
194             startx = start(cx2, fdy23, minx, startx, maxx);
195             startx = start(cx3, fdy31, minx, startx, maxx);
196 
197             cx1 -= (startx - minx) * fdy12;
198             cx2 -= (startx - minx) * fdy23;
199             cx3 -= (startx - minx) * fdy31;
200 
201             int endx = end(cx1, fdy12, startx, minx, maxx);
202             endx = end(cx2, fdy23, startx, minx, endx);
203             endx = end(cx3, fdy31, startx, minx, endx);
204 
205             for (int x = startx; x < endx; x++) {
206                 int point = x + off;
207                 float zval = p + dx * x;
208                 // Simple alpha-blending
209                 int prev = (buff[point] >> 24) & 0xFF;
210                 int res = (int) (zval * (255 - prev )) + prev;
211                 buff[point] = res << 24;
212             }
213             cy1 += fdx12;
214             cy2 += fdx23;
215             cy3 += fdx31;
216             off += w;
217         }
218     }
219 
220     /**
221      * Returns the minimum value of x in the range [minx, maxx]: y0 - dy * (x - x0) > 0
222      * If no value satisfies the expression, maxx is returned
223      *
224      * @param y0 - value in x0
225      * @param dy - delta y
226      * @param x0 - some position, for which value is known (y0)
227      * @param minx - start of the range
228      * @param maxx - end of the range
229      * @return minimum x
230      */
start(int y0, int dy, int x0, int minx, int maxx)231     private static int start(int y0, int dy, int x0, int minx, int maxx) {
232         if (y0 > 0) {
233             return minx;
234         }
235         if (dy >= 0) {
236             return maxx;
237         }
238         return max(x0 + y0 / dy + 1, minx);
239     }
240 
241     /**
242      * Returns the minimum value of x in range [minx, maxx]: y0 - dy * (x - x0) <= 0
243      * If no value satisfies the expression maxx is returned
244      *
245      * @param y0 - value in x0
246      * @param dy - delta y
247      * @param x0 - some position, for which value is known (y0)
248      * @param minx - start of the range
249      * @param maxx - end of the range
250      * @return minimum x
251      */
end(int y0, int dy, int x0, int minx, int maxx)252     private static int end(int y0, int dy, int x0, int minx, int maxx) {
253         if (y0 <= 0) {
254             return minx;
255         }
256         if (dy <= 0) {
257             return maxx;
258         }
259         return min(x0 + (y0 - 1) / dy + 1, maxx);
260     }
261 
clear()262     public void clear() {
263         Arrays.fill(mData, 0);
264     }
265 }