Project

General

Profile

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

magiccube / src / main / java / org / distorted / magic / RubikCube.java @ fdec60a3

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