Project

General

Profile

« Previous | Next » 

Revision 15bcc6f7

Added by Leszek Koltunski over 5 years ago

Improve the architecture of the Rubik App: new RubikCube class.

View differences:

src/main/java/org/distorted/examples/rubik/RubikCube.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
import org.distorted.library.type.Dynamic1D;
36
import org.distorted.library.type.Static1D;
37
import org.distorted.library.type.Static3D;
38
import org.distorted.library.type.Static4D;
39

  
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

  
42
class RubikCube
43
{
44
    static final int TEXTURE_SIZE = 200;
45

  
46
    private static final Static3D VectX = new Static3D(1,0,0);
47
    private static final Static3D VectY = new Static3D(0,1,0);
48
    private static final Static3D VectZ = new Static3D(0,0,1);
49

  
50
    private MeshCubes[][][] mCubes;
51
    private DistortedEffects[][][] mEffects;
52
    private Static4D[][][] mQuatScramble;
53
    private Static3D[][][] mRotationAxis;
54
    private Dynamic1D[][][] mRotationAngle;
55
    private Static3D[][][] mCurrentPosition;
56
    private Static1D mRotationAngleStatic;
57
    private DistortedTexture mTexture;
58

  
59
    private int mRotAxis, mRotRow;
60
    private int mSize;
61

  
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

  
64
    RubikCube(int size, Static3D move, Static3D scale, Static4D quatC, Static4D quatA)
65
      {
66
      mSize = size;
67

  
68
      mRotationAngleStatic = new Static1D(0);
69
      mRotAxis= RubikSurfaceView.VECTN;
70
      mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
71

  
72
      mCubes          = new MeshCubes[mSize][mSize][mSize];
73
      mEffects        = new DistortedEffects[mSize][mSize][mSize];
74
      mQuatScramble   = new Static4D[mSize][mSize][mSize];
75
      mRotationAxis   = new Static3D[mSize][mSize][mSize];
76
      mRotationAngle  = new Dynamic1D[mSize][mSize][mSize];
77
      mCurrentPosition= new Static3D[mSize][mSize][mSize];
78

  
79
      Static3D[][][] cubeVectors = new Static3D[mSize][mSize][mSize];
80

  
81
      Static3D center = new Static3D(TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f);
82
      Static4D region = new Static4D(0,0,0, TEXTURE_SIZE*0.72f);
83

  
84
      VertexEffectSink        sinkEffect = new VertexEffectSink( new Static1D(3.0f - 1.8f/mSize), center, region );
85
      MatrixEffectMove        moveEffect = new MatrixEffectMove(move);
86
      MatrixEffectScale      scaleEffect = new MatrixEffectScale(scale);
87
      MatrixEffectQuaternion quatCEffect = new MatrixEffectQuaternion(quatC, center);
88
      MatrixEffectQuaternion quatAEffect = new MatrixEffectQuaternion(quatA, center);
89

  
90
      // 3x2 bitmap = 6 squares:
91
      //
92
      // RED     GREEN   BLUE
93
      // YELLOW  WHITE   BROWN
94

  
95
      final float ze = 0.0f;
96
      final float ot = 1.0f/3.0f;
97
      final float tt = 2.0f/3.0f;
98
      final float oh = 1.0f/2.0f;
99
      final float of = 1.0f/40.0f;
100

  
101
      final Static4D mapFront = new Static4D(ze,oh, ze+ot,oh+oh);
102
      final Static4D mapBack  = new Static4D(tt,ze, tt+ot,ze+oh);
103
      final Static4D mapLeft  = new Static4D(ot,ze, ot+ot,ze+oh);
104
      final Static4D mapRight = new Static4D(ze,ze, ze+ot,ze+oh);
105
      final Static4D mapTop   = new Static4D(tt,oh, tt+ot,oh+oh);
106
      final Static4D mapBottom= new Static4D(ot,oh, ot+ot,oh+oh);
107

  
108
      final Static4D mapBlack = new Static4D(ze,ze, ze+of,ze+of);
109

  
110
      Static4D tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom;
111
      float nc = 0.5f*(mSize-1);
112
      int vertices = (int)(24.0f/mSize + 2.0f);
113

  
114
      for(int x = 0; x< mSize; x++)
115
        for(int y = 0; y< mSize; y++)
116
          for(int z = 0; z< mSize; z++)
117
            {
118
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 ) // only the external walls
119
              {
120
              tmpLeft  = (x==       0 ? mapLeft  :mapBlack);
121
              tmpRight = (x== mSize-1 ? mapRight :mapBlack);
122
              tmpFront = (z== mSize-1 ? mapFront :mapBlack);
123
              tmpBack  = (z==       0 ? mapBack  :mapBlack);
124
              tmpTop   = (y== mSize-1 ? mapTop   :mapBlack);
125
              tmpBottom= (y==       0 ? mapBottom:mapBlack);
126

  
127
              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
128
              cubeVectors[x][y][z]      = new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) );
129
              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
130
              mRotationAngle[x][y][z]   = new Dynamic1D();
131
              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
132
              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
133

  
134
              mEffects[x][y][z] = new DistortedEffects();
135
              mEffects[x][y][z].apply(sinkEffect);
136
              mEffects[x][y][z].apply(moveEffect);
137
              mEffects[x][y][z].apply(scaleEffect);
138
              mEffects[x][y][z].apply(quatCEffect);
139
              mEffects[x][y][z].apply(quatAEffect);
140
              mEffects[x][y][z].apply( new MatrixEffectRotate( mRotationAngle[x][y][z], mRotationAxis[x][y][z], center));
141
              mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], center));
