Project

General

Profile

Download (67.9 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObject.java @ 6777e712

1 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 4c87f159 Leszek Koltunski
// 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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10
package org.distorted.objectlib.main;
11
12 3a1efb32 Leszek Koltunski
import java.io.DataInputStream;
13
import java.io.IOException;
14
import java.io.InputStream;
15
import java.util.Random;
16
17 29b82486 Leszek Koltunski
import android.graphics.Bitmap;
18
import android.graphics.Canvas;
19
import android.graphics.Paint;
20
21
import org.distorted.library.effect.Effect;
22
import org.distorted.library.effect.MatrixEffectMove;
23
import org.distorted.library.effect.MatrixEffectQuaternion;
24
import org.distorted.library.effect.MatrixEffectScale;
25
import org.distorted.library.effect.VertexEffectQuaternion;
26 a0b0795b Leszek Koltunski
import org.distorted.library.effect.VertexEffectSink;
27 29b82486 Leszek Koltunski
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedLibrary;
29
import org.distorted.library.main.DistortedNode;
30
import org.distorted.library.main.DistortedTexture;
31 aacf5e27 Leszek Koltunski
import org.distorted.library.helpers.QuatHelper;
32 29b82486 Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
33
import org.distorted.library.mesh.MeshFile;
34
import org.distorted.library.mesh.MeshJoined;
35
import org.distorted.library.message.EffectListener;
36
import org.distorted.library.type.Static1D;
37
import org.distorted.library.type.Static3D;
38
import org.distorted.library.type.Static4D;
39 a57e6870 Leszek Koltunski
40 198c5bf0 Leszek Koltunski
import org.distorted.objectlib.helpers.FactoryCubit;
41
import org.distorted.objectlib.helpers.FactorySticker;
42 3ee1d662 Leszek Koltunski
import org.distorted.objectlib.helpers.ObjectFaceShape;
43 d887aa16 Leszek Koltunski
import org.distorted.objectlib.helpers.ObjectLibInterface;
44 198c5bf0 Leszek Koltunski
import org.distorted.objectlib.helpers.ObjectShape;
45 ae9d9227 leszek
import org.distorted.objectlib.metadata.Metadata;
46 97a75106 leszek
import org.distorted.objectlib.signature.ObjectSignature;
47 198c5bf0 Leszek Koltunski
import org.distorted.objectlib.helpers.ObjectSticker;
48 3a0a23bf Leszek Koltunski
import org.distorted.objectlib.helpers.ObjectStickerOverride;
49 84a17011 Leszek Koltunski
import org.distorted.objectlib.helpers.ObjectVertexEffects;
50 3103c3c8 Leszek Koltunski
import org.distorted.objectlib.helpers.OperatingSystemInterface;
51 802fe251 Leszek Koltunski
import org.distorted.objectlib.helpers.QuatGroupGenerator;
52 10b7e306 Leszek Koltunski
import org.distorted.objectlib.scrambling.ObjectScrambler;
53 82eb152a Leszek Koltunski
import org.distorted.objectlib.json.JsonReader;
54 731280f7 Leszek Koltunski
import org.distorted.objectlib.scrambling.ScrambleEdgeGenerator;
55 c0266cb1 Leszek Koltunski
import org.distorted.objectlib.tablebases.ImplementedTablebasesList;
56
import org.distorted.objectlib.tablebases.TablebasesAbstract;
57 3a1efb32 Leszek Koltunski
import org.distorted.objectlib.touchcontrol.*;
58 29b82486 Leszek Koltunski
59 3a1efb32 Leszek Koltunski
import static org.distorted.objectlib.touchcontrol.TouchControl.*;
60 59c20632 Leszek Koltunski
61 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
62
63 7ba38dd4 Leszek Koltunski
public abstract class TwistyObject
64 29b82486 Leszek Koltunski
  {
65 3bf19410 Leszek Koltunski
  public static final int MODE_ICON = 0;
66
  public static final int MODE_NORM = 1;
67
68 7ec32155 Leszek Koltunski
  public static final int COLOR_STROKE   = 0xff000000;
69 c60d98c4 Leszek Koltunski
  public static final int COLOR_INTERNAL = 0xff000000;
70 29b82486 Leszek Koltunski
71 cce2b48c leszek
  private static final int DEFAULT_TEXTURE_HEIGHT = 256;
72 d1025da5 leszek
  private static final int DEFAULT_TEXTURE_ROWS   = 8;
73 29b82486 Leszek Koltunski
74
  public static final float SQ2 = (float)Math.sqrt(2);
75
  public static final float SQ3 = (float)Math.sqrt(3);
76
  public static final float SQ5 = (float)Math.sqrt(5);
77
  public static final float SQ6 = (float)Math.sqrt(6);
78
79
  private static final float MAX_SIZE_CHANGE = 1.35f;
80
  private static final float MIN_SIZE_CHANGE = 0.75f;
81
82
  private static final Static3D CENTER = new Static3D(0,0,0);
83
84 ebe8c08e leszek
  protected float[][][][] mStickerCoords;
85 802fe251 Leszek Koltunski
  protected Static4D[] mObjectQuats;
86 82eb152a Leszek Koltunski
87 a05b6e06 Leszek Koltunski
  private int[][] mStickerVariants;
88
  private float[] mStickerScales;
89 5618c5a9 Leszek Koltunski
  private TwistyObjectCubit[] mCubits;
90
  private TwistyObjectSolved mSolved;
91 a05b6e06 Leszek Koltunski
  private MeshBase[] mMeshes;
92 3a0a23bf Leszek Koltunski
  private int mNumCubits, mNumQuats, mNumFaceColors, mNumTextures, mNumOverrides;
93 7af68038 Leszek Koltunski
  private int mNumCubitFaces, mNumStickerTypes;
94 82eb152a Leszek Koltunski
  private Static3D[] mAxis;
95
  private float[][] mCuts;
96 63bfcdd1 leszek
  private int[][] mMinimalCubiesInRow;
97 82eb152a Leszek Koltunski
  private int[] mNumCuts;
98
  private float[][] mOrigPos;
99 5931ae4d Leszek Koltunski
  private Static4D[] mOrigQuat;
100 00a28d71 Leszek Koltunski
  private Static4D[] mMixupModeQuats;
101
  private boolean mIsInMixupMode;
102 82eb152a Leszek Koltunski
  private Static4D mQuat;
103 3ce95490 Leszek Koltunski
  private int[] mNumLayers;
104
  private float mSize;
105 82eb152a Leszek Koltunski
  private DistortedEffects mEffects;
106
  private Static3D mObjectScale;
107
  private int[] mQuatDebug;
108
  private DistortedTexture mTexture;
109
  private float mInitScreenRatio;
110
  private boolean mIsBandaged;
111 29b82486 Leszek Koltunski
  private float mObjectScreenRatio;
112 f3eab97f leszek
  private int mNumTexRows, mNumTexCols, mTexHeight;
113 29b82486 Leszek Koltunski
  private MeshBase mMesh;
114 10b7e306 Leszek Koltunski
  private ObjectScrambler mScrambler;
115 c9c71c3f Leszek Koltunski
  private TouchControl mTouchControl;
116 7ba38dd4 Leszek Koltunski
  private DistortedNode mNode;
117 d887aa16 Leszek Koltunski
  private ObjectLibInterface mInterface;
118 d5c71d02 Leszek Koltunski
  private Bitmap mBitmap;
119 d53fb890 Leszek Koltunski
  private ObjectSticker[] mStickers;
120 b968d359 Leszek Koltunski
  private ObjectShape[] mShapes;
121
  private int mNumCubitVariants;
122 9b1fe915 Leszek Koltunski
  private int[][] mCubitFaceColors;
123 59a971c1 Leszek Koltunski
  private int[][] mVariantFaceIsOuter;
124 beee90ab Leszek Koltunski
  private int[][] mBasicAngles;
125 3bf19410 Leszek Koltunski
  private int mIconMode;
126 ae9d9227 leszek
  private Metadata mMetadata;
127 fbd18fc7 Leszek Koltunski
  private float[][] mRowOffsets;
128
  private boolean[] mBelongs;
129
  private float[] mTmp;
130 5a20f7a1 Leszek Koltunski
  private int mNumPuzzleFaces;
131 3a0a23bf Leszek Koltunski
  private ObjectStickerOverride[] mStickerOverrides;
132 3ce95490 Leszek Koltunski
  private boolean mError;
133
  private String mErrorString;
134 d85de775 Leszek Koltunski
  private int mMaxNumLayers;
135
  private int mNumAxis;
136 3788d0cd Leszek Koltunski
  private boolean mThereAreDeciders;
137 e3169794 leszek
  private TwistyLayerRotations mRotation;
138 962b8ff6 leszek
  private int[] mColorTable;
139 5ce579d2 leszek
  private int[] mOriginalColorTable;
140 6f5eb9b3 leszek
  private float mTextureBorderMultiplier, mTextureCornerMultiplier;
141 22d72239 leszek
  private boolean mCurrentColorSchemeSubmittable;
142 29b82486 Leszek Koltunski
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
145 1fda81c4 leszek
  TwistyObject(int iconMode, Static4D quat, Static3D move, float scale, InitAssets asset)
146 82eb152a Leszek Koltunski
    {
147 3ce95490 Leszek Koltunski
    try
148
      {
149 c0266cb1 Leszek Koltunski
      InputStream jsonStream = asset!=null ? asset.getJsonStream(): null;
150 958a6e81 Leszek Koltunski
      JsonReader reader = new JsonReader();
151 3ce95490 Leszek Koltunski
      reader.parseJsonFile(jsonStream);
152
      setReader(reader);
153
      mNumLayers = reader.getNumLayers();
154
      mSize      = reader.getSize();
155 ae9d9227 leszek
      mMetadata  = null;
156 1fda81c4 leszek
      initialize(iconMode,quat,move,scale,asset,true);
157 c0266cb1 Leszek Koltunski
      if( asset!=null ) asset.close();
158 3ce95490 Leszek Koltunski
      mError = false;
159
      mErrorString=null;
160
      }
161
    catch(Exception ex)
162
      {
163
      mError = true;
164
      mErrorString = ex.getMessage();
165
      }
166 82eb152a Leszek Koltunski
    }
167
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169
170 ae9d9227 leszek
  public TwistyObject(int iconMode, float size, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
171 29b82486 Leszek Koltunski
    {
172 ae9d9227 leszek
    mNumLayers = meta.getNumLayers();
173 82eb152a Leszek Koltunski
    mSize      = size;
174 ae9d9227 leszek
    mMetadata  = meta;
175 1fda81c4 leszek
    initialize(iconMode,quat,move,scale,asset,false);
176 c0266cb1 Leszek Koltunski
    if( asset!=null ) asset.close();
177 3ce95490 Leszek Koltunski
    mError = false;
178
    mErrorString = null;
179 82eb152a Leszek Koltunski
    }
180
181 1f329dcc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
182
183
  private void debugQuat(Static4D quat, int cubitIndex, float axisX, float axisY, float axisZ, float angle, int place)
184
    {
185
    float[] tracking = mCubits[cubitIndex].getTrackingPoint();
186
187 e61a7687 leszek
    if( tracking!=null )
188
      {
189
      String problem = (getShortName()+" "+cubitIndex+" "+quat.get0()+" "+quat.get1()+" "+quat.get2()+" "+quat.get3());
190
      problem += (" "+angle+" "+place+" "+tracking[0]+" "+tracking[1]+" "+tracking[2]);
191 e3169794 leszek
      problem += (" "+axisX+" "+axisY+" "+axisZ);
192 1f329dcc Leszek Koltunski
193 e61a7687 leszek
      mInterface.reportProblem(problem, true);
194
      }
195 1f329dcc Leszek Koltunski
    }
196
197 82eb152a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
198
199 1fda81c4 leszek
  private void initialize(int iconMode, Static4D quat, Static3D move, float scale, InitAssets asset, boolean fromJSON)
200 82eb152a Leszek Koltunski
    {
201 3bf19410 Leszek Koltunski
    mIconMode = iconMode;
202 82eb152a Leszek Koltunski
    mQuat = quat;
203 29b82486 Leszek Koltunski
    mAxis = getRotationAxis();
204
    mInitScreenRatio = getScreenRatio();
205 802fe251 Leszek Koltunski
    mBasicAngles = getBasicAngles();
206 89a00832 Leszek Koltunski
    mObjectQuats = getQuats();
207
    mNumQuats = mObjectQuats.length;
208
    mOrigPos = getCubitPositions(mNumLayers);
209 1eafa9c6 leszek
    mNumPuzzleFaces = getNumPuzzleFaces();
210 5a20f7a1 Leszek Koltunski
    mRowOffsets = new float[mNumPuzzleFaces][3];
211 fbd18fc7 Leszek Koltunski
    mTmp = new float[4];
212 d85de775 Leszek Koltunski
    mNumAxis = mAxis.length;
213 29b82486 Leszek Koltunski
    mCuts = getCuts(mNumLayers);
214 d85de775 Leszek Koltunski
    mNumCuts = new int[mNumAxis];
215
    mMaxNumLayers = -1;
216
    for(int i=0; i<mNumAxis; i++)
217 dfdb26a9 Leszek Koltunski
      {
218 d55d2c6a Leszek Koltunski
      if( mMaxNumLayers<mNumLayers[i] ) mMaxNumLayers = mNumLayers[i];
219 dfdb26a9 Leszek Koltunski
      mNumCuts[i] = (mCuts==null || mCuts[i]==null ? 0 : mCuts[i].length);
220
      }
221 29b82486 Leszek Koltunski
222 5ce579d2 leszek
    mOriginalColorTable = getColorTable();
223
    mNumFaceColors = mOriginalColorTable.length;
224
    mColorTable = new int[mNumFaceColors];
225 962b8ff6 leszek
    recreateFaceColors();
226 6f5eb9b3 leszek
    mTextureBorderMultiplier = 1.0f;
227
    mTextureCornerMultiplier = 1.0f;
228
229 63bfcdd1 leszek
    mMinimalCubiesInRow = getMinimalCubiesInRow();
230 a05b6e06 Leszek Koltunski
    mNumCubits = mOrigPos.length;
231 962b8ff6 leszek
232 fbd18fc7 Leszek Koltunski
    mBelongs = new boolean[mNumCubits];
233 a05b6e06 Leszek Koltunski
234 29b82486 Leszek Koltunski
    int scramblingType = getScrambleType();
235 9ba7f3f6 Leszek Koltunski
    int[][] edges = getScrambleEdges();
236
    int[][] algorithms = getScrambleAlgorithms();
237
238 3103c3c8 Leszek Koltunski
    OperatingSystemInterface os = asset==null ? null : asset.getOS();
239
    TablebasesAbstract tablebase = os!=null ? getTablebase(os) : null;
240 c0266cb1 Leszek Koltunski
    mScrambler = new ObjectScrambler(scramblingType,mNumAxis,mNumLayers,algorithms,edges,tablebase);
241 29b82486 Leszek Koltunski
242
    boolean bandaged=false;
243
244 a05b6e06 Leszek Koltunski
    for( int c=0; c<mNumCubits; c++)
245 29b82486 Leszek Koltunski
      {
246
      if( mOrigPos[c].length>3 )
247
        {
248
        bandaged=true;
249
        break;
250
        }
251
      }
252
    mIsBandaged = bandaged;
253 a05b6e06 Leszek Koltunski
    mQuatDebug = new int[mNumCubits];
254 29b82486 Leszek Koltunski
255 64c209f5 Leszek Koltunski
    mObjectScale = new Static3D(scale,scale,scale);
256
    setObjectRatioNow(scale,720);
257 e7daa161 Leszek Koltunski
258 00a28d71 Leszek Koltunski
    mEffects = new DistortedEffects();
259
    createQuaternionEffects();
260
261 a0ef8a1d leszek
    mRotation = new TwistyLayerRotations(this,mAxis,mNumLayers,getGhostAngle(),mEffects);
262 4a014840 leszek
263 29b82486 Leszek Koltunski
    MatrixEffectScale scaleEffect = new MatrixEffectScale(mObjectScale);
264 57ef6378 Leszek Koltunski
    MatrixEffectQuaternion quatEffect = new MatrixEffectQuaternion(mQuat, CENTER);
265 b80e6524 Leszek Koltunski
    MatrixEffectMove moveEffect = new MatrixEffectMove(move);
266 29b82486 Leszek Koltunski
267 c0266cb1 Leszek Koltunski
    InputStream meshStream = asset!=null ? asset.getMeshStream(): null;
268 1fda81c4 leszek
    boolean fromDMESH = (meshStream!=null);
269 4c9ca251 Leszek Koltunski
    getQuatsAndShapes(fromDMESH,fromJSON);
270 1fda81c4 leszek
    createMeshAndCubits(meshStream,fromDMESH);
271 e16fd960 Leszek Koltunski
    setUpTextures(fromDMESH,fromJSON);
272 5618c5a9 Leszek Koltunski
273
    int index = getSolvedFunctionIndex();
274
    mSolved = new TwistyObjectSolved(this,mOrigPos,index);
275 be95dbf5 Leszek Koltunski
    mSolved.setupSolvedQuats(getSolvedQuats());
276 1eafa9c6 leszek
    mSolved.setPuzzleFaceColor(mColorTable);
277 29b82486 Leszek Koltunski
278
    mEffects.apply(quatEffect);
279
    mEffects.apply(scaleEffect);
280 b80e6524 Leszek Koltunski
    mEffects.apply(moveEffect);
281 29b82486 Leszek Koltunski
282 7ba38dd4 Leszek Koltunski
    mNode = new DistortedNode(mTexture,mEffects,mMesh);
283 29b82486 Leszek Koltunski
    }
284
285 962b8ff6 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
286
287
  public void recreateFaceColors()
288
    {
289 5ce579d2 leszek
    for(int i=0; i<mNumFaceColors; i++) mColorTable[i] = mOriginalColorTable[i];
290 22d72239 leszek
    mCurrentColorSchemeSubmittable = true;
291 962b8ff6 leszek
    }
292
293 544c9224 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
294
// in degrees so that everything can be treated modulo 360
295
296
  public int getGhostAngle()
297
    {
298
    return 0;
299
    }
300
301 c0266cb1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
302
303 3103c3c8 Leszek Koltunski
  private TablebasesAbstract getTablebase(OperatingSystemInterface os)
304 c0266cb1 Leszek Koltunski
    {
305 1349f488 leszek
    String shortName = getShortName();
306
    return ImplementedTablebasesList.createPacked(os,shortName);
307 c0266cb1 Leszek Koltunski
    }
308
309 00a28d71 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
310
311
  private void createQuaternionEffects()
312
    {
313
    if( mNumQuats<=ObjectControl.MAX_QUATS )
314
      {
315
      mIsInMixupMode = false;
316
317
      for( int q=0; q<mNumQuats; q++)
318
        {
319
        VertexEffectQuaternion vq = new VertexEffectQuaternion(mObjectQuats[q],CENTER);
320
        vq.setMeshAssociation(0,q);
321
        mEffects.apply(vq);
322
        }
323
      }
324
    else if( mNumCubits<=ObjectControl.MAX_QUATS )
325
      {
326
      mIsInMixupMode = true;
327
      mMixupModeQuats = new Static4D[mNumCubits];
328
329
      for( int q=0; q<mNumCubits; q++)
330
        {
331
        mMixupModeQuats[q] = new Static4D(mObjectQuats[0]);
332
        VertexEffectQuaternion vq = new VertexEffectQuaternion(mMixupModeQuats[q],CENTER);
333
        vq.setMeshAssociation(0,q);
334
        mEffects.apply(vq);
335
        }
336
      }
337
    else
338
      {
339
      android.util.Log.e("D", "object has too many quaternions ("+mNumQuats+") or too many cubits ("+mNumCubits+")");
340
      }
341
    }
342
343 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
344
345
  private Static3D getPos(float[] origPos)
346
    {
347
    int len = origPos.length/3;
348
    float sumX = 0.0f;
349
    float sumY = 0.0f;
350
    float sumZ = 0.0f;
351
352
    for(int i=0; i<len; i++)
353
      {
354
      sumX += origPos[3*i  ];
355
      sumY += origPos[3*i+1];
356
      sumZ += origPos[3*i+2];
357
      }
358
359
    sumX /= len;
360
    sumY /= len;
361
    sumZ /= len;
362
363
    return new Static3D(sumX,sumY,sumZ);
364
    }
365
366 59a971c1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
367
368
  private void createOuterFaces()
369
    {
370
    for(int v=0; v<mNumCubitVariants; v++)
371
      {
372 89c2b479 Leszek Koltunski
      int numFaces = mShapes[v].getNumFaces();
373
      mVariantFaceIsOuter[v] = new int[numFaces];
374 59a971c1 Leszek Koltunski
      }
375
376 a05b6e06 Leszek Koltunski
    for( int cubit=0; cubit<mNumCubits; cubit++)
377 59a971c1 Leszek Koltunski
      {
378
      int variant = getCubitVariant(cubit,mNumLayers);
379 89c2b479 Leszek Koltunski
      int numFaces = mShapes[variant].getNumFaces();
380 59a971c1 Leszek Koltunski
381
      for(int face=0; face<numFaces; face++)
382 9ef0ad15 leszek
        if( getDefaultCubitFaceColor(cubit,face)>=0 )
383 59a971c1 Leszek Koltunski
          {
384
          mVariantFaceIsOuter[variant][face] = 1;
385
          }
386
      }
387
    }
388
389 4c9ca251 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
390
391
  private void getQuatsAndShapes(boolean fromDMESH, boolean fromJSON)
392
    {
393
    mNumCubitVariants = getNumCubitVariants(mNumLayers);
394
395
    if( !fromDMESH || !fromJSON )
396
      {
397
      FactoryCubit factory = FactoryCubit.getInstance();
398
      factory.clear();
399
400
      mShapes = new ObjectShape[mNumCubitVariants];
401 5e1b47f8 leszek
      for(int v=0; v<mNumCubitVariants; v++) mShapes[v] = getObjectShape(v);
402 4c9ca251 Leszek Koltunski
      mNumCubitFaces = ObjectShape.computeNumComponents(mShapes);
403 59a971c1 Leszek Koltunski
      mVariantFaceIsOuter = new int[mNumCubitVariants][];
404 4c9ca251 Leszek Koltunski
405 716f5517 Leszek Koltunski
      mOrigQuat = new Static4D[mNumCubits];
406
      for(int i=0; i<mNumCubits; i++) mOrigQuat[i] = getCubitQuats(i,mNumLayers);
407
408 59a971c1 Leszek Koltunski
      if( !fromJSON )
409 4c9ca251 Leszek Koltunski
        {
410 59a971c1 Leszek Koltunski
        mCubitFaceColors = ObjectShape.computeColors(mShapes,mOrigPos,mOrigQuat,this);
411
        createOuterFaces();
412 4c9ca251 Leszek Koltunski
        }
413 9b1fe915 Leszek Koltunski
414 59a971c1 Leszek Koltunski
      if( fromDMESH )
415 9b1fe915 Leszek Koltunski
        {
416 59a971c1 Leszek Koltunski
        for(int i=0; i<mNumCubitVariants; i++) factory.createNewFaceTransform(mShapes[i], mVariantFaceIsOuter[i]);
417 9b1fe915 Leszek Koltunski
        }
418 4c9ca251 Leszek Koltunski
      }
419
    }
420
421 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
422
423 1fda81c4 leszek
  private void createMeshAndCubits(InputStream stream, boolean fromDMESH)
424 29b82486 Leszek Koltunski
    {
425 5618c5a9 Leszek Koltunski
    mCubits = new TwistyObjectCubit[mNumCubits];
426 4c9ca251 Leszek Koltunski
427 e16fd960 Leszek Koltunski
    if( fromDMESH )
428 29b82486 Leszek Koltunski
      {
429 82eb152a Leszek Koltunski
      DataInputStream dos = new DataInputStream(stream);
430 29b82486 Leszek Koltunski
      mMesh = new MeshFile(dos);
431
432
      try
433
        {
434 82eb152a Leszek Koltunski
        stream.close();
435 29b82486 Leszek Koltunski
        }
436
      catch(IOException e)
437
        {
438 9cb7d66f Leszek Koltunski
        android.util.Log.e("meshFile", "Error closing InputStream: "+e);
439 29b82486 Leszek Koltunski
        }
440
      }
441
    else
442
      {
443 a05b6e06 Leszek Koltunski
      MeshBase[] cubitMesh = new MeshBase[mNumCubits];
444 5931ae4d Leszek Koltunski
445 a05b6e06 Leszek Koltunski
      for(int i=0; i<mNumCubits; i++)
446 29b82486 Leszek Koltunski
        {
447 1fda81c4 leszek
        cubitMesh[i] = createCubitMesh(i,mNumLayers,mNumCubitFaces);
448 29b82486 Leszek Koltunski
        Static3D pos = getPos(mOrigPos[i]);
449
        cubitMesh[i].apply(new MatrixEffectMove(pos),1,0);
450
        }
451
452
      mMesh = new MeshJoined(cubitMesh);
453 a0b0795b Leszek Koltunski
454
      float pillowCoeff = getPillowCoeff();
455
456
      if( pillowCoeff!=1.0f )
457
        {
458
        float radius = getCircumscribedRadius();
459
        Static1D coeff = new Static1D(pillowCoeff);
460
        Static4D region= new Static4D(0,0,0,radius);
461
        VertexEffectSink sink = new VertexEffectSink(coeff,CENTER,region);
462
        mMesh.apply(sink);
463
        }
464 29b82486 Leszek Koltunski
      }
465 00a28d71 Leszek Koltunski
466
    for(int i=0; i<mNumCubits; i++)
467
      {
468 5618c5a9 Leszek Koltunski
      mCubits[i] = new TwistyObjectCubit(this,mOrigPos[i],mNumAxis,mMaxNumLayers,i);
469 544c9224 leszek
      setCubitQuat(i,0);
470 3788d0cd Leszek Koltunski
471
      if( !mThereAreDeciders && mCubits[i].getType()==TwistyObjectCubit.TYPE_DECIDER )
472
        {
473
        mThereAreDeciders = true;
474
        }
475 00a28d71 Leszek Koltunski
      }
476 29b82486 Leszek Koltunski
    }
477
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479
480 1fda81c4 leszek
  private MeshBase createCubitMesh(int cubit, int[] numLayers, int numComponents)
481 29b82486 Leszek Koltunski
    {
482
    int variant = getCubitVariant(cubit,numLayers);
483
484 b968d359 Leszek Koltunski
    if( mMeshes==null ) mMeshes = new MeshBase[mNumCubitVariants];
485 29b82486 Leszek Koltunski
486
    if( mMeshes[variant]==null )
487
      {
488 3ee1d662 Leszek Koltunski
      ObjectFaceShape faceShape = getObjectFaceShape(variant);
489 84a17011 Leszek Koltunski
      ObjectVertexEffects effects = getVertexEffects(variant);
490 29b82486 Leszek Koltunski
      FactoryCubit factory = FactoryCubit.getInstance();
491 59a971c1 Leszek Koltunski
      factory.createNewFaceTransform(mShapes[variant],mVariantFaceIsOuter[variant]);
492 1fda81c4 leszek
      mMeshes[variant] = factory.createRoundedSolid(mShapes[variant],faceShape,effects,numComponents);
493 29b82486 Leszek Koltunski
      }
494
495
    MeshBase mesh = mMeshes[variant].copy(true);
496 5931ae4d Leszek Koltunski
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( mOrigQuat[cubit], CENTER );
497 29b82486 Leszek Koltunski
    mesh.apply(quat,0xffffffff,0);
498
499
    return mesh;
500
    }
501
502 f3eab97f leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
503
504
  private void figureOutBitmapDimensions(int numTextures)
505
    {
506
    int maxSize = DistortedLibrary.getMaxTextureSize();
507
508
    mTexHeight  = DEFAULT_TEXTURE_HEIGHT;
509
510
    while(true)
511
      {
512 d1025da5 leszek
      mNumTexCols = DEFAULT_TEXTURE_ROWS;
513 f3eab97f leszek
      mNumTexRows = numTextures/mNumTexCols + 1;
514
515 d1025da5 leszek
      if( mNumTexRows*mTexHeight <= maxSize &&
516
          mNumTexCols*mTexHeight <= maxSize  ) break;
517
518
      mTexHeight/=2;
519 f3eab97f leszek
      }
520
    }
521
522 7994b456 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
523
524
  private void setUpTextures(boolean fromDMESH, boolean fromJSON)
525
    {
526
    mTexture = new DistortedTexture();
527
528
    if( fromJSON )
529
      {
530
      mNumStickerTypes = getNumStickerTypes();
531
      mNumCubitFaces = getNumCubitFaces();
532
      }
533
    else
534
      {
535
      FactoryCubit factory = FactoryCubit.getInstance();
536 3d2493ea Leszek Koltunski
      mStickerCoords   = factory.getStickerCoords();
537 7994b456 Leszek Koltunski
      mStickerVariants = factory.getStickerVariants();
538 3d2493ea Leszek Koltunski
      mStickerScales   = factory.getStickerScales();
539 7994b456 Leszek Koltunski
      adjustStickerCoords();
540 325a17e0 Leszek Koltunski
      mNumStickerTypes = (mStickerCoords==null ? 0 : mStickerCoords.length);
541 7994b456 Leszek Koltunski
      }
542
543 3a0a23bf Leszek Koltunski
    mStickerOverrides = getStickerOverrides();
544
    mNumOverrides = mStickerOverrides==null ? 0 : mStickerOverrides.length;
545
546
    mNumTextures= mNumFaceColors*mNumStickerTypes + mNumOverrides;
547 f3eab97f leszek
    figureOutBitmapDimensions(mNumTextures);
548 a05b6e06 Leszek Koltunski
    if( mNumTexCols*mNumTexRows < mNumTextures+1 ) mNumTexRows++;
549 7994b456 Leszek Koltunski
550
    if( !fromDMESH || shouldResetTextureMaps() ) resetAllTextureMaps();
551 b0c97683 Leszek Koltunski
    else overrideCubitFaceColor();
552
553 7994b456 Leszek Koltunski
    setTexture();
554
    }
555
556 a8295031 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
557
558 ae9d9227 leszek
  public Metadata getMetadata()
559 a8295031 Leszek Koltunski
    {
560 ae9d9227 leszek
    return mMetadata;
561 a8295031 Leszek Koltunski
    }
562
563 3bf19410 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
564
565
  public boolean isInIconMode()
566
    {
567
    return mIconMode==MODE_ICON;
568
    }
569
570 ec42a6fe Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
571
572 51262d81 Leszek Koltunski
  public int getVariantStickerShape(int variant, int face)
573 ec42a6fe Leszek Koltunski
    {
574 f7f5771f leszek
    if( variant <mStickerVariants.length )
575
      {
576
      int[] var = mStickerVariants[variant];
577
      return face>=var.length ? -1 : var[face];
578
      }
579
    return -1;
580 ec42a6fe Leszek Koltunski
    }
581
582 19595510 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
583
584
  public boolean shouldResetTextureMaps()
585
    {
586
    return false;
587
    }
588
589 9ba7f3f6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
590
591
  public int[][] getScrambleAlgorithms()
592
    {
593 731280f7 Leszek Koltunski
    return ScrambleEdgeGenerator.getScramblingAlgorithms(mBasicAngles);
594 9ba7f3f6 Leszek Koltunski
    }
595
596 a4af26c1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
597
598
  private boolean sticksOut(Static3D[] faceAxis, float[] dist, float x, float y, float z )
599
    {
600
    final float MAXERR = 0.05f;
601
    int numAxis = dist.length;
602
603
    for(int i=0; i<numAxis; i++)
604
      {
605
      Static3D ax = faceAxis[i];
606
      float len = ax.get0()*x + ax.get1()*y + ax.get2()*z;
607 dcce7b29 Leszek Koltunski
      if( len>mSize*dist[i]+MAXERR ) return true;
608 a4af26c1 Leszek Koltunski
      }
609
610
    return false;
611
    }
612
613
///////////////////////////////////////////////////////////////////////////////////////////////////
614
615 9554f5d4 Leszek Koltunski
  private boolean doesNotStickOut(int variant, float px, float py, float pz, float[] tmp, Static4D quat)
616 a4af26c1 Leszek Koltunski
    {
617 fbd18fc7 Leszek Koltunski
    float[][] vertices = mShapes[variant].getVertices();
618 a4af26c1 Leszek Koltunski
    Static3D[] axis = getFaceAxis();
619
    float[] dist3D = getDist3D(mNumLayers);
620
621
    for( float[] vertex : vertices)
622
      {
623
      float x = vertex[0];
624
      float y = vertex[1];
625
      float z = vertex[2];
626
627
      QuatHelper.rotateVectorByQuat(tmp, x, y, z, 1, quat);
628
629 9554f5d4 Leszek Koltunski
      float mx = tmp[0] + px;
630
      float my = tmp[1] + py;
631
      float mz = tmp[2] + pz;
632 a4af26c1 Leszek Koltunski
633
      if( sticksOut(axis, dist3D, mx,my,mz) ) return false;
634
      }
635
636
    return true;
637
    }
638
639 9554f5d4 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
640
641
  private float computeAvg(float[] pos, int offset)
642
    {
643
    int len = pos.length/3;
644
    float ret=0.0f;
645
    for(int i=0; i<len; i++) ret += pos[3*i+offset];
646
    ret /= len;
647
648
    return ret;
649
    }
650
651 97a6aa87 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
652
653
  protected void displayCubitQuats()
654
    {
655
    StringBuilder builder = new StringBuilder();
656
    float[] tmp = new float[4];
657 a4af26c1 Leszek Koltunski
    float ERR = 0.01f;
658 97a6aa87 Leszek Koltunski
659
    for(int cubit=0; cubit<mNumCubits; cubit++)
660
      {
661 a4af26c1 Leszek Koltunski
      builder.append(cubit);
662
      builder.append(" : ");
663
664 97a6aa87 Leszek Koltunski
      int refCubit,variant = getCubitVariant(cubit,mNumLayers);
665
666
      for(refCubit=0; refCubit<mNumCubits; refCubit++)
667
        {
668
        if( getCubitVariant(refCubit,mNumLayers)==variant ) break;
669
        }
670
671
      float[] curpos = mOrigPos[cubit];
672
      float[] refpos = mOrigPos[refCubit];
673 9554f5d4 Leszek Koltunski
      float refX = computeAvg(refpos,0);
674
      float refY = computeAvg(refpos,1);
675
      float refZ = computeAvg(refpos,2);
676
      float curX = computeAvg(curpos,0);
677
      float curY = computeAvg(curpos,1);
678
      float curZ = computeAvg(curpos,2);
679 97a6aa87 Leszek Koltunski
680
      for(int quat=0; quat<mNumQuats; quat++)
681
        {
682
        QuatHelper.rotateVectorByQuat(tmp,refX,refY,refZ,0,mObjectQuats[quat]);
683
684
        float dx = tmp[0]-curX;
685
        float dy = tmp[1]-curY;
686
        float dz = tmp[2]-curZ;
687
688 a4af26c1 Leszek Koltunski
        if( dx>-ERR && dx<ERR && dy>-ERR && dy<ERR && dz>-ERR && dz<ERR )
689 97a6aa87 Leszek Koltunski
          {
690 9554f5d4 Leszek Koltunski
          if( doesNotStickOut(variant,curX,curY,curZ,tmp,mObjectQuats[quat]) )
691 a4af26c1 Leszek Koltunski
            {
692
            builder.append(quat);
693
            builder.append(',');
694
            }
695
          else
696
            {
697
            android.util.Log.e("D", "cubit: "+cubit+" quat: "+quat+" : center correct, but shape sticks out");
698
            }
699 97a6aa87 Leszek Koltunski
          }
700
        }
701
702
      builder.append('\n');
703
      }
704
705 9cb7d66f Leszek Koltunski
    android.util.Log.e("D", "cubitQuats: \n"+builder );
706 97a6aa87 Leszek Koltunski
    }
707
708 bc008758 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
709
710 fbd18fc7 Leszek Koltunski
  public int getCubitRotationType(int cubit)
711 bc008758 Leszek Koltunski
    {
712 5618c5a9 Leszek Koltunski
    return TwistyObjectCubit.TYPE_NORMAL;
713 fbd18fc7 Leszek Koltunski
    }
714
715
///////////////////////////////////////////////////////////////////////////////////////////////////
716
717 d844220f Leszek Koltunski
  float[] getTrackingPoint(int cubitIndex, int cubitType)
718 fbd18fc7 Leszek Koltunski
    {
719 5618c5a9 Leszek Koltunski
    if( cubitType!=TwistyObjectCubit.TYPE_NORMAL )
720 fbd18fc7 Leszek Koltunski
      {
721
      int variant = getCubitVariant(cubitIndex,mNumLayers);
722 40e77224 Leszek Koltunski
723
      // object must have been created from JSON
724
      if( mVariantFaceIsOuter==null || mVariantFaceIsOuter[variant]==null )
725
        {
726
        mVariantFaceIsOuter = getVariantFaceIsOuter();
727
        }
728 39c6b370 Leszek Koltunski
      if( mShapes==null )
729
        {
730
        mShapes = new ObjectShape[mNumCubitVariants];
731
        }
732
      if( mShapes[variant]==null )
733
        {
734
        mShapes[variant] = getObjectShape(variant);
735
        }
736
      if( mOrigQuat==null )
737
        {
738
        mOrigQuat = new Static4D[mNumCubits];
739
        }
740
      if( mOrigQuat[cubitIndex]==null )
741
        {
742
        mOrigQuat[cubitIndex] = getCubitQuats(cubitIndex,mNumLayers);
743
        }
744
745 efa5bc1e leszek
      int outer=-1, faces = mShapes[variant].getNumFaces();
746 fbd18fc7 Leszek Koltunski
747
      for(int i=0; i<faces; i++)
748
        {
749
        if( mVariantFaceIsOuter[variant][i]==1 )
750
          {
751
          outer=i;
752
          break;
753
          }
754
        }
755
756
      if( outer>=0 )
757
        {
758 efa5bc1e leszek
        float[] v = mShapes[variant].getFirstVertexInFace(outer);
759 fbd18fc7 Leszek Koltunski
        float[] ret = new float[3];
760
        float[] curpos = mOrigPos[cubitIndex];
761
        Static4D quat = mOrigQuat[cubitIndex];
762 efa5bc1e leszek
        QuatHelper.rotateVectorByQuat(mTmp, v[0], v[1], v[2], 1, quat);
763 fbd18fc7 Leszek Koltunski
764
        ret[0] = mTmp[0]+computeAvg(curpos,0);
765
        ret[1] = mTmp[1]+computeAvg(curpos,1);
766
        ret[2] = mTmp[2]+computeAvg(curpos,2);
767
768
        return ret;
769
        }
770
      else
771
        {
772 d844220f Leszek Koltunski
        android.util.Log.e("D", "Error in getTrackingPoint: no outer face??");
773 fbd18fc7 Leszek Koltunski
        }
774
      }
775
776
    return null;
777
    }
778
779
///////////////////////////////////////////////////////////////////////////////////////////////////
780
781 1f329dcc Leszek Koltunski
  public int computeCurrentPuzzleFace(int type, float[] vertex)
782 fbd18fc7 Leszek Koltunski
    {
783 5618c5a9 Leszek Koltunski
    if( type!=TwistyObjectCubit.TYPE_NORMAL )
784 fbd18fc7 Leszek Koltunski
      {
785
      Static3D[] axis = getFaceAxis();
786
      float[] dist3D = getDist3D(mNumLayers);
787
      final float MAXERR = 0.98f;
788
      int numAxis = axis.length;
789
      float x = vertex[0];
790
      float y = vertex[1];
791
      float z = vertex[2];
792
793
      for(int i=0; i<numAxis; i++)
794
        {
795
        Static3D ax = axis[i];
796
        float len = ax.get0()*x + ax.get1()*y + ax.get2()*z;
797
        if( len>mSize*dist3D[i]*MAXERR ) return i;
798
        }
799 4e1f3a8e Leszek Koltunski
800 1f329dcc Leszek Koltunski
      return -2;
801 fbd18fc7 Leszek Koltunski
      }
802
803
    return -1;
804
    }
805
806
///////////////////////////////////////////////////////////////////////////////////////////////////
807
808
  public float[] getCubitRowOffset(int cubitIndex)
809
    {
810
    return null;
811
    }
812
813
///////////////////////////////////////////////////////////////////////////////////////////////////
814
815
  void setRotationRowOffset(int puzzleFace, float[] offset)
816
    {
817
    mRowOffsets[puzzleFace][0] = offset[0];
818
    mRowOffsets[puzzleFace][1] = offset[1];
819
    mRowOffsets[puzzleFace][2] = offset[2];
820 bc008758 Leszek Koltunski
    }
821
822 d85de775 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
823
824
  int getNumAxis()
825
    {
826
    return mNumAxis;
827
    }
828
829 f5426a4c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
830
831 19595510 Leszek Koltunski
  public int[][] getSolvedQuats()
832 074a0284 leszek
    {
833
    return null;
834
    }
835
836
///////////////////////////////////////////////////////////////////////////////////////////////////
837
838
  protected int[][] getOldSolvedQuats()
839 f5426a4c Leszek Koltunski
    {
840 5618c5a9 Leszek Koltunski
    return mSolved.getSolvedQuats(mNumLayers,mNumCubitFaces,mCubitFaceColors);
841 f5426a4c Leszek Koltunski
    }
842
843
///////////////////////////////////////////////////////////////////////////////////////////////////
844 074a0284 leszek
// 0: old, groups-of-quaternions based function.
845
// Still used by: Masterball, Mirror Sqewb, Mirror Jing, Mirror Pyraminx & the Penrose Cubes.
846
//
847
// 1: specific function only for the Dino4.
848
//
849
// 2: the new default; automatic way based on automatic detection of monochromatic puzzle surfaces.
850 f5426a4c Leszek Koltunski
851
  public int getSolvedFunctionIndex()
852
    {
853 074a0284 leszek
    return 2;
854 f5426a4c Leszek Koltunski
    }
855
856 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
857
858 fbd18fc7 Leszek Koltunski
  int computeRow(float[] pos, int axisIndex, int cubitType, int puzzleFace)
859 29b82486 Leszek Koltunski
    {
860
    int ret=0;
861
    int len = pos.length / 3;
862
    Static3D axis = mAxis[axisIndex];
863
    float axisX = axis.get0();
864
    float axisY = axis.get1();
865
    float axisZ = axis.get2();
866 fbd18fc7 Leszek Koltunski
    float casted, xoff=0, yoff=0, zoff=0;
867 29b82486 Leszek Koltunski
868 5618c5a9 Leszek Koltunski
    if( cubitType!=TwistyObjectCubit.TYPE_NORMAL )
869 fbd18fc7 Leszek Koltunski
      {
870
      xoff = mRowOffsets[puzzleFace][0];
871
      yoff = mRowOffsets[puzzleFace][1];
872
      zoff = mRowOffsets[puzzleFace][2];
873
      }
874 bc008758 Leszek Koltunski
875 29b82486 Leszek Koltunski
    for(int i=0; i<len; i++)
876
      {
877 bc008758 Leszek Koltunski
      casted = (pos[3*i]+xoff)*axisX + (pos[3*i+1]+yoff)*axisY + (pos[3*i+2]+zoff)*axisZ;
878 29b82486 Leszek Koltunski
      ret |= computeSingleRow(axisIndex,casted);
879
      }
880
881
    return ret;
882
    }
883
884
///////////////////////////////////////////////////////////////////////////////////////////////////
885
886
  private int computeSingleRow(int axisIndex,float casted)
887
    {
888
    int num = mNumCuts[axisIndex];
889 b346ba5b leszek
    float[] cuts = mCuts[axisIndex];
890 29b82486 Leszek Koltunski
891
    for(int i=0; i<num; i++)
892
      {
893 b346ba5b leszek
      if( casted<cuts[i] ) return (1<<i);
894 29b82486 Leszek Koltunski
      }
895
896
    return (1<<num);
897
    }
898
899
///////////////////////////////////////////////////////////////////////////////////////////////////
900
901
  private boolean belongsToRotation( int cubit, int axis, int rowBitmap)
902
    {
903 a05b6e06 Leszek Koltunski
    return (mCubits[cubit].getRotRow(axis) & rowBitmap) != 0;
904 29b82486 Leszek Koltunski
    }
905
906
///////////////////////////////////////////////////////////////////////////////////////////////////
907
// note the minus in front of the sin() - we rotate counterclockwise
908
// when looking towards the direction where the axis increases in values.
909
910 1f329dcc Leszek Koltunski
  private Static4D makeQuaternion(float axisX, float axisY, float axisZ, int angleInDegrees)
911 29b82486 Leszek Koltunski
    {
912
    while( angleInDegrees<0 ) angleInDegrees += 360;
913
    angleInDegrees %= 360;
914
    
915
    float cosA = (float)Math.cos(Math.PI*angleInDegrees/360);
916
    float sinA =-(float)Math.sqrt(1-cosA*cosA);
917
918 1f329dcc Leszek Koltunski
    return new Static4D(axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
919 29b82486 Leszek Koltunski
    }
920
921 e3169794 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
922
923
  void rotateAllCubits(int axisIndex, int rowBitmap, int angle)
924
    {
925
    Static3D axis = mAxis[axisIndex];
926
    float axisX = axis.get0();
927
    float axisY = axis.get1();
928
    float axisZ = axis.get2();
929
    Static4D quat = makeQuaternion(axisX,axisY,axisZ,angle);
930
931
    for(int i=0; i<mNumCubits; i++)
932
      {
933
      mBelongs[i] = belongsToRotation(i,axisIndex,rowBitmap);
934
      if( mBelongs[i] )
935
        {
936
        boolean result = mCubits[i].rotateCubit(quat,false);
937
        if( !result ) debugQuat(quat,i,axisX,axisY,axisZ,angle,1);
938
        }
939
      }
940
941
    recomputeFaceOffsets();
942
943
    for(int i=0; i<mNumCubits; i++)
944
      {
945
      if( mBelongs[i] )
946
        {
947
        int index = mCubits[i].postRotateCubit(quat);
948
        setCubitQuat(i,index);
949
        }
950
      else if( mCubits[i].getType()==TwistyObjectCubit.TYPE_FOLLOWER )
951
        {
952
        mCubits[i].computeRotationRow();
953
        setCubitQuat(i,mCubits[i].mQuatIndex);
954
        }
955
      }
956
    }
957
958 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
959
960
  private synchronized void setupPosition(int[][] moves)
961
    {
962
    if( moves!=null )
963
      {
964 e3169794 leszek
      int axisIndex, row, rowBitmap, basic, angle;
965 29b82486 Leszek Koltunski
966
      for(int[] move: moves)
967
        {
968 1f329dcc Leszek Koltunski
        axisIndex= move[0];
969 e3169794 leszek
        rowBitmap= computeBandagedBitmap( move[1],axisIndex);
970 c9e40dfc Leszek Koltunski
        row      = computeRowFromBitmap( move[1] );
971 1f329dcc Leszek Koltunski
        basic    = mBasicAngles[axisIndex][row];
972 40e76ea4 Leszek Koltunski
        angle    = move[2]*(360/basic);   // this assumes that all layers from
973
                                          // the bitmap have the same BasicAngle.
974
                                          // at the moment this is always true as
975
                                          // there are no bandaged objects with
976
                                          // different per-layer BasicAngles.
977 29b82486 Leszek Koltunski
978 e3169794 leszek
        rotateAllCubits(axisIndex,rowBitmap,angle);
979 29b82486 Leszek Koltunski
        }
980 3788d0cd Leszek Koltunski
981
      for(int i=0; i<mNumCubits; i++)
982
        {
983
        float[] pos = mCubits[i].getCurrentPos();
984
        int len = pos.length/3;
985
        for(int j=0; j<len; j++) clampPos(pos,3*j);
986
        }
987 29b82486 Leszek Koltunski
      }
988
    }
989
990
///////////////////////////////////////////////////////////////////////////////////////////////////
991
992 f9a81f52 Leszek Koltunski
  public int getScrambleType()
993 29b82486 Leszek Koltunski
    {
994 9283a268 Leszek Koltunski
    return ObjectScrambler.SCRAMBLING_ALGORITHMS;
995 29b82486 Leszek Koltunski
    }
996
997 63bfcdd1 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
998
999
  public int[][] getMinimalCubiesInRow()
1000
    {
1001
    return null;
1002
    }
1003
1004 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1005
1006 7ca7a08f leszek
  int computeBandagedBitmap(int rowBitmap, int axisIndex)
1007 29b82486 Leszek Koltunski
    {
1008
    if( mIsBandaged )
1009
      {
1010
      int bitmap, initBitmap=0;
1011
1012
      while( initBitmap!=rowBitmap )
1013
        {
1014
        initBitmap = rowBitmap;
1015
1016 a05b6e06 Leszek Koltunski
        for(int cubit=0; cubit<mNumCubits; cubit++)
1017 29b82486 Leszek Koltunski
          {
1018 7ca7a08f leszek
          bitmap = mCubits[cubit].getRotRow(axisIndex);
1019 29b82486 Leszek Koltunski
          if( (rowBitmap & bitmap) != 0 ) rowBitmap |= bitmap;
1020
          }
1021
        }
1022
      }
1023
1024 63bfcdd1 leszek
    if( mMinimalCubiesInRow!=null )
1025
      {
1026 7ca7a08f leszek
      int[] minC = mMinimalCubiesInRow[axisIndex];
1027 63bfcdd1 leszek
      int numL = minC.length;
1028
      int[] numC = new int[numL];
1029
1030
      for(int cubit=0; cubit<mNumCubits; cubit++)
1031
        {
1032 7ca7a08f leszek
        int bitmap = mCubits[cubit].getRotRow(axisIndex);
1033 63bfcdd1 leszek
1034
        for(int i=0; i<numL; i++)
1035
          {
1036
          if( (bitmap&0x1)!=0 ) numC[i]++;
1037
          bitmap>>=1;
1038
          }
1039
        }
1040
1041
      int bitmap,initBitmap = 0;
1042
1043
      while( initBitmap!=rowBitmap )
1044
        {
1045
        initBitmap = rowBitmap;
1046
        bitmap = rowBitmap;
1047
        int last = 0;
1048
1049
        for(int i=0; i<numL; i++)
1050
          {
1051
          if( numC[i]<minC[i] && numC[i]>0 )
1052
            {
1053
            if( (bitmap&0x1)!=0 )
1054
              {
1055
              if( i>0     ) rowBitmap |= (1<<(i-1));
1056
              if( i<numL-1) rowBitmap |= (1<<(i+1));
1057
              }
1058
            else if( (bitmap&0x2)!=0 || last>0 ) // we are not rotating this row, but
1059
                                                 // we are rotating the next or the prev
1060
              {
1061
              rowBitmap |= (1<<i);
1062
              }
1063
            }
1064
1065
          last = (bitmap&0x1);
1066
          bitmap>>=1;
1067
          }
1068
        }
1069
      }
1070
1071 29b82486 Leszek Koltunski
    return rowBitmap;
1072
    }
1073
1074 c9e40dfc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1075
1076
  private int computeRowFromBitmap(int rowBitmap)
1077
    {
1078
    int index = 0;
1079
1080
    while(index<32)
1081
      {
1082
      if( (rowBitmap&0x1) != 0 ) return index;
1083
      rowBitmap>>=1;
1084
      index++;
1085
      }
1086
    return 0;
1087
    }
1088
1089 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1090
// Clamp all rotated positions to one of those original ones to avoid accumulating errors.
1091
// Do so only if minimal Error is appropriately low (shape-shifting puzzles - Square-1)
1092
1093 fbd18fc7 Leszek Koltunski
  void clampPos(float[] pos, int offset)
1094 29b82486 Leszek Koltunski
    {
1095
    float currError, minError = Float.MAX_VALUE;
1096
    int minErrorIndex1 = -1;
1097
    int minErrorIndex2 = -1;
1098
1099
    float x = pos[offset  ];
1100
    float y = pos[offset+1];
1101
    float z = pos[offset+2];
1102
1103
    float xo,yo,zo;
1104
1105 a05b6e06 Leszek Koltunski
    for(int i=0; i<mNumCubits; i++)
1106 29b82486 Leszek Koltunski
      {
1107
      int len = mOrigPos[i].length / 3;
1108
1109
      for(int j=0; j<len; j++)
1110
        {
1111
        xo = mOrigPos[i][3*j  ];
1112
        yo = mOrigPos[i][3*j+1];
1113
        zo = mOrigPos[i][3*j+2];
1114
1115
        currError = (xo-x)*(xo-x) + (yo-y)*(yo-y) + (zo-z)*(zo-z);
1116
1117
        if( currError<minError )
1118
          {
1119
          minError = currError;
1120
          minErrorIndex1 = i;
1121
          minErrorIndex2 = j;
1122
          }
1123
        }
1124
      }
1125
1126 4bd1b3d6 Leszek Koltunski
    if( minError< 0.05f ) // TODO: 0.05 ?
1127 29b82486 Leszek Koltunski
      {
1128
      pos[offset  ] = mOrigPos[minErrorIndex1][3*minErrorIndex2  ];
1129
      pos[offset+1] = mOrigPos[minErrorIndex1][3*minErrorIndex2+1];
1130
      pos[offset+2] = mOrigPos[minErrorIndex1][3*minErrorIndex2+2];
1131
      }
1132
    }
1133
1134 d887aa16 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1135
1136
  void setLibInterface(ObjectLibInterface inter)
1137
    {
1138
    mInterface = inter;
1139 c8bc83d9 Leszek Koltunski
    }
1140
1141 d356eecc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1142
1143
  void applyScrambles(int[][] moves)
1144
    {
1145
    setupPosition(moves);
1146
    }
1147
1148 7c111294 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1149 198c5bf0 Leszek Koltunski
1150 880beeea Leszek Koltunski
  void initializeObject(int[][] moves)
1151 7c111294 Leszek Koltunski
    {
1152
    solve();
1153
    setupPosition(moves);
1154
    }
1155 198c5bf0 Leszek Koltunski
1156 5a20f7a1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1157
1158
  private void recomputeFaceOffsets()
1159
    {
1160 3788d0cd Leszek Koltunski
    if( mThereAreDeciders )
1161 5a20f7a1 Leszek Koltunski
      {
1162 3788d0cd Leszek Koltunski
      for(int i=0; i<mNumPuzzleFaces; i++)
1163 5a20f7a1 Leszek Koltunski
        {
1164 3788d0cd Leszek Koltunski
        mRowOffsets[i][0] =0;
1165
        mRowOffsets[i][1] =0;
1166
        mRowOffsets[i][2] =0;
1167 5a20f7a1 Leszek Koltunski
        }
1168 3788d0cd Leszek Koltunski
1169
      for(int i=0; i<mNumCubits; i++)
1170
        if( mCubits[i].getType()==TwistyObjectCubit.TYPE_DECIDER )
1171
          {
1172
          float[] offset = mCubits[i].getOffset();
1173
          int face = mCubits[i].getPuzzleFace();
1174
          mRowOffsets[face][0] = offset[0];
1175
          mRowOffsets[face][1] = offset[1];
1176
          mRowOffsets[face][2] = offset[2];
1177
          }
1178
      }
1179 5a20f7a1 Leszek Koltunski
    }
1180
1181 c8bc83d9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1182
1183 4a014840 leszek
  synchronized float removeRotation()
1184 bb58b357 leszek
    {
1185 4a014840 leszek
    return mRotation.removeRotation();
1186 bb58b357 leszek
    }
1187
1188
///////////////////////////////////////////////////////////////////////////////////////////////////
1189
1190 a0ef8a1d leszek
  long finishRotation(ObjectPreRender pre, int finishAx, int finishRow, float finishAngle, float avgSpeed)
1191 c8bc83d9 Leszek Koltunski
    {
1192 e3169794 leszek
    int basicAngle = mBasicAngles[finishAx][finishRow];
1193 a0ef8a1d leszek
    return mRotation.finishRotation(pre,finishAx,finishRow,basicAngle,finishAngle,avgSpeed);
1194 c8bc83d9 Leszek Koltunski
    }
1195
1196 bb58b357 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1197
1198
  void continueRotation(float angleInDegrees)
1199
    {
1200 e3169794 leszek
    mRotation.continueRotation(angleInDegrees);
1201 bb58b357 leszek
    }
1202
1203 c8bc83d9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1204
1205 4a014840 leszek
  synchronized long addRotation(EffectListener listener, int axis, int rowBitmap, int angle, long durationMillis )
1206
    {
1207 63bfcdd1 leszek
    return mRotation.addRotation(listener,axis,rowBitmap,angle,durationMillis);
1208 4a014840 leszek
    }
1209
1210
///////////////////////////////////////////////////////////////////////////////////////////////////
1211
1212 93dc5a55 leszek
  void enableGhostAxis(int axNum, boolean enable)
1213 c8bc83d9 Leszek Koltunski
    {
1214 93dc5a55 leszek
    mTouchControl.enableGhostAxis(axNum,enable);
1215 c8bc83d9 Leszek Koltunski
    }
1216
1217 880beeea Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1218
1219 4a014840 leszek
  synchronized boolean beginRotation(int axis, int row )
1220 880beeea Leszek Koltunski
    {
1221 d55d2c6a Leszek Koltunski
    if( axis<0 || axis>=mNumAxis )
1222 880beeea Leszek Koltunski
      {
1223
      android.util.Log.e("object", "invalid rotation axis: "+axis);
1224 605f319b Leszek Koltunski
      return false;
1225 880beeea Leszek Koltunski
      }
1226
1227 63bfcdd1 leszek
    return mRotation.beginRotation(axis,row);
1228 880beeea Leszek Koltunski
    }
1229
1230
///////////////////////////////////////////////////////////////////////////////////////////////////
1231
1232 51262d81 Leszek Koltunski
  void setTextureMap(int cubit, int face, int color)
1233 29b82486 Leszek Koltunski
    {
1234 51262d81 Leszek Koltunski
    int variant  = getCubitVariant(cubit,mNumLayers);
1235
    int shape    = getVariantStickerShape(variant,face);
1236
    int texIndex = color<0 || shape<0 ? mNumTextures-mNumOverrides : shape*mNumFaceColors + color;
1237
    int row      = (mNumTexRows-1) - texIndex/mNumTexCols;
1238
    int col      = texIndex%mNumTexCols;
1239
1240 7c111294 Leszek Koltunski
    final float ratioW = 1.0f/mNumTexCols;
1241
    final float ratioH = 1.0f/mNumTexRows;
1242 51262d81 Leszek Koltunski
    final Static4D[] maps = new Static4D[1];
1243
    maps[0] = new Static4D(col*ratioW, row*ratioH, ratioW, ratioH);
1244
    mMesh.setTextureMap(maps,mNumCubitFaces*cubit+face);
1245 29b82486 Leszek Koltunski
    }
1246
1247 55acff1e leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1248
// figure out the whole face to which (cubit,face) belongs, repaint all (cubit,face) pairs to
1249
// the new color.
1250
1251 6f5eb9b3 leszek
  void repaintPuzzleFace(int cubit, int face, int newColor)
1252 55acff1e leszek
    {
1253 9ef0ad15 leszek
    int oldColorIndex = getDefaultCubitFaceColor(cubit,face);
1254 5ce579d2 leszek
1255
    if( oldColorIndex<0 || oldColorIndex>=mNumFaceColors )
1256
      {
1257 9ef0ad15 leszek
      android.util.Log.e("D", "TwistyObject.repaintPuzzleFace: index="+oldColorIndex);
1258 5ce579d2 leszek
      return;
1259
      }
1260
1261 962b8ff6 leszek
    int oldColor = mColorTable[oldColorIndex];
1262 7e8750c9 leszek
1263 962b8ff6 leszek
    if( oldColor!=newColor )
1264 7e8750c9 leszek
      {
1265 5ce579d2 leszek
      oldColor = mOriginalColorTable[oldColorIndex];
1266 6f5eb9b3 leszek
      changeColorInTexture(oldColor,newColor);
1267 962b8ff6 leszek
      mColorTable[oldColorIndex] = newColor;
1268 7e8750c9 leszek
      setTexture();
1269 22d72239 leszek
1270
      int numOrig = numberOfDifferentColors(mOriginalColorTable);
1271
      int numNow  = numberOfDifferentColors(mColorTable);
1272
      mCurrentColorSchemeSubmittable = (numOrig==numNow);
1273 7e8750c9 leszek
      }
1274 55acff1e leszek
    }
1275
1276 9b1fe915 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1277 1eafa9c6 leszek
// this doesn't have to return the real, displayed color - but the default one (from Shape classes).
1278
// The real displayed color can be different because of the sticker color overrides in 'Config'.
1279 9b1fe915 Leszek Koltunski
1280 9ef0ad15 leszek
  int getDefaultCubitFaceColor(int cubit, int face)
1281 9b1fe915 Leszek Koltunski
    {
1282 ed0988c0 Leszek Koltunski
    int puzzleFace = getCubitFaceMap(cubit,face);
1283
    if( puzzleFace>=0 ) puzzleFace %= mNumFaceColors;
1284
    return puzzleFace;
1285 1b7ece90 Leszek Koltunski
    }
1286
1287
///////////////////////////////////////////////////////////////////////////////////////////////////
1288
1289 ed0988c0 Leszek Koltunski
  public int getCubitFaceMap(int cubit, int face)
1290 1b7ece90 Leszek Koltunski
    {
1291
    int numFaces = mCubitFaceColors[cubit].length;
1292
    int puzzleFace = face<numFaces ? mCubitFaceColors[cubit][face] : -1;
1293
    return puzzleFace<0 ? -1 : puzzleFace;
1294
    }
1295
1296 f80b9473 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1297
// this would return the REAL value of outer; the 'getCubitFaceColor()>=0' returns if the face is
1298
// colored, which for example in case of Container (which has colored internal faces) is not the
1299
// same thing
1300
1301
  boolean faceIsOuter(int cubit, int face)
1302
    {
1303 d03443d4 leszek
    if( mCubitFaceColors==null )
1304
      {
1305
      if( mShapes==null )
1306
        {
1307
        mShapes = new ObjectShape[mNumCubitVariants];
1308
        }
1309
1310
      if( mShapes[0]==null )
1311
        {
1312
        for(int v=0; v<mNumCubitVariants; v++) mShapes[v] = getObjectShape(v);
1313
        }
1314
1315
      if( mOrigQuat==null )
1316
        {
1317
        mOrigQuat = new Static4D[mNumCubits];
1318
        }
1319
1320
      if( mOrigQuat[0]==null )
1321
        {
1322
        for(int c=0; c<mNumCubits; c++) mOrigQuat[c] = getCubitQuats(c,mNumLayers);
1323
        }
1324
1325
      mCubitFaceColors = ObjectShape.computeColors(mShapes,mOrigPos,mOrigQuat,this);
1326
      }
1327
1328 f80b9473 leszek
    return mCubitFaceColors[cubit][face]>=0;
1329
    }
1330
1331 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1332
1333 880beeea Leszek Koltunski
  void resetAllTextureMaps()
1334 29b82486 Leszek Koltunski
    {
1335 7c111294 Leszek Koltunski
    final float ratioW = 1.0f/mNumTexCols;
1336
    final float ratioH = 1.0f/mNumTexRows;
1337 51262d81 Leszek Koltunski
    int cubColor, stiShape, texIndex, variant, row, col;
1338 29b82486 Leszek Koltunski
1339 a05b6e06 Leszek Koltunski
    for(int cubit=0; cubit<mNumCubits; cubit++)
1340 29b82486 Leszek Koltunski
      {
1341 7c111294 Leszek Koltunski
      final Static4D[] maps = new Static4D[mNumCubitFaces];
1342 a75ae1ee Leszek Koltunski
      variant = getCubitVariant(cubit,mNumLayers);
1343 29b82486 Leszek Koltunski
1344 a75ae1ee Leszek Koltunski
      for(int face=0; face<mNumCubitFaces; face++)
1345 7c111294 Leszek Koltunski
        {
1346 9ef0ad15 leszek
        cubColor = getDefaultCubitFaceColor(cubit,face);
1347 51262d81 Leszek Koltunski
        stiShape = getVariantStickerShape(variant,face);
1348
        texIndex = cubColor<0 || stiShape<0 ? mNumTextures-mNumOverrides : stiShape*mNumFaceColors + cubColor;
1349
        row      = (mNumTexRows-1) - texIndex/mNumTexCols;
1350
        col      = texIndex%mNumTexCols;
1351 a75ae1ee Leszek Koltunski
1352
        maps[face] = new Static4D( col*ratioW, row*ratioH, ratioW, ratioH);
1353 7c111294 Leszek Koltunski
        }
1354 29b82486 Leszek Koltunski
1355 7c111294 Leszek Koltunski
      mMesh.setTextureMap(maps,mNumCubitFaces*cubit);
1356
      }
1357 0b050556 Leszek Koltunski
1358 b0c97683 Leszek Koltunski
    overrideCubitFaceColor();
1359
    }
1360
1361
///////////////////////////////////////////////////////////////////////////////////////////////////
1362
1363
  private void overrideCubitFaceColor()
1364
    {
1365
    final float ratioW = 1.0f/mNumTexCols;
1366
    final float ratioH = 1.0f/mNumTexRows;
1367
1368 0b050556 Leszek Koltunski
    for(int i=0; i<mNumOverrides; i++)
1369
      {
1370
      int[] cubitFaces = mStickerOverrides[i].getCubitFaces();
1371
      int length = cubitFaces.length/2;
1372
1373
      for(int j=0; j<length; j++)
1374 b0c97683 Leszek Koltunski
        {
1375
        final Static4D[] maps = new Static4D[1];
1376
        int color = mNumTextures-mNumOverrides+1+i;
1377
        int row   = (mNumTexRows-1) - color/mNumTexCols;
1378
        int col   = color%mNumTexCols;
1379
        int cubit = cubitFaces[2*j];
1380
        int face  = cubitFaces[2*j+1];
1381
        maps[0] = new Static4D(col*ratioW, row*ratioH, ratioW, ratioH);
1382
        mMesh.setTextureMap(maps,mNumCubitFaces*cubit+face);
1383
        }
1384 0b050556 Leszek Koltunski
      }
1385
    }
1386
1387 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1388
1389 880beeea Leszek Koltunski
  void releaseResources()
1390 29b82486 Leszek Koltunski
    {
1391 7c111294 Leszek Koltunski
    mTexture.markForDeletion();
1392
    mMesh.markForDeletion();
1393
    mEffects.markForDeletion();
1394
1395 94490b34 leszek
    if( mBitmap!=null )
1396
      {
1397
      mBitmap.recycle();
1398
      mBitmap = null;
1399
      }
1400
1401 a05b6e06 Leszek Koltunski
    for(int j=0; j<mNumCubits; j++)
1402 7c111294 Leszek Koltunski
      {
1403 a05b6e06 Leszek Koltunski
      mCubits[j].releaseResources();
1404 7c111294 Leszek Koltunski
      }
1405 29b82486 Leszek Koltunski
    }
1406
1407 00a28d71 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1408
1409 544c9224 leszek
  private void setCubitQuat(int cubit, int equAssociation)
1410 00a28d71 Leszek Koltunski
    {
1411 544c9224 leszek
    int andAssociation = mCubits[cubit].computeAssociation();
1412
1413 00a28d71 Leszek Koltunski
    if( !mIsInMixupMode )
1414
      {
1415
      mMesh.setEffectAssociation(cubit,andAssociation,equAssociation);
1416
      }
1417
    else
1418
      {
1419
      mMesh.setEffectAssociation(cubit,andAssociation,cubit);
1420
      Static4D tmp = mObjectQuats[equAssociation];
1421
      mMixupModeQuats[cubit].set(tmp);
1422
      }
1423
    }
1424
1425 22d72239 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1426
1427
  private int numberOfDifferentColors(int[] table)
1428
    {
1429
    int ret=0;
1430
    int len = table.length;
1431
1432
    for(int i=0; i<len; i++)
1433
      {
1434
      boolean increase = true;
1435
1436
      for(int j=0; j<i; j++)
1437
        if( table[j]==table[i] )
1438
          {
1439
          increase = false;
1440
          break;
1441
          }
1442
1443
      if( increase ) ret++;
1444
      }
1445
1446
    return ret;
1447
    }
1448
1449 224c0ff1 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1450
1451 ea48a493 leszek
  private void restoreSti(String key, OperatingSystemInterface os)
1452
    {
1453
    mTextureBorderMultiplier = os.getFloat(key+"_border", 1.0f);
1454
    mTextureCornerMultiplier = os.getFloat(key+"_corner", 1.0f);
1455
    String colors = os.getString(key+"_colors", null);
1456
    boolean different = false;
1457
1458
    if( colors!=null ) different = restoreColors(colors,mColorTable);
1459
1460
    if( different || mTextureBorderMultiplier!=1.0f || mTextureCornerMultiplier!=1.0f )
1461
      {
1462
      createTexture(mTextureBorderMultiplier,mTextureCornerMultiplier);
1463
      setTexture();
1464
      mSolved.setPuzzleFaceColor(mColorTable);
1465 22d72239 leszek
1466
      int numOrig = numberOfDifferentColors(mOriginalColorTable);
1467
      int numNow  = numberOfDifferentColors(mColorTable);
1468
      mCurrentColorSchemeSubmittable = (numOrig==numNow);
1469 ea48a493 leszek
      }
1470
    }
1471 224c0ff1 leszek
1472 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1473
1474 79c7c950 Leszek Koltunski
  synchronized void restorePreferences(OperatingSystemInterface os)
1475 29b82486 Leszek Koltunski
    {
1476
    boolean error = false;
1477 8b5894af Leszek Koltunski
    String key = getShortName();
1478 29b82486 Leszek Koltunski
1479 a05b6e06 Leszek Koltunski
    for(int i=0; i<mNumCubits; i++)
1480 29b82486 Leszek Koltunski
      {
1481 a2122d42 leszek
      mQuatDebug[i] = mCubits[i].restorePreferences(key,os);
1482 29b82486 Leszek Koltunski
1483 a05b6e06 Leszek Koltunski
      if( mQuatDebug[i]>=0 && mQuatDebug[i]<mNumQuats )
1484 29b82486 Leszek Koltunski
        {
1485 3788d0cd Leszek Koltunski
        boolean result = mCubits[i].rotateCubit(mObjectQuats[mQuatDebug[i]],true);
1486 1f329dcc Leszek Koltunski
        if( !result ) debugQuat(mObjectQuats[mQuatDebug[i]],i,0,0,0,mQuatDebug[i],3);
1487 fbd18fc7 Leszek Koltunski
        }
1488 7cd287b9 Leszek Koltunski
      else { error = true; break; }
1489 fbd18fc7 Leszek Koltunski
      }
1490
1491 7cd287b9 Leszek Koltunski
    if( !error )
1492 fbd18fc7 Leszek Koltunski
      {
1493 7cd287b9 Leszek Koltunski
      recomputeFaceOffsets();
1494
1495
      for(int i=0; i<mNumCubits; i++)
1496 29b82486 Leszek Koltunski
        {
1497 7cd287b9 Leszek Koltunski
        if( mQuatDebug[i]>=0 && mQuatDebug[i]<mNumQuats )
1498
          {
1499
          mCubits[i].computeRotationRow();
1500 544c9224 leszek
          setCubitQuat(i,mQuatDebug[i]);
1501 7cd287b9 Leszek Koltunski
          }
1502
        else { error = true; break; }
1503 29b82486 Leszek Koltunski
        }
1504
      }
1505
1506
    if( error )
1507
      {
1508 a05b6e06 Leszek Koltunski
      for(int i=0; i<mNumCubits; i++)
1509 29b82486 Leszek Koltunski
        {
1510 a05b6e06 Leszek Koltunski
        mCubits[i].solve();
1511 544c9224 leszek
        setCubitQuat(i,0);
1512 29b82486 Leszek Koltunski
        }
1513
      }
1514 43668bcc leszek
1515 ea48a493 leszek
    restoreSti(key,os);
1516 29b82486 Leszek Koltunski
    }
1517
1518 224c0ff1 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1519
1520
  synchronized void restoreStickers(OperatingSystemInterface os)
1521
    {
1522
    String key = getShortName();
1523 ea48a493 leszek
    restoreSti(key,os);
1524 224c0ff1 leszek
    }
1525
1526 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1527
1528 79c7c950 Leszek Koltunski
  void savePreferences(OperatingSystemInterface os)
1529 29b82486 Leszek Koltunski
    {
1530 8b5894af Leszek Koltunski
    String key = getShortName();
1531 79c7c950 Leszek Koltunski
    for(int i=0; i<mNumCubits; i++) mCubits[i].savePreferences(key,os);
1532 9c7d220a leszek
1533
    os.putFloat(key+"_border", mTextureBorderMultiplier);
1534
    os.putFloat(key+"_corner", mTextureCornerMultiplier);
1535
    os.putString(key+"_colors", createColors(mColorTable) );
1536 29b82486 Leszek Koltunski
    }
1537
1538 ea739ec8 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1539
1540 79c7c950 Leszek Koltunski
  public void removePreferences(OperatingSystemInterface os)
1541 ea739ec8 Leszek Koltunski
    {
1542
    String key = getShortName();
1543 79c7c950 Leszek Koltunski
    for(int i=0; i<mNumCubits; i++) mCubits[i].removePreferences(key,os);
1544 9c7d220a leszek
1545
    os.remove(key+"_border");
1546
    os.remove(key+"_corner");
1547
    os.remove(key+"_colors");
1548
    }
1549
1550
///////////////////////////////////////////////////////////////////////////////////////////////////
1551
1552
  private String createColors(int[] table)
1553
    {
1554
    StringBuilder sb = new StringBuilder();
1555
    int len = table!=null ? table.length : 0;
1556
1557
    for(int i=0; i<len; i++)
1558
      {
1559
      sb.append(table[i]);
1560
      sb.append(',');
1561
      }
1562
1563
    return sb.toString();
1564 ea739ec8 Leszek Koltunski
    }
1565
1566 43668bcc leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1567
1568
  private boolean restoreColors(String colors, int[] table)
1569
    {
1570
    String[] parts = colors.split(",");
1571
    int len = parts.length;
1572
    boolean ret = false;
1573
1574
    try
1575
      {
1576
      for(int s=0; s<len; s++)
1577
        {
1578
        table[s] = Integer.parseInt(parts[s]);
1579
        if( table[s]!=mOriginalColorTable[s] ) ret = true;
1580
        }
1581
      }
1582
    catch(NumberFormatException nfe)
1583
      {
1584
      for(int s=0; s<len; s++) table[s] = mOriginalColorTable[s];
1585
      return false;
1586
      }
1587
1588
    return ret;
1589
    }
1590
1591 00f4980d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1592
1593 7e9a35eb leszek
  private float computeRadiusCorrection(float[][] sticker, int curr, int len)
1594 00f4980d Leszek Koltunski
    {
1595
    final float A = 0.8f;  // 0<A<1
1596
1597
    int prev = curr>0 ? curr-1 : len-1;
1598
    int next = curr<len-1 ? curr+1 : 0;
1599
1600 7e9a35eb leszek
    float v1x = sticker[prev][0]-sticker[curr][0];
1601
    float v1y = sticker[prev][1]-sticker[curr][1];
1602
    float v2x = sticker[next][0]-sticker[curr][0];
1603
    float v2y = sticker[next][1]-sticker[curr][1];
1604 00f4980d Leszek Koltunski
1605
    float len1= v1x*v1x+v1y*v1y;
1606
    float len2= v2x*v2x+v2y*v2y;
1607
1608
    float cos = (v1x*v2x+v1y*v2y) / ( (float)Math.sqrt(len1*len2) );
1609
1610
    return 1-A*cos;
1611
    }
1612
1613 b9c861cf Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1614
// Radius of the sphere circumscribed on the puzzle. Needed for pillowing.
1615
//
1616
// This won't work correctly for pillowing off-center puzzles (e.g. mirrors) - for those we'd need
1617
// to introduce the concept of a 'sink center' as well.
1618
//
1619
// public because needed in TouchControlShapemod
1620
1621
  public float getCircumscribedRadius()
1622
    {
1623
    switch(mNumPuzzleFaces)
1624
      {
1625
      case  4: return (SQ6/4)*mSize;
1626
      case  6: return (SQ3/2)*mSize;
1627
      case  8: return (SQ2/2)*mSize;
1628
      case 12: return (SQ3/2)*((SQ5+1)/2)*mSize;
1629 c1452814 Leszek Koltunski
      case 16: return 0.50f*mSize;
1630 b9c861cf Leszek Koltunski
      }
1631
1632
    return 0.0f;
1633
    }
1634
1635 e61a158a leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1636
// might be overridden in subclasses which want per-edge radii
1637
1638
  protected float[][][] getStickerRadii()
1639
    {
1640
    float radius = getStickerRadius();
1641
    int numStickers = mStickerCoords.length;
1642
    float[][][] ret = new float[numStickers][][];
1643
1644
    for(int s=0; s<numStickers; s++)
1645
      {
1646
      int numLoops = mStickerCoords[s].length;
1647
      ret[s] = new float[numLoops][];
1648
1649
      for(int l=0; l<numLoops; l++)
1650
        {
1651
        int numVertices = mStickerCoords[s][l].length;
1652
        ret[s][l] = new float[numVertices];
1653
        for(int v=0; v<numVertices; v++) ret[s][l][v] = radius;
1654
        }
1655
      }
1656
1657
    return ret;
1658
    }
1659
1660
///////////////////////////////////////////////////////////////////////////////////////////////////
1661
// might be overridden in subclasses which want per-edge strokes
1662
1663
  protected float[][][] getStickerStrokes()
1664
    {
1665
    float stroke = getStickerStroke();
1666
    int numStickers = mStickerCoords.length;
1667
    float[][][] ret = new float[numStickers][][];
1668
1669
    for(int s=0; s<numStickers; s++)
1670
      {
1671
      int numLoops = mStickerCoords[s].length;
1672
      ret[s] = new float[numLoops][];
1673
1674
      for(int l=0; l<numLoops; l++)
1675
        {
1676
        int numVertices = mStickerCoords[s][l].length;
1677
        ret[s][l] = new float[numVertices];
1678
        for(int v=0; v<numVertices; v++) ret[s][l][v] = stroke;
1679
        }
1680
      }
1681
1682
    return ret;
1683
    }
1684
1685 d53fb890 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1686
1687
  public ObjectSticker retSticker(int sticker)
1688
    {
1689
    if( mStickers==null )
1690
      {
1691 e61a158a leszek
      float[][][] radii   = getStickerRadii();
1692
      float[][][] strokes = getStickerStrokes();
1693
      float[][][] angles  = getStickerAngles();
1694 d53fb890 Leszek Koltunski
      int numStickers = mStickerCoords.length;
1695
      mStickers = new ObjectSticker[numStickers];
1696
1697
      for(int s=0; s<numStickers; s++)
1698
        {
1699 bc008758 Leszek Koltunski
        float scale = mStickerScales.length>s ? mStickerScales[s] : 1.0f;
1700 ebe8c08e leszek
        int numLoops = mStickerCoords[s].length;
1701 e61a158a leszek
        float[][] rad = new float[numLoops][];
1702
        float[][] str = new float[numLoops][];
1703 ebe8c08e leszek
1704
        for(int l=0; l<numLoops; l++)
1705
          {
1706
          int numVerts = mStickerCoords[s][l].length;
1707 e61a158a leszek
          rad[l] = new float[numVerts];
1708
          str[l] = new float[numVerts];
1709
          float[] st = strokes[s][l];
1710
          float[] ra = radii[s][l];
1711 ebe8c08e leszek
1712
          for(int v=0; v<numVerts; v++)
1713 e61a158a leszek
            {
1714
            rad[l][v] = ra[v] * computeRadiusCorrection(mStickerCoords[s][l],v,numVerts) / scale;
1715
            str[l][v] = st[v] / scale;
1716
            }
1717 ebe8c08e leszek
          }
1718
1719 e61a158a leszek
        mStickers[s] = new ObjectSticker(mStickerCoords[s], (angles==null ? null : angles[s]) ,rad, str);
1720 d53fb890 Leszek Koltunski
        }
1721
      }
1722
1723
    return mStickers[sticker];
1724
    }
1725
1726 3d766df3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1727 e3937019 Leszek Koltunski
// some objects (currently Kilominx,Ivy,Rex) might want to change the stickers.
1728 3d766df3 Leszek Koltunski
1729
  public void adjustStickerCoords()
1730
    {
1731
1732
    }
1733
1734 802fe251 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1735
1736
  public Static4D[] getQuats()
1737
    {
1738
    if( mObjectQuats==null )
1739
      {
1740
      mObjectQuats = QuatGroupGenerator.computeGroup(mAxis,mBasicAngles);
1741
      }
1742
1743
    return mObjectQuats;
1744
    }
1745
1746 40e77224 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1747
1748
  public int[][] getVariantFaceIsOuter()
1749
    {
1750
    return mVariantFaceIsOuter;
1751
    }
1752
1753 253e440f Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1754
1755
  public int getInternalColor()
1756
    {
1757
    return COLOR_INTERNAL;
1758
    }
1759
1760 43668bcc leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1761
1762
  public float getTextureBorders()
1763
    {
1764
    return mTextureBorderMultiplier;
1765
    }
1766
1767
///////////////////////////////////////////////////////////////////////////////////////////////////
1768
1769
  public float getTextureCorners()
1770
    {
1771
    return mTextureCornerMultiplier;
1772
    }
1773
1774 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1775 3a0a23bf Leszek Koltunski
// the getFaceColors + final INTERNAL_COLOR in a grid (so that we do not exceed the maximum texture size)
1776 29b82486 Leszek Koltunski
1777 43668bcc leszek
  void createTexture(float border, float corner)
1778 29b82486 Leszek Koltunski
    {
1779 7c111294 Leszek Koltunski
    Paint paint = new Paint();
1780 d5c71d02 Leszek Koltunski
    Canvas canvas = new Canvas(mBitmap);
1781 29b82486 Leszek Koltunski
1782 7c111294 Leszek Koltunski
    paint.setAntiAlias(true);
1783
    paint.setTextAlign(Paint.Align.CENTER);
1784
    paint.setStyle(Paint.Style.FILL);
1785 253e440f Leszek Koltunski
    paint.setColor(getInternalColor());
1786 f3eab97f leszek
    canvas.drawRect(0, 0, mNumTexCols*mTexHeight, mNumTexRows*mTexHeight, paint);
1787 7c111294 Leszek Koltunski
1788 43668bcc leszek
    mTextureBorderMultiplier = border;
1789
    mTextureCornerMultiplier = corner;
1790 6f5eb9b3 leszek
1791 43a4ccff Leszek Koltunski
    int texture = 0;
1792 7c111294 Leszek Koltunski
    FactorySticker factory = FactorySticker.getInstance();
1793
1794
    for(int row=0; row<mNumTexRows; row++)
1795
      for(int col=0; col<mNumTexCols; col++)
1796 29b82486 Leszek Koltunski
        {
1797 3a0a23bf Leszek Koltunski
        if( texture<mNumTextures-mNumOverrides )
1798
          {
1799
          ObjectSticker sticker = retSticker(texture/mNumFaceColors);
1800 962b8ff6 leszek
          int color = mColorTable[texture%mNumFaceColors];
1801 6f5eb9b3 leszek
          factory.drawRoundedPolygons( canvas, paint, col*mTexHeight, (mNumTexRows-row)*mTexHeight, color,
1802
                                       mTexHeight, sticker,mTextureBorderMultiplier,mTextureCornerMultiplier);
1803 3a0a23bf Leszek Koltunski
          }
1804 ff60e713 Leszek Koltunski
        else if( texture>mNumTextures-mNumOverrides && texture<=mNumTextures )
1805 3a0a23bf Leszek Koltunski
          {
1806 ff60e713 Leszek Koltunski
          int color = mStickerOverrides[mNumTextures-texture].getColor();
1807 f3eab97f leszek
          factory.drawSolidColor(canvas, paint, col*mTexHeight, (mNumTexRows-row)*mTexHeight, color, mTexHeight);
1808 3a0a23bf Leszek Koltunski
          }
1809 ff60e713 Leszek Koltunski
1810
        texture++;
1811 7e8750c9 leszek
        }
1812
    }
1813
1814
///////////////////////////////////////////////////////////////////////////////////////////////////
1815
1816 6f5eb9b3 leszek
  private void changeColorInTexture(int oldColor, int newColor)
1817 7e8750c9 leszek
    {
1818
    Paint paint = new Paint();
1819
    Canvas canvas = new Canvas(mBitmap);
1820
    paint.setAntiAlias(true);
1821
    int texture = 0;
1822
    FactorySticker factory = FactorySticker.getInstance();
1823
1824
    for(int row=0; row<mNumTexRows; row++)
1825
      for(int col=0; col<mNumTexCols; col++)
1826
        {
1827
        if( texture<mNumTextures-mNumOverrides )
1828
          {
1829 5ce579d2 leszek
          int color = mOriginalColorTable[texture%mNumFaceColors];
1830 7e8750c9 leszek
1831
          if( color==oldColor )
1832
            {
1833
            ObjectSticker sticker = retSticker(texture/mNumFaceColors);
1834 6f5eb9b3 leszek
            factory.drawRoundedPolygons( canvas, paint, col*mTexHeight, (mNumTexRows-row)*mTexHeight,
1835
                                         newColor, mTexHeight, sticker,mTextureBorderMultiplier,mTextureCornerMultiplier);
1836 7e8750c9 leszek
            }
1837
          }
1838
1839
        texture++;
1840 29b82486 Leszek Koltunski
        }
1841 d5c71d02 Leszek Koltunski
    }
1842
1843
///////////////////////////////////////////////////////////////////////////////////////////////////
1844
1845
  void setTexture()
1846
    {
1847 352bd362 leszek
    if( mBitmap==null )
1848
      {
1849
      mBitmap = Bitmap.createBitmap( mNumTexCols*mTexHeight, mNumTexRows*mTexHeight, Bitmap.Config.ARGB_4444);
1850 43668bcc leszek
      createTexture(mTextureBorderMultiplier,mTextureCornerMultiplier);
1851 352bd362 leszek
      }
1852 29b82486 Leszek Koltunski
1853 a0ccffb4 Leszek Koltunski
    if( !mTexture.setTextureAlreadyInverted(mBitmap) )
1854 7c111294 Leszek Koltunski
      {
1855
      int max = DistortedLibrary.getMaxTextureSize();
1856 32c1697e Leszek Koltunski
      mInterface.reportProblem("failed to set texture of size "+mBitmap.getWidth()+"x"+mBitmap.getHeight()+" max is "+max, true);
1857 29b82486 Leszek Koltunski
      }
1858
    }
1859
1860 ee6bb8d7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1861
1862 45e0065d Leszek Koltunski
  void setObjectRatioNow(float sc, int nodeSize)
1863 ee6bb8d7 Leszek Koltunski
    {
1864 64c209f5 Leszek Koltunski
    mObjectScreenRatio = sc;
1865 45e0065d Leszek Koltunski
    float scale = mObjectScreenRatio*mInitScreenRatio*nodeSize/mSize;
1866 ee6bb8d7 Leszek Koltunski
    mObjectScale.set(scale,scale,scale);
1867 23afe4c4 Leszek Koltunski
1868 11fa413d Leszek Koltunski
    if( mTouchControl ==null ) mTouchControl = getTouchControl();
1869 c9c71c3f Leszek Koltunski
    mTouchControl.setObjectRatio(mObjectScreenRatio*mInitScreenRatio);
1870 ee6bb8d7 Leszek Koltunski
    }
1871
1872 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1873
1874 45e0065d Leszek Koltunski
  void setObjectRatio(float sizeChange, int nodeSize)
1875 29b82486 Leszek Koltunski
    {
1876 7c111294 Leszek Koltunski
    mObjectScreenRatio *= (1.0f+sizeChange)/2;
1877 29b82486 Leszek Koltunski
1878 7c111294 Leszek Koltunski
    if( mObjectScreenRatio>MAX_SIZE_CHANGE) mObjectScreenRatio = MAX_SIZE_CHANGE;
1879
    if( mObjectScreenRatio<MIN_SIZE_CHANGE) mObjectScreenRatio = MIN_SIZE_CHANGE;
1880
1881 45e0065d Leszek Koltunski
    setObjectRatioNow(mObjectScreenRatio, nodeSize);
1882
    }
1883
1884
///////////////////////////////////////////////////////////////////////////////////////////////////
1885
1886
  void setNodeSize(int nodeSize)
1887
    {
1888
    setObjectRatioNow(mObjectScreenRatio, nodeSize);
1889 29b82486 Leszek Koltunski
    }
1890
1891 02d80fe6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1892
1893
  public float getRatio()
1894
    {
1895
    return mObjectScreenRatio;
1896
    }
1897
1898 11fa413d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1899
1900
  public float getObjectRatio()
1901
    {
1902
    return mObjectScreenRatio*mInitScreenRatio;
1903
    }
1904
1905 7c111294 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1906 29b82486 Leszek Koltunski
1907 880beeea Leszek Koltunski
  boolean isSolved()
1908 7c111294 Leszek Koltunski
    {
1909 5df97ecb leszek
    boolean solved = mSolved.isSolved(mCubits);
1910
    return mRotation.isSolved(solved);
1911 29b82486 Leszek Koltunski
    }
1912
1913 880beeea Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1914
// INTERNAL API - those are called from 'effects' package
1915 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1916
1917 880beeea Leszek Koltunski
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
1918 29b82486 Leszek Koltunski
    {
1919 a72a4b6a Leszek Koltunski
    mScrambler.randomizeNewScramble(scramble,rnd,curr,total, getSignature() );
1920 7c111294 Leszek Koltunski
    }
1921 29b82486 Leszek Koltunski
1922
///////////////////////////////////////////////////////////////////////////////////////////////////
1923
1924 880beeea Leszek Koltunski
  public Static4D getRotationQuat()
1925 59c20632 Leszek Koltunski
    {
1926
    return mQuat;
1927
    }
1928
1929
///////////////////////////////////////////////////////////////////////////////////////////////////
1930
1931
  public float getSize()
1932
    {
1933
    return mSize;
1934
    }
1935 7c111294 Leszek Koltunski
1936 2df35810 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1937
1938 826d293e Leszek Koltunski
  public void applyEffect(Effect effect, int position)
1939 2df35810 Leszek Koltunski
    {
1940
    mEffects.apply(effect, position);
1941
    }
1942
1943
///////////////////////////////////////////////////////////////////////////////////////////////////
1944
1945 826d293e Leszek Koltunski
  public void removeEffect(long effectID)
1946 2df35810 Leszek Koltunski
    {
1947
    mEffects.abortById(effectID);
1948
    }
1949
1950 3e9df6aa Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1951
1952 758b028d Leszek Koltunski
  public MeshBase getObjectMesh()
1953 3e9df6aa Leszek Koltunski
    {
1954
    return mMesh;
1955
    }
1956
1957 758b028d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1958
1959
  public DistortedEffects getObjectEffects()
1960
    {
1961
    return mEffects;
1962
    }
1963
1964 7aae846c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1965
1966
  public int getCubitType(int cubit)
1967
    {
1968
    return mCubits[cubit].getType();
1969
    }
1970
1971
///////////////////////////////////////////////////////////////////////////////////////////////////
1972
1973
  public float[] getCubitOffset(int cubit)
1974
    {
1975
    return mCubits[cubit].getOffset();
1976
    }
1977
1978 3a0a23bf Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1979
1980
  public ObjectStickerOverride[] getStickerOverrides()
1981
    {
1982
    return null;
1983
    }
1984
1985 3ce95490 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1986
1987
  public boolean getError()
1988
    {
1989
    return mError;
1990
    }
1991
1992
///////////////////////////////////////////////////////////////////////////////////////////////////
1993
1994
  public String getErrorString()
1995
    {
1996
    return mErrorString;
1997
    }
1998
1999 880beeea Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2000
// PUBLIC API
2001 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2002
2003 a1f8dc90 Leszek Koltunski
  public int getCubitFaceStickerIndex(int cubit, int face)
2004 29b82486 Leszek Koltunski
    {
2005 a1f8dc90 Leszek Koltunski
    Static4D texMap = mMesh.getTextureMap(mNumCubitFaces*cubit + face);
2006 29b82486 Leszek Koltunski
2007 880beeea Leszek Koltunski
    int x = (int)(texMap.get0()/texMap.get2());
2008
    int y = (int)(texMap.get1()/texMap.get3());
2009 29b82486 Leszek Koltunski
2010 f3eab97f leszek
    return (mNumTexRows-1-y)*mNumTexCols + x;
2011 29b82486 Leszek Koltunski
    }
2012
2013
///////////////////////////////////////////////////////////////////////////////////////////////////
2014
2015 a57e6870 Leszek Koltunski
  public int[] getNumLayers()
2016 29b82486 Leszek Koltunski
    {
2017 880beeea Leszek Koltunski
    return mNumLayers;
2018
    }
2019 29b82486 Leszek Koltunski
2020
///////////////////////////////////////////////////////////////////////////////////////////////////
2021
2022 880beeea Leszek Koltunski
  public synchronized void solve()
2023 29b82486 Leszek Koltunski
    {
2024 f557ecc4 leszek
    for(int i=0; i<mNumCubits; i++) mCubits[i].solve();
2025 7d2fe403 Leszek Koltunski
2026
    recomputeFaceOffsets();
2027
2028
    for(int i=0; i<mNumCubits; i++)
2029
      {
2030
      mCubits[i].computeRotationRow();
2031 544c9224 leszek
      setCubitQuat(i,0);
2032 880beeea Leszek Koltunski
      }
2033 29b82486 Leszek Koltunski
    }
2034
2035 57ef6378 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2036
2037
  public int getCubitQuatIndex(int cubit)
2038
    {
2039 05b0a7dd Leszek Koltunski
    return (cubit>=0 && cubit<mNumCubits) ? mCubits[cubit].mQuatIndex : 0;
2040 57ef6378 Leszek Koltunski
    }
2041
2042 92a6fc8b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2043
2044
  public int getCubitRotRow(int cubit, int axis)
2045
    {
2046 a05b6e06 Leszek Koltunski
    return mCubits[cubit].getRotRow(axis);
2047 92a6fc8b Leszek Koltunski
    }
2048
2049 d5c71d02 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2050
2051
  public Bitmap getStickerBitmap()
2052
    {
2053
    return mBitmap;
2054
    }
2055
2056 7ba38dd4 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2057
2058
  public DistortedNode getNode()
2059
    {
2060
    return mNode;
2061
    }
2062
2063 7af68038 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2064
2065
  public int getNumStickerTypes()
2066
    {
2067
    return mNumStickerTypes;
2068
    }
2069
2070 93743a22 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2071
2072
  public String reportState()
2073
    {
2074
    StringBuilder builder = new StringBuilder();
2075
2076
    for(int i=0; i<mNumCubits; i++ )
2077
      {
2078
      if( i>0 ) builder.append('.');
2079
      builder.append(mCubits[i].mQuatIndex);
2080
      }
2081
2082
    return builder.toString();
2083
    }
2084
2085 d66e98d7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2086 a0b0795b Leszek Koltunski
// this is here only so it can be overridden in TwistyJSON so that we can get this from JSON.
2087 d66e98d7 Leszek Koltunski
2088
  public int getNumCubitFaces()
2089
    {
2090
    return 0;
2091
    }
2092
2093 a0b0795b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2094
// 1.0 - i.e. no pillowing - by default.
2095
// The coeff is really param of the 'sink' vertex effect - if it is not equal to 1.0, we apply the
2096
// sink effect [centered at (0,0,0)] to the whole mesh as the last step of composing it.
2097
2098
  public float getPillowCoeff()
2099
    {
2100
    return 1.0f;
2101
    }
2102
2103 59c20632 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2104
2105 11fa413d Leszek Koltunski
  public TouchControl getTouchControl()
2106 59c20632 Leszek Koltunski
    {
2107 57ef6378 Leszek Koltunski
    if( mTouchControl==null )
2108 59c20632 Leszek Koltunski
      {
2109 11fa413d Leszek Koltunski
      switch(getTouchControlType())
2110 59c20632 Leszek Koltunski
        {
2111 cd2e8d4c Leszek Koltunski
        case TC_TETRAHEDRON      : mTouchControl = new TouchControlTetrahedron(this);
2112
                                   break;
2113
        case TC_HEXAHEDRON       : mTouchControl = new TouchControlHexahedron(this);
2114
                                   break;
2115
        case TC_OCTAHEDRON       : mTouchControl = new TouchControlOctahedron(this);
2116
                                   break;
2117
        case TC_DODECAHEDRON     : mTouchControl = new TouchControlDodecahedron(this);
2118
                                   break;
2119 5caf2641 Leszek Koltunski
        case TC_ICOSAHEDRON      : mTouchControl = new TouchControlIcosahedron(this);
2120
                                   break;
2121 cd2e8d4c Leszek Koltunski
        case TC_CUBOID           : int[] numLayers = getNumLayers();
2122
                                   mTouchControl = new TouchControlCuboids(this,getDist3D(numLayers));
2123
                                   break;
2124 5caf2641 Leszek Koltunski
        case TC_BALL             : mTouchControl = new TouchControlBall(this);
2125
                                   break;
2126 09d5cf2b leszek
        case TC_BARREL           : mTouchControl = new TouchControlBarrel(this);
2127
                                   break;
2128 cd2e8d4c Leszek Koltunski
        case TC_CHANGING_MIRROR  : mTouchControl = new TouchControlMirror(this);
2129
                                   break;
2130
        case TC_CHANGING_SQUARE  : mTouchControl = new TouchControlSquare(this);
2131
                                   break;
2132
        case TC_CHANGING_SHAPEMOD: mTouchControl = new TouchControlShapemod(this);
2133
                                   break;
2134 59c20632 Leszek Koltunski
        }
2135
      }
2136 c9c71c3f Leszek Koltunski
    return mTouchControl;
2137 59c20632 Leszek Koltunski
    }
2138
2139 fb1e9a31 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2140
2141
  public float[][] returnRotationFactor()
2142
    {
2143
    float[][] factor = new float[mNumAxis][];
2144
2145
    for(int ax=0; ax<mNumAxis; ax++)
2146
      {
2147
      int numL = mNumLayers[ax];
2148
      factor[ax] = new float[numL];
2149
      for(int la=0; la<numL; la++) factor[ax][la] = 1.0f;
2150
      }
2151
2152
    return factor;
2153
    }
2154
2155 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2156
2157 82eb152a Leszek Koltunski
  protected void setReader(JsonReader reader)
2158
    {
2159
    // empty
2160
    }
2161
2162 743cdab7 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
2163
2164
  public String getInventor()
2165
    {
2166 71df2bd4 leszek
    return mMetadata.getAuthor();
2167 743cdab7 leszek
    }
2168
2169
///////////////////////////////////////////////////////////////////////////////////////////////////
2170
2171
  public int getYearOfInvention()
2172
    {
2173
    return mMetadata.getYearOfInvention();
2174
    }
2175
2176
///////////////////////////////////////////////////////////////////////////////////////////////////
2177
2178
  public float getComplexity()
2179
    {
2180 71df2bd4 leszek
    return mMetadata.getDifficulty();
2181 743cdab7 leszek
    }
2182
2183
///////////////////////////////////////////////////////////////////////////////////////////////////
2184
2185
  public String getObjectName()
2186
    {
2187
    return mMetadata.getObjectName();
2188
    }
2189
2190 baa031e2 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
2191
2192
  public ObjectSignature getSignature()
2193
    {
2194
    return mMetadata.getSignature();
2195
    }
2196
2197 22d72239 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
2198
2199
  public boolean isSubmittable()
2200
    {
2201
    return mCurrentColorSchemeSubmittable;
2202
    }
2203
2204 82eb152a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2205 59c20632 Leszek Koltunski
  // for JSON only
2206 11fa413d Leszek Koltunski
  public abstract int getTouchControlType();
2207
  public abstract int getTouchControlSplit();
2208 59c20632 Leszek Koltunski
  public abstract boolean[][] getLayerRotatable(int[] numLayers);
2209
  public abstract int[][][] getEnabled();
2210
  public abstract float[] getDist3D(int[] numLayers);
2211 4c9ca251 Leszek Koltunski
  public abstract Static3D[] getFaceAxis();
2212 9ba7f3f6 Leszek Koltunski
  public abstract int[][] getScrambleEdges();
2213 7bbfc84f Leszek Koltunski
  public abstract float[][] getCuts(int[] numLayers);
2214 d53fb890 Leszek Koltunski
  public abstract float getStickerRadius();
2215
  public abstract float getStickerStroke();
2216 ebe8c08e leszek
  public abstract float[][][] getStickerAngles();
2217 e30c522a Leszek Koltunski
  public abstract int getCubitVariant(int cubit, int[] numLayers);
2218
  public abstract ObjectShape getObjectShape(int variant);
2219 3ee1d662 Leszek Koltunski
  public abstract ObjectFaceShape getObjectFaceShape(int variant);
2220 84a17011 Leszek Koltunski
  public abstract ObjectVertexEffects getVertexEffects(int variant);
2221 e30c522a Leszek Koltunski
  public abstract int getNumCubitVariants(int[] numLayers);
2222 7b832206 Leszek Koltunski
  public abstract float[][] getCubitPositions(int[] numLayers);
2223 d0e6cf7f Leszek Koltunski
  public abstract Static4D getCubitQuats(int cubit, int[] numLayers);
2224 82eb152a Leszek Koltunski
  public abstract float getScreenRatio();
2225 962b8ff6 leszek
  public abstract int[] getColorTable();
2226 5f54927b Leszek Koltunski
  public abstract String getShortName();
2227 7b832206 Leszek Koltunski
2228 a75ae1ee Leszek Koltunski
  // not only for JSON
2229 29b82486 Leszek Koltunski
  public abstract Static3D[] getRotationAxis();
2230 beee90ab Leszek Koltunski
  public abstract int[][] getBasicAngles();
2231 1eafa9c6 leszek
  public abstract int getNumPuzzleFaces();
2232 7ba38dd4 Leszek Koltunski
  public abstract int getFOV();
2233 052e0362 Leszek Koltunski
  public abstract String[][] getTutorials();
2234 29b82486 Leszek Koltunski
  }