Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.java @ 9ce78850

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.objects;
21

    
22
import android.content.res.Resources;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.effect.VertexEffect;
30
import org.distorted.library.effect.VertexEffectMove;
31
import org.distorted.library.effect.VertexEffectRotate;
32
import org.distorted.library.effect.VertexEffectScale;
33
import org.distorted.library.main.DistortedEffects;
34
import org.distorted.library.main.DistortedTexture;
35
import org.distorted.library.mesh.MeshBase;
36
import org.distorted.library.mesh.MeshJoined;
37
import org.distorted.library.mesh.MeshPolygon;
38
import org.distorted.library.mesh.MeshSquare;
39
import org.distorted.library.type.Static1D;
40
import org.distorted.library.type.Static3D;
41
import org.distorted.library.type.Static4D;
42
import org.distorted.main.R;
43

    
44
import java.util.Random;
45

    
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

    
48
public class TwistyIvy extends TwistyObject
49
{
50
  public static final float IVY_D = 0.003f;
51
  public static final float IVY_C = 0.59f;
52
  public static final float IVY_M = 0.35f;
53
  private static final int IVY_N = 8;
54

    
55
  private static final int FACES_PER_CUBIT =6;
56

    
57
  // the four rotation axis of a RubikIvy. Must be normalized.
58
  static final Static3D[] ROT_AXIS = new Static3D[]
59
         {
60
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
61
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
62
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
63
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
64
         };
65

    
66
  private static final int[] BASIC_ANGLE = new int[] { 3,3,3,3 };
67

    
68
  private static final int[] FACE_COLORS = new int[]
69
         {
70
           COLOR_YELLOW, COLOR_WHITE,
71
           COLOR_BLUE  , COLOR_GREEN,
72
           COLOR_RED   , COLOR_ORANGE
73
         };
74

    
75
  // All legal rotation quats of a RubikIvy
76
  private static final Static4D[] QUATS = new Static4D[]
77
         {
78
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
79
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
80
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
81
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
82

    
83
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
84
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
85
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
86
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
87
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
88
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
89
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
90
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
91
         };
92

    
93
  private static final int[][] mFaceMap =
94
         {
95
           {  4, 2, 0, 12,12,12 },
96
           {  5, 2, 1, 12,12,12 },
97
           {  4, 3, 1, 12,12,12 },
98
           {  5, 3, 0, 12,12,12 },
99

    
100
           {  6, 12,12,12,12,12 },
101
           {  7, 12,12,12,12,12 },
102
           {  8, 12,12,12,12,12 },
103
           {  9, 12,12,12,12,12 },
104
           { 10, 12,12,12,12,12 },
105
           { 11, 12,12,12,12,12 },
106
         };
107

    
108
  private static MeshBase mCornerMesh, mFaceMesh;
109

    
110
///////////////////////////////////////////////////////////////////////////////////////////////////
111

    
112
  TwistyIvy(int size, Static4D quat, DistortedTexture texture,
113
            MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
114
    {
115
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.IVY, res, scrWidth);
116
    }
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

    
120
  float getScreenRatio()
121
    {
122
    return 1.0f;
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

    
127
  Static4D[] getQuats()
128
    {
129
    return QUATS;
130
    }
131

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  int getNumFaces()
135
    {
136
    return FACE_COLORS.length;
137
    }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

    
141
  boolean shouldResetTextureMaps()
142
    {
143
    return false;
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  int getNumStickerTypes(int numLayers)
149
    {
150
    return 2;
151
    }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

    
155
  float[][] getCuts(int numLayers)
156
    {
157
    float[] cut = new float[] {0.0f};
158
    return new float[][] { cut,cut,cut,cut };
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  int getNumCubitFaces()
164
    {
165
    return FACES_PER_CUBIT;
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  float[][] getCubitPositions(int numLayers)
171
    {
172
    final float DIST_CORNER = (numLayers-1)*0.50f;
173
    final float DIST_CENTER = (numLayers-1)*0.50f;
174

    
175
    final float[][] CENTERS = new float[10][];
176

    
177
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
178
    CENTERS[1] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
179
    CENTERS[2] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
180
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
181
    CENTERS[4] = new float[] { DIST_CENTER,           0,           0 };
182
    CENTERS[5] = new float[] {-DIST_CENTER,           0,           0 };
183
    CENTERS[6] = new float[] {           0, DIST_CENTER,           0 };
184
    CENTERS[7] = new float[] {           0,-DIST_CENTER,           0 };
185
    CENTERS[8] = new float[] {           0,           0, DIST_CENTER };
186
    CENTERS[9] = new float[] {           0,           0,-DIST_CENTER };
187

    
188
    return CENTERS;
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  private int getQuat(int cubit)
194
    {
195
    switch(cubit)
196
      {
197
      case  0: return 0;
198
      case  1: return 2;
199
      case  2: return 3;
200
      case  3: return 1;
201

    
202
      case  4: return 8;
203
      case  5: return 11;
204
      case  6: return 10;
205
      case  7: return 9;
206
      case  8: return 0;
207
      case  9: return 2;
208
      }
209

    
210
    return 0;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  MeshBase createFacesIvyCorner()
216
    {
217
    MeshBase[] meshes = new MeshBase[6];
218

    
219
    final float angle = (float)Math.PI/(2*IVY_N);
220
    final float CORR  = 1.0f - 2*IVY_D;
221
    final float DIST  = -0.5f*CORR + IVY_D;
222
    float[] vertices  = new float[2*(IVY_N+1)+6];
223

    
224
    vertices[0] = (0.5f-IVY_M) * IVY_C;
225
    vertices[1] = (DIST-IVY_M) * IVY_C;
226
    vertices[2] = (0.5f-IVY_M) * IVY_C;
227
    vertices[3] = (0.5f-IVY_M) * IVY_C;
228
    vertices[4] = (DIST-IVY_M) * IVY_C;
229
    vertices[5] = (0.5f-IVY_M) * IVY_C;
230

    
231
    for(int i=0; i<=IVY_N; i++)
232
      {
233
      float ang = (IVY_N-i)*angle;
234
      float sin = (float)Math.sin(ang);
235
      float cos = (float)Math.cos(ang);
236

    
237
      vertices[2*i+6] = (CORR*(cos-0.5f)-IVY_M)*IVY_C;
238
      vertices[2*i+7] = (CORR*(sin-0.5f)-IVY_M)*IVY_C;
239
      }
240

    
241
    FactoryCubit factory = FactoryCubit.getInstance();
242
    float[] bands0 = factory.computeBands(+0.012f,20,0.2f,0.5f,7);
243
    float[] bands1 = factory.computeBands(-0.100f,20,0.2f,0.0f,2);
244

    
245
    meshes[0] = new MeshPolygon(vertices,bands0,1,2);
246
    meshes[0].setEffectAssociation(0,1,0);
247
    meshes[1] = meshes[0].copy(true);
248
    meshes[1].setEffectAssociation(0,2,0);
249
    meshes[2] = meshes[0].copy(true);
250
    meshes[2].setEffectAssociation(0,4,0);
251
    meshes[3] = new MeshPolygon(vertices,bands1,1,2);
252
    meshes[3].setEffectAssociation(0,8,0);
253
    meshes[4] = meshes[3].copy(true);
254
    meshes[4].setEffectAssociation(0,16,0);
255
    meshes[5] = meshes[3].copy(true);
256
    meshes[5].setEffectAssociation(0,32,0);
257

    
258
    return new MeshJoined(meshes);
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  private VertexEffect[] createVertexEffectsIvyCorner()
264
    {
265
    Static3D axisX  = new Static3D(1,0,0);
266
    Static3D axisY  = new Static3D(0,1,0);
267
    Static1D angle1 = new Static1D(+90);
268
    Static1D angle2 = new Static1D(-90);
269
    Static3D center = new Static3D(0,0,0);
270
    Static3D move1  = new Static3D(IVY_M-0.5f,IVY_M-0.5f,0);
271

    
272
    VertexEffect[] effect = new VertexEffect[5];
273

    
274
    effect[0] = new VertexEffectScale(1/IVY_C);
275
    effect[1] = new VertexEffectMove(move1);
276
    effect[2] = new VertexEffectScale(new Static3D(1,1,-1));
277
    effect[3] = new VertexEffectRotate(angle1,axisX,center);
278
    effect[4] = new VertexEffectRotate(angle2,axisY,center);
279

    
280
    effect[2].setMeshAssociation(54,-1);  // meshes 1,2,4,5
281
    effect[3].setMeshAssociation(18,-1);  // meshes 1,4
282
    effect[4].setMeshAssociation(36,-1);  // meshes 2,5
283

    
284
    return effect;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  private MeshBase createFacesIvyFace()
290
    {
291
    MeshBase[] meshes = new MeshBase[2];
292

    
293
    final float angle = (float)Math.PI/(2*IVY_N);
294
    final float CORR  = 1.0f - 2*IVY_D;
295
    float[] vertices = new float[4*IVY_N];
296

    
297
    for(int i=0; i<IVY_N; i++)
298
      {
299
      float sin = (float)Math.sin(i*angle);
300
      float cos = (float)Math.cos(i*angle);
301

    
302
      vertices[2*i          ] = CORR*(0.5f-cos);
303
      vertices[2*i+1        ] = CORR*(0.5f-sin);
304
      vertices[2*i  +2*IVY_N] = CORR*(cos-0.5f);
305
      vertices[2*i+1+2*IVY_N] = CORR*(sin-0.5f);
306
      }
307

    
308
    FactoryCubit factory = FactoryCubit.getInstance();
309
    float[] bands0 = factory.computeBands(+0.03f,35,0.5f,0.5f,5);
310
    float[] bands1 = factory.computeBands(-0.10f,45,0.5f,0.0f,2);
311

    
312
    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
313
    meshes[0].setEffectAssociation(0,1,0);
314
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
315
    meshes[1].setEffectAssociation(0,2,0);
316

    
317
    return new MeshJoined(meshes);
318
    }
319

    
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321

    
322
  private MeshBase createIvyFaceMesh()
323
    {
324
    MeshBase mesh = createFacesIvyFace();
325

    
326
    Static3D center = new Static3D(-0.0f,-0.0f,-0.5f);
327
    Static3D[] vertices = new Static3D[2];
328
    vertices[0] = new Static3D(-0.5f,+0.5f,+0.0f);
329
    vertices[1] = new Static3D(+0.5f,-0.5f,+0.0f);
330

    
331
    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.03f,0.10f);
332

    
333
    mesh.mergeEffComponents();
334
    mesh.addEmptyTexComponent();
335
    mesh.addEmptyTexComponent();
336
    mesh.addEmptyTexComponent();
337
    mesh.addEmptyTexComponent();
338

    
339
    return mesh;
340
    }
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342

    
343
  private MeshBase createIvyCornerMesh()
344
    {
345
    MeshBase mesh = createFacesIvyCorner();
346
    VertexEffect[] effects = createVertexEffectsIvyCorner();
347
    for( VertexEffect effect : effects ) mesh.apply(effect);
348

    
349
    Static3D center = new Static3D(-0.5f,-0.5f,-0.5f);
350
    Static3D[] vertices = new Static3D[4];
351
    vertices[0] = new Static3D(+0.0f,+0.0f,+0.0f);
352
    vertices[1] = new Static3D(-1.0f,+0.0f,+0.0f);
353
    vertices[2] = new Static3D(+0.0f,-1.0f,+0.0f);
354
    vertices[3] = new Static3D(+0.0f,+0.0f,-1.0f);
355

    
356
    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.03f,0.10f);
357

    
358
    mesh.mergeEffComponents();
359

    
360
    return mesh;
361
    }
362

    
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364

    
365
  MeshBase createCubitMesh(int cubit, int numLayers)
366
    {
367
    MeshBase mesh;
368

    
369
    if( cubit<4 )
370
      {
371
      if( mCornerMesh==null ) mCornerMesh = createIvyCornerMesh();
372
      mesh = mCornerMesh.copy(true);
373
      }
374
    else
375
      {
376
      if( mFaceMesh==null ) mFaceMesh = createIvyFaceMesh();
377
      mesh = mFaceMesh.copy(true);
378
      }
379

    
380
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[getQuat(cubit)], new Static3D(0,0,0) );
381
    mesh.apply(quat,0xffffffff,0);
382

    
383
    return mesh;
384
    }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387

    
388
  int getFaceColor(int cubit, int cubitface, int numLayers)
389
    {
390
    return mFaceMap[cubit][cubitface];
391
    }
392

    
393
///////////////////////////////////////////////////////////////////////////////////////////////////
394

    
395
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
396
    {
397
    int COLORS = FACE_COLORS.length;
398
    FactorySticker factory = FactorySticker.getInstance();
399

    
400
    if( face<COLORS )
401
      {
402
      float S = 0.03f;
403
      float R = 0.02f;
404

    
405
      float ANGLE = (float)(Math.PI/4);
406

    
407
      float A = (+0.5f-IVY_M)*IVY_C;
408
      float B = (-0.5f-IVY_M)*IVY_C;
409

    
410
      float[] vertices = new float[] { A, B, A, A, B, A };
411
      float[] angles   = new float[] { 0, 0, ANGLE };
412

    
413
      factory.drawRoundedPolygon(canvas, paint, left, top, vertices, angles, S, FACE_COLORS[face%COLORS], R);
414
      }
415
    else
416
      {
417
      float S = 0.08f;
418
      float R = 0.06f;
419

    
420
      float ANGLE = (float)(Math.PI/4);
421
      float A = 0.50f-IVY_D;
422

    
423
      float[] vertices = new float[] { -A, A, A, -A };
424
      float[] angles   = new float[] { ANGLE, ANGLE };
425

    
426
      factory.drawRoundedPolygon(canvas, paint, left, top, vertices, angles, S, FACE_COLORS[face%COLORS], R);
427
      }
428
    }
429

    
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431

    
432
  float returnMultiplier()
433
    {
434
    return 2.0f;
435
    }
436

    
437
///////////////////////////////////////////////////////////////////////////////////////////////////
438
// PUBLIC API
439

    
440
  public Static3D[] getRotationAxis()
441
    {
442
    return ROT_AXIS;
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
  public int[] getBasicAngle()
448
    {
449
    return BASIC_ANGLE;
450
    }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453

    
454
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
455
    {
456
    if( curr==0 )
457
      {
458
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
459
      }
460
    else
461
      {
462
      int newVector = rnd.nextInt(NUM_AXIS -1);
463
      scramble[curr][0] = (newVector>=scramble[curr-1][0] ? newVector+1 : newVector);
464
      }
465

    
466
    scramble[curr][1] = rnd.nextFloat()<=0.5f ? 0 : 1;
467

    
468
    switch( rnd.nextInt(2) )
469
      {
470
      case 0: scramble[curr][2] = -1; break;
471
      case 1: scramble[curr][2] =  1; break;
472
      }
473
    }
474

    
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476
// The Ivy is solved if and only if:
477
//
478
// 1) all 4 of its corner cubits are rotated with the same quat
479
// 2) all its face cubits are rotated with the same quat like the corner ones,
480
//    and optionally they also might be upside down.
481
//
482
// i.e.
483
// cubits [4] and [5] - might be extra QUAT[1]
484
// cubits [6] and [7] - might be extra QUAT[2]
485
// cubits [8] and [9] - might be extra QUAT[3]
486

    
487
  public boolean isSolved()
488
    {
489
    int q1,q = CUBITS[0].mQuatIndex;
490

    
491
    if( CUBITS[1].mQuatIndex == q &&
492
        CUBITS[2].mQuatIndex == q &&
493
        CUBITS[3].mQuatIndex == q  )
494
      {
495
      q1 = mulQuat(q,1);
496
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
497
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
498

    
499
      q1 = mulQuat(q,2);
500
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
501
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
502

    
503
      q1 = mulQuat(q,3);
504
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
505
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
506

    
507
      return true;
508
      }
509

    
510
    return false;
511
    }
512

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514
// only needed for solvers - there are no Ivy solvers ATM)
515

    
516
  public String retObjectString()
517
    {
518
    return "";
519
    }
520

    
521
///////////////////////////////////////////////////////////////////////////////////////////////////
522

    
523
  public int getObjectName(int numLayers)
524
    {
525
    return R.string.ivy2;
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529

    
530
  public int getInventor(int numLayers)
531
    {
532
    return R.string.ivy2_inventor;
533
    }
534

    
535
///////////////////////////////////////////////////////////////////////////////////////////////////
536

    
537
  public int getComplexity(int numLayers)
538
    {
539
    return 1;
540
    }
541
}
(28-28/41)