142
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
143
              }
144
            }
145
      }
146

  
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

  
149
    void attachToScreen(DistortedScreen screen)
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 )
156
              {
157
              screen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
158
              }
159
            }
160
      }
161

  
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

  
164
    void addNewRotation(int vector, int row )
165
      {
166
      Static3D axis = VectX;
167

  
168
      switch(vector)
169
        {
170
        case RubikSurfaceView.VECTX: axis = VectX; break;
171
        case RubikSurfaceView.VECTY: axis = VectY; break;
172
        case RubikSurfaceView.VECTZ: axis = VectZ; break;
173
        }
174

  
175
      mRotAxis = vector;
176
      mRotRow  = row;
177

  
178
      mRotationAngleStatic.set1(0.0f);
179

  
180
      for(int x=0; x<mSize; x++)
181
        for(int y=0; y<mSize; y++)
182
          for(int z=0; z<mSize; z++)
183
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
184
              {
185
              if( belongsToRotation(x,y,z,vector,row) )
186
                {
187
                mRotationAxis[x][y][z].set(axis);
188
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
189
                }
190
              }
191
      }
192

  
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

  
195
    void continueRotation(float angle, int screenMin)
196
      {
197
      mRotationAngleStatic.set1(200.0f*angle/screenMin);
198
      }
199

  
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

  
202
    void finishRotationCalledOnNextRender()
203
      {
204
      float nearestAngle = (mRotationAngleStatic.get1()+45.0f)/90.0f;
205
      if( nearestAngle<0 ) nearestAngle-=1.0f;
206
      int nearestAngleInDegrees = 90*(4-((int)nearestAngle+4)%4);
207
      double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
208
      float sinA = (float)Math.sin(nearestAngleInRadians*0.5);
209
      float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
210

  
211
      mRotationAngleStatic.set1(0);
212

  
213
      float qx=0,qy=0,qz=0;
214

  
215
      switch(mRotAxis)
216
        {
217
        case RubikSurfaceView.VECTX: qx=1; break;
218
        case RubikSurfaceView.VECTY: qy=1; break;
219
        case RubikSurfaceView.VECTZ: qz=1; break;
220
        }
221

  
222
      Static4D quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
223

  
224
      for(int x=0; x<mSize; x++)
225
        for(int y=0; y<mSize; y++)
226
          for(int z=0; z<mSize; z++)
227
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
228
              {
229
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
230
                {
231
                mRotationAngle[x][y][z].removeAll();
232
                mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
233
                modifyCurrentPosition(x,y,z,quat);
234
                }
235
              }
236
      }
237

  
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

  
240
    private boolean belongsToRotation(int x, int y, int z, int vector, int row)
