Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.java @ a38fe4b2

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

    
24
import org.distorted.helpers.FactoryCubit;
25
import org.distorted.helpers.ObjectShape;
26
import org.distorted.helpers.ObjectSticker;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.main.DistortedEffects;
29
import org.distorted.library.main.DistortedTexture;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshSquare;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34
import org.distorted.main.R;
35

    
36
import java.util.Random;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

    
40
public class TwistyIvy extends TwistyObject
41
{
42
  public static final float IVY_D = 0.003f;
43
  private static final int  IVY_N = 8;
44

    
45
  private static final int FACES_PER_CUBIT =6;
46

    
47
  // the four rotation axis of a RubikIvy. Must be normalized.
48
  static final Static3D[] ROT_AXIS = new Static3D[]
49
         {
50
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
51
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
52
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
53
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
54
         };
55

    
56
  private static final int[] BASIC_ANGLE = new int[] { 3,3,3,3 };
57

    
58
  private static final int[] FACE_COLORS = new int[]
59
         {
60
           COLOR_YELLOW, COLOR_WHITE,
61
           COLOR_BLUE  , COLOR_GREEN,
62
           COLOR_RED   , COLOR_ORANGE
63
         };
64

    
65
  // All legal rotation quats of a RubikIvy
66
  private static final Static4D[] QUATS = new Static4D[]
67
         {
68
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
69
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
70
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
71
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
72

    
73
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
74
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
75
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
76
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
77
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
78
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
79
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
80
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
81
         };
82

    
83
  private static final int[][] mFaceMap =
84
         {
85
           {  4, 0, 2, 12,12,12 },
86
           {  5, 1, 2, 12,12,12 },
87
           {  4, 1, 3, 12,12,12 },
88
           {  5, 0, 3, 12,12,12 },
89

    
90
           {  6, 12,12,12,12,12 },
91
           {  7, 12,12,12,12,12 },
92
           {  8, 12,12,12,12,12 },
93
           {  9, 12,12,12,12,12 },
94
           { 10, 12,12,12,12,12 },
95
           { 11, 12,12,12,12,12 },
96
         };
97

    
98
  private static final ObjectSticker[] mStickers;
99

    
100
  private static final float[][] STICKERS = new float[][]
101
          {
102
             { 0.29258922f, -0.5f, 0.29258922f, 0.29258922f, -0.5f, 0.29258922f },
103
             { -0.5f, 0.5f, 0.5f, -0.5f }
104
          };
105
  private static final int NUM_STICKERS = STICKERS.length;
106

    
107
  static
108
    {
109
    mStickers = new ObjectSticker[NUM_STICKERS];
110

    
111
    float D = (float)(Math.PI/4);
112
    final float[][] angles = { { 0,0,D },{ D,D } };
113
    final float[][] radii  = { { 0,0.04f,0 },{ 0.06f,0.06f } };
114
    final float[] strokes = { 0.03f, 0.08f };
115

    
116
    for(int s=0; s<NUM_STICKERS; s++)
117
      {
118
      mStickers[s] = new ObjectSticker(STICKERS[s], angles[s],radii[s],strokes[s]);
119
      }
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  TwistyIvy(int size, Static4D quat, DistortedTexture texture,
125
            MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
126
    {
127
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.IVY, res, scrWidth);
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

    
132
  float getScreenRatio()
133
    {
134
    return 1.0f;
135
    }
136

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

    
139
  Static4D[] getQuats()
140
    {
141
    return QUATS;
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

    
146
  int getNumFaces()
147
    {
148
    return FACE_COLORS.length;
149
    }
150

    
151
///////////////////////////////////////////////////////////////////////////////////////////////////
152

    
153
  boolean shouldResetTextureMaps()
154
    {
155
    return false;
156
    }
157

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

    
160
  int getNumStickerTypes(int numLayers)
161
    {
162
    return NUM_STICKERS;
163
    }
164

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

    
167
  float[][] getCuts(int numLayers)
168
    {
169
    float[] cut = new float[] {0.0f};
170
    return new float[][] { cut,cut,cut,cut };
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

    
175
  int getNumCubitFaces()
176
    {
177
    return FACES_PER_CUBIT;
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
  float[][] getCubitPositions(int numLayers)
183
    {
184
    final float DIST_CORNER = (numLayers-1)*0.50f;
185
    final float DIST_CENTER = (numLayers-1)*0.50f;
186

    
187
    final float[][] CENTERS = new float[10][];
188

    
189
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
190
    CENTERS[1] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
191
    CENTERS[2] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
192
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
193
    CENTERS[4] = new float[] { DIST_CENTER,           0,           0 };
194
    CENTERS[5] = new float[] {-DIST_CENTER,           0,           0 };
195
    CENTERS[6] = new float[] {           0, DIST_CENTER,           0 };
196
    CENTERS[7] = new float[] {           0,-DIST_CENTER,           0 };
197
    CENTERS[8] = new float[] {           0,           0, DIST_CENTER };
198
    CENTERS[9] = new float[] {           0,           0,-DIST_CENTER };
199

    
200
    return CENTERS;
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  ObjectShape getObjectShape(int cubit, int numLayers)
206
    {
207
    int variant = getCubitVariant(cubit,numLayers);
208

    
209
    if( variant==0 )
210
      {
211
      final float angle = (float)Math.PI/(2*IVY_N);
212
      final float CORR  = 1.0f - 2*IVY_D;
213

    
214
      float[][] centers= new float[][] { {-0.5f,-0.5f,-0.5f} };
215
      float[][] corners= new float[][] { {0.03f,0.10f}, {0.02f,0.10f} };
216
      int[] cornerIndices= new int[3*(IVY_N+1)+4];
217
      int[] centerIndices= new int[3*(IVY_N+1)+4];
218
      double[][] vertices= new double[3*(IVY_N+1)+4][3];
219
      int[][] vertIndices= new int[6][IVY_N+4];
220
      int[] bandIndices  = new int[] { 0,0,0,1,1,1 };
221

    
222
      float[][] bands =
223
        {
224
          {+0.015f,20,0.2f,0.5f,7,1,2},
225
          {-0.100f,20,0.2f,0.0f,2,1,2}
226
        };
227

    
228
      for(int i=0; i<3*(IVY_N+1); i++)
229
        {
230
        cornerIndices[i+4] = -1;
231
        centerIndices[i+4] = -1;
232
        }
233

    
234
      cornerIndices[0] = 1;
235
      cornerIndices[1] = 0;
236
      cornerIndices[2] = 0;
237
      cornerIndices[3] = 0;
238

    
239
      centerIndices[0] = 0;
240
      centerIndices[1] = 0;
241
      centerIndices[2] = 0;
242
      centerIndices[3] = 0;
243

    
244
      vertices[0][0] = 0.0;
245
      vertices[0][1] = 0.0;
246
      vertices[0][2] = 0.0;
247
      vertices[1][0] =-1.0;
248
      vertices[1][1] = 0.0;
249
      vertices[1][2] = 0.0;
250
      vertices[2][0] = 0.0;
251
      vertices[2][1] =-1.0;
252
      vertices[2][2] = 0.0;
253
      vertices[3][0] = 0.0;
254
      vertices[3][1] = 0.0;
255
      vertices[3][2] =-1.0;
256

    
257
      vertIndices[0][0] = 2;
258
      vertIndices[0][1] = 0;
259
      vertIndices[0][2] = 1;
260
      vertIndices[3][0] = 2;
261
      vertIndices[3][1] = 0;
262
      vertIndices[3][2] = 1;
263

    
264
      vertIndices[1][0] = 3;
265
      vertIndices[1][1] = 0;
266
      vertIndices[1][2] = 2;
267
      vertIndices[4][0] = 3;
268
      vertIndices[4][1] = 0;
269
      vertIndices[4][2] = 2;
270

    
271
      vertIndices[2][0] = 1;
272
      vertIndices[2][1] = 0;
273
      vertIndices[2][2] = 3;
274
      vertIndices[5][0] = 1;
275
      vertIndices[5][1] = 0;
276
      vertIndices[5][2] = 3;
277

    
278
      int N1 = 4;
279
      int N2 = N1 + IVY_N + 1;
280
      int N3 = N2 + IVY_N + 1;
281

    
282
      for(int i=0; i<=IVY_N; i++)
283
        {
284
        double cos1 = Math.cos((IVY_N-i)*angle);
285
        double sin1 = Math.sin((IVY_N-i)*angle);
286
        double cos2 = Math.cos((      i)*angle);
287
        double sin2 = Math.sin((      i)*angle);
288

    
289
        vertices[N1+i][0] = CORR*(cos1-0.5) - 0.5;
290
        vertices[N1+i][1] = CORR*(sin1-0.5) - 0.5;
291
        vertices[N1+i][2] = 0.0;
292

    
293
        vertices[N2+i][0] = 0.0;
294
        vertices[N2+i][1] = CORR*(sin2-0.5) - 0.5;
295
        vertices[N2+i][2] = CORR*(cos2-0.5) - 0.5;
296

    
297
        vertices[N3+i][0] = CORR*(cos2-0.5) - 0.5;
298
        vertices[N3+i][1] = 0.0;
299
        vertices[N3+i][2] = CORR*(sin2-0.5) - 0.5;
300

    
301
        vertIndices[0][i+3] = N1 + i;
302
        vertIndices[1][i+3] = N2 + i;
303
        vertIndices[2][i+3] = N3 + i;
304
        vertIndices[3][i+3] = N1 + i;
305
        vertIndices[4][i+3] = N2 + i;
306
        vertIndices[5][i+3] = N3 + i;
307
        }
308

    
309
      float C = 0.5f - SQ2/4;
310
      float[] convexCenter = new float[] {-C,-C,-C};
311
      return new ObjectShape(vertices,vertIndices,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), convexCenter);
312
      }
313
    else
314
      {
315
      final float angle = (float)Math.PI/(2*IVY_N);
316
      final float CORR  = 1.0f - 2*IVY_D;
317
      double[][] vertices = new double[2*IVY_N][3];
318
      int[][] vert_indices = new int[2][2*IVY_N];
319

    
320
      int[] bandIndices= new int[] { 0,1 };
321
      int[] indexes    = new int[2*IVY_N];
322
      float[][] corners= new float[][] { {0.03f,0.10f} };
323
      float[][] centers= new float[][] { {-0.0f,-0.0f,-0.5f} };
324

    
325
      for(int i=0; i<IVY_N; i++)
326
        {
327
        double sin = Math.sin(i*angle);
328
        double cos = Math.cos(i*angle);
329

    
330
        vertices[i      ][0] = CORR*(0.5f-cos);
331
        vertices[i      ][1] = CORR*(0.5f-sin);
332
        vertices[i      ][2] = 0;
333
        vertices[i+IVY_N][0] = CORR*(cos-0.5f);
334
        vertices[i+IVY_N][1] = CORR*(sin-0.5f);
335
        vertices[i+IVY_N][2] = 0;
336
        }
337

    
338
      for(int i=0; i<2*IVY_N; i++)
339
        {
340
        vert_indices[0][i] = i;
341
        vert_indices[1][i] = 2*IVY_N-1-i;
342
        }
343

    
344
      for(int i=0; i<2*IVY_N; i++)
345
        {
346
        indexes[i] = -1;
347
        }
348
      indexes[0] = indexes[IVY_N] = 0;
349

    
350
      float[][] bands =
351
        {
352
          {+0.03f,35,0.5f,0.5f,5,0,0},
353
          {+0.10f,45,0.5f,0.0f,2,0,0}
354
        };
355

    
356
      return new ObjectShape(vertices,vert_indices,bands,bandIndices,corners,indexes,centers,indexes,getNumCubitFaces(), null);
357
      }
358
    }
359

    
360
///////////////////////////////////////////////////////////////////////////////////////////////////
361

    
362
  private Static4D getQuat(int cubit, int numLayers)
363
    {
364
    switch(cubit)
365
      {
366
      case  0: return QUATS[0];
367
      case  1: return QUATS[2];
368
      case  2: return QUATS[3];
369
      case  3: return QUATS[1];
370

    
371
      case  4: return QUATS[8];
372
      case  5: return QUATS[11];
373
      case  6: return QUATS[10];
374
      case  7: return QUATS[9];
375
      case  8: return QUATS[0];
376
      case  9: return QUATS[2];
377
      }
378

    
379
    return QUATS[0];
380
    }
381

    
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383

    
384
  private int getNumCubitVariants(int numLayers)
385
    {
386
    return 2;
387
    }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

    
391
  int getCubitVariant(int cubit, int numLayers)
392
    {
393
    return cubit<4 ? 0:1;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  MeshBase createCubitMesh(int cubit, int numLayers)
399
    {
400
    int variant = getCubitVariant(cubit,numLayers);
401

    
402
    if( mMeshes==null )
403
      {
404
      FactoryCubit factory = FactoryCubit.getInstance();
405
      factory.clear();
406
      mMeshes = new MeshBase[getNumCubitVariants(numLayers)];
407
      }
408

    
409
    if( mMeshes[variant]==null )
410
      {
411
      ObjectShape shape = getObjectShape(cubit,numLayers);
412
      FactoryCubit factory = FactoryCubit.getInstance();
413
      factory.createNewFaceTransform(shape);
414
      mMeshes[variant] = factory.createRoundedSolid(shape);
415
      }
416

    
417
    MeshBase mesh = mMeshes[variant].copy(true);
418
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit,numLayers), new Static3D(0,0,0) );
419
    mesh.apply(quat,0xffffffff,0);
420

    
421
    return mesh;
422
    }
423

    
424
///////////////////////////////////////////////////////////////////////////////////////////////////
425

    
426
  int getFaceColor(int cubit, int cubitface, int numLayers)
427
    {
428
    return mFaceMap[cubit][cubitface];
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  int getColor(int face)
434
    {
435
    return FACE_COLORS[face];
436
    }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
  ObjectSticker retSticker(int face)
441
    {
442
    return mStickers[face/NUM_FACES];
443
    }
444

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

    
447
  float returnMultiplier()
448
    {
449
    return 2.0f;
450
    }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453
// PUBLIC API
454

    
455
  public Static3D[] getRotationAxis()
456
    {
457
    return ROT_AXIS;
458
    }
459

    
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461

    
462
  public int[] getBasicAngle()
463
    {
464
    return BASIC_ANGLE;
465
    }
466

    
467
///////////////////////////////////////////////////////////////////////////////////////////////////
468

    
469
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
470
    {
471
    if( curr==0 )
472
      {
473
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
474
      }
475
    else
476
      {
477
      int newVector = rnd.nextInt(NUM_AXIS -1);
478
      scramble[curr][0] = (newVector>=scramble[curr-1][0] ? newVector+1 : newVector);
479
      }
480

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

    
483
    switch( rnd.nextInt(2) )
484
      {
485
      case 0: scramble[curr][2] = -1; break;
486
      case 1: scramble[curr][2] =  1; break;
487
      }
488
    }
489

    
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491
// The Ivy is solved if and only if:
492
//
493
// 1) all 4 of its corner cubits are rotated with the same quat
494
// 2) all its face cubits are rotated with the same quat like the corner ones,
495
//    and optionally they also might be upside down.
496
//
497
// i.e.
498
// cubits [4] and [5] - might be extra QUAT[1]
499
// cubits [6] and [7] - might be extra QUAT[2]
500
// cubits [8] and [9] - might be extra QUAT[3]
501

    
502
  public boolean isSolved()
503
    {
504
    int q1,q = CUBITS[0].mQuatIndex;
505

    
506
    if( CUBITS[1].mQuatIndex == q &&
507
        CUBITS[2].mQuatIndex == q &&
508
        CUBITS[3].mQuatIndex == q  )
509
      {
510
      q1 = mulQuat(q,1);
511
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
512
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
513

    
514
      q1 = mulQuat(q,2);
515
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
516
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
517

    
518
      q1 = mulQuat(q,3);
519
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
520
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
521

    
522
      return true;
523
      }
524

    
525
    return false;
526
    }
527

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

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

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

    
537
  public int getInventor(int numLayers)
538
    {
539
    return R.string.ivy2_inventor;
540
    }
541

    
542
///////////////////////////////////////////////////////////////////////////////////////////////////
543

    
544
  public int getComplexity(int numLayers)
545
    {
546
    return 1;
547
    }
548
}
(28-28/41)