blob: f6097cf12602a3af730bcafabca890b0e79035f4 [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 Onoratoc567acb2009-08-31 14:34:43 -070032#define SCROLL_HANDLE_POS 8
33
Joe Onorato43e7bcf2009-08-08 18:53:53 -070034// Scratch variables ======
Joe Onoratod769a632009-08-11 17:09:02 -070035#define SCRATCH_ADJUSTED_DECELERATION 0
Joe Onorato93839052009-08-06 20:34:32 -070036
Joe Onorato43e7bcf2009-08-08 18:53:53 -070037// Drawing constants, should be parameters ======
Joe Onoratoefabe002009-08-28 09:38:18 -070038#define SCREEN_WIDTH_PX 480
Joe Onorato43e7bcf2009-08-08 18:53:53 -070039#define SCREEN_HEIGHT 854
Joe Onorato43e7bcf2009-08-08 18:53:53 -070040
41#define PAGE_PADDING_TOP_PX 80
42#define CELL_PADDING_TOP_PX 5
43#define ICON_HEIGHT_PX 64
Joe Onorato9c1289c2009-08-17 11:03:03 -040044#define ICON_TEXTURE_HEIGHT_PX 128
Joe Onorato43e7bcf2009-08-08 18:53:53 -070045#define ICON_LABEL_GUTTER_PX 5
46#define CELL_PADDING_BOTTOM_PX 5
47#define ROW_GUTTER_PX 10
48
49#define PAGE_PADDING_LEFT_PX 22
50#define CELL_WIDTH_PX 105
51#define ICON_WIDTH_PX 64
Joe Onorato9c1289c2009-08-17 11:03:03 -040052#define ICON_TEXTURE_WIDTH_PX 128
Joe Onoratoefabe002009-08-28 09:38:18 -070053
54#define VIEW_ANGLE 1.28700222f
55#define RADIUS 4.0f
Joe Onorato43e7bcf2009-08-08 18:53:53 -070056
57int
58count_pages(int iconCount)
Joe Onorato93839052009-08-06 20:34:32 -070059{
Joe Onorato43e7bcf2009-08-08 18:53:53 -070060 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
61 int pages = iconCount / iconsPerPage;
62 if (pages*iconsPerPage != iconCount) {
Joe Onoratod769a632009-08-11 17:09:02 -070063 pages++;
Joe Onorato43e7bcf2009-08-08 18:53:53 -070064 }
Joe Onoratod769a632009-08-11 17:09:02 -070065 return pages;
66}
67
Joe Onoratod769a632009-08-11 17:09:02 -070068float
69modf(float x, float y)
70{
71 return x-(y*floorf(x/y));
Joe Onorato93839052009-08-06 20:34:32 -070072}
73
Joe Onorato0d1c5632009-08-28 15:57:18 -070074float
75far_size(float sizeAt0)
76{
77 return sizeAt0 * (RADIUS+2) / 2; // -2 is the camera z=(z-camZ)/z
78}
79
Joe Onoratoefabe002009-08-28 09:38:18 -070080void
81draw_page(int icon, int lastIcon, float centerAngle)
82{
83 int row;
84 int col;
85
86 float iconTextureWidth = ICON_WIDTH_PX / (float)ICON_TEXTURE_WIDTH_PX;
87 float iconTextureHeight = ICON_HEIGHT_PX / (float)ICON_TEXTURE_HEIGHT_PX;
88
89 float iconWidthAngle = VIEW_ANGLE * ICON_WIDTH_PX / SCREEN_WIDTH_PX;
Joe Onorato0d1c5632009-08-28 15:57:18 -070090 float columnGutterAngle = iconWidthAngle * 0.70f;
Joe Onoratoefabe002009-08-28 09:38:18 -070091
Joe Onorato0d1c5632009-08-28 15:57:18 -070092 float farIconSize = far_size(2 * ICON_WIDTH_PX / (float)SCREEN_WIDTH_PX);
93 float iconGutterHeight = farIconSize * 1.1f;
94
95 float labelWidthPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_WIDTH);
96 float labelHeightPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_HEIGHT);
97
98 float normalizedLabelWidth = 2 * labelWidthPx / (float)SCREEN_WIDTH_PX;
99 float farLabelWidth = far_size(normalizedLabelWidth);
100 float farLabelHeight = far_size(labelHeightPx * (normalizedLabelWidth / labelWidthPx));
101 float labelTextureWidth = labelWidthPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_WIDTH);
102 float labelTextureHeight = labelHeightPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_HEIGHT);
103
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 Onorato0d1c5632009-08-28 15:57:18 -0700109 float iconTop = (farIconSize + iconGutterHeight) * 2.2f
110 - row * (farIconSize + iconGutterHeight);
Joe Onoratoefabe002009-08-28 09:38:18 -0700111 float iconBottom = iconTop - farIconSize;
112
Joe Onorato0d1c5632009-08-28 15:57:18 -0700113 float labelTop = iconBottom - (.1 * farLabelHeight);
114 float labelBottom = labelTop - farLabelHeight;
115
Joe Onoratoefabe002009-08-28 09:38:18 -0700116 for (col=0; col<COLUMNS_PER_PAGE && icon<=lastIcon; col++) {
117 // icon
118 float sine = sinf(angle);
119 float cosine = cosf(angle);
120
Joe Onorato0d1c5632009-08-28 15:57:18 -0700121 float centerX = sine * RADIUS;
122 float centerZ = cosine * RADIUS;
123
124 float iconLeftX = centerX - (cosine * farIconSize * .5);
125 float iconRightX = centerX + (cosine * farIconSize * .5);
126 float iconLeftZ = centerZ + (sine * farIconSize * .5);
127 float iconRightZ = centerZ - (sine * farIconSize * .5);
Joe Onoratoefabe002009-08-28 09:38:18 -0700128
129 bindTexture(NAMED_PF, 0, loadI32(ALLOC_ICON_IDS, icon));
130 drawQuadTexCoords(
131 iconLeftX, iconTop, iconLeftZ, 0.0f, 0.0f,
132 iconRightX, iconTop, iconRightZ, iconTextureWidth, 0.0f,
133 iconRightX, iconBottom, iconRightZ, iconTextureWidth, iconTextureHeight,
134 iconLeftX, iconBottom, iconLeftZ, 0.0f, iconTextureHeight);
135
136 // label
Joe Onorato0d1c5632009-08-28 15:57:18 -0700137 float labelLeftX = centerX - farLabelWidth * 0.5f;
138 float labelRightX = centerX + farLabelWidth * 0.5f;
Joe Onoratoefabe002009-08-28 09:38:18 -0700139
Joe Onorato0d1c5632009-08-28 15:57:18 -0700140 bindTexture(NAMED_PF, 0, loadI32(ALLOC_LABEL_IDS, icon));
141 drawQuadTexCoords(
142 labelLeftX, labelTop, centerZ, 0.0f, 0.0f,
143 labelRightX, labelTop, centerZ, labelTextureWidth, 0.0f,
144 labelRightX, labelBottom, centerZ, labelTextureWidth, labelTextureHeight,
145 labelLeftX, labelBottom, centerZ, 0.0f, labelTextureHeight);
Joe Onoratoefabe002009-08-28 09:38:18 -0700146
Joe Onoratoefabe002009-08-28 09:38:18 -0700147 angle += columnGutterAngle + iconWidthAngle;
148 icon++;
149 }
150 }
151}
152
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700153int
Joe Onoratod769a632009-08-11 17:09:02 -0700154main(int launchID)
Joe Onorato93839052009-08-06 20:34:32 -0700155{
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700156 // Clear to transparent
Joe Onorato93839052009-08-06 20:34:32 -0700157 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Joe Onorato93839052009-08-06 20:34:32 -0700158
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700159 // icons & labels
Joe Onorato1feb3a82009-08-08 22:32:00 -0700160 int iconCount = loadI32(ALLOC_STATE, STATE_ICON_COUNT);
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700161 int pageCount = count_pages(iconCount);
162
Joe Onoratoefabe002009-08-28 09:38:18 -0700163 float densityScale = 2.0f / SCREEN_WIDTH_PX;
164 float screenTop = SCREEN_HEIGHT/(float)SCREEN_WIDTH_PX; // == (SCREEN_HEIGHT/2)*densityScale;
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700165
166 float pagePaddingTop = screenTop - (PAGE_PADDING_TOP_PX * densityScale);
167 float pageGutterY = ROW_GUTTER_PX * densityScale;
168 float cellHeight = (CELL_PADDING_TOP_PX + ICON_HEIGHT_PX + ICON_LABEL_GUTTER_PX
169 + loadI32(ALLOC_PARAMS, PARAM_BUBBLE_HEIGHT)
170 + CELL_PADDING_BOTTOM_PX + ROW_GUTTER_PX) * densityScale;
171 float cellPaddingTop = CELL_PADDING_TOP_PX * densityScale;
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700172 float iconLabelGutter = ICON_LABEL_GUTTER_PX * densityScale;
173
Joe Onoratod769a632009-08-11 17:09:02 -0700174 float scrollXPx = loadI32(ALLOC_STATE, STATE_SCROLL_X);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700175 float maxScrollXPx = -(pageCount-1) * SCREEN_WIDTH_PX;
Joe Onoratod769a632009-08-11 17:09:02 -0700176 int done = 0;
177
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700178 // Clamp -- because java doesn't know how big the icons are
179 if (scrollXPx > 0) {
180 scrollXPx = 0;
181 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700182 if (scrollXPx < maxScrollXPx) {
183 scrollXPx = maxScrollXPx;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700184 }
185
Joe Onoratod769a632009-08-11 17:09:02 -0700186 // If we've been given a velocity, start a fling
187 float flingVelocityPxMs = loadI32(ALLOC_STATE, STATE_FLING_VELOCITY_X);
188 if (flingVelocityPxMs != 0) {
189 // how many screens will this velocity do? TODO: use long
190 // G * ppi * friction // why G? // friction = 0.015
191 float deceleration = loadF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700192 float flingDurationMs;
Joe Onoratod769a632009-08-11 17:09:02 -0700193 if (deceleration == 0) {
194 // On the first frame, calculate which animation we're going to do. If it's
195 // going to end up less than halfway into a page, we'll bounce back the previous
196 // page. Otherwise, we'll adjust the deceleration so it just makes it to the
197 // page boundary.
198 if (flingVelocityPxMs > 0) {
199 deceleration = -1000;
200 } else {
201 deceleration = 1000;
202 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400203 // minimum velocity
204 if (flingVelocityPxMs < 0) {
205 if (flingVelocityPxMs > -500) {
206 flingVelocityPxMs = -500;
207 }
208 } else {
209 if (flingVelocityPxMs < 500) {
210 flingVelocityPxMs = 500;
211 }
212 }
213
Joe Onoratod769a632009-08-11 17:09:02 -0700214 // v' = v + at --> t = -v / a
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700215 // x' = x + vt + .5 a t^2
216 flingDurationMs = - flingVelocityPxMs / deceleration;
217 float endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
218 + ((deceleration*flingDurationMs*flingDurationMs)/2);
Joe Onoratod769a632009-08-11 17:09:02 -0700219
220 if (endPos > 0) {
221 endPos = 0;
222 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700223 if (endPos < maxScrollXPx) {
224 endPos = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700225 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700226 float scrollOnPage = modf(endPos, SCREEN_WIDTH_PX);
227 int endPage = -endPos/SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400228
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700229 if (flingVelocityPxMs < 0) {
Joe Onoratoefabe002009-08-28 09:38:18 -0700230 if (scrollOnPage < (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700231 // adjust the deceleration so we align on the page boundary
232 // a = 2(x-x0-v0t)/t^2
Joe Onoratoefabe002009-08-28 09:38:18 -0700233 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400234 debugI32("endPos case 1", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700235 } else {
236 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700237 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400238 debugI32("endPos case 2", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700239 }
240 } else {
Joe Onoratoefabe002009-08-28 09:38:18 -0700241 if (scrollOnPage >= (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700242 // adjust the deceleration so we align on the page boundary
Joe Onoratoefabe002009-08-28 09:38:18 -0700243 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400244 debugI32("endPos case 3", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700245 } else {
246 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700247 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400248 debugI32("endPos case 4", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700249 }
250 }
251 // v = v0 + at --> (v - v0) / t
252 deceleration = 2*(endPos-scrollXPx-(flingVelocityPxMs*flingDurationMs))
253 / (flingDurationMs*flingDurationMs);
254 endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
255 + ((deceleration*flingDurationMs*flingDurationMs)/2);
256
257 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, deceleration);
258 storeF(ALLOC_STATE, STATE_FLING_DURATION, flingDurationMs);
259 storeF(ALLOC_STATE, STATE_FLING_END_POS, endPos);
260 } else {
261 flingDurationMs = loadF(ALLOC_STATE, STATE_FLING_DURATION);
Joe Onoratod769a632009-08-11 17:09:02 -0700262 }
263
264 // adjust the deceleration so we always hit a page boundary
265
266 int flingTime = loadI32(ALLOC_STATE, STATE_FLING_TIME);
267 int now = uptimeMillis();
268 float elapsedTime = (now - flingTime) / 1000.0f;
269 int animEndTime = -flingVelocityPxMs / deceleration;
270
Joe Onoratod769a632009-08-11 17:09:02 -0700271 int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
272 + (deceleration * elapsedTime * elapsedTime / 2.0f);
273 scrollXPx += flingOffsetPx;
274
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700275 if (elapsedTime > flingDurationMs) {
276 scrollXPx = loadF(ALLOC_STATE, STATE_FLING_END_POS);
277 done = 1;
278 }
Joe Onoratod769a632009-08-11 17:09:02 -0700279 }
280
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700281 // Clamp
Joe Onoratod769a632009-08-11 17:09:02 -0700282 if (scrollXPx > 0) {
283 scrollXPx = 0;
284 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700285 if (scrollXPx < maxScrollXPx) {
286 scrollXPx = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700287 }
288
289 storeI32(ALLOC_STATE, STATE_CURRENT_SCROLL_X, scrollXPx);
290 if (done) {
291 storeI32(ALLOC_STATE, STATE_SCROLL_X, scrollXPx);
292 storeI32(ALLOC_STATE, STATE_FLING_VELOCITY_X, 0);
293 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, 0);
294 }
295
Joe Onoratoc567acb2009-08-31 14:34:43 -0700296 // Draw the icons ========================================
297 bindProgramVertex(NAMED_PV);
Joe Onoratoefabe002009-08-28 09:38:18 -0700298 bindProgramFragment(NAMED_PF);
299 bindProgramFragmentStore(NAMED_PFS);
300
301 // Bug makes 1.0f alpha fail.
302 color(1.0f, 1.0f, 1.0f, 0.99f);
303
304 int lastIcon = iconCount-1;
305
306 float currentPage = -scrollXPx / (float)SCREEN_WIDTH_PX;
307 int page = currentPage;
308 float currentPagePosition = currentPage - page;
Joe Onoratod769a632009-08-11 17:09:02 -0700309
Joe Onoratod769a632009-08-11 17:09:02 -0700310 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
Joe Onoratoefabe002009-08-28 09:38:18 -0700311 int icon = clamp(iconsPerPage * page, 0, lastIcon);
Joe Onorato93839052009-08-06 20:34:32 -0700312
Joe Onoratoefabe002009-08-28 09:38:18 -0700313 draw_page(icon, lastIcon, -VIEW_ANGLE*currentPagePosition);
314 draw_page(icon+iconsPerPage, lastIcon, (-VIEW_ANGLE*currentPagePosition)+VIEW_ANGLE);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700315
316 // Draw the scroll handle ========================================
317 /*
318 bindProgramVertex(NAMED_PVOrtho);
319 bindProgramFragment(NAMED_PFText);
320 bindProgramFragmentStore(NAMED_PFSText);
321
322 bindTexture(NAMED_PFText, 0, loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_ID));
323 float handleLeft = 40 + (320 * (scrollXPx/(float)(maxScrollXPx)));
324 float handleTop = 680;
325 float handleWidth = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_WIDTH);
326 float handleHeight = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_HEIGHT);
327 drawRect(handleLeft, handleTop, handleLeft+handleWidth, handleTop+handleHeight, 0.0f);
328 */
Joe Onorato93839052009-08-06 20:34:32 -0700329
Joe Onoratod769a632009-08-11 17:09:02 -0700330 return !done;
Joe Onorato93839052009-08-06 20:34:32 -0700331}
332