Project

General

Profile

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

magiccube / src / main / java / org / distorted / helpers / FactoryCubit.java @ 680469e6

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.helpers;
21

    
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.VertexEffect;
26
import org.distorted.library.effect.VertexEffectDeform;
27
import org.distorted.library.effect.VertexEffectMove;
28
import org.distorted.library.effect.VertexEffectRotate;
29
import org.distorted.library.effect.VertexEffectScale;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshJoined;
32
import org.distorted.library.mesh.MeshPolygon;
33
import org.distorted.library.type.Static1D;
34
import org.distorted.library.type.Static3D;
35
import org.distorted.library.type.Static4D;
36

    
37
import java.util.ArrayList;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

    
41
public class FactoryCubit
42
  {
43
  private static final float SQ2 = (float)Math.sqrt(2);
44
  private static final float SQ3 = (float)Math.sqrt(3);
45
  private static final float SQ5 = (float)Math.sqrt(5);
46

    
47
  private static final Static1D RADIUS = new Static1D(1);
48
  private static FactoryCubit mThis;
49

    
50
  // IVY
51
  static final float IVY_D = 0.003f;
52
  static final float IVY_C = 0.59f;
53
  static final float IVY_M = 0.35f;
54
  private static final int IVY_N = 8;
55

    
56
  // REX
57
  public static final float REX_D = 0.2f;
58

    
59
  // KILO / MEGAMINX
60
  public static final float SIN54    = (SQ5+1)/4;
61
  public static final float COS54    = (float)(Math.sqrt(10-2*SQ5)/4);
62
  public static final float SIN18    = (SQ5-1)/4;
63
  public static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
64
  public static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
65
  public static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
66
  public static final float DIHEDRAL1= (float)(Math.acos(-SQ5/5)*180/Math.PI);
67
  public static final float DIHEDRAL2= (float)((180/Math.PI)*Math.asin((2*SIN54*SIN54-1)/COS54) - 90);
68
  public static final float MINX_SC  = 0.5f;
69

    
70

    
71
  private static final double[] mBuffer = new double[3];
72
  private static final double[] mQuat1  = new double[4];
73
  private static final double[] mQuat2  = new double[4];
74
  private static final double[] mQuat3  = new double[4];
75
  private static final double[] mQuat4  = new double[4];
76

    
77
  private static class StickerCoords
78
    {
79
    double[] vertices;
80
    }
81

    
82
  private static class FaceTransform
83
    {
84
    int sticker;
85
    double vx,vy,vz;
86
    double scale;
87
    double qx,qy,qz,qw;
88
    boolean flip;
89
    }
90

    
91
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
92
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
93
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
  private FactoryCubit()
98
    {
99

    
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  public static FactoryCubit getInstance()
105
    {
106
    if( mThis==null ) mThis = new FactoryCubit();
107

    
108
    return mThis;
109
    }
110

    
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112
// H - height of the band in the middle
113
// alpha - angle of the edge  [0,90]
114
// dist - often in a polygon the distance from edge to center is not 1, but something else.
115
// This is the distance.
116
// K - where to begin the second, much more flat part of the band. [0,1]
117
// N - number of bands. N>=3
118
//
119
// theory: two distinct parts to the band:
120
// 1) (0,B) - steep
121
// 2) (B,1) - flat
122
//
123
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
124
//
125
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
126
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
127
// h(x) = R*(sin(alpha) - sin(x))
128
// R = H/(1-cos(alpha))
129
// D = H*sin(alpha)
130
// B = h(K*alpha)
131
//
132
// The N points are taken at:
133
//
134
// 1) in the second part, there are K2 = (N-3)/3 such points
135
// 2) in the first - K1 = (N-3) - K2
136
// 3) also, the 3 points 0,B,1
137
//
138
// so we have the sequence A[i] of N points
139
//
140
// 0
141
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
142
// B
143
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
144
// 1
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  private float f(float D, float B, float x)
149
    {
150
    return ((D-B)*x + B*(1-D))/(1-B);
151
    }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

    
155
  private float g(float R, float D, float x, float cosAlpha)
156
    {
157
    float d = x-D;
158
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  private float h(float R, float sinAlpha, float x)
164
    {
165
    return R*(sinAlpha-(float)Math.sin(x));
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
171
    {
172
    float[] bands = new float[2*N];
173

    
174
    bands[0] = 1.0f;
175
    bands[1] = 0.0f;
176

    
177
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
178
    float sinBeta = (float)Math.sin(beta);
179
    float cosBeta = (float)Math.cos(beta);
180
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
181
    float D = R*sinBeta;
182
    float B = h(R,sinBeta,K*beta);
183

    
184
    if( D>1.0f )
185
      {
186
      for(int i=1; i<N; i++)
187
        {
188
        bands[2*i  ] = (float)(N-1-i)/(N-1);
189
        bands[2*i+1] = H*(1-bands[2*i]);
190
        }
191
      }
192
    else
193
      {
194
      int K2 = (int)((N-3)*K);
195
      int K1 = (N-3)-K2;
196

    
197
      for(int i=0; i<=K1; i++)
198
        {
199
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
200
        float x = h(R,sinBeta,angle);
201
        bands[2*i+2] = 1.0f - x;
202
        bands[2*i+3] = g(R,D,x,cosBeta);
203
        }
204

    
205
      for(int i=0; i<=K2; i++)
206
        {
207
        float x = (1-B)*(i+1)/(K2+1) + B;
208
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
209
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
210
        }
211
      }
212

    
213
    bands[2*N-2] = 0.0f;
214
    bands[2*N-1] =    H;
215

    
216
    return bands;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
222
    {
223
    Static4D reg= new Static4D(0,0,0,regionRadius);
224

    
225
    float centX = center.get0();
226
    float centY = center.get1();
227
    float centZ = center.get2();
228

    
229
    for (Static3D vertex : vertices)
230
      {
231
      float x = strength*(centX - vertex.get0());
232
      float y = strength*(centY - vertex.get1());
233
      float z = strength*(centZ - vertex.get2());
234

    
235
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
236
      mesh.apply(effect);
237
      }
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  MeshBase createFacesIvyCorner()
243
    {
244
    MeshBase[] meshes = new MeshBase[6];
245

    
246
    final float angle = (float)Math.PI/(2*IVY_N);
247
    final float CORR  = 1.0f - 2*IVY_D;
248
    final float DIST  = -0.5f*CORR + IVY_D;
249
    float[] vertices  = new float[2*(IVY_N+1)+6];
250

    
251
    vertices[0] = (0.5f-IVY_M) * IVY_C;
252
    vertices[1] = (DIST-IVY_M) * IVY_C;
253
    vertices[2] = (0.5f-IVY_M) * IVY_C;
254
    vertices[3] = (0.5f-IVY_M) * IVY_C;
255
    vertices[4] = (DIST-IVY_M) * IVY_C;
256
    vertices[5] = (0.5f-IVY_M) * IVY_C;
257

    
258
    for(int i=0; i<=IVY_N; i++)
259
      {
260
      float ang = (IVY_N-i)*angle;
261
      float sin = (float)Math.sin(ang);
262
      float cos = (float)Math.cos(ang);
263

    
264
      vertices[2*i+6] = (CORR*(cos-0.5f)-IVY_M)*IVY_C;
265
      vertices[2*i+7] = (CORR*(sin-0.5f)-IVY_M)*IVY_C;
266
      }
267

    
268
    float[] bands0 = computeBands(+0.012f,20,0.2f,0.5f,7);
269
    float[] bands1 = computeBands(-0.100f,20,0.2f,0.0f,2);
270

    
271
    meshes[0] = new MeshPolygon(vertices,bands0,1,2);
272
    meshes[0].setEffectAssociation(0,1,0);
273
    meshes[1] = meshes[0].copy(true);
274
    meshes[1].setEffectAssociation(0,2,0);
275
    meshes[2] = meshes[0].copy(true);
276
    meshes[2].setEffectAssociation(0,4,0);
277
    meshes[3] = new MeshPolygon(vertices,bands1,1,2);
278
    meshes[3].setEffectAssociation(0,8,0);
279
    meshes[4] = meshes[3].copy(true);
280
    meshes[4].setEffectAssociation(0,16,0);
281
    meshes[5] = meshes[3].copy(true);
282
    meshes[5].setEffectAssociation(0,32,0);
283

    
284
    return new MeshJoined(meshes);
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  MeshBase createFacesIvyFace()
290
    {
291
    MeshBase[] meshes = new MeshBase[2];
292

    
293
    final float angle = (float)Math.PI/(2*IVY_N);
294
    final float CORR  = 1.0f - 2*IVY_D;
295
    float[] vertices = new float[4*IVY_N];
296

    
297
    for(int i=0; i<IVY_N; i++)
298
      {
299
      float sin = (float)Math.sin(i*angle);
300
      float cos = (float)Math.cos(i*angle);
301

    
302
      vertices[2*i          ] = CORR*(0.5f-cos);
303
      vertices[2*i+1        ] = CORR*(0.5f-sin);
304
      vertices[2*i  +2*IVY_N] = CORR*(cos-0.5f);
305
      vertices[2*i+1+2*IVY_N] = CORR*(sin-0.5f);
306
      }
307

    
308
    float[] bands0 = computeBands(+0.03f,35,0.5f,0.5f,5);
309
    float[] bands1 = computeBands(-0.10f,45,0.5f,0.0f,2);
310

    
311
    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
312
    meshes[0].setEffectAssociation(0,1,0);
313
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
314
    meshes[1].setEffectAssociation(0,2,0);
315

    
316
    return new MeshJoined(meshes);
317
    }
318

    
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320

    
321
  MeshBase createFacesRexCorner()
322
    {
323
    MeshBase[] meshes = new MeshBase[2];
324

    
325
    float F = REX_D*SQ2;
326
    float G = (1-REX_D)*SQ2/2;
327
    float H = 0.1f;
328
    float J = +2*G/3 - H*G;
329

    
330
    float[] vertices = { -F/2, -G/3, +F/2, -G/3, H*F/2, J, -H*F/2, J};
331

    
332
    float[] bands0 = computeBands(+0.016f,10,G/3,0.5f,5);
333
    float[] bands1 = computeBands(-0.230f,45,G/3,0.0f,2);
334

    
335
    meshes[0] = new MeshPolygon(vertices,bands0,1,1);
336
    meshes[0].setEffectAssociation(0,1,0);
337
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
338
    meshes[1].setEffectAssociation(0,2,0);
339

    
340
    return new MeshJoined(meshes);
341
    }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344

    
345
  MeshBase createFacesRexFace()
346
    {
347
    MeshBase[] meshes = new MeshBase[2];
348

    
349
    float[] vertices = { -REX_D,0.0f, 0.0f, -REX_D, +REX_D, 0.0f, 0.0f, +REX_D};
350

    
351
    float[] bands0 = computeBands(0.016f,10,REX_D/2,0.5f,5);
352
    float[] bands1 = computeBands(0.000f,45,REX_D/2,0.0f,2);
353

    
354
    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
355
    meshes[0].setEffectAssociation(0,1,0);
356
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
357
    meshes[1].setEffectAssociation(0,2,0);
358

    
359
    return new MeshJoined(meshes);
360
    }
361

    
362
///////////////////////////////////////////////////////////////////////////////////////////////////
363

    
364
  MeshBase createFacesRexEdge()
365
    {
366
    MeshBase[] meshes = new MeshPolygon[6];
367

    
368
    float E = 0.5f - REX_D;
369
    float F = 0.5f;
370
    float[] vertices0 = { -F,E/3, 0,-2*E/3, +F,E/3 };
371
    float[] bands0 = computeBands(0.03f,27,F/3,0.8f,5);
372

    
373
    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 3);
374
    meshes[0].setEffectAssociation(0,1,0);
375
    meshes[1] = meshes[0].copy(true);
376
    meshes[1].setEffectAssociation(0,2,0);
377

    
378
    float G = (float)Math.sqrt(E*E+F*F);
379
    float[] vertices1 = { -2*G/3, -E/3, G/3, -E/3, G/3, 2*E/3 };
380
    float[] bands1 = computeBands(0.00f,45,G/3,0.2f,3);
381

    
382
    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
383
    meshes[2].setEffectAssociation(0,4,0);
384
    meshes[3] = meshes[2].copy(true);
385
    meshes[3].setEffectAssociation(0,8,0);
386
    meshes[4] = meshes[2].copy(true);
387
    meshes[4].setEffectAssociation(0,16,0);
388
    meshes[5] = meshes[2].copy(true);
389
    meshes[5].setEffectAssociation(0,32,0);
390

    
391
    return new MeshJoined(meshes);
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
  MeshBase createFacesKilominxCenter()
397
    {
398
    MeshBase[] meshes = new MeshPolygon[6];
399

    
400
    float X1= 0.5f*SIN54;
401
    float Y1= 0.5f*SIN_HALFD;
402
    float Y2= Y1 - 0.5f*COS54;
403
    float H = 0.5f* SIN54 /COS54  ;
404
    float X2= MINX_SC*H* SIN_HALFD;
405
    float Y3= MINX_SC*H/(2*COS_HALFD);
406
    float Y4= MINX_SC*H*(1/(2*COS_HALFD) - COS_HALFD);
407

    
408
    float[] vertices0 = { -X1, Y2, 0, -Y1, X1, Y2, 0, Y1 };
409
    float[] bands0 = computeBands(0.04f,17,0.3f,0.2f,5);
410
    float[] vertices1 = { -X2, Y4, 0, -Y3, X2, Y4, 0, Y3 };
411
    float[] bands1 = computeBands(0.00f, 0,0.25f,0.5f,2);
412

    
413
    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
414
    meshes[0].setEffectAssociation(0, 1,0);
415
    meshes[1] = meshes[0].copy(true);
416
    meshes[1].setEffectAssociation(0, 2,0);
417
    meshes[2] = meshes[0].copy(true);
418
    meshes[2].setEffectAssociation(0, 4,0);
419
    meshes[3] = new MeshPolygon(vertices1, bands1, 0, 0);
420
    meshes[3].setEffectAssociation(0, 8,0);
421
    meshes[4] = meshes[3].copy(true);
422
    meshes[4].setEffectAssociation(0,16,0);
423
    meshes[5] = meshes[3].copy(true);
424
    meshes[5].setEffectAssociation(0,32,0);
425

    
426
    return new MeshJoined(meshes);
427
    }
428

    
429
///////////////////////////////////////////////////////////////////////////////////////////////////
430

    
431
  MeshBase createFacesMinxCorner(int numLayers)
432
    {
433
    MeshBase[] meshes = new MeshPolygon[6];
434

    
435
    float Y = COS54/(2*SIN54);
436

    
437
    float[] vertices0 = { -0.5f, 0.0f, 0.0f, -Y, 0.5f, 0.0f, 0.0f, Y };
438

    
439
    int numBands0 = numLayers==3 ? 5 : 3;
440
    int numBands1 = numLayers==3 ? 2 : 2;
441
    float h       = numLayers==3 ? 0.04f : 0.03f;
442
    int   e       = numLayers==3 ? 4 : 1;
443

    
444
    float[] bands0 = computeBands(h    ,34,0.3f,0.2f, numBands0);
445
    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f, numBands1);
446

    
447
    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
448
    meshes[0].setEffectAssociation(0, 1,0);
449
    meshes[1] = meshes[0].copy(true);
450
    meshes[1].setEffectAssociation(0, 2,0);
451
    meshes[2] = meshes[0].copy(true);
452
    meshes[2].setEffectAssociation(0, 4,0);
453
    meshes[3] = new MeshPolygon(vertices0, bands1, 1, e);
454
    meshes[3].setEffectAssociation(0, 8,0);
455
    meshes[4] = meshes[3].copy(true);
456
    meshes[4].setEffectAssociation(0,16,0);
457
    meshes[5] = meshes[3].copy(true);
458
    meshes[5].setEffectAssociation(0,32,0);
459

    
460
    return new MeshJoined(meshes);
461
    }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

    
465
  MeshBase createFacesKilominxEdge(int numLayers, float width, float height)
466
    {
467
     MeshBase[] meshes = new MeshPolygon[6];
468

    
469
    float D = height/COS18;
470
    float W = D*SIN18;
471
    float X1 = height/2;
472
    float Y1 = width/2;
473
    float Y2 = (width+W)/2;
474
    float X3 = D*SIN54;
475
    float Y3 = D*COS54;
476
    float X4 = height*SIN_HALFD;
477
    float Y4 = height*COS_HALFD;
478

    
479
    float[] vertices0 = { -X1,-Y1, X1, -Y1, X1, Y1+W,-X1, Y1 };
480
    float[] vertices1 = { -X1,-Y2, X1, -Y2, X1, Y2+W,-X1, Y2 };
481
    float[] vertices2 = { -X3, 0.0f, 0.0f, -Y3, X3, 0.0f, 0.0f, Y3 };
482
    float[] vertices3 = { -X4, 0.0f, 0.0f, -Y4, X4, 0.0f, 0.0f, Y4 };
483

    
484
    int numBands0 = numLayers<=5 ? 5 : 3;
485
    int numBands1 = numLayers<=5 ? 3 : 2;
486
    float h       = numLayers<=5 ? 0.03f : 0.03f;
487

    
488
    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
489
    float[] bands1 = computeBands(0.01f,34,0.3f,0.2f,numBands1);
490

    
491
    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
492
    meshes[0].setEffectAssociation(0, 1,0);
493
    meshes[1] = meshes[0].copy(true);
494
    meshes[1].setEffectAssociation(0, 2,0);
495
    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
496
    meshes[2].setEffectAssociation(0, 4,0);
497
    meshes[3] = meshes[2].copy(true);
498
    meshes[3].setEffectAssociation(0, 8,0);
499
    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
500
    meshes[4].setEffectAssociation(0,16,0);
501
    meshes[5] = new MeshPolygon(vertices3, bands1, 0, 0);
502
    meshes[5].setEffectAssociation(0,32,0);
503

    
504
    return new MeshJoined(meshes);
505
    }
506

    
507
///////////////////////////////////////////////////////////////////////////////////////////////////
508

    
509
  MeshBase createFacesMegaminxEdge(int numLayers, float width, float height)
510
    {
511
    MeshBase[] meshes = new MeshPolygon[6];
512

    
513
    float D = height/COS18;
514
    float W = D*SIN18;
515

    
516
    float Y1 = 0.5f*width;
517
    float Y2 = 0.5f*width + W;
518
    float Y3 = 0.5f*width + 2*W;
519
    float X2 = D*SIN54;
520
    float X1 = 0.5f*height;
521
    float Y4 = D*COS54;
522

    
523
    float[] vertices0 = { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
524
    float[] vertices1 = { -X1, Y3, -X1, -Y3, X1, -Y2, X1, Y2 };
525
    float[] vertices2 = { -X2, 0.0f, 0.0f, -Y4, X2, 0.0f, 0.0f, Y4 };
526

    
527
    int numBands0 = numLayers==3 ? 5 : 3;
528
    int numBands1 = numLayers==3 ? 2 : 2;
529
    float h       = numLayers==3 ? 0.03f : 0.03f;
530

    
531
    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
532
    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f,numBands1);
533

    
534
    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
535
    meshes[0].setEffectAssociation(0, 1,0);
536
    meshes[1] = meshes[0].copy(true);
537
    meshes[1].setEffectAssociation(0, 2,0);
538
    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
539
    meshes[2].setEffectAssociation(0, 4,0);
540
    meshes[3] = meshes[2].copy(true);
541
    meshes[3].setEffectAssociation(0, 8,0);
542
    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
543
    meshes[4].setEffectAssociation(0,16,0);
544
    meshes[5] = meshes[4].copy(true);
545
    meshes[5].setEffectAssociation(0,32,0);
546

    
547
    return new MeshJoined(meshes);
548
    }
549

    
550
///////////////////////////////////////////////////////////////////////////////////////////////////
551

    
552
  MeshBase createFacesMegaminxCenter(int numLayers)
553
    {
554
    MeshBase[] meshes = new MeshPolygon[2];
555

    
556
    float R  = 0.5f;
557
    float X1 = R*COS54;
558
    float Y1 = R*SIN54;
559
    float X2 = R*COS18;
560
    float Y2 = R*SIN18;
561

    
562
    float[] vertices0 = { -X1,+Y1, -X2,-Y2, 0.0f,-R, +X2,-Y2, +X1,+Y1 };
563

    
564
    int numBands0 = numLayers==3 ? 4 : 3;
565
    int numBands1 = numLayers==3 ? 2 : 2;
566
    float h       = numLayers==3 ? 0.04f : 0.04f;
567

    
568
    float[] bands0 = computeBands( h    ,45, R/3,0.2f, numBands0);
569
    float[] bands1 = computeBands( 0.00f,34, R/3,0.2f, numBands1);
570

    
571
    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
572
    meshes[0].setEffectAssociation(0,1,0);
573
    meshes[1] = new MeshPolygon(vertices0, bands1, 0, 0);
574
    meshes[1].setEffectAssociation(0,2,0);
575

    
576
    return new MeshJoined(meshes);
577
    }
578

    
579
///////////////////////////////////////////////////////////////////////////////////////////////////
580

    
581
  private float[] createVertices(int A, int B)
582
    {
583
    float E = 0.5f / Math.max(A,B);
584
    return new float[] { -A*E,-B*E, +A*E,-B*E, +A*E,+B*E, -A*E,+B*E };
585
    }
586

    
587
///////////////////////////////////////////////////////////////////////////////////////////////////
588

    
589
  MeshBase createCuboid(int[] dimensions)
590
    {
591
    int X = dimensions[0];
592
    int Y = dimensions[1];
593
    int Z = dimensions[2];
594

    
595
    float[] verticesXY = createVertices(X,Y);
596
    float[] verticesXZ = createVertices(X,Z);
597
    float[] verticesYZ = createVertices(Z,Y);
598

    
599
    float defHeight = 0.048f;
600

    
601
    float[] bandsX = computeBands( defHeight/X,65,0.25f,0.5f,5);
602
    float[] bandsY = computeBands( defHeight/Y,65,0.25f,0.5f,5);
603
    float[] bandsZ = computeBands( defHeight/Z,65,0.25f,0.5f,5);
604

    
605
    MeshBase[] meshes = new MeshPolygon[6];
606

    
607
    meshes[0] = new MeshPolygon(verticesYZ,bandsX,1,2);
608
    meshes[0].setEffectAssociation(0,1,0);
609
    meshes[1] = meshes[0].copy(true);
610
    meshes[1].setEffectAssociation(0,2,0);
611
    meshes[2] = new MeshPolygon(verticesXZ,bandsY,1,2);
612
    meshes[2].setEffectAssociation(0,4,0);
613
    meshes[3] = meshes[2].copy(true);
614
    meshes[3].setEffectAssociation(0,8,0);
615
    meshes[4] = new MeshPolygon(verticesXY,bandsZ,1,2);
616
    meshes[4].setEffectAssociation(0,16,0);
617
    meshes[5] = meshes[4].copy(true);
618
    meshes[5].setEffectAssociation(0,32,0);
619

    
620
    return new MeshJoined(meshes);
621
    }
622

    
623
///////////////////////////////////////////////////////////////////////////////////////////////////
624
// EFFECTS
625
///////////////////////////////////////////////////////////////////////////////////////////////////
626

    
627
  VertexEffect[] createVertexEffectsIvyCorner()
628
    {
629
    Static3D axisX  = new Static3D(1,0,0);
630
    Static3D axisY  = new Static3D(0,1,0);
631
    Static1D angle1 = new Static1D(+90);
632
    Static1D angle2 = new Static1D(-90);
633
    Static3D center = new Static3D(0,0,0);
634
    Static3D move1  = new Static3D(IVY_M-0.5f,IVY_M-0.5f,0);
635

    
636
    VertexEffect[] effect = new VertexEffect[5];
637

    
638
    effect[0] = new VertexEffectScale(1/IVY_C);
639
    effect[1] = new VertexEffectMove(move1);
640
    effect[2] = new VertexEffectScale(new Static3D(1,1,-1));
641
    effect[3] = new VertexEffectRotate(angle1,axisX,center);
642
    effect[4] = new VertexEffectRotate(angle2,axisY,center);
643

    
644
    effect[2].setMeshAssociation(54,-1);  // meshes 1,2,4,5
645
    effect[3].setMeshAssociation(18,-1);  // meshes 1,4
646
    effect[4].setMeshAssociation(36,-1);  // meshes 2,5
647

    
648
    return effect;
649
    }
650

    
651
///////////////////////////////////////////////////////////////////////////////////////////////////
652

    
653
  VertexEffect[] createVertexEffectsRexEdge()
654
    {
655
    float E = 0.5f - REX_D;
656
    float F = 0.5f;
657
    float G = (float)Math.sqrt(E*E+F*F);
658
    float A = (float)((180/Math.PI)*Math.asin(E/G));
659

    
660
    Static3D move1 = new Static3D(    0.0f, -E/3, 0.0f);
661
    Static3D move2 = new Static3D(2*G/3 -F, +E/3, 0.0f);
662

    
663
    Static3D center0= new Static3D(0.0f, 0.0f, 0.0f);
664
    Static3D center1= new Static3D(  -F, 0.0f, 0.0f);
665
    Static3D center2= new Static3D(  +F, 0.0f, 0.0f);
666
    Static3D axisX  = new Static3D(1.0f, 0.0f, 0.0f);
667
    Static3D axisY  = new Static3D(0.0f, 1.0f, 0.0f);
668
    Static3D axisZ  = new Static3D(0.0f, 0.0f, 1.0f);
669

    
670
    Static1D angle180 = new Static1D(180);
671
    Static1D angle90  = new Static1D( 90);
672
    Static1D angle270 = new Static1D(270);
673
    Static1D angle1   = new Static1D(+A);
674
    Static1D angle2   = new Static1D(-A);
675

    
676
    VertexEffect[] effect = new VertexEffect[12];
677

    
678
    effect[0] = new VertexEffectMove(move1);
679
    effect[1] = new VertexEffectMove(move2);
680
    effect[2] = new VertexEffectRotate(  angle90, axisX, center0 );
681
    effect[3] = new VertexEffectRotate( angle270, axisX, center0 );
682
    effect[4] = new VertexEffectRotate( angle180, axisX, center0 );
683
    effect[5] = new VertexEffectRotate( angle180, axisY, center0 );
684
    effect[6] = new VertexEffectScale ( new Static3D(-1, 1, 1) );
685
    effect[7] = new VertexEffectScale ( new Static3D( 1,-1, 1) );
686
    effect[8] = new VertexEffectRotate(   angle1, axisY, center1);
687
    effect[9] = new VertexEffectRotate(   angle2, axisY, center2);
688
    effect[10]= new VertexEffectRotate(   angle2, axisZ, center1);
689
    effect[11]= new VertexEffectRotate(   angle1, axisZ, center2);
690

    
691
    effect[0].setMeshAssociation( 3,-1);  // meshes 0 & 1
692
    effect[1].setMeshAssociation(60,-1);  // meshes 2,3,4,5
693
    effect[2].setMeshAssociation( 2,-1);  // meshes 1
694
    effect[3].setMeshAssociation(12,-1);  // meshes 2,3
695
    effect[4].setMeshAssociation(48,-1);  // meshes 4,5
696
    effect[5].setMeshAssociation(32,-1);  // mesh 5
697
    effect[6].setMeshAssociation( 8,-1);  // apply to mesh 3
698
    effect[7].setMeshAssociation( 2,-1);  // apply to mesh 1
699
    effect[8].setMeshAssociation(16,-1);  // apply to mesh 4
700
    effect[9].setMeshAssociation(32,-1);  // apply to mesh 5
701
    effect[10].setMeshAssociation(4,-1);  // apply to mesh 2
702
    effect[11].setMeshAssociation(8,-1);  // apply to mesh 3
703

    
704
    return effect;
705
    }
706

    
707
///////////////////////////////////////////////////////////////////////////////////////////////////
708

    
709
  VertexEffect[] createVertexEffectsRexCorner()
710
    {
711
    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
712
    Static3D axisZ = new Static3D(0.0f, 0.0f, 1.0f);
713
    Static1D angle = new Static1D(225);
714

    
715
    VertexEffect[] effect = new VertexEffect[1];
716
    effect[0] = new VertexEffectRotate(angle, axisZ, center);
717

    
718
    return effect;
719
    }
720

    
721
///////////////////////////////////////////////////////////////////////////////////////////////////
722

    
723
  VertexEffect[] createVertexEffectsKilominxCenter(float width)
724
    {
725
    VertexEffect[] effect = new VertexEffect[11];
726

    
727
    float H = 0.5f*(SIN54/COS54);
728
    float Y1= 0.5f*SIN_HALFD;
729
    float Y2= H/(2*COS_HALFD);
730
    float cos18 = (float)(Math.sqrt(1- SIN18 * SIN18));
731
    float LEN   = (float)Math.sqrt(H*H/(COS_HALFD*COS_HALFD) + 0.25f);
732

    
733
    Static3D axisZ = new Static3D(0.0f  , 0.0f , 1.0f);
734
    Static3D axisY = new Static3D(0.0f  , 1.0f , 0.0f);
735
    Static3D axisA = new Static3D(-SIN18, cos18, 0.0f);
736
    Static3D axisC = new Static3D( H/LEN, -0.5f/LEN,-H* SIN_HALFD /(COS_HALFD*LEN));
737

    
738
    Static3D move1 = new Static3D(0,-Y1,0);
739
    Static3D move2 = new Static3D(0,-Y2,0);
740
    Static3D move3 = new Static3D(0.5f*cos18,0.5f*SIN18,0);
741
    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
742

    
743
    Static1D angle1 = new Static1D(54);
744
    Static1D angle2 = new Static1D(DIHEDRAL1/2+18);
745
    Static1D angle3 = new Static1D(90);
746
    Static1D angle4 = new Static1D(120);
747
    Static1D angle5 = new Static1D(240);
748
    Static1D angle6 = new Static1D(90-DIHEDRAL1/2);
749

    
750
    effect[0] = new VertexEffectMove(move1);
751
    effect[1] = new VertexEffectScale(1/MINX_SC);
752
    effect[2] = new VertexEffectMove(move2);
753
    effect[3] = new VertexEffectRotate(angle1, axisZ, center);
754
    effect[4] = new VertexEffectRotate(angle2, axisZ, center);
755
    effect[5] = new VertexEffectRotate(angle3, axisA, center);
756
    effect[6] = new VertexEffectMove(move3);
757
    effect[7] = new VertexEffectRotate(angle4, axisC, center);
758
    effect[8] = new VertexEffectRotate(angle5, axisC, center);
759
    effect[9] = new VertexEffectRotate(angle6, axisY, center);
760
    effect[10]= new VertexEffectScale(width/0.5f);
761

    
762
    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
763
    effect[1].setMeshAssociation(56,-1);  // meshes 3,4,5
764
    effect[2].setMeshAssociation(56,-1);  // meshes 3,4,5
765
    effect[3].setMeshAssociation( 7,-1);  // meshes 0,1,2
766
    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
767
    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
768
    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
769
    effect[7].setMeshAssociation(18,-1);  // meshes 1,4
770
    effect[8].setMeshAssociation(36,-1);  // meshes 2,5
771

    
772
    return effect;
773
    }
774

    
775
///////////////////////////////////////////////////////////////////////////////////////////////////
776

    
777
  VertexEffect[] createVertexEffectsMinxCorner(float width)
778
    {
779
    VertexEffect[] effect = new VertexEffect[9];
780

    
781
    float Y = COS54/(2*SIN54);
782

    
783
    float sinA = (2*SIN54*SIN54-1)/COS54;
784
    float cosA = (float)Math.sqrt(1-sinA*sinA);
785
    float LEN  = 0.5f/SIN54;
786
    float scale= width/LEN;
787

    
788
    Static3D axisA = new Static3D( SIN54, COS54, 0.0f);
789
    Static3D axisB = new Static3D(-SIN54, COS54, 0.0f);
790
    Static3D axisX = new Static3D(  1.0f,  0.0f, 0.0f);
791

    
792
    Static3D centerU = new Static3D( 0.0f, Y, 0.0f);
793
    Static3D centerD = new Static3D( 0.0f,-Y, 0.0f);
794

    
795
    Static3D move1= new Static3D(0.0f, -sinA*LEN, -cosA*LEN );
796
    Static3D move2= new Static3D(0.0f, Y , 0.0f );
797

    
798
    Static1D angleD = new Static1D(DIHEDRAL1);
799
    Static1D angleE = new Static1D(360-DIHEDRAL1);
800
    Static1D angleF = new Static1D(DIHEDRAL2);
801

    
802
    effect[0] = new VertexEffectScale ( new Static3D( 1, 1,-1) );
803
    effect[1] = new VertexEffectRotate(angleE, axisA, centerU);
804
    effect[2] = new VertexEffectRotate(angleD, axisB, centerU);
805
    effect[3] = new VertexEffectMove(move1);
806
    effect[4] = new VertexEffectRotate(angleE, axisA, centerD);
807
    effect[5] = new VertexEffectRotate(angleD, axisB, centerD);
808
    effect[6] = new VertexEffectRotate(angleF, axisX, centerD);
809
    effect[7] = new VertexEffectMove(move2);
810
    effect[8] = new VertexEffectScale(scale);
811

    
812
    effect[0].setMeshAssociation(  3,-1);  // meshes 0,1
813
    effect[1].setMeshAssociation( 16,-1);  // mesh 4
814
    effect[2].setMeshAssociation( 32,-1);  // mesh 5
815
    effect[3].setMeshAssociation( 56,-1);  // meshes 3,4,5
816
    effect[4].setMeshAssociation(  1,-1);  // mesh 0
817
    effect[5].setMeshAssociation(  2,-1);  // mesh 1
818

    
819
    return effect;
820
    }
821

    
822
///////////////////////////////////////////////////////////////////////////////////////////////////
823

    
824
  VertexEffect[] createVertexEffectsKilominxEdge(float width, float height, boolean left)
825
    {
826
    VertexEffect[] effect = new VertexEffect[11 + (left ? 0:1)];
827

    
828
    float D = height/COS18;
829
    float W = D*SIN18;
830
    float X1 = height/2;
831
    float Y1 = width/2;
832
    float Y2 = (width+W)/2;
833
    float Y3 = D*COS54;
834
    float Y4 = height*COS_HALFD;
835
    float Z = 2*height*COS_HALFD;
836
    float alpha = 90-DIHEDRAL1/2;
837

    
838
    Static1D angle1 = new Static1D(alpha);
839
    Static1D angle2 = new Static1D(180-alpha);
840
    Static1D angle3 = new Static1D(DIHEDRAL2);
841
    Static1D angle4 = new Static1D(90);
842

    
843
    Static3D move1 = new Static3D(+X1,-Y1,0);
844
    Static3D move2 = new Static3D(-X1,-Y2+W,-Z);
845
    Static3D move3 = new Static3D(0,+Y3,0);
846
    Static3D move4 = new Static3D(0,-Y4-width,0);
847
    Static3D scale = new Static3D(+1,+1,-1);
848

    
849
    Static3D axisXplus = new Static3D(+1, 0, 0);
850
    Static3D axisYplus = new Static3D( 0,+1, 0);
851

    
852
    Static3D center1= new Static3D( 0, 0, 0);
853
    Static3D center2= new Static3D( 0, 0,-Z);
854
    Static3D center3= new Static3D( 0,-width, 0);
855

    
856
    effect[ 0] = new VertexEffectMove(move1);
857
    effect[ 1] = new VertexEffectMove(move2);
858
    effect[ 2] = new VertexEffectMove(move3);
859
    effect[ 3] = new VertexEffectMove(move4);
860
    effect[ 4] = new VertexEffectScale(scale);
861
    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
862
    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
863
    effect[ 7] = new VertexEffectRotate(angle1, axisYplus , center2);
864
    effect[ 8] = new VertexEffectRotate(angle2, axisYplus , center2);
865
    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center1);
866
    effect[10] = new VertexEffectRotate(angle4, axisXplus , center3);
867

    
868
    if( !left )
869
      {
870
      Static3D scale1 = new Static3D(+1,-1,+1);
871
      effect[11] = new VertexEffectScale(scale1);
872
      }
873

    
874
    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
875
    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
876
    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
877
    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
878
    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
879
    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
880
    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
881
    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
882
    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
883
    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
884
    effect[10].setMeshAssociation(32,-1);  // mesh 5
885

    
886
    return effect;
887
    }
888

    
889
///////////////////////////////////////////////////////////////////////////////////////////////////
890

    
891
  VertexEffect[] createVertexEffectsMegaminxEdge(float width, float height)
892
    {
893
    VertexEffect[] effect = new VertexEffect[11];
894

    
895
    float X = 0.5f*height;
896
    float Y = height*(COS54/COS18) + width*0.5f;
897
    float Z = 2*height*COS_HALFD;
898

    
899
    float alpha = 90-DIHEDRAL1/2;
900
    float beta  = DIHEDRAL2;
901

    
902
    Static1D angle1 = new Static1D(alpha);
903
    Static1D angle2 = new Static1D(180-alpha);
904
    Static1D angle3 = new Static1D(beta);
905

    
906
    Static3D move1 = new Static3D(X,0,0);
907
    Static3D move2 = new Static3D(X,0,-Z);
908
    Static3D move3 = new Static3D(0,+Y,0);
909
    Static3D move4 = new Static3D(0,-Y,0);
910
    Static3D scale = new Static3D(+1,+1,-1);
911

    
912
    Static3D axisXplus = new Static3D(+1, 0, 0);
913
    Static3D axisXminus= new Static3D(-1, 0, 0);
914
    Static3D axisYplus = new Static3D( 0,+1, 0);
915
    Static3D axisYminus= new Static3D( 0,-1, 0);
916

    
917
    Static3D center1= new Static3D( 0, 0, 0);
918
    Static3D center2= new Static3D( 0, 0,-Z);
919
    Static3D center3= new Static3D( 0,+width*0.5f, 0);
920
    Static3D center4= new Static3D( 0,-width*0.5f, 0);
921

    
922
    effect[ 0] = new VertexEffectMove(move1);
923
    effect[ 1] = new VertexEffectMove(move2);
924
    effect[ 2] = new VertexEffectMove(move3);
925
    effect[ 3] = new VertexEffectMove(move4);
926
    effect[ 4] = new VertexEffectScale(scale);
927
    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
928
    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
929
    effect[ 7] = new VertexEffectRotate(angle1, axisYminus, center2);
930
    effect[ 8] = new VertexEffectRotate(angle2, axisYminus, center2);
931
    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center3);
932
    effect[10] = new VertexEffectRotate(angle3, axisXminus, center4);
933

    
934
    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
935
    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
936
    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
937
    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
938
    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
939
    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
940
    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
941
    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
942
    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
943
    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
944
    effect[10].setMeshAssociation(32,-1);  // mesh 5
945

    
946
    return effect;
947
    }
948

    
949
///////////////////////////////////////////////////////////////////////////////////////////////////
950

    
951
  VertexEffect[] createVertexEffectsMegaminxCenter(float width)
952
    {
953
    VertexEffect[] effect = new VertexEffect[2];
954

    
955
    Static1D angle = new Static1D(DIHEDRAL2);
956
    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
957
    Static3D center= new Static3D( 0, 0, 0);
958

    
959
    effect[0] = new VertexEffectScale(width/COS54);
960
    effect[1] = new VertexEffectRotate(angle, axisX, center);
961

    
962
    return effect;
963
    }
964

    
965
///////////////////////////////////////////////////////////////////////////////////////////////////
966

    
967
  VertexEffect[] createCuboidEffects(int[] dimensions)
968
    {
969
    float X = dimensions[0];
970
    float Y = dimensions[1];
971
    float Z = dimensions[2];
972

    
973
    float MAX_XY = Math.max(X,Y);
974
    float MAX_XZ = Math.max(X,Z);
975
    float MAX_YZ = Math.max(Z,Y);
976

    
977
    Static1D angle = new Static1D(90);
978
    Static3D move  = new Static3D( 0.0f, 0.0f, 0.5f);
979
    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
980
    Static3D axisY = new Static3D( 0.0f, 1.0f, 0.0f);
981
    Static3D center= new Static3D( 0.0f, 0.0f, 0.0f);
982

    
983
    Static3D scale3 = new Static3D(MAX_XY,MAX_XY,+Z);
984
    Static3D scale4 = new Static3D(MAX_XY,MAX_XY,-Z);
985
    Static3D scale5 = new Static3D(MAX_XZ,+Y,MAX_XZ);
986
    Static3D scale6 = new Static3D(MAX_XZ,-Y,MAX_XZ);
987
    Static3D scale7 = new Static3D(+X,MAX_YZ,MAX_YZ);
988
    Static3D scale8 = new Static3D(-X,MAX_YZ,MAX_YZ);
989

    
990
    VertexEffect[] effect = new VertexEffect[9];
991

    
992
    effect[0] = new VertexEffectMove(move);
993
    effect[1] = new VertexEffectRotate(angle, axisX, center);
994
    effect[2] = new VertexEffectRotate(angle, axisY, center);
995
    effect[3] = new VertexEffectScale(scale3);
996
    effect[4] = new VertexEffectScale(scale4);
997
    effect[5] = new VertexEffectScale(scale5);
998
    effect[6] = new VertexEffectScale(scale6);
999
    effect[7] = new VertexEffectScale(scale7);
1000
    effect[8] = new VertexEffectScale(scale8);
1001

    
1002
    effect[1].setMeshAssociation(12,-1);  // meshes 2,3
1003
    effect[2].setMeshAssociation( 3,-1);  // meshes 0,1
1004
    effect[3].setMeshAssociation(16,-1);  // mesh 4
1005
    effect[4].setMeshAssociation(32,-1);  // mesh 5
1006
    effect[5].setMeshAssociation( 8,-1);  // mesh 3
1007
    effect[6].setMeshAssociation( 4,-1);  // mesh 2
1008
    effect[7].setMeshAssociation( 1,-1);  // mesh 0
1009
    effect[8].setMeshAssociation( 2,-1);  // mesh 1
1010

    
1011
    return effect;
1012
    }
1013

    
1014
///////////////////////////////////////////////////////////////////////////////////////////////////
1015
// OBJECTS
1016
///////////////////////////////////////////////////////////////////////////////////////////////////
1017

    
1018
  public MeshBase createIvyCornerMesh()
1019
    {
1020
    MeshBase mesh = createFacesIvyCorner();
1021
    VertexEffect[] effects = createVertexEffectsIvyCorner();
1022
    for( VertexEffect effect : effects ) mesh.apply(effect);
1023

    
1024
    Static3D center = new Static3D(-0.5f,-0.5f,-0.5f);
1025
    Static3D[] vertices = new Static3D[4];
1026
    vertices[0] = new Static3D(+0.0f,+0.0f,+0.0f);
1027
    vertices[1] = new Static3D(-1.0f,+0.0f,+0.0f);
1028
    vertices[2] = new Static3D(+0.0f,-1.0f,+0.0f);
1029
    vertices[3] = new Static3D(+0.0f,+0.0f,-1.0f);
1030

    
1031
    roundCorners(mesh,center,vertices,0.03f,0.10f);
1032

    
1033
    mesh.mergeEffComponents();
1034

    
1035
    return mesh;
1036
    }
1037

    
1038
///////////////////////////////////////////////////////////////////////////////////////////////////
1039

    
1040
  public MeshBase createIvyFaceMesh()
1041
    {
1042
    MeshBase mesh = createFacesIvyFace();
1043

    
1044
    Static3D center = new Static3D(-0.0f,-0.0f,-0.5f);
1045
    Static3D[] vertices = new Static3D[2];
1046
    vertices[0] = new Static3D(-0.5f,+0.5f,+0.0f);
1047
    vertices[1] = new Static3D(+0.5f,-0.5f,+0.0f);
1048

    
1049
    roundCorners(mesh,center,vertices,0.03f,0.10f);
1050

    
1051
    mesh.mergeEffComponents();
1052
    mesh.addEmptyTexComponent();
1053
    mesh.addEmptyTexComponent();
1054
    mesh.addEmptyTexComponent();
1055
    mesh.addEmptyTexComponent();
1056

    
1057
    return mesh;
1058
    }
1059

    
1060
///////////////////////////////////////////////////////////////////////////////////////////////////
1061

    
1062
  public MeshBase createRexCornerMesh()
1063
    {
1064
    MeshBase mesh = createFacesRexCorner();
1065
    VertexEffect[] effects = createVertexEffectsRexCorner();
1066
    for( VertexEffect effect : effects ) mesh.apply(effect);
1067

    
1068
    final float G = (1-REX_D)/3;
1069
    Static3D center = new Static3D(0.0f,0.0f,-G*SQ2/2);
1070
    Static3D[] vertices = new Static3D[1];
1071
    vertices[0] = new Static3D(+G,-G,+0.0f);
1072
    roundCorners(mesh,center,vertices,0.10f,0.10f);
1073

    
1074
    mesh.mergeEffComponents();
1075
    mesh.addEmptyTexComponent();
1076
    mesh.addEmptyTexComponent();
1077
    mesh.addEmptyTexComponent();
1078
    mesh.addEmptyTexComponent();
1079

    
1080
    return mesh;
1081
    }
1082

    
1083
///////////////////////////////////////////////////////////////////////////////////////////////////
1084

    
1085
  public MeshBase createRexFaceMesh()
1086
    {
1087
    MeshBase mesh = createFacesRexFace();
1088

    
1089
    mesh.mergeEffComponents();
1090
    mesh.addEmptyTexComponent();
1091
    mesh.addEmptyTexComponent();
1092
    mesh.addEmptyTexComponent();
1093
    mesh.addEmptyTexComponent();
1094

    
1095
    return mesh;
1096
    }
1097

    
1098
///////////////////////////////////////////////////////////////////////////////////////////////////
1099

    
1100
  public MeshBase createRexEdgeMesh()
1101
    {
1102
    MeshBase mesh = createFacesRexEdge();
1103
    VertexEffect[] effects = createVertexEffectsRexEdge();
1104
    for( VertexEffect effect : effects ) mesh.apply(effect);
1105

    
1106
    Static3D center = new Static3D(0.0f,-0.5f,-0.5f);
1107
    Static3D[] vertices = new Static3D[2];
1108
    vertices[0] = new Static3D(+0.5f,+0.0f,+0.0f);
1109
    vertices[1] = new Static3D(-0.5f,+0.0f,+0.0f);
1110
    roundCorners(mesh,center,vertices,0.06f,0.10f);
1111

    
1112
    mesh.mergeEffComponents();
1113

    
1114
    return mesh;
1115
    }
1116

    
1117
///////////////////////////////////////////////////////////////////////////////////////////////////
1118

    
1119
  public MeshBase createKilominxCenterMesh(float width)
1120
    {
1121
    MeshBase mesh = createFacesKilominxCenter();
1122
    VertexEffect[] effects = createVertexEffectsKilominxCenter(width);
1123
    for( VertexEffect effect : effects ) mesh.apply(effect);
1124

    
1125
    float A = (2*SQ3/3)* SIN54;
1126
    float B = 0.4f;
1127
    float X = SIN_HALFD * SIN54 *COS54  ;
1128
    float Y = SIN54 * SIN54 - 0.5f;
1129
    float Z = COS_HALFD* SIN54 *COS54  ;
1130

    
1131
    Static3D center = new Static3D(0.0f, -(float)Math.sqrt(1-A*A)*B,-A*B);
1132

    
1133
    Static3D[] vertices = new Static3D[4];
1134
    vertices[0] = new Static3D( 0.0f, 0.0f, 0.0f);
1135
    vertices[1] = new Static3D( 0.0f,-0.5f, 0.0f);
1136
    vertices[2] = new Static3D(-X   , Y   ,-Z   );
1137
    vertices[3] = new Static3D(+X   , Y   ,-Z   );
1138

    
1139
    roundCorners(mesh,center,vertices,0.03f,0.10f);
1140

    
1141
    mesh.mergeEffComponents();
1142

    
1143
    return mesh;
1144
    }
1145

    
1146
///////////////////////////////////////////////////////////////////////////////////////////////////
1147
// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
1148
// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
1149

    
1150
  public MeshBase createKilominxEdgeMesh(int numLayers, float width, float height, boolean left)
1151
    {
1152
    MeshBase mesh = createFacesKilominxEdge(numLayers,width,height);
1153
    VertexEffect[] effects = createVertexEffectsKilominxEdge(width,height,left);
1154
    for( VertexEffect effect : effects ) mesh.apply(effect);
1155

    
1156
// round...
1157

    
1158
    mesh.mergeEffComponents();
1159

    
1160
    return mesh;
1161
    }
1162

    
1163
///////////////////////////////////////////////////////////////////////////////////////////////////
1164

    
1165
  public MeshBase createMinxCornerMesh(int numLayers, float width)
1166
    {
1167
    MeshBase mesh = createFacesMinxCorner(numLayers);
1168
    VertexEffect[] effects = createVertexEffectsMinxCorner(width);
1169
    for( VertexEffect effect : effects ) mesh.apply(effect);
1170

    
1171
    float A = (2*SQ3/3)* SIN54;
1172
    float B = 0.4f;
1173
/*
1174
    float X = SIN_HALFD* SIN54 * COS54;
1175
    float Y = SIN54 * SIN54 - 0.5f;
1176
    float Z = COS_HALFD* SIN54 * COS54;
1177
    float S = 2*width;
1178
*/
1179
    Static3D center = new Static3D(0.0f, -(float)Math.sqrt(1-A*A)*B,-A*B);
1180
    Static3D[] vertices = new Static3D[1];
1181
    vertices[0] = new Static3D( 0.0f, 0.0f  , 0.0f);
1182
/*
1183
    vertices[1] = new Static3D( 0.0f,-0.5f*S, 0.0f);
1184
    vertices[2] = new Static3D(-X*S , Y*S   ,-Z*S );
1185
    vertices[3] = new Static3D(+X*S , Y*S   ,-Z*S );
1186
*/
1187
    roundCorners(mesh,center,vertices,0.04f,0.10f);
1188

    
1189
    mesh.mergeEffComponents();
1190

    
1191
    return mesh;
1192
    }
1193

    
1194
///////////////////////////////////////////////////////////////////////////////////////////////////
1195
// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
1196
// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
1197

    
1198
  public MeshBase createMegaminxEdgeMesh(int numLayers, float width, float height)
1199
    {
1200
    MeshBase mesh = createFacesMegaminxEdge(numLayers,width,height);
1201
    VertexEffect[] effects = createVertexEffectsMegaminxEdge(width,height);
1202
    for( VertexEffect effect : effects ) mesh.apply(effect);
1203

    
1204
    mesh.mergeEffComponents();
1205

    
1206
    return mesh;
1207
    }
1208

    
1209
///////////////////////////////////////////////////////////////////////////////////////////////////
1210

    
1211
  public MeshBase createMegaminxCenterMesh(int numLayers, float width)
1212
    {
1213
    MeshBase mesh = createFacesMegaminxCenter(numLayers);
1214
    VertexEffect[] effects = createVertexEffectsMegaminxCenter(width);
1215
    for( VertexEffect effect : effects ) mesh.apply(effect);
1216

    
1217
    mesh.mergeEffComponents();
1218
    mesh.addEmptyTexComponent();
1219
    mesh.addEmptyTexComponent();
1220
    mesh.addEmptyTexComponent();
1221
    mesh.addEmptyTexComponent();
1222

    
1223
    return mesh;
1224
    }
1225

    
1226
///////////////////////////////////////////////////////////////////////////////////////////////////
1227

    
1228
  public MeshBase createCuboidMesh(int[] dimensions)
1229
    {
1230
    MeshBase mesh = createCuboid(dimensions);
1231
    VertexEffect[] effects = createCuboidEffects(dimensions);
1232
    for( VertexEffect effect : effects ) mesh.apply(effect);
1233

    
1234
    int X = dimensions[0];
1235
    int Y = dimensions[1];
1236
    int Z = dimensions[2];
1237

    
1238
    float strength = 0.04f;
1239
    float radius   = 0.15f;
1240

    
1241
    Static3D[] vertices = new Static3D[1];
1242
    Static3D center;
1243

    
1244
    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,+0.5f*Z);
1245
    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
1246
    roundCorners(mesh, center, vertices, strength, radius);
1247

    
1248
    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,-0.5f*Z);
1249
    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
1250
    roundCorners(mesh, center, vertices, strength, radius);
1251

    
1252
    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,+0.5f*Z);
1253
    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
1254
    roundCorners(mesh, center, vertices, strength, radius);
1255

    
1256
    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,-0.5f*Z);
1257
    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
1258
    roundCorners(mesh, center, vertices, strength, radius);
1259

    
1260
    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,+0.5f*Z);
