Project

General

Profile

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

magiccube / src / main / java / org / distorted / object / RubikCube.java @ 8e1231ae

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