summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Sams <rjsams@android.com>2009-09-18 13:55:55 -0700
committerJason Sams <rjsams@android.com>2009-09-18 13:55:55 -0700
commit86c87ed0a8cbc87a09db7ca08117410f72c0b8b9 (patch)
treeab7d8e814b2c4b4cb50f50bd8452c224bc79aae6
parente82140fe200513ea820f0f95463c6230868ded9d (diff)
downloadpackages_apps_trebuchet-86c87ed0a8cbc87a09db7ca08117410f72c0b8b9.zip
packages_apps_trebuchet-86c87ed0a8cbc87a09db7ca08117410f72c0b8b9.tar.gz
packages_apps_trebuchet-86c87ed0a8cbc87a09db7ca08117410f72c0b8b9.tar.bz2
Implement new physics model for scroll.
-rw-r--r--res/raw/rollo.c289
-rw-r--r--src/com/android/launcher2/AllAppsView.java56
2 files changed, 197 insertions, 148 deletions
diff --git a/res/raw/rollo.c b/res/raw/rollo.c
index 5ff3308..98e5738 100644
--- a/res/raw/rollo.c
+++ b/res/raw/rollo.c
@@ -5,13 +5,82 @@
#define PI 3.14159f
-float deceleration;
+
+// Attraction to center values from page edge to page center.
+float g_AttractionTable[9];
+float g_FrictionTable[9];
+float g_PhysicsTableSize;
+
+float g_PosPage;
+float g_PosVelocity;
+float g_LastPositionX;
+int g_LastTouchDown;
+float g_DT;
+int g_LastTime;
+int g_Rendering;
+int g_PageCount;
// Drawing constants, should be parameters ======
#define VIEW_ANGLE 1.28700222f
void init() {
- deceleration = 0;
+ g_AttractionTable[0] = 4.5f;
+ g_AttractionTable[1] = 4.5f;
+ g_AttractionTable[2] = 5.0f;
+ g_AttractionTable[3] = 4.0f;
+ g_AttractionTable[4] = -4.0f;
+ g_AttractionTable[5] = -5.0f;
+ g_AttractionTable[6] = -4.5f;
+ g_AttractionTable[7] = -4.5f;
+ g_AttractionTable[8] = -4.5f; // dup 7 to avoid a clamp later
+ g_FrictionTable[0] = 3.5f;
+ g_FrictionTable[1] = 3.6f;
+ g_FrictionTable[2] = 3.7f;
+ g_FrictionTable[3] = 3.8f;
+ g_FrictionTable[4] = 3.8f;
+ g_FrictionTable[5] = 3.7f;
+ g_FrictionTable[6] = 3.6f;
+ g_FrictionTable[7] = 3.5f;
+ g_FrictionTable[8] = 3.5f; // dup 7 to avoid a clamp later
+ g_PhysicsTableSize = 7;
+
+ g_PosVelocity = 0;
+ g_PosPage = 0;
+ g_LastTouchDown = 0;
+ g_LastPositionX = 0;
+}
+
+void clampPosition() {
+ if (g_PosPage < 0) {
+ g_PosPage = 0;
+ g_PosVelocity = 0;
+ }
+ if (g_PosPage > (g_PageCount - 1)) {
+ g_PosPage = (g_PageCount - 1);
+ g_PosVelocity = 0;
+ }
+}
+
+void move() {
+ if (g_LastTouchDown) {
+ float dx = -(state->newPositionX - g_LastPositionX);
+ g_PosVelocity = 0;
+ g_PosPage += dx;
+ }
+ g_LastTouchDown = state->newTouchDown;
+ g_LastPositionX = state->newPositionX;
+ clampPosition();
+}
+
+void fling() {
+ g_LastTouchDown = 0;
+ g_PosVelocity = -state->flingVelocityX;
+ if (g_PosPage <= 0) {
+ g_PosVelocity = maxf(0, g_PosVelocity);
+ }
+ if (g_PosPage > (g_PageCount - 1)) {
+ g_PosVelocity = minf(0, (g_PageCount - 1) - g_PosPage);
+ }
}
int g_lastFrameTime = 0;
@@ -41,6 +110,76 @@ modf(float x, float y)
return x-(y*floorf(x/y));
}
+void updatePos() {
+ if (g_LastTouchDown) {
+ return;
+ }
+
+ //debugF("g_PosPage", g_PosPage);
+ //debugF(" g_PosVelocity", g_PosVelocity);
+
+ float tablePosNorm = fracf(g_PosPage + 0.5f);
+ float tablePosF = tablePosNorm * g_PhysicsTableSize;
+ int tablePosI = tablePosF;
+ float tablePosFrac = tablePosF - tablePosI;
+ //debugF("tablePosNorm", tablePosNorm);
+ //debugF("tablePosF", tablePosF);
+ //debugF("tablePosI", tablePosI);
+ //debugF("tablePosFrac", tablePosFrac);
+
+ float accel = lerpf(g_AttractionTable[tablePosI],
+ g_AttractionTable[tablePosI + 1],
+ tablePosFrac) * g_DT;
+ float friction = lerpf(g_FrictionTable[tablePosI],
+ g_FrictionTable[tablePosI + 1],
+ tablePosFrac) * g_DT;
+ //debugF(" accel", accel);
+ //debugF(" friction", friction);
+
+ g_PosVelocity += accel;
+ if ((friction > fabsf(g_PosVelocity)) && (friction > fabsf(accel))) {
+ // Special get back to center and overcome friction physics.
+ float t = tablePosNorm - 0.5f;
+ if (fabsf(t) < (friction * g_DT)) {
+ // really close, just snap
+ g_PosPage = roundf(g_PosPage);
+ g_PosVelocity = 0;
+ } else {
+ if (t > 0) {
+ g_PosVelocity = -friction;
+ } else {
+ g_PosVelocity = friction;
+ }
+ }
+ } else {
+ // Normal physics
+ if (g_PosVelocity > 0) {
+ g_PosVelocity -= friction;
+ if (g_PosVelocity < 0) {
+ g_PosVelocity = 0;
+ }
+ } else {
+ g_PosVelocity += friction;
+ if (g_PosVelocity > 0) {
+ g_PosVelocity = 0;
+ }
+ }
+ }
+ g_PosPage += g_PosVelocity * g_DT;
+
+ // Check for out of boundry conditions.
+ if (g_PosPage < 0 && g_PosVelocity < 0) {
+ float damp = 1.0 + (g_PosPage * 3);
+ damp = clampf(damp, 0.f, 0.9f);
+ g_PosVelocity *= damp;
+ }
+ if (g_PosPage > (g_PageCount-1) && g_PosVelocity > 0) {
+ float damp = 1.0 - ((g_PosPage - g_PageCount + 1) * 3);
+ damp = clampf(damp, 0.f, 0.9f);
+ g_PosVelocity *= damp;
+ }
+}
+
float
far_size(float sizeAt0)
{
@@ -53,6 +192,7 @@ draw_page(int icon, int lastIcon, float centerAngle)
int row;
int col;
+ //debugF("center angle", centerAngle);
float scale = 1.0f - state->zoom;
float iconTextureWidth = ICON_WIDTH_PX / (float)ICON_TEXTURE_WIDTH_PX;
@@ -142,6 +282,11 @@ main(int launchID)
// Clear to transparent
pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ int newTime = uptimeMillis();
+ g_DT = (newTime - g_LastTime) / 1000.f;
+ g_LastTime = newTime;
+ //debugF("*** dt ", g_DT);
+
// If we're not supposed to be showing, don't do anything.
if (!state->visible) {
return 0;
@@ -149,128 +294,13 @@ main(int launchID)
// icons & labels
int iconCount = state->iconCount;
- int pageCount = count_pages(iconCount);
-
- float scrollXPx = state->scrollX;
- float maxScrollXPx = -(pageCount-1) * SCREEN_WIDTH_PX;
- int done = 0;
+ g_PageCount = count_pages(iconCount);
- // Clamp -- because java doesn't know how big the icons are
- if (scrollXPx > 0) {
- scrollXPx = 0;
- }
- if (scrollXPx < maxScrollXPx) {
- scrollXPx = maxScrollXPx;
- }
+ updatePos(0.1f);
+ state->readPosX = g_PosPage;
+ state->readVel = g_PosVelocity;
- // If we've been given a velocity, start a fling
- float flingVelocityPxMs = state->flingVelocityX;
- if (flingVelocityPxMs != 0) {
- // how many screens will this velocity do? TODO: use long
- // G * ppi * friction // why G? // friction = 0.015
- float flingDurationMs;
- if (deceleration == 0) {
- // On the first frame, calculate which animation we're going to do. If it's
- // going to end up less than halfway into a page, we'll bounce back the previous
- // page. Otherwise, we'll adjust the deceleration so it just makes it to the
- // page boundary.
- if (flingVelocityPxMs > 0) {
- deceleration = -1000;
- } else {
- deceleration = 1000;
- }
- // minimum velocity
- if (flingVelocityPxMs < 0) {
- if (flingVelocityPxMs > -500) {
- flingVelocityPxMs = -500;
- }
- } else {
- if (flingVelocityPxMs < 500) {
- flingVelocityPxMs = 500;
- }
- }
-
- // v' = v + at --> t = -v / a
- // x' = x + vt + .5 a t^2
- flingDurationMs = - flingVelocityPxMs / deceleration;
- float endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
- + ((deceleration*flingDurationMs*flingDurationMs)/2);
-
- if (endPos > 0) {
- endPos = 0;
- }
- if (endPos < maxScrollXPx) {
- endPos = maxScrollXPx;
- }
- float scrollOnPage = modf(endPos, SCREEN_WIDTH_PX);
- int endPage = -endPos/SCREEN_WIDTH_PX;
-
- if (flingVelocityPxMs < 0) {
- if (scrollOnPage < (SCREEN_WIDTH_PX/2)) {
- // adjust the deceleration so we align on the page boundary
- // a = 2(x-x0-v0t)/t^2
- endPos = -(endPage+1) * SCREEN_WIDTH_PX;
- debugI32("endPos case 1", endPos);
- } else {
- // TODO: bounce
- endPos = -(endPage+1) * SCREEN_WIDTH_PX;
- debugI32("endPos case 2", endPos);
- }
- } else {
- if (scrollOnPage >= (SCREEN_WIDTH_PX/2)) {
- // adjust the deceleration so we align on the page boundary
- endPos = -endPage * SCREEN_WIDTH_PX;
- debugI32("endPos case 3", endPos);
- } else {
- // TODO: bounce
- endPos = -endPage * SCREEN_WIDTH_PX;
- debugI32("endPos case 4", endPos);
- }
- }
- // v = v0 + at --> (v - v0) / t
- deceleration = 2*(endPos-scrollXPx-(flingVelocityPxMs*flingDurationMs))
- / (flingDurationMs*flingDurationMs);
- endPos = scrollXPx + (flingVelocityPxMs*flingDurationMs)
- + ((deceleration*flingDurationMs*flingDurationMs)/2);
-
- state->flingDuration = flingDurationMs;
- state->flingEndPos = endPos;
- } else {
- flingDurationMs = state->flingDuration;
- }
-
- // adjust the deceleration so we always hit a page boundary
-
- int now = uptimeMillis();
- float elapsedTime = (now - state->flingTimeMs) / 1000.0f;
- int animEndTime = -flingVelocityPxMs / deceleration;
-
- int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
- + (deceleration * elapsedTime * elapsedTime / 2.0f);
- scrollXPx += flingOffsetPx;
-
- if (elapsedTime > flingDurationMs) {
- scrollXPx = state->flingEndPos;
- done = 1;
- }
- } else {
- done = 1;
- }
-
- // Clamp
- if (scrollXPx > 0) {
- scrollXPx = 0;
- }
- if (scrollXPx < maxScrollXPx) {
- scrollXPx = maxScrollXPx;
- }
-
- state->currentScrollX = scrollXPx;
- if (done) {
- state->scrollX = scrollXPx;
- state->flingVelocityX = 0;
- deceleration = 0.f;
- }
+ //debugF(" draw g_PosPage", g_PosPage);
// Draw the icons ========================================
bindProgramVertex(NAMED_PV);
@@ -282,9 +312,8 @@ main(int launchID)
int lastIcon = iconCount-1;
- float currentPage = -scrollXPx / (float)SCREEN_WIDTH_PX;
- int page = currentPage;
- float currentPagePosition = currentPage - page;
+ int page = g_PosPage;
+ float currentPagePosition = g_PosPage - page;
int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
int icon = clamp(iconsPerPage * page, 0, lastIcon);
@@ -292,6 +321,7 @@ main(int launchID)
draw_page(icon, lastIcon, -VIEW_ANGLE*currentPagePosition);
draw_page(icon+iconsPerPage, lastIcon, (-VIEW_ANGLE*currentPagePosition)+VIEW_ANGLE);
+
// Draw the border lines for debugging ========================================
/*
bindProgramVertex(NAMED_PVOrtho);
@@ -320,8 +350,13 @@ main(int launchID)
drawRect(handleLeft, handleTop, handleLeft+handleWidth, handleTop+handleHeight, 0.0f);
*/
- print_frame_rate();
+ //print_frame_rate();
- return !done;
+ // Bug workaround where the last frame is not always displayed
+ // So we render the last frame twice.
+ int rendering = g_Rendering;
+ g_Rendering = (g_PosVelocity != 0) || fracf(g_PosPage);
+ rendering |= g_Rendering;
+ return rendering;
}
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 95f36d6..03734c0 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -85,11 +85,11 @@ public class AllAppsView extends RSSurfaceView
private int mPageCount;
private boolean mStartedScrolling;
private VelocityTracker mVelocity;
- private int mLastScrollX;
private int mLastMotionX;
private int mMotionDownRawX;
private int mMotionDownRawY;
private int mScrollHandleTop;
+ private long mTouchTime;
static class Defines {
private static float farSize(float sizeAt0) {
@@ -191,16 +191,17 @@ public class AllAppsView extends RSSurfaceView
mMotionDownRawY = (int)ev.getRawY();
mLastMotionX = x;
mRollo.mState.read();
- mRollo.mState.startScrollX = mRollo.mState.scrollX = mLastScrollX
- = mRollo.mState.currentScrollX;
- if (mRollo.mState.flingVelocityX != 0) {
+
+ mRollo.mState.newPositionX = ev.getRawX() / Defines.SCREEN_WIDTH_PX;
+ mRollo.mState.newTouchDown = 1;
+
+ if (mRollo.mState.readVel != 0) {
mRollo.clearSelectedIcon();
} else {
- mRollo.selectIcon(x, (int)ev.getY(), mRollo.mState.startScrollX,
- (-mRollo.mState.startScrollX / Defines.SCREEN_WIDTH_PX));
+ mRollo.selectIcon(x, (int)ev.getY(), mRollo.mState.readPosX);
}
- mRollo.mState.flingVelocityX = 0;
mRollo.mState.save();
+ mRollo.mInvokeMove.execute();
mVelocity = VelocityTracker.obtain();
mVelocity.addMovement(ev);
mStartedScrolling = false;
@@ -212,25 +213,31 @@ public class AllAppsView extends RSSurfaceView
// don't update mLastMotionX so slop is right and when we do start scrolling
// below, we get the right delta.
} else {
+
+ mRollo.mState.newPositionX = ev.getRawX() / Defines.SCREEN_WIDTH_PX;
+ mRollo.mState.newTouchDown = 1;
+ mRollo.mInvokeMove.execute();
+
mStartedScrolling = true;
mRollo.clearSelectedIcon();
deltaX = x - mLastMotionX;
mVelocity.addMovement(ev);
- mRollo.mState.currentScrollX = mLastScrollX;
- mLastScrollX += deltaX;
- mRollo.mState.scrollX = mLastScrollX;
mRollo.mState.save();
mLastMotionX = x;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+
+ mRollo.mState.newPositionX = ev.getRawX() / Defines.SCREEN_WIDTH_PX;
+ mRollo.mState.newTouchDown = 0;
+
mVelocity.computeCurrentVelocity(1000 /* px/sec */,
mConfig.getScaledMaximumFlingVelocity());
- mRollo.mState.flingTimeMs = (int)SystemClock.uptimeMillis(); // TODO: use long
- mRollo.mState.flingVelocityX = (int)mVelocity.getXVelocity();
+ mRollo.mState.flingVelocityX = mVelocity.getXVelocity() / Defines.SCREEN_WIDTH_PX;
mRollo.clearSelectedIcon();
mRollo.mState.save();
+ mRollo.mInvokeFling.execute();
mLastMotionX = -10000;
mVelocity.recycle();
mVelocity = null;
@@ -354,6 +361,10 @@ public class AllAppsView extends RSSurfaceView
private Resources mRes;
private Script mScript;
+
+ private Script.Invokable mInvokeMove;
+ private Script.Invokable mInvokeFling;
+
private Sampler mSampler;
private Sampler mSamplerText;
private ProgramStore mPSBackground;
@@ -417,14 +428,13 @@ public class AllAppsView extends RSSurfaceView
}
class State extends BaseAlloc {
+ public float newPositionX;
+ public int newTouchDown;
+ public float readPosX;
+ public float readVel;
+ public float flingVelocityX;
public int iconCount;
public int scrollX;
- public int flingTimeMs;
- public float flingVelocityX;
- public int currentScrollX;
- public int flingDuration;
- public int flingEndPos;
- public int startScrollX;
public int selectedIconIndex = -1;
public int selectedIconTexture;
public int visible;
@@ -564,6 +574,8 @@ public class AllAppsView extends RSSurfaceView
sb.addDefines(Defines.class);
sb.setType(mParams.mType, "params", Defines.ALLOC_PARAMS);
sb.setType(mState.mType, "state", Defines.ALLOC_STATE);
+ mInvokeMove = sb.addInvokable("move");
+ mInvokeFling = sb.addInvokable("fling");
mScript = sb.create();
mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -653,7 +665,9 @@ public class AllAppsView extends RSSurfaceView
mAllocTouchXBorders.data(mTouchXBorders);
}
- int chooseTappedIcon(int x, int y, int scrollX, int currentPage) {
+ int chooseTappedIcon(int x, int y, float page) {
+ int currentPage = (int)page;
+
int col = -1;
int row = -1;
@@ -681,8 +695,8 @@ public class AllAppsView extends RSSurfaceView
/**
* You need to call save() on mState on your own after calling this.
*/
- void selectIcon(int x, int y, int scrollX, int currentPage) {
- int index = chooseTappedIcon(x, y, scrollX, currentPage);
+ void selectIcon(int x, int y, float pos) {
+ int index = chooseTappedIcon(x, y, pos);
selectIcon(index);
}