1261
    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
1262
    roundCorners(mesh, center, vertices, strength, radius);
1263

    
1264
    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,-0.5f*Z);
1265
    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
1266
    roundCorners(mesh, center, vertices, strength, radius);
1267

    
1268
    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,+0.5f*Z);
1269
    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
1270
    roundCorners(mesh, center, vertices, strength, radius);
1271

    
1272
    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,-0.5f*Z);
1273
    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
1274
    roundCorners(mesh, center, vertices, strength, radius);
1275

    
1276
    mesh.mergeEffComponents();
1277

    
1278
    return mesh;
1279
    }
1280

    
1281

    
1282

    
1283

    
1284
///////////////////////////////////////////////////////////////////////////////////////////////////
1285

    
1286
  private boolean areColinear(double[][] vertices, int index1, int index2, int index3)
1287
    {
1288
    double x1 = vertices[index1][0];
1289
    double y1 = vertices[index1][1];
1290
    double z1 = vertices[index1][2];
1291
    double x2 = vertices[index2][0];
1292
    double y2 = vertices[index2][1];
1293
    double z2 = vertices[index2][2];
1294
    double x3 = vertices[index3][0];
1295
    double y3 = vertices[index3][1];
1296
    double z3 = vertices[index3][2];
1297

    
1298
    double v1x = x2-x1;
1299
    double v1y = y2-y1;
1300
    double v1z = z2-z1;
1301
    double v2x = x3-x1;
1302
    double v2y = y3-y1;
1303
    double v2z = z3-z1;
1304

    
1305
    double A = Math.sqrt( (v1x*v1x+v1y*v1y+v1z*v1z) / (v2x*v2x+v2y*v2y+v2z*v2z) );
1306

    
1307
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
1308
    }
