Revision 8be29dfc
Added by Leszek Koltunski over 6 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.