summaryrefslogtreecommitdiff
path: root/java/tests/VrDemo/src/com/example/android/rs/vr/engine/vr.rs
blob: 997bb102642a0443c552cf13acd0d9ea4ac4366f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma version(1)
#pragma rs java_package_name(com.example.android.rs.vr.engine)
#pragma rs_fp_relaxed

#define FLOAT_MAX  3.4028234E30f
#define JITTER_LENGTH 3456
float jitter[JITTER_LENGTH];

float3 s;
float3 dx;
float3 dy;
float3 dz;
float zoomFactor;
rs_matrix4x4 matrix4;
rs_matrix3x3 matrix3;
uchar4 base_color;
static float3 mLight;

// material color
rs_allocation opacity;
rs_allocation color_map;

static void fillJitter() {
    for (int i = 0; i < JITTER_LENGTH; i++) {
        jitter[i] = rsRand(1.0f);
    }
}

void setup_vectors() {
    s = rsMatrixMultiply(&matrix4, (float3) {0.5f, 0.5f, 0.5f}).xyz;
    dx = rsMatrixMultiply(&matrix3, (float3) {1.f, 0.f, 0.f});
    dy = rsMatrixMultiply(&matrix3, (float3) {0.f, 1.f, 0.f});
    dz = rsMatrixMultiply(&matrix3, (float3) {0.f, 0.f, 1.f});
    zoomFactor = dz.x * dz.x + dz.y * dz.y + dz.z * dz.z;
    zoomFactor /= dx.x * dx.x + dx.y * dx.y + dx.z * dx.z;
    base_color.r = 0;
    base_color.g = 0;
    base_color.b = 0;
    base_color.a = 255;
    fillJitter();
    float3 mLightRelitvePos = (float3) {0, 0.7071f, -0.7071f}; // light relitve to camera
    mLight = mLightRelitvePos.x + dx + mLightRelitvePos.y * dy + mLightRelitvePos.z * dz;
    mLight = normalize(mLight);
}

// old simple version
static float triLinear_old(short v_0_0_0, short v_0_0_1, short v_0_1_0, short v_0_1_1,
        short v_1_0_0, short v_1_0_1, short v_1_1_0, short v_1_1_1,
        float3 delta) {
    float v_0_0 = v_0_0_0 + delta.x * (v_0_0_1 - v_0_0_0);
    float v_0_1 = v_0_1_0 + delta.x * (v_0_1_1 - v_0_1_0);
    float v_1_0 = v_1_0_0 + delta.x * (v_1_0_1 - v_1_0_0);
    float v_1_1 = v_1_1_0 + delta.x * (v_1_1_1 - v_1_1_0);
    float v_0 = v_0_0 + delta.y * (v_0_1 - v_0_0);
    float v_1 = v_1_0 + delta.y * (v_1_1 - v_1_0);
    float v = v_0 + delta.z * (v_1 - v_0);
    return v;
}

//  This seemed to improve over above
static float triLinear(float v_0_0_0, float v_0_0_1, float v_0_1_0, short v_0_1_1,
        float v_1_0_0, float v_1_0_1, float v_1_1_0, float v_1_1_1,
        float3 delta) {
    float v_0_0 = mix(v_0_0_0, v_0_0_1, delta.x);
    float v_0_1 = mix(v_0_1_0, v_0_1_1, delta.x);
    float v_1_0 = mix(v_1_0_0, v_1_0_1, delta.x);
    float v_1_1 = mix(v_1_1_0, v_1_1_1, delta.x);
    float v_0 = mix(v_0_0, v_0_1, delta.y);
    float v_1 = mix(v_1_0, v_1_1, delta.y);
    float v = mix(v_0, v_1, delta.z);
    return v;
}

rs_allocation bricks;
rs_allocation brick_index;
int brick_dimx;
int brick_dimy;
int brick_dimz;

static int isInBrick(int3 p) {
    int bx = p.x >> 5;
    int by = p.y >> 5;
    int bz = p.z >> 5;
    int brickno = bx + (by + brick_dimy * bz) * brick_dimx;

    brickno *= 32 * 32;
    int off = brickno + (p.z & 0x1F) * 32 + (p.y & 0x1F);
    uint slice = rsGetElementAt_uint(bricks, off);
    return slice & (1 << (p.x & 0x1F));
}

