blob: 028d537f9d8c8b4b80de23b171a86eb7d7cc737c [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 Onorato6665c0f2009-09-02 15:27:24 -070036#define STATE_BORDERY0 11
Joe Onorato93839052009-08-06 20:34:32 -070037
Joe Onorato43e7bcf2009-08-08 18:53:53 -070038// Drawing constants, should be parameters ======
Joe Onoratoefabe002009-08-28 09:38:18 -070039#define VIEW_ANGLE 1.28700222f
Joe Onorato43e7bcf2009-08-08 18:53:53 -070040
41int
42count_pages(int iconCount)
Joe Onorato93839052009-08-06 20:34:32 -070043{
Joe Onorato43e7bcf2009-08-08 18:53:53 -070044 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
45 int pages = iconCount / iconsPerPage;
46 if (pages*iconsPerPage != iconCount) {
Joe Onoratod769a632009-08-11 17:09:02 -070047 pages++;
Joe Onorato43e7bcf2009-08-08 18:53:53 -070048 }
Joe Onoratod769a632009-08-11 17:09:02 -070049 return pages;
50}
51
Joe Onoratod769a632009-08-11 17:09:02 -070052float
53modf(float x, float y)
54{
55 return x-(y*floorf(x/y));
Joe Onorato93839052009-08-06 20:34:32 -070056}
57
Joe Onorato0d1c5632009-08-28 15:57:18 -070058float
59far_size(float sizeAt0)
60{
61 return sizeAt0 * (RADIUS+2) / 2; // -2 is the camera z=(z-camZ)/z
62}
63
Joe Onoratoefabe002009-08-28 09:38:18 -070064void
65draw_page(int icon, int lastIcon, float centerAngle)
66{
67 int row;
68 int col;
69
70 float iconTextureWidth = ICON_WIDTH_PX / (float)ICON_TEXTURE_WIDTH_PX;
71 float iconTextureHeight = ICON_HEIGHT_PX / (float)ICON_TEXTURE_HEIGHT_PX;
72
73 float iconWidthAngle = VIEW_ANGLE * ICON_WIDTH_PX / SCREEN_WIDTH_PX;
Joe Onorato0d1c5632009-08-28 15:57:18 -070074 float columnGutterAngle = iconWidthAngle * 0.70f;
Joe Onoratoefabe002009-08-28 09:38:18 -070075
Joe Onorato6665c0f2009-09-02 15:27:24 -070076 float farIconSize = FAR_ICON_SIZE;
Joe Onorato0d1c5632009-08-28 15:57:18 -070077 float iconGutterHeight = farIconSize * 1.1f;
78
Joe Onorato6665c0f2009-09-02 15:27:24 -070079 float farIconTextureSize = far_size(2 * ICON_TEXTURE_WIDTH_PX / (float)SCREEN_WIDTH_PX);
80
Joe Onorato0d1c5632009-08-28 15:57:18 -070081 float labelWidthPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_WIDTH);
82 float labelHeightPx = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_HEIGHT);
83
84 float normalizedLabelWidth = 2 * labelWidthPx / (float)SCREEN_WIDTH_PX;
85 float farLabelWidth = far_size(normalizedLabelWidth);
86 float farLabelHeight = far_size(labelHeightPx * (normalizedLabelWidth / labelWidthPx));
87 float labelTextureWidth = labelWidthPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_WIDTH);
88 float labelTextureHeight = labelHeightPx / loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_HEIGHT);
89
Joe Onorato6665c0f2009-09-02 15:27:24 -070090 int selectedIconIndex = loadI32(ALLOC_STATE, STATE_SELECTED_ICON_INDEX);
Joe Onoratoefabe002009-08-28 09:38:18 -070091
92 for (row=0; row<ROWS_PER_PAGE && icon<=lastIcon; row++) {
93 float angle = centerAngle;
94 angle -= (columnGutterAngle + iconWidthAngle) * 1.5f;
95
Joe Onorato6665c0f2009-09-02 15:27:24 -070096 float iconTop = (farIconSize + iconGutterHeight) * (2.0f + ICON_TOP_OFFSET)
Joe Onorato0d1c5632009-08-28 15:57:18 -070097 - row * (farIconSize + iconGutterHeight);
Joe Onoratoefabe002009-08-28 09:38:18 -070098 float iconBottom = iconTop - farIconSize;
99
Joe Onorato0d1c5632009-08-28 15:57:18 -0700100 float labelTop = iconBottom - (.1 * farLabelHeight);
101 float labelBottom = labelTop - farLabelHeight;
102
Joe Onorato6665c0f2009-09-02 15:27:24 -0700103 float iconTextureTop = iconTop + (0.5f * (farIconTextureSize - farIconSize));
104 float iconTextureBottom = iconTextureTop - farIconTextureSize;
105
Joe Onoratoefabe002009-08-28 09:38:18 -0700106 for (col=0; col<COLUMNS_PER_PAGE && icon<=lastIcon; col++) {
107 // icon
108 float sine = sinf(angle);
109 float cosine = cosf(angle);
110
Joe Onorato0d1c5632009-08-28 15:57:18 -0700111 float centerX = sine * RADIUS;
112 float centerZ = cosine * RADIUS;
113
Joe Onorato6665c0f2009-09-02 15:27:24 -0700114 float iconLeftX = centerX - (cosine * farIconTextureSize * .5);
115 float iconRightX = centerX + (cosine * farIconTextureSize * .5);
116 float iconLeftZ = centerZ + (sine * farIconTextureSize * .5);
117 float iconRightZ = centerZ - (sine * farIconTextureSize * .5);
118
119 if (selectedIconIndex == icon) {
120 bindTexture(NAMED_PF, 0, loadI32(ALLOC_STATE, STATE_SELECTED_ICON_TEXTURE));
121 drawQuadTexCoords(
122 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
123 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
124 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
125 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
126 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700127
128 bindTexture(NAMED_PF, 0, loadI32(ALLOC_ICON_IDS, icon));
129 drawQuadTexCoords(
Joe Onorato6665c0f2009-09-02 15:27:24 -0700130 iconLeftX, iconTextureTop, iconLeftZ, 0.0f, 0.0f,
131 iconRightX, iconTextureTop, iconRightZ, 1.0f, 0.0f,
132 iconRightX, iconTextureBottom, iconRightZ, 1.0f, 1.0f,
133 iconLeftX, iconTextureBottom, iconLeftZ, 0.0f, 1.0f);
Joe Onoratoefabe002009-08-28 09:38:18 -0700134
135 // label
Joe Onorato0d1c5632009-08-28 15:57:18 -0700136 float labelLeftX = centerX - farLabelWidth * 0.5f;
137 float labelRightX = centerX + farLabelWidth * 0.5f;
Joe Onoratoefabe002009-08-28 09:38:18 -0700138
Joe Onorato0d1c5632009-08-28 15:57:18 -0700139 bindTexture(NAMED_PF, 0, loadI32(ALLOC_LABEL_IDS, icon));
140 drawQuadTexCoords(
141 labelLeftX, labelTop, centerZ, 0.0f, 0.0f,
142 labelRightX, labelTop, centerZ, labelTextureWidth, 0.0f,
143 labelRightX, labelBottom, centerZ, labelTextureWidth, labelTextureHeight,
144 labelLeftX, labelBottom, centerZ, 0.0f, labelTextureHeight);
Joe Onoratoefabe002009-08-28 09:38:18 -0700145
Joe Onoratoefabe002009-08-28 09:38:18 -0700146 angle += columnGutterAngle + iconWidthAngle;
147 icon++;
148 }
149 }
150}
151
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700152int
Joe Onoratod769a632009-08-11 17:09:02 -0700153main(int launchID)
Joe Onorato93839052009-08-06 20:34:32 -0700154{
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700155 // Clear to transparent
Joe Onorato93839052009-08-06 20:34:32 -0700156 pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Joe Onorato93839052009-08-06 20:34:32 -0700157
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700158 // icons & labels
Joe Onorato1feb3a82009-08-08 22:32:00 -0700159 int iconCount = loadI32(ALLOC_STATE, STATE_ICON_COUNT);
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700160 int pageCount = count_pages(iconCount);
161
Joe Onoratod769a632009-08-11 17:09:02 -0700162 float scrollXPx = loadI32(ALLOC_STATE, STATE_SCROLL_X);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700163 float maxScrollXPx = -(pageCount-1) * SCREEN_WIDTH_PX;
Joe Onoratod769a632009-08-11 17:09:02 -0700164 int done = 0;
165
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700166 // Clamp -- because java doesn't know how big the icons are
167 if (scrollXPx > 0) {
168 scrollXPx = 0;
169 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700170 if (scrollXPx < maxScrollXPx) {
171 scrollXPx = maxScrollXPx;
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700172 }
173
Joe Onoratod769a632009-08-11 17:09:02 -0700174 // If we've been given a velocity, start a fling
175 float flingVelocityPxMs = loadI32(ALLOC_STATE, STATE_FLING_VELOCITY_X);
176 if (flingVelocityPxMs != 0) {
177 // how many screens will this velocity do? TODO: use long
178 // G * ppi * friction // why G? // friction = 0.015
179 float deceleration = loadF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700180 float flingDurationMs;
Joe Onoratod769a632009-08-11 17:09:02 -0700181 if (deceleration == 0) {
182 // On the first frame, calculate which animation we're going to do. If it's
183 // going to end up less than halfway into a page, we'll bounce back the previous
184 // page. Otherwise, we'll adjust the deceleration so it just makes it to the
185 // page boundary.
186 if (flingVelocityPxMs > 0) {
187 deceleration = -1000;
188 } else {
189 deceleration = 1000;
190 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400191 // minimum velocity
192 if (flingVelocityPxMs < 0) {
193 if (flingVelocityPxMs > -500) {
194 flingVelocityPxMs = -500;
195 }
196 } else {
197 if (flingVelocityPxMs < 500) {
198 flingVelocityPxMs = 500;
199 }
200 }
201
Joe Onoratod769a632009-08-11 17:09:02 -0700202 // v' = v + at --> t = -v / a
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700203 // x' = x + vt + .5 a t^2
204 flingDurationMs = - flingVelocityPxMs / deceleration;
205 float endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
206 + ((deceleration*flingDurationMs*flingDurationMs)/2);
Joe Onoratod769a632009-08-11 17:09:02 -0700207
208 if (endPos > 0) {
209 endPos = 0;
210 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700211 if (endPos < maxScrollXPx) {
212 endPos = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700213 }
Joe Onoratoefabe002009-08-28 09:38:18 -0700214 float scrollOnPage = modf(endPos, SCREEN_WIDTH_PX);
215 int endPage = -endPos/SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400216
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700217 if (flingVelocityPxMs < 0) {
Joe Onoratoefabe002009-08-28 09:38:18 -0700218 if (scrollOnPage < (SCREEN_WIDTH_PX/2)) {
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700219 // adjust the deceleration so we align on the page boundary
220 // a = 2(x-x0-v0t)/t^2
Joe Onoratoefabe002009-08-28 09:38:18 -0700221 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400222 debugI32("endPos case 1", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700223 } else {
224 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700225 endPos = -(endPage+1) * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400226 debugI32("endPos case 2", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700227 }
228 } else {
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
Joe Onoratoefabe002009-08-28 09:38:18 -0700231 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400232 debugI32("endPos case 3", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700233 } else {
234 // TODO: bounce
Joe Onoratoefabe002009-08-28 09:38:18 -0700235 endPos = -endPage * SCREEN_WIDTH_PX;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400236 debugI32("endPos case 4", endPos);
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700237 }
238 }
239 // v = v0 + at --> (v - v0) / t
240 deceleration = 2*(endPos-scrollXPx-(flingVelocityPxMs*flingDurationMs))
241 / (flingDurationMs*flingDurationMs);
242 endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
243 + ((deceleration*flingDurationMs*flingDurationMs)/2);
244
245 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, deceleration);
246 storeF(ALLOC_STATE, STATE_FLING_DURATION, flingDurationMs);
247 storeF(ALLOC_STATE, STATE_FLING_END_POS, endPos);
248 } else {
249 flingDurationMs = loadF(ALLOC_STATE, STATE_FLING_DURATION);
Joe Onoratod769a632009-08-11 17:09:02 -0700250 }
251
252 // adjust the deceleration so we always hit a page boundary
253
254 int flingTime = loadI32(ALLOC_STATE, STATE_FLING_TIME);
255 int now = uptimeMillis();
256 float elapsedTime = (now - flingTime) / 1000.0f;
257 int animEndTime = -flingVelocityPxMs / deceleration;
258
Joe Onoratod769a632009-08-11 17:09:02 -0700259 int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
260 + (deceleration * elapsedTime * elapsedTime / 2.0f);
261 scrollXPx += flingOffsetPx;
262
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700263 if (elapsedTime > flingDurationMs) {
264 scrollXPx = loadF(ALLOC_STATE, STATE_FLING_END_POS);
265 done = 1;
266 }
Joe Onoratod769a632009-08-11 17:09:02 -0700267 }
268
Joe Onoratoeb2c02e2009-08-12 21:40:52 -0700269 // Clamp
Joe Onoratod769a632009-08-11 17:09:02 -0700270 if (scrollXPx > 0) {
271 scrollXPx = 0;
272 }
Joe Onoratoc567acb2009-08-31 14:34:43 -0700273 if (scrollXPx < maxScrollXPx) {
274 scrollXPx = maxScrollXPx;
Joe Onoratod769a632009-08-11 17:09:02 -0700275 }
276
277 storeI32(ALLOC_STATE, STATE_CURRENT_SCROLL_X, scrollXPx);
278 if (done) {
279 storeI32(ALLOC_STATE, STATE_SCROLL_X, scrollXPx);
280 storeI32(ALLOC_STATE, STATE_FLING_VELOCITY_X, 0);
281 storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, 0);
282 }
283
Joe Onoratoc567acb2009-08-31 14:34:43 -0700284 // Draw the icons ========================================
285 bindProgramVertex(NAMED_PV);
Joe Onoratoefabe002009-08-28 09:38:18 -0700286 bindProgramFragment(NAMED_PF);
287 bindProgramFragmentStore(NAMED_PFS);
288
289 // Bug makes 1.0f alpha fail.
290 color(1.0f, 1.0f, 1.0f, 0.99f);
291
292 int lastIcon = iconCount-1;
293
294 float currentPage = -scrollXPx / (float)SCREEN_WIDTH_PX;
295 int page = currentPage;
296 float currentPagePosition = currentPage - page;
Joe Onoratod769a632009-08-11 17:09:02 -0700297
Joe Onoratod769a632009-08-11 17:09:02 -0700298 int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
Joe Onoratoefabe002009-08-28 09:38:18 -0700299 int icon = clamp(iconsPerPage * page, 0, lastIcon);
Joe Onorato93839052009-08-06 20:34:32 -0700300
Joe Onoratoefabe002009-08-28 09:38:18 -0700301 draw_page(icon, lastIcon, -VIEW_ANGLE*currentPagePosition);
302 draw_page(icon+iconsPerPage, lastIcon, (-VIEW_ANGLE*currentPagePosition)+VIEW_ANGLE);
Joe Onoratoc567acb2009-08-31 14:34:43 -0700303
Joe Onorato6665c0f2009-09-02 15:27:24 -0700304 // Draw the border lines for debugging ========================================
Joe Onoratoc567acb2009-08-31 14:34:43 -0700305 /*
306 bindProgramVertex(NAMED_PVOrtho);
307 bindProgramFragment(NAMED_PFText);
308 bindProgramFragmentStore(NAMED_PFSText);
309
Joe Onorato6665c0f2009-09-02 15:27:24 -0700310 color(1.0f, 1.0f, 0.0f, 0.99f);
311 int i;
312 for (i=0; i<ROWS_PER_PAGE+1; i++) {
313 int y = loadI32(ALLOC_Y_BORDERS, i);
314 drawRect(0, y, SCREEN_WIDTH_PX, y+1, 0.0f);
315 }
316 for (i=0; i<COLUMNS_PER_PAGE+1; i++) {
317 int x = loadI32(ALLOC_X_BORDERS, i);
318 drawRect(x, 0, x+1, SCREEN_HEIGHT_PX, 0.0f);
319 }
320 */
321
322 // Draw the scroll handle ========================================
323 /*
Joe Onoratoc567acb2009-08-31 14:34:43 -0700324 bindTexture(NAMED_PFText, 0, loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_ID));
325 float handleLeft = 40 + (320 * (scrollXPx/(float)(maxScrollXPx)));
326 float handleTop = 680;
327 float handleWidth = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_WIDTH);
328 float handleHeight = loadI32(ALLOC_PARAMS, PARAM_SCROLL_HANDLE_TEX_HEIGHT);
329 drawRect(handleLeft, handleTop, handleLeft+handleWidth, handleTop+handleHeight, 0.0f);
330 */
Joe Onorato93839052009-08-06 20:34:32 -0700331
Joe Onoratod769a632009-08-11 17:09:02 -0700332 return !done;
Joe Onorato93839052009-08-06 20:34:32 -0700333}
334