Project

General

Profile

Download (25 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / object / RubikCube.java @ 775e675d

1 0c52af30 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4 fdec60a3 Leszek Koltunski
// This file is part of Magic Cube.                                                              //
5 0c52af30 Leszek Koltunski
//                                                                                               //
6 fdec60a3 Leszek Koltunski
// Magic Cube is free software: you can redistribute it and/or modify                            //
7 0c52af30 Leszek Koltunski
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11 fdec60a3 Leszek Koltunski
// Magic Cube is distributed in the hope that it will be useful,                                 //
12 0c52af30 Leszek Koltunski
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17 fdec60a3 Leszek Koltunski
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18 0c52af30 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20 beb325a0 Leszek Koltunski
package org.distorted.object;
21 0c52af30 Leszek Koltunski
22
import android.graphics.Bitmap;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25
26 434f2f5a Leszek Koltunski
import org.distorted.library.effect.Effect;
27 0c52af30 Leszek Koltunski
import org.distorted.library.effect.MatrixEffectMove;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.effect.MatrixEffectRotate;
30
import org.distorted.library.effect.MatrixEffectScale;
31
import org.distorted.library.effect.VertexEffectSink;
32
import org.distorted.library.main.DistortedEffects;
33 34998c9d Leszek Koltunski
import org.distorted.library.main.DistortedNode;
34 0c52af30 Leszek Koltunski
import org.distorted.library.main.DistortedTexture;
35
import org.distorted.library.mesh.MeshCubes;
36 39fb9047 Leszek Koltunski
import org.distorted.library.mesh.MeshFlat;
37 0c52af30 Leszek Koltunski
import org.distorted.library.message.EffectListener;
38
import org.distorted.library.type.Dynamic1D;
39
import org.distorted.library.type.Static1D;
40
import org.distorted.library.type.Static3D;
41
import org.distorted.library.type.Static4D;
42 beb325a0 Leszek Koltunski
import org.distorted.magic.RubikSurfaceView;
43 0c52af30 Leszek Koltunski
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45
46 9208e27b Leszek Koltunski
public class RubikCube extends DistortedNode
47 0c52af30 Leszek Koltunski
{
48 775e675d Leszek Koltunski
            static final float CUBE_SCREEN_RATIO = 0.5f;
49 0c52af30 Leszek Koltunski
    private static final int POST_ROTATION_MILLISEC = 500;
50
    private static final int TEXTURE_SIZE = 100;
51
52
    private static final Static3D VectX = new Static3D(1,0,0);
53
    private static final Static3D VectY = new Static3D(0,1,0);
54
    private static final Static3D VectZ = new Static3D(0,0,1);
55
56 e8764a49 Leszek Koltunski
    public static final int VECTX = 0;  //
57
    public static final int VECTY = 1;  // don't change this
58
    public static final int VECTZ = 2;  //
59
60 34998c9d Leszek Koltunski
    private DistortedNode[][][] mNodes;
61 0c52af30 Leszek Koltunski
    private MeshCubes[][][] mCubes;
62
    private DistortedEffects[][][] mEffects;
63
    private Static4D[][][] mQuatScramble;
64
    private Static3D[][][] mRotationAxis;
65
    private Dynamic1D[][][] mRotationAngle;
66
    private Static3D[][][] mCurrentPosition;
67 434f2f5a Leszek Koltunski
    private MatrixEffectRotate[][][] mRotateEffect;
68 0c52af30 Leszek Koltunski
    private Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
69 9208e27b Leszek Koltunski
    private Static3D mMove, mScale, mNodeMove, mNodeScale;
70 47ba5ddc Leszek Koltunski
    private Static4D mQuatAccumulated;
71 0c52af30 Leszek Koltunski
    private DistortedTexture mTexture;
72
73
    private int mRotAxis, mRotRow;
74
    private int mSize;
75
76 9208e27b Leszek Koltunski
    private DistortedTexture mNodeTexture;
77 0c52af30 Leszek Koltunski
78 05fa94d9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
79
80 47ba5ddc Leszek Koltunski
    private int computeNearestAngle(float angle)
81 05fa94d9 Leszek Koltunski
      {
82 47ba5ddc Leszek Koltunski
      final int NEAREST = 90;
83 05fa94d9 Leszek Koltunski
84 47ba5ddc Leszek Koltunski
      int tmp = (int)((angle+NEAREST/2)/NEAREST);
85 beb325a0 Leszek Koltunski
      if( angle< -(NEAREST*0.5) ) tmp-=1;
86 05fa94d9 Leszek Koltunski
87 47ba5ddc Leszek Koltunski
      return NEAREST*tmp;
88 05fa94d9 Leszek Koltunski
      }
89
90 0c52af30 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
91 47ba5ddc Leszek Koltunski
// All legal rotation quats must have all four of their components equal to either
92
// 0, 1, -1, 0.5, -0.5 or +-sqrt(2)/2.
93
//
94
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
95
// correct the value of the 'scramble' quat to what it should be.
96
//
97
// We also have to remember that the group of unit quaternions is a double-cover of rotations
98
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
99 0c52af30 Leszek Koltunski
100 47ba5ddc Leszek Koltunski
    private static final float SQ2 = 0.5f*((float)Math.sqrt(2));
101
    private static final float[] LEGAL = { 0.0f , 0.5f , -0.5f , 1.0f , -1.0f , SQ2 , -SQ2 };
102
103
    private void normalizeScrambleQuat(int i, int j, int k)
104 0c52af30 Leszek Koltunski
      {
105 47ba5ddc Leszek Koltunski
      Static4D quat = mQuatScramble[i][j][k];
106 34998c9d Leszek Koltunski
107 47ba5ddc Leszek Koltunski
      float x = quat.get1();
108
      float y = quat.get2();
109
      float z = quat.get3();
110
      float w = quat.get4();
111
      float diff;
112 434f2f5a Leszek Koltunski
113 47ba5ddc Leszek Koltunski
      for(float legal: LEGAL)
114
        {
115
        diff = x-legal;
116
        if( diff*diff<0.01f ) x = legal;
117
        diff = y-legal;
118
        if( diff*diff<0.01f ) y = legal;
119
        diff = z-legal;
120
        if( diff*diff<0.01f ) z = legal;
121
        diff = w-legal;
122
        if( diff*diff<0.01f ) w = legal;
123
        }
124
125
      if( w<0 )
126
        {
127
        w = -w;
128
        z = -z;
129
        y = -y;
130
        x = -x;
131
        }
132
      else if( w==0 )
133
        {
134
        if( z<0 )
135
          {
136
          z = -z;
137
          y = -y;
138
          x = -x;
139
          }
140
        else if( z==0 )
141
          {
142
          if( y<0 )
143 434f2f5a Leszek Koltunski
            {
144 47ba5ddc Leszek Koltunski
            y = -y;
145
            x = -x;
146
            }
147
          else if( y==0 )
148
            {
149
            if( x<0 )
150 434f2f5a Leszek Koltunski
              {
151 47ba5ddc Leszek Koltunski
              x = -x;
152 9208e27b Leszek Koltunski
              }
153
            }
154 47ba5ddc Leszek Koltunski
          }
155
        }
156 584f7954 Leszek Koltunski
157 47ba5ddc Leszek Koltunski
      mQuatScramble[i][j][k].set(x,y,z,w);
158 584f7954 Leszek Koltunski
      }
159
160 30b68322 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
161
162 47ba5ddc Leszek Koltunski
    private float getSinkStrength()
163 30b68322 Leszek Koltunski
      {
164 47ba5ddc Leszek Koltunski
      switch(mSize)
165 30b68322 Leszek Koltunski
        {
166 47ba5ddc Leszek Koltunski
        case 1 : return 1.1f;
167
        case 2 : return 1.5f;
168
        case 3 : return 1.8f;
169
        case 4 : return 2.0f;
170
        default: return 3.0f - 4.0f/mSize;
171 30b68322 Leszek Koltunski
        }
172 47ba5ddc Leszek Koltunski
      }
173 30b68322 Leszek Koltunski
174 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
175 30b68322 Leszek Koltunski
176 47ba5ddc Leszek Koltunski
    private boolean belongsToRotation(int x, int y, int z, int vector, int row)
177
      {
178
      switch(vector)
179 30b68322 Leszek Koltunski
        {
180 47ba5ddc Leszek Koltunski
        case VECTX: return mCurrentPosition[x][y][z].get1()==row;
181
        case VECTY: return mCurrentPosition[x][y][z].get2()==row;
182
        case VECTZ: return mCurrentPosition[x][y][z].get3()==row;
183 30b68322 Leszek Koltunski
        }
184
185 47ba5ddc Leszek Koltunski
      return false;
186 30b68322 Leszek Koltunski
      }
187 47ba5ddc Leszek Koltunski
188 9208e27b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
189
190 47ba5ddc Leszek Koltunski
    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
191 9208e27b Leszek Koltunski
      {
192 47ba5ddc Leszek Koltunski
      Static3D current = mCurrentPosition[x][y][z];
193
      float diff = 0.5f*(mSize-1);
194
      float cubitCenterX = current.get1() - diff;
195
      float cubitCenterY = current.get2() - diff;
196
      float cubitCenterZ = current.get3() - diff;
197
198
      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
199
      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
200
201
      float rotatedX = rotatedCenter.get1() + diff;
202
      float rotatedY = rotatedCenter.get2() + diff;
203
      float rotatedZ = rotatedCenter.get3() + diff;
204
205
      int roundedX = (int)(rotatedX+0.1f);
206
      int roundedY = (int)(rotatedY+0.1f);
207
      int roundedZ = (int)(rotatedZ+0.1f);
208
209
      mCurrentPosition[x][y][z].set1(roundedX);
210
      mCurrentPosition[x][y][z].set2(roundedY);
211
      mCurrentPosition[x][y][z].set3(roundedZ);
212 434f2f5a Leszek Koltunski
      }
213
214 beb325a0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
215
// PUBLIC API
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217
218
    public RubikCube(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture texture, MeshFlat mesh, DistortedEffects effects)
219
      {
220
      super(texture,effects,mesh);
221
222
      mNodeTexture = texture;
223
224
      mSize = size;
225
226
      mRotationAngleStatic = new Static1D(0);
227
      mRotationAngleMiddle = new Static1D(0);
228
      mRotationAngleFinal  = new Static1D(0);
229
230
      mMove     = new Static3D(0,0,0);
231
      mScale    = new Static3D(1,1,1);
232
      mNodeMove = new Static3D(0,0,0);
233
      mNodeScale= new Static3D(1,1,1);
234
235
      mQuatAccumulated = quatAcc;
236
237
      mRotAxis = VECTX;
238
      mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
239
240
      mNodes          = new DistortedNode[mSize][mSize][mSize];
241
      mCubes          = new MeshCubes[mSize][mSize][mSize];
242
      mEffects        = new DistortedEffects[mSize][mSize][mSize];
243
      mQuatScramble   = new Static4D[mSize][mSize][mSize];
244
      mRotationAxis   = new Static3D[mSize][mSize][mSize];
245
      mRotationAngle  = new Dynamic1D[mSize][mSize][mSize];
246
      mCurrentPosition= new Static3D[mSize][mSize][mSize];
247
      mRotateEffect   = new MatrixEffectRotate[mSize][mSize][mSize];
248
249
      Static3D[][][] cubeVectors = new Static3D[mSize][mSize][mSize];
250
251
      Static3D sinkCenter = new Static3D(TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f);
252
      Static3D matrCenter = new Static3D(0,0,0);
253
      Static4D region = new Static4D(0,0,0, TEXTURE_SIZE*0.72f);
254
255
      VertexEffectSink        sinkEffect = new VertexEffectSink( new Static1D(getSinkStrength()), sinkCenter, region );
256
      MatrixEffectMove        moveEffect = new MatrixEffectMove(mMove);
257
      MatrixEffectScale      scaleEffect = new MatrixEffectScale(mScale);
258
      MatrixEffectQuaternion quatCEffect = new MatrixEffectQuaternion(quatCur, matrCenter);
259
      MatrixEffectQuaternion quatAEffect = new MatrixEffectQuaternion(quatAcc, matrCenter);
260
261
      MatrixEffectMove       nodeMoveEffect  = new MatrixEffectMove(mNodeMove);
262
      MatrixEffectScale      nodeScaleEffect = new MatrixEffectScale(mNodeScale);
263
264
      effects.apply(nodeScaleEffect);
265
      effects.apply(nodeMoveEffect);
266
267
      // 3x2 bitmap = 6 squares:
268
      //
269
      // RED     GREEN   BLUE
270
      // YELLOW  WHITE   BROWN
271
272
      final float ze = 0.0f;
273
      final float ot = 1.0f/3.0f;
274
      final float tt = 2.0f/3.0f;
275
      final float oh = 1.0f/2.0f;
276
      final float of = 1.0f/40.0f;
277
278
      final Static4D mapFront = new Static4D(ze,oh, ze+ot,oh+oh);
279
      final Static4D mapBack  = new Static4D(tt,ze, tt+ot,ze+oh);
280
      final Static4D mapLeft  = new Static4D(ot,ze, ot+ot,ze+oh);
281
      final Static4D mapRight = new Static4D(ze,ze, ze+ot,ze+oh);
282
      final Static4D mapTop   = new Static4D(tt,oh, tt+ot,oh+oh);
283
      final Static4D mapBottom= new Static4D(ot,oh, ot+ot,oh+oh);
284
285
      final Static4D mapBlack = new Static4D(ze,ze, ze+of,ze+of);
286
287
      Static4D tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom;
288
      float nc = 0.5f*mSize;
289
      int vertices = (int)(24.0f/mSize + 2.0f);
290
291
      for(int x = 0; x< mSize; x++)
292
        for(int y = 0; y< mSize; y++)
293
          for(int z = 0; z< mSize; z++)
294
            {
295
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 ) // only the external walls
296
              {
297
              tmpLeft  = (x==       0 ? mapLeft  :mapBlack);
298
              tmpRight = (x== mSize-1 ? mapRight :mapBlack);
299
              tmpFront = (z== mSize-1 ? mapFront :mapBlack);
300
              tmpBack  = (z==       0 ? mapBack  :mapBlack);
301
              tmpTop   = (y== mSize-1 ? mapTop   :mapBlack);
302
              tmpBottom= (y==       0 ? mapBottom:mapBlack);
303
304
              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
305
              cubeVectors[x][y][z]      = new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) );
306
              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
307
              mRotationAngle[x][y][z]   = new Dynamic1D();
308
              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
309
              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
310
              mRotateEffect[x][y][z]    = new MatrixEffectRotate(mRotationAngle[x][y][z], mRotationAxis[x][y][z], matrCenter);
311
312
              mEffects[x][y][z] = new DistortedEffects();
313
              mEffects[x][y][z].apply(sinkEffect);
314
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
315
              mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], matrCenter));
