39 |
39 |
private final static int TOP = 4; //
|
40 |
40 |
private final static int BOTTOM = 5; //
|
41 |
41 |
|
42 |
|
static final int VECTX = 0;
|
43 |
|
static final int VECTY = 1;
|
44 |
|
static final int VECTZ = 2;
|
45 |
|
static final int VECTN = 3;
|
|
42 |
static final int VECTX = 0; //
|
|
43 |
static final int VECTY = 1; // dont change this
|
|
44 |
static final int VECTZ = 2; //
|
|
45 |
|
|
46 |
private static final int[] VECT = {VECTX,VECTY,VECTZ};
|
46 |
47 |
|
47 |
48 |
private boolean mDragging, mBeginRot;
|
48 |
49 |
private int mX, mY;
|
... | ... | |
51 |
52 |
private RubikRenderer mRenderer;
|
52 |
53 |
private RubikCube mCube;
|
53 |
54 |
|
54 |
|
private float mPoiX, mPoiY, mPoiZ, mCamX, mCamY, mCamZ;
|
55 |
|
private float mStartX, mStartY, mStartZ;
|
|
55 |
private float[] mPoi, mCam, mTouchedPointCastOntoFace, mDiff; // all in screen space
|
56 |
56 |
private int mLastTouchedFace;
|
57 |
57 |
private int mScreenWidth, mScreenHeight, mScreenMin;
|
58 |
58 |
private float mCameraDistance;
|
... | ... | |
65 |
65 |
|
66 |
66 |
mDragging = false;
|
67 |
67 |
mBeginRot = false;
|
68 |
|
mRotationVect = VECTN;
|
|
68 |
mRotationVect = VECT[0];
|
|
69 |
|
|
70 |
mPoi = new float[3];
|
|
71 |
mCam = new float[3];
|
|
72 |
mDiff = new float[3];
|
|
73 |
mTouchedPointCastOntoFace = new float[3];
|
69 |
74 |
|
70 |
75 |
mScreenWidth = mScreenHeight = mScreenMin = 0;
|
71 |
76 |
|
... | ... | |
160 |
165 |
}
|
161 |
166 |
|
162 |
167 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
168 |
// mTouchedPointCastOntoFace[x] is the x distance between the x-center of the face and the point
|
|
169 |
// we just touched cast onto the face. The face is touched iff -cH <= mTouchedPointCastOntoFace[0,1,2] <= +cH
|
163 |
170 |
|
164 |
|
private void addNewRotation(int x, int y)
|
|
171 |
private int faceTouched(int xTouch, int yTouch)
|
165 |
172 |
{
|
166 |
|
fillTouchPoint(x,y);
|
167 |
|
|
168 |
|
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
|
169 |
|
float A=retA(mLastTouchedFace,cubeHalfSize);
|
|
173 |
float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f;
|
170 |
174 |
|
171 |
|
float diffX = (mPoiX-mCamX)*A + mCamX - mStartX;
|
172 |
|
float diffY = (mPoiY-mCamY)*A + mCamY - mStartY;
|
173 |
|
float diffZ = (mPoiZ-mCamZ)*A + mCamZ - mStartZ;
|
|
175 |
convertTouchPointToScreenSpace(xTouch,yTouch);
|
|
176 |
convertCameraPointToScreenSpace();
|
174 |
177 |
|
175 |
|
switch(mLastTouchedFace)
|
|
178 |
for(int face=FRONT; face<=BOTTOM; face++)
|
176 |
179 |
{
|
177 |
|
case FRONT :
|
178 |
|
case BACK : mRotationVect = (isVertical(diffX, diffY) ? VECTX:VECTY); break;
|
179 |
|
case LEFT :
|
180 |
|
case RIGHT : mRotationVect = (isVertical(diffZ, diffY) ? VECTZ:VECTY); break;
|
181 |
|
case TOP :
|
182 |
|
case BOTTOM: mRotationVect = (isVertical(diffX, diffZ) ? VECTX:VECTZ); break;
|
183 |
|
}
|
|
180 |
if( faceIsVisible(face,cubeHalfSize) )
|
|
181 |
{
|
|
182 |
castTouchPointOntoFace(face,cubeHalfSize, mTouchedPointCastOntoFace);
|
184 |
183 |
|
185 |
|
float offset=0;
|
|
184 |
float qX= (mTouchedPointCastOntoFace[0]+cubeHalfSize) / (2*cubeHalfSize);
|
|
185 |
float qY= (mTouchedPointCastOntoFace[1]+cubeHalfSize) / (2*cubeHalfSize);
|
|
186 |
float qZ= (mTouchedPointCastOntoFace[2]+cubeHalfSize) / (2*cubeHalfSize);
|
186 |
187 |
|
187 |
|
switch(mRotationVect)
|
188 |
|
{
|
189 |
|
case VECTX: offset = (mStartX+cubeHalfSize)/(2*cubeHalfSize); break;
|
190 |
|
case VECTY: offset = (mStartY+cubeHalfSize)/(2*cubeHalfSize); break;
|
191 |
|
case VECTZ: offset = (mStartZ+cubeHalfSize)/(2*cubeHalfSize); break;
|
|
188 |
if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return face;
|
|
189 |
}
|
192 |
190 |
}
|
193 |
191 |
|
194 |
|
mStartX = diffX + mStartX;
|
195 |
|
mStartY = diffY + mStartY;
|
196 |
|
mStartZ = diffZ + mStartZ;
|
|
192 |
return NONE;
|
|
193 |
}
|
|
194 |
|
|
195 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
196 |
|
|
197 |
private void addNewRotation(int x, int y)
|
|
198 |
{
|
|
199 |
float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f;
|
|
200 |
|
|
201 |
convertTouchPointToScreenSpace(x,y);
|
|
202 |
castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize,mDiff);
|
|
203 |
|
|
204 |
mDiff[0] -= mTouchedPointCastOntoFace[0];
|
|
205 |
mDiff[1] -= mTouchedPointCastOntoFace[1];
|
|
206 |
mDiff[2] -= mTouchedPointCastOntoFace[2];
|
|
207 |
|
|
208 |
int xAxis = retFaceXaxis(mLastTouchedFace);
|
|
209 |
int yAxis = retFaceYaxis(mLastTouchedFace);
|
|
210 |
mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? VECT[xAxis]:VECT[yAxis]);
|
|
211 |
float offset= (mTouchedPointCastOntoFace[mRotationVect]+cubeHalfSize)/(2*cubeHalfSize);
|
|
212 |
|
|
213 |
mTouchedPointCastOntoFace[0] = mDiff[0] + mTouchedPointCastOntoFace[0];
|
|
214 |
mTouchedPointCastOntoFace[1] = mDiff[1] + mTouchedPointCastOntoFace[1];
|
|
215 |
mTouchedPointCastOntoFace[2] = mDiff[2] + mTouchedPointCastOntoFace[2];
|
197 |
216 |
|
198 |
217 |
mCube.addNewRotation(mRotationVect,offset);
|
199 |
218 |
}
|
... | ... | |
209 |
228 |
|
210 |
229 |
private void continueRotation(int x, int y)
|
211 |
230 |
{
|
212 |
|
fillTouchPoint(x,y);
|
|
231 |
float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f;
|
213 |
232 |
|
214 |
|
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
|
215 |
|
float A=retA(mLastTouchedFace,cubeHalfSize);
|
|
233 |
convertTouchPointToScreenSpace(x,y);
|
|
234 |
castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize,mDiff);
|
216 |
235 |
|
217 |
|
float diffX = (mPoiX-mCamX)*A + mCamX - mStartX;
|
218 |
|
float diffY = (mPoiY-mCamY)*A + mCamY - mStartY;
|
219 |
|
float diffZ = (mPoiZ-mCamZ)*A + mCamZ - mStartZ;
|
|
236 |
mDiff[0] -= mTouchedPointCastOntoFace[0];
|
|
237 |
mDiff[1] -= mTouchedPointCastOntoFace[1];
|
|
238 |
mDiff[2] -= mTouchedPointCastOntoFace[2];
|
220 |
239 |
|
221 |
|
float angle=0.0f;
|
|
240 |
int xAxis= retFaceXaxis(mLastTouchedFace);
|
|
241 |
int yAxis= retFaceYaxis(mLastTouchedFace);
|
|
242 |
int sign = retFaceRotationSign(mLastTouchedFace);
|
222 |
243 |
|
223 |
|
switch(mLastTouchedFace)
|
224 |
|
{
|
225 |
|
case FRONT : angle = (mRotationVect==VECTX ? -diffY : diffX); break;
|
226 |
|
case BACK : angle = (mRotationVect==VECTX ? diffY :-diffX); break;
|
227 |
|
case LEFT : angle = (mRotationVect==VECTY ? diffZ :-diffY); break;
|
228 |
|
case RIGHT : angle = (mRotationVect==VECTY ? -diffZ : diffY); break;
|
229 |
|
case TOP : angle = (mRotationVect==VECTZ ? -diffX : diffZ); break;
|
230 |
|
case BOTTOM: angle = (mRotationVect==VECTZ ? diffX :-diffZ); break;
|
231 |
|
}
|
|
244 |
float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]);
|
232 |
245 |
|
233 |
|
mCube.continueRotation(200.0f*angle/mScreenMin);
|
|
246 |
mCube.continueRotation(200.0f*sign*angle/mScreenMin);
|
234 |
247 |
}
|
235 |
248 |
|
236 |
249 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
237 |
250 |
|
238 |
251 |
private void finishRotation()
|
239 |
252 |
{
|
240 |
|
mRotationVect = VECTN;
|
241 |
253 |
mRenderer.finishRotation();
|
242 |
254 |
}
|
243 |
255 |
|
... | ... | |
322 |
334 |
|
323 |
335 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
324 |
336 |
|
325 |
|
private boolean faceIsVisible(int face)
|
|
337 |
private boolean faceIsVisible(int face, float cubeHalfSize)
|
326 |
338 |
{
|
327 |
|
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
|
|
339 |
int sign = retFaceSign(face);
|
|
340 |
int zAxis= retFaceZaxis(face);
|
328 |
341 |
|
329 |
|
Static4D rotated = rotateVectorByInvertedQuat(new Static4D(0,0,mCameraDistance,0), mQuatAccumulated);
|
|
342 |
return sign*mCam[zAxis] > cubeHalfSize;
|
|
343 |
}
|
330 |
344 |
|
331 |
|
switch(face)
|
332 |
|
{
|
333 |
|
case FRONT : return rotated.get3() > cubeHalfSize;
|
334 |
|
case BACK : return rotated.get3() < -cubeHalfSize;
|
335 |
|
case LEFT : return rotated.get1() < -cubeHalfSize;
|
336 |
|
case RIGHT : return rotated.get1() > cubeHalfSize;
|
337 |
|
case TOP : return rotated.get2() > cubeHalfSize;
|
338 |
|
case BOTTOM: return rotated.get2() < -cubeHalfSize;
|
339 |
|
}
|
|
345 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
340 |
346 |
|
341 |
|
return false;
|
|
347 |
private void convertTouchPointToScreenSpace(int x, int y)
|
|
348 |
{
|
|
349 |
float halfScrWidth = mScreenWidth *0.5f;
|
|
350 |
float halfScrHeight = mScreenHeight*0.5f;
|
|
351 |
Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
|
|
352 |
Static4D rotatedTouchPoint= rotateVectorByInvertedQuat(touchPoint, mQuatAccumulated);
|
|
353 |
|
|
354 |
mPoi[0] = rotatedTouchPoint.get1();
|
|
355 |
mPoi[1] = rotatedTouchPoint.get2();
|
|
356 |
mPoi[2] = rotatedTouchPoint.get3();
|
342 |
357 |
}
|
343 |
358 |
|
344 |
359 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
345 |
360 |
|
346 |
|
private int faceTouched(int xTouch, int yTouch)
|
|
361 |
private void convertCameraPointToScreenSpace()
|
347 |
362 |
{
|
348 |
|
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
|
349 |
|
|
350 |
|
fillTouchPoint(xTouch,yTouch);
|
351 |
|
fillCamera();
|
|
363 |
Static4D cameraPoint = new Static4D(0, 0, mCameraDistance, 0);
|
|
364 |
Static4D rotatedCamera= rotateVectorByInvertedQuat(cameraPoint, mQuatAccumulated);
|
352 |
365 |
|
353 |
|
for(int face=FRONT; face<=BOTTOM; face++)
|
354 |
|
{
|
355 |
|
if( faceIsVisible(face) && faceCondition(face) )
|
356 |
|
{
|
357 |
|
float A = retA(face,cubeHalfSize);
|
|
366 |
mCam[0] = rotatedCamera.get1();
|
|
367 |
mCam[1] = rotatedCamera.get2();
|
|
368 |
mCam[2] = rotatedCamera.get3();
|
|
369 |
}
|
358 |
370 |
|
359 |
|
mStartX = (mPoiX-mCamX)*A + mCamX;
|
360 |
|
mStartY = (mPoiY-mCamY)*A + mCamY;
|
361 |
|
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
371 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
372 |
// given precomputed mCam and mPoi, respectively camera and touch point positions in ScreenSpace,
|
|
373 |
// cast this touch point onto the 'face' and write the cast coords to 'output'.
|
|
374 |
// Center of the 'face' = (0,0)
|
362 |
375 |
|
363 |
|
float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
|
364 |
|
float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
|
365 |
|
float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
|
|
376 |
private void castTouchPointOntoFace(int face, float cubeHalfSize, float[] output)
|
|
377 |
{
|
|
378 |
int sign = retFaceSign(face);
|
|
379 |
int zAxis= retFaceZaxis(face);
|
|
380 |
float diff = mPoi[zAxis]-mCam[zAxis];
|
366 |
381 |
|
367 |
|
if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return face;
|
368 |
|
}
|
369 |
|
}
|
|
382 |
float ratio = diff!=0.0f ? (sign*cubeHalfSize-mCam[zAxis])/diff : 0.0f;
|
370 |
383 |
|
371 |
|
return NONE;
|
|
384 |
output[0] = (mPoi[0]-mCam[0])*ratio + mCam[0];
|
|
385 |
output[1] = (mPoi[1]-mCam[1])*ratio + mCam[1];
|
|
386 |
output[2] = (mPoi[2]-mCam[2])*ratio + mCam[2];
|
372 |
387 |
}
|
373 |
388 |
|
374 |
389 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
375 |
390 |
|
376 |
|
private void fillTouchPoint(int x, int y)
|
|
391 |
private int retFaceSign(int face)
|
377 |
392 |
{
|
378 |
|
float halfScrWidth = mScreenWidth *0.5f;
|
379 |
|
float halfScrHeight = mScreenHeight*0.5f;
|
380 |
|
Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
|
381 |
|
Static4D rotatedTouchPoint= rotateVectorByInvertedQuat(touchPoint, mQuatAccumulated);
|
|
393 |
return (face==FRONT || face==RIGHT || face==TOP) ? 1:-1;
|
|
394 |
}
|
|
395 |
|
|
396 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
382 |
397 |
|
383 |
|
mPoiX = rotatedTouchPoint.get1();
|
384 |
|
mPoiY = rotatedTouchPoint.get2();
|
385 |
|
mPoiZ = rotatedTouchPoint.get3();
|
|
398 |
private int retFaceRotationSign(int face)
|
|
399 |
{
|
|
400 |
return (face==BACK || face==RIGHT || face==TOP) ? 1:-1;
|
386 |
401 |
}
|
387 |
402 |
|
388 |
403 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
389 |
404 |
|
390 |
|
private void fillCamera()
|
|
405 |
private int retFaceXaxis(int face)
|
391 |
406 |
{
|
392 |
|
Static4D cameraPoint = new Static4D(0, 0, mCameraDistance, 0);
|
393 |
|
Static4D rotatedCamera= rotateVectorByInvertedQuat(cameraPoint, mQuatAccumulated);
|
|
407 |
switch(face)
|
|
408 |
{
|
|
409 |
case FRONT :
|
|
410 |
case BACK : return VECTX;
|
|
411 |
case LEFT :
|
|
412 |
case RIGHT : return VECTZ;
|
|
413 |
case TOP :
|
|
414 |
case BOTTOM: return VECTX;
|
|
415 |
}
|
394 |
416 |
|
395 |
|
mCamX = rotatedCamera.get1();
|
396 |
|
mCamY = rotatedCamera.get2();
|
397 |
|
mCamZ = rotatedCamera.get3();
|
|
417 |
return -1;
|
398 |
418 |
}
|
399 |
419 |
|
400 |
420 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
401 |
421 |
|
402 |
|
private float retA(int face, float cubeHalfSize)
|
|
422 |
private int retFaceYaxis(int face)
|
403 |
423 |
{
|
404 |
424 |
switch(face)
|
405 |
425 |
{
|
406 |
|
case FRONT : return ( mPoiZ!=mCamZ ? ( cubeHalfSize-mCamZ)/(mPoiZ-mCamZ) : 0f);
|
407 |
|
case BACK : return ( mPoiZ!=mCamZ ? (-cubeHalfSize-mCamZ)/(mPoiZ-mCamZ) : 0f);
|
408 |
|
case LEFT : return ( mPoiX!=mCamX ? (-cubeHalfSize-mCamX)/(mPoiX-mCamX) : 0f);
|
409 |
|
case RIGHT : return ( mPoiX!=mCamX ? ( cubeHalfSize-mCamX)/(mPoiX-mCamX) : 0f);
|
410 |
|
case TOP : return ( mPoiY!=mCamY ? ( cubeHalfSize-mCamY)/(mPoiY-mCamY) : 0f);
|
411 |
|
case BOTTOM: return ( mPoiY!=mCamY ? (-cubeHalfSize-mCamY)/(mPoiY-mCamY) : 0f);
|
|
426 |
case FRONT :
|
|
427 |
case BACK : return VECTY;
|
|
428 |
case LEFT :
|
|
429 |
case RIGHT : return VECTY;
|
|
430 |
case TOP :
|
|
431 |
case BOTTOM: return VECTZ;
|
412 |
432 |
}
|
413 |
433 |
|
414 |
|
return 0.0f;
|
|
434 |
return -1;
|
415 |
435 |
}
|
416 |
436 |
|
417 |
437 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
418 |
438 |
|
419 |
|
private boolean faceCondition(int face)
|
|
439 |
private int retFaceZaxis(int face)
|
420 |
440 |
{
|
421 |
441 |
switch(face)
|
422 |
442 |
{
|
423 |
443 |
case FRONT :
|
424 |
|
case BACK : return ( mPoiZ!=mCamZ );
|
|
444 |
case BACK : return VECTZ;
|
425 |
445 |
case LEFT :
|
426 |
|
case RIGHT : return ( mPoiX!=mCamX );
|
|
446 |
case RIGHT : return VECTX;
|
427 |
447 |
case TOP :
|
428 |
|
case BOTTOM: return ( mPoiY!=mCamY );
|
|
448 |
case BOTTOM: return VECTY;
|
429 |
449 |
}
|
430 |
450 |
|
431 |
|
return false;
|
|
451 |
return -1;
|
432 |
452 |
}
|
433 |
453 |
}
|
434 |
454 |
|
RubikApp: simplifications.