Project

General

Profile

Download (15.6 KB) Statistics
| Branch: | Revision:

examples / src / main / java / org / distorted / examples / rubik / RubikCube.java @ d4374cd3

1 15bcc6f7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// 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
// Distorted is distributed in the hope that it will be useful,                                  //
12
// 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
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.examples.rubik;
21
22
import android.graphics.Bitmap;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25
26
import org.distorted.library.effect.MatrixEffectMove;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.effect.MatrixEffectRotate;
29
import org.distorted.library.effect.MatrixEffectScale;
30
import org.distorted.library.effect.VertexEffectSink;
31
import org.distorted.library.main.DistortedEffects;
32
import org.distorted.library.main.DistortedScreen;
33
import org.distorted.library.main.DistortedTexture;
34
import org.distorted.library.mesh.MeshCubes;
35 b62eb334 Leszek Koltunski
import org.distorted.library.message.EffectListener;
36 15bcc6f7 Leszek Koltunski
import org.distorted.library.type.Dynamic1D;
37
import org.distorted.library.type.Static1D;
38
import org.distorted.library.type.Static3D;
39
import org.distorted.library.type.Static4D;
40
41
///////////////////////////////////////////////////////////////////////////////////////////////////
42
43
class RubikCube
44
{
45 d4374cd3 Leszek Koltunski
    private static final int POST_ROTATION_MILLISEC = 500;
46 7f986357 Leszek Koltunski
    private static final int TEXTURE_SIZE = 100;
47 15bcc6f7 Leszek Koltunski
48
    private static final Static3D VectX = new Static3D(1,0,0);
49
    private static final Static3D VectY = new Static3D(0,1,0);
50
    private static final Static3D VectZ = new Static3D(0,0,1);
51
52
    private MeshCubes[][][] mCubes;
53
    private DistortedEffects[][][] mEffects;
54
    private Static4D[][][] mQuatScramble;
55
    private Static3D[][][] mRotationAxis;
56
    private Dynamic1D[][][] mRotationAngle;
57
    private Static3D[][][] mCurrentPosition;
58 d4374cd3 Leszek Koltunski
    private Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
59 15bcc6f7 Leszek Koltunski
    private DistortedTexture mTexture;
60 b62eb334 Leszek Koltunski
    private DistortedEffects mEffectsListeningForNow;
61 15bcc6f7 Leszek Koltunski
62
    private int mRotAxis, mRotRow;
63
    private int mSize;
64
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66
67
    RubikCube(int size, Static3D move, Static3D scale, Static4D quatC, Static4D quatA)
68
      {
69
      mSize = size;
70
71 d4374cd3 Leszek Koltunski
      mRotationAngleStatic = new Static1D(0);
72
      mRotationAngleMiddle = new Static1D(0);
73
      mRotationAngleFinal  = new Static1D(0);
74 b62eb334 Leszek Koltunski
75 dc8979ba Leszek Koltunski
      mRotAxis= RubikSurfaceView.VECTX;
76 15bcc6f7 Leszek Koltunski
      mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
77
78
      mCubes          = new MeshCubes[mSize][mSize][mSize];
79
      mEffects        = new DistortedEffects[mSize][mSize][mSize];
80
      mQuatScramble   = new Static4D[mSize][mSize][mSize];
81
      mRotationAxis   = new Static3D[mSize][mSize][mSize];
82
      mRotationAngle  = new Dynamic1D[mSize][mSize][mSize];
83
      mCurrentPosition= new Static3D[mSize][mSize][mSize];
84
85
      Static3D[][][] cubeVectors = new Static3D[mSize][mSize][mSize];
86
87
      Static3D center = new Static3D(TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f);
88
      Static4D region = new Static4D(0,0,0, TEXTURE_SIZE*0.72f);
89
90
      VertexEffectSink        sinkEffect = new VertexEffectSink( new Static1D(3.0f - 1.8f/mSize), center, region );
91
      MatrixEffectMove        moveEffect = new MatrixEffectMove(move);
92
      MatrixEffectScale      scaleEffect = new MatrixEffectScale(scale);
93
      MatrixEffectQuaternion quatCEffect = new MatrixEffectQuaternion(quatC, center);
94
      MatrixEffectQuaternion quatAEffect = new MatrixEffectQuaternion(quatA, center);
95
96
      // 3x2 bitmap = 6 squares:
97
      //
98
      // RED     GREEN   BLUE
99
      // YELLOW  WHITE   BROWN
100
101
      final float ze = 0.0f;
102
      final float ot = 1.0f/3.0f;
103
      final float tt = 2.0f/3.0f;
104
      final float oh = 1.0f/2.0f;
105
      final float of = 1.0f/40.0f;
106
107
      final Static4D mapFront = new Static4D(ze,oh, ze+ot,oh+oh);
108
      final Static4D mapBack  = new Static4D(tt,ze, tt+ot,ze+oh);
109
      final Static4D mapLeft  = new Static4D(ot,ze, ot+ot,ze+oh);
110
      final Static4D mapRight = new Static4D(ze,ze, ze+ot,ze+oh);
111
      final Static4D mapTop   = new Static4D(tt,oh, tt+ot,oh+oh);
112
      final Static4D mapBottom= new Static4D(ot,oh, ot+ot,oh+oh);
113
114
      final Static4D mapBlack = new Static4D(ze,ze, ze+of,ze+of);
115
116
      Static4D tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom;
117
      float nc = 0.5f*(mSize-1);
118
      int vertices = (int)(24.0f/mSize + 2.0f);
119
120
      for(int x = 0; x< mSize; x++)
121
        for(int y = 0; y< mSize; y++)
122
          for(int z = 0; z< mSize; z++)
123
            {
124
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 ) // only the external walls
125
              {
126
              tmpLeft  = (x==       0 ? mapLeft  :mapBlack);
127
              tmpRight = (x== mSize-1 ? mapRight :mapBlack);
128
              tmpFront = (z== mSize-1 ? mapFront :mapBlack);
129
              tmpBack  = (z==       0 ? mapBack  :mapBlack);
130
              tmpTop   = (y== mSize-1 ? mapTop   :mapBlack);
131
              tmpBottom= (y==       0 ? mapBottom:mapBlack);
132
133
              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
134
              cubeVectors[x][y][z]      = new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) );
135
              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
136
              mRotationAngle[x][y][z]   = new Dynamic1D();
137
              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
138
              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
139
140
              mEffects[x][y][z] = new DistortedEffects();
141
              mEffects[x][y][z].apply(sinkEffect);
142
              mEffects[x][y][z].apply(moveEffect);
143
              mEffects[x][y][z].apply(scaleEffect);
144
              mEffects[x][y][z].apply(quatCEffect);
145
              mEffects[x][y][z].apply(quatAEffect);
146
              mEffects[x][y][z].apply( new MatrixEffectRotate( mRotationAngle[x][y][z], mRotationAxis[x][y][z], center));
147
              mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], center));