1309

    
1310
///////////////////////////////////////////////////////////////////////////////////////////////////
1311

    
1312
  private void computeNormalVector(double[][] vertices, int index1, int index2, int index3)
1313
    {
1314
    double x1 = vertices[index1][0];
1315
    double y1 = vertices[index1][1];
1316
    double z1 = vertices[index1][2];
1317
    double x2 = vertices[index2][0];
1318
    double y2 = vertices[index2][1];
1319
    double z2 = vertices[index2][2];
1320
    double x3 = vertices[index3][0];
1321
    double y3 = vertices[index3][1];
1322
    double z3 = vertices[index3][2];
1323

    
1324
    double v1x = x2-x1;
1325
    double v1y = y2-y1;
1326
    double v1z = z2-z1;
1327
    double v2x = x3-x1;
1328
    double v2y = y3-y1;
1329
    double v2z = z3-z1;
1330

    
1331
    mBuffer[0] = v1y*v2z - v2y*v1z;
1332
    mBuffer[1] = v1z*v2x - v2z*v1x;
1333
    mBuffer[2] = v1x*v2y - v2x*v1y;
1334

    
1335
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
1336
    len = Math.sqrt(len);
1337
    mBuffer[0] /= len;
1338
    mBuffer[1] /= len;
1339
    mBuffer[2] /= len;
1340
    }
