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
21int size;
22int z;
23rs_allocation volume;
24
25static float sigmoid(float f) {
26    return (float) (1 / (1 + exp(f / 2)));
27}
28
29static float pillDistance(float3 p1, float3 p2, float3 img) {
30
31    if (dot(p2 - p1, img - p1) > 0 && dot(p1 - p2, img - p2) > 0) {
32        return length(cross(img - p1, img - p2)) / length(p2 - p1);
33    }
34    return min(distance(p1, img), distance(p2, img));
35}
36
37static short pill(float3 p1, float3 p2, float rad, short max, float3 img) {
38    return (short) (max * sigmoid(pillDistance(p1, p2, img) - rad));
39}
40
41static short cogPill(float3 p1, float3 p2, float rad, short max, float3 img) {
42    float3 vec = (p1 + p2) / 2 - img;
43    float angle = fabs(2 * fract(atan2pi(vec.z, vec.y) * 5) - 1);
44    return (short) (max
45            * sigmoid(pillDistance(p1, p2, img) - rad * (1 + angle / 2)));
46}
47
48static float cylinderDistance(float3 p1, float3 p2, float3 img) {
49    float dot1 = dot(p2 - p1, img - p1);
50    float dot2 = dot(p1 - p2, img - p2);
51    if (dot1 > 0 && dot2 > 0) {
52        return length(cross(img - p1, img - p2)) / length(p2 - p1);
53    }
54    return -dot1 * dot2;
55}
56
57static short cylinder(float3 p1, float3 p2, float rad, short max, float3 img) {
58    return (short) (max * sigmoid(cylinderDistance(p1, p2, img) - rad));
59}
60
61static short cogCylinder(float3 p1, float3 p2, float rad, short max, float3 img) {
62    float3 vec = (p1 + p2) / 2 - img;
63    float angle = fabs(2 * fract(atan2pi(vec.y, vec.x) * 6) - 1);
64    return (short) (max
65            * sigmoid(cylinderDistance(p1, p2, img) - rad * (1 + angle / 5)));
66}
67
68static float distanceCircle(float3 center, float radius, float3 normal,
69        float3 img) {
70    float3 pc = img - center;
71    float tmp1 = dot(normal, pc);
72    tmp1 = tmp1 * tmp1;
73    float tmp2 = (sqrt(length(pc) * length(pc) - tmp1) - radius);
74    return tmp1 + tmp2 * tmp2;
75}
76
77static short circle(float3 center, float circleRadius, float3 normal, float rad,
78        short max, float3 img) {
79    return (short) (max
80            * sigmoid(distanceCircle(center, circleRadius, normal, img) - rad));
81}
82
83static float distanceDisk(float3 center, float radius, float3 normal,
84        float3 img) {
85    float3 pc = img - center;
86    float tmp1 = dot(normal, pc);
87    tmp1 = tmp1 * tmp1;
88    float tmp2 = (sqrt(length(pc) * length(pc) - tmp1) - radius);
89    if (length(pc - dot(normal, pc) * normal) > radius) {
90        return (tmp1 + tmp2 * tmp2);
91    }
92    return tmp1;
93}
94
95/* Unused function:
96static short disk(float3 center, float circleRadius, float3 normal, float rad,
97        short max, float3 img) {
98    return (short) (max
99            * sigmoid(distanceDisk(center, circleRadius, normal, img) - rad));
100}
101*/
102
103static short cogDisk(float3 center, float circleRadius, float3 normal,
104        float rad, short max, float3 img) {
105    float3 vec = center - img;
106    float angle = fabs(2 * fract(atan2pi(vec.y, vec.x) * 20) - 1);
107    return (short) (max
108            * sigmoid(
109                    distanceDisk(center, circleRadius * (1 + angle / 10),
110                            normal, img) - rad));
111}
112
113static float andyBody(float3 img) {
114    short v = 0;
115    { // body
116        float3 p1 = { size * 0.5f, size * 0.5f, size * 0.3f };
117        float3 p2 = { size * 0.5f, size * 0.5f, size * 0.65f };
118        float radius = size * 0.22f;
119        v = max(v, cylinder(p1, p2, radius, 144, img));
120        p2.z = size * 0.4f;
121        v = max(v, pill(p1, p2, radius, 144, img));
122        float3 normal = { 0.0f, 0.0f, 1.0f };
123        v -= circle(p1, radius*0.9f, normal, size * 0.05f, 144, img);
124    }
125    float armOffset = 0.27f;
126    { // arm 1
127        float3 p1 = { size * (0.5f - armOffset), size * 0.5f, size * 0.4f };
128        float3 p2 = { size * (0.5f - armOffset), size * 0.5f, size * 0.57f };
129        v = max(v, pill(p1, p2, size * 0.09f, 144, img));
130    }
131    { // arm 2
132        float3 p1 = { size * (0.5f + armOffset), size * 0.5f, size * 0.4f };
133        float3 p2 = { size * (0.5f + armOffset), size * 0.5f, size * 0.57f };
134        v = max(v, pill(p1, p2, size * 0.09f, 144, img));
135    }
136    { // leg 1
137        float3 p1 = { size * 0.6f, size * 0.5f, size * 0.6f };
138        float3 p2 = { size * 0.6f, size * 0.5f, size * 0.8f };
139        v = max(v, pill(p1, p2, size * 0.08f, 144, img));
140    }
141    { // leg 2
142        float3 p1 = { size * 0.4f, size * 0.5f, size * 0.6f };
143        float3 p2 = { size * 0.4f, size * 0.5f, size * 0.8f };
144        v = max(v, pill(p1, p2, size * 0.08f, 144, img));
145    }
146    float3 p1 = { size * 0.5f, size * 0.5f, size * 0.3f };
147    ;
148    { // antenna
149        float spacex = .1f;
150
151        float3 p2 = { size * (0.5f - spacex), size * 0.5f, size * 0.07f };
152        v = max(v, pill(p1, p2, size * 0.017f, 400, img));
153        float3 p3 = { size * (0.5f + spacex), size * 0.5f, size * 0.07f };
154        v = max(v, pill(p1, p3, size * 0.017f, 400, img));
155    }
156    { // eyes
157        float spacex = .105f;
158        float3 p2 = { size * (0.5f - spacex), size * 0.4f, size * 0.2f };
159        float3 p3 = { size * (0.5f + spacex), size * 0.4f, size * 0.2f };
160        v -= pill(p2, p2, size * 0.018f, 144, img);
161        v -= pill(p3, p3, size * 0.018f, 144, img);
162        v = max(v, pill(p1, p2, size * 0.032f, 400, img));
163        v = max(v, pill(p1, p3, size * 0.032f, 400, img));
164    }
165    return v;
166
167}
168
169static float andySkeleton(float3 img) {
170    short v = 0;
171    { // body
172        float3 p1 = { size * 0.5f, size * 0.5f, size * 0.3f };
173        float radius = size * 0.15f;
174
175        float3 normal = { 0.0f, 0.0f, 1.0f };
176        for (int i = 0; i < 5; i++) {
177            p1.z += size * 0.04f;
178            v += circle(p1, radius, normal, size * 0.07f, 400, img);
179        }
180        p1.z = size * 0.3f;
181        float3 p2 = { size * 0.5f, size * 0.5f, size * 0.6f };
182        v = max(v, cogDisk(p2, radius * 0.7f, normal, size * 0.07f, 400, img));
183        v = max(v, cogCylinder(p1, p2, size * 0.04f, 400, img));
184    }
185
186    float armOffset = 0.27f;
187    {
188        float3 p1 = { size * (0.5f - armOffset), size * 0.5f, size * 0.4f };
189        float3 p2 = { size * (0.5f + armOffset), size * 0.5f, size * 0.4f };
190        v = max(v, cogPill(p1, p2, size * 0.02f, 400, img));
191    }
192
193    { // arm 1
194        float3 p1 = { size * (0.5f - armOffset), size * 0.5f, size * 0.4f };
195        float3 p2 = { size * (0.5f - armOffset), size * 0.5f, size * 0.57f };
196        v = max(v, pill(p1, p2, size * 0.02f, 400, img));
197    }
198    { // arm 2
199        float3 p1 = { size * (0.5f + armOffset), size * 0.5f, size * 0.4f };
200        float3 p2 = { size * (0.5f + armOffset), size * 0.5f, size * 0.57f };
201        v = max(v, pill(p1, p2, size * 0.02f, 400, img));
202    }
203    { // leg 1
204        float3 p1 = { size * 0.6f, size * 0.5f, size * 0.6f };
205        float3 p2 = { size * 0.6f, size * 0.5f, size * 0.8f };
206        v = max(v, pill(p1, p2, size * 0.02f, 400, img));
207    }
208    { // leg 2
209        float3 p1 = { size * 0.4f, size * 0.5f, size * 0.6f };
210        float3 p2 = { size * 0.4f, size * 0.5f, size * 0.8f };
211        v = max(v, pill(p1, p2, size * 0.02f, 400, img));
212    }
213    return v;
214}
215
216short __attribute__((kernel)) andy(uint32_t x, uint32_t y) {
217    float3 img = { x, y, z };
218    float v = andyBody(img);
219    v = max(v, andySkeleton(img));
220    return v;
221
222}
223
224void __attribute__((kernel)) copy(short in, uint32_t x, uint32_t y) {
225    rsSetElementAt_short(volume, in, x, y, z);
226}
227