148
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
149
              }
150
            }
151
      }
152
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154
155
    void attachToScreen(DistortedScreen screen)
156
      {
157
      for(int x=0; x<mSize; x++)
158
        for(int y=0; y<mSize; y++)
159
          for(int z=0; z<mSize; z++)
160
            {
161
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
162
              {
163
              screen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
164
              }
165
            }
166
      }
167
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169
170 7f986357 Leszek Koltunski
    void addNewRotation(int vector, float offset )
171 15bcc6f7 Leszek Koltunski
      {
172
      Static3D axis = VectX;
173
174
      switch(vector)
175
        {
176
        case RubikSurfaceView.VECTX: axis = VectX; break;
177
        case RubikSurfaceView.VECTY: axis = VectY; break;
178
        case RubikSurfaceView.VECTZ: axis = VectZ; break;
179
        }
180
181
      mRotAxis = vector;
182 7f986357 Leszek Koltunski
      mRotRow  = (int)(mSize*offset);
183 15bcc6f7 Leszek Koltunski
184
      mRotationAngleStatic.set1(0.0f);
185
186
      for(int x=0; x<mSize; x++)
187
        for(int y=0; y<mSize; y++)
188
          for(int z=0; z<mSize; z++)
189
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
190
              {
191 7f986357 Leszek Koltunski
              if( belongsToRotation(x,y,z,vector,mRotRow) )
192 15bcc6f7 Leszek Koltunski
                {
193
                mRotationAxis[x][y][z].set(axis);
194
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
195
                }
196
              }
197
      }
