Revision 09d5cf2b
Added by Leszek Koltunski 2 months ago
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
beginnings of support for barrel-shaped objects.