1/*
2 * Copyright (C) 2015 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#pragma version(1)
18#pragma rs java_package_name(com.example.android.rs.vr.engine)
19#pragma rs_fp_relaxed
20
21#define FLOAT_MAX  3.4028234E30f
22#define JITTER_LENGTH 3457
23float jitter[JITTER_LENGTH];
24
25float3 s;
26float3 dx;
27float3 dy;
28float3 dz;
29float zoomFactor;
30rs_matrix4x4 matrix4;
31rs_matrix3x3 matrix3;
32uchar4 base_color;
33static float3 mLight;
34static float rscale;
35
36// material color
37rs_allocation opacity;
38rs_allocation color_map;
39
40static void fillJitter() {
41    for (int i = 0; i < JITTER_LENGTH; i++) {
42        jitter[i] = (rsRand(rscale)+rsRand(rscale)+rsRand(rscale))/3;
43    }
44}
45
46void setup_vectors() {
47    s = rsMatrixMultiply(&matrix4, (float3) {0.5f, 0.5f, 0.5f}).xyz;
48    dx = rsMatrixMultiply(&matrix3, (float3) {1.f, 0.f, 0.f});
49    dy = rsMatrixMultiply(&matrix3, (float3) {0.f, 1.f, 0.f});
50    dz = rsMatrixMultiply(&matrix3, (float3) {0.f, 0.f, 1.f});
51    zoomFactor = dz.x * dz.x + dz.y * dz.y + dz.z * dz.z;
52    zoomFactor /= dx.x * dx.x + dx.y * dx.y + dx.z * dx.z;
53    base_color.r = 0;
54    base_color.g = 0;
55    base_color.b = 0;
56    base_color.a = 255;
57
58    float3 mLightRelitvePos = (float3) {0.f, 0.7071f, -0.7071f}; // light relitve to camera
59    mLight = mLightRelitvePos.x + dx + mLightRelitvePos.y * dy + mLightRelitvePos.z * dz;
60    mLight = normalize(mLight);
61    rscale = 1.5f/length(dz);
62    fillJitter();
63}
64
65static float triLinear(float v_0_0_0, float v_0_0_1, float v_0_1_0, float v_0_1_1,
66        float v_1_0_0, float v_1_0_1, float v_1_1_0, float v_1_1_1,
67        float3 delta) {
68    float v_0_0 = mix(v_0_0_0, v_0_0_1, delta.x);
69    float v_0_1 = mix(v_0_1_0, v_0_1_1, delta.x);
70    float v_1_0 = mix(v_1_0_0, v_1_0_1, delta.x);
71    float v_1_1 = mix(v_1_1_0, v_1_1_1, delta.x);
72    float v_0 = mix(v_0_0, v_0_1, delta.y);
73    float v_1 = mix(v_1_0, v_1_1, delta.y);
74    float v = mix(v_0, v_1, delta.z);
75    return v;
76}
77
78rs_allocation bricks;
79rs_allocation brick_index;
80int brick_dimx;
81int brick_dimy;
82int brick_dimz;
83
84static int isInBrick(int3 p) {
85    int bx = p.x >> 5;
86    int by = p.y >> 5;
87    int bz = p.z >> 5;
88    int brickno = bx + (by + brick_dimy * bz) * brick_dimx;
89
90    brickno *= 32 * 32;
91    int off = brickno + (p.z & 0x1F) * 32 + (p.y & 0x1F);
92    uint slice = rsGetElementAt_uint(bricks, off);
93    return slice & (1 << (p.x & 0x1F));
94}
95
96rs_allocation volume;
97rs_allocation zbuff;
98bool debug = true;
99
100uchar4 __attribute__ ((kernel)) draw_z_buffer(float2 in, uint32_t x, uint32_t y) {
101    uchar4 out = base_color;
102
103    float zsuface = in.x + .5f;
104    float zstart = zsuface;
105    float zend = in.y - 2.f;//0.5f;
106    float zlen = zend - zstart;
107
108    if (zstart == FLOAT_MAX || zlen < 0) {
109        return out;
110    }
111
112    float3 p = s + x * dx + y * dy + dz * zstart;
113    float zb = zend;
114    int izlen = (int) zlen;
115    float light = 1;
116    float4 total_color = (float4) {0.f, 0.f, 0.f, 0.f};
117
118    if (false) { // show the walls only used for debuging
119        int3 ip = convert_int3(p);
120        ip = clamp(ip, 4, 500);
121        short pix = rsGetElementAt_short(volume, ip.x, ip.y, ip.z);
122
123        int intensity = (((short) pix) & 0xFFFF);
124        //   intensity = clamp(intensity,0,400);
125        uchar4 color = rsGetElementAt_uchar4(color_map, intensity * 2);
126        // int op = rsGetElementAt_uchar(opacity, intensity);
127
128        out.r = color.r;
129        out.g = color.g;
130        out.b = color.b;
131        out.a = 255;
132        return out;
133    }
134    {
135        int3 ip = convert_int3(p);
136
137        if (isInBrick(ip)) { // isInBrick(ip)) {
138
139            float3 delta = p - convert_float3(ip);
140            // TODO switch to rsAllocationVLoadX_short2
141            // short2 tmps = rsAllocationVLoadX_short2(volume, ip.x + 0, ip.y + 0, ip.z + 0);
142            //  float2 tmp =   convert_float2(tmps);
143            float v_0_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 0);
144            float v_0_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 0);
145
146            float v_0_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 0);
147            float v_0_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 0);
148            float v_1_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 1);
149            float v_1_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 1);
150            float v_1_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 1);
151            float v_1_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 1);
152            float v = triLinear(v_0_0_0, v_0_0_1, v_0_1_0, v_0_1_1,
153                    v_1_0_0, v_1_0_1, v_1_1_0, v_1_1_1,
154                    delta);
155            int intensity = (((short) v) & 0xFFFF);
156            uchar op = rsGetElementAt_uchar(opacity, intensity);
157
158            if (op != 0) { // near the surface "broken"
159
160                float sdx = rsGetElementAt_float2(zbuff, max(0, (int) x - 1), y).x - in.x;
161                float sdy = rsGetElementAt_float2(zbuff, x, max(0, (int) y - 1)).x - in.x;
162                float dot_prod = sqrt(1 / (1 + (sdy * sdy + sdx * sdx) * zoomFactor));
163                float opf = op  * (1/255.f);
164                uchar4 color = rsGetElementAt_uchar4(color_map, intensity * 2);
165                uchar4 mat = rsGetElementAt_uchar4(color_map, intensity * 2 + 1);
166                float4 fcolor = convert_float4(color);;
167
168                float ambient = mat.x * (1/255.f);
169                // float specular = mat.y * (1/255.f);
170                float diffuse = mat.z * (1/255.f);
171                float lop = (ambient + diffuse * dot_prod) * light * opf;
172                light -= opf;
173                total_color += fcolor * lop;
174                zb = zstart;
175
176            }
177        }
178    }
179    p += dz * jitter[(x+(y<<11))%JITTER_LENGTH];
180
181    if (light > 0) {
182        for (int k = 0; k < izlen - 1; k++) {
183
184            int3 ip = convert_int3(p);
185            if (isInBrick(ip)) {
186                float3 delta = p - convert_float3(ip);
187
188                float v_0_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 0);
189                float v_0_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 0);
190                float v_0_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 0);
191                float v_0_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 0);
192                float v_1_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 1);
193                float v_1_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 1);
194                float v_1_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 1);
195                float v_1_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 1);
196                float v = triLinear(v_0_0_0, v_0_0_1, v_0_1_0, v_0_1_1,
197                        v_1_0_0, v_1_0_1, v_1_1_0, v_1_1_1,
198                        delta);
199                int intensity = (((short) v) & 0xFFFF);
200                uchar op = rsGetElementAt_uchar(opacity, intensity);
201
202                if (op != 0) {
203
204                    float3 v;
205                    float3 vn;
206
207                    float v_0_0_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 0, ip.z + 0);
208                    float v_0_1_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 1, ip.z + 0);
209                    float v_1_0_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 0, ip.z + 1);
210                    float v_1_1_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 1, ip.z + 1);
211                    v.x = triLinear(v_0_0_1, v_0_0_2, v_0_1_1, v_0_1_2,
212                            v_1_0_1, v_1_0_2, v_1_1_1, v_1_1_2,
213                            delta);
214
215                    float v_0_0_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 0, ip.z + 0);
216                    float v_0_1_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 1, ip.z + 0);
217                    float v_1_0_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 0, ip.z + 1);
218                    float v_1_1_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 1, ip.z + 1);
219                    vn.x = triLinear(v_0_0_n, v_0_0_0, v_0_1_n, v_0_1_0,
220                            v_1_0_n, v_1_0_0, v_1_1_n, v_1_1_0,
221                            delta);
222
223                    float v_0_2_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 2, ip.z + 0);
224                    float v_0_2_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 2, ip.z + 0);
225                    float v_1_2_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 2, ip.z + 1);
226                    float v_1_2_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 2, ip.z + 1);
227                    v.y = triLinear(v_0_1_0, v_0_1_1, v_0_2_0, v_0_2_1,
228                            v_1_1_0, v_1_1_1, v_1_2_0, v_1_2_1,
229                            delta);
230
231                    float v_0_n_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 0);
232                    float v_0_n_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 0);
233                    float v_1_n_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 1);
234                    float v_1_n_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 1);
235                    vn.y = triLinear(v_0_n_0, v_0_n_1, v_0_0_0, v_0_0_1,
236                            v_1_n_0, v_1_n_1, v_1_0_0, v_1_0_1,
237                            delta);
238
239                    float v_n_0_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z - 1);
240                    float v_n_0_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z - 1);
241                    float v_n_1_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z - 1);
242                    float v_n_1_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z - 1);
243                    vn.z = triLinear(v_n_0_0, v_n_0_1, v_n_1_0, v_n_1_1,
244                            v_0_0_0, v_0_0_1, v_0_1_0, v_0_1_1,
245                            delta);
246
247                    float v_2_0_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 2);
248                    float v_2_0_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 2);
249                    float v_2_1_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 2);
250                    float v_2_1_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 2);
251                    v.z = triLinear(v_1_0_0, v_1_0_1, v_1_1_0, v_1_1_1,
252                            v_2_0_0, v_2_0_1, v_2_1_0, v_2_1_1,
253                            delta);
254
255                    float3 dv = normalize(v - vn);
256                    float dot_prod = dot(dv, dz);
257                    float opf = op / 255.f;
258
259                    uchar4 color = rsGetElementAt_uchar4(color_map, intensity * 2);
260                    uchar4 mat = rsGetElementAt_uchar4(color_map, intensity * 2 + 1);
261                    float4 fcolor = convert_float4(color);;
262
263                    // float3 mLight = (float3) {0,-1,0};
264                    float3 normal = dv;
265                    float3 r = 2 * normal * dot(mLight, normal) - mLight;
266                    float spec = dot(r, dz);
267
268                    // Eye point in this space is in the direction (0,0,-1)
269                    // Spec * Math.pow(R_z , P) lets use power == 2 (cheap)
270
271                    float ambient = mat.x * (1/255.f); // ambient
272                    float specular = mat.y * (1/255.f); // specular not used right now
273                    float diffuse = mat.z  * (1/255.f);// diffuse
274                    float lop = (ambient + diffuse * dot_prod + specular * pow(spec, 10)) * light * opf;
275                    light -= opf;
276                    total_color += fcolor * lop;
277
278                    zb = zstart + k;
279                    if (light <= 0) {
280                        break;
281                    }
282                }
283            }
284
285            p += dz;
286        }
287    }
288
289    out = convert_uchar4(clamp(total_color, 0.f, 255.f));
290    out.a = 0xFF;
291
292    return out;
293}
294