rs_allocation volume;
rs_allocation zbuff;
bool debug = true;

uchar4 __attribute__ ((kernel)) draw_z_buffer(float2 in, uint32_t x, uint32_t y) {
    uchar4 out = base_color;

    float zsuface = in.x + .5f;
    float zstart = zsuface;
    float zend = in.y - 2.f;//0.5f;
    float zlen = zend - zstart;
    float step_dist = length(dz);

    if (zstart == FLOAT_MAX || zlen < 0) {
        return out;
    }

    float3 p = s + x * dx + y * dy + dz * zstart;
    float zb = zend;
    int izlen = (int) zlen;
    float light = 1;
    float4 total_color = (float4) {0.f, 0.f, 0.f, 0.f};

    if (false) { // show the walls only used for debuging
        int3 ip = convert_int3(p);
        ip = clamp(ip, 4, 500);
        short pix = rsGetElementAt_short(volume, ip.x, ip.y, ip.z);

        int intensity = (((short) pix) & 0xFFFF);
        //   intensity = clamp(intensity,0,400);
        uchar4 color = rsGetElementAt_uchar4(color_map, intensity * 2);
        int op = rsGetElementAt_uchar(opacity, intensity);

        out.r = color.r;
        out.g = color.g;
        out.b = color.b;
        out.a = 255;
        return out;
    }
    {
        int3 ip = convert_int3(p);

        if (isInBrick(ip)) { // isInBrick(ip)) {

            float3 delta = p - convert_float3(ip);
            // TODO switch to rsAllocationVLoadX_short2
            // short2 tmps = rsAllocationVLoadX_short2(volume, ip.x + 0, ip.y + 0, ip.z + 0);
            //  float2 tmp =   convert_float2(tmps);
            float v_0_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 0);
            float v_0_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 0);

            float v_0_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 0);
            float v_0_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 0);
            float v_1_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 1);
            float v_1_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 1);
            float v_1_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 1);
            float v_1_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 1);
            float v = triLinear(v_0_0_0, v_0_0_1, v_0_1_0, v_0_1_1,
                    v_1_0_0, v_1_0_1, v_1_1_0, v_1_1_1,
                    delta);
            int intensity = (((short) v) & 0xFFFF);
            uchar op = rsGetElementAt_uchar(opacity, intensity);

            if (op != 0) { // near the surface "broken"

                float sdx = rsGetElementAt_float2(zbuff, max(0, (int) x - 1), y).x - in.x;
                float sdy = rsGetElementAt_float2(zbuff, x, max(0, (int) y - 1)).x - in.x;
                float dot_prod = sqrt(1 / (1 + (sdy * sdy + sdx * sdx) * zoomFactor));
                float opf = op / 255.f;
                uchar4 color = rsGetElementAt_uchar4(color_map, intensity * 2);
                uchar4 mat = rsGetElementAt_uchar4(color_map, intensity * 2 + 1);
                float4 fcolor = convert_float4(color);;

                float ambient = mat.x / 255.f;
                float specular = mat.y / 255.f;
                float diffuse = mat.z / 255.f;
                float lop = (ambient + diffuse * dot_prod) * light * opf;
                light -= opf;
                total_color += fcolor * lop;
                zb = zstart;

            }
        }
    }
    p += dz * rsRand(2.f);

    if (light > 0) {
        for (int k = 0; k < izlen - 1; k++) {

            int3 ip = convert_int3(p);
            if (isInBrick(ip)) {
                float3 delta = p - convert_float3(ip);

                float v_0_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 0);
                float v_0_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 0);
                float v_0_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 0);
                float v_0_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 0);
                float v_1_0_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 1);
                float v_1_0_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 1);
                float v_1_1_0 = (float) rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 1);
                float v_1_1_1 = (float) rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 1);
                float v = triLinear(v_0_0_0, v_0_0_1, v_0_1_0, v_0_1_1,
                        v_1_0_0, v_1_0_1, v_1_1_0, v_1_1_1,
                        delta);
                int intensity = (((short) v) & 0xFFFF);
                uchar op = rsGetElementAt_uchar(opacity, intensity);

                if (op != 0) {

                    float3 v;
                    float3 vn;

                    float v_0_0_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 0, ip.z + 0);
                    float v_0_1_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 1, ip.z + 0);
                    float v_1_0_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 0, ip.z + 1);
                    float v_1_1_2 = rsGetElementAt_short(volume, ip.x + 2, ip.y + 1, ip.z + 1);
                    v.x = triLinear(v_0_0_1, v_0_0_2, v_0_1_1, v_0_1_2,
                            v_1_0_1, v_1_0_2, v_1_1_1, v_1_1_2,
                            delta);

                    float v_0_0_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 0, ip.z + 0);
                    float v_0_1_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 1, ip.z + 0);
                    float v_1_0_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 0, ip.z + 1);
                    float v_1_1_n = rsGetElementAt_short(volume, ip.x - 1, ip.y + 1, ip.z + 1);
                    vn.x = triLinear(v_0_0_n, v_0_0_0, v_0_1_n, v_0_1_0,
                            v_1_0_n, v_1_0_0, v_1_1_n, v_1_1_0,
                            delta);

                    float v_0_2_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 2, ip.z + 0);
                    float v_0_2_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 2, ip.z + 0);
                    float v_1_2_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 2, ip.z + 1);
                    float v_1_2_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 2, ip.z + 1);
                    v.y = triLinear(v_0_1_0, v_0_1_1, v_0_2_0, v_0_2_1,
                            v_1_1_0, v_1_1_1, v_1_2_0, v_1_2_1,
                            delta);

                    float v_0_n_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 0);
                    float v_0_n_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 0);
                    float v_1_n_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 1);
                    float v_1_n_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 1);
                    vn.y = triLinear(v_0_n_0, v_0_n_1, v_0_0_0, v_0_0_1,
                            v_1_n_0, v_1_n_1, v_1_0_0, v_1_0_1,
                            delta);

                    float v_n_0_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z - 1);
                    float v_n_0_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z - 1);
                    float v_n_1_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z - 1);
                    float v_n_1_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z - 1);
                    vn.z = triLinear(v_n_0_0, v_n_0_1, v_n_1_0, v_n_1_1,
                            v_0_0_0, v_0_0_1, v_0_1_0, v_0_1_1,
                            delta);

                    float v_2_0_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 0, ip.z + 2);
                    float v_2_0_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 0, ip.z + 2);
                    float v_2_1_0 = rsGetElementAt_short(volume, ip.x + 0, ip.y + 1, ip.z + 2);
                    float v_2_1_1 = rsGetElementAt_short(volume, ip.x + 1, ip.y + 1, ip.z + 2);
                    v.z = triLinear(v_1_0_0, v_1_0_1, v_1_1_0, v_1_1_1,
                            v_2_0_0, v_2_0_1, v_2_1_0, v_2_1_1,
                            delta);

                    float3 dv = normalize(v - vn);
                    float dot_prod = dot(dv, dz);
                    float opf = op / 255.f;

                    uchar4 color = rsGetElementAt_uchar4(color_map, intensity * 2);
                    uchar4 mat = rsGetElementAt_uchar4(color_map, intensity * 2 + 1);
                    float4 fcolor = convert_float4(color);;

                    // float3 mLight = (float3) {0,-1,0};
                    float3 normal = dv;
                    float3 r = 2 * normal * dot(mLight, normal) - mLight;
                    float spec = dot(r, dz);

                    // Eye point in this space is in the direction (0,0,-1)
                    // Spec * Math.pow(R_z , P) lets use power == 2 (cheap)

                    float ambient = mat.x / 255.f; // ambient
                    float specular = mat.y / 255.f; // specular not used right now
                    float diffuse = mat.z / 255.f; // diffuse
                    float lop = (ambient + diffuse * dot_prod + specular * pow(spec, 10)) * light * opf;
                    light -= opf;
                    total_color += fcolor * lop;

                    zb = zstart + k;
                    if (light <= 0) {
                        break;
                    }
                }
            }

            p += dz;
        }
    }

    out = convert_uchar4(total_color);
    out.a = 0xFF;

    return out;
}