Project

General

Profile

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

magiccube / src / main / java / org / distorted / object / RubikObject.java @ efef689c

1 fdec60a3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube 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
// Magic Cube 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 Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20 4f9f99a2 Leszek Koltunski
package org.distorted.object;
21 fdec60a3 Leszek Koltunski
22 27a70eae Leszek Koltunski
import android.content.SharedPreferences;
23 411c6285 Leszek Koltunski
import android.graphics.Bitmap;
24
import android.graphics.Canvas;
25
import android.graphics.Paint;
26 27a70eae Leszek Koltunski
27
import org.distorted.library.effect.Effect;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
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.DistortedNode;
33
import org.distorted.library.main.DistortedTexture;
34 b32444ee Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
35 97c012ae Leszek Koltunski
import org.distorted.library.mesh.MeshRectangles;
36 27a70eae Leszek Koltunski
import org.distorted.library.message.EffectListener;
37 f16ff19d Leszek Koltunski
import org.distorted.library.type.Dynamic1D;
38 27a70eae Leszek Koltunski
import org.distorted.library.type.Static1D;
39
import org.distorted.library.type.Static3D;
40
import org.distorted.library.type.Static4D;
41 4f9f99a2 Leszek Koltunski
42 ba740a0c Leszek Koltunski
import static org.distorted.magic.RubikRenderer.NODE_FBO_SIZE;
43 d41742f7 Leszek Koltunski
44 0333d81e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
45
46 27a70eae Leszek Koltunski
public abstract class RubikObject extends DistortedNode
47 fdec60a3 Leszek Koltunski
  {
48 411c6285 Leszek Koltunski
  static final int TEXTURE_HEIGHT = 128;
49 27a70eae Leszek Koltunski
  static final float OBJECT_SCREEN_RATIO = 0.5f;
50 a10ada2a Leszek Koltunski
  final float[] LEGAL_QUATS;
51 efef689c Leszek Koltunski
  final Static3D[] ROTATION_AXIS;
52 27a70eae Leszek Koltunski
53 f16ff19d Leszek Koltunski
  private static final int POST_ROTATION_MILLISEC = 500;
54 a10ada2a Leszek Koltunski
  private final int NUM_CUBITS;
55 3c4a326c Leszek Koltunski
  private int mRotRow;
56 efef689c Leszek Koltunski
  private int mRotAxis;
57 5ba13c05 Leszek Koltunski
  private Static3D mScale, mNodeScale;
58 27a70eae Leszek Koltunski
  private Static4D mQuatAccumulated;
59 b32444ee Leszek Koltunski
  private Cubit[] mCubits;
60 27a70eae Leszek Koltunski
61 a10ada2a Leszek Koltunski
  int mSize;
62 fdec60a3 Leszek Koltunski
63 27a70eae Leszek Koltunski
  Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
64
  DistortedTexture mTexture;
65
66
  VertexEffectSink mSinkEffect;
67
  MatrixEffectScale mScaleEffect;
68
  MatrixEffectQuaternion mQuatCEffect;
69
  MatrixEffectQuaternion mQuatAEffect;
70
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72 fdec60a3 Leszek Koltunski
73 411c6285 Leszek Koltunski
  RubikObject(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture nodeTexture, MeshRectangles nodeMesh, DistortedEffects nodeEffects)
74 fdec60a3 Leszek Koltunski
    {
75 411c6285 Leszek Koltunski
    super(nodeTexture,nodeEffects,nodeMesh);
76 fdec60a3 Leszek Koltunski
77 ba740a0c Leszek Koltunski
    resizeFBO(NODE_FBO_SIZE, NODE_FBO_SIZE);
78 d41742f7 Leszek Koltunski
79 f16ff19d Leszek Koltunski
    LEGAL_QUATS = getLegalQuats();
80 a10ada2a Leszek Koltunski
    NUM_CUBITS  = getNumCubits(size);
81 efef689c Leszek Koltunski
    ROTATION_AXIS = getRotationAxis();
82 a10ada2a Leszek Koltunski
83 27a70eae Leszek Koltunski
    mSize = size;
84
85
    mRotationAngleStatic = new Static1D(0);
86
    mRotationAngleMiddle = new Static1D(0);
87
    mRotationAngleFinal  = new Static1D(0);
88
89
    mScale    = new Static3D(1,1,1);
90
    mNodeScale= new Static3D(1,1,1);
91
92
    mQuatAccumulated = quatAcc;
93
94 5ba13c05 Leszek Koltunski
    Static3D center = new Static3D(0,0,0);
95 5974d2ae Leszek Koltunski
    Static4D region = new Static4D(0,0,0,0.72f);
96 27a70eae Leszek Koltunski
97 5ba13c05 Leszek Koltunski
    mSinkEffect = new VertexEffectSink( new Static1D(getSinkStrength()), center, region );
98 27a70eae Leszek Koltunski
    mScaleEffect = new MatrixEffectScale(mScale);
99 5ba13c05 Leszek Koltunski
    mQuatCEffect = new MatrixEffectQuaternion(quatCur, center);
100
    mQuatAEffect = new MatrixEffectQuaternion(quatAcc, center);
101 27a70eae Leszek Koltunski
102
    MatrixEffectScale nodeScaleEffect = new MatrixEffectScale(mNodeScale);
103 411c6285 Leszek Koltunski
    nodeEffects.apply(nodeScaleEffect);
104 a10ada2a Leszek Koltunski
105
    mCubits = new Cubit[NUM_CUBITS];
106 5974d2ae Leszek Koltunski
    mTexture = new DistortedTexture();
107 a10ada2a Leszek Koltunski
108
    int vertices = (int)(24.0f/mSize + 2.0f);
109 b32444ee Leszek Koltunski
    int[][] positions = getCubitPositions(size);
110 a10ada2a Leszek Koltunski
111
    for(int i=0; i<NUM_CUBITS; i++)
112
      {
113 efef689c Leszek Koltunski
      Static3D pos = new Static3D(positions[i][0],positions[i][1],positions[i][2]);
114
      MeshBase cubitMesh = createCubitMesh(vertices);
115
      mCubits[i] = new Cubit(this,cubitMesh,pos);
116
      textureCubitMesh(cubitMesh,i);
117 a10ada2a Leszek Koltunski
118
      attach(mCubits[i].mNode);
119
      }
120 27a70eae Leszek Koltunski
    }
121
122 efef689c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
123
124
  private void textureCubitMesh(MeshBase mesh, int cubit)
125
    {
126
    boolean belongs;
127
    final int numFaces = getNumFaces();
128
    final Static4D[] maps = new Static4D[numFaces];
129
    final float ratio = 1.0f/(numFaces+1);
130
131
    if( 2*ROTATION_AXIS.length == numFaces )
132
      {
133
      for(int i=0; i<numFaces; i++)
134
        {
135
        belongs = belongsToRotation(cubit, i/2, i%2==0 ? mSize-1:0 );
136
        maps[i] = new Static4D( (belongs?i:6)*ratio, 0.0f, ratio, 1.0f);
137
        }
138
      }
139
    else if( ROTATION_AXIS.length == numFaces )
140
      {
141
      for(int i=0; i<numFaces; i++)
142
        {
143
        belongs = belongsToRotation(cubit, i, mSize-1 );
144
        maps[i] = new Static4D( (belongs?i:6)*ratio, 0.0f, ratio, 1.0f);
145
        }
146
      }
147
148
    mesh.setTextureMap(maps);
149
    }
150
151
///////////////////////////////////////////////////////////////////////////////////////////////////
152
// TODO: only works for RubikCube
153
154
  private boolean belongsToRotation( int cubit, int axis, int row)
155
    {
156
    Static3D position = mCubits[cubit].mCurrentPosition;
157
158
    if( axis==0 ) return position.get0()==row;
159
    if( axis==1 ) return position.get1()==row;
160
    if( axis==2 ) return position.get2()==row;
161
162
    return false;
163
    }
164
165 f16ff19d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
166
167 a10ada2a Leszek Koltunski
  private void resetRotationAngle(Dynamic1D rotationAngle)
168 f16ff19d Leszek Koltunski
    {
169
    rotationAngle.setDuration(POST_ROTATION_MILLISEC);
170
    rotationAngle.resetToBeginning();
171
    rotationAngle.removeAll();
172
    rotationAngle.add(mRotationAngleStatic);
173
    rotationAngle.add(mRotationAngleMiddle);
174
    rotationAngle.add(mRotationAngleFinal);
175
    }
176
177 fdec60a3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
178
179 27a70eae Leszek Koltunski
  private float getSinkStrength()
180 dd73fdab Leszek Koltunski
    {
181 27a70eae Leszek Koltunski
    switch(mSize)
182
      {
183
      case 1 : return 1.1f;
184
      case 2 : return 1.5f;
185
      case 3 : return 1.8f;
186
      case 4 : return 2.0f;
187
      default: return 3.0f - 4.0f/mSize;
188
      }
189 dd73fdab Leszek Koltunski
    }
190
191 411c6285 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
192
// the getFaceColors + final black in a horizontal strip.
193
194
  public void createTexture()
195
    {
196
    Bitmap bitmap;
197
198
    final int numColors = getNumFaces();
199
200
    Paint paint = new Paint();
201
    bitmap = Bitmap.createBitmap( (numColors+1)*TEXTURE_HEIGHT, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
202
    Canvas canvas = new Canvas(bitmap);
203
204
    paint.setAntiAlias(true);
205
    paint.setTextAlign(Paint.Align.CENTER);
206
    paint.setStyle(Paint.Style.FILL);
207
208
    paint.setColor(0xff000000);
209
    canvas.drawRect(0, 0, (numColors+1)*TEXTURE_HEIGHT, TEXTURE_HEIGHT, paint);
210
211
    for(int i=0; i<numColors; i++)
212
      {
213
      createFaceTexture(canvas,paint,i);
214
      }
215
216
    mTexture.setTexture(bitmap);
217
    }
218
219 dd73fdab Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
220
221 27a70eae Leszek Koltunski
  public int getSize()
222 fdec60a3 Leszek Koltunski
    {
223 27a70eae Leszek Koltunski
    return mSize;
224 fdec60a3 Leszek Koltunski
    }
225
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227
228 27a70eae Leszek Koltunski
  public void continueRotation(float angleInDegrees)
229 fdec60a3 Leszek Koltunski
    {
230 27a70eae Leszek Koltunski
    mRotationAngleStatic.set0(angleInDegrees);
231 fdec60a3 Leszek Koltunski
    }
232
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234
235 27a70eae Leszek Koltunski
  public Static4D getRotationQuat()
236
      {
237
      return mQuatAccumulated;
238
      }
239
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241
242 5ba13c05 Leszek Koltunski
  public void recomputeScaleFactor(int scrWidth, int scrHeight)
243 fdec60a3 Leszek Koltunski
    {
244 ba740a0c Leszek Koltunski
    float factor = scrWidth>scrHeight ? scrHeight : scrWidth;
245
    float scaleFactor = OBJECT_SCREEN_RATIO*NODE_FBO_SIZE/mSize;
246 27a70eae Leszek Koltunski
247 5ba13c05 Leszek Koltunski
    mNodeScale.set(factor,factor,factor);
248 27a70eae Leszek Koltunski
    mScale.set(scaleFactor,scaleFactor,scaleFactor);
249 fdec60a3 Leszek Koltunski
    }
250 27a70eae Leszek Koltunski
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252
253 a10ada2a Leszek Koltunski
  public void savePreferences(SharedPreferences.Editor editor)
254
    {
255
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].savePreferences(editor);
256
    }
257 f16ff19d Leszek Koltunski
258 a10ada2a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
259 27a70eae Leszek Koltunski
260 a10ada2a Leszek Koltunski
  public void restorePreferences(SharedPreferences preferences)
261
    {
262
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].restorePreferences(preferences);
263
    }
