OSDN Git Service

Initial commit of 3D gallery source code to project.
[android-x86/packages-apps-Gallery2.git] / src / com / cooliris / media / GridCamera.java
1 package com.cooliris.media;
2
3 import android.os.Bundle;
4
5 public final class GridCamera {
6     public static final float MAX_CAMERA_SPEED = 12.0f;
7     public static final float EYE_CONVERGENCE_SPEED = 3.0f;
8     public static final float EYE_X = 0;
9     public static final float EYE_Y = 0;
10     public static final float EYE_Z = 8.0f; // Initial z distance.
11     private static final float DEFAULT_PORTRAIT_ASPECT = 320.0f / 480.0f;
12     private static final float DEFAULT_LANDSCAPE_ASPECT = 1.0f / DEFAULT_PORTRAIT_ASPECT;
13     
14     public float mEyeX;
15     public float mEyeY;
16     public float mEyeZ;
17     public float mLookAtX;
18     public float mLookAtY;
19     public float mLookAtZ;
20     public float mUpX;
21     public float mUpY;
22     public float mUpZ;
23     
24     // To tilt the wall.
25     public float mEyeOffsetX;
26     public float mEyeOffsetY;
27     private float mEyeEdgeOffsetX;
28     private float mEyeEdgeOffsetXAnim;
29     private float mAmountExceeding;
30
31
32     // Animation speed, 1.0f is normal speed.
33     public float mConvergenceSpeed;
34     
35     // Camera field of view and its relation to the grid item width.
36     public float mFov;
37     public float mScale;
38     public float mOneByScale;
39     public int mWidth;
40     public int mHeight;
41     public int mItemHeight;
42     public int mItemWidth;
43     public float mAspectRatio;
44     public float mDefaultAspectRatio;
45
46     // Camera positional information.
47     private float mPosX;
48     private float mPosY;
49     private float mPosZ;
50     private float mTargetPosX;
51     private float mTargetPosY;
52     private float mTargetPosZ;
53     private float mEyeOffsetAnimX;
54     private float mEyeOffsetAnimY;
55     private float mTargetEyeX;
56     
57     // Screen width and height.
58     private int mWidthBy2;
59     private int mHeightBy2;
60     private float mTanFovBy2;
61     
62     public GridCamera(int width, int height, int itemWidth, int itemHeight) {
63         reset();
64         viewportChanged(width, height, itemWidth, itemHeight);
65         mConvergenceSpeed = 1.0f;
66     }
67
68     public void onRestoreInstanceState(Bundle savedInstanceState) {
69         mEyeX = savedInstanceState.getInt(new String("Camera.mEyeX")) + EYE_X;
70         mTargetPosX = savedInstanceState.getFloat(new String("Camera.mTargetPosX"));
71         mTargetPosY = savedInstanceState.getFloat(new String("Camera.mTargetPosY"));
72         mTargetPosZ = savedInstanceState.getFloat(new String("Camera.mTargetPosZ"));
73         commitMove();
74     }
75
76     public void onSaveInstanceState(Bundle outState) {
77         outState.putFloat(new String("Camera.mEyeX"), mEyeX - EYE_X);
78         outState.putFloat(new String("Camera.mTargetPosX"), mTargetPosX);
79         outState.putFloat(new String("Camera.mTargetPosY"), mTargetPosY);
80         outState.putFloat(new String("Camera.mTargetPosZ"), mTargetPosZ);
81     }
82
83     public void reset() {
84         mTargetEyeX = 0;
85         mEyeX = EYE_X;
86         mEyeY = EYE_Y;
87         mEyeZ = EYE_Z;
88         mLookAtX = EYE_X;
89         mLookAtY = EYE_Y;
90         mLookAtZ = 0;
91         mUpX = 0;
92         mUpY = 1.0f;
93         mUpZ = 0;
94         mPosX = 0;
95         mPosY = 0;
96         mPosZ = 0;
97         mTargetPosX = 0;
98         mTargetPosY = 0;
99         mTargetPosZ = 0;
100     }
101
102     public void viewportChanged(int w, int h, float itemWidth, float itemHeight) {
103         // For pixel precision we need to use this formula.
104         /* fov = 2tan-1(qFactor/2*defaultZ) where qFactor = height/ItemHeight */
105         float qFactor = h / (float) itemHeight;
106         float fov = 2.0f * (float) Math.toDegrees(Math.atan2(qFactor / 2, GridCamera.EYE_Z));
107         mWidth = w;
108         mHeight = h;
109         mWidthBy2 = w >> 1;
110         mHeightBy2 = h >> 1;
111         mAspectRatio = (h == 0) ? 1.0f : (float)w / (float)h;
112         mDefaultAspectRatio = (w > h) ? DEFAULT_LANDSCAPE_ASPECT : DEFAULT_PORTRAIT_ASPECT;
113         mTanFovBy2 = (float) Math.tan(Math.toRadians(fov * 0.5f));
114         mItemHeight = (int) itemHeight;
115         mItemWidth = (int) itemWidth;
116         mScale = itemHeight;
117         mOneByScale = 1.0f / (float) itemHeight;
118         mFov = fov;
119     }
120
121     public void convertToScreenSpace(int posX, int posY, int posZ, Vector3f retVal) {
122         // TODO
123     }
124
125     public void convertToCameraSpace(float posX, float posY, float posZ, Vector3f retVal) {
126         float posXx = posX - mWidthBy2;
127         float posYx = posY - mHeightBy2;
128         convertToRelativeCameraSpace(posXx, posYx, posZ, retVal);
129         retVal.x += (EYE_X + mTargetPosX);
130         retVal.y += (mTargetPosY);
131     }
132
133     public void convertToRelativeCameraSpace(float posX, float posY, float posZ, Vector3f retVal) {
134         float posXx = posX;
135         float posYx = posY;
136         posXx = posXx / mWidth;
137         posYx = posYx / mHeight;
138         float posZx = posZ;
139         float zDiscriminant = (mTanFovBy2 * (mTargetPosZ + EYE_Z + posZx));
140         zDiscriminant *= 2.0f;
141         float yRange = zDiscriminant;
142         float xRange = zDiscriminant * mAspectRatio;
143         posXx = ((posXx * xRange));
144         posYx = ((posYx * yRange));
145         retVal.x = posXx;
146         retVal.y = posYx;
147     }
148
149     public float getDistanceToFitRect(float f, float g) {
150         final float thisAspectRatio = (float) f / (float) g;
151         float h = g;
152         if (thisAspectRatio > mAspectRatio) {
153             // The width will hit the screen.
154             h = (f * mHeight) / mWidth;
155         }
156         // To fit ITEM_HEIGHT pixels perfectly, the targetZ value must be the 1.0f for the given fov
157         // Thus to fit h pixels,
158         h = h / mItemHeight;
159         float targetZ = h / mTanFovBy2;
160         targetZ = targetZ * 0.5f;
161         return -(EYE_Z - targetZ);
162     }
163
164     public void moveXTo(float posX) {
165         mTargetPosX = posX;
166     }
167
168     public void moveYTo(float posY) {
169         mTargetPosY = posY;
170     }
171
172     public void moveZTo(float posZ) {
173         mTargetPosZ = posZ;
174     }
175
176     public void moveTo(float posX, float posY, float posZ) {
177         float delta = posX - mTargetPosX;
178         float maxDelta = mWidth * 2.0f * mOneByScale;
179         delta = FloatUtils.clamp(delta, -maxDelta, maxDelta);
180         mTargetPosX += delta;
181         mTargetPosY = posY;
182         mTargetPosZ = posZ;
183     }
184
185     public void moveBy(float posX, float posY, float posZ) {
186         moveTo(posX + mTargetPosX, posY + mTargetPosY, posZ + mTargetPosZ);
187     }
188
189     public void commitMove() {
190         mPosX = mTargetPosX;
191         mPosY = mTargetPosY;
192         mPosZ = mTargetPosZ;
193     }
194     
195     public void commitMoveInX() {
196         mPosX = mTargetPosX;
197     }
198
199     public void commitMoveInY() {
200         mPosY = mTargetPosY;
201     }
202
203     public void commitMoveInZ() {
204         mPosZ = mTargetPosZ;
205     }
206     
207     public boolean computeConstraints(boolean applyConstraints, boolean applyOverflowFeedback, Vector3f firstSlotPosition,
208             Vector3f lastSlotPosition) {
209         boolean retVal = false;
210         float minX = (firstSlotPosition.x) * (1.0f / mItemHeight);
211         float maxX = (lastSlotPosition.x) * (1.0f / mItemHeight);
212         if (mTargetPosX < minX) {
213             mAmountExceeding += mTargetPosX - minX;
214             mTargetPosX = minX;
215             mPosX = minX;
216             if (applyConstraints) {
217                 mTargetPosX = minX;
218             }
219             retVal = true;
220         }
221         if (mTargetPosX > maxX) {
222             mAmountExceeding += mTargetPosX - maxX;
223             mTargetPosX = maxX;
224             mPosX = maxX;
225             if (applyConstraints) {
226                 mTargetPosX = maxX;
227             }
228             retVal = true;
229         }
230         if (!retVal) {
231             float scrollingFromEdgeX = 0.0f;
232             if (mAmountExceeding < 0.0f) {
233                 scrollingFromEdgeX = mTargetPosX - minX;
234             } else {
235                 scrollingFromEdgeX = maxX - mTargetPosX;
236             }
237             if (scrollingFromEdgeX > 0.1f) {
238                 mAmountExceeding = 0.0f;
239             }
240         }
241         if (applyConstraints) {
242             mEyeEdgeOffsetX = 0.0f;
243             // We look at amount exceeding and calculate target position in the reverse direction.
244             final float maxBounceBack = 0.8f;
245             if (mAmountExceeding < -maxBounceBack)
246                 mAmountExceeding = -maxBounceBack;
247             if (mAmountExceeding > maxBounceBack)
248                 mAmountExceeding = maxBounceBack;
249             mTargetPosX -= mAmountExceeding * 0.8f;
250             if (mTargetPosX > maxX)
251                 mTargetPosX = maxX;
252             if (mTargetPosX < minX)
253                 mTargetPosX = minX;
254             mAmountExceeding = 0.0f;
255         } else {
256             float amountExceedingToUse = mAmountExceeding;
257             final float maxThreshold = 0.6f;
258             if (amountExceedingToUse > maxThreshold)
259                 amountExceedingToUse = maxThreshold;
260             if (amountExceedingToUse < -maxThreshold)
261                 amountExceedingToUse = -maxThreshold;
262             if (applyOverflowFeedback)
263                 mEyeEdgeOffsetX = -10.0f * amountExceedingToUse;
264             else
265                 mEyeEdgeOffsetX = 0.0f;
266         }
267         return retVal;
268     }
269
270     public void stopMovement() {
271         mTargetPosX = mPosX;
272         mTargetPosY = mPosY;
273         mTargetPosZ = mPosZ;
274     }
275
276     public void stopMovementInX() {
277         mTargetPosX = mPosX;
278     }
279
280     public void stopMovementInY() {
281         mTargetPosY = mPosY;
282     }
283
284     public void stopMovementInZ() {
285         mTargetPosZ = mPosZ;
286     }
287
288     public boolean isAnimating() {
289         return (mPosX != mTargetPosX || mPosY != mTargetPosY || mPosZ != mTargetPosZ || mEyeOffsetAnimX != mEyeOffsetX || mEyeEdgeOffsetXAnim != mEyeEdgeOffsetX);
290     }
291     
292     public boolean isZAnimating() {
293         return mPosZ != mTargetPosZ;
294     }
295
296     public void update(float timeElapsed) {
297         float factor = mConvergenceSpeed;
298         timeElapsed = (timeElapsed * factor);
299         mPosX = FloatUtils.animate(mPosX, mTargetPosX, timeElapsed);
300         mPosY = FloatUtils.animate(mPosY, mTargetPosY, timeElapsed);
301         mPosZ = FloatUtils.animate(mPosZ, mTargetPosZ, timeElapsed);
302         if (mEyeZ != EYE_Z) {
303             mEyeOffsetX = 0;
304             mEyeOffsetY = 0;
305         }
306         mEyeOffsetAnimX = FloatUtils.animate(mEyeOffsetAnimX, mEyeOffsetX, timeElapsed);
307         mEyeOffsetAnimY = FloatUtils.animate(mEyeOffsetAnimY, mEyeOffsetY, timeElapsed);
308         mEyeEdgeOffsetXAnim = FloatUtils.animate(mEyeEdgeOffsetXAnim, mEyeEdgeOffsetX, timeElapsed);
309         mTargetEyeX = EYE_X + mPosX;
310         if (mEyeZ == EYE_Z) {
311             mEyeX = mTargetEyeX;
312             // Enable the line below for achieving tilt while you scroll the wall.
313             // FloatUtils.animate(eyeX_, targetEyeX_, timeElapsedx - (timeElapsedx * 0.35f));
314         } else {
315             mEyeX = mTargetEyeX;
316         }
317         mEyeX += (mEyeOffsetAnimX + mEyeEdgeOffsetXAnim);
318         mLookAtX = EYE_X + mPosX;
319         mEyeY = EYE_Y + mPosY;
320         mLookAtY = EYE_Y + mPosY;
321         mEyeZ = EYE_Z + mPosZ;
322         mLookAtZ = mPosZ;
323     }
324 }
325