Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
import org.distorted.library.mesh.MeshCubes;
30
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
  private MeshCubes mCube;
47
  private Static3D mRotationAxis;
48
  private MatrixEffectRotate mRotateEffect;
49

    
50
  Dynamic1D mRotationAngle;
51
  Static3D mCurrentPosition;
52
  DistortedNode mNode;
53
  DistortedEffects mEffect;
54
  Static4D mQuatScramble;
55

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
58
// correct the value of the 'scramble' quat to what it should be - one of the legal quats from the
59
// list LEGAL_QUATS.
60
//
61
// We also have to remember that the group of unit quaternions is a double-cover of rotations
62
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
63

    
64
  private void normalizeScrambleQuat(Static4D quat)
65
    {
66
    float x = quat.get0();
67
    float y = quat.get1();
68
    float z = quat.get2();
69
    float w = quat.get3();
70
    float diff;
71

    
72
    for(float legal: mParent.LEGAL_QUATS)
73
      {
74
      diff = x-legal;
75
      if( diff*diff<0.01f ) x = legal;
76
      diff = y-legal;
77
      if( diff*diff<0.01f ) y = legal;
78
      diff = z-legal;
79
      if( diff*diff<0.01f ) z = legal;
80
      diff = w-legal;
81
      if( diff*diff<0.01f ) w = legal;
82
      }
83

    
84
    if( w<0 )
85
      {
86
      w = -w;
87
      z = -z;
88
      y = -y;
89
      x = -x;
90
      }
91
    else if( w==0 )
92
      {
93
      if( z<0 )
94
        {
95
        z = -z;
96
        y = -y;
97
        x = -x;
98
        }
99
      else if( z==0 )
100
        {
101
        if( y<0 )
102
          {
103
          y = -y;
104
          x = -x;
105
          }
106
        else if( y==0 )
107
          {
108
          if( x<0 )
109
            {
110
            x = -x;
111
            }
112
          }
113
        }
114
      }
115

    
116
    quat.set(x,y,z,w);
117
    }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
  private int computeNearestAngle(float angle)
122
    {
123
    final int NEAREST = 90;
124

    
125
    int tmp = (int)((angle+NEAREST/2)/NEAREST);
126
    if( angle< -(NEAREST*0.5) ) tmp-=1;
127

    
128
    return NEAREST*tmp;
129
    }
130

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132

    
133
  private void modifyCurrentPosition(Static3D currentPosition, Static4D quat)