1341

    
1342
///////////////////////////////////////////////////////////////////////////////////////////////////
1343
// return quat1*quat2
1344

    
1345
  private static void quatMultiply( double[] quat1, double[] quat2, double[] result )
1346
    {
1347
    double qx = quat1[0];
1348
    double qy = quat1[1];
1349
    double qz = quat1[2];
1350
    double qw = quat1[3];
1351

    
1352
    double rx = quat2[0];
1353
    double ry = quat2[1];
1354
    double rz = quat2[2];
1355
    double rw = quat2[3];
1356

    
1357
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
1358
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
1359
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
1360
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
1361
    }
1362

    
1363
///////////////////////////////////////////////////////////////////////////////////////////////////
1364

    
1365
  private void fitInSquare(FaceTransform info, double[][] vert3D)
1366
    {
1367
    double minX = Double.MAX_VALUE;
1368
    double maxX =-Double.MAX_VALUE;
1369
    double minY = Double.MAX_VALUE;
1370
    double maxY =-Double.MAX_VALUE;
1371

    
1372
    for (double[] vert : vert3D)
1373
      {
1374
      double x = vert[0];
1375
      double y = vert[1];
1376

    
1377
      if (x > maxX) maxX = x;
1378
      if (x < minX) minX = x;
1379
      if (y > maxY) maxY = y;
1380
      if (y < minY) minY = y;
1381
      }
1382

    
1383
    minX = minX<0 ? -minX:minX;
1384
    maxX = maxX<0 ? -maxX:maxX;
1385
    minY = minY<0 ? -minY:minY;
1386
    maxY = maxY<0 ? -maxY:maxY;
1387

    
1388
    double max1 = Math.max(minX,minY);
1389
    double max2 = Math.max(maxX,maxY);
1390
    double max3 = Math.max(max1,max2);
1391

    
1392
    info.scale = max3/0.5;
1393

    
1394
    int len = vert3D.length;
1395
    StickerCoords sInfo = new StickerCoords();
1396
    sInfo.vertices = new double[2*len];
1397

    
1398
    for( int vertex=0; vertex<len; vertex++ )
1399
      {
1400
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
1401
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
1402
      }
1403

    
1404
    mStickerCoords.add(sInfo);
1405

    
1406
    info.sticker = mStickerCoords.size() -1;
1407
    info.flip = false;
1408
    }
