Revision 8be29dfc
Added by Leszek Koltunski over 5 years ago
src/main/java/org/distorted/examples/rubik/RubikRenderer.java | ||
---|---|---|
24 | 24 |
import android.graphics.Paint; |
25 | 25 |
import android.opengl.GLSurfaceView; |
26 | 26 |
|
27 |
import org.distorted.library.effect.EffectName; |
|
28 | 27 |
import org.distorted.library.effect.MatrixEffectMove; |
29 | 28 |
import org.distorted.library.effect.MatrixEffectQuaternion; |
29 |
import org.distorted.library.effect.MatrixEffectRotate; |
|
30 | 30 |
import org.distorted.library.effect.MatrixEffectScale; |
31 |
import org.distorted.library.effect.PostprocessEffectGlow; |
|
32 | 31 |
import org.distorted.library.effect.VertexEffectSink; |
33 | 32 |
import org.distorted.library.main.Distorted; |
34 | 33 |
import org.distorted.library.main.DistortedEffects; |
35 | 34 |
import org.distorted.library.main.DistortedScreen; |
36 | 35 |
import org.distorted.library.main.DistortedTexture; |
37 | 36 |
import org.distorted.library.mesh.MeshCubes; |
37 |
import org.distorted.library.type.Dynamic1D; |
|
38 | 38 |
import org.distorted.library.type.Static1D; |
39 | 39 |
import org.distorted.library.type.Static3D; |
40 | 40 |
import org.distorted.library.type.Static4D; |
... | ... | |
48 | 48 |
{ |
49 | 49 |
static final int NUM_CUBES = 3; |
50 | 50 |
private static final int SIZE = 200; |
51 |
|
|
52 | 51 |
private static final float CUBE_SCREEN_RATIO = 0.5f; |
53 | 52 |
|
53 |
private static final Static3D VectX = new Static3D(1,0,0); |
|
54 |
private static final Static3D VectY = new Static3D(0,1,0); |
|
55 |
private static final Static3D VectZ = new Static3D(0,0,1); |
|
56 |
|
|
54 | 57 |
private GLSurfaceView mView; |
55 | 58 |
private DistortedTexture mTexture; |
56 | 59 |
private DistortedScreen mScreen; |
57 | 60 |
private Static3D mMove, mScale, mCenter; |
58 | 61 |
private MeshCubes[][][] mCubes; |
59 | 62 |
private DistortedEffects[][][] mEffects; |
63 |
private Static4D[][][] mQuatScramble; |
|
64 |
private Static3D[][][] mRotationAxis; |
|
65 |
private Dynamic1D[][][] mRotationAngle; |
|
66 |
private Static1D mRotationAngleStatic; |
|
67 |
private int mRotAxis; |
|
68 |
private int mRotRow; |
|
60 | 69 |
|
61 | 70 |
private int mScreenWidth, mScreenHeight; |
62 |
private int mLastRow, mLastCol, mLastSli; |
|
63 |
|
|
64 |
private Static1D mGlowRadius; |
|
65 |
private Static4D mGlowColor; |
|
66 | 71 |
|
67 | 72 |
private Static4D mQuatCurrent, mQuatAccumulated; |
68 | 73 |
private Static4D mTempCurrent, mTempAccumulated; |
... | ... | |
86 | 91 |
mEffects = new DistortedEffects[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
87 | 92 |
Static3D[][][] cubeVectors = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
88 | 93 |
|
94 |
mQuatScramble = new Static4D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
95 |
mRotationAxis = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
96 |
mRotationAngle= new Dynamic1D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
97 |
|
|
89 | 98 |
float sinkDegree = 3.0f - 1.7f/NUM_CUBES; // f(1)=1.3, f(inf)=3 |
90 | 99 |
|
91 | 100 |
VertexEffectSink sink = new VertexEffectSink( new Static1D(sinkDegree), |
... | ... | |
95 | 104 |
mScale = new Static3D(1,1,1); |
96 | 105 |
mCenter= new Static3D(0,0,0); |
97 | 106 |
|
98 |
mLastRow = mLastCol = mLastSli = 0; |
|
99 |
|
|
100 |
mGlowRadius = new Static1D(5); |
|
101 |
mGlowColor = new Static4D(1.0f,1.0f,1.0f,0.6f); |
|
107 |
mRotationAngleStatic = new Static1D(0); |
|
108 |
mRotAxis= RubikSurfaceView.VECTN; |
|
102 | 109 |
|
103 | 110 |
MatrixEffectMove move = new MatrixEffectMove(mMove); |
104 | 111 |
MatrixEffectScale scale = new MatrixEffectScale(mScale); |
... | ... | |
143 | 150 |
tmpBottom= (y== 0 ? mapBottom:mapBlack); |
144 | 151 |
|
145 | 152 |
mCubes[x][y][z] = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom); |
146 |
|
|
147 | 153 |
cubeVectors[x][y][z] = new Static3D( SIZE*(x-nc), SIZE*(y-nc), SIZE*(z-nc) ); |
154 |
mQuatScramble[x][y][z] = new Static4D(0,0,0,1); |
|
155 |
mRotationAngle[x][y][z] = new Dynamic1D(); |
|
156 |
mRotationAxis[x][y][z] = new Static3D(1,0,0); |
|
148 | 157 |
|
149 | 158 |
mEffects[x][y][z] = new DistortedEffects(); |
150 | 159 |
mEffects[x][y][z].apply(sink); |
... | ... | |
152 | 161 |
mEffects[x][y][z].apply(scale); |
153 | 162 |
mEffects[x][y][z].apply(quat1); |
154 | 163 |
mEffects[x][y][z].apply(quat2); |
164 |
mEffects[x][y][z].apply( new MatrixEffectRotate( mRotationAngle[x][y][z], mRotationAxis[x][y][z], mCenter)); |
|
165 |
mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], mCenter)); |
|
155 | 166 |
mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) ); |
156 | 167 |
} |
157 | 168 |
} |
... | ... | |
242 | 253 |
mScreen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]); |
243 | 254 |
} |
244 | 255 |
|
245 |
PostprocessEffectGlow.enable(); |
|
246 | 256 |
VertexEffectSink.enable(); |
247 | 257 |
|
248 | 258 |
try |
... | ... | |
283 | 293 |
|
284 | 294 |
void addNewRotation(int vector, int row ) |
285 | 295 |
{ |
286 |
String vect="?";
|
|
296 |
Static3D axis = VectX;
|
|
287 | 297 |
|
288 | 298 |
switch(vector) |
289 | 299 |
{ |
290 |
case RubikSurfaceView.VECTX: vect="X"; break;
|
|
291 |
case RubikSurfaceView.VECTY: vect="Y"; break;
|
|
292 |
case RubikSurfaceView.VECTZ: vect="Z"; break;
|
|
300 |
case RubikSurfaceView.VECTX: axis = VectX; break;
|
|
301 |
case RubikSurfaceView.VECTY: axis = VectY; break;
|
|
302 |
case RubikSurfaceView.VECTZ: axis = VectZ; break;
|
|
293 | 303 |
} |
294 | 304 |
|
295 |
android.util.Log.e("rubik", "added new rotation (row="+row+" vector: "+vect+")"); |
|
305 |
mRotAxis = vector; |
|
306 |
mRotRow = row; |
|
307 |
|
|
308 |
mRotationAngleStatic.set1(0.0f); |
|
309 |
|
|
310 |
for(int x = 0; x< NUM_CUBES; x++) |
|
311 |
for(int y = 0; y< NUM_CUBES; y++) |
|
312 |
for(int z = 0; z< NUM_CUBES; z++) |
|
313 |
if( x==0 || x==NUM_CUBES-1 || y==0 || y==NUM_CUBES-1 || z==0 || z==NUM_CUBES-1 ) |
|
314 |
{ |
|
315 |
if( belongsToRotation(x,y,z,vector,row) ) |
|
316 |
{ |
|
317 |
mRotationAxis[x][y][z].set(axis); |
|
318 |
mRotationAngle[x][y][z].add(mRotationAngleStatic); |
|
319 |
} |
|
320 |
} |
|
296 | 321 |
} |
297 | 322 |
|
298 | 323 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
299 | 324 |
|
300 | 325 |
void continueRotation(float angle) |
301 | 326 |
{ |
302 |
android.util.Log.e("rubik", "rotating by angle: "+ (((float)((int)(angle*100.0f)))/100.0f) );
|
|
327 |
mRotationAngleStatic.set1(120.0f*angle/mScreenMin);
|
|
303 | 328 |
} |
304 | 329 |
|
305 | 330 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
306 | 331 |
|
307 | 332 |
void finishRotation() |
308 | 333 |
{ |
309 |
android.util.Log.e("rubik", "finishing rotation"); |
|
310 |
} |
|
334 |
float nearestAngle = (mRotationAngleStatic.get1()+45.0f)/90.0f; |
|
335 |
if( nearestAngle<0 ) nearestAngle-=1.0f; |
|
336 |
int nearestAngleInDegrees = 90*(4-((int)nearestAngle+4)%4); |
|
337 |
double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180; |
|
338 |
float sinA = (float)Math.sin(nearestAngleInRadians*0.5); |
|
339 |
float cosA = (float)Math.cos(nearestAngleInRadians*0.5); |
|
311 | 340 |
|
312 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
341 |
mRotationAngleStatic.set1(0);
|
|
313 | 342 |
|
314 |
float getScreenWidth() |
|
315 |
{ |
|
316 |
return mScreenWidth; |
|
343 |
float qx=0,qy=0,qz=0; |
|
344 |
|
|
345 |
switch(mRotAxis) |
|
346 |
{ |
|
347 |
case RubikSurfaceView.VECTX: qx=1; break; |
|
348 |
case RubikSurfaceView.VECTY: qy=1; break; |
|
349 |
case RubikSurfaceView.VECTZ: qz=1; break; |
|
350 |
} |
|
351 |
|
|
352 |
Static4D quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA); |
|
353 |
|
|
354 |
for(int x = 0; x< NUM_CUBES; x++) |
|
355 |
for(int y = 0; y< NUM_CUBES; y++) |
|
356 |
for(int z = 0; z< NUM_CUBES; z++) |
|
357 |
if( x==0 || x==NUM_CUBES-1 || y==0 || y==NUM_CUBES-1 || z==0 || z==NUM_CUBES-1 ) |
|
358 |
{ |
|
359 |
if( belongsToRotation(x,y,z,mRotAxis,mRotRow) ) |
|
360 |
{ |
|
361 |
mRotationAngle[x][y][z].removeAll(); |
|
362 |
mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z])); |
|
363 |
} |
|
364 |
} |
|
317 | 365 |
} |
318 | 366 |
|
319 | 367 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
320 | 368 |
|
321 |
float getScreenHeight()
|
|
369 |
private boolean belongsToRotation(int x, int y, int z, int vector, int row)
|
|
322 | 370 |
{ |
323 |
return mScreenHeight; |
|
371 |
switch(vector) |
|
372 |
{ |
|
373 |
case RubikSurfaceView.VECTX: return x==row; |
|
374 |
case RubikSurfaceView.VECTY: return y==row; |
|
375 |
case RubikSurfaceView.VECTZ: return z==row; |
|
376 |
} |
|
377 |
|
|
378 |
return false; |
|
324 | 379 |
} |
325 | 380 |
|
326 | 381 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
327 | 382 |
|
328 |
void abortLastEffect()
|
|
383 |
float getScreenWidth()
|
|
329 | 384 |
{ |
330 |
mEffects[mLastCol][mLastRow][mLastSli].abortByName(EffectName.GLOW);
|
|
385 |
return mScreenWidth;
|
|
331 | 386 |
} |
332 | 387 |
|
333 | 388 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
334 | 389 |
|
335 |
void applyNewEffect(int col, int row, int sli)
|
|
390 |
float getScreenHeight()
|
|
336 | 391 |
{ |
337 |
mLastCol = col; |
|
338 |
mLastRow = row; |
|
339 |
mLastSli = sli; |
|
340 |
|
|
341 |
mEffects[mLastCol][mLastRow][mLastSli].apply(new PostprocessEffectGlow(mGlowRadius,mGlowColor)); |
|
392 |
return mScreenHeight; |
|
342 | 393 |
} |
343 | 394 |
|
344 | 395 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java | ||
---|---|---|
51 | 51 |
|
52 | 52 |
private boolean mDragging, mRotating; |
53 | 53 |
private int mX, mY; |
54 |
private int mTouchedRow, mTouchedCol, mTouchedSli; |
|
55 | 54 |
private Static4D mQuatCurrent, mQuatAccumulated; |
56 | 55 |
private int mRotationVect; |
57 | 56 |
private RubikRenderer mRenderer; |
... | ... | |
106 | 105 |
|
107 | 106 |
if( mLastTouchedFace != NONE ) |
108 | 107 |
{ |
109 |
mRenderer.abortLastEffect(); |
|
110 |
mRenderer.applyNewEffect(mTouchedCol, mTouchedRow, mTouchedSli); |
|
111 | 108 |
mRotating = true; |
112 | 109 |
} |
113 | 110 |
else |
... | ... | |
127 | 124 |
if( (mX-x)*(mX-x)+(mY-y)*(mY-y)>minimumToRotate ) |
128 | 125 |
{ |
129 | 126 |
addNewRotation(x,y); |
127 |
mX = x; |
|
128 |
mY = y; |
|
130 | 129 |
mRotating = false; |
131 | 130 |
} |
132 | 131 |
} |
... | ... | |
207 | 206 |
{ |
208 | 207 |
fillTouchPoint(x,y); |
209 | 208 |
|
210 |
float angle=0.0f;
|
|
209 |
int sign=1;
|
|
211 | 210 |
float cubeHalfSize= mRenderer.returnCubeSize()*0.5f; |
212 | 211 |
float A=retA(mLastTouchedFace,cubeHalfSize); |
213 | 212 |
|
... | ... | |
219 | 218 |
{ |
220 | 219 |
case VECTX: switch(mLastTouchedFace) |
221 | 220 |
{ |
222 |
case FRONT : angle = returnAngle(-diffZ, diffY); break;
|
|
223 |
case BACK : angle = returnAngle( diffZ,-diffY); break;
|
|
224 |
case TOP : angle = returnAngle(-diffY,-diffZ); break;
|
|
225 |
case BOTTOM: angle = returnAngle( diffY, diffZ); break;
|
|
221 |
case FRONT : sign = returnSign(-diffY); break;
|
|
222 |
case BACK : sign = returnSign( diffY); break;
|
|
223 |
case TOP : sign = returnSign( diffZ); break;
|
|
224 |
case BOTTOM: sign = returnSign(-diffZ); break;
|
|
226 | 225 |
} |
227 | 226 |
break; |
228 | 227 |
case VECTY: switch(mLastTouchedFace) |
229 | 228 |
{ |
230 |
case FRONT : angle = returnAngle(-diffZ, diffX); break;
|
|
231 |
case BACK : angle = returnAngle( diffZ,-diffX); break;
|
|
232 |
case LEFT : angle = returnAngle( diffX, diffZ); break;
|
|
233 |
case RIGHT : angle = returnAngle(-diffX,-diffZ); break;
|
|
229 |
case FRONT : sign = returnSign( diffX); break;
|
|
230 |
case BACK : sign = returnSign(-diffX); break;
|
|
231 |
case LEFT : sign = returnSign( diffZ); break;
|
|
232 |
case RIGHT : sign = returnSign(-diffZ); break;
|
|
234 | 233 |
} |
235 | 234 |
break; |
236 | 235 |
case VECTZ: switch(mLastTouchedFace) |
237 | 236 |
{ |
238 |
case TOP : angle = returnAngle( diffY, diffX); break;
|
|
239 |
case BOTTOM: angle = returnAngle(-diffY,-diffX); break;
|
|
240 |
case LEFT : angle = returnAngle(-diffX, diffY); break;
|
|
241 |
case RIGHT : angle = returnAngle( diffX,-diffY); break;
|
|
237 |
case TOP : sign = returnSign(-diffX); break;
|
|
238 |
case BOTTOM: sign = returnSign( diffX); break;
|
|
239 |
case LEFT : sign = returnSign(-diffY); break;
|
|
240 |
case RIGHT : sign = returnSign( diffY); break;
|
|
242 | 241 |
} |
243 | 242 |
break; |
244 | 243 |
default : android.util.Log.e("View", "impossible vector: "+mRotationVect); |
245 | 244 |
} |
246 | 245 |
|
247 |
mRenderer.continueRotation(angle); |
|
246 |
float dX = mX-x; |
|
247 |
float dY = mY-y; |
|
248 |
float calibration = (float)Math.sqrt(dX*dX+dY*dY); |
|
249 |
|
|
250 |
mRenderer.continueRotation(calibration*sign); |
|
248 | 251 |
} |
249 | 252 |
|
250 | 253 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
258 | 261 |
|
259 | 262 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
260 | 263 |
|
261 |
private float returnAngle(float diff1, float diff2)
|
|
264 |
private int returnSign(float diff)
|
|
262 | 265 |
{ |
263 |
float len = (float)Math.sqrt(diff1*diff1 + diff2*diff2); |
|
264 |
len /= mRenderer.mScreenMin; |
|
265 |
|
|
266 |
return diff2>0 ? len : -len; |
|
266 |
return diff>0 ? 1 : -1; |
|
267 | 267 |
} |
268 | 268 |
|
269 | 269 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
277 | 277 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
278 | 278 |
// return quat1*quat2 |
279 | 279 |
|
280 |
private Static4D quatMultiply( Static4D quat1, Static4D quat2 )
|
|
280 |
static Static4D quatMultiply( Static4D quat1, Static4D quat2 )
|
|
281 | 281 |
{ |
282 | 282 |
float qx = quat1.get1(); |
283 | 283 |
float qy = quat1.get2(); |
... | ... | |
403 | 403 |
float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize); |
404 | 404 |
float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize); |
405 | 405 |
|
406 |
if( qX==1.0f ) qX-= 0.5f/RubikRenderer.NUM_CUBES; |
|
407 |
if( qY==1.0f ) qY-= 0.5f/RubikRenderer.NUM_CUBES; |
|
408 |
if( qZ==1.0f ) qZ-= 0.5f/RubikRenderer.NUM_CUBES; |
|
409 |
|
|
410 |
if( qX<1 && qX>=0 && qY<1 && qY>=0 && qZ<1 && qZ>=0 ) |
|
411 |
{ |
|
412 |
mTouchedCol = (int)(qX*RubikRenderer.NUM_CUBES); |
|
413 |
mTouchedRow = (int)(qY*RubikRenderer.NUM_CUBES); |
|
414 |
mTouchedSli = (int)(qZ*RubikRenderer.NUM_CUBES); |
|
415 |
return face; |
|
416 |
} |
|
406 |
if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return face; |
|
417 | 407 |
} |
418 | 408 |
} |
419 | 409 |
|
420 |
mTouchedRow = -1; |
|
421 |
mTouchedCol = -1; |
|
422 |
mTouchedSli = -1; |
|
423 |
|
|
424 | 410 |
return NONE; |
425 | 411 |
} |
426 | 412 |
|
Also available in: Unified diff
Improve the Rubik App - beginnings of rotation.