blob: e9c31b1ecc687c7990efef4586ac50001b4f1259 [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
42int
43count_pages(int iconCount)
Joe Onorato93839052009-08-06 20:34:32 -070044{
Joe Onorato43e7bcf2009-08-08 18:53:53 -070045 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
46 int pages = iconCount / iconsPerPage;
47 if (pages*iconsPerPage != iconCount) {
Joe Onoratod769a632009-08-11 17:09:02 -070048 pages++;
Joe Onorato43e7bcf2009-08-08 18:53:53 -070049 }
Joe Onoratod769a632009-08-11 17:09:02 -070050 return pages;
51}
52
Joe Onoratod769a632009-08-11 17:09:02 -070053float
54modf(float x, float y)
55{
56 return x-(y*floorf(x/y));
Joe Onorato93839052009-08-06 20:34:32 -070057}
58
Joe Onorato0d1c5632009-08-28 15:57:18 -070059float
60far_size(float sizeAt0)
61{
62 return sizeAt0 * (RADIUS+2) / 2; // -2 is the camera z=(z-camZ)/z
63}
64
Joe Onoratoefabe002009-08-28 09:38:18 -070065void
66draw_page(int icon, int lastIcon, float centerAngle)
67{
68 int row;
69 int col;
70
Joe Onorato85a02a82009-09-08 12:34:22 -070071 float scale = 1.0f - loadI32(ALLOC_STATE, STATE_ZOOM)/100000.0f;
72
Joe Onoratoefabe002009-08-28 09:38:18 -070073 float iconTextureWidth = ICON_WIDTH_PX / (float)ICON_TEXTURE_WIDTH_PX;
74 float iconTextureHeight = ICON_HEIGHT_PX / (float)ICON_TEXTURE_HEIGHT_PX;
75
76 float iconWidthAngle = VIEW_ANGLE * ICON_WIDTH_PX / SCREEN_WIDTH_PX;
Joe Onorato0d1c5632009-08-28 15:57:18 -070077 float columnGutterAngle = iconWidthAngle * 0.70f;
Joe Onoratoefabe002009-08-28 09:38:18 -070078
Joe Onorato6665c0f2009-09-02 15:27:24 -070079 float farIconSize = FAR_ICON_SIZE;
Joe Onorato0d1c5632009-08-28 15:57:18 -070080 float iconGutterHeight = farIconSize * 1.1f;
81
Joe Onorato6665c0f2009-09-02 15:27:24 -070082 float farIconTextureSize = far_size(2 * ICON_TEXTURE_WIDTH_PX / (float)SCREEN_WIDTH_PX);
83
Joe Onorato0d1c5632009-08-28 15:57:18 -070084 float labelWidthPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_WIDTH);
85 float labelHeightPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_HEIGHT);
86
87 float normalizedLabelWidth = 2 * labelWidthPx / (float)SCREEN_WIDTH_PX;
88 float farLabelWidth = far_size(normalizedLabelWidth);
89 float farLabelHeight = far_size(labelHeightPx * (normalizedLabelWidth / labelWidthPx));
90 float labelTextureWidth = labelWidthPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_WIDTH);
91 float labelTextureHeight = labelHeightPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_HEIGHT);
92
Joe Onorato6665c0f2009-09-02 15:27:24 -070093 int selectedIconIndex = loadI32(ALLOC_STATE, STATE_SELECTED_ICON_INDEX);
Joe Onoratoefabe002009-08-28 09:38:18 -070094
95 for (row=0; row<ROWS_PER_PAGE && icon<=lastIcon; row++) {
96 float angle = centerAngle;
97 angle -= (columnGutterAngle + iconWidthAngle) * 1.5f;
98
Joe Onorato6665c0f2009-09-02 15:27:24 -070099 float iconTop = (farIconSize + iconGutterHeight) * (2.0f + ICON_TOP_OFFSET)
Joe Onorato0d1c5632009-08-28 15:57:18 -0700100 - row * (farIconSize + iconGutterHeight);
Joe Onoratoefabe002009-08-28 09:38:18 -0700101 float iconBottom = iconTop - farIconSize;
102
Joe Onorato0d1c5632009-08-28 15:57:18 -0700103 float labelTop = iconBottom - (.1 * farLabelHeight);
104 float labelBottom = labelTop - farLabelHeight;
105
Joe Onorato6665c0f2009-09-02 15:27:24 -0700106 float iconTextureTop = iconTop + (0.5f * (farIconTextureSize - farIconSize));
107 float iconTextureBottom = iconTextureTop - farIconTextureSize;
108
Joe Onoratoefabe002009-08-28 09:38:18 -0700109 for (col=0; col<COLUMNS_PER_PAGE && icon<=lastIcon; col++) {
110 // icon
111 float sine = sinf(angle);
112 float cosine = cosf(angle);
113
Joe Onorato0d1c5632009-08-28 15:57:18 -0700114 float centerX = sine * RADIUS;
115 float centerZ = cosine * RADIUS;
Joe Onorato85a02a82009-09-08 12:34:22 -0700116 centerZ -= (7*scale);
Joe Onorato0d1c5632009-08-28 15:57:18 -0700117
Joe Onorato6665c0f2009-09-02 15:27:24 -0700118 float iconLeftX = centerX - (cosine * farIconTextureSize * .5);
119 float iconRightX = centerX + (cosine * farIconTextureSize * .5);
120 float iconLeftZ = centerZ + (sine * farIconTextureSize * .5);
121 float iconRightZ = centerZ - (sine * farIconTextureSize * .5);
122
123 if (selectedIconIndex == icon) {
124 bindTexture(NAMED_PF, 0, loadI32(ALLOC_STATE, STATE_SELECTED_ICON_TEXTURE));
125 drawQuadTexCoords(
126 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
127 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
128 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
129 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
130 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700131
132 bindTexture(NAMED_PF, 0, loadI32(ALLOC_ICON_IDS, icon));
133 drawQuadTexCoords(
Joe Onorato6665c0f2009-09-02 15:27:24 -0700134 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
135 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
136 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
137 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
Joe Onoratoefabe002009-08-28 09:38:18 -0700138
139 // label
Joe Onorato85a02a82009-09-08 12:34:22 -0700140 if (scale <= 1.04f) {
141 float labelLeftX = centerX - farLabelWidth * 0.5f;
142 float labelRightX = centerX + farLabelWidth * 0.5f;
Joe Onoratoefabe002009-08-28 09:38:18 -0700143
Joe Onorato85a02a82009-09-08 12:34:22 -0700144 bindTexture(NAMED_PF, 0, loadI32(ALLOC_LABEL_IDS, icon));
145 drawQuadTexCoords(
146 labelLeftX, labelTop, centerZ, 0.0f, 0.0f,
147 labelRightX, labelTop, centerZ, labelTextureWidth, 0.0f,
148 labelRightX, labelBottom, centerZ, labelTextureWidth, labelTextureHeight,
149 labelLeftX, labelBottom, centerZ, 0.0f, labelTextureHeight);
150 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700151
Joe Onoratoefabe002009-08-28 09:38:18 -0700152 angle += columnGutterAngle + iconWidthAngle;
153 icon++;
154 }
155 }
156}
157
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700158int
Joe Onoratod769a632009-08-11 17:09:02 -0700159main(int launchID)
Joe Onorato93839052009-08-06 20:34:32 -0700160{
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700161 // Clear to transparent
Joe Onorato93839052009-08-06 20:34:32 -0700162 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Joe Onorato93839052009-08-06 20:34:32 -0700163
Joe Onorato006b25f2009-09-03 11:38:43 -0700164 // If we're not supposed to be showing, don't do anything.
165 if (!loadI32(ALLOC_STATE, STATE_VISIBLE)) {
166 return 0;
167 }
168
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700169 // icons & labels
Joe Onorato1feb3a82009-08-08 22:32:00 -0700170 int iconCount = loadI32(ALLOC_STATE, STATE_ICON_COUNT);
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700171 int pageCount = count_pages(iconCount);
172
Joe Onoratod769a632009-08-11 17:09:02 -0700173 float scrollXPx = loadI32(ALLOC_STATE, STATE_SCROLL_X);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700174 float maxScrollXPx = -(pageCount-1) * SCREEN_WIDTH_PX;
Joe Onoratod769a632009-08-11 17:09:02 -0700175 int done = 0;
176
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700177 // Clamp -- because java doesn't know how big the icons are
178 if (scrollXPx > 0) {
179 scrollXPx = 0;
180 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700181 if (scrollXPx < maxScrollXPx) {
182 scrollXPx = maxScrollXPx;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700183 }
184
Joe Onoratod769a632009-08-11 17:09:02 -0700185 // If we've been given a velocity, start a fling
186 float flingVelocityPxMs = loadI32(ALLOC_STATE, STATE_FLING_VELOCITY_X);
187 if (flingVelocityPxMs != 0) {
188 // how many screens will this velocity do? TODO: use long
189 // G * ppi * friction // why G? // friction = 0.015
190 float deceleration = loadF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700191 float flingDurationMs;
Joe Onoratod769a632009-08-11 17:09:02 -0700192 if (deceleration == 0) {
193 // On the first frame, calculate which animation we're going to do. If it's
194 // going to end up less than halfway into a page, we'll bounce back the previous
195 // page. Otherwise, we'll adjust the deceleration so it just makes it to the
196 // page boundary.
197 if (flingVelocityPxMs > 0) {
198 deceleration = -1000;
199 } else {
200 deceleration = 1000;
201 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400202 // minimum velocity
203 if (flingVelocityPxMs < 0) {
204 if (flingVelocityPxMs > -500) {
205 flingVelocityPxMs = -500;
206 }
207 } else {
208 if (flingVelocityPxMs < 500) {
209 flingVelocityPxMs = 500;
210 }
211 }
212
Joe Onoratod769a632009-08-11 17:09:02 -0700213 // v' = v + at --> t = -v / a
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700214 // x' = x + vt + .5 a t^2
215 flingDurationMs = - flingVelocityPxMs / deceleration;
216 float endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
217 + ((deceleration*flingDurationMs*flingDurationMs)/2);
Joe Onoratod769a632009-08-11 17:09:02 -0700218
219 if (endPos > 0) {
220 endPos = 0;
221 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700222 if (endPos < maxScrollXPx) {
223 endPos = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700224 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700225 float scrollOnPage = modf(endPos, SCREEN_WIDTH_PX);
226 int endPage = -endPos/SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400227
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700228 if (flingVelocityPxMs < 0) {
Joe Onoratoefabe002009-08-28 09:38:18 -0700229 if (scrollOnPage < (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700230 // adjust the deceleration so we align on the page boundary
231 // a = 2(x-x0-v0t)/t^2
Joe Onoratoefabe002009-08-28 09:38:18 -0700232 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400233 debugI32("endPos case 1", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700234 } else {
235 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700236 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400237 debugI32("endPos case 2", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700238 }
239 } else {
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
Joe Onoratoefabe002009-08-28 09:38:18 -0700242 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400243 debugI32("endPos case 3", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700244 } else {
245 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700246 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400247 debugI32("endPos case 4", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700248 }
249 }
250 // v = v0 + at --> (v - v0) / t
251 deceleration = 2*(endPos-scrollXPx-(flingVelocityPxMs*flingDurationMs))
252 / (flingDurationMs*flingDurationMs);
253 endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
254 + ((deceleration*flingDurationMs*flingDurationMs)/2);
255
256 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, deceleration);
257 storeF(ALLOC_STATE, STATE_FLING_DURATION, flingDurationMs);
258 storeF(ALLOC_STATE, STATE_FLING_END_POS, endPos);
259 } else {
260 flingDurationMs = loadF(ALLOC_STATE, STATE_FLING_DURATION);
Joe Onoratod769a632009-08-11 17:09:02 -0700261 }
262
263 // adjust the deceleration so we always hit a page boundary
264
265 int flingTime = loadI32(ALLOC_STATE, STATE_FLING_TIME);
266 int now = uptimeMillis();
267 float elapsedTime = (now - flingTime) / 1000.0f;
268 int animEndTime = -flingVelocityPxMs / deceleration;
269
Joe Onoratod769a632009-08-11 17:09:02 -0700270 int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
271 + (deceleration * elapsedTime * elapsedTime / 2.0f);
272 scrollXPx += flingOffsetPx;
273
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700274 if (elapsedTime > flingDurationMs) {
275 scrollXPx = loadF(ALLOC_STATE, STATE_FLING_END_POS);
276 done = 1;
277 }
Joe Onorato85a02a82009-09-08 12:34:22 -0700278 } else {
279 done = 1;
Joe Onoratod769a632009-08-11 17:09:02 -0700280 }
281
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700282 // Clamp
Joe Onoratod769a632009-08-11 17:09:02 -0700283 if (scrollXPx > 0) {
284 scrollXPx = 0;
285 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700286 if (scrollXPx < maxScrollXPx) {
287 scrollXPx = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700288 }
289
290 storeI32(ALLOC_STATE, STATE_CURRENT_SCROLL_X, scrollXPx);
291 if (done) {
292 storeI32(ALLOC_STATE, STATE_SCROLL_X, scrollXPx);
293 storeI32(ALLOC_STATE, STATE_FLING_VELOCITY_X, 0);
294 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, 0);
295 }
296
Joe Onoratoc567acb2009-08-31 14:34:43 -0700297 // Draw the icons ========================================
298 bindProgramVertex(NAMED_PV);
Joe Onoratoefabe002009-08-28 09:38:18 -0700299 bindProgramFragment(NAMED_PF);
300 bindProgramFragmentStore(NAMED_PFS);
301
302 // Bug makes 1.0f alpha fail.
303 color(1.0f, 1.0f, 1.0f, 0.99f);
304
305 int lastIcon = iconCount-1;
306
307 float currentPage = -scrollXPx / (float)SCREEN_WIDTH_PX;
308 int page = currentPage;
309 float currentPagePosition = currentPage - page;
Joe Onoratod769a632009-08-11 17:09:02 -0700310
Joe Onoratod769a632009-08-11 17:09:02 -0700311 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
Joe Onoratoefabe002009-08-28 09:38:18 -0700312 int icon = clamp(iconsPerPage * page, 0, lastIcon);
Joe Onorato93839052009-08-06 20:34:32 -0700313
Joe Onoratoefabe002009-08-28 09:38:18 -0700314 draw_page(icon, lastIcon, -VIEW_ANGLE*currentPagePosition);
315 draw_page(icon+iconsPerPage, lastIcon, (-VIEW_ANGLE*currentPagePosition)+VIEW_ANGLE);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700316
Joe Onorato6665c0f2009-09-02 15:27:24 -0700317 // Draw the border lines for debugging ========================================
Joe Onoratoc567acb2009-08-31 14:34:43 -0700318 /*
319 bindProgramVertex(NAMED_PVOrtho);
320 bindProgramFragment(NAMED_PFText);
321 bindProgramFragmentStore(NAMED_PFSText);
322
Joe Onorato6665c0f2009-09-02 15:27:24 -0700323 color(1.0f, 1.0f, 0.0f, 0.99f);
324 int i;
325 for (i=0; i<ROWS_PER_PAGE+1; i++) {
326 int y = loadI32(ALLOC_Y_BORDERS, i);
327 drawRect(0, y, SCREEN_WIDTH_PX, y+1, 0.0f);
328 }
329 for (i=0; i<COLUMNS_PER_PAGE+1; i++) {
330 int x = loadI32(ALLOC_X_BORDERS, i);
331 drawRect(x, 0, x+1, SCREEN_HEIGHT_PX, 0.0f);
332 }
333 */
334
335 // Draw the scroll handle ========================================
336 /*
Joe Onoratoc567acb2009-08-31 14:34:43 -0700337 bindTexture(NAMED_PFText, 0, loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_ID));
338 float handleLeft = 40 + (320 * (scrollXPx/(float)(maxScrollXPx)));
339 float handleTop = 680;
340 float handleWidth = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_WIDTH);
341 float handleHeight = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_HEIGHT);
342 drawRect(handleLeft, handleTop, handleLeft+handleWidth, handleTop+handleHeight, 0.0f);
343 */
Joe Onorato93839052009-08-06 20:34:32 -0700344
Joe Onoratod769a632009-08-11 17:09:02 -0700345 return !done;
Joe Onorato93839052009-08-06 20:34:32 -0700346}
347