blob: 5ff33088512f6ccb936722107a9355c6aeb3368c [file] [log] [blame]
Joe Onorato93839052009-08-06 20:34:32 -07001#pragma version(1)
2#pragma stateVertex(PV)
3#pragma stateFragment(PF)
4#pragma stateFragmentStore(PFS)
5
Joe Onorato43e7bcf2009-08-08 18:53:53 -07006#define PI 3.14159f
7
Jason Sams78aebd82009-09-15 13:06:59 -07008float deceleration;
Joe Onorato93839052009-08-06 20:34:32 -07009
Joe Onorato43e7bcf2009-08-08 18:53:53 -070010// Drawing constants, should be parameters ======
Joe Onoratoefabe002009-08-28 09:38:18 -070011#define VIEW_ANGLE 1.28700222f
Joe Onorato43e7bcf2009-08-08 18:53:53 -070012
Jason Sams78aebd82009-09-15 13:06:59 -070013void init() {
14 deceleration = 0;
15}
16
Joe Onoratofb0ca672009-09-14 17:55:46 -040017int g_lastFrameTime = 0;
18void print_frame_rate()
19{
20 int now = uptimeMillis();
21 if (g_lastFrameTime != 0) {
22 debugI32("frame_rate", 1000/(now-g_lastFrameTime));
23 }
24 g_lastFrameTime = now;
25}
26
Joe Onorato43e7bcf2009-08-08 18:53:53 -070027int
28count_pages(int iconCount)
Joe Onorato93839052009-08-06 20:34:32 -070029{
Joe Onorato43e7bcf2009-08-08 18:53:53 -070030 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
31 int pages = iconCount / iconsPerPage;
32 if (pages*iconsPerPage != iconCount) {
Joe Onoratod769a632009-08-11 17:09:02 -070033 pages++;
Joe Onorato43e7bcf2009-08-08 18:53:53 -070034 }
Joe Onoratod769a632009-08-11 17:09:02 -070035 return pages;
36}
37
Joe Onoratod769a632009-08-11 17:09:02 -070038float
39modf(float x, float y)
40{
41 return x-(y*floorf(x/y));
Joe Onorato93839052009-08-06 20:34:32 -070042}
43
Joe Onorato0d1c5632009-08-28 15:57:18 -070044float
45far_size(float sizeAt0)
46{
47 return sizeAt0 * (RADIUS+2) / 2; // -2 is the camera z=(z-camZ)/z
48}
49
Joe Onoratoefabe002009-08-28 09:38:18 -070050void
51draw_page(int icon, int lastIcon, float centerAngle)
52{
53 int row;
54 int col;
55
Jason Sams78aebd82009-09-15 13:06:59 -070056 float scale = 1.0f - state->zoom;
Joe Onorato85a02a82009-09-08 12:34:22 -070057
Joe Onoratoefabe002009-08-28 09:38:18 -070058 float iconTextureWidth = ICON_WIDTH_PX / (float)ICON_TEXTURE_WIDTH_PX;
59 float iconTextureHeight = ICON_HEIGHT_PX / (float)ICON_TEXTURE_HEIGHT_PX;
60
61 float iconWidthAngle = VIEW_ANGLE * ICON_WIDTH_PX / SCREEN_WIDTH_PX;
Joe Onorato0d1c5632009-08-28 15:57:18 -070062 float columnGutterAngle = iconWidthAngle * 0.70f;
Joe Onoratoefabe002009-08-28 09:38:18 -070063
Joe Onorato6665c0f2009-09-02 15:27:24 -070064 float farIconSize = FAR_ICON_SIZE;
Joe Onorato0d1c5632009-08-28 15:57:18 -070065 float iconGutterHeight = farIconSize * 1.1f;
66
Joe Onorato6665c0f2009-09-02 15:27:24 -070067 float farIconTextureSize = far_size(2 * ICON_TEXTURE_WIDTH_PX / (float)SCREEN_WIDTH_PX);
68
Jason Sams78aebd82009-09-15 13:06:59 -070069 float normalizedLabelWidth = 2 * params->bubbleWidth / (float)SCREEN_WIDTH_PX;
Joe Onorato0d1c5632009-08-28 15:57:18 -070070 float farLabelWidth = far_size(normalizedLabelWidth);
Jason Sams78aebd82009-09-15 13:06:59 -070071 float farLabelHeight = far_size(params->bubbleHeight * (normalizedLabelWidth / params->bubbleWidth));
72 float labelTextureWidth = (float)params->bubbleWidth / params->bubbleBitmapWidth;
73 float labelTextureHeight = (float)params->bubbleHeight / params->bubbleBitmapHeight;
Joe Onoratoefabe002009-08-28 09:38:18 -070074
75 for (row=0; row<ROWS_PER_PAGE && icon<=lastIcon; row++) {
76 float angle = centerAngle;
77 angle -= (columnGutterAngle + iconWidthAngle) * 1.5f;
78
Joe Onorato6665c0f2009-09-02 15:27:24 -070079 float iconTop = (farIconSize + iconGutterHeight) * (2.0f + ICON_TOP_OFFSET)
Joe Onorato0d1c5632009-08-28 15:57:18 -070080 - row * (farIconSize + iconGutterHeight);
Joe Onoratod40eec32009-09-08 12:34:22 -070081 iconTop -= 6 * scale; // make the zoom point below center
Joe Onoratoefabe002009-08-28 09:38:18 -070082 float iconBottom = iconTop - farIconSize;
83
Joe Onorato0d1c5632009-08-28 15:57:18 -070084 float labelTop = iconBottom - (.1 * farLabelHeight);
85 float labelBottom = labelTop - farLabelHeight;
86
Joe Onorato6665c0f2009-09-02 15:27:24 -070087 float iconTextureTop = iconTop + (0.5f * (farIconTextureSize - farIconSize));
88 float iconTextureBottom = iconTextureTop - farIconTextureSize;
89
Joe Onoratoefabe002009-08-28 09:38:18 -070090 for (col=0; col<COLUMNS_PER_PAGE && icon<=lastIcon; col++) {
91 // icon
92 float sine = sinf(angle);
93 float cosine = cosf(angle);
94
Joe Onorato0d1c5632009-08-28 15:57:18 -070095 float centerX = sine * RADIUS;
96 float centerZ = cosine * RADIUS;
Joe Onoratod40eec32009-09-08 12:34:22 -070097 centerZ -= ((RADIUS+2+1)*scale); // 2 is camera loc, 1 put it slightly behind that.
Joe Onorato0d1c5632009-08-28 15:57:18 -070098
Joe Onorato6665c0f2009-09-02 15:27:24 -070099 float iconLeftX = centerX - (cosine * farIconTextureSize * .5);
100 float iconRightX = centerX + (cosine * farIconTextureSize * .5);
101 float iconLeftZ = centerZ + (sine * farIconTextureSize * .5);
102 float iconRightZ = centerZ - (sine * farIconTextureSize * .5);
103
Jason Sams78aebd82009-09-15 13:06:59 -0700104 if (state->selectedIconIndex == icon) {
105 bindTexture(NAMED_PF, 0, state->selectedIconTexture);
Joe Onorato6665c0f2009-09-02 15:27:24 -0700106 drawQuadTexCoords(
107 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
108 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
109 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
110 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
Joe Onorato1291a8c2009-09-15 15:07:25 -0400111 } else {
112 bindTexture(NAMED_PF, 0, loadI32(ALLOC_ICON_IDS, icon));
113 drawQuadTexCoords(
114 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
115 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
116 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
117 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
Joe Onorato6665c0f2009-09-02 15:27:24 -0700118 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700119
Joe Onoratoefabe002009-08-28 09:38:18 -0700120 // label
Joe Onoratofb0ca672009-09-14 17:55:46 -0400121 if (scale <= 0.1f) {
Joe Onorato85a02a82009-09-08 12:34:22 -0700122 float labelLeftX = centerX - farLabelWidth * 0.5f;
123 float labelRightX = centerX + farLabelWidth * 0.5f;
Joe Onoratoefabe002009-08-28 09:38:18 -0700124
Joe Onorato85a02a82009-09-08 12:34:22 -0700125 bindTexture(NAMED_PF, 0, loadI32(ALLOC_LABEL_IDS, icon));
126 drawQuadTexCoords(
127 labelLeftX, labelTop, centerZ, 0.0f, 0.0f,
128 labelRightX, labelTop, centerZ, labelTextureWidth, 0.0f,
129 labelRightX, labelBottom, centerZ, labelTextureWidth, labelTextureHeight,
130 labelLeftX, labelBottom, centerZ, 0.0f, labelTextureHeight);
131 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700132
Joe Onoratoefabe002009-08-28 09:38:18 -0700133 angle += columnGutterAngle + iconWidthAngle;
134 icon++;
135 }
136 }
137}
138
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700139int
Joe Onoratod769a632009-08-11 17:09:02 -0700140main(int launchID)
Joe Onorato93839052009-08-06 20:34:32 -0700141{
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700142 // Clear to transparent
Joe Onorato93839052009-08-06 20:34:32 -0700143 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Joe Onorato93839052009-08-06 20:34:32 -0700144
Joe Onorato006b25f2009-09-03 11:38:43 -0700145 // If we're not supposed to be showing, don't do anything.
Jason Sams78aebd82009-09-15 13:06:59 -0700146 if (!state->visible) {
Joe Onorato006b25f2009-09-03 11:38:43 -0700147 return 0;
148 }
149
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700150 // icons & labels
Jason Sams78aebd82009-09-15 13:06:59 -0700151 int iconCount = state->iconCount;
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700152 int pageCount = count_pages(iconCount);
153
Jason Sams78aebd82009-09-15 13:06:59 -0700154 float scrollXPx = state->scrollX;
Joe Onoratoc567acb2009-08-31 14:34:43 -0700155 float maxScrollXPx = -(pageCount-1) * SCREEN_WIDTH_PX;
Joe Onoratod769a632009-08-11 17:09:02 -0700156 int done = 0;
157
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700158 // Clamp -- because java doesn't know how big the icons are
159 if (scrollXPx > 0) {
160 scrollXPx = 0;
161 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700162 if (scrollXPx < maxScrollXPx) {
163 scrollXPx = maxScrollXPx;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700164 }
165
Joe Onoratod769a632009-08-11 17:09:02 -0700166 // If we've been given a velocity, start a fling
Jason Sams78aebd82009-09-15 13:06:59 -0700167 float flingVelocityPxMs = state->flingVelocityX;
Joe Onoratod769a632009-08-11 17:09:02 -0700168 if (flingVelocityPxMs != 0) {
169 // how many screens will this velocity do? TODO: use long
170 // G * ppi * friction // why G? // friction = 0.015
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700171 float flingDurationMs;
Joe Onoratod769a632009-08-11 17:09:02 -0700172 if (deceleration == 0) {
173 // On the first frame, calculate which animation we're going to do. If it's
174 // going to end up less than halfway into a page, we'll bounce back the previous
175 // page. Otherwise, we'll adjust the deceleration so it just makes it to the
176 // page boundary.
177 if (flingVelocityPxMs > 0) {
178 deceleration = -1000;
179 } else {
180 deceleration = 1000;
181 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400182 // minimum velocity
183 if (flingVelocityPxMs < 0) {
184 if (flingVelocityPxMs > -500) {
185 flingVelocityPxMs = -500;
186 }
187 } else {
188 if (flingVelocityPxMs < 500) {
189 flingVelocityPxMs = 500;
190 }
191 }
192
Joe Onoratod769a632009-08-11 17:09:02 -0700193 // v' = v + at --> t = -v / a
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700194 // x' = x + vt + .5 a t^2
195 flingDurationMs = - flingVelocityPxMs / deceleration;
196 float endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
197 + ((deceleration*flingDurationMs*flingDurationMs)/2);
Joe Onoratod769a632009-08-11 17:09:02 -0700198
199 if (endPos > 0) {
200 endPos = 0;
201 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700202 if (endPos < maxScrollXPx) {
203 endPos = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700204 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700205 float scrollOnPage = modf(endPos, SCREEN_WIDTH_PX);
206 int endPage = -endPos/SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400207
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700208 if (flingVelocityPxMs < 0) {
Joe Onoratoefabe002009-08-28 09:38:18 -0700209 if (scrollOnPage < (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700210 // adjust the deceleration so we align on the page boundary
211 // a = 2(x-x0-v0t)/t^2
Joe Onoratoefabe002009-08-28 09:38:18 -0700212 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400213 debugI32("endPos case 1", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700214 } else {
215 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700216 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400217 debugI32("endPos case 2", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700218 }
219 } else {
Joe Onoratoefabe002009-08-28 09:38:18 -0700220 if (scrollOnPage >= (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700221 // adjust the deceleration so we align on the page boundary
Joe Onoratoefabe002009-08-28 09:38:18 -0700222 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400223 debugI32("endPos case 3", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700224 } else {
225 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700226 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400227 debugI32("endPos case 4", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700228 }
229 }
230 // v = v0 + at --> (v - v0) / t
231 deceleration = 2*(endPos-scrollXPx-(flingVelocityPxMs*flingDurationMs))
232 / (flingDurationMs*flingDurationMs);
233 endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
234 + ((deceleration*flingDurationMs*flingDurationMs)/2);
235
Jason Sams78aebd82009-09-15 13:06:59 -0700236 state->flingDuration = flingDurationMs;
237 state->flingEndPos = endPos;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700238 } else {
Jason Sams78aebd82009-09-15 13:06:59 -0700239 flingDurationMs = state->flingDuration;
Joe Onoratod769a632009-08-11 17:09:02 -0700240 }
241
242 // adjust the deceleration so we always hit a page boundary
243
Joe Onoratod769a632009-08-11 17:09:02 -0700244 int now = uptimeMillis();
Jason Sams78aebd82009-09-15 13:06:59 -0700245 float elapsedTime = (now - state->flingTimeMs) / 1000.0f;
Joe Onoratod769a632009-08-11 17:09:02 -0700246 int animEndTime = -flingVelocityPxMs / deceleration;
247
Joe Onoratod769a632009-08-11 17:09:02 -0700248 int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
249 + (deceleration * elapsedTime * elapsedTime / 2.0f);
250 scrollXPx += flingOffsetPx;
251
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700252 if (elapsedTime > flingDurationMs) {
Jason Sams78aebd82009-09-15 13:06:59 -0700253 scrollXPx = state->flingEndPos;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700254 done = 1;
255 }
Joe Onorato85a02a82009-09-08 12:34:22 -0700256 } else {
257 done = 1;
Joe Onoratod769a632009-08-11 17:09:02 -0700258 }
259
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700260 // Clamp
Joe Onoratod769a632009-08-11 17:09:02 -0700261 if (scrollXPx > 0) {
262 scrollXPx = 0;
263 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700264 if (scrollXPx < maxScrollXPx) {
265 scrollXPx = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700266 }
Jason Sams78aebd82009-09-15 13:06:59 -0700267
268 state->currentScrollX = scrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700269 if (done) {
Jason Sams78aebd82009-09-15 13:06:59 -0700270 state->scrollX = scrollXPx;
271 state->flingVelocityX = 0;
272 deceleration = 0.f;
Joe Onoratod769a632009-08-11 17:09:02 -0700273 }
274
Joe Onoratoc567acb2009-08-31 14:34:43 -0700275 // Draw the icons ========================================
276 bindProgramVertex(NAMED_PV);
Joe Onoratoefabe002009-08-28 09:38:18 -0700277 bindProgramFragment(NAMED_PF);
278 bindProgramFragmentStore(NAMED_PFS);
279
280 // Bug makes 1.0f alpha fail.
281 color(1.0f, 1.0f, 1.0f, 0.99f);
282
283 int lastIcon = iconCount-1;
284
285 float currentPage = -scrollXPx / (float)SCREEN_WIDTH_PX;
286 int page = currentPage;
287 float currentPagePosition = currentPage - page;
Joe Onoratod769a632009-08-11 17:09:02 -0700288
Joe Onoratod769a632009-08-11 17:09:02 -0700289 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
Joe Onoratoefabe002009-08-28 09:38:18 -0700290 int icon = clamp(iconsPerPage * page, 0, lastIcon);
Joe Onorato93839052009-08-06 20:34:32 -0700291
Joe Onoratoefabe002009-08-28 09:38:18 -0700292 draw_page(icon, lastIcon, -VIEW_ANGLE*currentPagePosition);
293 draw_page(icon+iconsPerPage, lastIcon, (-VIEW_ANGLE*currentPagePosition)+VIEW_ANGLE);
Jason Sams78aebd82009-09-15 13:06:59 -0700294
Joe Onorato6665c0f2009-09-02 15:27:24 -0700295 // Draw the border lines for debugging ========================================
Joe Onoratoc567acb2009-08-31 14:34:43 -0700296 /*
297 bindProgramVertex(NAMED_PVOrtho);
298 bindProgramFragment(NAMED_PFText);
299 bindProgramFragmentStore(NAMED_PFSText);
300
Joe Onorato6665c0f2009-09-02 15:27:24 -0700301 color(1.0f, 1.0f, 0.0f, 0.99f);
302 int i;
303 for (i=0; i<ROWS_PER_PAGE+1; i++) {
304 int y = loadI32(ALLOC_Y_BORDERS, i);
305 drawRect(0, y, SCREEN_WIDTH_PX, y+1, 0.0f);
306 }
307 for (i=0; i<COLUMNS_PER_PAGE+1; i++) {
308 int x = loadI32(ALLOC_X_BORDERS, i);
309 drawRect(x, 0, x+1, SCREEN_HEIGHT_PX, 0.0f);
310 }
311 */
312
313 // Draw the scroll handle ========================================
314 /*
Joe Onoratoc567acb2009-08-31 14:34:43 -0700315 bindTexture(NAMED_PFText, 0, loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_ID));
316 float handleLeft = 40 + (320 * (scrollXPx/(float)(maxScrollXPx)));
317 float handleTop = 680;
318 float handleWidth = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_WIDTH);
319 float handleHeight = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_HEIGHT);
320 drawRect(handleLeft, handleTop, handleLeft+handleWidth, handleTop+handleHeight, 0.0f);
321 */
Joe Onorato93839052009-08-06 20:34:32 -0700322
Joe Onoratofb0ca672009-09-14 17:55:46 -0400323 print_frame_rate();
324
Joe Onoratod769a632009-08-11 17:09:02 -0700325 return !done;
Joe Onorato93839052009-08-06 20:34:32 -0700326}
327