264 27a70eae Leszek Koltunski
265 a10ada2a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
266 74686c71 Leszek Koltunski
267 a10ada2a Leszek Koltunski
  public long finishRotationNow(EffectListener listener)
268
    {
269
    boolean first = true;
270
    long effectID=0;
271
272
    for(int i=0; i<NUM_CUBITS; i++)
273
      {
274 efef689c Leszek Koltunski
      if( belongsToRotation(i,mRotAxis,mRotRow) )
275 a10ada2a Leszek Koltunski
        {
276
        if( first )
277
          {
278
          first=false;
279
          effectID = mCubits[i].finishRotationNow(listener);
280
          }
281
        resetRotationAngle(mCubits[i].mRotationAngle);
282
        }
283
      }
284
285
    return effectID;
286
    }
287
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289
290
  public void releaseResources()
291
    {
292
    mTexture.markForDeletion();
293
294
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].releaseResources();
295
    }
296
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298
299
  public void apply(Effect effect, int position)
300
    {
301
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].mEffect.apply(effect, position);
302
    }
303
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305
306
  public void remove(long effectID)
307
    {
308
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].mEffect.abortById(effectID);
309
    }
310 74686c71 Leszek Koltunski
311 a10ada2a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
312
313
  public void solve()
314
    {
315
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].solve();
316
    }
