Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikHelicopter.java @ 475cbfe7

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 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.objects;
21

    
22
import android.content.res.Resources;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.library.effect.MatrixEffectQuaternion;
27
import org.distorted.library.effect.VertexEffectDeform;
28
import org.distorted.library.effect.VertexEffectMove;
29
import org.distorted.library.effect.VertexEffectRotate;
30
import org.distorted.library.effect.VertexEffectScale;
31
import org.distorted.library.main.DistortedEffects;
32
import org.distorted.library.main.DistortedTexture;
33
import org.distorted.library.mesh.MeshBase;
34
import org.distorted.library.mesh.MeshJoined;
35
import org.distorted.library.mesh.MeshPolygon;
36
import org.distorted.library.mesh.MeshSquare;
37
import org.distorted.library.mesh.MeshTriangle;
38
import org.distorted.library.type.Static1D;
39
import org.distorted.library.type.Static3D;
40
import org.distorted.library.type.Static4D;
41
import org.distorted.main.RubikSurfaceView;
42

    
43
import java.util.Random;
44

    
45
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
public class RubikHelicopter extends RubikObject
50
{
51
  private static final float SQ2 = (float)Math.sqrt(2);
52
  private static final float SQ3 = (float)Math.sqrt(3);
53

    
54
  private static final int FACES_PER_CUBIT =6;
55

    
56
  // the six rotation axis of a Helicopter. Must be normalized.
57
  static final Static3D[] ROT_AXIS = new Static3D[]
58
         {
59
           new Static3D(     0, +SQ2/2, -SQ2/2),
60
           new Static3D(     0, -SQ2/2, -SQ2/2),
61
           new Static3D(+SQ2/2,      0, -SQ2/2),
62
           new Static3D(-SQ2/2,      0, -SQ2/2),
63
           new Static3D(+SQ2/2, -SQ2/2,      0),
64
           new Static3D(-SQ2/2, -SQ2/2,      0)
65
         };
66

    
67
  // the six axis that determine the faces
68
  static final Static3D[] FACE_AXIS = new Static3D[]
69
         {
70
           new Static3D(1,0,0), new Static3D(-1,0,0),
71
           new Static3D(0,1,0), new Static3D(0,-1,0),
72
           new Static3D(0,0,1), new Static3D(0,0,-1)
73
         };
74

    
75
  private static final int[] FACE_COLORS = new int[]
76
         {
77
           0xffffff00, 0xffffffff,   // FACE_AXIS[0] (right-YELLOW) FACE_AXIS[1] (left  -WHITE)
78
           0xff0000ff, 0xff00ff00,   // FACE_AXIS[2] (top  -BLUE  ) FACE_AXIS[3] (bottom-GREEN)
79
           0xffff0000, 0xffb5651d    // FACE_AXIS[4] (front-RED   ) FACE_AXIS[5] (back  -BROWN)
80
         };
81

    
82
  // All legal rotation quats of a HELICOPTER (same as the Cube!)
83
  private static final Static4D[] QUATS = new Static4D[]
84
         {
85
           new Static4D( 0.00f,  0.00f,  0.00f,  1.00f ),
86
           new Static4D( 1.00f,  0.00f,  0.00f,  0.00f ),
87
           new Static4D( 0.00f,  1.00f,  0.00f,  0.00f ),
88
           new Static4D( 0.00f,  0.00f,  1.00f,  0.00f ),
89

    
90
           new Static4D( SQ2/2,  SQ2/2,  0.00f,  0.00f ),
91
           new Static4D( SQ2/2, -SQ2/2,  0.00f,  0.00f ),
92
           new Static4D( SQ2/2,  0.00f,  SQ2/2,  0.00f ),
93
           new Static4D( SQ2/2,  0.00f, -SQ2/2,  0.00f ),
94
           new Static4D( SQ2/2,  0.00f,  0.00f,  SQ2/2 ),
95
           new Static4D( SQ2/2,  0.00f,  0.00f, -SQ2/2 ),
96
           new Static4D( 0.00f,  SQ2/2,  SQ2/2,  0.00f ),
97
           new Static4D( 0.00f,  SQ2/2, -SQ2/2,  0.00f ),
98
           new Static4D( 0.00f,  SQ2/2,  0.00f,  SQ2/2 ),
99
           new Static4D( 0.00f,  SQ2/2,  0.00f, -SQ2/2 ),
100
           new Static4D( 0.00f,  0.00f,  SQ2/2,  SQ2/2 ),
101
           new Static4D( 0.00f,  0.00f,  SQ2/2, -SQ2/2 ),
102

    
103
           new Static4D( 0.50f,  0.50f,  0.50f,  0.50f ),
104
           new Static4D( 0.50f,  0.50f,  0.50f, -0.50f ),
105
           new Static4D( 0.50f,  0.50f, -0.50f,  0.50f ),
106
           new Static4D( 0.50f,  0.50f, -0.50f, -0.50f ),
107
           new Static4D( 0.50f, -0.50f,  0.50f,  0.50f ),
108
           new Static4D( 0.50f, -0.50f,  0.50f, -0.50f ),
109
           new Static4D( 0.50f, -0.50f, -0.50f,  0.50f ),
110
           new Static4D( 0.50f, -0.50f, -0.50f, -0.50f )
111
         };
112

    
113
  private static final float DIST_CORNER = 0.50f;
114
  private static final float DIST_CENTER = 0.50f;
115
  private static final float XY_CENTER   = DIST_CORNER/3;
116

    
117
  // centers of the 8 corners + 6*4 face triangles ( i.e. of the all 32 cubits)
118
  private static final Static3D[] CENTERS = new Static3D[]
119
         {
120
           new Static3D(   DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
121
           new Static3D(   DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
122
           new Static3D(   DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
123
           new Static3D(   DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
124
           new Static3D(  -DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
125
           new Static3D(  -DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
126
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
127
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
128

    
129
           new Static3D(   DIST_CENTER,     XY_CENTER,     XY_CENTER ),
130
           new Static3D(   DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
131
           new Static3D(   DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
132
           new Static3D(   DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
133

    
134
           new Static3D(  -DIST_CENTER,     XY_CENTER,     XY_CENTER ),
135
           new Static3D(  -DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
136
           new Static3D(  -DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
137
           new Static3D(  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
138

    
139
           new Static3D(   XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
140
           new Static3D(   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
141
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
142
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
143

    
144
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
145
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
146
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
147
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
148

    
149
           new Static3D(   XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
150
           new Static3D(   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
151
           new Static3D(  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
152
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
153

    
154
           new Static3D(   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
155
           new Static3D(   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
156
           new Static3D(  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
157
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
158
         };
159

    
160
  // Colors of the faces of cubits. Each cubit has 6 faces
161
  private static final int[][] mFaceMap = new int[][]
162
         {
163
           { 4,2,0, 6,6,6 },
164
           { 0,2,5, 6,6,6 },
165
           { 4,0,3, 6,6,6 },
166
           { 5,3,0, 6,6,6 },
167
           { 1,2,4, 6,6,6 },
168
           { 5,2,1, 6,6,6 },
169
           { 4,3,1, 6,6,6 },
170
           { 1,3,5, 6,6,6 },
171

    
172
           { 0 , 6,6,6,6,6 },
173
           { 0 , 6,6,6,6,6 },
174
           { 0 , 6,6,6,6,6 },
175
           { 0 , 6,6,6,6,6 },
176

    
177
           { 1 , 6,6,6,6,6 },
178
           { 1 , 6,6,6,6,6 },
179
           { 1 , 6,6,6,6,6 },
180
           { 1 , 6,6,6,6,6 },
181

    
182
           { 2 , 6,6,6,6,6 },
183
           { 2 , 6,6,6,6,6 },
184
           { 2 , 6,6,6,6,6 },
185
           { 2 , 6,6,6,6,6 },
186

    
187
           { 3 , 6,6,6,6,6 },
188
           { 3 , 6,6,6,6,6 },
189
           { 3 , 6,6,6,6,6 },
190
           { 3 , 6,6,6,6,6 },
191

    
192
           { 4 , 6,6,6,6,6 },
193
           { 4 , 6,6,6,6,6 },
194
           { 4 , 6,6,6,6,6 },
195
           { 4 , 6,6,6,6,6 },
196

    
197
           { 5 , 6,6,6,6,6 },
198
           { 5 , 6,6,6,6,6 },
199
           { 5 , 6,6,6,6,6 },
200
           { 5 , 6,6,6,6,6 },
201
         };
202

    
203
  private static int[] QUAT_INDICES =
204
      { 0,13,14,1,12,2,3,7,20,6,13,17,7,23,18,12,22,10,8,16,11,21,19,9,3,15,14,0,5,2,1,4 };
205

    
206
  private static MeshBase mCornerMesh, mFaceMesh;
207

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209

    
210
  RubikHelicopter(int size, Static4D quat, DistortedTexture texture,
211
                  MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
212
    {
213
    super(size, 60, quat, texture, mesh, effects, moves, RubikObjectList.HELI, res, scrWidth);
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

    
218
  private void createCornerMesh()
219
    {
220
    float D = 0.02f;
221
    float E = 0.5f;
222
    float F = SQ2/4;
223

    
224
    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
225

    
226
    float[] bands0 = { 1.0f    , 0,
227
                       1.0f-2*D, D*0.25f,
228
                       1.0f-4*D, D*0.35f,
229
                       1.0f-8*D, D*0.6f,
230
                       0.60f   , D*1.0f,
231
                       0.30f   , D*1.375f,
232
                       0.0f    , D*1.4f };
233

    
234
    MeshBase[] meshes = new MeshBase[6];
235

    
236
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
237
    meshes[0].setEffectAssociation(0,1,0);
238
    meshes[1] = meshes[0].copy(true);
239
    meshes[1].setEffectAssociation(0,2,0);
240
    meshes[2] = meshes[0].copy(true);
241
    meshes[2].setEffectAssociation(0,4,0);
242

    
243
    float[] vertices1 = { -F,-1.0f/12, +F,-1.0f/12, 0,1.0f/6 };
244
    float[] bands1 = { 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f };
245

    
246
    meshes[3] = new MeshPolygon(vertices1,bands1,1,5);
247
    meshes[3].setEffectAssociation(0,8,0);
248
    meshes[4] = meshes[3].copy(true);
249
    meshes[4].setEffectAssociation(0,16,0);
250
    meshes[5] = meshes[3].copy(true);
251
    meshes[5].setEffectAssociation(0,32,0);
252

    
253
    mCornerMesh = new MeshJoined(meshes);
254

    
255
    Static3D axisX  = new Static3D(1,0,0);
256
    Static3D axisY  = new Static3D(0,1,0);
257
    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
258
    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
259
    Static1D angle1 = new Static1D(+90);
260
    Static1D angle2 = new Static1D(-90);
261
    Static1D angle3 = new Static1D(-135);
262
    Static1D angle4 = new Static1D(90);
263
    Static1D angle5 = new Static1D(120);
264
    Static1D angle6 = new Static1D(240);
265
    Static3D center1= new Static3D(0,0,0);
266
    Static3D center2= new Static3D(-0.25f,-0.25f,-0.25f);
267
    Static3D move1  = new Static3D(-E/4,-E/4,0);
268
    Static3D move2  = new Static3D(-0.25f,(-1.0f/6)-0.25f,-0.25f);
269

    
270
    float d0 =-0.04f;
271
    float d1 = 0.04f;
272
    float r0 = 0.15f;
273
    float r1 = 0.10f;
274

    
275
    Static3D vec0   = new Static3D(d0*(+SQ3/3),d0*(+SQ3/3),d0*(+SQ3/3));
276
    Static3D vec1   = new Static3D(d1*(+SQ3/3),d1*(-SQ3/3),d1*(-SQ3/3));
277
    Static3D vec2   = new Static3D(d1*(-SQ3/3),d1*(+SQ3/3),d1*(-SQ3/3));
278
    Static3D vec3   = new Static3D(d1*(-SQ3/3),d1*(-SQ3/3),d1*(+SQ3/3));
279

    
280
    Static1D radius = new Static1D(0.5f);
281

    
282
    Static3D cent0  = new Static3D( 0.0f, 0.0f, 0.0f);
283
    Static3D cent1  = new Static3D(-0.5f, 0.0f, 0.0f);
284
    Static3D cent2  = new Static3D( 0.0f,-0.5f, 0.0f);
285
    Static3D cent3  = new Static3D( 0.0f, 0.0f,-0.5f);
286

    
287
    Static4D reg0   = new Static4D(0,0,0,r0);
288
    Static4D reg1   = new Static4D(0,0,0,r1);
289

    
290
    VertexEffectMove   effect0 = new VertexEffectMove(move1);
291
    VertexEffectScale  effect1 = new VertexEffectScale(new Static3D(1,1,-1));
292
    VertexEffectRotate effect2 = new VertexEffectRotate(angle1,axisX,center1);
293
    VertexEffectRotate effect3 = new VertexEffectRotate(angle2,axisY,center1);
294
    VertexEffectMove   effect4 = new VertexEffectMove(move2);
295
    VertexEffectRotate effect5 = new VertexEffectRotate(angle1,axisX,center2);
296
    VertexEffectRotate effect6 = new VertexEffectRotate(angle3,axisY,center2);
297
    VertexEffectRotate effect7 = new VertexEffectRotate(angle4,axis0,center2);
298
    VertexEffectRotate effect8 = new VertexEffectRotate(angle5,axis1,center2);
299
    VertexEffectRotate effect9 = new VertexEffectRotate(angle6,axis1,center2);
300

    
301
    VertexEffectDeform effect10= new VertexEffectDeform(vec0,radius,cent0,reg0);
302
    VertexEffectDeform effect11= new VertexEffectDeform(vec1,radius,cent1,reg1);
303
    VertexEffectDeform effect12= new VertexEffectDeform(vec2,radius,cent2,reg1);
304
    VertexEffectDeform effect13= new VertexEffectDeform(vec3,radius,cent3,reg1);
305

    
306
    effect0.setMeshAssociation( 7,-1);  // meshes 0,1,2
307
    effect1.setMeshAssociation( 6,-1);  // meshes 1,2
308
    effect2.setMeshAssociation( 2,-1);  // mesh 1
309
    effect3.setMeshAssociation( 4,-1);  // mesh 2
310
    effect4.setMeshAssociation(56,-1);  // meshes 3,4,5
311
    effect5.setMeshAssociation(56,-1);  // meshes 3,4,5
312
    effect6.setMeshAssociation(56,-1);  // meshes 3,4,5
313
    effect7.setMeshAssociation(56,-1);  // meshes 3,4,5
314
    effect8.setMeshAssociation(16,-1);  // mesh 4
315
    effect9.setMeshAssociation(32,-1);  // mesh 5
316

    
317
    effect10.setMeshAssociation(63,-1); // all meshes
318
    effect11.setMeshAssociation(63,-1); // all meshes
319
    effect12.setMeshAssociation(63,-1); // all meshes
320
    effect13.setMeshAssociation(63,-1); // all meshes
321

    
322
    mCornerMesh.apply(effect0);
323
    mCornerMesh.apply(effect1);
324
    mCornerMesh.apply(effect2);
325
    mCornerMesh.apply(effect3);
326
    mCornerMesh.apply(effect4);
327
    mCornerMesh.apply(effect5);
328
    mCornerMesh.apply(effect6);
329
    mCornerMesh.apply(effect7);
330
    mCornerMesh.apply(effect8);
331
    mCornerMesh.apply(effect9);
332

    
333
    mCornerMesh.apply(effect10);
334
    mCornerMesh.apply(effect11);
335
    mCornerMesh.apply(effect12);
336
    mCornerMesh.apply(effect13);
337

    
338
    mCornerMesh.mergeEffComponents();
339
    }
340

    
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342

    
343
  private void createFaceMesh()
344
    {
345
    MeshBase[] meshes = new MeshBase[6];
346

    
347
    float D = 0.02f;
348
    float E = 0.5f;
349
    float F = SQ2/4;
350
    float G = 1.0f/12;
351

    
352
    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
353

    
354
    float[] bands0 = { 1.0f    , 0,
355
                       1.0f-2*D, D*0.25f,
356
                       1.0f-4*D, D*0.35f,
357
                       1.0f-8*D, D*0.6f,
358
                       0.60f   , D*1.0f,
359
                       0.30f   , D*1.375f,
360
                       0.0f    , D*1.4f };
361

    
362
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
363
    meshes[0].setEffectAssociation(0,1,0);
364

    
365
    float[] vertices1 = { -F,-G, +F,-G, 0,2*G};
366

    
367
    float[] bands1 = { 1.0f   , 0.0f,
368
                       0.5f   , 0.01f,
369
                       0.0f   , 0.01f };
370

    
371
    meshes[1] = new MeshPolygon(vertices1, bands1, 1, 3);
372
    meshes[1].setEffectAssociation(0,2,0);
373

    
374
    float[] vertices2 = { -E/2,-F/3, +E/2,-F/3, 0,2*F/3};
375

    
376
    float[] bands2 = { 1.0f   , 0.0f,
377
                       0.5f   , 0.01f,
378
                       0.0f   , 0.01f };
379

    
380
    meshes[2] = new MeshPolygon(vertices2, bands2, 1, 3);
381
    meshes[2].setEffectAssociation(0,4,0);
382
    meshes[3] = meshes[2].copy(true);
383
    meshes[3].setEffectAssociation(0,8,0);
384
    meshes[4] = new MeshTriangle(1);
385
    meshes[4].setEffectAssociation(0,16,0);
386
    meshes[5] = new MeshTriangle(1);
387
    meshes[5].setEffectAssociation(0,32,0);
388

    
389
    mFaceMesh = new MeshJoined(meshes);
390

    
391
    Static3D move0  = new Static3D(-1.0f/8, -1.0f/8, 0);
392
    Static3D move1  = new Static3D(-(SQ2/24)-1.0f/4, -(SQ2/24)-1.0f/4, 0);
393
    Static3D move2  = new Static3D(-E/2, F/3, 0);
394
    Static3D move3  = new Static3D(+E/2, F/3, 0);
395
    Static3D move4  = new Static3D(+E/3,+E/3, 0);
396
    Static1D angle1 = new Static1D(135);
397
    Static1D angle2 = new Static1D(90);
398
    Static1D angle3 = new Static1D(-90);
399
    Static1D angle4 = new Static1D(-135);
400
    Static3D axisX  = new Static3D(1,0,0);
401
    Static3D axisY  = new Static3D(0,1,0);
402
    Static3D axisZ  = new Static3D(0,0,1);
403
    Static3D axis1  = new Static3D(1,-1,0);
404
    Static3D center = new Static3D(0,0,0);
405
    Static3D center1= new Static3D(-0.25f,-0.25f,0);
406

    
407
    float d0 =-0.03f;
408
    float d1 =-0.04f;
409
    float r0 = 0.15f;
410
    float r1 = 0.10f;
411

    
412
    Static3D vec0   = new Static3D(d0*(+SQ3/3),d0*(+SQ3/3),d0*(+SQ3/3));
413
    Static3D vec1   = new Static3D(d1*(-SQ3/3),d1*(+SQ3/3),d1*(+SQ3/3));
414
    Static3D vec2   = new Static3D(d1*(+SQ3/3),d1*(-SQ3/3),d1*(+SQ3/3));
415

    
416
    Static1D radius = new Static1D(0.5f);
417

    
418
    Static3D cent0  = new Static3D( 0.0f, 0.0f, 0.0f);
419
    Static3D cent1  = new Static3D(-0.5f, 0.0f, 0.0f);
420
    Static3D cent2  = new Static3D( 0.0f,-0.5f, 0.0f);
421

    
422
    Static4D reg0   = new Static4D(0,0,0,r0);
423
    Static4D reg1   = new Static4D(0,0,0,r1);
424

    
425
    VertexEffectMove   effect0 = new VertexEffectMove(move0);
426
    VertexEffectRotate effect1 = new VertexEffectRotate(angle1, axisZ, center);
427
    VertexEffectMove   effect2 = new VertexEffectMove(move1);
428
    VertexEffectRotate effect3 = new VertexEffectRotate(angle2, axis1, center1);
429
    VertexEffectMove   effect4 = new VertexEffectMove(move2);
430
    VertexEffectMove   effect5 = new VertexEffectMove(move3);
431
    VertexEffectRotate effect6 = new VertexEffectRotate(angle3, axisZ, center);
432
    VertexEffectRotate effect7 = new VertexEffectRotate(angle4, axisX, center);
433
    VertexEffectRotate effect8 = new VertexEffectRotate(angle1, axisY, center);
434
    VertexEffectScale  effect9 = new VertexEffectScale(0);
435
    VertexEffectDeform effect10= new VertexEffectDeform(vec0,radius,cent0,reg0);
436
    VertexEffectDeform effect11= new VertexEffectDeform(vec1,radius,cent1,reg1);
437
    VertexEffectDeform effect12= new VertexEffectDeform(vec2,radius,cent2,reg1);
438
    VertexEffectMove   effect13= new VertexEffectMove(move4);
439

    
440
    effect0.setMeshAssociation( 1,-1);  // mesh 0
441
    effect1.setMeshAssociation( 2,-1);  // mesh 1
442
    effect2.setMeshAssociation( 2,-1);  // mesh 1
443
    effect3.setMeshAssociation( 2,-1);  // mesh 1
444
    effect4.setMeshAssociation( 4,-1);  // mesh 2
445
    effect5.setMeshAssociation( 8,-1);  // mesh 3
446
    effect6.setMeshAssociation( 8,-1);  // mesh 3
447
    effect7.setMeshAssociation( 4,-1);  // mesh 2
448
    effect8.setMeshAssociation( 8,-1);  // mesh 3
449
    effect9.setMeshAssociation(48,-1);  // meshes 4,5
450
    effect10.setMeshAssociation(15,-1); // meshes 0,1,2,3
451
    effect11.setMeshAssociation(15,-1); // meshes 0,1,2,3
452
    effect12.setMeshAssociation(15,-1); // meshes 0,1,2,3
453
    effect13.setMeshAssociation(15,-1); // meshes 0,1,2,3
454

    
455
    mFaceMesh.apply(effect0);
456
    mFaceMesh.apply(effect1);
457
    mFaceMesh.apply(effect2);
458
    mFaceMesh.apply(effect3);
459
    mFaceMesh.apply(effect4);
460
    mFaceMesh.apply(effect5);
461
    mFaceMesh.apply(effect6);
462
    mFaceMesh.apply(effect7);
463
    mFaceMesh.apply(effect8);
464
    mFaceMesh.apply(effect9);
465
    mFaceMesh.apply(effect10);
466
    mFaceMesh.apply(effect11);
467
    mFaceMesh.apply(effect12);
468
    mFaceMesh.apply(effect13);
469

    
470
    mFaceMesh.mergeEffComponents();
471
    }
472

    
473
///////////////////////////////////////////////////////////////////////////////////////////////////
474

    
475
  float getScreenRatio()
476
    {
477
    return 1.5f;
478
    }
479

    
480
///////////////////////////////////////////////////////////////////////////////////////////////////
481

    
482
  Static4D[] getQuats()
483
    {
484
    return QUATS;
485
    }
486

    
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488

    
489
  int getNumFaces()
490
    {
491
    return FACE_COLORS.length;
492
    }
493

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495

    
496
  int getNumStickerTypes()
497
    {
498
    return 1;
499
    }
500

    
501
///////////////////////////////////////////////////////////////////////////////////////////////////
502

    
503
  float getBasicStep()
504
    {
505
    return SQ2/2;
506
    }
507

    
508
///////////////////////////////////////////////////////////////////////////////////////////////////
509

    
510
  int getNumCubitFaces()
511
    {
512
    return FACES_PER_CUBIT;
513
    }
514

    
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516

    
517
  Static3D[] getCubitPositions(int size)
518
    {
519
    return CENTERS;
520
    }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523

    
524
  MeshBase createCubitMesh(int cubit)
525
    {
526
    MeshBase mesh;
527

    
528
    if( cubit<8 )
529
      {
530
      if( mCornerMesh==null ) createCornerMesh();
531
      mesh = mCornerMesh.copy(true);
532
      }
533
    else
534
      {
535
      if( mFaceMesh==null ) createFaceMesh();
536
      mesh = mFaceMesh.copy(true);
537
      }
538

    
539
    int index = QUAT_INDICES[cubit];
540
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
541
    mesh.apply(quat,0xffffffff,0);
542

    
543
    return mesh;
544
    }
545

    
546
///////////////////////////////////////////////////////////////////////////////////////////////////
547

    
548
  int getFaceColor(int cubit, int cubitface, int size)
549
    {
550
    return mFaceMap[cubit][cubitface];
551
    }
552

    
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554

    
555
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
556
    {
557
    float STROKE = 0.035f*side;
558
    float L= left+0.125f*side;
559
    float H= 0.375f*side;
560
    float LEN = 0.5f*side;
561

    
562
    paint.setAntiAlias(true);
563
    paint.setStrokeWidth(STROKE);
564
    paint.setColor(FACE_COLORS[face]);
565
    paint.setStyle(Paint.Style.FILL);
566

    
567
    canvas.drawRect(left,top,left+side,top+side,paint);
568

    
569
    paint.setColor(INTERIOR_COLOR);
570
    paint.setStyle(Paint.Style.STROKE);
571

    
572
    canvas.drawLine( L    , H,  L+LEN, H    , paint);
573
    canvas.drawLine( L    , H,  L+LEN, H+LEN, paint);
574
    canvas.drawLine( L+LEN, H,  L+LEN, H+LEN, paint);
575

    
576
    float S1 = 0.125f*side;
577
    float S2 = 0.070f*side;
578
    float X  = 0.7f*S2;
579

    
580
    float LA = left+0.625f*side;
581
    float RA = left+0.125f*side;
582
    float TA = 0.375f*side;
583
    float BA = 0.875f*side;
584

    
585
    canvas.drawArc( LA-S1, TA     , LA     , TA+S1, 270, 90, false, paint);
586
    canvas.drawArc( RA+X , TA     , RA+X+S2, TA+S2, 135,135, false, paint);
587
    canvas.drawArc( LA-S2, BA-X-S2, LA     , BA-X ,   0,135, false, paint);
588
    }
589

    
590
///////////////////////////////////////////////////////////////////////////////////////////////////
591

    
592
  float returnMultiplier()
593
    {
594
    return 2.0f;
595
    }
596

    
597
///////////////////////////////////////////////////////////////////////////////////////////////////
598

    
599
  float[] getRowChances()
600
    {
601
    float[] chances = new float[3];
602

    
603
    chances[0] = 0.5f;
604
    chances[1] = 0.5f;
605
    chances[2] = 1.0f;
606

    
607
    return chances;
608
    }
609

    
610
///////////////////////////////////////////////////////////////////////////////////////////////////
611
// PUBLIC API
612

    
613
  public Static3D[] getRotationAxis()
614
    {
615
    return ROT_AXIS;
616
    }
617

    
618
///////////////////////////////////////////////////////////////////////////////////////////////////
619

    
620
  public int getBasicAngle()
621
    {
622
    return 2;
623
    }
624

    
625
///////////////////////////////////////////////////////////////////////////////////////////////////
626

    
627
  public int computeRowFromOffset(float offset)
628
    {
629
    return offset<0.166f ? 0:2;
630
    }
631

    
632
///////////////////////////////////////////////////////////////////////////////////////////////////
633

    
634
  public float returnRotationFactor(float offset)
635
    {
636
    return 1.0f;
637
    }
638

    
639
///////////////////////////////////////////////////////////////////////////////////////////////////
640

    
641
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
642
    {
643
    int numAxis = ROTATION_AXIS.length;
644

    
645
    if( oldRotAxis == START_AXIS )
646
      {
647
      return rnd.nextInt(numAxis);
648
      }
649
    else
650
      {
651
      int newVector = rnd.nextInt(numAxis-2);
652

    
653
      switch(oldRotAxis)
654
        {
655
        case  0:
656
        case  1: return newVector+2;
657
        case  2:
658
        case  3: return (newVector==0 || newVector==1) ? newVector:newVector+2;
659
        default: return newVector;
660
        }
661
      }
662
    }
663

    
664
///////////////////////////////////////////////////////////////////////////////////////////////////
665

    
666
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
667
    {
668
    float rowFloat = rnd.nextFloat();
669

    
670
    for(int row=0; row<mRowChances.length; row++)
671
      {
672
      if( rowFloat<=mRowChances[row] ) return row;
673
      }
674

    
675
    return 0;
676
    }
677

    
678
///////////////////////////////////////////////////////////////////////////////////////////////////
679
// remember about the double cover or unit quaternions!
680

    
681
  private int mulQuat(int q1, int q2)
682
    {
683
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
684

    
685
    float rX = result.get0();
686
    float rY = result.get1();
687
    float rZ = result.get2();
688
    float rW = result.get3();
689

    
690
    final float MAX_ERROR = 0.1f;
691
    float dX,dY,dZ,dW;
692

    
693
    for(int i=0; i<QUATS.length; i++)
694
      {
695
      dX = QUATS[i].get0() - rX;
696
      dY = QUATS[i].get1() - rY;
697
      dZ = QUATS[i].get2() - rZ;
698
      dW = QUATS[i].get3() - rW;
699

    
700
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
701
          dY<MAX_ERROR && dY>-MAX_ERROR &&
702
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
703
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
704

    
705
      dX = QUATS[i].get0() + rX;
706
      dY = QUATS[i].get1() + rY;
707
      dZ = QUATS[i].get2() + rZ;
708
      dW = QUATS[i].get3() + rW;
709

    
710
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
711
          dY<MAX_ERROR && dY>-MAX_ERROR &&
712
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
713
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
714
      }
715

    
716
    return -1;
717
    }
718

    
719
///////////////////////////////////////////////////////////////////////////////////////////////////
720
// The Helicopter is solved if and only if:
721
//
722
// 1) all of its corner cubits are rotated with the same quat
723
// 2) all its face cubits are rotated with the same quat like the corner ones,
724
//    and optionally they also might be turned by a multiple of 90 degrees along
725
//    a vector perpendicular to the face they lie on.
726
//
727
// i.e.
728
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
729
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
730
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
731

    
732
  public boolean isSolved()
733
    {
734
    int q = CUBITS[0].mQuatIndex;
735

    
736
    if ( CUBITS[1].mQuatIndex == q &&
737
         CUBITS[2].mQuatIndex == q &&
738
         CUBITS[3].mQuatIndex == q &&
739
         CUBITS[4].mQuatIndex == q &&
740
         CUBITS[5].mQuatIndex == q &&
741
         CUBITS[6].mQuatIndex == q &&
742
         CUBITS[7].mQuatIndex == q  )
743
      {
744
      int q1 = mulQuat(q,1);
745
      int q2 = mulQuat(q,8);
746
      int q3 = mulQuat(q,9);
747

    
748
      for(int index=8; index<16; index++)
749
        {
750
        int qIndex = CUBITS[index].mQuatIndex;
751
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
752
        }
753

    
754
      q1 = mulQuat(q, 2);
755
      q2 = mulQuat(q,12);
756
      q3 = mulQuat(q,13);
757

    
758
      for(int index=16; index<24; index++)
759
        {
760
        int qIndex = CUBITS[index].mQuatIndex;
761
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
762
        }
763

    
764
      q1 = mulQuat(q, 3);
765
      q2 = mulQuat(q,14);
766
      q3 = mulQuat(q,15);
767

    
768
      for(int index=24; index<32; index++)
769
        {
770
        int qIndex = CUBITS[index].mQuatIndex;
771
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
772
        }
773

    
774
      return true;
775
      }
776

    
777
    return false;
778
    }
779

    
780
///////////////////////////////////////////////////////////////////////////////////////////////////
781
// only needed for solvers - there are no Helicopter solvers ATM)
782

    
783
  public String retObjectString()
784
    {
785
    return "";
786
    }
787

    
788
}
(4-4/14)