25 |
25 |
import android.opengl.GLSurfaceView;
|
26 |
26 |
import android.view.MotionEvent;
|
27 |
27 |
|
|
28 |
import org.distorted.library.type.Static3D;
|
28 |
29 |
import org.distorted.library.type.Static4D;
|
29 |
30 |
|
30 |
31 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
31 |
32 |
|
32 |
33 |
class RubikSurfaceView extends GLSurfaceView
|
33 |
34 |
{
|
34 |
|
private final static int NONE =-1;
|
|
35 |
private final static int NONE =-1;
|
35 |
36 |
private final static int FRONT = 0;
|
36 |
37 |
private final static int BACK = 1;
|
37 |
38 |
private final static int LEFT = 2;
|
... | ... | |
39 |
40 |
private final static int TOP = 4;
|
40 |
41 |
private final static int BOTTOM = 5;
|
41 |
42 |
|
42 |
|
private boolean mDragging;
|
|
43 |
private static final int DIR_UP =0;
|
|
44 |
private static final int DIR_DOWN =1;
|
|
45 |
private static final int DIR_LEFT =2;
|
|
46 |
private static final int DIR_RIGHT=3;
|
|
47 |
|
|
48 |
private static final Static3D VECTX = new Static3D(1,0,0);
|
|
49 |
private static final Static3D VECTY = new Static3D(0,1,0);
|
|
50 |
private static final Static3D VECTZ = new Static3D(0,0,1);
|
|
51 |
|
|
52 |
private boolean mDragging, mRotating;
|
43 |
53 |
private int mX, mY;
|
44 |
54 |
private int mTouchedRow, mTouchedCol, mTouchedSli;
|
45 |
55 |
private Static4D mQuatCurrent, mQuatAccumulated;
|
46 |
56 |
private RubikRenderer mRenderer;
|
47 |
57 |
|
|
58 |
private float mPoiX, mPoiY, mPoiZ, mCamX, mCamY, mCamZ;
|
|
59 |
private float mStartX, mStartY, mStartZ;
|
|
60 |
private int mLastTouchedFace;
|
|
61 |
|
48 |
62 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
49 |
63 |
|
50 |
64 |
public RubikSurfaceView(Context context)
|
... | ... | |
52 |
66 |
super(context);
|
53 |
67 |
|
54 |
68 |
mDragging = false;
|
|
69 |
mRotating = false;
|
55 |
70 |
mRenderer = new RubikRenderer(this);
|
56 |
71 |
|
57 |
72 |
mQuatCurrent = new Static4D(0,0,0,1);
|
... | ... | |
81 |
96 |
|
82 |
97 |
switch(action)
|
83 |
98 |
{
|
84 |
|
case MotionEvent.ACTION_DOWN: if( faceTouched(x,y) != NONE )
|
|
99 |
case MotionEvent.ACTION_DOWN: mX = x;
|
|
100 |
mY = y;
|
|
101 |
|
|
102 |
mLastTouchedFace = faceTouched(x,y);
|
|
103 |
|
|
104 |
if( mLastTouchedFace != NONE )
|
85 |
105 |
{
|
86 |
106 |
mRenderer.abortLastEffect();
|
87 |
107 |
mRenderer.applyNewEffect(mTouchedCol, mTouchedRow, mTouchedSli);
|
|
108 |
mRotating = true;
|
88 |
109 |
}
|
89 |
110 |
else
|
90 |
111 |
{
|
91 |
|
mX = x;
|
92 |
|
mY = y;
|
93 |
112 |
mDragging = true;
|
94 |
113 |
}
|
95 |
114 |
break;
|
... | ... | |
98 |
117 |
mQuatCurrent.set(quatFromDrag(mX-x,mY-y));
|
99 |
118 |
mRenderer.setQuatCurrent(mQuatCurrent);
|
100 |
119 |
}
|
|
120 |
else if( mRotating )
|
|
121 |
{
|
|
122 |
int minimumToRotate = (mRenderer.mScreenMin*mRenderer.mScreenMin)/36;
|
|
123 |
|
|
124 |
if( (mX-x)*(mX-x)+(mY-y)*(mY-y)>minimumToRotate )
|
|
125 |
{
|
|
126 |
rotateFace(x,y);
|
|
127 |
mRotating = false;
|
|
128 |
}
|
|
129 |
}
|
101 |
130 |
break;
|
102 |
131 |
case MotionEvent.ACTION_UP : mDragging = false;
|
|
132 |
mRotating = false;
|
|
133 |
|
103 |
134 |
mQuatAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated));
|
104 |
135 |
mQuatCurrent.set(0f, 0f, 0f, 1f);
|
105 |
|
|
106 |
136 |
mRenderer.setQuatCurrent(mQuatCurrent);
|
107 |
137 |
mRenderer.setQuatAccumulated(mQuatAccumulated);
|
108 |
138 |
break;
|
... | ... | |
111 |
141 |
return true;
|
112 |
142 |
}
|
113 |
143 |
|
|
144 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
145 |
|
|
146 |
private void rotateFace(int x, int y)
|
|
147 |
{
|
|
148 |
fillCameraAndTouchPoint(x,y);
|
|
149 |
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
|
|
150 |
float A=0f;
|
|
151 |
|
|
152 |
switch(mLastTouchedFace)
|
|
153 |
{
|
|
154 |
case FRONT : A = ( mPoiZ!=mCamZ ? ( cubeHalfSize-mCamZ)/(mPoiZ-mCamZ) : 0f); break;
|
|
155 |
case BACK : A = ( mPoiZ!=mCamZ ? (-cubeHalfSize-mCamZ)/(mPoiZ-mCamZ) : 0f); break;
|
|
156 |
case LEFT : A = ( mPoiX!=mCamX ? (-cubeHalfSize-mCamX)/(mPoiX-mCamX) : 0f); break;
|
|
157 |
case RIGHT : A = ( mPoiX!=mCamX ? ( cubeHalfSize-mCamX)/(mPoiX-mCamX) : 0f); break;
|
|
158 |
case TOP : A = ( mPoiY!=mCamY ? ( cubeHalfSize-mCamY)/(mPoiY-mCamY) : 0f); break;
|
|
159 |
case BOTTOM: A = ( mPoiY!=mCamY ? (-cubeHalfSize-mCamY)/(mPoiY-mCamY) : 0f); break;
|
|
160 |
}
|
|
161 |
float diffX = (mPoiX-mCamX)*A + mCamX - mStartX;
|
|
162 |
float diffY = (mPoiY-mCamY)*A + mCamY - mStartY;
|
|
163 |
float diffZ = (mPoiZ-mCamZ)*A + mCamZ - mStartZ;
|
|
164 |
|
|
165 |
Static3D rotV=VECTX;
|
|
166 |
int dir, rotA =1, rotRC=1;
|
|
167 |
|
|
168 |
switch(mLastTouchedFace)
|
|
169 |
{
|
|
170 |
case FRONT : dir = retDirection( diffX, diffY);
|
|
171 |
rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTY;
|
|
172 |
rotA = (dir==DIR_UP || dir==DIR_LEFT) ? -90:90;
|
|
173 |
rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
|
|
174 |
break;
|
|
175 |
case BACK : dir = retDirection(-diffX, diffY);
|
|
176 |
rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTY;
|
|
177 |
rotA = (dir==DIR_UP || dir==DIR_RIGHT) ? 90:-90;
|
|
178 |
rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
|
|
179 |
break;
|
|
180 |
case LEFT : dir = retDirection( diffZ, diffY);
|
|
181 |
rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTZ:VECTY;
|
|
182 |
rotA = (dir==DIR_UP || dir==DIR_LEFT) ? -90:90;
|
|
183 |
rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTZ?mStartZ:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
|
|
184 |
break;
|
|
185 |
case RIGHT : dir = retDirection(-diffZ, diffY);
|
|
186 |
rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTZ:VECTY;
|
|
187 |
rotA = (dir==DIR_UP || dir==DIR_RIGHT) ? 90:-90;
|
|
188 |
rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTZ?mStartZ:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
|
|
189 |
break;
|
|
190 |
case TOP : dir = retDirection( diffX,-diffZ);
|
|
191 |
rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTZ;
|
|
192 |
rotA = (dir==DIR_UP || dir==DIR_RIGHT) ? -90:90;
|
|
193 |
rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartZ)+cubeHalfSize)/(2*cubeHalfSize) );
|
|
194 |
break;
|
|
195 |
case BOTTOM: dir = retDirection( diffX, diffZ);
|
|
196 |
rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTZ;
|
|
197 |
rotA = (dir==DIR_UP || dir==DIR_LEFT) ? -90:90;
|
|
198 |
rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartZ)+cubeHalfSize)/(2*cubeHalfSize) );
|
|
199 |
break;
|
|
200 |
}
|
|
201 |
|
|
202 |
//if( rotRC==cubeHalfSize+1 ) rotRC=cubeHalfSize;
|
|
203 |
|
|
204 |
String vect = (rotV==VECTX ? "X" : (rotV==VECTY? "Y":"Z") );
|
|
205 |
|
|
206 |
android.util.Log.e("rubik", "rotating by "+rotA+" degrees, face="+rotRC+" vector: "+vect);
|
|
207 |
}
|
|
208 |
|
|
209 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
210 |
|
|
211 |
private int retDirection(float a, float b)
|
|
212 |
{
|
|
213 |
if( b>a ) return a>-b ? DIR_UP :DIR_LEFT;
|
|
214 |
else return a>-b ? DIR_RIGHT:DIR_DOWN;
|
|
215 |
}
|
|
216 |
|
114 |
217 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
115 |
218 |
// return quat1*quat2
|
116 |
219 |
|
... | ... | |
221 |
324 |
|
222 |
325 |
private int faceTouched(int xTouch, int yTouch)
|
223 |
326 |
{
|
224 |
|
float cameraDistance = mRenderer.returnCameraDistance();
|
225 |
|
float halfScrWidth = mRenderer.getScreenWidth()*0.5f;
|
226 |
|
float halfScrHeight = mRenderer.getScreenHeight()*0.5f;
|
227 |
|
float cubeHalfSize = mRenderer.returnCubeSize()*0.5f;
|
|
327 |
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
|
228 |
328 |
|
229 |
|
Static4D cameraPoint = new Static4D( 0, 0, cameraDistance, 0);
|
230 |
|
Static4D touchPoint = new Static4D(xTouch-halfScrWidth, halfScrHeight-yTouch, 0, 0);
|
231 |
|
|
232 |
|
Static4D rotatedCamera = rotateVector(cameraPoint);
|
233 |
|
Static4D rotatedTouchPoint= rotateVector(touchPoint);
|
234 |
|
|
235 |
|
float camX = rotatedCamera.get1();
|
236 |
|
float camY = rotatedCamera.get2();
|
237 |
|
float camZ = rotatedCamera.get3();
|
238 |
|
|
239 |
|
float poiX = rotatedTouchPoint.get1();
|
240 |
|
float poiY = rotatedTouchPoint.get2();
|
241 |
|
float poiZ = rotatedTouchPoint.get3();
|
|
329 |
fillCameraAndTouchPoint(xTouch,yTouch);
|
242 |
330 |
|
243 |
331 |
if( faceIsVisible(FRONT) )
|
244 |
332 |
{
|
245 |
|
if( poiZ!= camZ )
|
|
333 |
if( mPoiZ!= mCamZ )
|
246 |
334 |
{
|
247 |
|
float A = (cubeHalfSize-camZ)/(poiZ-camZ);
|
248 |
|
float X = (poiX-camX)*A + camX;
|
249 |
|
float Y = (poiY-camY)*A + camY;
|
250 |
|
float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
|
251 |
|
float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
|
|
335 |
float A = (cubeHalfSize-mCamZ)/(mPoiZ-mCamZ);
|
|
336 |
mStartX = (mPoiX-mCamX)*A + mCamX;
|
|
337 |
mStartY = (mPoiY-mCamY)*A + mCamY;
|
|
338 |
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
339 |
float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
|
|
340 |
float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
|
252 |
341 |
|
253 |
342 |
if( qX<=1 && qX>=0 && qY<=1 && qY>=0 )
|
254 |
343 |
{
|
... | ... | |
261 |
350 |
}
|
262 |
351 |
if( faceIsVisible(BACK) )
|
263 |
352 |
{
|
264 |
|
if( poiZ!= camZ )
|
|
353 |
if( mPoiZ!= mCamZ )
|
265 |
354 |
{
|
266 |
|
float A = (-cubeHalfSize-camZ)/(poiZ-camZ);
|
267 |
|
float X = (poiX-camX)*A + camX;
|
268 |
|
float Y = (poiY-camY)*A + camY;
|
269 |
|
float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
|
270 |
|
float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
|
|
355 |
float A = (-cubeHalfSize-mCamZ)/(mPoiZ-mCamZ);
|
|
356 |
mStartX = (mPoiX-mCamX)*A + mCamX;
|
|
357 |
mStartY = (mPoiY-mCamY)*A + mCamY;
|
|
358 |
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
359 |
float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
|
|
360 |
float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
|
271 |
361 |
|
272 |
362 |
if( qX<=1 && qX>=0 && qY<=1 && qY>=0 )
|
273 |
363 |
{
|
... | ... | |
280 |
370 |
}
|
281 |
371 |
if( faceIsVisible(LEFT) )
|
282 |
372 |
{
|
283 |
|
if( poiX!= camX )
|
|
373 |
if( mPoiX!= mCamX )
|
284 |
374 |
{
|
285 |
|
float A = (-cubeHalfSize-camX)/(poiX-camX);
|
286 |
|
float Y = (poiY-camY)*A + camY;
|
287 |
|
float Z = (poiZ-camZ)*A + camZ;
|
288 |
|
float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
|
289 |
|
float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
|
|
375 |
float A = (-cubeHalfSize-mCamX)/(mPoiX-mCamX);
|
|
376 |
mStartX = (mPoiX-mCamX)*A + mCamX;
|
|
377 |
mStartY = (mPoiY-mCamY)*A + mCamY;
|
|
378 |
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
379 |
float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
|
|
380 |
float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
|
290 |
381 |
|
291 |
382 |
if( qZ<=1 && qZ>=0 && qY<=1 && qY>=0 )
|
292 |
383 |
{
|
... | ... | |
299 |
390 |
}
|
300 |
391 |
if( faceIsVisible(RIGHT) )
|
301 |
392 |
{
|
302 |
|
if( poiX!= camX )
|
|
393 |
if( mPoiX!= mCamX )
|
303 |
394 |
{
|
304 |
|
float A = (cubeHalfSize-camX)/(poiX-camX);
|
305 |
|
float Y = (poiY-camY)*A + camY;
|
306 |
|
float Z = (poiZ-camZ)*A + camZ;
|
307 |
|
float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
|
308 |
|
float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
|
|
395 |
float A = (cubeHalfSize-mCamX)/(mPoiX-mCamX);
|
|
396 |
mStartX = (mPoiX-mCamX)*A + mCamX;
|
|
397 |
mStartY = (mPoiY-mCamY)*A + mCamY;
|
|
398 |
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
399 |
float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
|
|
400 |
float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
|
309 |
401 |
|
310 |
402 |
if( qZ<=1 && qZ>=0 && qY<=1 && qY>=0 )
|
311 |
403 |
{
|
... | ... | |
318 |
410 |
}
|
319 |
411 |
if( faceIsVisible(TOP) )
|
320 |
412 |
{
|
321 |
|
if( poiY!= camY )
|
|
413 |
if( mPoiY!= mCamY )
|
322 |
414 |
{
|
323 |
|
float A = (cubeHalfSize-camY)/(poiY-camY);
|
324 |
|
float X = (poiX-camX)*A + camX;
|
325 |
|
float Z = (poiZ-camZ)*A + camZ;
|
326 |
|
float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
|
327 |
|
float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
|
|
415 |
float A = (cubeHalfSize-mCamY)/(mPoiY-mCamY);
|
|
416 |
mStartX = (mPoiX-mCamX)*A + mCamX;
|
|
417 |
mStartY = (mPoiY-mCamY)*A + mCamY;
|
|
418 |
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
419 |
float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
|
|
420 |
float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
|
328 |
421 |
|
329 |
422 |
if( qZ<=1 && qZ>=0 && qX<=1 && qX>=0 )
|
330 |
423 |
{
|
... | ... | |
337 |
430 |
}
|
338 |
431 |
if( faceIsVisible(BOTTOM) )
|
339 |
432 |
{
|
340 |
|
if( poiY!= camY )
|
|
433 |
if( mPoiY!= mCamY )
|
341 |
434 |
{
|
342 |
|
float A = (-cubeHalfSize-camY)/(poiY-camY);
|
343 |
|
float X = (poiX-camX)*A + camX;
|
344 |
|
float Z = (poiZ-camZ)*A + camZ;
|
345 |
|
float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
|
346 |
|
float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
|
|
435 |
float A = (-cubeHalfSize-mCamY)/(mPoiY-mCamY);
|
|
436 |
mStartX = (mPoiX-mCamX)*A + mCamX;
|
|
437 |
mStartY = (mPoiY-mCamY)*A + mCamY;
|
|
438 |
mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
|
|
439 |
float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
|
|
440 |
float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
|
347 |
441 |
|
348 |
442 |
if( qZ<=1 && qZ>=0 && qX<=1 && qX>=0 )
|
349 |
443 |
{
|
... | ... | |
361 |
455 |
|
362 |
456 |
return NONE;
|
363 |
457 |
}
|
|
458 |
|
|
459 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
460 |
|
|
461 |
void fillCameraAndTouchPoint(int x, int y)
|
|
462 |
{
|
|
463 |
float cameraDistance = mRenderer.returnCameraDistance();
|
|
464 |
float halfScrWidth = mRenderer.getScreenWidth()*0.5f;
|
|
465 |
float halfScrHeight = mRenderer.getScreenHeight()*0.5f;
|
|
466 |
|
|
467 |
Static4D cameraPoint = new Static4D( 0, 0, cameraDistance, 0);
|
|
468 |
Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
|
|
469 |
|
|
470 |
Static4D rotatedCamera = rotateVector(cameraPoint);
|
|
471 |
Static4D rotatedTouchPoint= rotateVector(touchPoint);
|
|
472 |
|
|
473 |
mCamX = rotatedCamera.get1();
|
|
474 |
mCamY = rotatedCamera.get2();
|
|
475 |
mCamZ = rotatedCamera.get3();
|
|
476 |
|
|
477 |
mPoiX = rotatedTouchPoint.get1();
|
|
478 |
mPoiY = rotatedTouchPoint.get2();
|
|
479 |
mPoiZ = rotatedTouchPoint.get3();
|
|
480 |
}
|
364 |
481 |
}
|
365 |
482 |
|
Improve the Rubik App.