blob: 5eec22a91f38a553ff99f6c0c8116ea7158d3986 [file] [log] [blame]
Jason Sams0f505e52009-10-13 17:18:35 -07001#pragma version(1)
2#pragma stateVertex(PV)
3#pragma stateFragment(PFTexLinear)
4#pragma stateStore(PSIcons)
5
6#define PI 3.14159f
7
8
9// Attraction to center values from page edge to page center.
10float g_AttractionTable[9];
Jason Sams0f505e52009-10-13 17:18:35 -070011float g_PhysicsTableSize;
12
13float g_PosPage;
14float g_PosVelocity;
15float g_LastPositionX;
16int g_LastTouchDown;
17float g_DT;
18int g_LastTime;
19int g_PosMax;
20float g_Zoom;
21float g_OldPosPage;
22float g_OldPosVelocity;
23float g_OldZoom;
24
25// Drawing constants, should be parameters ======
26#define VIEW_ANGLE 1.28700222f
27
28int g_DrawLastFrame;
29int lastFrame(int draw) {
30 // We draw one extra frame to work around the last frame post bug.
31 // We also need to track if we drew the last frame to deal with large DT
32 // in the physics.
33 int ret = g_DrawLastFrame | draw;
34 g_DrawLastFrame = draw;
35 return ret; // should return draw instead.
36}
37
38void updateReadback() {
39 if ((g_OldPosPage != g_PosPage) ||
40 (g_OldPosVelocity != g_PosVelocity) ||
41 (g_OldZoom != g_Zoom)) {
42
43 g_OldPosPage = g_PosPage;
44 g_OldPosVelocity = g_PosVelocity;
45 g_OldZoom = g_Zoom;
46
47 int i[3];
48 i[0] = g_PosPage * (1 << 16);
49 i[1] = g_PosVelocity * (1 << 16);
50 i[2] = g_OldZoom * (1 << 16);
51 sendToClient(&i[0], 1, 12, 1);
52 }
53}
54
55
56void init() {
57 g_AttractionTable[0] = 6.5f;
58 g_AttractionTable[1] = 6.5f;
59 g_AttractionTable[2] = 7.0f;
60 g_AttractionTable[3] = 6.0f;
61 g_AttractionTable[4] = -6.0f;
62 g_AttractionTable[5] = -7.0f;
63 g_AttractionTable[6] = -6.5f;
64 g_AttractionTable[7] = -6.5f;
65 g_AttractionTable[8] = -6.5f; // dup 7 to avoid a clamp later
Jason Sams0f505e52009-10-13 17:18:35 -070066 g_PhysicsTableSize = 7;
67
68 g_PosVelocity = 0;
69 g_PosPage = 0;
70 g_LastTouchDown = 0;
71 g_LastPositionX = 0;
72 g_Zoom = 0;
73}
74
75void move() {
76 if (g_LastTouchDown) {
77 float dx = -(state->newPositionX - g_LastPositionX);
78 g_PosVelocity = 0;
79 g_PosPage += dx * 4;
80
81 float pmin = -0.25f;
82 float pmax = g_PosMax + 0.25f;
83 g_PosPage = clampf(g_PosPage, pmin, pmax);
84 }
85 g_LastTouchDown = state->newTouchDown;
86 g_LastPositionX = state->newPositionX;
87 //debugF("Move P", g_PosPage);
88}
89
90void fling() {
91 g_LastTouchDown = 0;
92 g_PosVelocity = -state->flingVelocityX * 2;
93 float av = fabsf(g_PosVelocity);
94 float minVel = 3.5f;
95
96 minVel *= 1.f - (fabsf(fracf(g_PosPage + 0.5f) - 0.5f) * 0.45f);
97
98 if (av < minVel && av > 0.2f) {
99 if (g_PosVelocity > 0) {
100 g_PosVelocity = minVel;
101 } else {
102 g_PosVelocity = -minVel;
103 }
104 }
105
106 if (g_PosPage <= 0) {
107 g_PosVelocity = maxf(0, g_PosVelocity);
108 }
109 if (g_PosPage > g_PosMax) {
110 g_PosVelocity = minf(0, g_PosVelocity);
111 }
112}
113
Jason Sams0f505e52009-10-13 17:18:35 -0700114float
115modf(float x, float y)
116{
117 return x-(y*floorf(x/y));
118}
119
120void updatePos() {
121 if (g_LastTouchDown) {
122 return;
123 }
124
125 int outOfRange = 0;
126 float tablePosNorm = fracf(g_PosPage + 0.5f);
127 float tablePosF = tablePosNorm * g_PhysicsTableSize;
128 int tablePosI = tablePosF;
129 float tablePosFrac = tablePosF - tablePosI;
130 float accel = lerpf(g_AttractionTable[tablePosI],
131 g_AttractionTable[tablePosI + 1],
132 tablePosFrac) * g_DT;
Jason Samsb52dfa02009-10-14 20:16:14 -0700133 float friction = 4.f * g_DT;
Jason Sams0f505e52009-10-13 17:18:35 -0700134
135 if (g_PosPage < -0.5f) {
136 accel = g_AttractionTable[0] * g_DT;
Jason Sams0f505e52009-10-13 17:18:35 -0700137 outOfRange = 1;
138 }
139 if ((g_PosPage - g_PosMax) > 0.5f) {
140 accel = g_AttractionTable[(int)g_PhysicsTableSize] * g_DT;
Jason Sams0f505e52009-10-13 17:18:35 -0700141 outOfRange = 1;
142 }
143
144 // If our velocity is low OR acceleration is opposing it, apply it.
Jason Samsb52dfa02009-10-14 20:16:14 -0700145 if (fabsf(g_PosVelocity) < 1.0f || (g_PosVelocity * accel) < 0 || outOfRange) {
Jason Sams0f505e52009-10-13 17:18:35 -0700146 g_PosVelocity += accel;
147 }
148
149 if ((friction > fabsf(g_PosVelocity)) &&
150 (friction > fabsf(accel)) &&
151 !outOfRange) {
152 // Special get back to center and overcome friction physics.
153 float t = tablePosNorm - 0.5f;
154 if (fabsf(t) < (friction * g_DT)) {
155 // really close, just snap
156 g_PosPage = roundf(g_PosPage);
157 g_PosVelocity = 0;
158 } else {
159 if (t > 0) {
160 g_PosVelocity = -friction;
161 } else {
162 g_PosVelocity = friction;
163 }
164 }
165 } else {
166 // Normal physics
167 if (g_PosVelocity > 0) {
168 g_PosVelocity -= friction;
169 g_PosVelocity = maxf(g_PosVelocity, 0);
170 } else {
171 g_PosVelocity += friction;
172 g_PosVelocity = minf(g_PosVelocity, 0);
173 }
174 }
175 g_PosPage += g_PosVelocity * g_DT;
176
177 // Check for out of boundry conditions.
178 if (g_PosPage < 0 && g_PosVelocity < 0) {
179 g_PosPage = maxf(g_PosPage, -0.49);
180 float damp = 1.0 + (g_PosPage * 4);
181 damp = clampf(damp, 0.f, 0.9f);
182 g_PosVelocity *= damp;
183 }
184 if (g_PosPage > g_PosMax && g_PosVelocity > 0) {
185 g_PosPage = minf(g_PosPage, g_PosMax + 0.49);
186 float damp = 1.0 - ((g_PosPage - g_PosMax) * 4);
187 damp = clampf(damp, 0.f, 0.9f);
188 g_PosVelocity *= damp;
189 }
190}
191
192int positionStrip(float row, float column, int isTop)
193{
194 float mat1[16];
Jason Sams0f505e52009-10-13 17:18:35 -0700195 float x = 0.5f * (column - 1.5f);
Jason Sams0f505e52009-10-13 17:18:35 -0700196 float scale = 72.f * 3 / getWidth();
Jason Sams0f505e52009-10-13 17:18:35 -0700197
198 if (isTop) {
199 matrixLoadTranslate(mat1, x, 0.8f, 0.f);
200 matrixScale(mat1, scale, scale, 1.f);
201 } else {
202 matrixLoadTranslate(mat1, x, -0.9f, 0.f);
203 matrixScale(mat1, scale, -scale, 1.f);
204 }
205 vpLoadModelMatrix(mat1);
206
Jason Samsb52dfa02009-10-14 20:16:14 -0700207 float soff = -(row * 1.4);
Jason Sams0f505e52009-10-13 17:18:35 -0700208 if (isTop) {
209 matrixLoadScale(mat1, 1.f, -0.85f, 1.f);
Jason Samsb52dfa02009-10-14 20:16:14 -0700210 matrixTranslate(mat1, 0, soff - 0.97f, 0);
Jason Sams0f505e52009-10-13 17:18:35 -0700211 } else {
212 matrixLoadScale(mat1, 1.f, 0.85f, 1.f);
Jason Samsb52dfa02009-10-14 20:16:14 -0700213 matrixTranslate(mat1, 0, soff - 0.45f, 0);
Jason Sams0f505e52009-10-13 17:18:35 -0700214 }
215 vpLoadTextureMatrix(mat1);
Jason Samsb52dfa02009-10-14 20:16:14 -0700216 return -soff * 10.f;
Jason Sams0f505e52009-10-13 17:18:35 -0700217}
218
219void
220draw_home_button()
221{
222 color(1.0f, 1.0f, 1.0f, 1.0f);
223 bindTexture(NAMED_PFTexLinear, 0, params->homeButtonId);
224
225 float scale = 2.0f / SCREEN_WIDTH_PX;
226
227 float x = 0.0f;
228
229 float y = -(SCREEN_HEIGHT_PX / (float)SCREEN_WIDTH_PX);
230 y += g_Zoom * (scale * params->homeButtonTextureHeight / 2);
231
232 float z = 0.0f;
233 drawSprite(x, y, z, params->homeButtonTextureWidth, params->homeButtonTextureHeight);
234}
235
236void drawFrontGrid(float rowOffset)
237{
238 float h = getHeight();
239 float w = getWidth();
240
241 int intRowOffset = rowOffset;
242 float rowFrac = rowOffset - intRowOffset;
243 float colWidth = getWidth() / 4;
244 float rowHeight = colWidth + 25.f;
245 float yoff = h - ((h - (rowHeight * 4.f)) / 2);
246
247 yoff -= 110;
248
249 int row, col;
250 int iconNum = intRowOffset * 4;
251 float ymax = yoff;
252 float ymin = yoff - (3 * rowHeight) - 70;
253
254 for (row = 0; row < 5; row++) {
255 float y = yoff - ((-rowFrac + row) * rowHeight);
256
257 for (col=0; col < 4; col++) {
258 if (iconNum >= state->iconCount) {
259 return;
260 }
261
262 if (iconNum >= 0) {
263 float x = colWidth * col - ((128 - colWidth) / 2);
264
265 if ((y >= ymin) && (y <= ymax)) {
266 color(1.f, 1.f, 1.f, 1.f);
267 bindTexture(NAMED_PFTexLinear, 0, loadI32(ALLOC_ICON_IDS, iconNum));
268 drawSpriteScreenspace(x, y, 0, 128, 128);
269 }
270
271 float y2 = y - 44;
272 float a = 1.f;
273 if (y2 < ymin) {
274 a = 1.f - (ymin - y2) * 0.02f;
275 }
276 if (y > (ymax + 40)) {
277 a = 1.f - (y - (ymax + 40)) * 0.02f;
278 }
279 a = clampf(a, 0, 1);
280
281 color(1, 1, 1, a);
282 bindTexture(NAMED_PFTexLinear, 0, loadI32(ALLOC_LABEL_IDS, iconNum));
283 drawSpriteScreenspace(x, y - 44, 0,
284 params->bubbleBitmapWidth, params->bubbleBitmapHeight);
285 }
286 iconNum++;
287 }
288 }
289}
290
Jason Samsb52dfa02009-10-14 20:16:14 -0700291void drawStrip(float row, float column, int isTop, int iconNum)
292{
293 if (iconNum < 0) return;
294 int offset = positionStrip(row, column, isTop);
295 bindTexture(NAMED_PFTexLinear, 0, loadI32(ALLOC_ICON_IDS, iconNum));
296 if (offset < -20) return;
297 offset = clamp(offset, 0, 199 - 20);
298 drawSimpleMeshRange(NAMED_SMMesh2, offset * 6, 20 * 6);
299}
300
Jason Sams0f505e52009-10-13 17:18:35 -0700301void drawTop(float rowOffset)
302{
Jason Sams0f505e52009-10-13 17:18:35 -0700303 int row, col;
304 int iconNum = 0;
305 for (row = 0; row < rowOffset; row++) {
306 for (col=0; col < 4; col++) {
307 if (iconNum >= state->iconCount) {
308 return;
309 }
Jason Samsb52dfa02009-10-14 20:16:14 -0700310 drawStrip(rowOffset - row, col, 1, iconNum);
Jason Sams0f505e52009-10-13 17:18:35 -0700311 iconNum++;
312 }
313 }
314}
315
316void drawBottom(float rowOffset)
317{
318 float pos = -1.f;
319 int intRowOffset = rowOffset;
320 pos -= rowOffset - intRowOffset;
321
322 int row, col;
323 int iconNum = (intRowOffset + 3) * 4;
324 while (1) {
325 for (col=0; col < 4; col++) {
326 if (iconNum >= state->iconCount) {
327 return;
328 }
329 if (pos > -1) {
Jason Samsb52dfa02009-10-14 20:16:14 -0700330 drawStrip(pos, col, 0, iconNum);
Jason Sams0f505e52009-10-13 17:18:35 -0700331 }
332 iconNum++;
333 }
334 pos += 1.f;
335 }
336}
337
338int
339main(int launchID)
340{
341 // Compute dt in seconds.
342 int newTime = uptimeMillis();
343 g_DT = (newTime - g_LastTime) / 1000.f;
344 g_LastTime = newTime;
345
346 if (!g_DrawLastFrame) {
347 // If we stopped rendering we cannot use DT.
348 // assume 30fps in this case.
349 g_DT = 0.033f;
350 }
Jason Samsb52dfa02009-10-14 20:16:14 -0700351 // physics may break if DT is large.
352 g_DT = minf(g_DT, 0.2f);
Jason Sams0f505e52009-10-13 17:18:35 -0700353
354 if (g_Zoom != state->zoomTarget) {
355 float dz = (state->zoomTarget - g_Zoom) * g_DT * 5;
356 if (dz && (fabsf(dz) < 0.03f)) {
357 if (dz > 0) {
358 dz = 0.03f;
359 } else {
360 dz = -0.03f;
361 }
362 }
363 if (fabsf(g_Zoom - state->zoomTarget) < fabsf(dz)) {
364 g_Zoom = state->zoomTarget;
365 } else {
366 g_Zoom += dz;
367 }
368 updateReadback();
369 }
370
371 // Set clear value to dim the background based on the zoom position.
372 if ((g_Zoom < 0.001f) && (state->zoomTarget < 0.001f)) {
373 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
374 // When we're zoomed out and not tracking motion events, reset the pos to 0.
375 if (!g_LastTouchDown) {
376 g_PosPage = 0;
377 }
378 return lastFrame(0);
379 } else if (g_Zoom < 0.85f) {
380 pfClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
381 } else {
382 pfClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
383 }
384
385 // icons & labels
386 int iconCount = state->iconCount;
387 g_PosMax = ((iconCount + 3) / 4) - 4;
388 if (g_PosMax < 0) g_PosMax = 0;
389
390 updatePos(0.1f);
391 updateReadback();
392
393 //debugF(" draw g_PosPage", g_PosPage);
394
395 // Draw the icons ========================================
396
397 //bindProgramFragment(NAMED_PFColor);
398 //positionStrip(1, 0, 0);
399 //drawSimpleMesh(NAMED_SMMesh2);
Jason Sams0f505e52009-10-13 17:18:35 -0700400
401 bindProgramFragment(NAMED_PFTexLinear);
402
403
Jason Samsb52dfa02009-10-14 20:16:14 -0700404 float zoomOffset = 8.f * (1 - g_Zoom);
405 drawTop(g_PosPage - zoomOffset);
406 drawBottom(g_PosPage - zoomOffset);
407 drawFrontGrid(g_PosPage - zoomOffset);
Jason Sams0f505e52009-10-13 17:18:35 -0700408
409 {
410 float mat1[16];
411 matrixLoadIdentity(mat1);
412 vpLoadModelMatrix(mat1);
413 vpLoadTextureMatrix(mat1);
414 }
Jason Samsb52dfa02009-10-14 20:16:14 -0700415 draw_home_button();
Jason Sams0f505e52009-10-13 17:18:35 -0700416
417 if (0) {
418 float h = getHeight();
419
420 color(1, 1, 1, 1);
421 bindProgramFragment(NAMED_PFColor);
422 bindProgramVertex(NAMED_PVOrtho);
423 float dy = 145.f;
424 float y = h - ((h - (dy * 4.f)) / 2);
425
426 drawLine(0, y, 0, 480, y, 0);
427 y -= dy;
428 drawLine(0, y, 0, 480, y, 0);
429 y -= dy;
430 drawLine(0, y, 0, 480, y, 0);
431 y -= dy;
432 drawLine(0, y, 0, 480, y, 0);
433 y -= dy;
434 drawLine(0, y, 0, 480, y, 0);
435 }
436
437
438 // Draw the home button ========================================
439 //draw_home_button();
440
441 // Bug workaround where the last frame is not always displayed
442 // So we keep rendering until the bug is fixed.
443 return lastFrame((g_PosVelocity != 0) || fracf(g_PosPage) || g_Zoom != state->zoomTarget);
444}
445