1
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2
|
// Copyright 2023 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_CHANGING_SHAPEMOD;
|
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.FactoryShape;
|
19
|
import org.distorted.objectlib.helpers.ObjectFaceShape;
|
20
|
import org.distorted.objectlib.helpers.ObjectShape;
|
21
|
import org.distorted.objectlib.helpers.ObjectVertexEffects;
|
22
|
import org.distorted.objectlib.main.InitAssets;
|
23
|
import org.distorted.objectlib.metadata.ListObjects;
|
24
|
import org.distorted.objectlib.metadata.Metadata;
|
25
|
import org.distorted.objectlib.scrambling.ScrambleEdgeGenerator;
|
26
|
import org.distorted.objectlib.shape.ShapeColors;
|
27
|
import org.distorted.objectlib.shape.ShapeHexahedron;
|
28
|
import org.distorted.objectlib.touchcontrol.TouchControlHexahedron;
|
29
|
|
30
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
31
|
|
32
|
public class TwistyMirrorSkewb extends ShapeHexahedron
|
33
|
{
|
34
|
public static final Static3D[] ROT_AXIS =
|
35
|
{
|
36
|
new Static3D( SQ3/3, SQ3/3, SQ3/3),
|
37
|
new Static3D( SQ3/3, SQ3/3,-SQ3/3),
|
38
|
new Static3D( SQ3/3,-SQ3/3, SQ3/3),
|
39
|
new Static3D( SQ3/3,-SQ3/3,-SQ3/3)
|
40
|
};
|
41
|
|
42
|
private static final int[] FACE_COLORS = new int[] { ShapeColors.COLOR_WHITE};
|
43
|
private static final float[] MIRROR_VEC = { 0.10f, 0.15f, 0.20f };
|
44
|
|
45
|
private int[][] mEdges;
|
46
|
private int[][] mBasicAngle;
|
47
|
private float[][] mCuts;
|
48
|
private float[][] mPositions;
|
49
|
private ObjectShape[] mShapes;
|
50
|
private float[][] mCutPlanes;
|
51
|
private float[] mDist3D, mDist;
|
52
|
private float[][] mPotentialVertices;
|
53
|
|
54
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
55
|
|
56
|
public TwistyMirrorSkewb(int iconMode, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
|
57
|
{
|
58
|
super(iconMode, 2*meta.getNumLayers()[0]-2, quat, move, scale, meta, asset);
|
59
|
}
|
60
|
|
61
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
62
|
// here we cannot automatically detect the outer monochromatic walls -> use the old way.
|
63
|
|
64
|
@Override
|
65
|
public int getSolvedFunctionIndex()
|
66
|
{
|
67
|
return 0;
|
68
|
}
|
69
|
|
70
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
71
|
|
72
|
@Override
|
73
|
public int[][] getSolvedQuats()
|
74
|
{
|
75
|
return getOldSolvedQuats();
|
76
|
}
|
77
|
|
78
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
79
|
|
80
|
@Override
|
81
|
public int getInternalColor()
|
82
|
{
|
83
|
return 0xff333333;
|
84
|
}
|
85
|
|
86
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
87
|
|
88
|
@Override
|
89
|
public int[] getColorTable()
|
90
|
{
|
91
|
return FACE_COLORS;
|
92
|
}
|
93
|
|
94
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
95
|
|
96
|
@Override
|
97
|
public float[][] returnRotationFactor()
|
98
|
{
|
99
|
int numL = getNumLayers()[0];
|
100
|
float[] f = new float[numL];
|
101
|
for(int i=0; i<numL; i++) f[i] = 1.7f;
|
102
|
return new float[][] { f,f,f,f };
|
103
|
}
|
104
|
|
105
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
106
|
|
107
|
public int[][] getScrambleEdges()
|
108
|
{
|
109
|
if( mEdges==null ) mEdges = ScrambleEdgeGenerator.getScrambleEdgesSingle(mBasicAngle);
|
110
|
return mEdges;
|
111
|
}
|
112
|
|
113
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
114
|
|
115
|
public float[][] getCuts(int[] numLayers)
|
116
|
{
|
117
|
if( mCuts==null )
|
118
|
{
|
119
|
float[] c = {0};
|
120
|
mCuts = new float[][] {c,c,c,c};
|
121
|
}
|
122
|
|
123
|
return mCuts;
|
124
|
}
|
125
|
|
126
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
127
|
|
128
|
public boolean[][] getLayerRotatable(int[] numLayers)
|
129
|
{
|
130
|
boolean[] tmp = {true,true};
|
131
|
return new boolean[][] { tmp,tmp,tmp,tmp };
|
132
|
}
|
133
|
|
134
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
135
|
|
136
|
public int getTouchControlType()
|
137
|
{
|
138
|
return TC_CHANGING_SHAPEMOD;
|
139
|
}
|
140
|
|
141
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
142
|
|
143
|
public int getTouchControlSplit()
|
144
|
{
|
145
|
return TYPE_NOT_SPLIT;
|
146
|
}
|
147
|
|
148
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
149
|
|
150
|
public int[][][] getEnabled()
|
151
|
{
|
152
|
return null;
|
153
|
}
|
154
|
|
155
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
156
|
// 'full' dists (not divided by numLayers)
|
157
|
|
158
|
private float[] getDist()
|
159
|
{
|
160
|
if( mDist==null )
|
161
|
{
|
162
|
float DX = MIRROR_VEC[0];
|
163
|
float DY = MIRROR_VEC[1];
|
164
|
float DZ = MIRROR_VEC[2];
|
165
|
mDist = new float[] { 1+DX, 1-DX, 1+DY, 1-DY, 1+DZ, 1-DZ };
|
166
|
}
|
167
|
|
168
|
return mDist;
|
169
|
}
|
170
|
|
171
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
172
|
// 'regular' dists for the touchControl (have to be divided by numLayers)
|
173
|
|
174
|
public float[] getDist3D(int[] numLayers)
|
175
|
{
|
176
|
if( mDist3D==null )
|
177
|
{
|
178
|
float[] d = getDist();
|
179
|
mDist3D = new float[] { d[0]/2, d[1]/2, d[2]/2, d[3]/2, d[4]/2, d[5]/2 };
|
180
|
}
|
181
|
|
182
|
return mDist3D;
|
183
|
}
|
184
|
|
185
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
186
|
|
187
|
public Static3D[] getFaceAxis()
|
188
|
{
|
189
|
return TouchControlHexahedron.FACE_AXIS;
|
190
|
}
|
191
|
|
192
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
193
|
|
194
|
private float[][] getPositions()
|
195
|
{
|
196
|
if( mPositions==null )
|
197
|
{
|
198
|
final float COR = 1.0f;
|
199
|
final float CEN = 1.0f;
|
200
|
final float X = MIRROR_VEC[0];
|
201
|
final float Y = MIRROR_VEC[1];
|
202
|
final float Z = MIRROR_VEC[2];
|
203
|
|
204
|
mPositions = new float[8+6][];
|
205
|
|
206
|
mPositions[0] = new float[]{ COR+X, COR+Y, COR+Z };
|
207
|
mPositions[1] = new float[]{ COR+X, COR+Y, -COR+Z };
|
208
|
mPositions[2] = new float[]{ COR+X, -COR+Y, COR+Z };
|
209
|
mPositions[3] = new float[]{ COR+X, -COR+Y, -COR+Z };
|
210
|
mPositions[4] = new float[]{-COR+X, COR+Y, COR+Z };
|
211
|
mPositions[5] = new float[]{-COR+X, COR+Y, -COR+Z };
|
212
|
mPositions[6] = new float[]{-COR+X, -COR+Y, COR+Z };
|
213
|
mPositions[7] = new float[]{-COR+X, -COR+Y, -COR+Z };
|
214
|
|
215
|
mPositions[ 8] = new float[]{ X, Y, CEN+Z };
|
216
|
mPositions[ 9] = new float[]{ X, Y,-CEN+Z };
|
217
|
mPositions[10] = new float[]{ X, CEN+Y, Z };
|
218
|
mPositions[11] = new float[]{ X,-CEN+Y, Z };
|
219
|
mPositions[12] = new float[]{ CEN+X, Y, Z };
|
220
|
mPositions[13] = new float[]{-CEN+X, Y, Z };
|
221
|
}
|
222
|
|
223
|
return mPositions;
|
224
|
}
|
225
|
|
226
|
|
227
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
228
|
|
229
|
public float[][] getCubitPositions(int[] numLayers)
|
230
|
{
|
231
|
return getPositions();
|
232
|
}
|
233
|
|
234
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
235
|
|
236
|
public Static4D getCubitQuats(int cubit, int[] numLayers)
|
237
|
{
|
238
|
return mObjectQuats[0];
|
239
|
}
|
240
|
|
241
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
242
|
|
243
|
private void createCutPlanes()
|
244
|
{
|
245
|
int numPlanes = 6+4;
|
246
|
mCutPlanes = new float[numPlanes][];
|
247
|
Static3D[] faceAxis = getFaceAxis();
|
248
|
float[] dist = getDist();
|
249
|
|
250
|
for(int p=0; p<6; p++)
|
251
|
{
|
252
|
Static3D ax = faceAxis[p];
|
253
|
mCutPlanes[p] = new float[] { ax.get0(), ax.get1(), ax.get2(), dist[p] };
|
254
|
}
|
255
|
|
256
|
for(int p=6; p<10; p++)
|
257
|
{
|
258
|
Static3D ax = ROT_AXIS[p-6];
|
259
|
mCutPlanes[p] = new float[] { ax.get0(), ax.get1(), ax.get2(), 0 };
|
260
|
}
|
261
|
}
|
262
|
|
263
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
264
|
|
265
|
private float[] internalPoint(int variant)
|
266
|
{
|
267
|
float[][] pos = getPositions();
|
268
|
float[] position = pos[variant];
|
269
|
float[][] center = computeVertexEffectCenter(variant);
|
270
|
float[] cent = center[0];
|
271
|
|
272
|
float[] ret = new float[3];
|
273
|
|
274
|
float A = 0.1f;
|
275
|
|
276
|
ret[0] = position[0] + A*cent[0];
|
277
|
ret[1] = position[1] + A*cent[1];
|
278
|
ret[2] = position[2] + A*cent[2];
|
279
|
|
280
|
return ret;
|
281
|
}
|
282
|
|
283
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
284
|
|
285
|
public ObjectShape getObjectShape(int variant)
|
286
|
{
|
287
|
if( mShapes==null )
|
288
|
{
|
289
|
int[] numLayers = getNumLayers();
|
290
|
int numV = getNumCubitVariants(numLayers);
|
291
|
mShapes = new ObjectShape[numV];
|
292
|
createCutPlanes();
|
293
|
mPotentialVertices = FactoryShape.computePotentialVertices(mCutPlanes);
|
294
|
}
|
295
|
|
296
|
if( mShapes[variant]==null )
|
297
|
{
|
298
|
float[][] pos = getPositions();
|
299
|
float[] point = internalPoint(variant);
|
300
|
mShapes[variant] = FactoryShape.createShape(mCutPlanes,mPotentialVertices,pos[variant],point);
|
301
|
}
|
302
|
|
303
|
return mShapes[variant];
|
304
|
}
|
305
|
|
306
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
307
|
|
308
|
public ObjectFaceShape getObjectFaceShape(int variant)
|
309
|
{
|
310
|
ObjectShape shape = getObjectShape(variant);
|
311
|
int[][] ind = shape.getVertIndices();
|
312
|
float[][] vert = shape.getVertices();
|
313
|
float[][] pos = getPositions();
|
314
|
int[] indices = FactoryShape.produceBandIndices(vert, pos[variant], ind, getFaceAxis(), getDist() );
|
315
|
|
316
|
if( variant<8 )
|
317
|
{
|
318
|
int N = 5;
|
319
|
int E = 2;
|
320
|
float height = isInIconMode() ? 0.001f : 0.04f;
|
321
|
float[][] bands = { {height,35,0.16f,0.7f,N,E,E}, {0.001f, 35,1.00f,0.0f,N,E,E} };
|
322
|
return new ObjectFaceShape(bands,indices,null);
|
323
|
}
|
324
|
else
|
325
|
{
|
326
|
int N = 5;
|
327
|
int E = 1;
|
328
|
float height = isInIconMode() ? 0.001f : 0.05f;
|
329
|
float[][] bands = { {height,35,SQ2/8,0.9f,N,E,E}, {0.001f,35,1,0.0f,3,0,0} };
|
330
|
return new ObjectFaceShape(bands,indices,null);
|
331
|
}
|
332
|
}
|
333
|
|
334
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
335
|
|
336
|
private float[][] computeVertexEffectCenter(int variant)
|
337
|
{
|
338
|
final float A = 1.0f;
|
339
|
|
340
|
switch(variant)
|
341
|
{
|
342
|
case 0: return new float[][] { {-A,-A,-A} };
|
343
|
case 1: return new float[][] { {-A,-A, A} };
|
344
|
case 2: return new float[][] { {-A, A,-A} };
|
345
|
case 3: return new float[][] { {-A, A, A} };
|
346
|
case 4: return new float[][] { { A,-A,-A} };
|
347
|
case 5: return new float[][] { { A,-A, A} };
|
348
|
case 6: return new float[][] { { A, A,-A} };
|
349
|
case 7: return new float[][] { { A, A, A} };
|
350
|
case 8: return new float[][] { { 0, 0,-A} };
|
351
|
case 9: return new float[][] { { 0, 0, A} };
|
352
|
case 10: return new float[][] { { 0,-A, 0} };
|
353
|
case 11: return new float[][] { { 0, A, 0} };
|
354
|
case 12: return new float[][] { {-A, 0, 0} };
|
355
|
case 13: return new float[][] { { A, 0, 0} };
|
356
|
}
|
357
|
|
358
|
return null;
|
359
|
}
|
360
|
|
361
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
362
|
|
363
|
public ObjectVertexEffects getVertexEffects(int variant)
|
364
|
{
|
365
|
ObjectShape shape = getObjectShape(variant);
|
366
|
float[][] vertices = shape.getVertices();
|
367
|
float[][] centers = computeVertexEffectCenter(variant);
|
368
|
float[][] pos = getPositions();
|
369
|
int[] indices = FactoryShape.computeVertexEffectsIndices(vertices, pos[variant], getFaceAxis(), getDist() );
|
370
|
float[][] corners = variant<8 ? new float[][]{{0.03f, 0.20f}} : new float[][]{{0.03f, 0.15f}};
|
371
|
|
372
|
return FactoryCubit.generateVertexEffect(vertices,corners,indices,centers,indices);
|
373
|
}
|
374
|
|
375
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
376
|
|
377
|
public int getNumCubitVariants(int[] numLayers)
|
378
|
{
|
379
|
return 14;
|
380
|
}
|
381
|
|
382
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
383
|
|
384
|
public int getCubitVariant(int cubit, int[] numLayers)
|
385
|
{
|
386
|
return cubit;
|
387
|
}
|
388
|
|
389
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
390
|
|
391
|
public float getStickerRadius()
|
392
|
{
|
393
|
return 0.08f;
|
394
|
}
|
395
|
|
396
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
397
|
|
398
|
public float getStickerStroke()
|
399
|
{
|
400
|
return isInIconMode() ? 0.16f : 0.08f;
|
401
|
}
|
402
|
|
403
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
404
|
|
405
|
public float[][][] getStickerAngles()
|
406
|
{
|
407
|
return null;
|
408
|
}
|
409
|
|
410
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
411
|
// PUBLIC API
|
412
|
|
413
|
public Static3D[] getRotationAxis()
|
414
|
{
|
415
|
return ROT_AXIS;
|
416
|
}
|
417
|
|
418
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
419
|
|
420
|
public int[][] getBasicAngles()
|
421
|
{
|
422
|
if( mBasicAngle ==null )
|
423
|
{
|
424
|
int num = getNumLayers()[0];
|
425
|
int[] tmp = new int[num];
|
426
|
for(int i=0; i<num; i++) tmp[i] = 3;
|
427
|
mBasicAngle = new int[][] { tmp,tmp,tmp,tmp };
|
428
|
}
|
429
|
|
430
|
return mBasicAngle;
|
431
|
}
|
432
|
|
433
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
434
|
|
435
|
public String getShortName()
|
436
|
{
|
437
|
return ListObjects.MSKE_2.name();
|
438
|
}
|
439
|
|
440
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
441
|
|
442
|
public String[][] getTutorials()
|
443
|
{
|
444
|
return null;
|
445
|
}
|
446
|
}
|