Revision 47ba5ddc
Added by Leszek Koltunski over 4 years ago
src/main/java/org/distorted/magic/RubikSurfaceView.java | ||
---|---|---|
34 | 34 |
{ |
35 | 35 |
// Moving the finger from the middle of the vertical screen to the right edge will rotate a |
36 | 36 |
// given face by SWIPING_SENSITIVITY/2 degrees. |
37 |
private final static int SWIPING_SENSITIVITY = 240; |
|
37 |
private final static int SWIPING_SENSITIVITY = 240;
|
|
38 | 38 |
|
39 | 39 |
// Moving the finger by 1/12 the distance of min(scrWidth,scrHeight) will start a Rotation. |
40 |
private final static int ROTATION_SENSITIVITY= 12; |
|
40 |
private final static int ROTATION_SENSITIVITY = 12;
|
|
41 | 41 |
|
42 | 42 |
// Every 1/12 the distance of min(scrWidth,scrHeight) the direction of cube rotation will reset. |
43 | 43 |
private final static int DIRECTION_SENSITIVITY= 12; |
... | ... | |
68 | 68 |
private static Static4D mTempAccumulated= new Static4D(0,0,0,1); |
69 | 69 |
|
70 | 70 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
71 |
// return quat1*quat2 |
|
71 | 72 |
|
72 |
public RubikSurfaceView(Context context, AttributeSet attrs) |
|
73 |
{ |
|
74 |
super(context,attrs); |
|
75 |
|
|
76 |
if(!isInEditMode()) |
|
77 |
{ |
|
78 |
mRotationVect = VECT[0]; |
|
79 |
|
|
80 |
mPoint = new float[3]; |
|
81 |
mCamera= new float[3]; |
|
82 |
mDiff = new float[3]; |
|
83 |
mTouchPoint = new float[3]; |
|
84 |
mTouchPointCastOntoFace = new float[3]; |
|
85 |
|
|
86 |
mScreenWidth = mScreenHeight = mScreenMin = 0; |
|
87 |
|
|
88 |
mRenderer = new RubikRenderer(this); |
|
89 |
|
|
90 |
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
|
91 |
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo(); |
|
92 |
setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 ); |
|
93 |
setRenderer(mRenderer); |
|
94 |
} |
|
95 |
} |
|
96 |
|
|
97 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
98 |
|
|
99 |
@Override |
|
100 |
public boolean onTouchEvent(MotionEvent event) |
|
101 |
{ |
|
102 |
int action = event.getAction(); |
|
103 |
int x = (int)event.getX(); |
|
104 |
int y = (int)event.getY(); |
|
105 |
|
|
106 |
switch(action) |
|
107 |
{ |
|
108 |
case MotionEvent.ACTION_DOWN: mX = x; |
|
109 |
mY = y; |
|
110 |
mLastTouchedFace = faceTouched(x,y); |
|
111 |
|
|
112 |
if( mLastTouchedFace != NONE ) |
|
113 |
{ |
|
114 |
mDragging = false; |
|
115 |
mBeginningRotation = mRenderer.canRotate(); |
|
116 |
mContinuingRotation = false; |
|
117 |
} |
|
118 |
else |
|
119 |
{ |
|
120 |
mDragging = mRenderer.canDrag(); |
|
121 |
mBeginningRotation = false; |
|
122 |
mContinuingRotation = false; |
|
123 |
} |
|
124 |
break; |
|
125 |
case MotionEvent.ACTION_MOVE: if( mDragging ) |
|
126 |
{ |
|
127 |
mTempCurrent.set(quatFromDrag(mX-x,mY-y)); |
|
128 |
mRenderer.setQuatCurrentOnNextRender(); |
|
129 |
|
|
130 |
int minimumDist = (mScreenMin*mScreenMin)/(DIRECTION_SENSITIVITY*DIRECTION_SENSITIVITY); |
|
131 |
|
|
132 |
if( (mX-x)*(mX-x) + (mY-y)*(mY-y) > minimumDist ) |
|
133 |
{ |
|
134 |
mX = x; |
|
135 |
mY = y; |
|
136 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
|
137 |
mTempCurrent.set(0f, 0f, 0f, 1f); |
|
138 |
mRenderer.setQuatCurrentOnNextRender(); |
|
139 |
mRenderer.setQuatAccumulatedOnNextRender(); |
|
140 |
} |
|
141 |
} |
|
142 |
if( mBeginningRotation ) |
|
143 |
{ |
|
144 |
int minimumDistToStartRotating = (mScreenMin*mScreenMin)/(ROTATION_SENSITIVITY*ROTATION_SENSITIVITY); |
|
145 |
|
|
146 |
if( (mX-x)*(mX-x)+(mY-y)*(mY-y) > minimumDistToStartRotating ) |
|
147 |
{ |
|
148 |
addNewRotation(x,y); |
|
149 |
mBeginningRotation = false; |
|
150 |
mContinuingRotation= true; |
|
151 |
} |
|
152 |
} |
|
153 |
else if( mContinuingRotation ) |
|
154 |
{ |
|
155 |
continueRotation(x,y); |
|
156 |
} |
|
157 |
break; |
|
158 |
case MotionEvent.ACTION_UP : if( mDragging ) |
|
159 |
{ |
|
160 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
|
161 |
mTempCurrent.set(0f, 0f, 0f, 1f); |
|
162 |
mRenderer.setQuatCurrentOnNextRender(); |
|
163 |
mRenderer.setQuatAccumulatedOnNextRender(); |
|
164 |
} |
|
165 |
|
|
166 |
if( mContinuingRotation ) |
|
167 |
{ |
|
168 |
finishRotation(); |
|
169 |
} |
|
170 |
|
|
171 |
break; |
|
172 |
} |
|
173 |
|
|
174 |
return true; |
|
175 |
} |
|
176 |
|
|
177 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
178 |
|
|
179 |
void setQuatAccumulated() |
|
73 |
static Static4D quatMultiply( Static4D quat1, Static4D quat2 ) |
|
180 | 74 |
{ |
181 |
mQuatAccumulated.set(mTempAccumulated);
|
|
182 |
}
|
|
183 |
|
|
184 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
75 |
float qx = quat1.get1();
|
|
76 |
float qy = quat1.get2();
|
|
77 |
float qz = quat1.get3(); |
|
78 |
float qw = quat1.get4();
|
|
185 | 79 |
|
186 |
void setQuatCurrent()
|
|
187 |
{
|
|
188 |
mQuatCurrent.set(mTempCurrent);
|
|
189 |
}
|
|
80 |
float rx = quat2.get1();
|
|
81 |
float ry = quat2.get2();
|
|
82 |
float rz = quat2.get3();
|
|
83 |
float rw = quat2.get4();
|
|
190 | 84 |
|
191 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
85 |
float tx = rw*qx - rz*qy + ry*qz + rx*qw; |
|
86 |
float ty = rw*qy + rz*qx + ry*qw - rx*qz; |
|
87 |
float tz = rw*qz + rz*qw - ry*qx + rx*qy; |
|
88 |
float tw = rw*qw - rz*qz - ry*qy - rx*qx; |
|
192 | 89 |
|
193 |
Static4D getQuatAccumulated() |
|
194 |
{ |
|
195 |
return mQuatAccumulated; |
|
90 |
return new Static4D(tx,ty,tz,tw); |
|
196 | 91 |
} |
197 | 92 |
|
198 | 93 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
94 |
// rotate 'vector' by quat^(-1) ( i.e. return (quat^-1)*vector*quat ) |
|
199 | 95 |
|
200 |
Static4D getQuatCurrent()
|
|
96 |
static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat)
|
|
201 | 97 |
{ |
202 |
return mQuatCurrent; |
|
203 |
} |
|
98 |
float qx = quat.get1(); |
|
99 |
float qy = quat.get2(); |
|
100 |
float qz = quat.get3(); |
|
101 |
float qw = quat.get4(); |
|
204 | 102 |
|
205 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
103 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
104 |
Static4D tmp = quatMultiply(quatInverted,vector); |
|
206 | 105 |
|
207 |
RubikRenderer getRenderer() |
|
208 |
{ |
|
209 |
return mRenderer; |
|
106 |
return quatMultiply(tmp,quat); |
|
210 | 107 |
} |
211 | 108 |
|
212 | 109 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
110 |
// rotate 'vector' by quat ( i.e. return quat*vector*(quat^-1) ) |
|
213 | 111 |
|
214 |
void setScreenSize(int width, int height)
|
|
112 |
static Static4D rotateVectorByQuat(Static4D vector, Static4D quat)
|
|
215 | 113 |
{ |
216 |
mScreenWidth = width; |
|
217 |
mScreenHeight= height; |
|
218 |
|
|
219 |
mScreenMin = width<height ? width:height; |
|
220 |
} |
|
114 |
float qx = quat.get1(); |
|
115 |
float qy = quat.get2(); |
|
116 |
float qz = quat.get3(); |
|
117 |
float qw = quat.get4(); |
|
221 | 118 |
|
222 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
119 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
120 |
Static4D tmp = quatMultiply(quat,vector); |
|
223 | 121 |
|
224 |
void setCameraDist(float distance) |
|
225 |
{ |
|
226 |
mCameraDistance = distance; |
|
122 |
return quatMultiply(tmp,quatInverted); |
|
227 | 123 |
} |
228 | 124 |
|
229 | 125 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
310 | 206 |
mRenderer.finishRotation(); |
311 | 207 |
} |
312 | 208 |
|
313 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
314 |
// return quat1*quat2 |
|
315 |
|
|
316 |
static Static4D quatMultiply( Static4D quat1, Static4D quat2 ) |
|
317 |
{ |
|
318 |
float qx = quat1.get1(); |
|
319 |
float qy = quat1.get2(); |
|
320 |
float qz = quat1.get3(); |
|
321 |
float qw = quat1.get4(); |
|
322 |
|
|
323 |
float rx = quat2.get1(); |
|
324 |
float ry = quat2.get2(); |
|
325 |
float rz = quat2.get3(); |
|
326 |
float rw = quat2.get4(); |
|
327 |
|
|
328 |
float tx = rw*qx - rz*qy + ry*qz + rx*qw; |
|
329 |
float ty = rw*qy + rz*qx + ry*qw - rx*qz; |
|
330 |
float tz = rw*qz + rz*qw - ry*qx + rx*qy; |
|
331 |
float tw = rw*qw - rz*qz - ry*qy - rx*qx; |
|
332 |
|
|
333 |
return new Static4D(tx,ty,tz,tw); |
|
334 |
} |
|
335 |
|
|
336 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
337 |
// rotate 'vector' by quat^(-1) ( i.e. return (quat^-1)*vector*quat ) |
|
338 |
|
|
339 |
static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat) |
|
340 |
{ |
|
341 |
float qx = quat.get1(); |
|
342 |
float qy = quat.get2(); |
|
343 |
float qz = quat.get3(); |
|
344 |
float qw = quat.get4(); |
|
345 |
|
|
346 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
347 |
Static4D tmp = quatMultiply(quatInverted,vector); |
|
348 |
|
|
349 |
return quatMultiply(tmp,quat); |
|
350 |
} |
|
351 |
|
|
352 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
353 |
// rotate 'vector' by quat ( i.e. return quat*vector*(quat^-1) ) |
|
354 |
|
|
355 |
static Static4D rotateVectorByQuat(Static4D vector, Static4D quat) |
|
356 |
{ |
|
357 |
float qx = quat.get1(); |
|
358 |
float qy = quat.get2(); |
|
359 |
float qz = quat.get3(); |
|
360 |
float qw = quat.get4(); |
|
361 |
|
|
362 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
363 |
Static4D tmp = quatMultiply(quat,vector); |
|
364 |
|
|
365 |
return quatMultiply(tmp,quatInverted); |
|
366 |
} |
|
367 |
|
|
368 | 209 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
369 | 210 |
|
370 | 211 |
private Static4D quatFromDrag(float dragX, float dragY) |
... | ... | |
513 | 354 |
|
514 | 355 |
return -1; |
515 | 356 |
} |
357 |
|
|
358 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
359 |
|
|
360 |
void setQuatAccumulated() |
|
361 |
{ |
|
362 |
mQuatAccumulated.set(mTempAccumulated); |
|
363 |
} |
|
364 |
|
|
365 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
366 |
|
|
367 |
void setQuatCurrent() |
|
368 |
{ |
|
369 |
mQuatCurrent.set(mTempCurrent); |
|
370 |
} |
|
371 |
|
|
372 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
373 |
|
|
374 |
Static4D getQuatAccumulated() |
|
375 |
{ |
|
376 |
return mQuatAccumulated; |
|
377 |
} |
|
378 |
|
|
379 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
380 |
|
|
381 |
Static4D getQuatCurrent() |
|
382 |
{ |
|
383 |
return mQuatCurrent; |
|
384 |
} |
|
385 |
|
|
386 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
387 |
|
|
388 |
RubikRenderer getRenderer() |
|
389 |
{ |
|
390 |
return mRenderer; |
|
391 |
} |
|
392 |
|
|
393 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
394 |
|
|
395 |
void setScreenSize(int width, int height) |
|
396 |
{ |
|
397 |
mScreenWidth = width; |
|
398 |
mScreenHeight= height; |
|
399 |
|
|
400 |
mScreenMin = width<height ? width:height; |
|
401 |
} |
|
402 |
|
|
403 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
404 |
|
|
405 |
void setCameraDist(float distance) |
|
406 |
{ |
|
407 |
mCameraDistance = distance; |
|
408 |
} |
|
409 |
|
|
410 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
411 |
// PUBLIC API |
|
412 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
413 |
|
|
414 |
public RubikSurfaceView(Context context, AttributeSet attrs) |
|
415 |
{ |
|
416 |
super(context,attrs); |
|
417 |
|
|
418 |
if(!isInEditMode()) |
|
419 |
{ |
|
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 |
|
|
430 |
mRenderer = new RubikRenderer(this); |
|
431 |
|
|
432 |
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
|
433 |
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo(); |
|
434 |
setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 ); |
|
435 |
setRenderer(mRenderer); |
|
436 |
} |
|
437 |
} |
|
438 |
|
|
439 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
440 |
|
|
441 |
@Override |
|
442 |
public boolean onTouchEvent(MotionEvent event) |
|
443 |
{ |
|
444 |
int action = event.getAction(); |
|
445 |
int x = (int)event.getX(); |
|
446 |
int y = (int)event.getY(); |
|
447 |
|
|
448 |
switch(action) |
|
449 |
{ |
|
450 |
case MotionEvent.ACTION_DOWN: mX = x; |
|
451 |
mY = y; |
|
452 |
mLastTouchedFace = faceTouched(x,y); |
|
453 |
|
|
454 |
if( mLastTouchedFace != NONE ) |
|
455 |
{ |
|
456 |
mDragging = false; |
|
457 |
mBeginningRotation = mRenderer.canRotate(); |
|
458 |
mContinuingRotation = false; |
|
459 |
} |
|
460 |
else |
|
461 |
{ |
|
462 |
mDragging = mRenderer.canDrag(); |
|
463 |
mBeginningRotation = false; |
|
464 |
mContinuingRotation = false; |
|
465 |
} |
|
466 |
break; |
|
467 |
case MotionEvent.ACTION_MOVE: if( mDragging ) |
|
468 |
{ |
|
469 |
mTempCurrent.set(quatFromDrag(mX-x,mY-y)); |
|
470 |
mRenderer.setQuatCurrentOnNextRender(); |
|
471 |
|
|
472 |
int minimumDist = (mScreenMin*mScreenMin)/(DIRECTION_SENSITIVITY*DIRECTION_SENSITIVITY); |
|
473 |
|
|
474 |
if( (mX-x)*(mX-x) + (mY-y)*(mY-y) > minimumDist ) |
|
475 |
{ |
|
476 |
mX = x; |
|
477 |
mY = y; |
|
478 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
|
479 |
mTempCurrent.set(0f, 0f, 0f, 1f); |
|
480 |
mRenderer.setQuatCurrentOnNextRender(); |
|
481 |
mRenderer.setQuatAccumulatedOnNextRender(); |
|
482 |
} |
|
483 |
} |
|
484 |
if( mBeginningRotation ) |
|
485 |
{ |
|
486 |
int minimumDistToStartRotating = (mScreenMin*mScreenMin)/(ROTATION_SENSITIVITY*ROTATION_SENSITIVITY); |
|
487 |
|
|
488 |
if( (mX-x)*(mX-x)+(mY-y)*(mY-y) > minimumDistToStartRotating ) |
|
489 |
{ |
|
490 |
addNewRotation(x,y); |
|
491 |
mBeginningRotation = false; |
|
492 |
mContinuingRotation= true; |
|
493 |
} |
|
494 |
} |
|
495 |
else if( mContinuingRotation ) |
|
496 |
{ |
|
497 |
continueRotation(x,y); |
|
498 |
} |
|
499 |
break; |
|
500 |
case MotionEvent.ACTION_UP : if( mDragging ) |
|
501 |
{ |
|
502 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
|
503 |
mTempCurrent.set(0f, 0f, 0f, 1f); |
|
504 |
mRenderer.setQuatCurrentOnNextRender(); |
|
505 |
mRenderer.setQuatAccumulatedOnNextRender(); |
|
506 |
} |
|
507 |
|
|
508 |
if( mContinuingRotation ) |
|
509 |
{ |
|
510 |
finishRotation(); |
|
511 |
} |
|
512 |
|
|
513 |
break; |
|
514 |
} |
|
515 |
|
|
516 |
return true; |
|
517 |
} |
|
516 | 518 |
} |
517 | 519 |
|
Also available in: Unified diff
RubikCube: further fixes