1#pragma version(1)
2#pragma rs java_package_name(com.example.android.rs.balls)
3
4#include "balls.rsh"
5
6float2 gGravityVector = {0.f, 9.8f};
7
8float2 gMinPos = {0.f, 0.f};
9float2 gMaxPos = {1280.f, 700.f};
10
11static float2 touchPos[10];
12static float touchPressure[10];
13static const float gDT = 1.f / 30.f;
14
15rs_allocation gGrid;
16rs_allocation gGridCache;
17rs_allocation gBalls;
18
19float gScale = 1.f;
20
21void touch(float x, float y, float pressure, int id) {
22    if (id >= 10) {
23        return;
24    }
25
26    touchPos[id].x = x;
27    touchPos[id].y = y;
28    touchPressure[id] = pressure;
29}
30
31void root(Ball_t *ball, uint32_t x) {
32    float2 fv = 0;
33    float pressure = 0;
34    float2 pos = ball->position;
35    int2 gridPos[9];
36
37    gridPos[0] = convert_int2((ball->position / 100.f) /*- 0.4999f*/);
38    gridPos[1] = (int2){gridPos[0].x - 1, gridPos[0].y - 1};
39    gridPos[2] = (int2){gridPos[0].x + 0, gridPos[0].y - 1};
40    gridPos[3] = (int2){gridPos[0].x + 1, gridPos[0].y - 1};
41    gridPos[4] = (int2){gridPos[0].x - 1, gridPos[0].y};
42    gridPos[5] = (int2){gridPos[0].x + 1, gridPos[0].y};
43    gridPos[6] = (int2){gridPos[0].x - 1, gridPos[0].y + 1};
44    gridPos[7] = (int2){gridPos[0].x + 0, gridPos[0].y + 1};
45    gridPos[8] = (int2){gridPos[0].x + 1, gridPos[0].y + 1};
46
47    for (int gct=0; gct < 9; gct++) {
48        if ((gridPos[gct].x >= rsAllocationGetDimX(gGrid)) ||
49            (gridPos[gct].x < 0) ||
50            (gridPos[gct].y >= rsAllocationGetDimY(gGrid)) ||
51            (gridPos[gct].y < 0)) {
52            continue;
53        }
54        //rsDebug("grid ", gridPos[gct]);
55        const BallGrid_t *bg = (const BallGrid_t *)rsGetElementAt(gGrid, gridPos[gct].x, gridPos[gct].y);
56
57        for (int cidx = 0; cidx < bg->count; cidx++) {
58            float2 bcptr = rsGetElementAt_float2(gGridCache, bg->cacheIdx + cidx);
59            float2 vec = bcptr - pos;
60            float2 vec2 = vec * vec;
61            float len2 = vec2.x + vec2.y;
62
63            if ((len2 < 10000.f) && (len2 > 0.001f)) {
64                float len = rsqrt(len2 + 4.f);
65                float f = (len * len * len) * 20000.f;
66                fv -= vec * f;
67                pressure += f;
68            }
69        }
70    }
71
72    //fv /= ball->size * ball->size * ball->size;
73    fv -= gGravityVector * 4.f * gScale;
74    fv *= gDT;
75
76    for (int i=0; i < 10; i++) {
77        if (touchPressure[i] > 0.1f) {
78            float2 vec = touchPos[i] - ball->position;
79            float2 vec2 = vec * vec;
80            float len2 = max(2.f, vec2.x + vec2.y);
81            float2 pfv = (vec / len2) * touchPressure[i] * 500.f * gScale;
82            pressure += length(pfv);
83            fv -= pfv;
84        }
85    }
86
87    ball->delta = (ball->delta * (1.f - 0.008f)) + fv;
88    ball->position = ball->position + (ball->delta * gDT);
89
90    const float wallForce = 400.f * gScale;
91    if (ball->position.x > (gMaxPos.x - 20.f)) {
92        float d = gMaxPos.x - ball->position.x;
93        if (d < 0.f) {
94            if (ball->delta.x > 0) {
95                ball->delta.x *= -0.7f;
96            }
97            ball->position.x = gMaxPos.x - 1.f;
98        } else {
99            ball->delta.x -= min(wallForce / (d * d), 10.f);
100        }
101    }
102
103    if (ball->position.x < (gMinPos.x + 20.f)) {
104        float d = ball->position.x - gMinPos.x;
105        if (d < 0.f) {
106            if (ball->delta.x < 0) {
107                ball->delta.x *= -0.7f;
108            }
109            ball->position.x = gMinPos.x + 1.f;
110        } else {
111            ball->delta.x += min(wallForce / (d * d), 10.f);
112        }
113    }
114
115    if (ball->position.y > (gMaxPos.y - 20.f)) {
116        float d = gMaxPos.y - ball->position.y;
117        if (d < 0.f) {
118            if (ball->delta.y > 0) {
119                ball->delta.y *= -0.7f;
120            }
121            ball->position.y = gMaxPos.y - 1.f;
122        } else {
123            ball->delta.y -= min(wallForce / (d * d), 10.f);
124        }
125    }
126
127    if (ball->position.y < (gMinPos.y + 20.f)) {
128        float d = ball->position.y - gMinPos.y;
129        if (d < 0.f) {
130            if (ball->delta.y < 0) {
131                ball->delta.y *= -0.7f;
132            }
133            ball->position.y = gMinPos.y + 1.f;
134        } else {
135            ball->delta.y += min(wallForce / (d * d * d), 10.f);
136        }
137    }
138
139    // low pressure ~500, high ~2500
140    pressure *= 12.f;
141    ball->pressure = pressure;
142
143    //rsDebug("p ", pressure);
144
145    float4 color = 1.f;
146    color.r = pow(pressure, 0.25f) / 12.f;
147    color.b = 1.f - color.r;
148    color.g = sin(pressure / 1500.f * 3.14f);
149    color.rgb = max(color.rgb, (float3)0);
150    color.rgb = normalize(color.rgb);
151    ball->color = rsPackColorTo8888(color);
152
153    //rsDebug("physics pos out", ball->position);
154}
155
156