316
              mEffects[x][y][z].apply(mRotateEffect[x][y][z]);
317
              mEffects[x][y][z].apply(quatAEffect);
318
              mEffects[x][y][z].apply(quatCEffect);
319
              mEffects[x][y][z].apply(scaleEffect);
320
              mEffects[x][y][z].apply(moveEffect);
321
322
              mNodes[x][y][z] = new DistortedNode(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
323
324
              attach(mNodes[x][y][z]);
325
              }
326
            }
327
      }
328
329 775e675d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
330
331
    public void addNewRotation(int vector, int row )
332
      {
333
      Static3D axis = VectX;
334
335
      switch(vector)
336
        {
337
        case VECTX: axis = VectX; break;
338
        case VECTY: axis = VectY; break;
339
        case VECTZ: axis = VectZ; break;
340
        }
341
342
      mRotAxis = vector;
343
      mRotRow  = row;
344
345
      mRotationAngleStatic.set1(0.0f);
346
347
      for(int x=0; x<mSize; x++)
348
        for(int y=0; y<mSize; y++)
349
          for(int z=0; z<mSize; z++)
350
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
351
              {
352
              if( belongsToRotation(x,y,z,vector,mRotRow) )
353
                {
354
                mRotationAxis[x][y][z].set(axis);
355
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
356
                }
357
              }
358
      }
