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