Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObject.java @ 1eafa9c6

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