134
    {
135
    float diff = 0.5f*(mParent.mSize-1);
136
    float cubitCenterX = currentPosition.get0() - diff;
137
    float cubitCenterY = currentPosition.get1() - diff;
138
    float cubitCenterZ = currentPosition.get2() - diff;
139

    
140
    Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
141
    Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
142

    
143
    float rotatedX = rotatedCenter.get0() + diff;
144
    float rotatedY = rotatedCenter.get1() + diff;
145
    float rotatedZ = rotatedCenter.get2() + diff;
146

    
147
    int roundedX = (int)(rotatedX+0.1f);
148
    int roundedY = (int)(rotatedY+0.1f);
149
    int roundedZ = (int)(rotatedZ+0.1f);
150

    
151
    currentPosition.set(roundedX, roundedY, roundedZ);
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  Cubit(RubikObject parent, MeshCubes mesh, Static3D position)
157
    {
158
    float x = position.get0();
159
    float y = position.get1();
160
    float z = position.get2();
161

    
162
    float nc = parent.mSize*0.5f;
163
    int TS = RubikObject.TEXTURE_SIZE;
164
    Static3D vector = new Static3D(TS*(x-nc), TS*(y-nc), TS*(z-nc));
165

    
166
    mParent          = parent;
167
    mCube            = mesh;
168
    mOrigPosition    = new Static3D(x,y,z);
169
    mQuatScramble    = new Static4D(0,0,0,1);
170
    mRotationAngle   = new Dynamic1D();
171
    mRotationAxis    = new Static3D(1,0,0);
172
    mCurrentPosition = position;
173
    mRotateEffect    = new MatrixEffectRotate(mRotationAngle, mRotationAxis, matrCenter);
174

    
175
    mEffect = new DistortedEffects();
176
    mEffect.apply(mParent.mSinkEffect);
177
    mEffect.apply( new MatrixEffectMove(vector) );
178
    mEffect.apply( new MatrixEffectQuaternion(mQuatScramble, matrCenter));
179
    mEffect.apply(mRotateEffect);
180
    mEffect.apply(mParent.mQuatAEffect);
181
    mEffect.apply(mParent.mQuatCEffect);
182
    mEffect.apply(mParent.mScaleEffect);
183
    mEffect.apply(mParent.mMoveEffect);
184

    
185
    mNode = new DistortedNode(mParent.mTexture,mEffect,mCube);
186
    }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

    
190
  void savePreferences(SharedPreferences.Editor editor)
191
    {
192
    String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
193

    
194
    editor.putFloat("qx_"+number, mQuatScramble.get0());
195
    editor.putFloat("qy_"+number, mQuatScramble.get1());
196
    editor.putFloat("qz_"+number, mQuatScramble.get2());
197
    editor.putFloat("qw_"+number, mQuatScramble.get3());
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
  void restorePreferences(SharedPreferences preferences)
203
    {
204
    String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
205

    
206
    float qx = preferences.getFloat("qx_"+number, 0.0f);
207
    float qy = preferences.getFloat("qy_"+number, 0.0f);
208
    float qz = preferences.getFloat("qz_"+number, 0.0f);
209
    float qw = preferences.getFloat("qw_"+number, 1.0f);
210

    
211
    mQuatScramble.set(qx,qy,qz,qw);
212
    modifyCurrentPosition( mCurrentPosition, mQuatScramble);
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

    
217
  long finishRotationNow(EffectListener listener)
218
    {
219
    int pointNum = mRotationAngle.getNumPoints();
220

    
221
    if( pointNum>=1 )
222
      {
223
      float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
224
      int nearestAngleInDegrees = computeNearestAngle(startingAngle);
225
      mParent.mRotationAngleStatic.set0(startingAngle);
226
      mParent.mRotationAngleFinal.set0(nearestAngleInDegrees);
227
      mParent.mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
228
      return setUpCallback(listener);
229
      }
230

    
231
    return 0;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  Static4D returnRotationQuat(float qx,float qy,float qz)
237
    {
238
    int pointNum = mRotationAngle.getNumPoints();
239

    
240
    if( pointNum>=1 )
241
      {
242
      float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
243
      int nearestAngleInDegrees = computeNearestAngle(startingAngle);
244
      double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
245
      float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
246
      float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
247
      return new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
248
      }
249

    
250
    return null;
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  void removeRotationNow(Static4D quat)
256
    {
257
    mRotationAngle.removeAll();
258
    mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
259
    normalizeScrambleQuat( mQuatScramble );
260
    modifyCurrentPosition( mCurrentPosition,quat);
261
    }
262

    
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264
// all DistortedTextures, DistortedNodes, DistortedFramebuffers, DistortedScreens and all types of
265
// Meshes HAVE TO be markedForDeletion when they are no longer needed- otherwise we have a major
266
// memory leak.
267

    
268
  void releaseResources()
269
    {
270
    mCube.markForDeletion();
271
    mNode.markForDeletion();
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  void solve()
277
    {
278
    mQuatScramble.set(0,0,0,1);
279
    mCurrentPosition.set(mOrigPosition);
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

    
284
  void beginNewRotation(Static3D axis)
285
    {
286
    mRotationAxis.set(axis);
287
    mRotationAngle.add(mParent.mRotationAngleStatic);
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  void addNewRotation(Static3D axis, long durationMillis, int angle)
293
    {
294
    mRotationAxis.set(axis);
295
    mRotationAngle.setDuration(durationMillis);
296
    mRotationAngle.resetToBeginning();
297
    mRotationAngle.add(new Static1D(0));
298
    mRotationAngle.add(new Static1D(angle));
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

    
303
  long setUpCallback(EffectListener listener)
304
    {
305
    mRotateEffect.notifyWhenFinished(listener);
306
    return mRotateEffect.getID();
307
    }
308
}
(1-1/6)