1409

    
1410
///////////////////////////////////////////////////////////////////////////////////////////////////
1411

    
1412
  private FaceTransform constructNewTransform(final double[][] vert3D)
1413
    {
1414
    FaceTransform ft = new FaceTransform();
1415

    
1416
    // compute center of gravity
1417
    ft.vx = 0.0f;
1418
    ft.vy = 0.0f;
1419
    ft.vz = 0.0f;
1420
    int len = vert3D.length;
1421

    
1422
    for (double[] vert : vert3D)
1423
      {
1424
      ft.vx += vert[0];
1425
      ft.vy += vert[1];
1426
      ft.vz += vert[2];
1427
      }
1428

    
1429
    ft.vx /= len;
1430
    ft.vy /= len;
1431
    ft.vz /= len;
1432

    
1433
    // move all vertices so that their center of gravity is at (0,0,0)
1434
    for (int i=0; i<len; i++)
1435
      {
1436
      vert3D[i][0] -= ft.vx;
1437
      vert3D[i][1] -= ft.vy;
1438
      vert3D[i][2] -= ft.vz;
1439
      }
1440

    
1441
    // find 3 non-colinear vertices
1442
    int foundIndex = -1;
1443

    
1444
    for(int vertex=2; vertex<len; vertex++)
1445
      {
1446
      if( !areColinear(vert3D,0,1,vertex) )
1447
        {
1448
        foundIndex = vertex;
1449
        break;
1450
        }
1451
      }
1452

    
1453
    // compute the normal vector
1454
    if( foundIndex==-1 )
1455
      {
1456
      throw new RuntimeException("all vertices colinear");
1457
      }
1458

    
1459
    computeNormalVector(vert3D,0,1,foundIndex);
1460

    
1461
    // rotate so that the normal vector becomes (0,0,1)
1462
    double axisX, axisY, axisZ;
1463

    
1464
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
1465
      {
1466
      axisX = -mBuffer[1];
1467
      axisY =  mBuffer[0];
1468
      axisZ = 0.0f;
1469

    
1470
      double axiLen = axisX*axisX + axisY*axisY;
1471
      axiLen = Math.sqrt(axiLen);
1472
      axisX /= axiLen;
1473
      axisY /= axiLen;
1474
      axisZ /= axiLen;
1475
      }
1476
    else
1477
      {
1478
      axisX = 0.0f;
1479
      axisY = 1.0f;
1480
      axisZ = 0.0f;
1481
      }
1482

    
1483
    double cosTheta = mBuffer[2];
1484
    double sinTheta = Math.sqrt(1-cosTheta*cosTheta);
1485
    double sinHalfTheta = computeSinHalf(cosTheta);
1486
    double cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
1487

    
1488
    mQuat1[0] = axisX*sinHalfTheta;
1489
    mQuat1[1] = axisY*sinHalfTheta;
1490
    mQuat1[2] = axisZ*sinHalfTheta;
1491
    mQuat1[3] = cosHalfTheta;
1492
    mQuat2[0] =-axisX*sinHalfTheta;
1493
    mQuat2[1] =-axisY*sinHalfTheta;
1494
    mQuat2[2] =-axisZ*sinHalfTheta;
1495
    mQuat2[3] = cosHalfTheta;
1496

    
1497
    for (double[] vert : vert3D)
1498
      {
1499
      quatMultiply(mQuat1, vert  , mQuat3);
1500
      quatMultiply(mQuat3, mQuat2, vert  );
1501
      }
1502

    
1503
    // fit the whole thing in a square and remember the scale & 2D vertices
1504
    fitInSquare(ft, vert3D);
1505

    
1506
    // remember the rotation
1507
    ft.qx =-mQuat1[0];
1508
    ft.qy =-mQuat1[1];
1509
    ft.qz =-mQuat1[2];
1510
    ft.qw = mQuat1[3];
1511

    
1512
    return ft;
1513
    }
