Revision 8d50e08d
Added by Leszek Koltunski over 4 years ago
src/main/java/org/distorted/main/RubikSurfaceView.java | ||
---|---|---|
42 | 42 |
public class RubikSurfaceView extends GLSurfaceView |
43 | 43 |
{ |
44 | 44 |
private static final int NUM_SPEED_PROBES = 10; |
45 |
private static final int INVALID_POINTER_ID = -1; |
|
45 | 46 |
|
46 | 47 |
public static final int MODE_ROTATE = 0; |
47 | 48 |
public static final int MODE_DRAG = 1; |
... | ... | |
72 | 73 |
private boolean mDragging, mBeginningRotation, mContinuingRotation; |
73 | 74 |
private int mScreenWidth, mScreenHeight, mScreenMin; |
74 | 75 |
|
75 |
private float mX, mY; |
|
76 |
private int mPtrID1, mPtrID2; |
|
77 |
private float mX, mY, mBegX1, mBegY1, mBegX2, mBegY2; |
|
76 | 78 |
private float mStartRotX, mStartRotY; |
77 | 79 |
private float mAxisX, mAxisY; |
78 | 80 |
private float mRotationFactor; |
... | ... | |
156 | 158 |
mMovement = movement; |
157 | 159 |
} |
158 | 160 |
|
161 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
162 |
|
|
163 |
private Static4D quatFromAngle(float angle) |
|
164 |
{ |
|
165 |
float cosA = (float)Math.cos(angle); |
|
166 |
float sinA =-(float)Math.sin(angle); |
|
167 |
|
|
168 |
return new Static4D(0, 0, sinA, cosA); |
|
169 |
} |
|
170 |
|
|
159 | 171 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
160 | 172 |
|
161 | 173 |
private Static4D quatFromDrag(float dragX, float dragY) |
... | ... | |
383 | 395 |
|
384 | 396 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
385 | 397 |
|
386 |
private void actionDown(float x, float y)
|
|
398 |
private void dragging(float x, float y)
|
|
387 | 399 |
{ |
388 |
mX = x; |
|
389 |
mY = y; |
|
390 |
setUpDragOrRotate(true,x,y); |
|
400 |
mTempCurrent.set(quatFromDrag(mX-x,y-mY)); |
|
401 |
mPreRender.setQuatCurrentOnNextRender(); |
|
402 |
|
|
403 |
if( retFingerDragDistanceInInches(mX,mY,x,y) > DIRECTION_SENSITIVITY ) |
|
404 |
{ |
|
405 |
mX = x; |
|
406 |
mY = y; |
|
407 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
|
408 |
mTempCurrent.set(0f, 0f, 0f, 1f); |
|
409 |
mPreRender.setQuatCurrentOnNextRender(); |
|
410 |
mPreRender.setQuatAccumulatedOnNextRender(); |
|
411 |
} |
|
391 | 412 |
} |
392 | 413 |
|
393 | 414 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
394 | 415 |
|
395 |
private void actionMove(float x, float y)
|
|
416 |
private void continuingRotation(float x, float y)
|
|
396 | 417 |
{ |
397 |
if( mBeginningRotation ) |
|
398 |
{ |
|
399 |
if( retFingerDragDistanceInInches(mX,mY,x,y) > ROTATION_SENSITIVITY ) |
|
400 |
{ |
|
401 |
mStartRotX = x; |
|
402 |
mStartRotY = y; |
|
403 |
|
|
404 |
Static4D touchPoint2 = new Static4D(x, y, 0, 0); |
|
405 |
Static4D rotatedTouchPoint2= rotateVectorByInvertedQuat(touchPoint2, mQuatAccumulated); |
|
418 |
float angle = continueRotation(x-mStartRotX,y-mStartRotY); |
|
419 |
mCurrentAngle = SWIPING_SENSITIVITY*angle; |
|
420 |
mPreRender.getObject().continueRotation(mCurrentAngle); |
|
406 | 421 |
|
407 |
Static2D res = mMovement.newRotation(rotatedTouchPoint2);
|
|
408 |
RubikObject object = mPreRender.getObject();
|
|
422 |
addSpeedProbe(x,y);
|
|
423 |
}
|
|
409 | 424 |
|
410 |
mCurrentAxis = (int)res.get0(); |
|
411 |
float offset = res.get1(); |
|
412 |
mCurrentRow = (int)(object.returnMultiplier()*offset); |
|
413 |
computeCurrentAxis( object.getRotationAxis()[mCurrentAxis] ); |
|
414 |
mRotationFactor = object.returnRotationFactor(offset); |
|
425 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
415 | 426 |
|
416 |
object.beginNewRotation( mCurrentAxis, mCurrentRow ); |
|
427 |
private void beginningRotation(float x, float y) |
|
428 |
{ |
|
429 |
mStartRotX = x; |
|
430 |
mStartRotY = y; |
|
417 | 431 |
|
418 |
if( RubikState.getCurrentState()==RubikState.READ ) |
|
419 |
{ |
|
420 |
RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass(); |
|
421 |
solving.resetElapsed(); |
|
432 |
Static4D touchPoint2 = new Static4D(x, y, 0, 0); |
|
433 |
Static4D rotatedTouchPoint2= rotateVectorByInvertedQuat(touchPoint2, mQuatAccumulated); |
|
422 | 434 |
|
423 |
final RubikActivity act = (RubikActivity)getContext(); |
|
435 |
Static2D res = mMovement.newRotation(rotatedTouchPoint2); |
|
436 |
RubikObject object = mPreRender.getObject(); |
|
424 | 437 |
|
425 |
act.runOnUiThread(new Runnable() |
|
426 |
{ |
|
427 |
@Override |
|
428 |
public void run() |
|
429 |
{ |
|
430 |
RubikState.switchState( act, RubikState.SOLV); |
|
431 |
} |
|
432 |
}); |
|
433 |
} |
|
438 |
mCurrentAxis = (int)res.get0(); |
|
439 |
float offset = res.get1(); |
|
440 |
mCurrentRow = (int)(object.returnMultiplier()*offset); |
|
441 |
computeCurrentAxis( object.getRotationAxis()[mCurrentAxis] ); |
|
442 |
mRotationFactor = object.returnRotationFactor(offset); |
|
434 | 443 |
|
435 |
addSpeedProbe(x,y);
|
|
444 |
object.beginNewRotation( mCurrentAxis, mCurrentRow );
|
|
436 | 445 |
|
437 |
mBeginningRotation = false; |
|
438 |
mContinuingRotation= true; |
|
439 |
} |
|
440 |
} |
|
441 |
else if( mContinuingRotation ) |
|
446 |
if( RubikState.getCurrentState()==RubikState.READ ) |
|
442 | 447 |
{ |
443 |
float angle = continueRotation(x-mStartRotX,y-mStartRotY); |
|
444 |
mCurrentAngle = SWIPING_SENSITIVITY*angle; |
|
445 |
mPreRender.getObject().continueRotation(mCurrentAngle); |
|
448 |
RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass(); |
|
449 |
solving.resetElapsed(); |
|
450 |
|
|
451 |
final RubikActivity act = (RubikActivity)getContext(); |
|
446 | 452 |
|
447 |
addSpeedProbe(x,y); |
|
453 |
act.runOnUiThread(new Runnable() |
|
454 |
{ |
|
455 |
@Override |
|
456 |
public void run() |
|
457 |
{ |
|
458 |
RubikState.switchState( act, RubikState.SOLV); |
|
459 |
} |
|
460 |
}); |
|
448 | 461 |
} |
449 |
else if( mDragging ) |
|
462 |
|
|
463 |
addSpeedProbe(x,y); |
|
464 |
|
|
465 |
mBeginningRotation = false; |
|
466 |
mContinuingRotation= true; |
|
467 |
} |
|
468 |
|
|
469 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
470 |
|
|
471 |
private void actionMove(MotionEvent event) |
|
472 |
{ |
|
473 |
if( mPtrID2 == INVALID_POINTER_ID ) |
|
450 | 474 |
{ |
451 |
mTempCurrent.set(quatFromDrag(mX-x,y-mY));
|
|
452 |
mPreRender.setQuatCurrentOnNextRender();
|
|
475 |
float x = (event.getX() - mScreenWidth*0.5f)/mScreenMin;
|
|
476 |
float y = (mScreenHeight*0.5f -event.getY())/mScreenMin;
|
|
453 | 477 |
|
454 |
if( retFingerDragDistanceInInches(mX,mY,x,y) > DIRECTION_SENSITIVITY )
|
|
478 |
if( mBeginningRotation )
|
|
455 | 479 |
{ |
456 |
mX = x; |
|
457 |
mY = y; |
|
458 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
|
459 |
mTempCurrent.set(0f, 0f, 0f, 1f); |
|
460 |
mPreRender.setQuatCurrentOnNextRender(); |
|
461 |
mPreRender.setQuatAccumulatedOnNextRender(); |
|
480 |
if( retFingerDragDistanceInInches(mX,mY,x,y) > ROTATION_SENSITIVITY ) |
|
481 |
{ |
|
482 |
beginningRotation(x,y); |
|
483 |
} |
|
484 |
} |
|
485 |
else if( mContinuingRotation ) |
|
486 |
{ |
|
487 |
continuingRotation(x,y); |
|
488 |
} |
|
489 |
else if( mDragging ) |
|
490 |
{ |
|
491 |
dragging(x,y); |
|
492 |
} |
|
493 |
else |
|
494 |
{ |
|
495 |
setUpDragOrRotate(false,x,y); |
|
462 | 496 |
} |
463 | 497 |
} |
464 | 498 |
else |
465 | 499 |
{ |
466 |
setUpDragOrRotate(false,x,y); |
|
500 |
int index1 = event.findPointerIndex(mPtrID1); |
|
501 |
int index2 = event.findPointerIndex(mPtrID2); |
|
502 |
|
|
503 |
float nX1 = event.getX(index1); |
|
504 |
float nY1 = event.getY(index1); |
|
505 |
float nX2 = event.getX(index2); |
|
506 |
float nY2 = event.getY(index2); |
|
507 |
|
|
508 |
float angle1 = (float) Math.atan2(mBegY1-mBegY2, mBegX1-mBegX2); |
|
509 |
float angle2 = (float) Math.atan2( nY1-nY2 , nX1-nX2 ); |
|
510 |
|
|
511 |
mTempCurrent.set(quatFromAngle(angle1-angle2)); |
|
512 |
mPreRender.setQuatCurrentOnNextRender(); |
|
467 | 513 |
} |
468 | 514 |
} |
469 | 515 |
|
516 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
517 |
|
|
518 |
private void actionDown(MotionEvent event) |
|
519 |
{ |
|
520 |
mPtrID1 = event.getPointerId(0); |
|
521 |
|
|
522 |
mX = (event.getX() - mScreenWidth*0.5f)/mScreenMin; |
|
523 |
mY = (mScreenHeight*0.5f -event.getY())/mScreenMin; |
|
524 |
|
|
525 |
setUpDragOrRotate(true,mX,mY); |
|
526 |
} |
|
527 |
|
|
470 | 528 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
471 | 529 |
|
472 | 530 |
private void actionUp() |
473 | 531 |
{ |
532 |
mPtrID1 = INVALID_POINTER_ID; |
|
533 |
|
|
474 | 534 |
if( mDragging ) |
475 | 535 |
{ |
476 | 536 |
mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated)); |
... | ... | |
498 | 558 |
} |
499 | 559 |
} |
500 | 560 |
|
561 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
562 |
|
|
563 |
private void actionDown2(MotionEvent event) |
|
564 |
{ |
|
565 |
mPtrID2 = event.getPointerId(event.getActionIndex()); |
|
566 |
|
|
567 |
int index1 = event.findPointerIndex(mPtrID1); |
|
568 |
mBegX1 = event.getX(index1); |
|
569 |
mBegY1 = event.getY(index1); |
|
570 |
|
|
571 |
mX = (mBegX1 - mScreenWidth*0.5f)/mScreenMin; |
|
572 |
mY = (mScreenHeight*0.5f -mBegY1)/mScreenMin; |
|
573 |
|
|
574 |
int index2 = event.findPointerIndex(mPtrID2); |
|
575 |
mBegX2 = event.getX(index2); |
|
576 |
mBegY2 = event.getY(index2); |
|
577 |
} |
|
578 |
|
|
579 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
580 |
|
|
581 |
private void actionUp2() |
|
582 |
{ |
|
583 |
mPtrID2 = INVALID_POINTER_ID; |
|
584 |
} |
|
585 |
|
|
501 | 586 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
502 | 587 |
// PUBLIC API |
503 | 588 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
517 | 602 |
mFirstIndex =0; |
518 | 603 |
mLastIndex =0; |
519 | 604 |
|
605 |
mPtrID1 = INVALID_POINTER_ID; |
|
606 |
mPtrID2 = INVALID_POINTER_ID; |
|
607 |
|
|
520 | 608 |
mRenderer = new RubikRenderer(this); |
521 | 609 |
mPreRender = new RubikPreRender(this); |
522 | 610 |
|
... | ... | |
542 | 630 |
@Override |
543 | 631 |
public boolean onTouchEvent(MotionEvent event) |
544 | 632 |
{ |
545 |
int action = event.getAction(); |
|
546 |
float x = (event.getX() - mScreenWidth*0.5f)/mScreenMin; |
|
547 |
float y = (mScreenHeight*0.5f -event.getY())/mScreenMin; |
|
633 |
int action = event.getActionMasked(); |
|
548 | 634 |
|
549 | 635 |
switch(action) |
550 | 636 |
{ |
551 |
case MotionEvent.ACTION_DOWN: actionDown(x,y); break; |
|
552 |
case MotionEvent.ACTION_MOVE: actionMove(x,y); break; |
|
553 |
case MotionEvent.ACTION_UP : actionUp() ; break; |
|
637 |
case MotionEvent.ACTION_DOWN : actionDown(event) ; break; |
|
638 |
case MotionEvent.ACTION_MOVE : actionMove(event) ; break; |
|
639 |
case MotionEvent.ACTION_UP : actionUp() ; break; |
|
640 |
case MotionEvent.ACTION_POINTER_DOWN: actionDown2(event); break; |
|
641 |
case MotionEvent.ACTION_POINTER_UP : actionUp2() ; break; |
|
554 | 642 |
} |
555 | 643 |
|
556 | 644 |
return true; |
Also available in: Unified diff
Initial attempt at two-finger rotation.
Mostly works; still, one corner case doesnt:
- put two fingers down, start rotating
- lift one of them up
- put it back down
depending if we lifted the first or second finger, weird things may happen.