Project

General

Profile

« Previous | Next » 

Revision 09d5cf2b

Added by Leszek Koltunski 2 months ago

beginnings of support for barrel-shaped objects.

View differences:

src/main/java/org/distorted/objectlib/main/TwistyObject.java
2123 2123
                                   break;
2124 2124
        case TC_BALL             : mTouchControl = new TouchControlBall(this);
2125 2125
                                   break;
2126
        case TC_BARREL           : mTouchControl = new TouchControlBarrel(this);
2127
                                   break;
2126 2128
        case TC_CHANGING_MIRROR  : mTouchControl = new TouchControlMirror(this);
2127 2129
                                   break;
2128 2130
        case TC_CHANGING_SQUARE  : mTouchControl = new TouchControlSquare(this);
src/main/java/org/distorted/objectlib/metadata/ListObjects.java
129 129
  CU_424 ( new MetadataCU_424() ),
130 130
  CU_432 ( new MetadataCU_432() ),
131 131
  PENR_2 ( new MetadataPENR_2() ),
132

  
132 133
  PENR_3 ( new MetadataPENR_3() ),
133 134
  PENR_4 ( new MetadataPENR_4() ),
135
  CHES_2 ( new MetadataCHES_2() ),
134 136

  
135 137
  //OF_334 ( new MetadataOF_334() ),
136 138
  //TEST   ( new MetadataTEST()   ),
src/main/java/org/distorted/objectlib/metadata/Metadata.java
24 24
  public static final int CATEGORY_SHAPE_ICO    = 4;
25 25
  public static final int CATEGORY_SHAPE_BAL    = 5;
26 26
  public static final int CATEGORY_SHAPE_OTH    = 6;
27
  public static final int CATEGORY_SHAPE_BAR    = 7;
27 28

  
28 29
  public static final int CATEGORY_AXIS_FACE    = (0<<3);  // next 2 bits
29 30
  public static final int CATEGORY_AXIS_EDGE    = (1<<3);
src/main/java/org/distorted/objectlib/metadata/MetadataCHES_2.java
1

  
2
///////////////////////////////////////////////////////////////////////////////////////////////////
3
// Copyright 2024 Leszek Koltunski                                                               //
4
//                                                                                               //
5
// This file is part of Magic Cube.                                                              //
6
//                                                                                               //
7
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
8
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
9
///////////////////////////////////////////////////////////////////////////////////////////////////
10

  
11
package org.distorted.objectlib.metadata;
12

  
13
import org.distorted.objectlib.R;
14
import org.distorted.objectlib.objects.TwistyCheese;
15

  
16
///////////////////////////////////////////////////////////////////////////////////////////////////
17

  
18
public class MetadataCHES_2 extends Metadata
19
  {
20
  public static int INDEX = 92;
21
  public MetadataCHES_2()         { super( TwistyCheese.class, new int[] {2,2,2,2}, 0, null, INDEX ); }
22
  public int numScrambles()       { return 15; }
23
  public int icon()               { return R.drawable.dske_3; }
24
  public boolean getActive()      { return false; }
25
  public int price()              { return 50; }
26
  public int extrasJson()         { return 0; }
27
  public int objectJson()         { return 0; }
28
  public int mesh()               { return 0; }
29
  public String getAuthor()       { return "Anthony Greenhill"; }
30
  public int getYearOfInvention() { return 2002; }
31
  public float getDifficulty()    { return 1.1f; }
32
  public String getObjectName()   { return "Rubik Cheese"; }
33
  public int getCategory()        { return CATEGORY_SHAPE_BAR | CATEGORY_AXIS_OTHE; }
34
  }
