Project

General

Profile

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

magiccube / src / main / java / org / distorted / object / RubikObject.java @ 10a2e360

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
package org.distorted.object;
21

    
22
import android.content.SharedPreferences;
23
import android.graphics.Bitmap;
24
import android.graphics.Canvas;
25
import android.graphics.Paint;
26

    
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
import org.distorted.library.mesh.MeshBase;
35
import org.distorted.library.mesh.MeshRectangles;
36
import org.distorted.library.message.EffectListener;
37
import org.distorted.library.type.Dynamic1D;
38
import org.distorted.library.type.Static1D;
39
import org.distorted.library.type.Static3D;
40
import org.distorted.library.type.Static4D;
41

    
42
import static org.distorted.magic.RubikRenderer.NODE_FBO_SIZE;
43

    
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45

    
46
public abstract class RubikObject extends DistortedNode
47
  {
48
  static final int TEXTURE_HEIGHT = 128;
49
  static final float OBJECT_SCREEN_RATIO = 0.5f;
50
  final float[] LEGAL_QUATS;
51
  final Static3D[] ROTATION_AXIS;
52

    
53
  private static final int POST_ROTATION_MILLISEC = 500;
54
  private final int NUM_CUBITS;
55
  private int mRotRow;
56
  private int mRotAxis;
57
  private Static3D mScale, mNodeScale;
58
  private Static4D mQuatAccumulated;
59
  private Cubit[] mCubits;
60

    
61
  int mSize;
62

    
63
  Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
64
  DistortedTexture mTexture;
65

    
66
  VertexEffectSink mSinkEffect;
67
  MatrixEffectScale mScaleEffect;
68
  MatrixEffectQuaternion mQuatCEffect;
69
  MatrixEffectQuaternion mQuatAEffect;
70

    
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72

    
73
  RubikObject(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture nodeTexture, MeshRectangles nodeMesh, DistortedEffects nodeEffects)
74
    {
75
    super(nodeTexture,nodeEffects,nodeMesh);
76

    
77
    resizeFBO(NODE_FBO_SIZE, NODE_FBO_SIZE);
78

    
79
    Static3D[] positions = getCubitPositions(size);
80

    
81
    LEGAL_QUATS = getLegalQuats();
82
    NUM_CUBITS  = positions.length;
83
    ROTATION_AXIS = getRotationAxis();
84

    
85
    mSize = size;
86

    
87
    mRotationAngleStatic = new Static1D(0);
88
    mRotationAngleMiddle = new Static1D(0);
89
    mRotationAngleFinal  = new Static1D(0);
90

    
91
    mScale    = new Static3D(1,1,1);
92
    mNodeScale= new Static3D(1,1,1);
93

    
94
    mQuatAccumulated = quatAcc;
95

    
96
    Static3D center = new Static3D(0,0,0);
97
    Static4D region = new Static4D(0,0,0,0.72f);
98

    
99
    mSinkEffect = new VertexEffectSink( new Static1D(getSinkStrength()), center, region );
100
    mScaleEffect = new MatrixEffectScale(mScale);
101
    mQuatCEffect = new MatrixEffectQuaternion(quatCur, center);
102
    mQuatAEffect = new MatrixEffectQuaternion(quatAcc, center);
103

    
104
    MatrixEffectScale nodeScaleEffect = new MatrixEffectScale(mNodeScale);
105
    nodeEffects.apply(nodeScaleEffect);
106

    
107
    mCubits = new Cubit[NUM_CUBITS];
108
    mTexture = new DistortedTexture();
109

    
110
    int vertices = (int)(24.0f/mSize + 2.0f);
111

    
112
    for(int i=0; i<NUM_CUBITS; i++)
113
      {
114
      MeshBase cubitMesh = createCubitMesh(vertices);
115
      mCubits[i] = new Cubit(this,cubitMesh,positions[i]);
116
      textureCubitMesh(cubitMesh,i);
117

    
118
      attach(mCubits[i].mNode);
119
      }
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
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

    
153
  private boolean belongsToRotation( int cubit, int axis, int row)
154
    {
155
    return mCubits[cubit].mRotationRow[axis]==row;
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private void resetRotationAngle(Dynamic1D rotationAngle)
161
    {
162
    rotationAngle.setDuration(POST_ROTATION_MILLISEC);
163
    rotationAngle.resetToBeginning();
164
    rotationAngle.removeAll();
165
    rotationAngle.add(mRotationAngleStatic);
166
    rotationAngle.add(mRotationAngleMiddle);
167
    rotationAngle.add(mRotationAngleFinal);
168
    }
169

    
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

    
172
  private float getSinkStrength()
173
    {
174
    switch(mSize)
175
      {
176
      case 1 : return 1.1f;
177
      case 2 : return 1.5f;
178
      case 3 : return 1.8f;
179
      case 4 : return 2.0f;
180
      default: return 3.0f - 4.0f/mSize;
181
      }
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// the getFaceColors + final black in a horizontal strip.
186

    
187
  public void createTexture()
188
    {
189
    Bitmap bitmap;
190

    
191
    final int numColors = getNumFaces();
192

    
193
    Paint paint = new Paint();
194
    bitmap = Bitmap.createBitmap( (numColors+1)*TEXTURE_HEIGHT, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
195
    Canvas canvas = new Canvas(bitmap);
196

    
197
    paint.setAntiAlias(true);
198
    paint.setTextAlign(Paint.Align.CENTER);
199
    paint.setStyle(Paint.Style.FILL);
200

    
201
    paint.setColor(0xff000000);
202
    canvas.drawRect(0, 0, (numColors+1)*TEXTURE_HEIGHT, TEXTURE_HEIGHT, paint);
203

    
204
    for(int i=0; i<numColors; i++)
205
      {
206
      createFaceTexture(canvas,paint,i);
207
      }
208

    
209
    mTexture.setTexture(bitmap);
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  public int getSize()
215
    {
216
    return mSize;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  public void continueRotation(float angleInDegrees)
222
    {
223
    mRotationAngleStatic.set0(angleInDegrees);
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  public Static4D getRotationQuat()
229
      {
230
      return mQuatAccumulated;
231
      }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  public void recomputeScaleFactor(int scrWidth, int scrHeight)
236
    {
237
    float factor = scrWidth>scrHeight ? scrHeight : scrWidth;
238
    float scaleFactor = OBJECT_SCREEN_RATIO*NODE_FBO_SIZE/mSize;
239

    
240
    mNodeScale.set(factor,factor,factor);
241
    mScale.set(scaleFactor,scaleFactor,scaleFactor);
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  public void savePreferences(SharedPreferences.Editor editor)
247
    {
248
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].savePreferences(editor);
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  public void restorePreferences(SharedPreferences preferences)
254
    {
255
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].restorePreferences(preferences);
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  public long finishRotationNow(EffectListener listener)
261
    {
262
    boolean first = true;
263
    long effectID=0;
264

    
265
    for(int i=0; i<NUM_CUBITS; i++)
266
      {
267
      if( belongsToRotation(i,mRotAxis,mRotRow) )
268
        {
269
        if( first )
270
          {
271
          first=false;
272
          effectID = mCubits[i].finishRotationNow(listener);
273
          }
274
        resetRotationAngle(mCubits[i].mRotationAngle);
275
        }
276
      }
277

    
278
    return effectID;
279
    }
280

    
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282

    
283
  public void releaseResources()
284
    {
285
    mTexture.markForDeletion();
286

    
287
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].releaseResources();
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  public void apply(Effect effect, int position)
293
    {
294
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].mEffect.apply(effect, position);
295
    }
296

    
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298

    
299
  public void remove(long effectID)
300
    {
301
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].mEffect.abortById(effectID);
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

    
306
  public void solve()
307
    {
308
    for(int i=0; i<NUM_CUBITS; i++) mCubits[i].solve();
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  public boolean isSolved()
314
    {
315
    Static4D q = mCubits[0].mQuatScramble;
316

    
317
    float x = q.get0();
318
    float y = q.get1();
319
    float z = q.get2();
320
    float w = q.get3();
321

    
322
    for(int i=0; i<NUM_CUBITS; i++)
323
      {
324
      q = mCubits[i].mQuatScramble;
325

    
326
      if( q.get0()!=x || q.get1()!=y || q.get2()!=z || q.get3()!=w ) return false;
327
      }
328

    
329
    return true;
330
    }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
  public void beginNewRotation(int axis, int row )
335
    {
336
    mRotAxis = axis;
337
    mRotRow  = row;
338

    
339
    mRotationAngleStatic.set0(0.0f);
340

    
341
    for(int i=0; i<NUM_CUBITS; i++)
342
      if( belongsToRotation(i,mRotAxis,mRotRow) )
343
        {
344
        mCubits[i].beginNewRotation(axis);
345
        }
346
     }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  public long addNewRotation( int axis, int row, int angle, long durationMillis, EffectListener listener )
351
     {
352
     long effectID=0;
353
     boolean first = true;
354

    
355
     mRotAxis = axis;
356
     mRotRow  = row;
357

    
358
     mRotationAngleStatic.set0(0.0f);
359

    
360
     for(int i=0; i<NUM_CUBITS; i++)
361
       if( belongsToRotation(i,mRotAxis,mRotRow) )
362
         {
363
         mCubits[i].addNewRotation(axis,durationMillis,angle);
364

    
365
         if( first )
366
           {
367
           first = false;
368
           effectID = mCubits[i].setUpCallback(listener);
369
           }
370
         }
371

    
372
     return effectID;
373
     }
374

    
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376

    
377
  public void removeRotationNow()
378
     {
379
     boolean first = true;
380
     Static4D quat = null;
381

    
382
     for(int i=0; i<NUM_CUBITS; i++)
383
       if( belongsToRotation(i,mRotAxis,mRotRow) )
384
         {
385
         if( first )
386
           {
387
           first = false;
388
           quat = mCubits[i].returnRotationQuat(mRotAxis);
389
           }
390

    
391
         mCubits[i].removeRotationNow(quat);
392
         }
393

    
394
     mRotationAngleStatic.set0(0);
395
     }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398

    
399
  public int getNumRotations()
400
    {
401
    return ROTATION_AXIS.length;
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

    
406
  abstract Static3D[] getCubitPositions(int size);
407
  abstract float[] getLegalQuats();
408
  abstract int getNumFaces();
409
  abstract void createFaceTexture(Canvas canvas, Paint paint, int face);
410
  abstract MeshBase createCubitMesh(int vertices);
411
  abstract Static3D[] getRotationAxis();
412
  }
(4-4/6)