Project

General

Profile

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

magiccube / src / main / java / org / distorted / object / RubikObject.java @ 89a11f7b

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 49f67f9b Leszek Koltunski
  private Static3D[] mOrigPos;
58 5ba13c05 Leszek Koltunski
  private Static3D mScale, mNodeScale;
59 27a70eae Leszek Koltunski
  private Static4D mQuatAccumulated;
60 b32444ee Leszek Koltunski
  private Cubit[] mCubits;
61 49f67f9b Leszek Koltunski
  private int mSize;
62 27a70eae Leszek Koltunski
63 e844c116 Leszek Koltunski
  float mStart, mStep;
64 fdec60a3 Leszek Koltunski
65 27a70eae Leszek Koltunski
  Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
66
  DistortedTexture mTexture;
67
68
  VertexEffectSink mSinkEffect;
69
  MatrixEffectScale mScaleEffect;
70
  MatrixEffectQuaternion mQuatCEffect;
71
  MatrixEffectQuaternion mQuatAEffect;
72
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74 fdec60a3 Leszek Koltunski
75 411c6285 Leszek Koltunski
  RubikObject(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture nodeTexture, MeshRectangles nodeMesh, DistortedEffects nodeEffects)
76 fdec60a3 Leszek Koltunski
    {
77 411c6285 Leszek Koltunski
    super(nodeTexture,nodeEffects,nodeMesh);
78 fdec60a3 Leszek Koltunski
79 ba740a0c Leszek Koltunski
    resizeFBO(NODE_FBO_SIZE, NODE_FBO_SIZE);
80 d41742f7 Leszek Koltunski
81 49f67f9b Leszek Koltunski
    mOrigPos = getCubitPositions(size);
82 10a2e360 Leszek Koltunski
83 f16ff19d Leszek Koltunski
    LEGAL_QUATS = getLegalQuats();
84 49f67f9b Leszek Koltunski
    NUM_CUBITS  = mOrigPos.length;
85 efef689c Leszek Koltunski
    ROTATION_AXIS = getRotationAxis();
86 a10ada2a Leszek Koltunski
87 27a70eae Leszek Koltunski
    mSize = size;
88 49f67f9b Leszek Koltunski
    computeStartAndStep(mOrigPos);
89 e844c116 Leszek Koltunski
90 27a70eae Leszek Koltunski
    mRotationAngleStatic = new Static1D(0);
91
    mRotationAngleMiddle = new Static1D(0);
92
    mRotationAngleFinal  = new Static1D(0);
93
94
    mScale    = new Static3D(1,1,1);
95
    mNodeScale= new Static3D(1,1,1);
96
97
    mQuatAccumulated = quatAcc;
98
99 5ba13c05 Leszek Koltunski
    Static3D center = new Static3D(0,0,0);
100 5974d2ae Leszek Koltunski
    Static4D region = new Static4D(0,0,0,0.72f);
101 27a70eae Leszek Koltunski
102 5ba13c05 Leszek Koltunski
    mSinkEffect = new VertexEffectSink( new Static1D(getSinkStrength()), center, region );
103 27a70eae Leszek Koltunski
    mScaleEffect = new MatrixEffectScale(mScale);
104 5ba13c05 Leszek Koltunski
    mQuatCEffect = new MatrixEffectQuaternion(quatCur, center);
105
    mQuatAEffect = new MatrixEffectQuaternion(quatAcc, center);
106 27a70eae Leszek Koltunski
107
    MatrixEffectScale nodeScaleEffect = new MatrixEffectScale(mNodeScale);
108 411c6285 Leszek Koltunski
    nodeEffects.apply(nodeScaleEffect);
109 a10ada2a Leszek Koltunski
110
    mCubits = new Cubit[NUM_CUBITS];
111 5974d2ae Leszek Koltunski
    mTexture = new DistortedTexture();
112 a10ada2a Leszek Koltunski
113
    int vertices = (int)(24.0f/mSize + 2.0f);
114
115
    for(int i=0; i<NUM_CUBITS; i++)
116
      {
117 89a11f7b Leszek Koltunski
      MeshBase cubitMesh = createCubitMesh(i,vertices);
118 49f67f9b Leszek Koltunski
      mCubits[i] = new Cubit(this,cubitMesh,mOrigPos[i]);
119 efef689c Leszek Koltunski
      textureCubitMesh(cubitMesh,i);
120 a10ada2a Leszek Koltunski
121
      attach(mCubits[i].mNode);
122
      }
123 27a70eae Leszek Koltunski
    }