1514

    
1515
///////////////////////////////////////////////////////////////////////////////////////////////////
1516

    
1517
  private double computeCos(double oldX, double oldY, double newX, double newY, double len1, double len2)
1518
    {
1519
    double ret= (oldX*newX+oldY*newY) / (len1*len2);
1520
    if( ret<-1.0 ) return -1.0;
1521
    if( ret> 1.0 ) return  1.0;
1522

    
1523
    return ret;
1524
    }
1525

    
1526
///////////////////////////////////////////////////////////////////////////////////////////////////
1527
// sin of (signed!) angle between vectors 'old' and 'new', counterclockwise!
1528

    
1529
  private double computeSin(double oldX, double oldY, double newX, double newY, double len1, double len2)
1530
    {
1531
    double ret= (newX*oldY-oldX*newY) / (len1*len2);
1532
    if( ret<-1.0 ) return -1.0;
1533
    if( ret> 1.0 ) return  1.0;
1534

    
1535
    return ret;
1536
    }
1537

    
1538
///////////////////////////////////////////////////////////////////////////////////////////////////
1539

    
1540
  private void rotateAllVertices(double[] result, int len, double[] vertices, double sin, double cos)
1541
    {
1542
    for(int i=0; i<len; i++)
1543
      {
1544
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
1545
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
1546
      }
1547
    }