359
360
///////////////////////////////////////////////////////////////////////////////////////////////////
361
362
    public void continueRotation(float angleInDegrees)
363
      {
364
      mRotationAngleStatic.set1(angleInDegrees);
365
      }
366
367 beb325a0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
368
369
    public Static4D getRotationQuat()
370
      {
371
      return mQuatAccumulated;
372
      }
373
374
///////////////////////////////////////////////////////////////////////////////////////////////////
375
376
    public long finishRotationNow(EffectListener listener)
377 0c52af30 Leszek Koltunski
      {
378
      boolean first = true;
379 434f2f5a Leszek Koltunski
      long effectID=0;
380 0c52af30 Leszek Koltunski
381
      for(int x=0; x<mSize; x++)
382
        for(int y=0; y<mSize; y++)
383
          for(int z=0; z<mSize; z++)
384
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
385
              {
386
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
387
                {
388
                if( first )
389
                  {
390
                  first = false;
391 f647630d Leszek Koltunski
                  mRotateEffect[x][y][z].notifyWhenFinished(listener);
392 434f2f5a Leszek Koltunski
                  effectID = mRotateEffect[x][y][z].getID();
393 ffd48105 Leszek Koltunski
                  int pointNum = mRotationAngle[x][y][z].getNumPoints();
394
395
                  if( pointNum>=1 )
396
                    {
397
                    float startingAngle = mRotationAngle[x][y][z].getPoint(pointNum-1).get1();
398
                    int nearestAngleInDegrees = computeNearestAngle(startingAngle);
399
                    mRotationAngleStatic.set1(startingAngle);
400
                    mRotationAngleFinal.set1(nearestAngleInDegrees);
401
                    mRotationAngleMiddle.set1( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
402
                    }
403
                  else
404
                    {
405
                    android.util.Log.e("cube", "ERROR finishing rotation!");
406
                    return 0;
407
                    }
408 0c52af30 Leszek Koltunski
                  }
409 ffd48105 Leszek Koltunski
410
                mRotationAngle[x][y][z].setDuration(POST_ROTATION_MILLISEC);
411
                mRotationAngle[x][y][z].resetToBeginning();
412
                mRotationAngle[x][y][z].removeAll();
413
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
414
                mRotationAngle[x][y][z].add(mRotationAngleMiddle);
415
                mRotationAngle[x][y][z].add(mRotationAngleFinal);
416 0c52af30 Leszek Koltunski
                }
417
              }
418 434f2f5a Leszek Koltunski
419
      return effectID;
420 0c52af30 Leszek Koltunski
      }
421
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423 beb325a0 Leszek Koltunski
// all DistortedTextures, DistortedNodes, DistortedFramebuffers, DistortedScreens and all types of
424
// Meshes HAVE TO be markedForDeletion when they are no longer needed- otherwise we have a major
425
// memory leak.
426 0c52af30 Leszek Koltunski
427 beb325a0 Leszek Koltunski
    public void releaseResources()
428 0c52af30 Leszek Koltunski
      {
429 beb325a0 Leszek Koltunski
      mTexture.markForDeletion();
430
431
      for(int x=0; x<mSize; x++)
432
        for(int y=0; y<mSize; y++)
433
          for(int z=0; z<mSize; z++)
434
            {
435
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
436
              {
437
              mCubes[x][y][z].markForDeletion();
438
              mNodes[x][y][z].markForDeletion();
439
              }
440
            }
441 47ba5ddc Leszek Koltunski
      }
442 0c52af30 Leszek Koltunski
443 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
444 0c52af30 Leszek Koltunski
445 beb325a0 Leszek Koltunski
    public void createTexture()
446 0c52af30 Leszek Koltunski
      {
447
      Bitmap bitmap;
448
449
      final int S = 128;
450
      final int W = 3*S;
451
      final int H = 2*S;
452
      final int R = S/10;
453
      final int M = S/20;
454
455
      Paint paint = new Paint();
456
      bitmap = Bitmap.createBitmap(W,H, Bitmap.Config.ARGB_8888);
457
      Canvas canvas = new Canvas(bitmap);
458
459
      paint.setAntiAlias(true);
460
      paint.setTextAlign(Paint.Align.CENTER);
461
      paint.setStyle(Paint.Style.FILL);
462
463
      // 3x2 bitmap = 6 squares:
464
      //
465
      // RED     GREEN   BLUE
466
      // YELLOW  WHITE   BROWN
467
468
      paint.setColor(0xff000000);                                  // BLACK BACKGROUND
469
      canvas.drawRect(0, 0, W, H, paint);                          //
470
471
      paint.setColor(0xffff0000);                                  // RED
472
      canvas.drawRoundRect(    M,   M,   S-M,   S-M, R, R, paint); //
473
      paint.setColor(0xff00ff00);                                  // GREEN
474
      canvas.drawRoundRect(  S+M,   M, 2*S-M,   S-M, R, R, paint); //
475
      paint.setColor(0xff0000ff);                                  // BLUE
476
      canvas.drawRoundRect(2*S+M,   M, 3*S-M,   S-M, R, R, paint); //
477
      paint.setColor(0xffffff00);                                  // YELLOW
478
      canvas.drawRoundRect(    M, S+M,   S-M, 2*S-M, R, R, paint); //
479
      paint.setColor(0xffffffff);                                  // WHITE
480
      canvas.drawRoundRect(  S+M, S+M, 2*S-M, 2*S-M, R, R, paint); //
481
      paint.setColor(0xffb5651d);                                  // BROWN
482
      canvas.drawRoundRect(2*S+M, S+M, 3*S-M, 2*S-M, R, R, paint); //
483
484
      mTexture.setTexture(bitmap);
485
      }
486
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488
489 beb325a0 Leszek Koltunski
    public void recomputeScaleFactor(int screenWidth, int screenHeight)
490 e8764a49 Leszek Koltunski
      {
491
      int texW = mNodeTexture.getWidth();
492
      int texH = mNodeTexture.getHeight();
493 0c52af30 Leszek Koltunski
494 e8764a49 Leszek Koltunski
      if( (float)texH/texW > (float)screenHeight/screenWidth )
495
        {
496
        int w = (screenHeight*texW)/texH;
497
        float factor = (float)screenHeight/texH;
498
        mNodeMove.set((screenWidth-w)*0.5f ,0, 0);
499
        mNodeScale.set(factor,factor,factor);
500
        }
501
      else
502
        {
503
        int h = (screenWidth*texH)/texW;
504
        float factor = (float)screenWidth/texW;
505
        mNodeMove.set(0,(screenHeight-h)*0.5f,0);
506
        mNodeScale.set(factor,factor,factor);
507
        }
508 0c52af30 Leszek Koltunski
509 775e675d Leszek Koltunski
      float scaleFactor = (CUBE_SCREEN_RATIO*texW/(TEXTURE_SIZE*mSize));
510 e8764a49 Leszek Koltunski
511
      mMove.set( texW*0.5f , texH*0.5f , 0.0f );
512
      mScale.set(scaleFactor,scaleFactor,scaleFactor);
513 0c52af30 Leszek Koltunski
      }
514 47ba5ddc Leszek Koltunski
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516
517
    public void apply(Effect effect, int position)
518
      {
519
      for(int x=0; x<mSize; x++)
520
        for(int y=0; y<mSize; y++)
521
          for(int z=0; z<mSize; z++)
522
            {
523
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
524
              {
525
              mEffects[x][y][z].apply(effect, position);
526
              }
527
            }
528
      }
529
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531
532
    public void remove(long effectID)
533
      {
534
      for(int x=0; x<mSize; x++)
535
        for(int y=0; y<mSize; y++)
536
          for(int z=0; z<mSize; z++)
537
            {
538
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
539
              {
540
              mEffects[x][y][z].abortById(effectID);
541
              }
542
            }
543
      }
544
545
///////////////////////////////////////////////////////////////////////////////////////////////////
546
547
    public void solve()
548
      {
549
      for(int x=0; x<mSize; x++)
550
        for(int y=0; y<mSize; y++)
551
          for(int z=0; z<mSize; z++)
552
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
553
              {
554
              mQuatScramble[x][y][z].set(0,0,0,1);
555
              mCurrentPosition[x][y][z].set(x,y,z);
556
              }
557
      }
558
559 beb325a0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
560
561
    public boolean isSolved()
562
      {
563
      Static4D q = mQuatScramble[0][0][0];
564
565
      float x = q.get1();
566
      float y = q.get2();
567
      float z = q.get3();
568
      float w = q.get4();
569
570
      for(int i = 0; i< mSize; i++)
571
        for(int j = 0; j< mSize; j++)
572
          for(int k = 0; k< mSize; k++)
573
            {
574
            if( i==0 || i==mSize-1 || j==0 || j==mSize-1 || k==0 || k==mSize-1 )
575
              {
576
              q = mQuatScramble[i][j][k];
577
578
              if( q.get1()!=x || q.get2()!=y || q.get3()!=z || q.get4()!=w )
579
                {
580
                return false;
581
                }
582
              }
583
            }
584
585
      return true;
586
      }
587
588 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
589
590
    public int getSize()
591
      {
592
      return mSize;
593
      }
594
595
///////////////////////////////////////////////////////////////////////////////////////////////////
596
597
    public long addNewRotation(int vector, int row, int angle, long durationMillis, EffectListener listener )
598
      {
599
      Static3D axis = VectX;
600
      long effectID=0;
601
      boolean first = true;
602
603
      switch(vector)
604
        {
605
        case VECTX: axis = VectX; break;
606
        case VECTY: axis = VectY; break;
607
        case VECTZ: axis = VectZ; break;
608
        }
609
610
      mRotAxis = vector;
611
      mRotRow  = row;
612
613
      mRotationAngleStatic.set1(0.0f);
614
615
      for(int x=0; x<mSize; x++)
616
        for(int y=0; y<mSize; y++)
617
          for(int z=0; z<mSize; z++)
618
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
619
              {
620
              if( belongsToRotation(x,y,z,vector,mRotRow) )
621
                {
622
                mRotationAxis[x][y][z].set(axis);
623
                mRotationAngle[x][y][z].setDuration(durationMillis);
624
                mRotationAngle[x][y][z].resetToBeginning();
625
                mRotationAngle[x][y][z].add(new Static1D(0));
626
                mRotationAngle[x][y][z].add(new Static1D(angle));
627
628
                if( first )
629
                  {
630
                  first = false;
631
                  effectID = mRotateEffect[x][y][z].getID();
632
                  mRotateEffect[x][y][z].notifyWhenFinished(listener);
633
                  }
634
                }
635
              }
636
637
      return effectID;
638
      }
639
640
///////////////////////////////////////////////////////////////////////////////////////////////////
641
642
    public void removeRotationNow()
643
      {
644
      float qx=0,qy=0,qz=0;
645
      boolean first = true;
646
      Static4D quat = null;
647
648
      switch(mRotAxis)
649
        {
650
        case VECTX: qx=1; break;
651
        case VECTY: qy=1; break;
652
        case VECTZ: qz=1; break;
653
        }
654
655
      for(int x=0; x<mSize; x++)
656
        for(int y=0; y<mSize; y++)
657
          for(int z=0; z<mSize; z++)
658
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
659
              {
660
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
661
                {
662
                if( first )
663
                  {
664
                  first = false;
665
                  int pointNum = mRotationAngle[x][y][z].getNumPoints();
666
667
                  if( pointNum>=1 )
668
                    {
669
                    float startingAngle = mRotationAngle[x][y][z].getPoint(pointNum-1).get1();
670
                    int nearestAngleInDegrees = computeNearestAngle(startingAngle);
671
                    double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
672
                    float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
673
                    float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
674
                    quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
675
                    }
676
                  else
677
                    {
678
                    android.util.Log.e("cube", "ERROR removing rotation!");
679
                    return;
680
                    }
681
                  }
682
683
                mRotationAngle[x][y][z].removeAll();
684
                mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
685
                normalizeScrambleQuat(x,y,z);
686
                modifyCurrentPosition(x,y,z,quat);
687
                }
688
              }
689
690
      mRotationAngleStatic.set1(0);
691
      }
692 0c52af30 Leszek Koltunski
}