124
125 efef689c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
126
127
  private void textureCubitMesh(MeshBase mesh, int cubit)
128
    {
129
    boolean belongs;
130
    final int numFaces = getNumFaces();
131
    final Static4D[] maps = new Static4D[numFaces];
132
    final float ratio = 1.0f/(numFaces+1);
133
134 97d2f701 Leszek Koltunski
    if( 2*ROTATION_AXIS.length == numFaces )  // i.e. there are faces on both ends of the axis (cube)
135 efef689c Leszek Koltunski
      {
136
      for(int i=0; i<numFaces; i++)
137
        {
138
        belongs = belongsToRotation(cubit, i/2, i%2==0 ? mSize-1:0 );
139
        maps[i] = new Static4D( (belongs?i:6)*ratio, 0.0f, ratio, 1.0f);
140
        }
141
      }
142 97d2f701 Leszek Koltunski
    else if( ROTATION_AXIS.length == numFaces )  // just a single face on the right end of an axis (pyraminx)
143 efef689c Leszek Koltunski
      {
144
      for(int i=0; i<numFaces; i++)
145
        {
146 49f67f9b Leszek Koltunski
        belongs = belongsToRotation(cubit, i, 0 );
147 efef689c Leszek Koltunski
        maps[i] = new Static4D( (belongs?i:6)*ratio, 0.0f, ratio, 1.0f);
148
        }
149
      }
150
151
    mesh.setTextureMap(maps);
152
    }
153
154 e844c116 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
155 97d2f701 Leszek Koltunski
// Cast centers of all Cubits on the first rotation Axis and compute the leftmost and rightmost
156
// one. From there compute the 'start' (i.e. the leftmost) and 'step' (i.e. distance between two
157
// consecutive).
158
// it is assumed that other rotation axis have the same 'start' and 'step' - this is the case with
159
// the Cube and the Pyraminx.
160
// Start and Step are then needed to compute which rotation row (with respect to a given axis) a
161
// given Cubit belongs to.
162 e844c116 Leszek Koltunski
163
  private void computeStartAndStep(Static3D[] pos)
164
    {
165
    float min = Float.MAX_VALUE;
166
    float max = Float.MIN_VALUE;
167
    float axisX = ROTATION_AXIS[0].get0();
168
    float axisY = ROTATION_AXIS[0].get1();
169
    float axisZ = ROTATION_AXIS[0].get2();
170
    float tmp;
171
172
    for(int i=0; i<NUM_CUBITS; i++)
173
      {
174
      tmp = pos[i].get0()*axisX + pos[i].get1()*axisY + pos[i].get2()*axisZ;
175
      if( tmp<min ) min=tmp;
176
      if( tmp>max ) max=tmp;
177
      }
178
179
    mStart = min;
180
    mStep  = (max-min+1.0f)/mSize;
181
    }
182
183 efef689c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
184
185
  private boolean belongsToRotation( int cubit, int axis, int row)
186
    {
187 10a2e360 Leszek Koltunski
    return mCubits[cubit].mRotationRow[axis]==row;
188 efef689c Leszek Koltunski
    }
189
190 f16ff19d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
191
192 a10ada2a Leszek Koltunski
  private void resetRotationAngle(Dynamic1D rotationAngle)
193 f16ff19d Leszek Koltunski
    {
194
    rotationAngle.setDuration(POST_ROTATION_MILLISEC);
195
    rotationAngle.resetToBeginning();
196
    rotationAngle.removeAll();
197
    rotationAngle.add(mRotationAngleStatic);
198
    rotationAngle.add(mRotationAngleMiddle);
199
    rotationAngle.add(mRotationAngleFinal);
200
    }
201
202 fdec60a3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
203
204 27a70eae Leszek Koltunski
  private float getSinkStrength()
205 dd73fdab Leszek Koltunski
    {
206 27a70eae Leszek Koltunski
    switch(mSize)
207
      {
208
      case 1 : return 1.1f;
209
      case 2 : return 1.5f;
210
      case 3 : return 1.8f;
211
      case 4 : return 2.0f;
212
      default: return 3.0f - 4.0f/mSize;
213
      }
214 dd73fdab Leszek Koltunski
    }
215
216 49f67f9b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
217
// Clamp all rotated positions to one of those original ones to avoid accumulating errors.
218
219
  void clampPos(Static3D pos)