317
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319
320
  public boolean isSolved()
321
    {
322
    Static4D q = mCubits[0].mQuatScramble;
323
324
    float x = q.get0();
325
    float y = q.get1();
326
    float z = q.get2();
327
    float w = q.get3();
328
329
    for(int i=0; i<NUM_CUBITS; i++)
330
      {
331
      q = mCubits[i].mQuatScramble;
332
333
      if( q.get0()!=x || q.get1()!=y || q.get2()!=z || q.get3()!=w ) return false;
334
      }
335
336
    return true;
337
    }
338
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340
341 efef689c Leszek Koltunski
  public void beginNewRotation(int axis, int row )
342 a10ada2a Leszek Koltunski
    {
343 3c4a326c Leszek Koltunski
    mRotAxis = axis;
344 a10ada2a Leszek Koltunski
    mRotRow  = row;
345
346
    mRotationAngleStatic.set0(0.0f);
347
348
    for(int i=0; i<NUM_CUBITS; i++)
349 efef689c Leszek Koltunski
      if( belongsToRotation(i,mRotAxis,mRotRow) )
350 a10ada2a Leszek Koltunski
        {
351
        mCubits[i].beginNewRotation(axis);
352
        }
353
     }
354
355
///////////////////////////////////////////////////////////////////////////////////////////////////
356
357 efef689c Leszek Koltunski
  public long addNewRotation( int axis, int row, int angle, long durationMillis, EffectListener listener )
