Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / FactoryCubit.java @ 308e497b

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.helpers;
11

    
12
import org.distorted.library.effect.EffectName;
13
import org.distorted.library.effect.MatrixEffectMove;
14
import org.distorted.library.effect.MatrixEffectQuaternion;
15
import org.distorted.library.effect.MatrixEffectScale;
16
import org.distorted.library.effect.VertexEffect;
17
import org.distorted.library.helpers.QuatHelper;
18
import org.distorted.library.mesh.MeshBase;
19
import org.distorted.library.mesh.MeshJoined;
20
import org.distorted.library.mesh.MeshMultigon;
21
import org.distorted.library.mesh.MeshPolygon;
22
import org.distorted.library.type.Static3D;
23
import org.distorted.library.type.Static4D;
24

    
25
import java.util.ArrayList;
26

    
27
import static org.distorted.objectlib.main.TwistyObject.MESH_FAST;
28
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
29

    
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

    
32
public class FactoryCubit
33
  {
34
  private static FactoryCubit mThis;
35

    
36
  private static final float MAX_CORE_DIFF = 0.01f;
37

    
38
  private static final float[] mBuffer = new float[3];
39
  private static final float[] mQuat1  = new float[4];
40
  private static final float[] mQuat2  = new float[4];
41
  private static final float[] mQuat3  = new float[4];
42

    
43
  public static final String NAME = EffectName.DEFORM.name();
44

    
45
  private static class StickerCoords
46
    {
47
    float[] vertices;
48
    float[][] fullVertices;
49
    float scale;
50
    boolean outer;
51
    }
52

    
53
  private static class FaceTransform
54
    {
55
    int face;
56
    int numFaces;
57

    
58
    int sticker;
59
    float vx,vy,vz;
60
    float scale;
61
    float qx,qy,qz,qw;
62
    }
63

    
64
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
65
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
66
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
67

    
68
///////////////////////////////////////////////////////////////////////////////////////////////////
69

    
70
  private FactoryCubit()
71
    {
72

    
73
    }
74

    
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76
// H - height of the band in the middle
77
// alpha - angle of the edge  [0,90]
78
// dist - often in a polygon the distance from edge to center is not 1, but something else.
79
// This is the distance.
80
// K - where to begin the second, much more flat part of the band. [0,1]
81
// N - number of bands. N>=3
82
//
83
// theory: two distinct parts to the band:
84
// 1) (0,B) - steep
85
// 2) (B,1) - flat
86
//
87
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
88
//
89
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
90
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
91
// h(x) = R*(sin(alpha) - sin(x))
92
// R = H/(1-cos(alpha))
93
// D = H*sin(alpha)
94
// B = h(K*alpha)
95
//
96
// The N points are taken at:
97
//
98
// 1) in the second part, there are K2 = (N-3)/3 such points
99
// 2) in the first - K1 = (N-3) - K2
100
// 3) also, the 3 points 0,B,1
101
//
102
// so we have the sequence A[i] of N points
103
//
104
// 0
105
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
106
// B
107
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
108
// 1
109

    
110
///////////////////////////////////////////////////////////////////////////////////////////////////
111

    
112
  private float f(float D, float B, float x)
113
    {
114
    return ((D-B)*x + B*(1-D))/(1-B);
115
    }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

    
119
  private float g(float R, float D, float x, float cosAlpha)
120
    {
121
    float d = x-D;
122
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

    
127
  private float h(float R, float sinAlpha, float x)
128
    {
129
    return R*(sinAlpha-(float)Math.sin(x));
130
    }
131

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  private boolean areColinear(float[][] vertices, int index1, int index2, int index3)
135
    {
136
    float x1 = vertices[index1][0];
137
    float y1 = vertices[index1][1];
138
    float z1 = vertices[index1][2];
139
    float x2 = vertices[index2][0];
140
    float y2 = vertices[index2][1];
141
    float z2 = vertices[index2][2];
142
    float x3 = vertices[index3][0];
143
    float y3 = vertices[index3][1];
144
    float z3 = vertices[index3][2];
145

    
146
    float v1x = x2-x1;
147
    float v1y = y2-y1;
148
    float v1z = z2-z1;
149
    float v2x = x3-x1;
150
    float v2y = y3-y1;
151
    float v2z = z3-z1;
152

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

    
155
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private void computeNormalVector(float[][] vertices, int index1, int index2, int index3)
161
    {
162
    float x1 = vertices[index1][0];
163
    float y1 = vertices[index1][1];
164
    float z1 = vertices[index1][2];
165
    float x2 = vertices[index2][0];
166
    float y2 = vertices[index2][1];
167
    float z2 = vertices[index2][2];
168
    float x3 = vertices[index3][0];
169
    float y3 = vertices[index3][1];
170
    float z3 = vertices[index3][2];
171

    
172
    float v1x = x2-x1;
173
    float v1y = y2-y1;
174
    float v1z = z2-z1;
175
    float v2x = x3-x1;
176
    float v2y = y3-y1;
177
    float v2z = z3-z1;
178

    
179
    mBuffer[0] = v1y*v2z - v2y*v1z;
180
    mBuffer[1] = v1z*v2x - v2z*v1x;
181
    mBuffer[2] = v1x*v2y - v2x*v1y;
182

    
183
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
184
    len = Math.sqrt(len);
185
    mBuffer[0] /= len;
186
    mBuffer[1] /= len;
187
    mBuffer[2] /= len;
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

    
192
  private float[] detectFirstOuterVertex(float[][] vertices)
193
    {
194
    float X = -Float.MAX_VALUE;
195
    int I=0,J=0, len = vertices.length;
196

    
197
    for(int i=0; i<len; i++ )
198
      {
199
      float[] v = vertices[i];
200
      int num = v.length/2;
201

    
202
      for(int j=0; j<num; j++)
203
        if(v[2*j]>X)
204
          {
205
          X = v[2*j];
206
          I = i;
207
          J = j;
208
          }
209
      }
210

    
211
    float[] v = vertices[I];
212
    return new float[] {v[2*J],v[2*J+1]};
213
    }
214

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

    
217
  private double computeAngle(float x1,float y1, float x2, float y2)
218
    {
219
    double diff = Math.atan2(y2,x2)-Math.atan2(y1,x1);
220
    return diff<0 ? diff+(2*Math.PI) : diff;
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224

    
225
  private float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
226
    {
227
    double minAngle = 2*Math.PI;
228
    float x=0, y=0;
229

    
230
    for( float[] v : vertices )
231
      {
232
      int num = v.length/2;
233

    
234
      for( int j=0; j<num; j++)
235
        {
236
        float xc = v[2*j];
237
        float yc = v[2*j+1];
238

    
239
        if( xc==curr[0] && yc==curr[1])
240
          {
241
          int n = (j==num-1 ? 0 : j+1);
242
          float xn = v[2*n];
243
          float yn = v[2*n+1];
244

    
245
          double angle = computeAngle(vect[0], vect[1], xn-xc, yn-yc);
246

    
247
          if (angle < minAngle)
248
            {
249
            minAngle = angle;
250
            x = xn;
251
            y = yn;
252
            }
253

    
254
          break;
255
          }
256
        }
257
      }
258

    
259
    return new float[] {x,y};
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263
// same as in MeshMultigon
264

    
265
  private float[] computeOuterEdge(float[][] vertices)
266
    {
267
    ArrayList<float[]> tmp = new ArrayList<>();
268

    
269
    float[] vect = new float[] {1,0};
270
    float[] first= detectFirstOuterVertex(vertices);
271
    float[] next = first;
272

    
273
    do
274
      {
275
      float[] prev = next;
276
      next = detectNextOuterVertex(vertices,next,vect);
277
      vect[0] = prev[0]-next[0];
278
      vect[1] = prev[1]-next[1];
279
      tmp.add(next);
280
      }
281
    while( next[0]!=first[0] || next[1]!=first[1] );
282

    
283
    int num = tmp.size();
284
    float[] ret = new float[2*num];
285

    
286
    for(int i=0; i<num; i++)
287
      {
288
      float[] t = tmp.remove(0);
289
      ret[2*i  ] = t[0];
290
      ret[2*i+1] = t[1];
291
      }
292

    
293
    return ret;
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297
// polygon
298

    
299
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
300
    {
301
    float minX = Float.MAX_VALUE;
302
    float maxX =-Float.MAX_VALUE;
303
    float minY = Float.MAX_VALUE;
304
    float maxY =-Float.MAX_VALUE;
305

    
306
    for (float[] vert : vert3D)
307
      {
308
      float x = vert[0];
309
      float y = vert[1];
310

    
311
      if (x > maxX) maxX = x;
312
      if (x < minX) minX = x;
313
      if (y > maxY) maxY = y;
314
      if (y < minY) minY = y;
315
      }
316

    
317
    minX = minX<0 ? -minX:minX;
318
    maxX = maxX<0 ? -maxX:maxX;
319
    minY = minY<0 ? -minY:minY;
320
    maxY = maxY<0 ? -maxY:maxY;
321

    
322
    float max1 = Math.max(minX,minY);
323
    float max2 = Math.max(maxX,maxY);
324
    float max3 = Math.max(max1,max2);
325

    
326
    info.scale = max3/0.5f;
327

    
328
    int len = vert3D.length;
329
    StickerCoords sInfo = new StickerCoords();
330
    sInfo.outer = isOuter;
331
    sInfo.scale = info.scale;
332
    sInfo.vertices = new float[2*len];
333
    sInfo.fullVertices = null;
334

    
335
    for( int vertex=0; vertex<len; vertex++ )
336
      {
337
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
338
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
339
      }
340

    
341
    mStickerCoords.add(sInfo);
342

    
343
    info.sticker = mStickerCoords.size() -1;
344
    }
345

    
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348
// multigon
349

    
350
  private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
351
    {
352
    float minX = Float.MAX_VALUE;
353
    float maxX =-Float.MAX_VALUE;
354
    float minY = Float.MAX_VALUE;
355
    float maxY =-Float.MAX_VALUE;
356

    
357
    for( float[][] vert : vert3D)
358
      for( float[] v : vert)
359
        {
360
        float x = v[0];
361
        float y = v[1];
362

    
363
        if (x > maxX) maxX = x;
364
        if (x < minX) minX = x;
365
        if (y > maxY) maxY = y;
366
        if (y < minY) minY = y;
367
        }
368

    
369
    minX = minX<0 ? -minX:minX;
370
    maxX = maxX<0 ? -maxX:maxX;
371
    minY = minY<0 ? -minY:minY;
372
    maxY = maxY<0 ? -maxY:maxY;
373

    
374
    float max1 = Math.max(minX,minY);
375
    float max2 = Math.max(maxX,maxY);
376
    float max3 = Math.max(max1,max2);
377

    
378
    info.scale = max3/0.5f;
379

    
380
    int len = vert3D.length;
381
    StickerCoords sInfo = new StickerCoords();
382
    sInfo.outer = isOuter;
383
    sInfo.scale = info.scale;
384
    sInfo.fullVertices = new float[len][];
385

    
386
    for( int comp=0; comp<len; comp++ )
387
      {
388
      float[][] vert = vert3D[comp];
389
      int num = vert.length;
390
      sInfo.fullVertices[comp] = new float[2*num];
391
      float[] t = sInfo.fullVertices[comp];
392

    
393
      for( int vertex=0; vertex<num; vertex++)
394
        {
395
        t[2*vertex  ] = vert[vertex][0] / info.scale;
396
        t[2*vertex+1] = vert[vertex][1] / info.scale;
397
        }
398
      }
399

    
400
    sInfo.vertices = computeOuterEdge(sInfo.fullVertices);
401

    
402
    mStickerCoords.add(sInfo);
403

    
404
    info.sticker = mStickerCoords.size() -1;
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408
// polygon
409

    
410
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
411
    {
412
    FaceTransform ft = new FaceTransform();
413
    ft.face = face;
414
    ft.numFaces = numFaces;
415

    
416
    // compute center of gravity
417
    ft.vx = 0.0f;
418
    ft.vy = 0.0f;
419
    ft.vz = 0.0f;
420
    int len = vert3D.length;
421

    
422
    for (float[] vert : vert3D)
423
      {
424
      ft.vx += vert[0];
425
      ft.vy += vert[1];
426
      ft.vz += vert[2];
427
      }
428

    
429
    ft.vx /= len;
430
    ft.vy /= len;
431
    ft.vz /= len;
432

    
433
    // move all vertices so that their center of gravity is at (0,0,0)
434
    for (int i=0; i<len; i++)
435
      {
436
      vert3D[i][0] -= ft.vx;
437
      vert3D[i][1] -= ft.vy;
438
      vert3D[i][2] -= ft.vz;
439
      }
440

    
441
    // find 3 non-colinear vertices
442
    int foundIndex = -1;
443

    
444
    for(int vertex=2; vertex<len; vertex++)
445
      {
446
      if( !areColinear(vert3D,0,1,vertex) )
447
        {
448
        foundIndex = vertex;
449
        break;
450
        }
451
      }
452

    
453
    // compute the normal vector
454
    if( foundIndex==-1 )
455
      {
456
      StringBuilder sb = new StringBuilder();
457

    
458
      for (float[] floats : vert3D)
459
        {
460
        sb.append(' ');
461
        sb.append("(");
462
        sb.append(floats[0]);
463
        sb.append(" ");
464
        sb.append(floats[1]);
465
        sb.append(" ");
466
        sb.append(floats[2]);
467
        sb.append(")");
468
        }
469
      android.util.Log.e("D", "verts: "+sb);
470

    
471
      throw new RuntimeException("all vertices colinear");
472
      }
473

    
474
    computeNormalVector(vert3D,0,1,foundIndex);
475

    
476
    // rotate so that the normal vector becomes (0,0,1)
477
    float axisX, axisY, axisZ;
478

    
479
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
480
      {
481
      axisX = -mBuffer[1];
482
      axisY =  mBuffer[0];
483
      axisZ = 0.0f;
484

    
485
      float axiLen = axisX*axisX + axisY*axisY;
486
      axiLen = (float)Math.sqrt(axiLen);
487
      axisX /= axiLen;
488
      axisY /= axiLen;
489
      axisZ /= axiLen;
490
      }
491
    else
492
      {
493
      axisX = 0.0f;
494
      axisY = 1.0f;
495
      axisZ = 0.0f;
496
      }
497

    
498
    float cosTheta = mBuffer[2];
499
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
500
    float sinHalfTheta = computeSinHalf(cosTheta);
501
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
502

    
503
    mQuat1[0] = axisX*sinHalfTheta;
504
    mQuat1[1] = axisY*sinHalfTheta;
505
    mQuat1[2] = axisZ*sinHalfTheta;
506
    mQuat1[3] = cosHalfTheta;
507
    mQuat2[0] =-axisX*sinHalfTheta;
508
    mQuat2[1] =-axisY*sinHalfTheta;
509
    mQuat2[2] =-axisZ*sinHalfTheta;
510
    mQuat2[3] = cosHalfTheta;
511

    
512
    for (float[] vert : vert3D)
513
      {
514
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
515
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
516
      }
517

    
518
    // fit the whole thing in a square and remember the scale & 2D vertices
519
    fitInSquare(ft, vert3D, isOuter);
520

    
521
    // remember the rotation
522
    ft.qx =-mQuat1[0];
523
    ft.qy =-mQuat1[1];
524
    ft.qz =-mQuat1[2];
525
    ft.qw = mQuat1[3];
526

    
527
    return ft;
528
    }
529

    
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531
// multigon
532

    
533
  private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
534
    {
535
    FaceTransform ft = new FaceTransform();
536
    ft.face = face;
537
    ft.numFaces = numFaces;
538

    
539
    // compute center of gravity
540
    ft.vx = 0.0f;
541
    ft.vy = 0.0f;
542
    ft.vz = 0.0f;
543
    int len = 0;
544

    
545
    for( float[][] vert : vert3D )
546
      for( float[] v : vert )
547
        {
548
        ft.vx += v[0];
549
        ft.vy += v[1];
550
        ft.vz += v[2];
551
        len++;
552
        }
553

    
554
    ft.vx /= len;
555
    ft.vy /= len;
556
    ft.vz /= len;
557

    
558
    // move all vertices so that their center of gravity is at (0,0,0)
559
    for( float[][] vert : vert3D )
560
      for( float[] v : vert )
561
        {
562
        v[0] -= ft.vx;
563
        v[1] -= ft.vy;
564
        v[2] -= ft.vz;
565
        }
566

    
567
    // find 3 non-colinear vertices
568
    int foundIndex = -1;
569
    len = vert3D[0].length;
570

    
571
    for(int vertex=2; vertex<len; vertex++)
572
      {
573
      if( !areColinear(vert3D[0],0,1,vertex) )
574
        {
575
        foundIndex = vertex;
576
        break;
577
        }
578
      }
579

    
580
    // compute the normal vector
581
    if( foundIndex==-1 )
582
      {
583
      StringBuilder sb = new StringBuilder();
584

    
585
      for (float[] v : vert3D[0])
586
        {
587
        sb.append(' ');
588
        sb.append("(");
589
        sb.append(v[0]);
590
        sb.append(" ");
591
        sb.append(v[1]);
592
        sb.append(" ");
593
        sb.append(v[2]);
594
        sb.append(")");
595
        }
596
      android.util.Log.e("D", "verts: "+sb);
597

    
598
      throw new RuntimeException("all vertices colinear");
599
      }
600

    
601
    computeNormalVector(vert3D[0],0,1,foundIndex);
602

    
603
    // rotate so that the normal vector becomes (0,0,1)
604
    float axisX, axisY, axisZ;
605

    
606
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
607
      {
608
      axisX = -mBuffer[1];
609
      axisY =  mBuffer[0];
610
      axisZ = 0.0f;
611

    
612
      float axiLen = axisX*axisX + axisY*axisY;
613
      axiLen = (float)Math.sqrt(axiLen);
614
      axisX /= axiLen;
615
      axisY /= axiLen;
616
      axisZ /= axiLen;
617
      }
618
    else
619
      {
620
      axisX = 0.0f;
621
      axisY = 1.0f;
622
      axisZ = 0.0f;
623
      }
624

    
625
    float cosTheta = mBuffer[2];
626
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
627
    float sinHalfTheta = computeSinHalf(cosTheta);
628
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
629

    
630
    mQuat1[0] = axisX*sinHalfTheta;
631
    mQuat1[1] = axisY*sinHalfTheta;
632
    mQuat1[2] = axisZ*sinHalfTheta;
633
    mQuat1[3] = cosHalfTheta;
634
    mQuat2[0] =-axisX*sinHalfTheta;
635
    mQuat2[1] =-axisY*sinHalfTheta;
636
    mQuat2[2] =-axisZ*sinHalfTheta;
637
    mQuat2[3] = cosHalfTheta;
638

    
639
    for( float[][] vert : vert3D)
640
      for( float[] v : vert)
641
        {
642
        QuatHelper.quatMultiply(mQuat3, mQuat1, v  );
643
        QuatHelper.quatMultiply(  v, mQuat3, mQuat2);
644
        }
645

    
646
    // fit the whole thing in a square and remember the scale & 2D vertices
647
    fitInSquare(ft, vert3D, isOuter);
648

    
649
    // remember the rotation
650
    ft.qx =-mQuat1[0];
651
    ft.qy =-mQuat1[1];
652
    ft.qz =-mQuat1[2];
653
    ft.qw = mQuat1[3];
654

    
655
    return ft;
656
    }
657

    
658
///////////////////////////////////////////////////////////////////////////////////////////////////
659

    
660
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
661
    {
662
    for(int i=0; i<len; i++)
663
      {
664
      float x = vertices[2*i];
665
      float y = vertices[2*i+1];
666
      result[2*i  ] = x*cos - y*sin;
667
      result[2*i+1] = x*sin + y*cos;
668
      }
669
    }
670

    
671
///////////////////////////////////////////////////////////////////////////////////////////////////
672

    
673
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
674
    {
675
    float v1x = v1[2*v1i];
676
    float v1y = v1[2*v1i+1];
677
    float v2x = v2[2*v2i];
678
    float v2y = v2[2*v2i+1];
679

    
680
    float lenSq1 = v1x*v1x + v1y*v1y;
681
    float lenSq2 = v2x*v2x + v2y*v2y;
682

    
683
    return (float)Math.sqrt(lenSq2/lenSq1);
684
    }
685

    
686
///////////////////////////////////////////////////////////////////////////////////////////////////
687
// valid for 0<angle<2*PI
688

    
689
  private float computeSinHalf(float cos)
690
    {
691
    return (float)Math.sqrt((1-cos)/2);
692
    }
693

    
694
///////////////////////////////////////////////////////////////////////////////////////////////////
695
// valid for 0<angle<2*PI
696

    
697
  private float computeCosHalf(float sin, float cos)
698
    {
699
    float cosHalf = (float)Math.sqrt((1+cos)/2);
700
    return sin<0 ? -cosHalf : cosHalf;
701
    }
702

    
703
///////////////////////////////////////////////////////////////////////////////////////////////////
704

    
705
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
706
    {
707
    int v = (rotatedVertex + oldVertex);
708
    if( v>=len ) v-=len;
709
    if( v< 0   ) v+=len;
710

    
711
    return v;
712
    }
713

    
714
///////////////////////////////////////////////////////////////////////////////////////////////////
715

    
716
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex)
717
    {
718
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
719
    float EPSILON = 0.001f;
720
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
721

    
722
    for(int i=1; i<len; i++)
723
      {
724
      int index = computeRotatedIndex(i,len,vertex);
725

    
726
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
727
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
728

    
729
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
730
      }
731

    
732
    return true;
733
    }
734

    
735
///////////////////////////////////////////////////////////////////////////////////////////////////
736

    
737
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
738
    {
739
    mStickerCoords.remove(info.sticker);
740

    
741
    info.sticker = oldSticker;
742
    info.scale  *= scale;
743

    
744
    mQuat1[0] = info.qx;
745
    mQuat1[1] = info.qy;
746
    mQuat1[2] = info.qz;
747
    mQuat1[3] = info.qw;
748

    
749
    float sinHalf = computeSinHalf(cos);
750
    float cosHalf = computeCosHalf(sin,cos);
751

    
752
    mQuat2[0] = 0.0f;
753
    mQuat2[1] = 0.0f;
754
    mQuat2[2] = sinHalf;
755
    mQuat2[3] = cosHalf;
756

    
757
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
758

    
759
    info.qx = mQuat3[0];
760
    info.qy = mQuat3[1];
761
    info.qz = mQuat3[2];
762
    info.qw = mQuat3[3];
763
    }
764

    
765
///////////////////////////////////////////////////////////////////////////////////////////////////
766

    
767
  private void printVert(double[] buffer)
768
    {
769
    int len = buffer.length/2;
770
    String str = "";
771

    
772
    for(int i=0; i<len; i++)
773
      {
774
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
775
      }
776

    
777
    android.util.Log.d("D", str);
778
    }
779

    
780
///////////////////////////////////////////////////////////////////////////////////////////////////
781

    
782
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert, float[] oldVert, int oldSticker)
783
    {
784
    int lenVertOld = oldVert.length/2;
785
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
786

    
787
    for(int oldV=0; oldV<lenVertOld; oldV++)
788
      {
789
      oldX = oldVert[2*oldV];
790
      oldY = oldVert[2*oldV+1];
791
      lenOld = (float)Math.sqrt(oldX*oldX + oldY*oldY);
792

    
793
      if( lenOld!=0 ) break;
794
      }
795

    
796
    for(int vertex=0; vertex<len; vertex++)
797
      {
798
      float newX = newVert[2*vertex  ];
799
      float newY = newVert[2*vertex+1];
800
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
801

    
802
      if( lenNew!=0 )
803
        {
804
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
805
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
806

    
807
        rotateAllVertices(buffer,len,newVert,sin,cos);
808

    
809
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
810
          {
811
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
812
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
813
          correctInfo(info,scale,sin,cos,oldSticker);
814
          return true;
815
          }
816
        }
817
      }
818

    
819
    return false;
820
    }
821

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

    
824
  private float computeCoreDistance(float[] verts)
825
    {
826
    float ret = 0.0f;
827
    float centerX=0.0f,centerY=0.0f;
828
    int len = verts.length/2;
829

    
830
    for(int i=0; i<len; i++)
831
      {
832
      centerX += verts[2*i  ];
833
      centerY += verts[2*i+1];
834
      }
835

    
836
    centerX /= (2*len);
837
    centerY /= (2*len);
838

    
839
    for(int i=0; i<len; i++)
840
      {
841
      float distX = centerX-verts[2*i  ];
842
      float distY = centerY-verts[2*i+1];
843
      ret += (float)Math.sqrt(distX*distX + distY*distY);
844
      }
845

    
846
    return ret;
847
    }
848

    
849
///////////////////////////////////////////////////////////////////////////////////////////////////
850

    
851
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
852
    {
853
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
854
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
855

    
856
    float[] newVert = sNewInfo.vertices;
857
    float[] oldVert = sOldInfo.vertices;
858
    int oldLen = oldVert.length;
859
    int newLen = newVert.length;
860

    
861
    if( oldLen==newLen )
862
      {
863
      float coreDistOld = computeCoreDistance(oldVert);                     // the two stickers are at different scales,
864
      float coreDistNew = computeCoreDistance(newVert);                     // so even if they are in fact the same, do not
865
      float diff = (coreDistOld*oldInfo.scale)/(coreDistNew*newInfo.scale); // collapse them into one. Example: Master Skewb
866
      if( diff<1.0-MAX_CORE_DIFF || diff>1.0+MAX_CORE_DIFF ) return false;  // and two triangular stickers of different size.
867

    
868
      int oldSticker = oldInfo.sticker;
869
      float[] buffer1 = new float[oldLen];
870

    
871
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, oldSticker) )
872
        {
873
        if( sNewInfo.outer ) sOldInfo.outer = true;
874
        return true;
875
        }
876
      }
877

    
878
    return false;
879
    }
880

    
881
///////////////////////////////////////////////////////////////////////////////////////////////////
882
// polygon
883

    
884
  private float[][] constructVert(float[][] vertices, int[] index)
885
    {
886
    int len = index.length;
887
    float[][] ret = new float[len][4];
888

    
889
    for(int i=0; i<len; i++)
890
      {
891
      float[] tmp = vertices[index[i]];
892
      ret[i][0] = tmp[0];
893
      ret[i][1] = tmp[1];
894
      ret[i][2] = tmp[2];
895
      ret[i][3] = 1.0f;
896
      }
897

    
898
    return ret;
899
    }
900

    
901
///////////////////////////////////////////////////////////////////////////////////////////////////
902
// multigon
903

    
904
  private float[][][] constructVert(float[][] vertices, int[][] index)
905
    {
906
    int len = index.length;
907
    float[][][] ret = new float[len][][];
908

    
909
    for(int i=0; i<len; i++)
910
      {
911
      int[] ind = index[i];
912
      int num = ind.length;
913
      ret[i] = new float[num][4];
914

    
915
      for(int j=0; j<num; j++)
916
        {
917
        float[] r = ret[i][j];
918
        float[] v = vertices[ind[j]];
919
        r[0] = v[0];
920
        r[1] = v[1];
921
        r[2] = v[2];
922
        r[3] = 1.0f;
923
        }
924
      }
925

    
926
    return ret;
927
    }
928

    
929
///////////////////////////////////////////////////////////////////////////////////////////////////
930

    
931
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects, int meshState)
932
    {
933
    boolean[] uses      = effects.getUses();
934
    String[] names      = effects.getNames();
935
    float[][] variables = effects.getVariables();
936
    float[][] centers   = effects.getCenters();
937
    float[][] regions   = effects.getRegions();
938
    int numEffects = uses.length;
939

    
940
    for(int eff=0; eff<numEffects; eff++)
941
      if( names[eff]!=null && (meshState==MESH_NICE || uses[eff]) )
942
        {
943
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
944
        if( effect!=null ) mesh.apply(effect);
945
        }
946
    }
947

    
948
///////////////////////////////////////////////////////////////////////////////////////////////////
949

    
950
  private void correctComponents(MeshBase mesh, int numComponents)
951
    {
952
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
953

    
954
    mesh.mergeEffComponents();
955

    
956
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
957
    }
958

    
959
///////////////////////////////////////////////////////////////////////////////////////////////////
960

    
961
  private void printTransform(FaceTransform f)
962
    {
963
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
964
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
965
    }
966

    
967
///////////////////////////////////////////////////////////////////////////////////////////////////
968

    
969
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
970
    {
971
    float[] bands = new float[2*N];
972

    
973
    bands[0] = 1.0f;
974
    bands[1] = 0.0f;
975

    
976
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
977
    float sinBeta = (float)Math.sin(beta);
978
    float cosBeta = (float)Math.cos(beta);
979
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
980
    float D = R*sinBeta;
981
    float B = h(R,sinBeta,K*beta);
982

    
983
    if( D>1.0f )
984
      {
985
      for(int i=1; i<N; i++)
986
        {
987
        bands[2*i  ] = (float)(N-1-i)/(N-1);
988
        bands[2*i+1] = H*(1-bands[2*i]);
989
        }
990
      }
991
    else
992
      {
993
      int K2 = (int)((N-3)*K);
994
      int K1 = (N-3)-K2;
995

    
996
      for(int i=0; i<=K1; i++)
997
        {
998
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
999
        float x = h(R,sinBeta,angle);
1000
        bands[2*i+2] = 1.0f - x;
1001
        bands[2*i+3] = g(R,D,x,cosBeta);
1002
        }
1003

    
1004
      for(int i=0; i<=K2; i++)
1005
        {
1006
        float x = (1-B)*(i+1)/(K2+1) + B;
1007
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
1008
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
1009
        }
1010
      }
1011

    
1012
    bands[2*N-2] = 0.0f;
1013
    bands[2*N-1] =    H;
1014

    
1015
    return bands;
1016
    }
1017

    
1018
///////////////////////////////////////////////////////////////////////////////////////////////////
1019

    
1020
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
1021
    {
1022
    if( in==null )
1023
      {
1024
      out[0] = out[1] = 0.0f;
1025
      }
1026
    else
1027
      {
1028
      out[0] = in[0] - ft.vx;
1029
      out[1] = in[1] - ft.vy;
1030
      out[2] = in[2] - ft.vz;
1031
      out[3] = 1.0f;
1032

    
1033
      mQuat1[0] =-ft.qx;
1034
      mQuat1[1] =-ft.qy;
1035
      mQuat1[2] =-ft.qz;
1036
      mQuat1[3] = ft.qw;
1037

    
1038
      mQuat2[0] = -mQuat1[0];
1039
      mQuat2[1] = -mQuat1[1];
1040
      mQuat2[2] = -mQuat1[2];
1041
      mQuat2[3] =  mQuat1[3];
1042

    
1043
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1044
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1045

    
1046
      out[0] /= ft.scale;
1047
      out[1] /= ft.scale;
1048
      out[2] /= ft.scale;
1049
      }
1050
    }
1051

    
1052
///////////////////////////////////////////////////////////////////////////////////////////////////
1053

    
1054
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
1055
    {
1056
    int len = table.length;
1057

    
1058
    for(int i=0; i<len; i++)
1059
      {
1060
      int lenInner = table[i].length;
1061

    
1062
      for(int j=0; j<lenInner; j++)
1063
        if( table[i][j]==oldPointer ) table[i][j] = newPointer;
1064
      }
1065
    }
1066

    
1067
///////////////////////////////////////////////////////////////////////////////////////////////////
1068
// INTERNAL API
1069

    
1070
  public int printStickerCoords()
1071
    {
1072
    int stickers = mStickerCoords.size();
1073
    int ret = 0;
1074

    
1075
    android.util.Log.d("D", "---- STICKER COORDS ----");
1076

    
1077
    for(int s=0; s<stickers; s++)
1078
      {
1079
      StickerCoords info = mStickerCoords.get(s);
1080

    
1081
      if( info.outer )  ret++;
1082

    
1083
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
1084
      int len = info.vertices.length/2;
1085

    
1086
      for(int i =0; i<len; i++)
1087
        {
1088
        if( i!=0 ) ver += ", ";
1089
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
1090
        }
1091

    
1092
      ver += " }";
1093
      android.util.Log.d("D", ver);
1094
      }
1095

    
1096
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1097

    
1098
    return ret;
1099
    }
1100

    
1101
///////////////////////////////////////////////////////////////////////////////////////////////////
1102

    
1103
  public void printFaceTransform()
1104
    {
1105
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1106

    
1107
    int oldfaces = mOldFaceTransf.size();
1108

    
1109
    for(int f=0; f<oldfaces; f++)
1110
      {
1111
      printTransform(mOldFaceTransf.get(f));
1112
      }
1113

    
1114
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1115

    
1116
    int newfaces = mNewFaceTransf.size();
1117

    
1118
    for(int f=0; f<newfaces; f++)
1119
      {
1120
      printTransform(mNewFaceTransf.get(f));
1121
      }
1122
    }
1123

    
1124
///////////////////////////////////////////////////////////////////////////////////////////////////
1125
// PUBLIC API
1126

    
1127
  public static FactoryCubit getInstance()
1128
    {
1129
    if( mThis==null ) mThis = new FactoryCubit();
1130
    return mThis;
1131
    }
1132

    
1133
///////////////////////////////////////////////////////////////////////////////////////////////////
1134

    
1135
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
1136
                                                          float[][] corners, int[] cornerIndices,
1137
                                                          float[][] centers, int[] centerIndices )
1138
    {
1139
    int numVerts = vertices.length;
1140
    String[] names = new String[numVerts];
1141
    float[][] vars = new float[numVerts][];
1142
    float[][] cents= new float[numVerts][];
1143
    float[][] regs = new float[numVerts][];
1144
    boolean[] uses = new boolean[numVerts];
1145

    
1146
    for(int i=0; i<numVerts; i++)
1147
      {
1148
      int centerI = centerIndices[i];
1149
      int cornerI = cornerIndices[i];
1150

    
1151
      if( centerI>=0 && cornerI>=0 )
1152
        {
1153
        float[] ce = centers[centerI];
1154
        float[] ve = vertices[i];
1155
        float S = corners[cornerI][0];
1156
        float R = corners[cornerI][1];
1157

    
1158
        float CX = ve[0];
1159
        float CY = ve[1];
1160
        float CZ = ve[2];
1161
        float X = S*(ce[0]-CX);
1162
        float Y = S*(ce[1]-CY);
1163
        float Z = S*(ce[2]-CZ);
1164

    
1165
        names[i]= NAME;
1166
        vars[i] = new float[] { 0, X,Y,Z, 1 };
1167
        cents[i]= new float[] { CX, CY, CZ };
1168
        regs[i] = new float[] { 0,0,0, R };
1169
        uses[i] = false;
1170
        }
1171
      }
1172

    
1173
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1174
    }
1175

    
1176
///////////////////////////////////////////////////////////////////////////////////////////////////
1177

    
1178
  public float[] getStickerScales()
1179
    {
1180
    int index=0,num=0,len = mStickerCoords.size();
1181

    
1182
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
1183

    
1184
    if( num>0 )
1185
      {
1186
      float[] scales = new float[num];
1187

    
1188
      for(int i=0; i<len; i++)
1189
        {
1190
        StickerCoords sticker = mStickerCoords.get(i);
1191
        if( sticker.outer ) scales[index++] = sticker.scale;
1192
        }
1193

    
1194
      return scales;
1195
      }
1196

    
1197
    return null;
1198
    }
1199

    
1200
///////////////////////////////////////////////////////////////////////////////////////////////////
1201

    
1202
  public float[][] getStickerCoords()
1203
    {
1204
    int index=0,num=0,len = mStickerCoords.size();
1205

    
1206
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
1207

    
1208
    if( num>0 )
1209
      {
1210
      float[][] coords = new float[num][];
1211

    
1212
      for(int i=0; i<len; i++)
1213
        {
1214
        StickerCoords sticker = mStickerCoords.get(i);
1215
        if( sticker.outer ) coords[index++] = sticker.vertices;
1216
        }
1217

    
1218
      return coords;
1219
      }
1220

    
1221
    return null;
1222
    }
1223

    
1224
///////////////////////////////////////////////////////////////////////////////////////////////////
1225

    
1226
  public int[][] getStickerVariants()
1227
    {
1228
    int numvariants = 1; // there's one in the 'new' array
1229

    
1230
    int oldfaces = mOldFaceTransf.size();
1231

    
1232
    for(int f=0; f<oldfaces; f++)
1233
      {
1234
      FaceTransform ft = mOldFaceTransf.get(f);
1235
      if( ft.face==0 ) numvariants++;
1236
      }
1237

    
1238
    int[][] ret = new int[numvariants][];
1239
    int inner=0, index=-1;
1240

    
1241
    for(int f=0; f<oldfaces; f++)
1242
      {
1243
      FaceTransform ft = mOldFaceTransf.get(f);
1244
      if( ft.face==0 )
1245
        {
1246
        index++;
1247
        inner=0;
1248
        ret[index] = new int[ft.numFaces];
1249
        }
1250

    
1251
      ret[index][inner++] = ft.sticker;
1252
      }
1253

    
1254
    int newfaces = mNewFaceTransf.size();
1255

    
1256
    for(int f=0; f<newfaces; f++)
1257
      {
1258
      FaceTransform ft = mNewFaceTransf.get(f);
1259
      if( ft.face==0 )
1260
        {
1261
        index++;
1262
        inner=0;
1263
        ret[index] = new int[ft.numFaces];
1264
        }
1265

    
1266
      ret[index][inner++] = ft.sticker;
1267
      }
1268

    
1269
    int numStickers = mStickerCoords.size();
1270
    int numOuter=0;
1271

    
1272
    for(int i=0; i<numStickers; i++)
1273
      {
1274
      StickerCoords sc = mStickerCoords.get(i);
1275
      if( sc.outer )
1276
        {
1277
        changeStickerPointers(ret,i,numOuter);
1278
        numOuter++;
1279
        }
1280
      else
1281
        {
1282
        changeStickerPointers(ret,i,-1);
1283
        }
1284
      }
1285

    
1286
    return ret;
1287
    }
1288

    
1289
///////////////////////////////////////////////////////////////////////////////////////////////////
1290

    
1291
  public void clear()
1292
    {
1293
    mStickerCoords.clear();
1294
    mNewFaceTransf.clear();
1295
    mOldFaceTransf.clear();
1296
    }
1297

    
1298
///////////////////////////////////////////////////////////////////////////////////////////////////
1299
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
1300
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
1301
// been called.
1302

    
1303
  public Static4D getQuaternion(int face)
1304
    {
1305
    FaceTransform ft = mNewFaceTransf.get(face);
1306
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
1307
    }
1308

    
1309
///////////////////////////////////////////////////////////////////////////////////////////////////
1310

    
1311
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1312
    {
1313
    float[][] vertices = shape.getVertices();
1314
    int[][] indices = shape.getVertIndices();
1315
    int[][][] fullIndices = shape.getMultigonIndices();
1316
    boolean isMultigon = shape.isMultigon();
1317
    FaceTransform ft;
1318
    int numNew = mNewFaceTransf.size();
1319

    
1320
    for(int i=0; i<numNew; i++)
1321
      {
1322
      ft = mNewFaceTransf.remove(0);
1323
      mOldFaceTransf.add(ft);
1324
      }
1325

    
1326
    int numFaces = shape.getNumFaces();
1327
    int numOld = mOldFaceTransf.size();
1328

    
1329
    for (int face=0; face<numFaces; face++)
1330
      {
1331
      boolean collapsed = false;
1332
      boolean isOuter = (outer!=null && outer[face]>0);
1333
      FaceTransform newT;
1334

    
1335
      if( !isMultigon )
1336
        {
1337
        float[][] vert = constructVert(vertices, indices[face]);
1338
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1339
        }
1340
      else
1341
        {
1342
        float[][][] vert = constructVert(vertices, fullIndices[face]);
1343
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1344
        }
1345

    
1346
      for (int old=0; !collapsed && old<numOld; old++)
1347
        {
1348
        ft = mOldFaceTransf.get(old);
1349
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1350
        }
1351

    
1352
      for (int pre=0; !collapsed && pre<face; pre++)
1353
        {
1354
        ft = mNewFaceTransf.get(pre);
1355
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1356
        }
1357

    
1358
      mNewFaceTransf.add(newT);
1359
      }
1360
    }
1361

    
1362
///////////////////////////////////////////////////////////////////////////////////////////////////
1363

    
1364
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1365
                                     final ObjectVertexEffects effects, int meshState, int numComponents)
1366
    {
1367
    float[][] bands         = faceShape.getBands();
1368
    int[]   bandIndexes     = faceShape.getBandIndices();
1369
    float[] convexityCenter = faceShape.getConvexityCenter();
1370

    
1371
    int numFaces = shape.getNumFaces();
1372
    boolean multigonMode = shape.isMultigon();
1373
    float[] band, bandsComputed;
1374
    MeshBase[] meshes = new MeshBase[numFaces];
1375
    FaceTransform fInfo;
1376
    StickerCoords sInfo;
1377
    float[] convexXY = new float[4];
1378
    int exIndex=0, exVertices=0, alpha=0, N=0;
1379
    float height=0.0f, dist=0.0f, K=0.0f;
1380

    
1381
    for(int face=0; face<numFaces; face++)
1382
      {
1383
      fInfo = mNewFaceTransf.get(face);
1384
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1385

    
1386
      int index = bandIndexes[face];
1387
      band = bands[index];
1388

    
1389
      switch(meshState)
1390
        {
1391
        case MESH_NICE: height     = band[0];
1392
                        alpha      = (int)band[1];
1393
                        dist       = band[2];
1394
                        K          = band[3];
1395
                        N          = (int)band[4];
1396
                        exIndex    = (int)band[5];
1397
                        exVertices = (int)band[6];
1398
                        break;
1399
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
1400
                                                               // (example: Ivy cube center and edge cubits!)
1401
                        alpha      = 0;
1402
                        dist       = 0;
1403
                        K          = 0;
1404
                        N          = 2;
1405
                        exIndex    = 0;
1406
                        exVertices = 0;
1407
                        break;
1408
        }
1409

    
1410
      bandsComputed = computeBands(height,alpha,dist,K,N);
1411

    
1412
      if( !multigonMode )
1413
        {
1414
        sInfo = mStickerCoords.get(fInfo.sticker);
1415
        float[] verts = sInfo.vertices;
1416
        int lenVerts = verts.length;
1417
        float[] copiedVerts = new float[lenVerts];
1418
        System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1419
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1420
        }
1421
      else
1422
        {
1423
        sInfo = mStickerCoords.get(fInfo.sticker);
1424
        float[][] verts = sInfo.fullVertices;
1425
        int lenVerts = verts.length;
1426
        float[][] copiedVerts = new float[lenVerts][];
1427

    
1428
        for(int i=0; i<lenVerts; i++)
1429
          {
1430
          float[] v = verts[i];
1431
          int len = v.length;
1432
          copiedVerts[i] = new float[len];
1433
          System.arraycopy(v, 0, copiedVerts[i], 0, len);
1434
          }
1435

    
1436
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1437
        }
1438

    
1439
      meshes[face].setEffectAssociation(0,0,face);
1440
      }
1441

    
1442
    MeshBase mesh = new MeshJoined(meshes);
1443
    Static3D center = new Static3D(0,0,0);
1444

    
1445
    for(int face=0; face<numFaces; face++)
1446
      {
1447
      fInfo = mNewFaceTransf.get(face);
1448

    
1449
      float vx = fInfo.vx;
1450
      float vy = fInfo.vy;
1451
      float vz = fInfo.vz;
1452
      float sc = fInfo.scale;
1453
      float qx = fInfo.qx;
1454
      float qy = fInfo.qy;
1455
      float qz = fInfo.qz;
1456
      float qw = fInfo.qw;
1457

    
1458
      Static3D scale = new Static3D(sc,sc,sc);
1459
      Static3D move3D= new Static3D(vx,vy,vz);
1460
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1461

    
1462
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1463
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1464
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1465
      }
1466

    
1467
    correctComponents(mesh,numComponents);
1468
    if( effects!=null ) applyVertexEffects(mesh,effects,meshState);
1469

    
1470
    return mesh;
1471
    }
1472
  }
(5-5/16)