220
    {
221
    float currError, minError = Float.MAX_VALUE;
222
    int minErrorIndex= -1;
223
    float x = pos.get0();
224
    float y = pos.get1();
225
    float z = pos.get2();
226
    float xo,yo,zo;
227
228
    for(int i=0; i<NUM_CUBITS; i++)
229
      {
230
      xo = mOrigPos[i].get0();
231
      yo = mOrigPos[i].get1();
232
      zo = mOrigPos[i].get2();
233
234
      currError = (xo-x)*(xo-x) + (yo-y)*(yo-y) + (zo-z)*(zo-z);
235
236
      if( currError<minError )
237
        {
238
        minError = currError;
239
        minErrorIndex = i;
240
        }
241
      }
242
243
    pos.set( mOrigPos[minErrorIndex] );
244
    }
245
246 411c6285 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
247
// the getFaceColors + final black in a horizontal strip.
248
249
  public void createTexture()
250
    {
251
    Bitmap bitmap;
252
253
    final int numColors = getNumFaces();
254
255
    Paint paint = new Paint();
256
    bitmap = Bitmap.createBitmap( (numColors+1)*TEXTURE_HEIGHT, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
257
    Canvas canvas = new Canvas(bitmap);
258
259
    paint.setAntiAlias(true);
260
    paint.setTextAlign(Paint.Align.CENTER);
261
    paint.setStyle(Paint.Style.FILL);
262
263
    paint.setColor(0xff000000);
264
    canvas.drawRect(0, 0, (numColors+1)*TEXTURE_HEIGHT, TEXTURE_HEIGHT, paint);
265
266
    for(int i=0; i<numColors; i++)
267
      {
268
      createFaceTexture(canvas,paint,i);
269
      }
270
271
    mTexture.setTexture(bitmap);
272
    }
273
274 dd73fdab Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
275
276 27a70eae Leszek Koltunski
  public int getSize()
277 fdec60a3 Leszek Koltunski
    {
278 27a70eae Leszek Koltunski
    return mSize;
279 fdec60a3 Leszek Koltunski
    }
280
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282
283 27a70eae Leszek Koltunski
  public void continueRotation(float angleInDegrees)
284 fdec60a3 Leszek Koltunski
    {
285 27a70eae Leszek Koltunski
    mRotationAngleStatic.set0(angleInDegrees);
286 fdec60a3 Leszek Koltunski
    }
287
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289
290 27a70eae Leszek Koltunski
  public Static4D getRotationQuat()
291
      {
292
      return mQuatAccumulated;
293
      }
294
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296
297 5ba13c05 Leszek Koltunski
  public void recomputeScaleFactor(int scrWidth, int scrHeight)
298 fdec60a3 Leszek Koltunski
    {
299 ba740a0c Leszek Koltunski
    float factor = scrWidth>scrHeight ? scrHeight : scrWidth;
300
    float scaleFactor = OBJECT_SCREEN_RATIO*NODE_FBO_SIZE/mSize;
301 27a70eae Leszek Koltunski
302 5ba13c05 Leszek Koltunski
    mNodeScale.set(factor,factor,factor);
303 27a70eae Leszek Koltunski
    mScale.set(scaleFactor,scaleFactor,scaleFactor);
304 fdec60a3 Leszek Koltunski
    }
305 27a70eae Leszek Koltunski
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
308 a10ada2a Leszek Koltunski
  public void savePreferences(SharedPreferences.Editor editor)
309
    {
310
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].savePreferences(editor);
311
    }
312 f16ff19d Leszek Koltunski
313 a10ada2a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
314 27a70eae Leszek Koltunski
315 a10ada2a Leszek Koltunski
  public void restorePreferences(SharedPreferences preferences)
316
    {
317
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].restorePreferences(preferences);
318
    }
319 27a70eae Leszek Koltunski
320 a10ada2a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
321 74686c71 Leszek Koltunski
322 a10ada2a Leszek Koltunski
  public long finishRotationNow(EffectListener listener)
323
    {
324
    boolean first = true;
325
    long effectID=0;
326
327
    for(int i=0; i<NUM_CUBITS; i++)
328
      {
329 efef689c Leszek Koltunski
      if( belongsToRotation(i,mRotAxis,mRotRow) )
330 a10ada2a Leszek Koltunski
        {
331
        if( first )
332
          {
333
          first=false;
334
          effectID = mCubits[i].finishRotationNow(listener);
335
          }
336
        resetRotationAngle(mCubits[i].mRotationAngle);
337
        }
338
      }
339
340
    return effectID;
341
    }
