Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / FactoryCubit.java @ 49cfdaa6

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
// even if this is a multigon, then FaceTransform.vertices is the outer edge!
851
// (see fitInSquare multigon variant)
852

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

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

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

    
870
      int oldSticker = oldInfo.sticker;
871
      float[] buffer1 = new float[oldLen];
872

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

    
880
    return false;
881
    }
882

    
883
///////////////////////////////////////////////////////////////////////////////////////////////////
884
// polygon
885

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

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

    
900
    return ret;
901
    }
902

    
903
///////////////////////////////////////////////////////////////////////////////////////////////////
904
// multigon
905

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

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

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

    
928
    return ret;
929
    }
930

    
931
///////////////////////////////////////////////////////////////////////////////////////////////////
932

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

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

    
950
///////////////////////////////////////////////////////////////////////////////////////////////////
951

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

    
956
    mesh.mergeEffComponents();
957

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

    
961
///////////////////////////////////////////////////////////////////////////////////////////////////
962

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

    
969
///////////////////////////////////////////////////////////////////////////////////////////////////
970

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

    
975
    bands[0] = 1.0f;
976
    bands[1] = 0.0f;
977

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

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

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

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

    
1014
    bands[2*N-2] = 0.0f;
1015
    bands[2*N-1] =    H;
1016

    
1017
    return bands;
1018
    }
1019

    
1020
///////////////////////////////////////////////////////////////////////////////////////////////////
1021

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

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

    
1040
      mQuat2[0] = -mQuat1[0];
1041
      mQuat2[1] = -mQuat1[1];
1042
      mQuat2[2] = -mQuat1[2];
1043
      mQuat2[3] =  mQuat1[3];
1044

    
1045
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1046
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1047

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

    
1054
///////////////////////////////////////////////////////////////////////////////////////////////////
1055

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

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

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

    
1069
///////////////////////////////////////////////////////////////////////////////////////////////////
1070
// INTERNAL API
1071

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

    
1077
    android.util.Log.d("D", "---- STICKER COORDS ----");
1078

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

    
1083
      if( info.outer )  ret++;
1084

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

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

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

    
1098
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1099

    
1100
    return ret;
1101
    }
1102

    
1103
///////////////////////////////////////////////////////////////////////////////////////////////////
1104

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

    
1109
    int oldfaces = mOldFaceTransf.size();
1110

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

    
1116
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1117

    
1118
    int newfaces = mNewFaceTransf.size();
1119

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

    
1126
///////////////////////////////////////////////////////////////////////////////////////////////////
1127
// PUBLIC API
1128

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

    
1135
///////////////////////////////////////////////////////////////////////////////////////////////////
1136

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

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

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

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

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

    
1175
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1176
    }
1177

    
1178
///////////////////////////////////////////////////////////////////////////////////////////////////
1179

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

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

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

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

    
1196
      return scales;
1197
      }
1198

    
1199
    return null;
1200
    }
1201

    
1202
///////////////////////////////////////////////////////////////////////////////////////////////////
1203

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

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

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

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

    
1220
      return coords;
1221
      }
1222

    
1223
    return null;
1224
    }
1225

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

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

    
1232
    int oldfaces = mOldFaceTransf.size();
1233

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

    
1240
    int[][] ret = new int[numvariants][];
1241
    int inner=0, index=-1;
1242

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

    
1253
      ret[index][inner++] = ft.sticker;
1254
      }
1255

    
1256
    int newfaces = mNewFaceTransf.size();
1257

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

    
1268
      ret[index][inner++] = ft.sticker;
1269
      }
1270

    
1271
    int numStickers = mStickerCoords.size();
1272
    int numOuter=0;
1273

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

    
1288
    return ret;
1289
    }
1290

    
1291
///////////////////////////////////////////////////////////////////////////////////////////////////
1292

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

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

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

    
1311
///////////////////////////////////////////////////////////////////////////////////////////////////
1312

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

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

    
1328
    int numFaces = shape.getNumFaces();
1329
    int numOld = mOldFaceTransf.size();
1330

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

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

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

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

    
1360
      mNewFaceTransf.add(newT);
1361
      }
1362
    }
1363

    
1364
///////////////////////////////////////////////////////////////////////////////////////////////////
1365

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

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

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

    
1388
      int index = bandIndexes[face];
1389
      band = bands[index];
1390

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

    
1412
      bandsComputed = computeBands(height,alpha,dist,K,N);
1413

    
1414
      sInfo = mStickerCoords.get(fInfo.sticker);
1415
      float[][] vertsF = sInfo.fullVertices;
1416

    
1417
      // i.e. multigon which hasn't been 'successfully collapsed'
1418
      // with a previously computed polygon sticker!
1419
      if( vertsF!=null )
1420
        {
1421
        int lenVerts = vertsF.length;
1422
        float[][] copiedVerts = new float[lenVerts][];
1423

    
1424
        for(int i=0; i<lenVerts; i++)
1425
          {
1426
          float[] v = vertsF[i];
1427
          int len = v.length;
1428
          copiedVerts[i] = new float[len];
1429
          System.arraycopy(v, 0, copiedVerts[i], 0, len);
1430
          }
1431

    
1432
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1433
        }
1434
      else
1435
        {
1436
        float[] verts = sInfo.vertices;
1437
        int lenVerts = verts.length;
1438
        float[] copiedVerts = new float[lenVerts];
1439
        System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1440
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1441
        }
1442

    
1443
      meshes[face].setEffectAssociation(0,0,face);
1444
      }
1445

    
1446
    MeshBase mesh = new MeshJoined(meshes);
1447
    Static3D center = new Static3D(0,0,0);
1448

    
1449
    for(int face=0; face<numFaces; face++)
1450
      {
1451
      fInfo = mNewFaceTransf.get(face);
1452

    
1453
      float vx = fInfo.vx;
1454
      float vy = fInfo.vy;
1455
      float vz = fInfo.vz;
1456
      float sc = fInfo.scale;
1457
      float qx = fInfo.qx;
1458
      float qy = fInfo.qy;
1459
      float qz = fInfo.qz;
1460
      float qw = fInfo.qw;
1461

    
1462
      Static3D scale = new Static3D(sc,sc,sc);
1463
      Static3D move3D= new Static3D(vx,vy,vz);
1464
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1465

    
1466
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1467
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1468
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1469
      }
1470

    
1471
    correctComponents(mesh,numComponents);
1472
    if( effects!=null ) applyVertexEffects(mesh,effects,meshState);
1473

    
1474
    return mesh;
1475
    }
1476
  }
(6-6/17)