1548

    
1549
///////////////////////////////////////////////////////////////////////////////////////////////////
1550

    
1551
  private double computeScale(double[] v1, double[] v2, int v1i, int v2i)
1552
    {
1553
    double v1x = v1[2*v1i];
1554
    double v1y = v1[2*v1i+1];
1555
    double v2x = v2[2*v2i];
1556
    double v2y = v2[2*v2i+1];
1557

    
1558
    double lenSq1 = v1x*v1x + v1y*v1y;
1559
    double lenSq2 = v2x*v2x + v2y*v2y;
1560

    
1561
    return Math.sqrt(lenSq2/lenSq1);
1562
    }
1563

    
1564
///////////////////////////////////////////////////////////////////////////////////////////////////
1565
// valid for 0<angle<2*PI
1566

    
1567
  private double computeSinHalf(double cos)
1568
    {
1569
    return Math.sqrt((1-cos)/2);
1570
    }
1571

    
1572
///////////////////////////////////////////////////////////////////////////////////////////////////
1573
// valid for 0<angle<2*PI
1574

    
1575
  private double computeCosHalf(double sin, double cos)
1576
    {
1577
    double cosHalf = Math.sqrt((1+cos)/2);
1578
    return sin<0 ? -cosHalf : cosHalf;
1579
    }
1580

    
1581
///////////////////////////////////////////////////////////////////////////////////////////////////
1582

    
1583
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
1584
    {
1585
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
1586
    if( v>=len ) v-=len;
1587
    if( v< 0   ) v+=len;
1588

    
1589
    return v;
1590
    }
1591

    
1592
///////////////////////////////////////////////////////////////////////////////////////////////////
1593

    
1594
  private boolean isScaledVersionOf(double[] newVert, double[] oldVert, int len, int vertex, boolean inverted)
1595
    {
1596
    int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
1597
    double EPSILON = 0.001;
1598
    double scale = computeScale(newVert,oldVert,newZeroIndex,0);
1599

    
1600
    for(int i=1; i<len; i++)
1601
      {
1602
      int index = computeRotatedIndex(i,len,vertex,inverted);
1603

    
1604
      double horz = oldVert[2*i  ] - scale*newVert[2*index  ];
1605
      double vert = oldVert[2*i+1] - scale*newVert[2*index+1];
1606

    
1607
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
1608
      }
1609

    
1610
    return true;
1611
    }
1612

    
1613
///////////////////////////////////////////////////////////////////////////////////////////////////
1614

    
1615
  private void mirrorAllVertices(double[] output, int len, double[] input)
1616
    {
1617
    for(int vertex=0; vertex<len; vertex++)
1618
      {
1619
      output[2*vertex  ] = input[2*vertex  ];
1620
      output[2*vertex+1] =-input[2*vertex+1];
1621
      }
1622
    }
1623

    
1624
///////////////////////////////////////////////////////////////////////////////////////////////////
1625

    
1626
  private void correctInfo(FaceTransform info, double scale, double sin, double cos, int oldSticker, boolean flip)
1627
    {
1628
    mStickerCoords.remove(info.sticker);
1629

    
1630
    info.flip    = flip;
1631
    info.sticker = oldSticker;
1632
    info.scale  *= scale;
1633

    
1634
    mQuat1[0] = info.qx;
1635
    mQuat1[1] = info.qy;
1636
    mQuat1[2] = info.qz;
1637
    mQuat1[3] = info.qw;
1638

    
1639
    double sinHalf = computeSinHalf(cos);
1640
    double cosHalf = computeCosHalf(sin,cos);
1641

    
1642
    if( flip )
1643
      {
1644
      mQuat3[0] = 0.0f;
1645
      mQuat3[1] = 0.0f;
1646
      mQuat3[2] = sinHalf;
1647
      mQuat3[3] = cosHalf;
1648

    
1649
      mQuat4[0] = 1.0;
1650
      mQuat4[1] = 0.0;
1651
      mQuat4[2] = 0.0;
1652
      mQuat4[3] = 0.0;
1653

    
1654
      quatMultiply( mQuat3, mQuat4, mQuat2 );
1655
      }
1656
    else
1657
      {
1658
      mQuat2[0] = 0.0f;
1659
      mQuat2[1] = 0.0f;
1660
      mQuat2[2] = sinHalf;
1661
      mQuat2[3] = cosHalf;
1662
      }
1663

    
1664
    quatMultiply( mQuat1, mQuat2, mQuat3 );
1665

    
1666
    info.qx = mQuat3[0];
1667
    info.qy = mQuat3[1];
1668
    info.qz = mQuat3[2];
1669
    info.qw = mQuat3[3];
1670
    }
1671

    
1672
///////////////////////////////////////////////////////////////////////////////////////////////////
1673

    
1674
  private void printVert(double[] buffer)
1675
    {
1676
    int len = buffer.length/2;
1677
    String str = "";
1678

    
1679
    for(int i=0; i<len; i++)
1680
      {
1681
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
1682
      }
1683

    
1684
    android.util.Log.d("D", str);
1685
    }