241
      {
242
      switch(vector)
243
        {
244
        case RubikSurfaceView.VECTX: return mCurrentPosition[x][y][z].get1()==row;
245
        case RubikSurfaceView.VECTY: return mCurrentPosition[x][y][z].get2()==row;
246
        case RubikSurfaceView.VECTZ: return mCurrentPosition[x][y][z].get3()==row;
247
        }
248

  
249
      return false;
250
      }
251

  
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

  
254
    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
255
      {
256
      Static3D current = mCurrentPosition[x][y][z];
257
      float beforeX = current.get1();
258
      float beforeY = current.get2();
259
      float beforeZ = current.get3();
260

  
261
      float diff = 0.5f*(mSize-1);
262

  
263
      float cubitCenterX = beforeX - diff;
264
      float cubitCenterY = beforeY - diff;
265
      float cubitCenterZ = beforeZ - diff;
266

  
267
      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
268
      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
269

  
270
      float rotatedX = rotatedCenter.get1() + diff;
271
      float rotatedY = rotatedCenter.get2() + diff;
272
      float rotatedZ = rotatedCenter.get3() + diff;
273

  
274
      int roundedX = (int)(rotatedX+0.1f);
275
      int roundedY = (int)(rotatedY+0.1f);
276
      int roundedZ = (int)(rotatedZ+0.1f);
277

  
278
      //android.util.Log.e("rubik", "before: ("+((int)beforeX)+","+((int)beforeY)+","+((int)beforeZ)+") after: ("+roundedX+","+roundedY+","+roundedZ+")");
279

  
280
      mCurrentPosition[x][y][z].set1(roundedX);
281
      mCurrentPosition[x][y][z].set2(roundedY);
282
      mCurrentPosition[x][y][z].set3(roundedZ);
283
      }
284

  
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286

  
287
    void createTexture()
288
      {
289
      Bitmap bitmap;
290

  
291
      final int S = 128;
292
      final int W = 3*S;
293
      final int H = 2*S;
294
      final int R = S/10;
295
      final int M = S/20;
296

  
297
      Paint paint = new Paint();
298
      bitmap = Bitmap.createBitmap(W,H, Bitmap.Config.ARGB_8888);
299
      Canvas canvas = new Canvas(bitmap);
300

  
301
      paint.setAntiAlias(true);
302
      paint.setTextAlign(Paint.Align.CENTER);
303
      paint.setStyle(Paint.Style.FILL);
304

  
305
      // 3x2 bitmap = 6 squares:
306
      //
307
      // RED     GREEN   BLUE
308
      // YELLOW  WHITE   BROWN
309

  
310
      paint.setColor(0xff000000);                                  // BLACK BACKGROUND
311
      canvas.drawRect(0, 0, W, H, paint);                          //
312

  
313
      paint.setColor(0xffff0000);                                  // RED
314
      canvas.drawRoundRect(    M,   M,   S-M,   S-M, R, R, paint); //
315
      paint.setColor(0xff00ff00);                                  // GREEN
316
      canvas.drawRoundRect(  S+M,   M, 2*S-M,   S-M, R, R, paint); //
317
      paint.setColor(0xff0000ff);                                  // BLUE
318
      canvas.drawRoundRect(2*S+M,   M, 3*S-M,   S-M, R, R, paint); //
319
      paint.setColor(0xffffff00);                                  // YELLOW
320
      canvas.drawRoundRect(    M, S+M,   S-M, 2*S-M, R, R, paint); //
321
      paint.setColor(0xffffffff);                                  // WHITE
322
      canvas.drawRoundRect(  S+M, S+M, 2*S-M, 2*S-M, R, R, paint); //
323
      paint.setColor(0xffb5651d);                                  // BROWN
324
      canvas.drawRoundRect(2*S+M, S+M, 3*S-M, 2*S-M, R, R, paint); //
325

  
326
      mTexture.setTexture(bitmap);
327
      }
328

  
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

  
331
    float getWidth()
332
      {
333
      return mTexture.getWidth();
334
      }
335

  
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

  
338
    float getHeight()
339
      {
340
      return mTexture.getHeight();
341
      }
342

  
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344

  
345
    float getDepth()
346
      {
347
      return mTexture.getDepth(mCubes[0][0][0]);
348
      }
349
}

Also available in: Unified diff