342
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344
345
  public void releaseResources()
346
    {
347
    mTexture.markForDeletion();
348
349
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].releaseResources();
350
    }
351
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353
354
  public void apply(Effect effect, int position)
355
    {
356
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].mEffect.apply(effect, position);
357
    }
358
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
361
  public void remove(long effectID)
362
    {
363
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].mEffect.abortById(effectID);
364
    }
365 74686c71 Leszek Koltunski
366 a10ada2a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
367
368
  public void solve()
369
    {
370
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].solve();
371
    }
372
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374
375
  public boolean isSolved()
376
    {
377
    Static4D q = mCubits[0].mQuatScramble;
378
379
    float x = q.get0();
380
    float y = q.get1();
381
    float z = q.get2();
382
    float w = q.get3();
383
384
    for(int i=0; i<NUM_CUBITS; i++)
385
      {
386
      q = mCubits[i].mQuatScramble;
387
388
      if( q.get0()!=x || q.get1()!=y || q.get2()!=z || q.get3()!=w ) return false;
389
      }
390
391
    return true;
392
    }
393
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395
396 efef689c Leszek Koltunski
  public void beginNewRotation(int axis, int row )
397 a10ada2a Leszek Koltunski
    {
398 3c4a326c Leszek Koltunski
    mRotAxis = axis;
399 a10ada2a Leszek Koltunski
    mRotRow  = row;
400
401
    mRotationAngleStatic.set0(0.0f);
402
403
    for(int i=0; i<NUM_CUBITS; i++)
404 efef689c Leszek Koltunski
      if( belongsToRotation(i,mRotAxis,mRotRow) )
405 a10ada2a Leszek Koltunski
        {
406
        mCubits[i].beginNewRotation(axis);
407
        }
408
     }
409
410
///////////////////////////////////////////////////////////////////////////////////////////////////
411
412 efef689c Leszek Koltunski
  public long addNewRotation( int axis, int row, int angle, long durationMillis, EffectListener listener )
413 a10ada2a Leszek Koltunski
     {
414
     long effectID=0;
415
     boolean first = true;
416
417 3c4a326c Leszek Koltunski
     mRotAxis = axis;
418 a10ada2a Leszek Koltunski
     mRotRow  = row;
419
420
     mRotationAngleStatic.set0(0.0f);
421
422
     for(int i=0; i<NUM_CUBITS; i++)
423 efef689c Leszek Koltunski
       if( belongsToRotation(i,mRotAxis,mRotRow) )
424 a10ada2a Leszek Koltunski
         {
425
         mCubits[i].addNewRotation(axis,durationMillis,angle);
426
427
         if( first )
428
           {
429
           first = false;
430
           effectID = mCubits[i].setUpCallback(listener);
431
           }
432
         }
433
434
     return effectID;
435
     }
436
437
///////////////////////////////////////////////////////////////////////////////////////////////////
438
439
  public void removeRotationNow()
440
     {
441
     boolean first = true;
442
     Static4D quat = null;
443
444
     for(int i=0; i<NUM_CUBITS; i++)
445 efef689c Leszek Koltunski
       if( belongsToRotation(i,mRotAxis,mRotRow) )
446 a10ada2a Leszek Koltunski
         {
447
         if( first )
448
           {
449
           first = false;
450 3c4a326c Leszek Koltunski
           quat = mCubits[i].returnRotationQuat(mRotAxis);
451 a10ada2a Leszek Koltunski
           }
452
453
         mCubits[i].removeRotationNow(quat);
454
         }
455
456
     mRotationAngleStatic.set0(0);
457
     }
458
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460
461 e844c116 Leszek Koltunski
  public int getNumAxis()
462 10a2e360 Leszek Koltunski
    {
463
    return ROTATION_AXIS.length;
464
    }
465
466
///////////////////////////////////////////////////////////////////////////////////////////////////
467
468
  abstract Static3D[] getCubitPositions(int size);
469 a10ada2a Leszek Koltunski
  abstract float[] getLegalQuats();
470 411c6285 Leszek Koltunski
  abstract int getNumFaces();
471
  abstract void createFaceTexture(Canvas canvas, Paint paint, int face);
472 89a11f7b Leszek Koltunski
  abstract MeshBase createCubitMesh(int cubit, int vertices);
473 efef689c Leszek Koltunski
  abstract Static3D[] getRotationAxis();
474 e844c116 Leszek Koltunski
  public abstract int getBasicAngle();
475 fdec60a3 Leszek Koltunski
  }