src/main/java/org/distorted/objectlib/objects/TwistyCheese.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.objects;
11

  
12
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_BARREL;
13
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_NOT_SPLIT;
14

  
15
import org.distorted.library.type.Static3D;
16
import org.distorted.library.type.Static4D;
17
import org.distorted.objectlib.helpers.FactoryCubit;
18
import org.distorted.objectlib.helpers.ObjectFaceShape;
19
import org.distorted.objectlib.helpers.ObjectShape;
20
import org.distorted.objectlib.helpers.ObjectVertexEffects;
21
import org.distorted.objectlib.main.InitAssets;
22
import org.distorted.objectlib.metadata.ListObjects;
23
import org.distorted.objectlib.metadata.Metadata;
24
import org.distorted.objectlib.shape.ShapeBarrel;
25
import org.distorted.objectlib.touchcontrol.TouchControlBarrel;
26

  
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

  
29
public class TwistyCheese extends ShapeBarrel
30
{
31
  static final Static3D[] ROT_AXIS = new Static3D[]
32
         {
33
           new Static3D(    0, 1,     0),
34
           new Static3D(    1, 0,     0),
35
           new Static3D( 0.5f, 0, SQ3/2),
36
           new Static3D(-0.5f, 0, SQ3/2),
37
         };
38

  
39
  private int[][] mEdges;
40
  private int[][] mBasicAngle;
41
  private int[] mQuatIndex;
42
  private float[][] mCuts;
43
  private float[][] mCenters;
44

  
45
///////////////////////////////////////////////////////////////////////////////////////////////////
46

  
47
  public TwistyCheese(int iconMode, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
48
    {
49
    super(iconMode, meta.getNumLayers()[0], quat, move, scale, meta, asset);
50
    }
51

  
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53
// here we cannot automatically detect the outer monochromatic walls -> use the old way.
54

  
55
  @Override
56
  public int getSolvedFunctionIndex()
57
    {
58
    return 0;
59
    }
60

  
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62

  
63
  @Override
64
  public float[][] returnRotationFactor()
65
    {
66
    float C1 = 1.0f;
67
    float C2 = 1.7f;
68
    float[] f1 = new float[] { C1,C1 };
69
    float[] f2 = new float[] { C2,C2 };
70
    return new float[][] { f1,f2,f2,f2 };
71
    }
72

  
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74
// make the equator a bit thicker
75
/*
76
  @Override
77
  public void adjustStickerCoords()
78
    {
79
    final float X1 = -0.38861537f;
80
    final float Y1 = -0.4252297f;
81
    final float X2 =  0.5f;
82
    final float Y2 = -0.2860808f;
83
    final float X3 =  0.18867691f;
84
    final float Y3 =  1.05f*0.39392126f;
85
    final float X4 = -0.30006152f;
86
    final float Y4 =  1.05f*0.3173893f;
87

  
88
    final float Y = 0.02f;
89

  
90
    mStickerCoords = new float[][][][]
91
          {
92
            { { {X1+Y*(X4-X1), Y1+Y*(Y4-Y1)}, {X2+Y*(X3-X2), Y2+Y*(Y3-Y2)}, {X3, Y3}, {X4, Y4} } },
93
            { { {-0.17166577f, 0.92f*-0.28301144f}, {0.24996112f, 0.92f*-0.21698855f}, {-0.07829534f, 0.5f} } }
94
          };
95
    }
96
*/
97

  
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99
/*
100
  @Override
101
  public int[][] getSolvedQuats()
102
    {
103
    // special SolvedQuats for the case where there are no corner of edge cubits.
104
    // first row {0} - means there are no corners or edges.
105
    // each next defines all cubits of a singe face
106
    // (numCubits, firstCubit, cubit1,..,cubitN-1, quat0,..., quatM)
107

  
108
    return new int[][] {
109
                         {0},
110
                         {4, 0, 1,16,17, 13},
111
                         {4, 2, 3,18,19, 12},
112
                         {4, 4, 5,20,21, 15},
113
                         {4, 6, 7,22,23, 14},
114
                         {4, 8, 9,24,25, 13},
115
                         {4,10,11,26,27, 12},
116
                         {4,12,13,28,29, 15},
117
                         {4,14,15,30,31, 14},
118
                       };
119
    }
120
*/
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122
// TODO
123

  
124
  public int[][] getScrambleEdges()
125
    {
126
    if( mEdges==null )
127
      {
128
      mEdges = new int[][]
129
        {
130
          { 0,1, 1,1, 2,1, 3,1, 4,1, 5,1, 6,1, 7,1, 8,1, 9,1,
131
           10,1,11,1,12,1,13,1,14,1,15,1,16,1,17,1,18,1,19,1,
132
           20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1
133
          },
134

  
135
          {28,2,29,2,30,2,31,2,32,2,33,2,34,2,35,2 },
136

  
137
          { 0,1, 1,1, 2,1, 3,1, 4,1, 5,1, 6,1, 7,1, 8,1, 9,1,
138
           10,1,11,1,12,1,13,1,14,1,15,1,16,1,17,1,18,1,19,1,
139
           20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1,
140
           28,0,29,0,30,0,31,0,32,0,33,0,34,0,35,0
141
          }
142
        };
143
      }
144

  
145
    return mEdges;
146
    }
147

  
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

  
150
  public float[][] getCuts(int[] numLayers)
151
    {
152
    if( mCuts==null )
153
      {
154
      float[] c = { 0.0f };
155
      mCuts = new float[][] { c,c,c,c };
156
      }
157

  
158
    return mCuts;
159
    }
160

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

  
163
  public boolean[][] getLayerRotatable(int[] numLayers)
164
    {
165
    boolean[] l = {true,true};
166
    return new boolean[][] { l,l,l,l };
167
    }
168

  
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170

  
171
  public int getTouchControlType()
172
    {
173
    return TC_BARREL;
174
    }
175

  
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177
// not used
178

  
179
  public int getTouchControlSplit()
180
    {
181
    return TYPE_NOT_SPLIT;
182
    }
183

  
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// Each 'face' is a vertical strip of 1/8 of longitude (PI/4).
186
// The first one spans longitude from -PI/8 to +PI/8, where Greenwich is long=0.
187
// Next successively to the east.
188

  
189
  public int[][][] getEnabled()
190
    {
191
    return new int[][][] { {{0,1}},{{0,4}},{{0,3}},{{0,2}},{{0,1}},{{0,4}},{{0,3}},{{0,2}} };
192
    }
193

  
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

  
196
  public float[] getDist3D(int[] numLayers)
197
    {
198
    final float D = 0.5f*(float)Math.sqrt((2*SQ2+5)/17);
199
    return new float[] { D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D };
200
    }
201

  
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203

  
204
  public Static3D[] getFaceAxis()
205
    {
206
    return TouchControlBarrel.FACE_AXIS;
207
    }
208

  
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

  
211
  public float[][] getCubitPositions(int[] numLayers)
212
    {
213
    if( mCenters==null )
214
      {
215
      final float X1 = 3*SQ2/8;
216
      final float Y1 = 0.5f;
217
      final float Z1 = 0.750f+3*SQ2/8;
218
      final float X2 = X1/3;
219
      final float Y2 = 1.5f;
220
      final float Z2 = Z1/3;
221

  
222
      mCenters = new float[][]
223
         {
224
             { X1, Y1, Z1 },
225
             { X1,-Y1, Z1 },
226
             { Z1, Y1, X1 },
227
             { Z1,-Y1, X1 },
228
             { Z1, Y1,-X1 },
229
             { Z1,-Y1,-X1 },
230
             { X1, Y1,-Z1 },
231
             { X1,-Y1,-Z1 },
232
             {-X1, Y1,-Z1 },
233
             {-X1,-Y1,-Z1 },
234
             {-Z1, Y1,-X1 },
235
             {-Z1,-Y1,-X1 },
236
             {-Z1, Y1, X1 },
237
             {-Z1,-Y1, X1 },
238
             {-X1, Y1, Z1 },
239
             {-X1,-Y1, Z1 },
240

  
241
             { X2, Y2, Z2 },
242
             { X2,-Y2, Z2 },
243
             { Z2, Y2, X2 },
244
             { Z2,-Y2, X2 },
245
             { Z2, Y2,-X2 },
246
             { Z2,-Y2,-X2 },
247
             { X2, Y2,-Z2 },
248
             { X2,-Y2,-Z2 },
249
             {-X2, Y2,-Z2 },
250
             {-X2,-Y2,-Z2 },
251
             {-Z2, Y2,-X2 },
252
             {-Z2,-Y2,-X2 },
253
             {-Z2, Y2, X2 },
254
             {-Z2,-Y2, X2 },
255
             {-X2, Y2, Z2 },
256
             {-X2,-Y2, Z2 },
257
         };
258
      }
259

  
260
    return mCenters;
261
    }
262

  
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264

  
265
  public Static4D getCubitQuats(int cubit, int[] numLayers)
266
    {
267
    if( mQuatIndex==null ) mQuatIndex = new int[] { 0,13,7,9,6,12,5,8,4,15,3,11,2,14,1,10,
268
                                                    0,13,7,9,6,12,5,8,4,15,3,11,2,14,1,10 };
269
    return mObjectQuats[mQuatIndex[cubit]];
270
    }
271

  
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273

  
274
  private float[][] getVertices(int variant)
275
    {
276
    final float D = 0.1f;
277

  
278
    if( variant==0 )
279
      {
280
      return new float[][]
281
          {
282
              { -3*SQ2/8             ,        -0.5f  ,  1.250f-3*SQ2/8 },
283
              {  5*SQ2/8             ,        -0.5f  , -0.750f+5*SQ2/8 },
284
              { -3*SQ2/8             ,         0.5f-D,  0.250f-3*SQ2/8 +D },
285
              {    SQ2/8 +D*(4*SQ2/8),         0.5f-D, -0.750f+  SQ2/8 +D*(4*SQ2/8) },
286
              { -3*SQ2/8             ,        -0.5f  , -0.750f-3*SQ2/8 },
287
              { -3*SQ2/8             , 0.01f*(0.5f-D), -0.750f-3*SQ2/8 },
288
          };
289
      }
290
    else
291
      {
292
      return new float[][]
293
          {
294
              { -SQ2/8             , -0.5f -D,  -SQ2/8+0.75f +D },
295
              {3*SQ2/8 +D*(4*SQ2/8), -0.5f -D, 3*SQ2/8-0.25f +D*(4*SQ2/8) },
296
              { -SQ2/8             , -0.5f -D,  -SQ2/8-0.25f },
297
              { -SQ2/8             , +0.5f   ,  -SQ2/8-0.25f }
298
          };
299
      }
300
    }
301

  
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

  
304
  public ObjectShape getObjectShape(int variant)
305
    {
306
    if( variant==0 )
307
      {
308
      int[][] indices =
309
          {
310
              {0,1,3,2},
311
              {4,0,2,5},
312
              {1,4,5,3},
313
              {2,3,5},
314
              {4,1,0}
315
          };
316

  
317
      return new ObjectShape(getVertices(variant), indices);
318
      }
319
    else
320
      {
321
      int[][] indices =
322
          {
323
              {0,1,3},
324
              {2,0,3},
325
              {1,2,3},
326
              {2,1,0}
327
          };
328

  
329
      return new ObjectShape(getVertices(variant), indices);
330
      }
331
    }
332

  
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334

  
335
  public ObjectFaceShape getObjectFaceShape(int variant)
336
    {
337
    if( variant==0 )
338
      {
339
      float height = isInIconMode() ? 0.001f : 0.015f;
340
      float[][] bands = { {height,35,0.25f,0.5f,10,0,0},{0.001f,35,0.25f,0.5f,4,0,0} };
341
      int[] indices   = { 0,1,1,1,1 };
342
      return new ObjectFaceShape(bands,indices,null);
343
      }
344
    else
345
      {
346
      float height = isInIconMode() ? 0.001f : 0.020f;
347
      float[][] bands = { {height,35,0.20f,0.6f,9,0,0}, {0.001f,35,0.20f,0.6f,4,0,0} };
348
      int[] indices   = { 0,1,1,1 };
349
      return new ObjectFaceShape(bands,indices,null);
350
      }
351
    }
352

  
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354

  
355
  public ObjectVertexEffects getVertexEffects(int variant)
356
    {
357
    if( variant==0 )
358
      {
359
      float[][] corners   = { {0.04f,0.10f} };
360
      int[] cornerIndices = { -1,-1,-1,-1,-1,-1 };
361
      float[][] centers   = { { -3*SQ2/16, -0.5f,-0.375f-3*SQ2/16 } };
362
      int[] centerIndices = { 0,0,0,0,-1,-1 };
363
      return FactoryCubit.generateVertexEffect(getVertices(variant),corners,cornerIndices,centers,centerIndices);
364
      }
365
    else
366
      {
367
      float[][] corners   = { {0.02f,0.10f} };
368
      int[] cornerIndices = { -1,-1,-1,-1 };
369
      float[][] centers   = {  { -SQ2/8, -0.5f, -SQ2/8-0.25f } };
370
      int[] centerIndices = { 0,0,-1,0 };
371
      return FactoryCubit.generateVertexEffect(getVertices(variant),corners,cornerIndices,centers,centerIndices);
372
      }
373
    }
374

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

  
377
  public int getNumCubitVariants(int[] numLayers)
378
    {
379
    return 2;
380
    }
381

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

  
384
  public int getCubitVariant(int cubit, int[] numLayers)
385
    {
386
    return cubit<16 ? 0:1;
387
    }
388

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

  
391
  public float getStickerRadius()
392
    {
393
    return 0.10f;
394
    }
395

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

  
398
  public float getStickerStroke()
399
    {
400
    return isInIconMode() ? 0.13f : 0.10f;
401
    }
402

  
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

  
405
  public float[][][] getStickerAngles()
406
    {
407
    float A = (float)(Math.PI/12);
408
    return new float[][][] { {{ 0,0,-A,0 }} , {{A,0,0}}  };
409
    }
410

  
411
///////////////////////////////////////////////////////////////////////////////////////////////////
412
// PUBLIC API
413

  
414
  public Static3D[] getRotationAxis()
415
    {
416
    return ROT_AXIS;
417
    }
418

  
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

  
421
  public int[][] getBasicAngles()
422
    {
423
    if( mBasicAngle==null )
424
      {
425
      int[] AV = {8,8,8,8};
426
      int[] AH = {2,2};
427
      mBasicAngle = new int[][] { AV,AH,AH,AH,AH };
428
      }
429

  
430
    return mBasicAngle;
431
    }
432

  
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

  
435
  public String getShortName()
436
    {
437
    return ListObjects.BALL_4.name();
438
    }
439

  
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

  
442
  public String[][] getTutorials()
443
    {
444
    return new String[][]{
445
                          {"gb","n41Rng0g65c","How to solve Masterball","javahamburg"},
446
                          {"es","zmdgV15BQi0","Tutorial para la Masterball","Robert Cubes"},
447
                          {"de","EjGf-VytMcA","Masterball Tutorial Deutsch","javahamburg"},
448
                         };
449
    }
450
}
src/main/java/org/distorted/objectlib/shape/ShapeBarrel.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2024 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.shape;
11

  
12
import org.distorted.library.type.Static3D;
13
import org.distorted.library.type.Static4D;
14
import org.distorted.objectlib.main.InitAssets;
15
import org.distorted.objectlib.main.TwistyObject;
16
import org.distorted.objectlib.metadata.Metadata;
17

  
18
import static org.distorted.objectlib.shape.ShapeColors.*;
19

  
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21

  
22
public abstract class ShapeBarrel extends TwistyObject
23
{
24
  public static final Static4D DEFAULT_ROT = new Static4D(-0.09848663f, 0.6306283f, 0.67572856f, 0.36878252f);
25

  
26
  public static final int[] FACE_COLORS = new int[]
27
         {
28
                 COLOR_VIOLET, COLOR_GREY,
29
                 COLOR_BLUE, COLOR_RED,
30
                 COLOR_ORANGE, COLOR_LGREEN,
31
                 COLOR_WHITE, COLOR_YELLOW
32
         };
33

  
34
  public static final int NUM_FACES = 8;
35
  public static final int FOV = 40;
36
  public static final float RATIO = 0.75f;
37

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

  
40
  public ShapeBarrel(int iconMode, float realSize, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
41
    {
42
    super(iconMode, realSize, quat, move, scale, meta, asset);
43
    }
44

  
45
///////////////////////////////////////////////////////////////////////////////////////////////////
46

  
47
  public final int getNumPuzzleFaces()
48
    {
49
    return NUM_FACES;
50
    }
51

  
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53

  
54
  public int[] getColorTable()
55
    {
56
    return FACE_COLORS;
57
    }
58

  
59
///////////////////////////////////////////////////////////////////////////////////////////////////
60

  
61
  public int getFOV()
62
    {
63
    return FOV;
64
    }
65

  
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

  
68
  public float getScreenRatio()
69
    {
70
    return RATIO;
71
    }
72
}
src/main/java/org/distorted/objectlib/touchcontrol/TouchControl.java
37 37
  public static final int TC_ICOSAHEDRON       =  20;
38 38
  public static final int TC_CUBOID            =   0;
39 39
  public static final int TC_BALL              =   1;
40
  public static final int TC_BARREL            =   2;
40 41
  public static final int TC_CHANGING_MIRROR   = 100;
41 42
  public static final int TC_CHANGING_SQUARE   = 101;
42 43
  public static final int TC_CHANGING_SHAPEMOD = 102;
src/main/java/org/distorted/objectlib/touchcontrol/TouchControlBarrel.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2024 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.touchcontrol;
11

  
12
import static org.distorted.objectlib.main.TwistyObject.SQ2;
13

  
14
import org.distorted.library.helpers.QuatHelper;
15
import org.distorted.library.type.Static3D;
16
import org.distorted.library.type.Static4D;
17
import org.distorted.objectlib.main.TwistyObject;
18

  
19
///////////////////////////////////////////////////////////////////////////////////////////////////
20
// Barrel-shaped objects: map the 2D swipes of user's fingers to 3D rotations
21

  
22
public class TouchControlBarrel extends TouchControl
23
{
24
  private static final float MIN_LEN = 0.35f;
25
  private static final float[] mTmp = new float[4];
26

  
27
  private final Static3D[] mRotAxis;
28
  private final float[] mPoint, mCamera, mTouch;
29
  private final int[] mEnabledRotAxis;
30
  private final int[][][] mEnabled;
31
  private final float[] mMove2D;
32
  private final float[][] mCastedRotAxis;
33
  private float[][] mTouchBorders;
34

  
35
  private float mLongitude, mLatitude;
36
  private float mX, mY, mZ;
37

  
38
  private static final float X = (float)Math.sqrt( (2-SQ2)/(6+SQ2) );
39
  private static final float Y = (float)Math.sqrt( (2+SQ2)/(6+SQ2) );
40

  
41
  public static final Static3D[] FACE_AXIS = new Static3D[]
42
        {
43
          new Static3D( X, Y, Y),
44
          new Static3D( X,-Y, Y),
45
          new Static3D( Y, Y, X),
46
          new Static3D( Y,-Y, X),
47
          new Static3D( Y, Y,-X),
48
          new Static3D( Y,-Y,-X),
49
          new Static3D( X, Y,-Y),
50
          new Static3D( X,-Y,-Y),
51
          new Static3D(-X, Y,-Y),
52
          new Static3D(-X,-Y,-Y),
53
          new Static3D(-Y, Y,-X),
54
          new Static3D(-Y,-Y,-X),
55
          new Static3D(-Y, Y, X),
56
          new Static3D(-Y,-Y, X),
57
          new Static3D(-X, Y, Y),
58
          new Static3D(-X,-Y, Y),
59
        };
60

  
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62

  
63
  public TouchControlBarrel(TwistyObject object)
64
    {
65
    super(object);
66

  
67
    int[] numLayers       = object.getNumLayers();
68
    float[][] cuts        = object.getCuts(numLayers);
69
    boolean[][] rotatable = object.getLayerRotatable(numLayers);
70
    float size            = object.getSize();
71
    mRotAxis = object.getRotationAxis();
72
    mEnabled = object.getEnabled();
73

  
74
    mMove2D  = new float[2];
75

  
76
    mPoint = new float[3];
77
    mCamera= new float[3];
78
    mTouch = new float[3];
79

  
80
    int numRotAxis = mRotAxis.length;
81
    mEnabledRotAxis = new int[numRotAxis+1];
82
    mCastedRotAxis = new float[numRotAxis][2];
83

  
84
    mGhostAxisEnabled = -1;
85

  
86
    computeBorders(cuts,rotatable,size);
87
    }
88

  
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

  
91
  private float[] computeBorder(float[] cuts, boolean[] rotatable, float size)
92
    {
93
    if( cuts==null ) return null;
94

  
95
    int len = cuts.length;
96
    float[] border = new float[len];
97

  
98
    for(int i=0; i<len; i++)
99
      {
100
      if( !rotatable[i] )
101
        {
102
        border[i] = i>0 ? border[i-1] : -Float.MAX_VALUE;
103
        }
104
      else
105
        {
106
        if( rotatable[i+1] ) border[i] = cuts[i]/size;
107
        else
108
          {
109
          int found = -1;
110

  
111
          for(int j=i+2; j<=len; j++)
112
            {
113
            if( rotatable[j] )
114
              {
115
              found=j;
116
              break;
117
              }
118
            }
119

  
120
          border[i] = found>0 ? (cuts[i]+cuts[found-1])/(2*size) : Float.MAX_VALUE;
121
          }
122
        }
123
      }
124

  
125
    return border;
126
    }
127

  
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
// size, not numLayers (see Master Skewb where size!=numLayers) - also cuboids.
130

  
131
  void computeBorders(float[][] cuts, boolean[][] rotatable, float size)
132
    {
133
    int numCuts = cuts.length;
134
    mTouchBorders = new float[numCuts][];
135

  
136
    for(int axis=0; axis<numCuts; axis++)
137
      {
138
      mTouchBorders[axis] = computeBorder(cuts[axis],rotatable[axis],size);
139
      }
140
    }
141

  
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

  
144
  private int computeRowFromOffset(int axisIndex, float offset)
145
    {
146
    float[] borders = mTouchBorders[axisIndex];
147
    if( borders==null ) return 0;
148
    int len = borders.length;
149

  
150
    for(int i=0; i<len; i++)
151
      {
152
      if( offset<borders[i] ) return i;
153
      }
154

  
155
    return len;
156
    }
157

  
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159
// Longitude spans from 0 (at Guinea Bay) increasing to the east all the way to 2PI
160
// Latitude - from -PI/2 (South Pole) to +PI/2 (North Pole)
161

  
162
  private void computeLongitudeAndLatitude(float A, float B, float C)
163
    {
164
    float sqrt = (float)Math.sqrt(B*B - 4*A*C);
165
    float alpha= (-B+sqrt)/(2*A); // this is the closer point
166

  
167
    float cx = mCamera[0];
168
    float cy = mCamera[1];
169
    float cz = mCamera[2];
170

  
171
    float vx = mCamera[0]-mPoint[0];
172
    float vy = mCamera[1]-mPoint[1];
173
    float vz = mCamera[2]-mPoint[2];
174

  
175
    mX = cx + alpha*vx;
176
    mY = cy + alpha*vy;
177
    mZ = cz + alpha*vz;
178

  
179
    mLongitude = mZ==0 ? 0 : (float)Math.atan(mX/mZ);
180
    mLatitude  = (float)Math.asin(2*mY);
181

  
182
    if( mZ<0 ) mLongitude += Math.PI;
183
    else if( mX<0 ) mLongitude += 2*Math.PI;
184
    }
185

  
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187
// this is Masterball-specific. See TwistyMasterball.getEnabled()
188

  
189
  private int returnTouchedFace()
190
    {
191
    float t = (float)(mLongitude + Math.PI/8);
192
    if( t>2*Math.PI ) t-=(2*Math.PI);
193
    int ret = (int)(t/(Math.PI/4));
194
    return ret<8 ? ret : 7;
195
    }
196

  
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198
// this is Masterball-specific. No parts in any faces.
199

  
200
  private int returnTouchedPart()
201
    {
202
    return 0;
203
    }
204

  
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

  
207
  private float computeOffset(int rotIndex)
208
    {
209
    Static3D axis = mRotAxis[rotIndex];
210
    return mX*axis.get0() + mY*axis.get1() + mZ*axis.get2();
211
    }
212

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

  
215
  private void computeEnabledAxis()
216
    {
217
    if( mGhostAxisEnabled<0 )
218
      {
219
      int face = returnTouchedFace();
220
      int part = returnTouchedPart();
221
      int num = mEnabled[face][0].length;
222
      mEnabledRotAxis[0] = num;
223
      System.arraycopy(mEnabled[face][part], 0, mEnabledRotAxis, 1, num);
224
      }
225
    else
226
      {
227
      mEnabledRotAxis[0] = 1;  // if in 'ghost' mode, only one axis is enabled.
228
      mEnabledRotAxis[1] = mGhostAxisEnabled;
229
      }
230
    }
231

  
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

  
234
  public int getTouchedCubitFace()
235
    {
236
    return 0;
237
    }
238

  
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

  
241
  public float[] getTouchedPuzzleCenter()
242
    {
243
    return null;
244
    }
245

  
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

  
248
  public int getTouchedCubit()
249
    {
250
    return 0;
251
    }
252

  
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

  
255
  public boolean objectTouched(Static4D rotatedTouchPoint, Static4D rotatedCamera)
256
    {
257
    mPoint[0]  = rotatedTouchPoint.get0()/mObjectRatio;
258
    mPoint[1]  = rotatedTouchPoint.get1()/mObjectRatio;
259
    mPoint[2]  = rotatedTouchPoint.get2()/mObjectRatio;
260

  
261
    mCamera[0] = rotatedCamera.get0()/mObjectRatio;
262
    mCamera[1] = rotatedCamera.get1()/mObjectRatio;
263
    mCamera[2] = rotatedCamera.get2()/mObjectRatio;
264

  
265
    float vx = mCamera[0]-mPoint[0];
266
    float vy = mCamera[1]-mPoint[1];
267
    float vz = mCamera[2]-mPoint[2];
268

  
269
    float R = 0.5f;
270
    float A = vx*vx + vy*vy + vz*vz;
271
    float B = 2*(vx*mCamera[0] + vy*mCamera[1] + vz*mCamera[2]);
272
    float C = (mCamera[0]*mCamera[0] + mCamera[1]*mCamera[1] + mCamera[2]*mCamera[2]) - R*R;
273

  
274
    if( B*B >= 4*A*C )
275
      {
276
      computeLongitudeAndLatitude(A,B,C);
277
      return true;
278
      }
279

  
280
    return false;
281
    }
282

  
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

  
285
  public void newRotation(int[] output, Static4D rotatedTouchPoint, Static4D quat)
286
    {
287
    computeEnabledAxis();
288

  
289
    mTouch[0]  = rotatedTouchPoint.get0()/mObjectRatio;
290
    mTouch[1]  = rotatedTouchPoint.get1()/mObjectRatio;
291
    mTouch[2]  = rotatedTouchPoint.get2()/mObjectRatio;
292

  
293
    float x = mTouch[0]-mPoint[0];
294
    float y = mTouch[1]-mPoint[1];
295
    float z = mTouch[2]-mPoint[2];
296

  
297
    QuatHelper.rotateVectorByQuat(mTmp,x,y,z,0,quat);
298
    mMove2D[0] = mTmp[0];
299
    mMove2D[1] = mTmp[1];
300

  
301
    for(int i=1; i<=mEnabledRotAxis[0]; i++)
302
      {
303
      int enabled = mEnabledRotAxis[i];
304
      Static3D axis = mRotAxis[enabled];
305
      float[] vector = mCastedRotAxis[enabled];
306
      float bx = axis.get0();
307
      float by = axis.get1();
308
      float bz = axis.get2();
309

  
310
      QuatHelper.rotateVectorByQuat(mTmp,bx,by,bz,0,quat);
311
      float len = (float)Math.sqrt(mTmp[0]*mTmp[0] + mTmp[1]*mTmp[1]);
312

  
313
      if( len<MIN_LEN )
314
        {
315
        vector[0] = 1000f;  // switch off the axis because when casted
316
        vector[1] = 1000f;  // onto the screen it is too short
317
        }
318
      else
319
        {
320
        vector[0] = mTmp[0]/len;
321
        vector[1] = mTmp[1]/len;
322
        }
323
      }
324

  
325
    int rotIndex = computeRotationIndex( mCastedRotAxis, mMove2D, mEnabledRotAxis);
326
    float offset = computeOffset(rotIndex);
327
    int row      = computeRowFromOffset(rotIndex,offset);
328

  
329
    output[0] = rotIndex;
330
    output[1] = row;
331
    }
332

  
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334
// simply cast the appropriate rotational axis of the object to the screen surface.
335

  
336
  public void getCastedRotAxis(float[] output, Static4D quat, int axisIndex)
337
    {
338
    Static3D a = mRotAxis[axisIndex];
339
    Static4D result = QuatHelper.rotateVectorByQuat(a.get0(),a.get1(),a.get2(),0,quat);
340

  
341
    float cx = result.get0();
342
    float cy = result.get1();
343
    float len= (float)Math.sqrt(cx*cx+cy*cy);
344

  
345
    if( len!=0 )
346
      {
347
      output[0] = cx/len;
348
      output[1] = cy/len;
349
      }
350
    else
351
      {
352
      output[0] = 1;
353
      output[1] = 0;
354
      }
355
    }
356

  
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358

  
359
  public boolean axisAndFaceAgree(int axisIndex)
360
    {
361
    return false;
362
    }
363
}

Also available in: Unified diff