blob: d7df6b96e7ef505c8ca87f3e9d60354ee7477b9b [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
Joe Onorato43e7bcf2009-08-08 18:53:53 -07008// Variables from java ======
9
10// Parameters ======
11#define PARAM_BUBBLE_WIDTH 0
12#define PARAM_BUBBLE_HEIGHT 1
13#define PARAM_BUBBLE_BITMAP_WIDTH 2
14#define PARAM_BUBBLE_BITMAP_HEIGHT 3
Joe Onoratoc567acb2009-08-31 14:34:43 -070015#define PARAM_SCROLL_HANDLE_ID 4
16#define PARAM_SCROLL_HANDLE_TEX_WIDTH 5
17#define PARAM_SCROLL_HANDLE_TEX_HEIGHT 6
Joe Onorato93839052009-08-06 20:34:32 -070018
Joe Onorato1feb3a82009-08-08 22:32:00 -070019// State ======
20#define STATE_ICON_COUNT 0
21#define STATE_SCROLL_X 1
Joe Onoratod769a632009-08-11 17:09:02 -070022#define STATE_FLING_TIME 2
23#define STATE_FLING_VELOCITY_X 3
24#define STATE_ADJUSTED_DECELERATION 4
Joe Onorato9c1289c2009-08-17 11:03:03 -040025
26/* with fling offset applied */
27#define STATE_CURRENT_SCROLL_X 5
28
Joe Onoratoeb2c02e2009-08-12 21:40:52 -070029#define STATE_FLING_DURATION 6
30#define STATE_FLING_END_POS 7
Joe Onorato93839052009-08-06 20:34:32 -070031
Joe Onorato6665c0f2009-09-02 15:27:24 -070032#define STATE_START_SCROLL_X 8
33#define STATE_SELECTED_ICON_INDEX 9
34#define STATE_SELECTED_ICON_TEXTURE 10
Joe Onoratoc567acb2009-08-31 14:34:43 -070035
Joe Onorato006b25f2009-09-03 11:38:43 -070036#define STATE_VISIBLE 11
Joe Onorato85a02a82009-09-08 12:34:22 -070037#define STATE_ZOOM 12
Joe Onorato93839052009-08-06 20:34:32 -070038
Joe Onorato43e7bcf2009-08-08 18:53:53 -070039// Drawing constants, should be parameters ======
Joe Onoratoefabe002009-08-28 09:38:18 -070040#define VIEW_ANGLE 1.28700222f
Joe Onorato43e7bcf2009-08-08 18:53:53 -070041
Joe Onoratofb0ca672009-09-14 17:55:46 -040042int g_lastFrameTime = 0;
43void print_frame_rate()
44{
45 int now = uptimeMillis();
46 if (g_lastFrameTime != 0) {
47 debugI32("frame_rate", 1000/(now-g_lastFrameTime));
48 }
49 g_lastFrameTime = now;
50}
51
Joe Onorato43e7bcf2009-08-08 18:53:53 -070052int
53count_pages(int iconCount)
Joe Onorato93839052009-08-06 20:34:32 -070054{
Joe Onorato43e7bcf2009-08-08 18:53:53 -070055 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
56 int pages = iconCount / iconsPerPage;
57 if (pages*iconsPerPage != iconCount) {
Joe Onoratod769a632009-08-11 17:09:02 -070058 pages++;
Joe Onorato43e7bcf2009-08-08 18:53:53 -070059 }
Joe Onoratod769a632009-08-11 17:09:02 -070060 return pages;
61}
62
Joe Onoratod769a632009-08-11 17:09:02 -070063float
64modf(float x, float y)
65{
66 return x-(y*floorf(x/y));
Joe Onorato93839052009-08-06 20:34:32 -070067}
68
Joe Onorato0d1c5632009-08-28 15:57:18 -070069float
70far_size(float sizeAt0)
71{
72 return sizeAt0 * (RADIUS+2) / 2; // -2 is the camera z=(z-camZ)/z
73}
74
Joe Onoratoefabe002009-08-28 09:38:18 -070075void
76draw_page(int icon, int lastIcon, float centerAngle)
77{
78 int row;
79 int col;
80
Joe Onorato85a02a82009-09-08 12:34:22 -070081 float scale = 1.0f - loadI32(ALLOC_STATE, STATE_ZOOM)/100000.0f;
82
Joe Onoratoefabe002009-08-28 09:38:18 -070083 float iconTextureWidth = ICON_WIDTH_PX / (float)ICON_TEXTURE_WIDTH_PX;
84 float iconTextureHeight = ICON_HEIGHT_PX / (float)ICON_TEXTURE_HEIGHT_PX;
85
86 float iconWidthAngle = VIEW_ANGLE * ICON_WIDTH_PX / SCREEN_WIDTH_PX;
Joe Onorato0d1c5632009-08-28 15:57:18 -070087 float columnGutterAngle = iconWidthAngle * 0.70f;
Joe Onoratoefabe002009-08-28 09:38:18 -070088
Joe Onorato6665c0f2009-09-02 15:27:24 -070089 float farIconSize = FAR_ICON_SIZE;
Joe Onorato0d1c5632009-08-28 15:57:18 -070090 float iconGutterHeight = farIconSize * 1.1f;
91
Joe Onorato6665c0f2009-09-02 15:27:24 -070092 float farIconTextureSize = far_size(2 * ICON_TEXTURE_WIDTH_PX / (float)SCREEN_WIDTH_PX);
93
Joe Onorato0d1c5632009-08-28 15:57:18 -070094 float labelWidthPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_WIDTH);
95 float labelHeightPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_HEIGHT);
96
97 float normalizedLabelWidth = 2 * labelWidthPx / (float)SCREEN_WIDTH_PX;
98 float farLabelWidth = far_size(normalizedLabelWidth);
99 float farLabelHeight = far_size(labelHeightPx * (normalizedLabelWidth / labelWidthPx));
100 float labelTextureWidth = labelWidthPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_WIDTH);
101 float labelTextureHeight = labelHeightPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_HEIGHT);
102
Joe Onorato6665c0f2009-09-02 15:27:24 -0700103 int selectedIconIndex = loadI32(ALLOC_STATE, STATE_SELECTED_ICON_INDEX);
Joe Onoratoefabe002009-08-28 09:38:18 -0700104
105 for (row=0; row<ROWS_PER_PAGE && icon<=lastIcon; row++) {
106 float angle = centerAngle;
107 angle -= (columnGutterAngle + iconWidthAngle) * 1.5f;
108
Joe Onorato6665c0f2009-09-02 15:27:24 -0700109 float iconTop = (farIconSize + iconGutterHeight) * (2.0f + ICON_TOP_OFFSET)
Joe Onorato0d1c5632009-08-28 15:57:18 -0700110 - row * (farIconSize + iconGutterHeight);
Joe Onoratod40eec32009-09-08 12:34:22 -0700111 iconTop -= 6 * scale; // make the zoom point below center
Joe Onoratoefabe002009-08-28 09:38:18 -0700112 float iconBottom = iconTop - farIconSize;
113
Joe Onorato0d1c5632009-08-28 15:57:18 -0700114 float labelTop = iconBottom - (.1 * farLabelHeight);
115 float labelBottom = labelTop - farLabelHeight;
116
Joe Onorato6665c0f2009-09-02 15:27:24 -0700117 float iconTextureTop = iconTop + (0.5f * (farIconTextureSize - farIconSize));
118 float iconTextureBottom = iconTextureTop - farIconTextureSize;
119
Joe Onoratoefabe002009-08-28 09:38:18 -0700120 for (col=0; col<COLUMNS_PER_PAGE && icon<=lastIcon; col++) {
121 // icon
122 float sine = sinf(angle);
123 float cosine = cosf(angle);
124
Joe Onorato0d1c5632009-08-28 15:57:18 -0700125 float centerX = sine * RADIUS;
126 float centerZ = cosine * RADIUS;
Joe Onoratod40eec32009-09-08 12:34:22 -0700127 centerZ -= ((RADIUS+2+1)*scale); // 2 is camera loc, 1 put it slightly behind that.
Joe Onorato0d1c5632009-08-28 15:57:18 -0700128
Joe Onorato6665c0f2009-09-02 15:27:24 -0700129 float iconLeftX = centerX - (cosine * farIconTextureSize * .5);
130 float iconRightX = centerX + (cosine * farIconTextureSize * .5);
131 float iconLeftZ = centerZ + (sine * farIconTextureSize * .5);
132 float iconRightZ = centerZ - (sine * farIconTextureSize * .5);
133
134 if (selectedIconIndex == icon) {
135 bindTexture(NAMED_PF, 0, loadI32(ALLOC_STATE, STATE_SELECTED_ICON_TEXTURE));
136 drawQuadTexCoords(
137 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
138 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
139 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
140 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
Joe Onorato1291a8c2009-09-15 15:07:25 -0400141 } else {
142 bindTexture(NAMED_PF, 0, loadI32(ALLOC_ICON_IDS, icon));
143 drawQuadTexCoords(
144 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
145 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
146 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
147 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
Joe Onorato6665c0f2009-09-02 15:27:24 -0700148 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700149
Joe Onoratoefabe002009-08-28 09:38:18 -0700150 // label
Joe Onoratofb0ca672009-09-14 17:55:46 -0400151 if (scale <= 0.1f) {
Joe Onorato85a02a82009-09-08 12:34:22 -0700152 float labelLeftX = centerX - farLabelWidth * 0.5f;
153 float labelRightX = centerX + farLabelWidth * 0.5f;
Joe Onoratoefabe002009-08-28 09:38:18 -0700154
Joe Onorato85a02a82009-09-08 12:34:22 -0700155 bindTexture(NAMED_PF, 0, loadI32(ALLOC_LABEL_IDS, icon));
156 drawQuadTexCoords(
157 labelLeftX, labelTop, centerZ, 0.0f, 0.0f,
158 labelRightX, labelTop, centerZ, labelTextureWidth, 0.0f,
159 labelRightX, labelBottom, centerZ, labelTextureWidth, labelTextureHeight,
160 labelLeftX, labelBottom, centerZ, 0.0f, labelTextureHeight);
161 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700162
Joe Onoratoefabe002009-08-28 09:38:18 -0700163 angle += columnGutterAngle + iconWidthAngle;
164 icon++;
165 }
166 }
167}
168
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700169int
Joe Onoratod769a632009-08-11 17:09:02 -0700170main(int launchID)
Joe Onorato93839052009-08-06 20:34:32 -0700171{
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700172 // Clear to transparent
Joe Onorato93839052009-08-06 20:34:32 -0700173 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Joe Onorato93839052009-08-06 20:34:32 -0700174
Joe Onorato006b25f2009-09-03 11:38:43 -0700175 // If we're not supposed to be showing, don't do anything.
176 if (!loadI32(ALLOC_STATE, STATE_VISIBLE)) {
177 return 0;
178 }
179
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700180 // icons & labels
Joe Onorato1feb3a82009-08-08 22:32:00 -0700181 int iconCount = loadI32(ALLOC_STATE, STATE_ICON_COUNT);
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700182 int pageCount = count_pages(iconCount);
183
Joe Onoratod769a632009-08-11 17:09:02 -0700184 float scrollXPx = loadI32(ALLOC_STATE, STATE_SCROLL_X);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700185 float maxScrollXPx = -(pageCount-1) * SCREEN_WIDTH_PX;
Joe Onoratod769a632009-08-11 17:09:02 -0700186 int done = 0;
187
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700188 // Clamp -- because java doesn't know how big the icons are
189 if (scrollXPx > 0) {
190 scrollXPx = 0;
191 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700192 if (scrollXPx < maxScrollXPx) {
193 scrollXPx = maxScrollXPx;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700194 }
195
Joe Onoratod769a632009-08-11 17:09:02 -0700196 // If we've been given a velocity, start a fling
197 float flingVelocityPxMs = loadI32(ALLOC_STATE, STATE_FLING_VELOCITY_X);
198 if (flingVelocityPxMs != 0) {
199 // how many screens will this velocity do? TODO: use long
200 // G * ppi * friction // why G? // friction = 0.015
201 float deceleration = loadF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700202 float flingDurationMs;
Joe Onoratod769a632009-08-11 17:09:02 -0700203 if (deceleration == 0) {
204 // On the first frame, calculate which animation we're going to do. If it's
205 // going to end up less than halfway into a page, we'll bounce back the previous
206 // page. Otherwise, we'll adjust the deceleration so it just makes it to the
207 // page boundary.
208 if (flingVelocityPxMs > 0) {
209 deceleration = -1000;
210 } else {
211 deceleration = 1000;
212 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400213 // minimum velocity
214 if (flingVelocityPxMs < 0) {
215 if (flingVelocityPxMs > -500) {
216 flingVelocityPxMs = -500;
217 }
218 } else {
219 if (flingVelocityPxMs < 500) {
220 flingVelocityPxMs = 500;
221 }
222 }
223
Joe Onoratod769a632009-08-11 17:09:02 -0700224 // v' = v + at --> t = -v / a
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700225 // x' = x + vt + .5 a t^2
226 flingDurationMs = - flingVelocityPxMs / deceleration;
227 float endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
228 + ((deceleration*flingDurationMs*flingDurationMs)/2);
Joe Onoratod769a632009-08-11 17:09:02 -0700229
230 if (endPos > 0) {
231 endPos = 0;
232 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700233 if (endPos < maxScrollXPx) {
234 endPos = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700235 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700236 float scrollOnPage = modf(endPos, SCREEN_WIDTH_PX);
237 int endPage = -endPos/SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400238
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700239 if (flingVelocityPxMs < 0) {
Joe Onoratoefabe002009-08-28 09:38:18 -0700240 if (scrollOnPage < (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700241 // adjust the deceleration so we align on the page boundary
242 // a = 2(x-x0-v0t)/t^2
Joe Onoratoefabe002009-08-28 09:38:18 -0700243 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400244 debugI32("endPos case 1", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700245 } else {
246 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700247 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400248 debugI32("endPos case 2", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700249 }
250 } else {
Joe Onoratoefabe002009-08-28 09:38:18 -0700251 if (scrollOnPage >= (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700252 // adjust the deceleration so we align on the page boundary
Joe Onoratoefabe002009-08-28 09:38:18 -0700253 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400254 debugI32("endPos case 3", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700255 } else {
256 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700257 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400258 debugI32("endPos case 4", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700259 }
260 }
261 // v = v0 + at --> (v - v0) / t
262 deceleration = 2*(endPos-scrollXPx-(flingVelocityPxMs*flingDurationMs))
263 / (flingDurationMs*flingDurationMs);
264 endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
265 + ((deceleration*flingDurationMs*flingDurationMs)/2);
266
267 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, deceleration);
268 storeF(ALLOC_STATE, STATE_FLING_DURATION, flingDurationMs);
269 storeF(ALLOC_STATE, STATE_FLING_END_POS, endPos);
270 } else {
271 flingDurationMs = loadF(ALLOC_STATE, STATE_FLING_DURATION);
Joe Onoratod769a632009-08-11 17:09:02 -0700272 }
273
274 // adjust the deceleration so we always hit a page boundary
275
276 int flingTime = loadI32(ALLOC_STATE, STATE_FLING_TIME);
277 int now = uptimeMillis();
278 float elapsedTime = (now - flingTime) / 1000.0f;
279 int animEndTime = -flingVelocityPxMs / deceleration;
280
Joe Onoratod769a632009-08-11 17:09:02 -0700281 int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
282 + (deceleration * elapsedTime * elapsedTime / 2.0f);
283 scrollXPx += flingOffsetPx;
284
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700285 if (elapsedTime > flingDurationMs) {
286 scrollXPx = loadF(ALLOC_STATE, STATE_FLING_END_POS);
287 done = 1;
288 }
Joe Onorato85a02a82009-09-08 12:34:22 -0700289 } else {
290 done = 1;
Joe Onoratod769a632009-08-11 17:09:02 -0700291 }
292
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700293 // Clamp
Joe Onoratod769a632009-08-11 17:09:02 -0700294 if (scrollXPx > 0) {
295 scrollXPx = 0;
296 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700297 if (scrollXPx < maxScrollXPx) {
298 scrollXPx = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700299 }
300
301 storeI32(ALLOC_STATE, STATE_CURRENT_SCROLL_X, scrollXPx);
302 if (done) {
303 storeI32(ALLOC_STATE, STATE_SCROLL_X, scrollXPx);
304 storeI32(ALLOC_STATE, STATE_FLING_VELOCITY_X, 0);
305 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, 0);
306 }
307
Joe Onoratoc567acb2009-08-31 14:34:43 -0700308 // Draw the icons ========================================
309 bindProgramVertex(NAMED_PV);
Joe Onoratoefabe002009-08-28 09:38:18 -0700310 bindProgramFragment(NAMED_PF);
311 bindProgramFragmentStore(NAMED_PFS);
312
313 // Bug makes 1.0f alpha fail.
314 color(1.0f, 1.0f, 1.0f, 0.99f);
315
316 int lastIcon = iconCount-1;
317
318 float currentPage = -scrollXPx / (float)SCREEN_WIDTH_PX;
319 int page = currentPage;
320 float currentPagePosition = currentPage - page;
Joe Onoratod769a632009-08-11 17:09:02 -0700321
Joe Onoratod769a632009-08-11 17:09:02 -0700322 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
Joe Onoratoefabe002009-08-28 09:38:18 -0700323 int icon = clamp(iconsPerPage * page, 0, lastIcon);
Joe Onorato93839052009-08-06 20:34:32 -0700324
Joe Onoratoefabe002009-08-28 09:38:18 -0700325 draw_page(icon, lastIcon, -VIEW_ANGLE*currentPagePosition);
326 draw_page(icon+iconsPerPage, lastIcon, (-VIEW_ANGLE*currentPagePosition)+VIEW_ANGLE);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700327
Joe Onorato6665c0f2009-09-02 15:27:24 -0700328 // Draw the border lines for debugging ========================================
Joe Onoratoc567acb2009-08-31 14:34:43 -0700329 /*
330 bindProgramVertex(NAMED_PVOrtho);
331 bindProgramFragment(NAMED_PFText);
332 bindProgramFragmentStore(NAMED_PFSText);
333
Joe Onorato6665c0f2009-09-02 15:27:24 -0700334 color(1.0f, 1.0f, 0.0f, 0.99f);
335 int i;
336 for (i=0; i<ROWS_PER_PAGE+1; i++) {
337 int y = loadI32(ALLOC_Y_BORDERS, i);
338 drawRect(0, y, SCREEN_WIDTH_PX, y+1, 0.0f);
339 }
340 for (i=0; i<COLUMNS_PER_PAGE+1; i++) {
341 int x = loadI32(ALLOC_X_BORDERS, i);
342 drawRect(x, 0, x+1, SCREEN_HEIGHT_PX, 0.0f);
343 }
344 */
345
346 // Draw the scroll handle ========================================
347 /*
Joe Onoratoc567acb2009-08-31 14:34:43 -0700348 bindTexture(NAMED_PFText, 0, loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_ID));
349 float handleLeft = 40 + (320 * (scrollXPx/(float)(maxScrollXPx)));
350 float handleTop = 680;
351 float handleWidth = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_WIDTH);
352 float handleHeight = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_HEIGHT);
353 drawRect(handleLeft, handleTop, handleLeft+handleWidth, handleTop+handleHeight, 0.0f);
354 */
Joe Onorato93839052009-08-06 20:34:32 -0700355
Joe Onoratofb0ca672009-09-14 17:55:46 -0400356 print_frame_rate();
357
Joe Onoratod769a632009-08-11 17:09:02 -0700358 return !done;
Joe Onorato93839052009-08-06 20:34:32 -0700359}
360