Revision beb325a0
Added by Leszek Koltunski over 4 years ago
src/main/java/org/distorted/magic/RubikSurfaceView.java | ||
---|---|---|
22 | 22 |
import android.app.ActivityManager; |
23 | 23 |
import android.content.Context; |
24 | 24 |
import android.content.pm.ConfigurationInfo; |
25 |
import android.graphics.PorterDuff; |
|
26 |
import android.graphics.drawable.Drawable; |
|
25 | 27 |
import android.opengl.GLSurfaceView; |
28 |
import android.support.v4.content.ContextCompat; |
|
26 | 29 |
import android.util.AttributeSet; |
30 |
import android.util.DisplayMetrics; |
|
27 | 31 |
import android.view.MotionEvent; |
32 |
import android.view.ViewGroup; |
|
33 |
import android.widget.Button; |
|
34 |
import android.widget.ImageButton; |
|
35 |
import android.widget.LinearLayout; |
|
28 | 36 |
|
29 | 37 |
import org.distorted.library.type.Static4D; |
38 |
import org.distorted.object.RubikCubeMovement; |
|
30 | 39 |
|
31 | 40 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
32 | 41 |
|
33 |
class RubikSurfaceView extends GLSurfaceView |
|
42 |
public class RubikSurfaceView extends GLSurfaceView
|
|
34 | 43 |
{ |
35 |
// Moving the finger from the middle of the vertical screen to the right edge will rotate a |
|
36 |
// given face by SWIPING_SENSITIVITY/2 degrees. |
|
37 |
private final static int SWIPING_SENSITIVITY = 240; |
|
38 |
|
|
39 | 44 |
// Moving the finger by 1/12 the distance of min(scrWidth,scrHeight) will start a Rotation. |
40 | 45 |
private final static int ROTATION_SENSITIVITY = 12; |
41 | 46 |
|
42 | 47 |
// Every 1/12 the distance of min(scrWidth,scrHeight) the direction of cube rotation will reset. |
43 | 48 |
private final static int DIRECTION_SENSITIVITY= 12; |
44 | 49 |
|
45 |
private final static int NONE =-1; |
|
46 |
private final static int FRONT = 0; // has to be 6 consecutive ints |
|
47 |
private final static int BACK = 1; // FRONT ... BOTTOM |
|
48 |
private final static int LEFT = 2; // |
|
49 |
private final static int RIGHT = 3; // |
|
50 |
private final static int TOP = 4; // |
|
51 |
private final static int BOTTOM = 5; // |
|
50 |
private RubikRenderer mRenderer; |
|
51 |
private RubikCubeMovement mMovement; |
|
52 | 52 |
|
53 |
private static final int[] VECT = {RubikCube.VECTX,RubikCube.VECTY,RubikCube.VECTZ}; |
|
53 |
private boolean mInScrambleMode; |
|
54 |
private int mButton = RubikSize.SIZE3.ordinal(); |
|
54 | 55 |
|
55 | 56 |
private boolean mDragging, mBeginningRotation, mContinuingRotation; |
56 | 57 |
private int mX, mY; |
57 |
private int mRotationVect; |
|
58 |
private RubikRenderer mRenderer; |
|
59 |
|
|
60 |
private float[] mPoint, mCamera, mTouchPointCastOntoFace, mDiff, mTouchPoint; // all in screen space |
|
61 | 58 |
private int mLastTouchedFace; |
62 |
private int mScreenWidth, mScreenHeight, mScreenMin; |
|
63 | 59 |
private float mCameraDistance; |
60 |
private int mScreenWidth, mScreenHeight, mScreenMin; |
|
64 | 61 |
|
65 | 62 |
private static Static4D mQuatCurrent = new Static4D(0,0,0,1); |
66 | 63 |
private static Static4D mQuatAccumulated= new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f); |
... | ... | |
70 | 67 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
71 | 68 |
// return quat1*quat2 |
72 | 69 |
|
73 |
static Static4D quatMultiply( Static4D quat1, Static4D quat2 ) |
|
70 |
public static Static4D quatMultiply( Static4D quat1, Static4D quat2 )
|
|
74 | 71 |
{ |
75 | 72 |
float qx = quat1.get1(); |
76 | 73 |
float qy = quat1.get2(); |
... | ... | |
91 | 88 |
} |
92 | 89 |
|
93 | 90 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
94 |
// rotate 'vector' by quat^(-1) ( i.e. return (quat^-1)*vector*quat )
|
|
91 |
// rotate 'vector' by quat ( i.e. return quat*vector*(quat^-1) )
|
|
95 | 92 |
|
96 |
static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat)
|
|
93 |
public static Static4D rotateVectorByQuat(Static4D vector, Static4D quat)
|
|
97 | 94 |
{ |
98 | 95 |
float qx = quat.get1(); |
99 | 96 |
float qy = quat.get2(); |
... | ... | |
101 | 98 |
float qw = quat.get4(); |
102 | 99 |
|
103 | 100 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
104 |
Static4D tmp = quatMultiply(quatInverted,vector);
|
|
101 |
Static4D tmp = quatMultiply(quat,vector); |
|
105 | 102 |
|
106 |
return quatMultiply(tmp,quat); |
|
103 |
return quatMultiply(tmp,quatInverted);
|
|
107 | 104 |
} |
108 | 105 |
|
109 | 106 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
110 |
// rotate 'vector' by quat ( i.e. return quat*vector*(quat^-1) )
|
|
107 |
// rotate 'vector' by quat^(-1) ( i.e. return (quat^-1)*vector*quat )
|
|
111 | 108 |
|
112 |
static Static4D rotateVectorByQuat(Static4D vector, Static4D quat)
|
|
109 |
public static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat)
|
|
113 | 110 |
{ |
114 | 111 |
float qx = quat.get1(); |
115 | 112 |
float qy = quat.get2(); |
... | ... | |
117 | 114 |
float qw = quat.get4(); |
118 | 115 |
|
119 | 116 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
120 |
Static4D tmp = quatMultiply(quat,vector); |
|
121 |
|
|
122 |
return quatMultiply(tmp,quatInverted); |
|
123 |
} |
|
124 |
|
|
125 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
126 |
|
|
127 |
private int faceTouched(int xTouch, int yTouch) |
|
128 |
{ |
|
129 |
float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f; |
|
130 |
|
|
131 |
convertTouchPointToScreenSpace(xTouch,yTouch); |
|
132 |
convertCameraPointToScreenSpace(); |
|
133 |
|
|
134 |
for(int face=FRONT; face<=BOTTOM; face++) |
|
135 |
{ |
|
136 |
if( faceIsVisible(face,cubeHalfSize) ) |
|
137 |
{ |
|
138 |
castTouchPointOntoFace(face,cubeHalfSize, mTouchPointCastOntoFace); |
|
139 |
|
|
140 |
float qX= (mTouchPointCastOntoFace[0]+cubeHalfSize) / (2*cubeHalfSize); |
|
141 |
float qY= (mTouchPointCastOntoFace[1]+cubeHalfSize) / (2*cubeHalfSize); |
|
142 |
float qZ= (mTouchPointCastOntoFace[2]+cubeHalfSize) / (2*cubeHalfSize); |
|
143 |
|
|
144 |
if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return face; |
|
145 |
} |
|
146 |
} |
|
117 |
Static4D tmp = quatMultiply(quatInverted,vector); |
|
147 | 118 |
|
148 |
return NONE;
|
|
119 |
return quatMultiply(tmp,quat);
|
|
149 | 120 |
} |
150 | 121 |
|
151 | 122 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
152 | 123 |
|
153 |
private void addNewRotation(int x, int y)
|
|
124 |
void setScreenSize(int width, int height)
|
|
154 | 125 |
{ |
155 |
float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f; |
|
156 |
|
|
157 |
convertTouchPointToScreenSpace(x,y); |
|
158 |
castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize,mDiff); |
|
159 |
|
|
160 |
mDiff[0] -= mTouchPointCastOntoFace[0]; |
|
161 |
mDiff[1] -= mTouchPointCastOntoFace[1]; |
|
162 |
mDiff[2] -= mTouchPointCastOntoFace[2]; |
|
163 |
|
|
164 |
int xAxis = retFaceXaxis(mLastTouchedFace); |
|
165 |
int yAxis = retFaceYaxis(mLastTouchedFace); |
|
166 |
mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? VECT[xAxis]:VECT[yAxis]); |
|
167 |
float offset= (mTouchPointCastOntoFace[mRotationVect]+cubeHalfSize)/(2*cubeHalfSize); |
|
168 |
|
|
169 |
mTouchPoint[0] = mPoint[0]; |
|
170 |
mTouchPoint[1] = mPoint[1]; |
|
171 |
mTouchPoint[2] = mPoint[2]; |
|
126 |
mScreenWidth = width; |
|
127 |
mScreenHeight= height; |
|
172 | 128 |
|
173 |
RubikCube cube = mRenderer.getCube(); |
|
174 |
cube.addNewRotation(mRotationVect, (int)(cube.getSize()*offset) ); |
|
129 |
mScreenMin = width<height ? width:height; |
|
175 | 130 |
} |
176 | 131 |
|
177 | 132 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
178 | 133 |
|
179 |
private boolean isVertical(float x, float y)
|
|
134 |
void setCameraDist(float distance)
|
|
180 | 135 |
{ |
181 |
return (y>x) ? (y>=-x) : (y< -x);
|
|
136 |
mCameraDistance = distance;
|
|
182 | 137 |
} |
183 | 138 |
|
184 | 139 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
185 | 140 |
|
186 |
private void continueRotation(int x, int y)
|
|
141 |
RubikRenderer getRenderer()
|
|
187 | 142 |
{ |
188 |
convertTouchPointToScreenSpace(x,y); |
|
189 |
|
|
190 |
mDiff[0] = mPoint[0]-mTouchPoint[0]; |
|
191 |
mDiff[1] = mPoint[1]-mTouchPoint[1]; |
|
192 |
mDiff[2] = mPoint[2]-mTouchPoint[2]; |
|
193 |
|
|
194 |
int xAxis= retFaceXaxis(mLastTouchedFace); |
|
195 |
int yAxis= retFaceYaxis(mLastTouchedFace); |
|
196 |
int sign = retFaceRotationSign(mLastTouchedFace); |
|
197 |
float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]); |
|
198 |
|
|
199 |
mRenderer.getCube().continueRotation(SWIPING_SENSITIVITY*sign*angle/mScreenMin); |
|
143 |
return mRenderer; |
|
200 | 144 |
} |
201 | 145 |
|
202 | 146 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
203 | 147 |
|
204 |
private void finishRotation()
|
|
148 |
int getRedButton()
|
|
205 | 149 |
{ |
206 |
mRenderer.finishRotation();
|
|
150 |
return mButton;
|
|
207 | 151 |
} |
208 | 152 |
|
209 | 153 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
210 | 154 |
|
211 |
private Static4D quatFromDrag(float dragX, float dragY)
|
|
155 |
void markButton(int button)
|
|
212 | 156 |
{ |
213 |
float axisX = dragY; // inverted X and Y - rotation axis is perpendicular to (dragX,dragY) |
|
214 |
float axisY = dragX; // Why not (-dragY, dragX) ? because Y axis is also inverted! |
|
215 |
float axisZ = 0; |
|
216 |
float axisL = (float)Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ); |
|
157 |
mButton = button; |
|
158 |
RubikActivity act = (RubikActivity)getContext(); |
|
217 | 159 |
|
218 |
if( axisL>0 )
|
|
160 |
for(int b=0; b<RubikSize.LENGTH; b++)
|
|
219 | 161 |
{ |
220 |
axisX /= axisL; |
|
221 |
axisY /= axisL; |
|
222 |
axisZ /= axisL; |
|
162 |
Drawable d = act.findViewById(b).getBackground(); |
|
223 | 163 |
|
224 |
float ratio = axisL/mScreenMin; |
|
225 |
ratio = ratio - (int)ratio; // the cos() is only valid in (0,Pi) |
|
226 |
|
|
227 |
float cosA = (float)Math.cos(Math.PI*ratio); |
|
228 |
float sinA = (float)Math.sqrt(1-cosA*cosA); |
|
229 |
|
|
230 |
return new Static4D(axisX*sinA, axisY*sinA, axisZ*sinA, cosA); |
|
164 |
if( b==button ) |
|
165 |
{ |
|
166 |
d.setColorFilter(ContextCompat.getColor(act,R.color.red), PorterDuff.Mode.MULTIPLY); |
|
167 |
} |
|
168 |
else |
|
169 |
{ |
|
170 |
d.clearColorFilter(); |
|
171 |
} |
|
231 | 172 |
} |
232 |
|
|
233 |
return new Static4D(0f, 0f, 0f, 1f); |
|
234 | 173 |
} |
235 | 174 |
|
236 | 175 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
237 | 176 |
|
238 |
private boolean faceIsVisible(int face, float cubeHalfSize)
|
|
177 |
void addSizeButtons(RubikActivity act)
|
|
239 | 178 |
{ |
240 |
int sign = retFaceSign(face);
|
|
241 |
int zAxis= retFaceZaxis(face);
|
|
242 |
|
|
243 |
return sign*mCamera[zAxis] > cubeHalfSize;
|
|
244 |
}
|
|
245 |
|
|
246 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
247 |
|
|
248 |
private void convertTouchPointToScreenSpace(int x, int y)
|
|
249 |
{
|
|
250 |
float halfScrWidth = mScreenWidth *0.5f;
|
|
251 |
float halfScrHeight = mScreenHeight*0.5f;
|
|
252 |
Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
|
|
253 |
Static4D rotatedTouchPoint= rotateVectorByInvertedQuat(touchPoint, mQuatAccumulated);
|
|
254 |
|
|
255 |
mPoint[0] = rotatedTouchPoint.get1();
|
|
256 |
mPoint[1] = rotatedTouchPoint.get2();
|
|
257 |
mPoint[2] = rotatedTouchPoint.get3();
|
|
179 |
LinearLayout layout = act.findViewById(R.id.sizeLayout);
|
|
180 |
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
|
181 |
float scale = metrics.density; |
|
182 |
int size = (int)(64*scale +0.5f);
|
|
183 |
int padding = (int)(3*scale + 0.5f);
|
|
184 |
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(size,size); |
|
185 |
|
|
186 |
for(int i=0; i<RubikSize.LENGTH; i++) |
|
187 |
{
|
|
188 |
ImageButton button = new ImageButton(act);
|
|
189 |
button.setLayoutParams(params);
|
|
190 |
button.setId(i);
|
|
191 |
button.setPadding(padding,0,padding,0);
|
|
192 |
int iconID = RubikSize.getSize(i).getIconID();
|
|
193 |
button.setImageResource(iconID); |
|
194 |
button.setOnClickListener(act);
|
|
195 |
layout.addView(button);
|
|
196 |
}
|
|
258 | 197 |
} |
259 | 198 |
|
260 | 199 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
261 | 200 |
|
262 |
private void convertCameraPointToScreenSpace()
|
|
201 |
void enterScrambleMode()
|
|
263 | 202 |
{ |
264 |
Static4D cameraPoint = new Static4D(0, 0, mCameraDistance, 0); |
|
265 |
Static4D rotatedCamera= rotateVectorByInvertedQuat(cameraPoint, mQuatAccumulated); |
|
266 |
|
|
267 |
mCamera[0] = rotatedCamera.get1(); |
|
268 |
mCamera[1] = rotatedCamera.get2(); |
|
269 |
mCamera[2] = rotatedCamera.get3(); |
|
270 |
} |
|
203 |
if( !mInScrambleMode ) |
|
204 |
{ |
|
205 |
mInScrambleMode = true; |
|
271 | 206 |
|
272 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
273 |
// given precomputed mCamera and mPoint, respectively camera and touch point positions in ScreenSpace, |
|
274 |
// cast this touch point onto the surface defined by the 'face' and write the cast coords to 'output'. |
|
275 |
// Center of the 'face' = (0,0), third coord always +- cubeHalfSize. |
|
207 |
android.util.Log.e("view", "entering scramble mode"); |
|
276 | 208 |
|
277 |
private void castTouchPointOntoFace(int face, float cubeHalfSize, float[] output) |
|
278 |
{ |
|
279 |
int sign = retFaceSign(face); |
|
280 |
int zAxis= retFaceZaxis(face); |
|
281 |
float diff = mPoint[zAxis]-mCamera[zAxis]; |
|
209 |
RubikActivity act = (RubikActivity)getContext(); |
|
282 | 210 |
|
283 |
float ratio = diff!=0.0f ? (sign*cubeHalfSize-mCamera[zAxis])/diff : 0.0f;
|
|
211 |
Button scrambleButt = act.findViewById(R.id.rubikScramble);
|
|
284 | 212 |
|
285 |
output[0] = (mPoint[0]-mCamera[0])*ratio + mCamera[0]; |
|
286 |
output[1] = (mPoint[1]-mCamera[1])*ratio + mCamera[1]; |
|
287 |
output[2] = (mPoint[2]-mCamera[2])*ratio + mCamera[2]; |
|
213 |
if( scrambleButt!=null ) |
|
214 |
{ |
|
215 |
scrambleButt.setClickable(false); |
|
216 |
scrambleButt.setVisibility(INVISIBLE); |
|
217 |
} |
|
218 |
else |
|
219 |
{ |
|
220 |
android.util.Log.e("view", "button null!"); |
|
221 |
} |
|
222 |
} |
|
288 | 223 |
} |
289 | 224 |
|
290 | 225 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
291 | 226 |
|
292 |
private int retFaceSign(int face)
|
|
227 |
void leaveScrambleMode()
|
|
293 | 228 |
{ |
294 |
return (face==FRONT || face==RIGHT || face==TOP) ? 1:-1; |
|
295 |
} |
|
229 |
if( mInScrambleMode ) |
|
230 |
{ |
|
231 |
mInScrambleMode = false; |
|
296 | 232 |
|
297 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
233 |
android.util.Log.e("view", "leaving scramble mode");
|
|
298 | 234 |
|
299 |
private int retFaceRotationSign(int face) |
|
300 |
{ |
|
301 |
return (face==BACK || face==RIGHT || face==TOP) ? 1:-1; |
|
302 |
} |
|
235 |
RubikActivity act = (RubikActivity)getContext(); |
|
303 | 236 |
|
304 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
305 |
// retFace{X,Y,Z}axis: 3 functions which return which real AXIS gets mapped to which when we look |
|
306 |
// directly at a given face. For example, when we look at the RIGHT face of the cube (with TOP still |
|
307 |
// in the top) then the 'real' X axis becomes the 'Z' axis, thus retFaceZaxis(RIGHT) = VECTX. |
|
237 |
Button scrambleButt = act.findViewById(R.id.rubikScramble); |
|
308 | 238 |
|
309 |
private int retFaceXaxis(int face) |
|
310 |
{ |
|
311 |
switch(face) |
|
312 |
{ |
|
313 |
case FRONT : |
|
314 |
case BACK : return RubikCube.VECTX; |
|
315 |
case LEFT : |
|
316 |
case RIGHT : return RubikCube.VECTZ; |
|
317 |
case TOP : |
|
318 |
case BOTTOM: return RubikCube.VECTX; |
|
239 |
if( scrambleButt!=null ) |
|
240 |
{ |
|
241 |
scrambleButt.setClickable(true); |
|
242 |
scrambleButt.setVisibility(VISIBLE); |
|
243 |
} |
|
244 |
else |
|
245 |
{ |
|
246 |
android.util.Log.e("view", "button null!"); |
|
247 |
} |
|
319 | 248 |
} |
320 |
|
|
321 |
return -1; |
|
322 | 249 |
} |
323 | 250 |
|
324 | 251 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
325 | 252 |
|
326 |
private int retFaceYaxis(int face)
|
|
253 |
void leaveScrambleModeNonUI()
|
|
327 | 254 |
{ |
328 |
switch(face) |
|
329 |
{ |
|
330 |
case FRONT : |
|
331 |
case BACK : return RubikCube.VECTY; |
|
332 |
case LEFT : |
|
333 |
case RIGHT : return RubikCube.VECTY; |
|
334 |
case TOP : |
|
335 |
case BOTTOM: return RubikCube.VECTZ; |
|
336 |
} |
|
255 |
RubikActivity act = (RubikActivity)getContext(); |
|
337 | 256 |
|
338 |
return -1; |
|
339 |
} |
|
340 |
|
|
341 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
342 |
|
|
343 |
private int retFaceZaxis(int face) |
|
344 |
{ |
|
345 |
switch(face) |
|
257 |
act.runOnUiThread(new Runnable() |
|
346 | 258 |
{ |
347 |
case FRONT : |
|
348 |
case BACK : return RubikCube.VECTZ; |
|
349 |
case LEFT : |
|
350 |
case RIGHT : return RubikCube.VECTX; |
|
351 |
case TOP : |
|
352 |
case BOTTOM: return RubikCube.VECTY; |
|
353 |
} |
|
354 |
|
|
355 |
return -1; |
|
259 |
@Override |
|
260 |
public void run() |
|
261 |
{ |
|
262 |
leaveScrambleMode(); |
|
263 |
} |
|
264 |
}); |
|
356 | 265 |
} |
357 | 266 |
|
358 | 267 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
385 | 294 |
|
386 | 295 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
387 | 296 |
|
388 |
RubikRenderer getRenderer()
|
|
297 |
private Static4D quatFromDrag(float dragX, float dragY)
|
|
389 | 298 |
{ |
390 |
return mRenderer; |
|
391 |
} |
|
299 |
float axisX = dragY; // inverted X and Y - rotation axis is perpendicular to (dragX,dragY) |
|
300 |
float axisY = dragX; // Why not (-dragY, dragX) ? because Y axis is also inverted! |
|
301 |
float axisZ = 0; |
|
302 |
float axisL = (float)Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ); |
|
392 | 303 |
|
393 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
304 |
if( axisL>0 ) |
|
305 |
{ |
|
306 |
axisX /= axisL; |
|
307 |
axisY /= axisL; |
|
308 |
axisZ /= axisL; |
|
394 | 309 |
|
395 |
void setScreenSize(int width, int height) |
|
396 |
{ |
|
397 |
mScreenWidth = width; |
|
398 |
mScreenHeight= height; |
|
310 |
float ratio = axisL/mScreenMin; |
|
311 |
ratio = ratio - (int)ratio; // the cos() is only valid in (0,Pi) |
|
399 | 312 |
|
400 |
mScreenMin = width<height ? width:height; |
|
313 |
float cosA = (float)Math.cos(Math.PI*ratio); |
|
314 |
float sinA = (float)Math.sqrt(1-cosA*cosA); |
|
315 |
|
|
316 |
return new Static4D(axisX*sinA, axisY*sinA, axisZ*sinA, cosA); |
|
317 |
} |
|
318 |
|
|
319 |
return new Static4D(0f, 0f, 0f, 1f); |
|
401 | 320 |
} |
402 | 321 |
|
403 | 322 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
404 | 323 |
|
405 |
void setCameraDist(float distance)
|
|
324 |
void setMovement(RubikCubeMovement movement)
|
|
406 | 325 |
{ |
407 |
mCameraDistance = distance;
|
|
326 |
mMovement = movement;
|
|
408 | 327 |
} |
409 | 328 |
|
410 | 329 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
417 | 336 |
|
418 | 337 |
if(!isInEditMode()) |
419 | 338 |
{ |
420 |
mRotationVect = VECT[0]; |
|
421 |
|
|
422 |
mPoint = new float[3]; |
|
423 |
mCamera= new float[3]; |
|
424 |
mDiff = new float[3]; |
|
425 |
mTouchPoint = new float[3]; |
|
426 |
mTouchPointCastOntoFace = new float[3]; |
|
427 |
|
|
428 |
mScreenWidth = mScreenHeight = mScreenMin = 0; |
|
429 |
|
|
339 |
mInScrambleMode = false; |
|
430 | 340 |
mRenderer = new RubikRenderer(this); |
431 | 341 |
|
432 | 342 |
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
... | ... | |
449 | 359 |
{ |
450 | 360 |
case MotionEvent.ACTION_DOWN: mX = x; |
451 | 361 |
mY = y; |
452 |
mLastTouchedFace = faceTouched(x,y);
|
|
362 |
mLastTouchedFace = mMovement.faceTouched(mQuatAccumulated,mCameraDistance, x,y, mScreenWidth, mScreenHeight);
|
|
453 | 363 |
|
454 |
if( mLastTouchedFace != NONE ) |
|
364 |
if( mLastTouchedFace != RubikCubeMovement.NONE )
|
|
455 | 365 |
{ |
456 | 366 |
mDragging = false; |
457 | 367 |
mBeginningRotation = mRenderer.canRotate(); |
... | ... | |
487 | 397 |
|
488 | 398 |
if( (mX-x)*(mX-x)+(mY-y)*(mY-y) > minimumDistToStartRotating ) |
489 | 399 |
{ |
490 |
addNewRotation(x,y);
|
|
400 |
mMovement.addNewRotation(mQuatAccumulated,mLastTouchedFace, x,y, mScreenWidth, mScreenHeight);
|
|
491 | 401 |
mBeginningRotation = false; |
492 | 402 |
mContinuingRotation= true; |
493 | 403 |
} |
494 | 404 |
} |
495 | 405 |
else if( mContinuingRotation ) |
496 | 406 |
{ |
497 |
continueRotation(x,y);
|
|
407 |
mMovement.continueRotation(mQuatAccumulated,mLastTouchedFace, x,y, mScreenWidth, mScreenHeight);
|
|
498 | 408 |
} |
499 | 409 |
break; |
500 | 410 |
case MotionEvent.ACTION_UP : if( mDragging ) |
... | ... | |
507 | 417 |
|
508 | 418 |
if( mContinuingRotation ) |
509 | 419 |
{ |
510 |
finishRotation(); |
|
420 |
mRenderer.finishRotation();
|
|
511 | 421 |
} |
512 |
|
|
513 | 422 |
break; |
514 | 423 |
} |
515 | 424 |
|
Also available in: Unified diff
Major restructuring - separate the Manipulated Objects (i.e. at the time being - Cubes of various sizes) and the class holding knowledge how those Objects move ( RubikCubeMovement ) into a separate package; remove all knowledge of Objects and the way they move from the main package.