1686

    
1687
///////////////////////////////////////////////////////////////////////////////////////////////////
1688

    
1689
  private boolean foundVertex(FaceTransform info, double[] buffer, int len, double[] newVert,
1690
                              double[] oldVert, double lenFirstOld, int oldSticker, boolean inverted)
1691
    {
1692
    for(int vertex=0; vertex<len; vertex++)
1693
      {
1694
      double newX = newVert[2*vertex  ];
1695
      double newY = newVert[2*vertex+1];
1696
      double lenIthNew = Math.sqrt(newX*newX + newY*newY);
1697
      double cos = computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
1698
      double sin = computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
1699

    
1700
      rotateAllVertices(buffer,len,newVert,sin,cos);
1701

    
1702
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
1703
        {
1704
        int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
1705
        double scale = computeScale(oldVert,newVert,0,newZeroIndex);
1706
        correctInfo(info,scale,sin,cos,oldSticker,inverted);
1707
        return true;
1708
        }
1709
      }
1710

    
1711
    return false;
1712
    }
1713

    
1714
///////////////////////////////////////////////////////////////////////////////////////////////////
1715

    
1716
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
1717
    {
1718
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
1719
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
1720
    double[] newVert = sNewInfo.vertices;
1721
    double[] oldVert = sOldInfo.vertices;
1722
    int oldLen = oldVert.length;
1723
    int newLen = newVert.length;
1724

    
1725
    if( oldLen == newLen )
1726
      {
1727
      int oldSticker = oldInfo.sticker;
1728
      double[] buffer1 = new double[oldLen];
1729
      double lenFirstOld = Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
1730
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) ) return true;
1731
      double[] buffer2 = new double[oldLen];
1732
      mirrorAllVertices(buffer2, newLen/2, newVert);
1733
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) ) return true;
1734
      }
1735

    
1736
    return false;
1737
    }
1738

    
1739
///////////////////////////////////////////////////////////////////////////////////////////////////
1740

    
1741
  private double[][] constructVert(double[][] vertices, int[] index)
1742
    {
1743
    int len = index.length;
1744
    double[][] ret = new double[len][4];
1745

    
1746
    for(int i=0; i<len; i++)
1747
      {
1748
      ret[i][0] = vertices[index[i]][0];
1749
      ret[i][1] = vertices[index[i]][1];
1750
      ret[i][2] = vertices[index[i]][2];
1751
      ret[i][3] = 1.0f;
1752
      }
1753

    
1754
    return ret;
1755
    }
1756

    
1757
///////////////////////////////////////////////////////////////////////////////////////////////////
1758

    
1759
  private void prepareAndRoundCorners(MeshBase mesh, double[][] vertices,
1760
                                      float[][] corners, int[] cornerIndexes,
1761
                                      float[][] centers, int[] centerIndexes )
1762
    {
1763
    int lenV = vertices.length;
1764
    Static3D[] staticVert = new Static3D[1];
1765
    Static3D center = new Static3D(0,0,0);
1766

    
1767
    for(int v=0; v<lenV; v++)
1768
      {
1769
      staticVert[0] = new Static3D( (float)vertices[v][0], (float)vertices[v][1], (float)vertices[v][2]);
1770

    
1771
      int cent = centerIndexes[v];
1772

    
1773
      if( cent>=0 )
1774
        {
1775
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
1776

    
1777
        int corn = cornerIndexes[v];
1778
        float strength = corners[corn][0];
1779
        float radius   = corners[corn][1];
1780

    
1781
        roundCorners(mesh, center, staticVert, strength, radius);
1782
        }
1783
      }
1784
    }
1785

    
1786
///////////////////////////////////////////////////////////////////////////////////////////////////
1787

    
1788
  private void correctComponents(MeshBase mesh, int numComponents)
1789
    {
1790
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
1791

    
1792
    mesh.mergeEffComponents();
1793

    
1794
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
1795
    }
1796

    
1797
///////////////////////////////////////////////////////////////////////////////////////////////////
1798

    
1799
  private void printTransform(FaceTransform f)
1800
    {
1801
    android.util.Log.e("D", "q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
1802
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
1803
    }
1804

    
1805
///////////////////////////////////////////////////////////////////////////////////////////////////
1806
// PUBLIC
1807

    
1808
  public void printStickerCoords()
1809
    {
1810
    int stickers = mStickerCoords.size();
1811

    
1812
    android.util.Log.d("D", "---- STICKER COORDS ----");
1813

    
1814
    for(int s=0; s<stickers; s++)
1815
      {
1816
      String ver = "{ ";
1817
      StickerCoords info = mStickerCoords.get(s);
1818
      int len = info.vertices.length/2;
1819

    
1820
      for(int i =0; i<len; i++)
1821
        {
1822
        if( i!=0 ) ver += ", ";
1823
        ver += ( (float)info.vertices[2*i]+"f, "+(float)info.vertices[2*i+1]+"f");
1824
        }
1825

    
1826
      ver += " }";
1827
      android.util.Log.d("D", ver);
1828
      }
1829

    
1830
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1831
    }
1832

    
1833
///////////////////////////////////////////////////////////////////////////////////////////////////
1834

    
1835
  public void printFaceTransform()
1836
    {
1837
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1838

    
1839
    int oldfaces = mOldFaceTransf.size();
1840

    
1841
    for(int f=0; f<oldfaces; f++)
1842
      {
1843
      printTransform(mOldFaceTransf.get(f));
1844
      }
1845

    
1846
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1847

    
1848
    int newfaces = mNewFaceTransf.size();
1849

    
1850
    for(int f=0; f<newfaces; f++)
1851
      {
1852
      printTransform(mNewFaceTransf.get(f));
1853
      }
1854
    }
1855

    
1856
///////////////////////////////////////////////////////////////////////////////////////////////////
1857

    
1858
  public void clear()
1859
    {
1860
    mStickerCoords.clear();
1861
    mNewFaceTransf.clear();
1862
    mOldFaceTransf.clear();
1863
    }
1864

    
1865
///////////////////////////////////////////////////////////////////////////////////////////////////
1866

    
1867
  public void createNewFaceTransform( final double[][] vertices, final int[][] indexes)
1868
    {
1869
    FaceTransform ft;
1870
    int numNew = mNewFaceTransf.size();
1871

    
1872
    for(int i=0; i<numNew; i++)
1873
      {
1874
      ft = mNewFaceTransf.remove(0);
1875
      mOldFaceTransf.add(ft);
1876
      }
1877

    
1878
    int numFaces = indexes.length;
1879
    int numOld = mOldFaceTransf.size();
1880

    
1881
    for (int face=0; face<numFaces; face++)
1882
      {
1883
      boolean collapsed = false;
1884

    
1885
      double[][] vert = constructVert(vertices, indexes[face]);
1886
      FaceTransform newT = constructNewTransform(vert);
1887

    
1888
      for (int old=0; !collapsed && old<numOld; old++)
1889
        {
1890
        ft = mOldFaceTransf.get(old);
1891
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1892
        }
1893

    
1894
      for (int pre=0; !collapsed && pre<face; pre++)
1895
        {
1896
        ft = mNewFaceTransf.get(pre);
1897
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1898
        }
1899

    
1900
      mNewFaceTransf.add(newT);
1901
      }
1902
    }
1903

    
1904
///////////////////////////////////////////////////////////////////////////////////////////////////
1905

    
1906
  public MeshBase createRoundedSolid(final double[][] vertices, final int[][] vertIndexes,
1907
                                     final float[][] bands    , final int[]   bandIndexes,
1908
                                     final float[][] corners  , final int[]   cornerIndexes,
1909
                                     final float[][] centers  , final int[]   centerIndexes,
1910
                                     final int numComponents )
1911
    {
1912
    int numFaces = vertIndexes.length;
1913
    float[] band, bandsComputed;
1914
    MeshBase[] meshes = new MeshBase[numFaces];
1915
    FaceTransform fInfo;
1916
    StickerCoords sInfo;
1917

    
1918
    for(int face=0; face<numFaces; face++)
1919
      {
1920
      fInfo = mNewFaceTransf.get(face);
1921
      sInfo = mStickerCoords.get(fInfo.sticker);
1922

    
1923
      double[] verts = sInfo.vertices;
1924
      int lenVerts = verts.length;
1925
      float[] vertsFloat = new float[lenVerts];
1926
      for(int i=0; i<lenVerts; i++) vertsFloat[i] = (float)verts[i];
1927

    
1928
      band = bands[bandIndexes[face]];
1929
      bandsComputed = computeBands( band[0], (int)band[1], band[2], band[3], (int)band[4]);
1930
      meshes[face] = new MeshPolygon(vertsFloat,bandsComputed,(int)band[5],(int)band[6]);
1931
      meshes[face].setEffectAssociation(0,(1<<face),0);
1932
      }
1933

    
1934
    MeshBase mesh = new MeshJoined(meshes);
1935
    Static3D center = new Static3D(0,0,0);
1936

    
1937
    for(int face=0; face<numFaces; face++)
1938
      {
1939
      int assoc = (1<<face);
1940
      fInfo = mNewFaceTransf.get(face);
1941

    
1942
      float vx = (float)fInfo.vx;
1943
      float vy = (float)fInfo.vy;
1944
      float vz = (float)fInfo.vz;
1945
      float sc = (float)fInfo.scale;
1946
      float qx = (float)fInfo.qx;
1947
      float qy = (float)fInfo.qy;
1948
      float qz = (float)fInfo.qz;
1949
      float qw = (float)fInfo.qw;
1950

    
1951
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
1952
      Static3D move3D= new Static3D(vx,vy,vz);
1953
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1954

    
1955
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
1956
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
1957
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
1958
      }
1959

    
1960
    prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
1961

    
1962
    correctComponents(mesh,numComponents);
1963

    
1964
    return mesh;
1965
    }
1966
  }
(3-3/4)