Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObject.java @ 224c0ff1

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