Project

General

Profile

Download (11.8 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / object / Cubit.java @ e844c116

1 70b76549 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.object;
21
22
import android.content.SharedPreferences;
23
24
import org.distorted.library.effect.MatrixEffectMove;
25
import org.distorted.library.effect.MatrixEffectQuaternion;
26
import org.distorted.library.effect.MatrixEffectRotate;
27
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedNode;
29 b32444ee Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
30 70b76549 Leszek Koltunski
import org.distorted.library.message.EffectListener;
31
import org.distorted.library.type.Dynamic1D;
32
import org.distorted.library.type.Static1D;
33
import org.distorted.library.type.Static3D;
34
import org.distorted.library.type.Static4D;
35
import org.distorted.magic.RubikSurfaceView;
36
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38
39
class Cubit
40
  {
41
  private static final Static3D matrCenter = new Static3D(0,0,0);
42
43
  private final Static3D mOrigPosition;
44
45
  private RubikObject mParent;
46 b32444ee Leszek Koltunski
  private MeshBase mMesh;
47 70b76549 Leszek Koltunski
  private Static3D mRotationAxis;
48
  private MatrixEffectRotate mRotateEffect;
49 0e7bcfb1 Leszek Koltunski
  private Static3D mCurrentPosition;
50 e844c116 Leszek Koltunski
  private int mNumAxis;
51 70b76549 Leszek Koltunski
52
  Dynamic1D mRotationAngle;
53
  DistortedNode mNode;
54
  DistortedEffects mEffect;
55
  Static4D mQuatScramble;
56 10a2e360 Leszek Koltunski
  int[] mRotationRow;
57 70b76549 Leszek Koltunski
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
60
// correct the value of the 'scramble' quat to what it should be - one of the legal quats from the
61
// list LEGAL_QUATS.
62
//
63
// We also have to remember that the group of unit quaternions is a double-cover of rotations
64
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
65
66
  private void normalizeScrambleQuat(Static4D quat)
67
    {
68
    float x = quat.get0();
69
    float y = quat.get1();
70
    float z = quat.get2();
71
    float w = quat.get3();
72
    float diff;
73
74
    for(float legal: mParent.LEGAL_QUATS)
75
      {
76
      diff = x-legal;
77
      if( diff*diff<0.01f ) x = legal;
78
      diff = y-legal;
79
      if( diff*diff<0.01f ) y = legal;
80
      diff = z-legal;
81
      if( diff*diff<0.01f ) z = legal;
82
      diff = w-legal;
83
      if( diff*diff<0.01f ) w = legal;
84
      }
85
86
    if( w<0 )
87
      {
88
      w = -w;
89
      z = -z;
90
      y = -y;
91
      x = -x;
92
      }
93
    else if( w==0 )
94
      {
95
      if( z<0 )
96
        {
97
        z = -z;
98
        y = -y;
99
        x = -x;
100
        }
101
      else if( z==0 )
102
        {
103
        if( y<0 )
104
          {
105
          y = -y;
106
          x = -x;
107
          }
108
        else if( y==0 )
109
          {
110
          if( x<0 )
111
            {
112
            x = -x;
113
            }
114
          }
115
        }
116
      }
117
118
    quat.set(x,y,z,w);
119
    }
120
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122
123
  private int computeNearestAngle(float angle)
124
    {
125
    final int NEAREST = 90;
126
127
    int tmp = (int)((angle+NEAREST/2)/NEAREST);
128
    if( angle< -(NEAREST*0.5) ) tmp-=1;
129
130
    return NEAREST*tmp;
131
    }
132
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
135
  private void modifyCurrentPosition(Static3D currentPosition, Static4D quat)
136
    {
137
    float diff = 0.5f*(mParent.mSize-1);
138
    float cubitCenterX = currentPosition.get0() - diff;
139
    float cubitCenterY = currentPosition.get1() - diff;
140
    float cubitCenterZ = currentPosition.get2() - diff;
141
142
    Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
143
    Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
144
145
    float rotatedX = rotatedCenter.get0() + diff;
146
    float rotatedY = rotatedCenter.get1() + diff;
147
    float rotatedZ = rotatedCenter.get2() + diff;
148
149
    int roundedX = (int)(rotatedX+0.1f);
150
    int roundedY = (int)(rotatedY+0.1f);
151
    int roundedZ = (int)(rotatedZ+0.1f);
152
153
    currentPosition.set(roundedX, roundedY, roundedZ);
154 10a2e360 Leszek Koltunski
    computeRotationRow();
155
    }
156
157
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159 e844c116 Leszek Koltunski
// cast current position on axis; use mStart and mStep to compute the rotation row for each axis.
160 10a2e360 Leszek Koltunski
161
  private void computeRotationRow()
162
    {
163 e844c116 Leszek Koltunski
    float tmp;
164
    Static3D axis;
165
    float x = mCurrentPosition.get0();
166
    float y = mCurrentPosition.get1();
167
    float z = mCurrentPosition.get2();
168
169
    for(int i=0; i<mNumAxis; i++)
170
      {
171
      axis = mParent.ROTATION_AXIS[i];
172
      tmp = x*axis.get0() + y*axis.get1() + z*axis.get2();
173
      mRotationRow[i] = (int)( (tmp-mParent.mStart)/mParent.mStep + 0.5f );
174
      }
175 70b76549 Leszek Koltunski
    }
176
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178
179 b32444ee Leszek Koltunski
  Cubit(RubikObject parent, MeshBase mesh, Static3D position)
180 70b76549 Leszek Koltunski
    {
181
    float x = position.get0();
182
    float y = position.get1();
183
    float z = position.get2();
184
185 a10ada2a Leszek Koltunski
    float nc = parent.mSize*0.5f;
186 5ba13c05 Leszek Koltunski
    Static3D vector = new Static3D(x-nc+0.5f, y-nc+0.5f, z-nc+0.5f);
187 70b76549 Leszek Koltunski
188
    mParent          = parent;
189 b32444ee Leszek Koltunski
    mMesh            = mesh;
190 70b76549 Leszek Koltunski
    mOrigPosition    = new Static3D(x,y,z);
191
    mQuatScramble    = new Static4D(0,0,0,1);
192
    mRotationAngle   = new Dynamic1D();
193
    mRotationAxis    = new Static3D(1,0,0);
194
    mCurrentPosition = position;
195
    mRotateEffect    = new MatrixEffectRotate(mRotationAngle, mRotationAxis, matrCenter);
196
197 e844c116 Leszek Koltunski
    mNumAxis     = mParent.ROTATION_AXIS.length;
198
    mRotationRow = new int[mNumAxis];
199 10a2e360 Leszek Koltunski
    computeRotationRow();
200
201 36273130 Leszek Koltunski
    mEffect = new DistortedEffects();
202 70b76549 Leszek Koltunski
    mEffect.apply(mParent.mSinkEffect);
203
    mEffect.apply( new MatrixEffectMove(vector) );
204
    mEffect.apply( new MatrixEffectQuaternion(mQuatScramble, matrCenter));
205
    mEffect.apply(mRotateEffect);
206
    mEffect.apply(mParent.mQuatAEffect);
207
    mEffect.apply(mParent.mQuatCEffect);
208
    mEffect.apply(mParent.mScaleEffect);
209
210 b32444ee Leszek Koltunski
    mNode = new DistortedNode(mParent.mTexture,mEffect,mMesh);
211 70b76549 Leszek Koltunski
    }
212
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214
215
  void savePreferences(SharedPreferences.Editor editor)
216
    {
217
    String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
218
219
    editor.putFloat("qx_"+number, mQuatScramble.get0());
220
    editor.putFloat("qy_"+number, mQuatScramble.get1());
221
    editor.putFloat("qz_"+number, mQuatScramble.get2());
222
    editor.putFloat("qw_"+number, mQuatScramble.get3());
223
    }
224
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226
227
  void restorePreferences(SharedPreferences preferences)
228
    {
229
    String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
230
231
    float qx = preferences.getFloat("qx_"+number, 0.0f);
232
    float qy = preferences.getFloat("qy_"+number, 0.0f);
233
    float qz = preferences.getFloat("qz_"+number, 0.0f);
234
    float qw = preferences.getFloat("qw_"+number, 1.0f);
235
236
    mQuatScramble.set(qx,qy,qz,qw);
237
    modifyCurrentPosition( mCurrentPosition, mQuatScramble);
238
    }
239
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241
242
  long finishRotationNow(EffectListener listener)
243
    {
244
    int pointNum = mRotationAngle.getNumPoints();
245
246
    if( pointNum>=1 )
247
      {
248
      float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
249
      int nearestAngleInDegrees = computeNearestAngle(startingAngle);
250
      mParent.mRotationAngleStatic.set0(startingAngle);
251
      mParent.mRotationAngleFinal.set0(nearestAngleInDegrees);
252
      mParent.mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
253
      return setUpCallback(listener);
254
      }
255
256
    return 0;
257
    }
258
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
261 efef689c Leszek Koltunski
  Static4D returnRotationQuat(int axis)
262 70b76549 Leszek Koltunski
    {
263
    int pointNum = mRotationAngle.getNumPoints();
264
265
    if( pointNum>=1 )
266
      {
267 efef689c Leszek Koltunski
      float axisX = mParent.ROTATION_AXIS[axis].get0();
268
      float axisY = mParent.ROTATION_AXIS[axis].get1();
269
      float axisZ = mParent.ROTATION_AXIS[axis].get2();
270
271 70b76549 Leszek Koltunski
      float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
272
      int nearestAngleInDegrees = computeNearestAngle(startingAngle);
273
      double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
274
      float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
275
      float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
276 efef689c Leszek Koltunski
      return new Static4D( axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
277 70b76549 Leszek Koltunski
      }
278
279
    return null;
280
    }
281
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283
284
  void removeRotationNow(Static4D quat)
285
    {
286
    mRotationAngle.removeAll();
287
    mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
288
    normalizeScrambleQuat( mQuatScramble );
289
    modifyCurrentPosition( mCurrentPosition,quat);
290
    }
291
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293
// all DistortedTextures, DistortedNodes, DistortedFramebuffers, DistortedScreens and all types of
294
// Meshes HAVE TO be markedForDeletion when they are no longer needed- otherwise we have a major
295
// memory leak.
296
297
  void releaseResources()
298
    {
299 b32444ee Leszek Koltunski
    mMesh.markForDeletion();
300 70b76549 Leszek Koltunski
    mNode.markForDeletion();
301
    }
302
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304
305
  void solve()
306
    {
307
    mQuatScramble.set(0,0,0,1);
308
    mCurrentPosition.set(mOrigPosition);
309 0e7bcfb1 Leszek Koltunski
    computeRotationRow();
310 70b76549 Leszek Koltunski
    }
311
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313
314 efef689c Leszek Koltunski
  void beginNewRotation(int axis)
315 70b76549 Leszek Koltunski
    {
316 efef689c Leszek Koltunski
    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
317 70b76549 Leszek Koltunski
    mRotationAngle.add(mParent.mRotationAngleStatic);
318
    }
319
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321
322 efef689c Leszek Koltunski
  void addNewRotation(int axis, long durationMillis, int angle)
323 70b76549 Leszek Koltunski
    {
324 efef689c Leszek Koltunski
    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
325 70b76549 Leszek Koltunski
    mRotationAngle.setDuration(durationMillis);
326
    mRotationAngle.resetToBeginning();
327
    mRotationAngle.add(new Static1D(0));
328
    mRotationAngle.add(new Static1D(angle));
329
    }
330
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332
333
  long setUpCallback(EffectListener listener)
334
    {
335
    mRotateEffect.notifyWhenFinished(listener);
336
    return mRotateEffect.getID();
337
    }
338
}