blob: af5abd311865e0af5bd1d4d3b04933b75a503648 [file] [log] [blame]
Jason Sams0f505e52009-10-13 17:18:35 -07001#pragma version(1)
2#pragma stateVertex(PV)
Jason Samsc8514792009-10-29 14:27:29 -07003#pragma stateFragment(PFTexNearest)
Jason Sams0f505e52009-10-13 17:18:35 -07004#pragma stateStore(PSIcons)
5
6#define PI 3.14159f
7
Jason Sams41b61c82009-10-15 15:40:54 -07008int g_SpecialHWWar;
Jason Sams0f505e52009-10-13 17:18:35 -07009
10// Attraction to center values from page edge to page center.
11float g_AttractionTable[9];
Jason Sams2e19c052009-10-20 18:19:55 -070012float g_FrictionTable[9];
Jason Sams0f505e52009-10-13 17:18:35 -070013float g_PhysicsTableSize;
14
15float g_PosPage;
16float g_PosVelocity;
17float g_LastPositionX;
18int g_LastTouchDown;
19float g_DT;
20int g_LastTime;
21int g_PosMax;
22float g_Zoom;
Jason Sams6471c8b2010-01-20 14:15:22 -080023float g_Animation;
Jason Sams0f505e52009-10-13 17:18:35 -070024float g_OldPosPage;
25float g_OldPosVelocity;
26float g_OldZoom;
Jason Samsc1c521e2009-10-19 14:45:45 -070027float g_MoveToTotalTime;
28float g_MoveToTime;
29float g_MoveToOldPos;
30
Joe Onorato20e7a562010-03-18 17:12:52 -070031int g_Cols;
32int g_Rows;
Jason Sams0f505e52009-10-13 17:18:35 -070033
34// Drawing constants, should be parameters ======
35#define VIEW_ANGLE 1.28700222f
36
37int g_DrawLastFrame;
38int lastFrame(int draw) {
39 // We draw one extra frame to work around the last frame post bug.
40 // We also need to track if we drew the last frame to deal with large DT
41 // in the physics.
42 int ret = g_DrawLastFrame | draw;
43 g_DrawLastFrame = draw;
44 return ret; // should return draw instead.
45}
46
47void updateReadback() {
48 if ((g_OldPosPage != g_PosPage) ||
49 (g_OldPosVelocity != g_PosVelocity) ||
50 (g_OldZoom != g_Zoom)) {
51
52 g_OldPosPage = g_PosPage;
53 g_OldPosVelocity = g_PosVelocity;
54 g_OldZoom = g_Zoom;
55
56 int i[3];
57 i[0] = g_PosPage * (1 << 16);
58 i[1] = g_PosVelocity * (1 << 16);
59 i[2] = g_OldZoom * (1 << 16);
60 sendToClient(&i[0], 1, 12, 1);
61 }
62}
63
Jason Sams41b61c82009-10-15 15:40:54 -070064void setColor(float r, float g, float b, float a) {
65 if (g_SpecialHWWar) {
66 color(0, 0, 0, 0.001f);
67 } else {
68 color(r, g, b, a);
69 }
70}
Jason Sams0f505e52009-10-13 17:18:35 -070071
72void init() {
Jason Sams2e19c052009-10-20 18:19:55 -070073 g_AttractionTable[0] = 20.0f;
74 g_AttractionTable[1] = 20.0f;
Jason Samsc8514792009-10-29 14:27:29 -070075 g_AttractionTable[2] = 20.0f;
Jason Sams2e19c052009-10-20 18:19:55 -070076 g_AttractionTable[3] = 10.0f;
77 g_AttractionTable[4] = -10.0f;
Jason Samsc8514792009-10-29 14:27:29 -070078 g_AttractionTable[5] = -20.0f;
79 g_AttractionTable[6] = -20.0f;
Jason Sams2e19c052009-10-20 18:19:55 -070080 g_AttractionTable[7] = -20.0f;
81 g_AttractionTable[8] = -20.0f; // dup 7 to avoid a clamp later
82 g_FrictionTable[0] = 10.0f;
83 g_FrictionTable[1] = 10.0f;
84 g_FrictionTable[2] = 11.0f;
85 g_FrictionTable[3] = 15.0f;
86 g_FrictionTable[4] = 15.0f;
87 g_FrictionTable[5] = 11.0f;
88 g_FrictionTable[6] = 10.0f;
89 g_FrictionTable[7] = 10.0f;
90 g_FrictionTable[8] = 10.0f; // dup 7 to avoid a clamp later
Jason Sams0f505e52009-10-13 17:18:35 -070091 g_PhysicsTableSize = 7;
92
93 g_PosVelocity = 0;
94 g_PosPage = 0;
95 g_LastTouchDown = 0;
96 g_LastPositionX = 0;
97 g_Zoom = 0;
Jason Sams2a131552010-02-26 13:50:31 -080098 g_Animation = 1.f;
Jason Sams41b61c82009-10-15 15:40:54 -070099 g_SpecialHWWar = 1;
Jason Samsc1c521e2009-10-19 14:45:45 -0700100 g_MoveToTime = 0;
101 g_MoveToOldPos = 0;
Mike Cleron7d5d7462009-10-20 14:06:00 -0700102 g_MoveToTotalTime = 0.2f; // Duration of scrolling 1 line
Jason Sams41b61c82009-10-15 15:40:54 -0700103}
104
105void resetHWWar() {
106 g_SpecialHWWar = 1;
Jason Sams0f505e52009-10-13 17:18:35 -0700107}
108
109void move() {
110 if (g_LastTouchDown) {
111 float dx = -(state->newPositionX - g_LastPositionX);
112 g_PosVelocity = 0;
Jason Sams6ec11bc2010-01-19 17:56:52 -0800113 g_PosPage += dx * 5.2f;
Jason Sams0f505e52009-10-13 17:18:35 -0700114
Jason Samsc8514792009-10-29 14:27:29 -0700115 float pmin = -0.49f;
116 float pmax = g_PosMax + 0.49f;
Jason Sams0f505e52009-10-13 17:18:35 -0700117 g_PosPage = clampf(g_PosPage, pmin, pmax);
118 }
119 g_LastTouchDown = state->newTouchDown;
120 g_LastPositionX = state->newPositionX;
Jason Samsc1c521e2009-10-19 14:45:45 -0700121 g_MoveToTime = 0;
Jason Sams0f505e52009-10-13 17:18:35 -0700122 //debugF("Move P", g_PosPage);
123}
124
Jason Samsc1c521e2009-10-19 14:45:45 -0700125void moveTo() {
126 g_MoveToTime = g_MoveToTotalTime;
127 g_PosVelocity = 0;
128 g_MoveToOldPos = g_PosPage;
Jason Sams2e19c052009-10-20 18:19:55 -0700129
Mike Cleron7d5d7462009-10-20 14:06:00 -0700130 // debugF("======= moveTo", state->targetPos);
Jason Samsc1c521e2009-10-19 14:45:45 -0700131}
132
Joe Onorato3a8820b2009-11-10 15:06:42 -0800133void setZoom() {
134 g_Zoom = state->zoomTarget;
135 g_DrawLastFrame = 1;
136 updateReadback();
137}
138
Jason Sams0f505e52009-10-13 17:18:35 -0700139void fling() {
140 g_LastTouchDown = 0;
Jason Sams37e7c2b2009-10-19 12:55:43 -0700141 g_PosVelocity = -state->flingVelocity * 4;
Jason Sams0f505e52009-10-13 17:18:35 -0700142 float av = fabsf(g_PosVelocity);
143 float minVel = 3.5f;
144
145 minVel *= 1.f - (fabsf(fracf(g_PosPage + 0.5f) - 0.5f) * 0.45f);
146
147 if (av < minVel && av > 0.2f) {
148 if (g_PosVelocity > 0) {
149 g_PosVelocity = minVel;
150 } else {
151 g_PosVelocity = -minVel;
152 }
153 }
154
155 if (g_PosPage <= 0) {
156 g_PosVelocity = maxf(0, g_PosVelocity);
157 }
158 if (g_PosPage > g_PosMax) {
159 g_PosVelocity = minf(0, g_PosVelocity);
160 }
161}
162
Jason Sams0f505e52009-10-13 17:18:35 -0700163float
164modf(float x, float y)
165{
166 return x-(y*floorf(x/y));
167}
168
Mike Cleron7d5d7462009-10-20 14:06:00 -0700169
170/*
171 * Interpolates values in the range 0..1 to a curve that eases in
172 * and out.
173 */
174float
175getInterpolation(float input) {
176 return (cosf((input + 1) * PI) / 2.0f) + 0.5f;
177}
178
179
Jason Sams0f505e52009-10-13 17:18:35 -0700180void updatePos() {
181 if (g_LastTouchDown) {
182 return;
183 }
184
Jason Sams0f505e52009-10-13 17:18:35 -0700185 float tablePosNorm = fracf(g_PosPage + 0.5f);
186 float tablePosF = tablePosNorm * g_PhysicsTableSize;
187 int tablePosI = tablePosF;
188 float tablePosFrac = tablePosF - tablePosI;
189 float accel = lerpf(g_AttractionTable[tablePosI],
190 g_AttractionTable[tablePosI + 1],
191 tablePosFrac) * g_DT;
Jason Sams2e19c052009-10-20 18:19:55 -0700192 float friction = lerpf(g_FrictionTable[tablePosI],
193 g_FrictionTable[tablePosI + 1],
194 tablePosFrac) * g_DT;
Jason Sams0f505e52009-10-13 17:18:35 -0700195
Jason Samsc1c521e2009-10-19 14:45:45 -0700196 if (g_MoveToTime) {
Jason Samsc8514792009-10-29 14:27:29 -0700197 // New position is old posiition + (total distance) * (interpolated time)
198 g_PosPage = g_MoveToOldPos + (state->targetPos - g_MoveToOldPos) * getInterpolation((g_MoveToTotalTime - g_MoveToTime) / g_MoveToTotalTime);
Jason Samsc1c521e2009-10-19 14:45:45 -0700199 g_MoveToTime -= g_DT;
200 if (g_MoveToTime <= 0) {
201 g_MoveToTime = 0;
202 g_PosPage = state->targetPos;
203 }
204 return;
205 }
206
Jason Sams0f505e52009-10-13 17:18:35 -0700207 // If our velocity is low OR acceleration is opposing it, apply it.
Jason Samsc8514792009-10-29 14:27:29 -0700208 if (fabsf(g_PosVelocity) < 4.0f || (g_PosVelocity * accel) < 0) {
Jason Sams0f505e52009-10-13 17:18:35 -0700209 g_PosVelocity += accel;
210 }
Jason Samsc8514792009-10-29 14:27:29 -0700211 //debugF("g_PosPage", g_PosPage);
212 //debugF(" g_PosVelocity", g_PosVelocity);
213 //debugF(" friction", friction);
214 //debugF(" accel", accel);
Jason Sams0f505e52009-10-13 17:18:35 -0700215
Jason Samsc8514792009-10-29 14:27:29 -0700216 // Normal physics
217 if (g_PosVelocity > 0) {
218 g_PosVelocity -= friction;
219 g_PosVelocity = maxf(g_PosVelocity, 0);
220 } else {
221 g_PosVelocity += friction;
222 g_PosVelocity = minf(g_PosVelocity, 0);
223 }
224
225 if ((friction > fabsf(g_PosVelocity)) && (friction > fabsf(accel))) {
Jason Sams0f505e52009-10-13 17:18:35 -0700226 // Special get back to center and overcome friction physics.
227 float t = tablePosNorm - 0.5f;
228 if (fabsf(t) < (friction * g_DT)) {
229 // really close, just snap
230 g_PosPage = roundf(g_PosPage);
231 g_PosVelocity = 0;
232 } else {
233 if (t > 0) {
234 g_PosVelocity = -friction;
235 } else {
236 g_PosVelocity = friction;
237 }
238 }
Jason Sams0f505e52009-10-13 17:18:35 -0700239 }
Jason Sams0f505e52009-10-13 17:18:35 -0700240
241 // Check for out of boundry conditions.
242 if (g_PosPage < 0 && g_PosVelocity < 0) {
Jason Sams0f505e52009-10-13 17:18:35 -0700243 float damp = 1.0 + (g_PosPage * 4);
244 damp = clampf(damp, 0.f, 0.9f);
245 g_PosVelocity *= damp;
246 }
247 if (g_PosPage > g_PosMax && g_PosVelocity > 0) {
Jason Sams0f505e52009-10-13 17:18:35 -0700248 float damp = 1.0 - ((g_PosPage - g_PosMax) * 4);
249 damp = clampf(damp, 0.f, 0.9f);
250 g_PosVelocity *= damp;
251 }
Jason Samsc8514792009-10-29 14:27:29 -0700252
253 g_PosPage += g_PosVelocity * g_DT;
254 g_PosPage = clampf(g_PosPage, -0.49, g_PosMax + 0.49);
Jason Sams0f505e52009-10-13 17:18:35 -0700255}
256
Jason Sams0f505e52009-10-13 17:18:35 -0700257
258void
259draw_home_button()
260{
Jason Sams41b61c82009-10-15 15:40:54 -0700261 setColor(1.0f, 1.0f, 1.0f, 1.0f);
Jason Samsc8514792009-10-29 14:27:29 -0700262 bindTexture(NAMED_PFTexNearest, 0, state->homeButtonId);
Jason Sams0f505e52009-10-13 17:18:35 -0700263
Jason Sams76512482010-02-04 16:31:35 -0800264 float w = getWidth();
265 float h = getHeight();
266
267 float x;
268 float y;
269 if (getWidth() > getHeight()) {
270 x = w - (params->homeButtonTextureWidth * (1 - g_Animation)) + 20;
271 y = (h - params->homeButtonTextureHeight) * 0.5f;
272 } else {
273 x = (w - params->homeButtonTextureWidth) / 2;
274 y = -g_Animation * params->homeButtonTextureHeight;
275 y -= 30; // move the house to the edge of the screen as it doesn't fill the texture.
276 }
277
Jason Sams96b49d82009-10-20 14:28:53 -0700278 drawSpriteScreenspace(x, y, 0, params->homeButtonTextureWidth, params->homeButtonTextureHeight);
Jason Sams0f505e52009-10-13 17:18:35 -0700279}
280
Jason Sams09c6fc02009-10-16 17:23:23 -0700281void drawFrontGrid(float rowOffset, float p)
Jason Sams0f505e52009-10-13 17:18:35 -0700282{
283 float h = getHeight();
284 float w = getWidth();
285
286 int intRowOffset = rowOffset;
287 float rowFrac = rowOffset - intRowOffset;
Jason Sams76512482010-02-04 16:31:35 -0800288 float colWidth = 120.f;//getWidth() / 4;
Jason Sams0f505e52009-10-13 17:18:35 -0700289 float rowHeight = colWidth + 25.f;
Jason Samsb4ecab22010-01-19 16:43:26 -0800290 float yoff = 0.5f * h + 1.5f * rowHeight;
Jason Sams0f505e52009-10-13 17:18:35 -0700291
292 int row, col;
Jason Sams76512482010-02-04 16:31:35 -0800293 int colCount = 4;
294 if (w > h) {
295 colCount = 6;
296 rowHeight -= 12.f;
297 yoff = 0.47f * h + 1.0f * rowHeight;
298 }
299
300 int iconNum = (intRowOffset - 5) * colCount;
301
Jason Sams0f505e52009-10-13 17:18:35 -0700302
Jason Samsb4ecab22010-01-19 16:43:26 -0800303 bindProgramVertex(NAMED_PVCurve);
304
Jason Sams76512482010-02-04 16:31:35 -0800305 vpConstants->Position.z = p;
Jason Samsb4ecab22010-01-19 16:43:26 -0800306
Jason Samse78ace92010-02-02 17:37:44 -0800307 setColor(1.0f, 1.0f, 1.0f, 1.0f);
Jason Samsb4ecab22010-01-19 16:43:26 -0800308 for (row = -5; row < 15; row++) {
Jason Sams0f505e52009-10-13 17:18:35 -0700309 float y = yoff - ((-rowFrac + row) * rowHeight);
310
Jason Sams76512482010-02-04 16:31:35 -0800311 for (col=0; col < colCount; col++) {
Jason Sams0f505e52009-10-13 17:18:35 -0700312 if (iconNum >= state->iconCount) {
313 return;
314 }
315
316 if (iconNum >= 0) {
Jason Samsb4ecab22010-01-19 16:43:26 -0800317 float x = colWidth * col + (colWidth / 2);
Jason Sams6b08ffe2010-02-22 15:41:30 -0800318 vpConstants->Position.x = x + 0.2f;
Jason Sams1a94ee32010-01-20 13:34:30 -0800319
Jason Sams37f262d2010-01-20 11:19:51 -0800320 if (state->selectedIconIndex == iconNum && !p) {
Jason Sams1a94ee32010-01-20 13:34:30 -0800321 bindProgramFragment(NAMED_PFTexNearest);
322 bindTexture(NAMED_PFTexNearest, 0, state->selectedIconTexture);
Jason Sams76512482010-02-04 16:31:35 -0800323 vpConstants->ImgSize.x = SELECTION_TEXTURE_WIDTH_PX;
324 vpConstants->ImgSize.y = SELECTION_TEXTURE_HEIGHT_PX;
325 vpConstants->Position.y = y - (SELECTION_TEXTURE_HEIGHT_PX - ICON_TEXTURE_HEIGHT_PX) * 0.5f;
Jason Sams1a94ee32010-01-20 13:34:30 -0800326 drawSimpleMesh(NAMED_SMCell);
Jason Sams37f262d2010-01-20 11:19:51 -0800327 }
328
Jason Sams1a94ee32010-01-20 13:34:30 -0800329 bindProgramFragment(NAMED_PFTexMip);
Jason Sams76512482010-02-04 16:31:35 -0800330 vpConstants->ImgSize.x = ICON_TEXTURE_WIDTH_PX;
331 vpConstants->ImgSize.y = ICON_TEXTURE_HEIGHT_PX;
Jason Sams6b08ffe2010-02-22 15:41:30 -0800332 vpConstants->Position.y = y - 0.2f;
Jason Samsb4ecab22010-01-19 16:43:26 -0800333 bindTexture(NAMED_PFTexMip, 0, loadI32(ALLOC_ICON_IDS, iconNum));
334 drawSimpleMesh(NAMED_SMCell);
Joe Onorato742d7fc2009-10-15 19:48:16 -0700335
Jason Sams37f262d2010-01-20 11:19:51 -0800336 bindProgramFragment(NAMED_PFTexMipAlpha);
Jason Sams76512482010-02-04 16:31:35 -0800337 vpConstants->ImgSize.x = 120.f;
338 vpConstants->ImgSize.y = 64.f;
Jason Sams6b08ffe2010-02-22 15:41:30 -0800339 vpConstants->Position.y = y - 64.f - 0.2f;
Jason Sams37f262d2010-01-20 11:19:51 -0800340 bindTexture(NAMED_PFTexMipAlpha, 0, loadI32(ALLOC_LABEL_IDS, iconNum));
Jason Samsb4ecab22010-01-19 16:43:26 -0800341 drawSimpleMesh(NAMED_SMCell);
Jason Sams0f505e52009-10-13 17:18:35 -0700342 }
343 iconNum++;
344 }
345 }
346}
347
Jason Sams0f505e52009-10-13 17:18:35 -0700348
349int
350main(int launchID)
351{
352 // Compute dt in seconds.
353 int newTime = uptimeMillis();
354 g_DT = (newTime - g_LastTime) / 1000.f;
355 g_LastTime = newTime;
Jason Sams2e19c052009-10-20 18:19:55 -0700356
Jason Sams0f505e52009-10-13 17:18:35 -0700357 if (!g_DrawLastFrame) {
358 // If we stopped rendering we cannot use DT.
359 // assume 30fps in this case.
360 g_DT = 0.033f;
361 }
Jason Samsb52dfa02009-10-14 20:16:14 -0700362 // physics may break if DT is large.
363 g_DT = minf(g_DT, 0.2f);
Jason Sams0f505e52009-10-13 17:18:35 -0700364
365 if (g_Zoom != state->zoomTarget) {
Jason Sams6471c8b2010-01-20 14:15:22 -0800366 float dz = g_DT * 1.7f;
367 if (state->zoomTarget < 0.5f) {
368 dz = -dz;
Jason Sams0f505e52009-10-13 17:18:35 -0700369 }
370 if (fabsf(g_Zoom - state->zoomTarget) < fabsf(dz)) {
371 g_Zoom = state->zoomTarget;
372 } else {
373 g_Zoom += dz;
374 }
375 updateReadback();
376 }
Jason Sams638a93d2010-03-08 17:03:51 -0800377 g_Animation = powf(1-g_Zoom, 3);
Jason Sams0f505e52009-10-13 17:18:35 -0700378
379 // Set clear value to dim the background based on the zoom position.
Jason Sams41b61c82009-10-15 15:40:54 -0700380 if ((g_Zoom < 0.001f) && (state->zoomTarget < 0.001f) && !g_SpecialHWWar) {
Jason Sams0f505e52009-10-13 17:18:35 -0700381 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
382 // When we're zoomed out and not tracking motion events, reset the pos to 0.
383 if (!g_LastTouchDown) {
384 g_PosPage = 0;
385 }
386 return lastFrame(0);
Jason Sams0f505e52009-10-13 17:18:35 -0700387 } else {
388 pfClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
389 }
390
391 // icons & labels
392 int iconCount = state->iconCount;
Jason Samscc903492010-03-12 12:46:04 -0800393 if (getWidth() > getHeight()) {
Joe Onorato20e7a562010-03-18 17:12:52 -0700394 g_Cols = 6;
395 g_Rows = 3;
396 } else {
397 g_Cols = 4;
398 g_Rows = 4;
Jason Samscc903492010-03-12 12:46:04 -0800399 }
Joe Onorato20e7a562010-03-18 17:12:52 -0700400 g_PosMax = ((iconCount + (g_Cols-1)) / g_Cols) - g_Rows;
Jason Sams0f505e52009-10-13 17:18:35 -0700401 if (g_PosMax < 0) g_PosMax = 0;
402
Jason Samscc903492010-03-12 12:46:04 -0800403 updatePos();
Jason Sams0f505e52009-10-13 17:18:35 -0700404 updateReadback();
405
406 //debugF(" draw g_PosPage", g_PosPage);
407
408 // Draw the icons ========================================
Jason Sams6471c8b2010-01-20 14:15:22 -0800409 drawFrontGrid(g_PosPage, g_Animation);
Jason Samsc8514792009-10-29 14:27:29 -0700410
411 bindProgramFragment(NAMED_PFTexNearest);
Jason Samsb52dfa02009-10-14 20:16:14 -0700412 draw_home_button();
Jason Sams0f505e52009-10-13 17:18:35 -0700413
Jason Sams41b61c82009-10-15 15:40:54 -0700414 // This is a WAR to do a rendering pass without drawing during init to
415 // force the driver to preload and compile its shaders.
416 // Without this the first animation does not appear due to the time it
417 // takes to init the driver state.
418 if (g_SpecialHWWar) {
419 g_SpecialHWWar = 0;
420 return 1;
421 }
422
Jason Sams0f505e52009-10-13 17:18:35 -0700423 // Bug workaround where the last frame is not always displayed
424 // So we keep rendering until the bug is fixed.
Mike Cleron7d5d7462009-10-20 14:06:00 -0700425 return lastFrame((g_PosVelocity != 0) || fracf(g_PosPage) || g_Zoom != state->zoomTarget || (g_MoveToTime != 0));
Jason Sams0f505e52009-10-13 17:18:35 -0700426}
427