198
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200
201 b62eb334 Leszek Koltunski
    void continueRotation(float angleInDegrees)
202
      {
203
      mRotationAngleStatic.set1(angleInDegrees);
204
      }
205
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
208
    private int computeNearestAngle(float angle)
209 15bcc6f7 Leszek Koltunski
      {
210 b62eb334 Leszek Koltunski
      final int NEAREST = 90;
211
212
      int tmp = (int)((angle+NEAREST/2)/NEAREST);
213
      if( angle< -(NEAREST/2) ) tmp-=1;
214
215
      return NEAREST*tmp;
216 15bcc6f7 Leszek Koltunski
      }
217
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219
220 b62eb334 Leszek Koltunski
    void finishRotationCalledOnNextRender(EffectListener listener)
221 15bcc6f7 Leszek Koltunski
      {
222 b62eb334 Leszek Koltunski
      boolean first = true;
223 d4374cd3 Leszek Koltunski
      float startingAngle = mRotationAngleStatic.get1();
224
      int nearestAngleInDegrees = computeNearestAngle(startingAngle);
225 b62eb334 Leszek Koltunski
226 d4374cd3 Leszek Koltunski
      mRotationAngleFinal.set1(nearestAngleInDegrees);
227
      mRotationAngleMiddle.set1( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
228 b62eb334 Leszek Koltunski
229
      for(int x=0; x<mSize; x++)
230
        for(int y=0; y<mSize; y++)
231
          for(int z=0; z<mSize; z++)
232
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
233
              {
234
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
235
                {
236 d4374cd3 Leszek Koltunski
                mRotationAngle[x][y][z].makeRunNowFor(POST_ROTATION_MILLISEC);
237
                mRotationAngle[x][y][z].add(mRotationAngleMiddle);
238
                mRotationAngle[x][y][z].add(mRotationAngleFinal);
239 b62eb334 Leszek Koltunski
240
                if( first )
241
                  {
242
                  first = false;
243
                  mEffectsListeningForNow = mEffects[x][y][z];
244
                  mEffectsListeningForNow.registerForMessages(listener);
245
                  }
246
                }
247
              }
248
      }
249
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251
252
    void removeRotationCalledOnNextRender(EffectListener listener)
253
      {
254
      mEffectsListeningForNow.deregisterForMessages(listener);
255
256
      int nearestAngleInDegrees = computeNearestAngle(mRotationAngleStatic.get1());
257 15bcc6f7 Leszek Koltunski
      double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
258 b62eb334 Leszek Koltunski
      float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
259 15bcc6f7 Leszek Koltunski
      float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
260
261
      mRotationAngleStatic.set1(0);
262
263
      float qx=0,qy=0,qz=0;
264
265
      switch(mRotAxis)
266
        {
267
        case RubikSurfaceView.VECTX: qx=1; break;
268
        case RubikSurfaceView.VECTY: qy=1; break;
269
        case RubikSurfaceView.VECTZ: qz=1; break;
270
        }
271
272
      Static4D quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
273
274
      for(int x=0; x<mSize; x++)
275
        for(int y=0; y<mSize; y++)
276
          for(int z=0; z<mSize; z++)
277
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
278
              {
279
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
280
                {
281 b62eb334 Leszek Koltunski
                mRotationAngle[x][y][z].makeRunNowFor(0);
282 15bcc6f7 Leszek Koltunski
                mRotationAngle[x][y][z].removeAll();
283
                mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
284
                modifyCurrentPosition(x,y,z,quat);
285
                }
286
              }
287
      }
288
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290
291
    private boolean belongsToRotation(int x, int y, int z, int vector, int row)
292
      {
293
      switch(vector)
294
        {
295
        case RubikSurfaceView.VECTX: return mCurrentPosition[x][y][z].get1()==row;
296
        case RubikSurfaceView.VECTY: return mCurrentPosition[x][y][z].get2()==row;
297
        case RubikSurfaceView.VECTZ: return mCurrentPosition[x][y][z].get3()==row;
298
        }
299
300
      return false;
301
      }
302
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304
305
    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
306
      {
307
      Static3D current = mCurrentPosition[x][y][z];
308
      float diff = 0.5f*(mSize-1);
309 483ae94e Leszek Koltunski
      float cubitCenterX = current.get1() - diff;
310
      float cubitCenterY = current.get2() - diff;
311
      float cubitCenterZ = current.get3() - diff;
312 15bcc6f7 Leszek Koltunski
313
      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
314
      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
315
316
      float rotatedX = rotatedCenter.get1() + diff;
317
      float rotatedY = rotatedCenter.get2() + diff;
318
      float rotatedZ = rotatedCenter.get3() + diff;
319
320
      int roundedX = (int)(rotatedX+0.1f);
321
      int roundedY = (int)(rotatedY+0.1f);
322
      int roundedZ = (int)(rotatedZ+0.1f);
323
324
      mCurrentPosition[x][y][z].set1(roundedX);
325
      mCurrentPosition[x][y][z].set2(roundedY);
326
      mCurrentPosition[x][y][z].set3(roundedZ);
327
      }
328
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330
331
    void createTexture()
332
      {
333
      Bitmap bitmap;
334
335
      final int S = 128;
336
      final int W = 3*S;
337
      final int H = 2*S;
338
      final int R = S/10;
339
      final int M = S/20;
340
341
      Paint paint = new Paint();
342
      bitmap = Bitmap.createBitmap(W,H, Bitmap.Config.ARGB_8888);
343
      Canvas canvas = new Canvas(bitmap);
344
345
      paint.setAntiAlias(true);
346
      paint.setTextAlign(Paint.Align.CENTER);
347
      paint.setStyle(Paint.Style.FILL);
348
349
      // 3x2 bitmap = 6 squares:
350
      //
351
      // RED     GREEN   BLUE
352
      // YELLOW  WHITE   BROWN
353
354
      paint.setColor(0xff000000);                                  // BLACK BACKGROUND
355
      canvas.drawRect(0, 0, W, H, paint);                          //
356
357
      paint.setColor(0xffff0000);                                  // RED
358
      canvas.drawRoundRect(    M,   M,   S-M,   S-M, R, R, paint); //
359
      paint.setColor(0xff00ff00);                                  // GREEN
360
      canvas.drawRoundRect(  S+M,   M, 2*S-M,   S-M, R, R, paint); //
361
      paint.setColor(0xff0000ff);                                  // BLUE
362
      canvas.drawRoundRect(2*S+M,   M, 3*S-M,   S-M, R, R, paint); //
363
      paint.setColor(0xffffff00);                                  // YELLOW
364
      canvas.drawRoundRect(    M, S+M,   S-M, 2*S-M, R, R, paint); //
365
      paint.setColor(0xffffffff);                                  // WHITE
366
      canvas.drawRoundRect(  S+M, S+M, 2*S-M, 2*S-M, R, R, paint); //
367
      paint.setColor(0xffb5651d);                                  // BROWN
368
      canvas.drawRoundRect(2*S+M, S+M, 3*S-M, 2*S-M, R, R, paint); //
369
370
      mTexture.setTexture(bitmap);
371
      }
372
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374
375 483ae94e Leszek Koltunski
    float getTextureSize()
376 15bcc6f7 Leszek Koltunski
      {
377 483ae94e Leszek Koltunski
      return TEXTURE_SIZE;
378 15bcc6f7 Leszek Koltunski
      }
379 7f986357 Leszek Koltunski
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381
382 483ae94e Leszek Koltunski
    float getSize()
383 7f986357 Leszek Koltunski
      {
384 483ae94e Leszek Koltunski
      return mSize;
385 7f986357 Leszek Koltunski
      }
386 15bcc6f7 Leszek Koltunski
}