358 a10ada2a Leszek Koltunski
     {
359
     long effectID=0;
360
     boolean first = true;
361
362 3c4a326c Leszek Koltunski
     mRotAxis = axis;
363 a10ada2a Leszek Koltunski
     mRotRow  = row;
364
365
     mRotationAngleStatic.set0(0.0f);
366
367
     for(int i=0; i<NUM_CUBITS; i++)
368 efef689c Leszek Koltunski
       if( belongsToRotation(i,mRotAxis,mRotRow) )
369 a10ada2a Leszek Koltunski
         {
370
         mCubits[i].addNewRotation(axis,durationMillis,angle);
371
372
         if( first )
373
           {
374
           first = false;
375
           effectID = mCubits[i].setUpCallback(listener);
376
           }
377
         }
378
379
     return effectID;
380
     }
381
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
384
  public void removeRotationNow()
385
     {
386
     boolean first = true;
387
     Static4D quat = null;
388
389
     for(int i=0; i<NUM_CUBITS; i++)
390 efef689c Leszek Koltunski
       if( belongsToRotation(i,mRotAxis,mRotRow) )
391 a10ada2a Leszek Koltunski
         {
392
         if( first )
393
           {
394
           first = false;
395 3c4a326c Leszek Koltunski
           quat = mCubits[i].returnRotationQuat(mRotAxis);
396 a10ada2a Leszek Koltunski
           }
397
398
         mCubits[i].removeRotationNow(quat);
399
         }
400
401
     mRotationAngleStatic.set0(0);
402
     }
403
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405
406
  abstract int getNumCubits(int size);
407
  abstract int[][] getCubitPositions(int size);
408
  abstract float[] getLegalQuats();
409 411c6285 Leszek Koltunski
  abstract int getNumFaces();
410
  abstract void createFaceTexture(Canvas canvas, Paint paint, int face);
411
  abstract MeshBase createCubitMesh(int vertices);
412 efef689c Leszek Koltunski
  abstract Static3D[] getRotationAxis();
413 fdec60a3 Leszek Koltunski
  }