Project

General

Profile

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

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

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 boolean pointsTheSame(float dx, float dy)
226
    {
227
    return dx*dx + dy*dy < 0.000001f;
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
  private float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
233
    {
234
    double minAngle = 2*Math.PI;
235
    float x=0, y=0;
236

    
237
    for( float[] v : vertices )
238
      {
239
      int num = v.length/2;
240

    
241
      for( int j=0; j<num; j++)
242
        {
243
        float xc = v[2*j];
244
        float yc = v[2*j+1];
245

    
246
        if( pointsTheSame(xc-curr[0],yc-curr[1]) )
247
          {
248
          int n = (j==num-1 ? 0 : j+1);
249
          float xn = v[2*n];
250
          float yn = v[2*n+1];
251

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

    
254
          if (angle < minAngle)
255
            {
256
            minAngle = angle;
257
            x = xn;
258
            y = yn;
259
            }
260

    
261
          break;
262
          }
263
        }
264
      }
265

    
266
    return new float[] {x,y};
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270
// same as in MeshMultigon
271

    
272
  private float[] computeOuterEdge(float[][] vertices)
273
    {
274
    ArrayList<float[]> tmp = new ArrayList<>();
275

    
276
    float[] vect = new float[] {1,0};
277
    float[] first= detectFirstOuterVertex(vertices);
278
    float[] next = first;
279

    
280
    do
281
      {
282
      float[] prev = next;
283
      next = detectNextOuterVertex(vertices,next,vect);
284
      vect[0] = prev[0]-next[0];
285
      vect[1] = prev[1]-next[1];
286
      tmp.add(next);
287
      }
288
    while( !pointsTheSame(next[0]-first[0],next[1]-first[1]) );
289

    
290
    int num = tmp.size();
291
    float[] ret = new float[2*num];
292

    
293
    for(int i=0; i<num; i++)
294
      {
295
      float[] t = tmp.remove(0);
296
      ret[2*i  ] = t[0];
297
      ret[2*i+1] = t[1];
298
      }
299

    
300
    return ret;
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304
// polygon
305

    
306
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
307
    {
308
    float minX = Float.MAX_VALUE;
309
    float maxX =-Float.MAX_VALUE;
310
    float minY = Float.MAX_VALUE;
311
    float maxY =-Float.MAX_VALUE;
312

    
313
    for (float[] vert : vert3D)
314
      {
315
      float x = vert[0];
316
      float y = vert[1];
317

    
318
      if (x > maxX) maxX = x;
319
      if (x < minX) minX = x;
320
      if (y > maxY) maxY = y;
321
      if (y < minY) minY = y;
322
      }
323

    
324
    minX = minX<0 ? -minX:minX;
325
    maxX = maxX<0 ? -maxX:maxX;
326
    minY = minY<0 ? -minY:minY;
327
    maxY = maxY<0 ? -maxY:maxY;
328

    
329
    float max1 = Math.max(minX,minY);
330
    float max2 = Math.max(maxX,maxY);
331
    float max3 = Math.max(max1,max2);
332

    
333
    info.scale = max3/0.5f;
334

    
335
    int len = vert3D.length;
336
    StickerCoords sInfo = new StickerCoords();
337
    sInfo.outer = isOuter;
338
    sInfo.scale = info.scale;
339
    sInfo.vertices = new float[2*len];
340
    sInfo.fullVertices = null;
341

    
342
    for( int vertex=0; vertex<len; vertex++ )
343
      {
344
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
345
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
346
      }
347

    
348
    mStickerCoords.add(sInfo);
349

    
350
    info.sticker = mStickerCoords.size() -1;
351
    }
352

    
353

    
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355
// multigon
356

    
357
  private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
358
    {
359
    float minX = Float.MAX_VALUE;
360
    float maxX =-Float.MAX_VALUE;
361
    float minY = Float.MAX_VALUE;
362
    float maxY =-Float.MAX_VALUE;
363

    
364
    for( float[][] vert : vert3D)
365
      for( float[] v : vert)
366
        {
367
        float x = v[0];
368
        float y = v[1];
369

    
370
        if (x > maxX) maxX = x;
371
        if (x < minX) minX = x;
372
        if (y > maxY) maxY = y;
373
        if (y < minY) minY = y;
374
        }
375

    
376
    minX = minX<0 ? -minX:minX;
377
    maxX = maxX<0 ? -maxX:maxX;
378
    minY = minY<0 ? -minY:minY;
379
    maxY = maxY<0 ? -maxY:maxY;
380

    
381
    float max1 = Math.max(minX,minY);
382
    float max2 = Math.max(maxX,maxY);
383
    float max3 = Math.max(max1,max2);
384

    
385
    info.scale = max3/0.5f;
386

    
387
    int len = vert3D.length;
388
    StickerCoords sInfo = new StickerCoords();
389
    sInfo.outer = isOuter;
390
    sInfo.scale = info.scale;
391
    sInfo.fullVertices = new float[len][];
392

    
393
    for( int comp=0; comp<len; comp++ )
394
      {
395
      float[][] vert = vert3D[comp];
396
      int num = vert.length;
397
      sInfo.fullVertices[comp] = new float[2*num];
398
      float[] t = sInfo.fullVertices[comp];
399

    
400
      for( int vertex=0; vertex<num; vertex++)
401
        {
402
        t[2*vertex  ] = vert[vertex][0] / info.scale;
403
        t[2*vertex+1] = vert[vertex][1] / info.scale;
404
        }
405
      }
406

    
407
    sInfo.vertices = computeOuterEdge(sInfo.fullVertices);
408

    
409
    mStickerCoords.add(sInfo);
410

    
411
    info.sticker = mStickerCoords.size() -1;
412
    }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415
// polygon
416

    
417
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
418
    {
419
    FaceTransform ft = new FaceTransform();
420
    ft.face = face;
421
    ft.numFaces = numFaces;
422

    
423
    // compute center of gravity
424
    ft.vx = 0.0f;
425
    ft.vy = 0.0f;
426
    ft.vz = 0.0f;
427
    int len = vert3D.length;
428

    
429
    for (float[] vert : vert3D)
430
      {
431
      ft.vx += vert[0];
432
      ft.vy += vert[1];
433
      ft.vz += vert[2];
434
      }
435

    
436
    ft.vx /= len;
437
    ft.vy /= len;
438
    ft.vz /= len;
439

    
440
    // move all vertices so that their center of gravity is at (0,0,0)
441
    for (int i=0; i<len; i++)
442
      {
443
      vert3D[i][0] -= ft.vx;
444
      vert3D[i][1] -= ft.vy;
445
      vert3D[i][2] -= ft.vz;
446
      }
447

    
448
    // find 3 non-colinear vertices
449
    int foundIndex = -1;
450

    
451
    for(int vertex=2; vertex<len; vertex++)
452
      {
453
      if( !areColinear(vert3D,0,1,vertex) )
454
        {
455
        foundIndex = vertex;
456
        break;
457
        }
458
      }
459

    
460
    // compute the normal vector
461
    if( foundIndex==-1 )
462
      {
463
      StringBuilder sb = new StringBuilder();
464

    
465
      for (float[] floats : vert3D)
466
        {
467
        sb.append(' ');
468
        sb.append("(");
469
        sb.append(floats[0]);
470
        sb.append(" ");
471
        sb.append(floats[1]);
472
        sb.append(" ");
473
        sb.append(floats[2]);
474
        sb.append(")");
475
        }
476
      android.util.Log.e("D", "verts: "+sb);
477

    
478
      throw new RuntimeException("all vertices colinear");
479
      }
480

    
481
    computeNormalVector(vert3D,0,1,foundIndex);
482

    
483
    // rotate so that the normal vector becomes (0,0,1)
484
    float axisX, axisY, axisZ;
485

    
486
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
487
      {
488
      axisX = -mBuffer[1];
489
      axisY =  mBuffer[0];
490
      axisZ = 0.0f;
491

    
492
      float axiLen = axisX*axisX + axisY*axisY;
493
      axiLen = (float)Math.sqrt(axiLen);
494
      axisX /= axiLen;
495
      axisY /= axiLen;
496
      axisZ /= axiLen;
497
      }
498
    else
499
      {
500
      axisX = 0.0f;
501
      axisY = 1.0f;
502
      axisZ = 0.0f;
503
      }
504

    
505
    float cosTheta = mBuffer[2];
506
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
507
    float sinHalfTheta = computeSinHalf(cosTheta);
508
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
509

    
510
    mQuat1[0] = axisX*sinHalfTheta;
511
    mQuat1[1] = axisY*sinHalfTheta;
512
    mQuat1[2] = axisZ*sinHalfTheta;
513
    mQuat1[3] = cosHalfTheta;
514
    mQuat2[0] =-axisX*sinHalfTheta;
515
    mQuat2[1] =-axisY*sinHalfTheta;
516
    mQuat2[2] =-axisZ*sinHalfTheta;
517
    mQuat2[3] = cosHalfTheta;
518

    
519
    for (float[] vert : vert3D)
520
      {
521
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
522
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
523
      }
524

    
525
    // fit the whole thing in a square and remember the scale & 2D vertices
526
    fitInSquare(ft, vert3D, isOuter);
527

    
528
    // remember the rotation
529
    ft.qx =-mQuat1[0];
530
    ft.qy =-mQuat1[1];
531
    ft.qz =-mQuat1[2];
532
    ft.qw = mQuat1[3];
533

    
534
    return ft;
535
    }
536

    
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538
// multigon
539

    
540
  private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
541
    {
542
    FaceTransform ft = new FaceTransform();
543
    ft.face = face;
544
    ft.numFaces = numFaces;
545

    
546
    // compute center of gravity
547
    ft.vx = 0.0f;
548
    ft.vy = 0.0f;
549
    ft.vz = 0.0f;
550
    int len = 0;
551

    
552
    for( float[][] vert : vert3D )
553
      for( float[] v : vert )
554
        {
555
        ft.vx += v[0];
556
        ft.vy += v[1];
557
        ft.vz += v[2];
558
        len++;
559
        }
560

    
561
    ft.vx /= len;
562
    ft.vy /= len;
563
    ft.vz /= len;
564

    
565
    // move all vertices so that their center of gravity is at (0,0,0)
566
    for( float[][] vert : vert3D )
567
      for( float[] v : vert )
568
        {
569
        v[0] -= ft.vx;
570
        v[1] -= ft.vy;
571
        v[2] -= ft.vz;
572
        }
573

    
574
    // find 3 non-colinear vertices
575
    int foundIndex = -1;
576
    len = vert3D[0].length;
577

    
578
    for(int vertex=2; vertex<len; vertex++)
579
      {
580
      if( !areColinear(vert3D[0],0,1,vertex) )
581
        {
582
        foundIndex = vertex;
583
        break;
584
        }
585
      }
586

    
587
    // compute the normal vector
588
    if( foundIndex==-1 )
589
      {
590
      StringBuilder sb = new StringBuilder();
591

    
592
      for (float[] v : vert3D[0])
593
        {
594
        sb.append(' ');
595
        sb.append("(");
596
        sb.append(v[0]);
597
        sb.append(" ");
598
        sb.append(v[1]);
599
        sb.append(" ");
600
        sb.append(v[2]);
601
        sb.append(")");
602
        }
603
      android.util.Log.e("D", "verts: "+sb);
604

    
605
      throw new RuntimeException("all vertices colinear");
606
      }
607

    
608
    computeNormalVector(vert3D[0],0,1,foundIndex);
609

    
610
    // rotate so that the normal vector becomes (0,0,1)
611
    float axisX, axisY, axisZ;
612

    
613
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
614
      {
615
      axisX = -mBuffer[1];
616
      axisY =  mBuffer[0];
617
      axisZ = 0.0f;
618

    
619
      float axiLen = axisX*axisX + axisY*axisY;
620
      axiLen = (float)Math.sqrt(axiLen);
621
      axisX /= axiLen;
622
      axisY /= axiLen;
623
      axisZ /= axiLen;
624
      }
625
    else
626
      {
627
      axisX = 0.0f;
628
      axisY = 1.0f;
629
      axisZ = 0.0f;
630
      }
631

    
632
    float cosTheta = mBuffer[2];
633
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
634
    float sinHalfTheta = computeSinHalf(cosTheta);
635
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
636

    
637
    mQuat1[0] = axisX*sinHalfTheta;
638
    mQuat1[1] = axisY*sinHalfTheta;
639
    mQuat1[2] = axisZ*sinHalfTheta;
640
    mQuat1[3] = cosHalfTheta;
641
    mQuat2[0] =-axisX*sinHalfTheta;
642
    mQuat2[1] =-axisY*sinHalfTheta;
643
    mQuat2[2] =-axisZ*sinHalfTheta;
644
    mQuat2[3] = cosHalfTheta;
645

    
646
    for( float[][] vert : vert3D)
647
      for( float[] v : vert)
648
        {
649
        QuatHelper.quatMultiply(mQuat3, mQuat1, v  );
650
        QuatHelper.quatMultiply(  v, mQuat3, mQuat2);
651
        }
652

    
653
    // fit the whole thing in a square and remember the scale & 2D vertices
654
    fitInSquare(ft, vert3D, isOuter);
655

    
656
    // remember the rotation
657
    ft.qx =-mQuat1[0];
658
    ft.qy =-mQuat1[1];
659
    ft.qz =-mQuat1[2];
660
    ft.qw = mQuat1[3];
661

    
662
    return ft;
663
    }
664

    
665
///////////////////////////////////////////////////////////////////////////////////////////////////
666

    
667
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
668
    {
669
    for(int i=0; i<len; i++)
670
      {
671
      float x = vertices[2*i];
672
      float y = vertices[2*i+1];
673
      result[2*i  ] = x*cos - y*sin;
674
      result[2*i+1] = x*sin + y*cos;
675
      }
676
    }
677

    
678
///////////////////////////////////////////////////////////////////////////////////////////////////
679

    
680
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
681
    {
682
    float v1x = v1[2*v1i];
683
    float v1y = v1[2*v1i+1];
684
    float v2x = v2[2*v2i];
685
    float v2y = v2[2*v2i+1];
686

    
687
    float lenSq1 = v1x*v1x + v1y*v1y;
688
    float lenSq2 = v2x*v2x + v2y*v2y;
689

    
690
    return (float)Math.sqrt(lenSq2/lenSq1);
691
    }
692

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

    
696
  private float computeSinHalf(float cos)
697
    {
698
    return (float)Math.sqrt((1-cos)/2);
699
    }
700

    
701
///////////////////////////////////////////////////////////////////////////////////////////////////
702
// valid for 0<angle<2*PI
703

    
704
  private float computeCosHalf(float sin, float cos)
705
    {
706
    float cosHalf = (float)Math.sqrt((1+cos)/2);
707
    return sin<0 ? -cosHalf : cosHalf;
708
    }
709

    
710
///////////////////////////////////////////////////////////////////////////////////////////////////
711

    
712
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
713
    {
714
    int v = (rotatedVertex + oldVertex);
715
    if( v>=len ) v-=len;
716
    if( v< 0   ) v+=len;
717

    
718
    return v;
719
    }
720

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

    
723
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex)
724
    {
725
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
726
    float EPSILON = 0.001f;
727
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
728

    
729
    for(int i=1; i<len; i++)
730
      {
731
      int index = computeRotatedIndex(i,len,vertex);
732

    
733
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
734
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
735

    
736
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
737
      }
738

    
739
    return true;
740
    }
741

    
742
///////////////////////////////////////////////////////////////////////////////////////////////////
743

    
744
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
745
    {
746
    mStickerCoords.remove(info.sticker);
747

    
748
    info.sticker = oldSticker;
749
    info.scale  *= scale;
750

    
751
    mQuat1[0] = info.qx;
752
    mQuat1[1] = info.qy;
753
    mQuat1[2] = info.qz;
754
    mQuat1[3] = info.qw;
755

    
756
    float sinHalf = computeSinHalf(cos);
757
    float cosHalf = computeCosHalf(sin,cos);
758

    
759
    mQuat2[0] = 0.0f;
760
    mQuat2[1] = 0.0f;
761
    mQuat2[2] = sinHalf;
762
    mQuat2[3] = cosHalf;
763

    
764
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
765

    
766
    info.qx = mQuat3[0];
767
    info.qy = mQuat3[1];
768
    info.qz = mQuat3[2];
769
    info.qw = mQuat3[3];
770
    }
771

    
772
///////////////////////////////////////////////////////////////////////////////////////////////////
773

    
774
  private void printVert(double[] buffer)
775
    {
776
    int len = buffer.length/2;
777
    String str = "";
778

    
779
    for(int i=0; i<len; i++)
780
      {
781
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
782
      }
783

    
784
    android.util.Log.d("D", str);
785
    }
786

    
787
///////////////////////////////////////////////////////////////////////////////////////////////////
788

    
789
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert, float[] oldVert, int oldSticker)
790
    {
791
    int lenVertOld = oldVert.length/2;
792
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
793

    
794
    for(int oldV=0; oldV<lenVertOld; oldV++)
795
      {
796
      oldX = oldVert[2*oldV];
797
      oldY = oldVert[2*oldV+1];
798
      lenOld = (float)Math.sqrt(oldX*oldX + oldY*oldY);
799

    
800
      if( lenOld!=0 ) break;
801
      }
802

    
803
    for(int vertex=0; vertex<len; vertex++)
804
      {
805
      float newX = newVert[2*vertex  ];
806
      float newY = newVert[2*vertex+1];
807
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
808

    
809
      if( lenNew!=0 )
810
        {
811
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
812
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
813

    
814
        rotateAllVertices(buffer,len,newVert,sin,cos);
815

    
816
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
817
          {
818
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
819
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
820
          correctInfo(info,scale,sin,cos,oldSticker);
821
          return true;
822
          }
823
        }
824
      }
825

    
826
    return false;
827
    }
828

    
829
///////////////////////////////////////////////////////////////////////////////////////////////////
830

    
831
  private float computeCoreDistance(float[] verts)
832
    {
833
    float ret = 0.0f;
834
    float centerX=0.0f,centerY=0.0f;
835
    int len = verts.length/2;
836

    
837
    for(int i=0; i<len; i++)
838
      {
839
      centerX += verts[2*i  ];
840
      centerY += verts[2*i+1];
841
      }
842

    
843
    centerX /= (2*len);
844
    centerY /= (2*len);
845

    
846
    for(int i=0; i<len; i++)
847
      {
848
      float distX = centerX-verts[2*i  ];
849
      float distY = centerY-verts[2*i+1];
850
      ret += (float)Math.sqrt(distX*distX + distY*distY);
851
      }
852

    
853
    return ret;
854
    }
855

    
856
///////////////////////////////////////////////////////////////////////////////////////////////////
857
// even if this is a multigon, then FaceTransform.vertices is the outer edge!
858
// (see fitInSquare multigon variant)
859

    
860
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
861
    {
862
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
863
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
864

    
865
    float[] newVert = sNewInfo.vertices;
866
    float[] oldVert = sOldInfo.vertices;
867
    int oldLen = oldVert.length;
868
    int newLen = newVert.length;
869

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

    
877
      int oldSticker = oldInfo.sticker;
878
      float[] buffer1 = new float[oldLen];
879

    
880
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, oldSticker) )
881
        {
882
        if( sNewInfo.outer ) sOldInfo.outer = true;
883
        return true;
884
        }
885
      }
886

    
887
    return false;
888
    }
889

    
890
///////////////////////////////////////////////////////////////////////////////////////////////////
891
// polygon
892

    
893
  private float[][] constructVert(float[][] vertices, int[] index)
894
    {
895
    int len = index.length;
896
    float[][] ret = new float[len][4];
897

    
898
    for(int i=0; i<len; i++)
899
      {
900
      float[] tmp = vertices[index[i]];
901
      ret[i][0] = tmp[0];
902
      ret[i][1] = tmp[1];
903
      ret[i][2] = tmp[2];
904
      ret[i][3] = 1.0f;
905
      }
906

    
907
    return ret;
908
    }
909

    
910
///////////////////////////////////////////////////////////////////////////////////////////////////
911
// multigon
912

    
913
  private float[][][] constructVert(float[][] vertices, int[][] index)
914
    {
915
    int len = index.length;
916
    float[][][] ret = new float[len][][];
917

    
918
    for(int i=0; i<len; i++)
919
      {
920
      int[] ind = index[i];
921
      int num = ind.length;
922
      ret[i] = new float[num][4];
923

    
924
      for(int j=0; j<num; j++)
925
        {
926
        float[] r = ret[i][j];
927
        float[] v = vertices[ind[j]];
928
        r[0] = v[0];
929
        r[1] = v[1];
930
        r[2] = v[2];
931
        r[3] = 1.0f;
932
        }
933
      }
934

    
935
    return ret;
936
    }
937

    
938
///////////////////////////////////////////////////////////////////////////////////////////////////
939

    
940
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects, int meshState)
941
    {
942
    boolean[] uses      = effects.getUses();
943
    String[] names      = effects.getNames();
944
    float[][] variables = effects.getVariables();
945
    float[][] centers   = effects.getCenters();
946
    float[][] regions   = effects.getRegions();
947
    int numEffects = uses.length;
948

    
949
    for(int eff=0; eff<numEffects; eff++)
950
      if( names[eff]!=null && (meshState==MESH_NICE || uses[eff]) )
951
        {
952
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
953
        if( effect!=null ) mesh.apply(effect);
954
        }
955
    }
956

    
957
///////////////////////////////////////////////////////////////////////////////////////////////////
958

    
959
  private void correctComponents(MeshBase mesh, int numComponents)
960
    {
961
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
962

    
963
    mesh.mergeEffComponents();
964

    
965
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
966
    }
967

    
968
///////////////////////////////////////////////////////////////////////////////////////////////////
969

    
970
  private void printTransform(FaceTransform f)
971
    {
972
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
973
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
974
    }
975

    
976
///////////////////////////////////////////////////////////////////////////////////////////////////
977

    
978
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
979
    {
980
    float[] bands = new float[2*N];
981

    
982
    bands[0] = 1.0f;
983
    bands[1] = 0.0f;
984

    
985
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
986
    float sinBeta = (float)Math.sin(beta);
987
    float cosBeta = (float)Math.cos(beta);
988
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
989
    float D = R*sinBeta;
990
    float B = h(R,sinBeta,K*beta);
991

    
992
    if( D>1.0f )
993
      {
994
      for(int i=1; i<N; i++)
995
        {
996
        bands[2*i  ] = (float)(N-1-i)/(N-1);
997
        bands[2*i+1] = H*(1-bands[2*i]);
998
        }
999
      }
1000
    else
1001
      {
1002
      int K2 = (int)((N-3)*K);
1003
      int K1 = (N-3)-K2;
1004

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

    
1013
      for(int i=0; i<=K2; i++)
1014
        {
1015
        float x = (1-B)*(i+1)/(K2+1) + B;
1016
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
1017
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
1018
        }
1019
      }
1020

    
1021
    bands[2*N-2] = 0.0f;
1022
    bands[2*N-1] =    H;
1023

    
1024
    return bands;
1025
    }
1026

    
1027
///////////////////////////////////////////////////////////////////////////////////////////////////
1028

    
1029
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
1030
    {
1031
    if( in==null )
1032
      {
1033
      out[0] = out[1] = 0.0f;
1034
      }
1035
    else
1036
      {
1037
      out[0] = in[0] - ft.vx;
1038
      out[1] = in[1] - ft.vy;
1039
      out[2] = in[2] - ft.vz;
1040
      out[3] = 1.0f;
1041

    
1042
      mQuat1[0] =-ft.qx;
1043
      mQuat1[1] =-ft.qy;
1044
      mQuat1[2] =-ft.qz;
1045
      mQuat1[3] = ft.qw;
1046

    
1047
      mQuat2[0] = -mQuat1[0];
1048
      mQuat2[1] = -mQuat1[1];
1049
      mQuat2[2] = -mQuat1[2];
1050
      mQuat2[3] =  mQuat1[3];
1051

    
1052
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1053
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1054

    
1055
      out[0] /= ft.scale;
1056
      out[1] /= ft.scale;
1057
      out[2] /= ft.scale;
1058
      }
1059
    }
1060

    
1061
///////////////////////////////////////////////////////////////////////////////////////////////////
1062

    
1063
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
1064
    {
1065
    int len = table.length;
1066

    
1067
    for(int i=0; i<len; i++)
1068
      {
1069
      int lenInner = table[i].length;
1070

    
1071
      for(int j=0; j<lenInner; j++)
1072
        if( table[i][j]==oldPointer ) table[i][j] = newPointer;
1073
      }
1074
    }
1075

    
1076
///////////////////////////////////////////////////////////////////////////////////////////////////
1077
// INTERNAL API
1078

    
1079
  public int printStickerCoords()
1080
    {
1081
    int stickers = mStickerCoords.size();
1082
    int ret = 0;
1083

    
1084
    android.util.Log.d("D", "---- STICKER COORDS ----");
1085

    
1086
    for(int s=0; s<stickers; s++)
1087
      {
1088
      StickerCoords info = mStickerCoords.get(s);
1089

    
1090
      if( info.outer )  ret++;
1091

    
1092
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
1093
      int len = info.vertices.length/2;
1094

    
1095
      for(int i =0; i<len; i++)
1096
        {
1097
        if( i!=0 ) ver += ", ";
1098
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
1099
        }
1100

    
1101
      ver += " }";
1102
      android.util.Log.d("D", ver);
1103
      }
1104

    
1105
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1106

    
1107
    return ret;
1108
    }
1109

    
1110
///////////////////////////////////////////////////////////////////////////////////////////////////
1111

    
1112
  public void printFaceTransform()
1113
    {
1114
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1115

    
1116
    int oldfaces = mOldFaceTransf.size();
1117

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

    
1123
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1124

    
1125
    int newfaces = mNewFaceTransf.size();
1126

    
1127
    for(int f=0; f<newfaces; f++)
1128
      {
1129
      printTransform(mNewFaceTransf.get(f));
1130
      }
1131
    }
1132

    
1133
///////////////////////////////////////////////////////////////////////////////////////////////////
1134
// PUBLIC API
1135

    
1136
  public static FactoryCubit getInstance()
1137
    {
1138
    if( mThis==null ) mThis = new FactoryCubit();
1139
    return mThis;
1140
    }
1141

    
1142
///////////////////////////////////////////////////////////////////////////////////////////////////
1143

    
1144
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
1145
                                                          float[][] corners, int[] cornerIndices,
1146
                                                          float[][] centers, int[] centerIndices )
1147
    {
1148
    int numVerts = vertices.length;
1149
    String[] names = new String[numVerts];
1150
    float[][] vars = new float[numVerts][];
1151
    float[][] cents= new float[numVerts][];
1152
    float[][] regs = new float[numVerts][];
1153
    boolean[] uses = new boolean[numVerts];
1154

    
1155
    for(int i=0; i<numVerts; i++)
1156
      {
1157
      int centerI = centerIndices[i];
1158
      int cornerI = cornerIndices[i];
1159

    
1160
      if( centerI>=0 && cornerI>=0 )
1161
        {
1162
        float[] ce = centers[centerI];
1163
        float[] ve = vertices[i];
1164
        float S = corners[cornerI][0];
1165
        float R = corners[cornerI][1];
1166

    
1167
        float CX = ve[0];
1168
        float CY = ve[1];
1169
        float CZ = ve[2];
1170
        float X = S*(ce[0]-CX);
1171
        float Y = S*(ce[1]-CY);
1172
        float Z = S*(ce[2]-CZ);
1173

    
1174
        names[i]= NAME;
1175
        vars[i] = new float[] { 0, X,Y,Z, 1 };
1176
        cents[i]= new float[] { CX, CY, CZ };
1177
        regs[i] = new float[] { 0,0,0, R };
1178
        uses[i] = false;
1179
        }
1180
      }
1181

    
1182
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1183
    }
1184

    
1185
///////////////////////////////////////////////////////////////////////////////////////////////////
1186

    
1187
  public float[] getStickerScales()
1188
    {
1189
    int index=0,num=0,len = mStickerCoords.size();
1190

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

    
1193
    if( num>0 )
1194
      {
1195
      float[] scales = new float[num];
1196

    
1197
      for(int i=0; i<len; i++)
1198
        {
1199
        StickerCoords sticker = mStickerCoords.get(i);
1200
        if( sticker.outer ) scales[index++] = sticker.scale;
1201
        }
1202

    
1203
      return scales;
1204
      }
1205

    
1206
    return null;
1207
    }
1208

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

    
1211
  public float[][] getStickerCoords()
1212
    {
1213
    int index=0,num=0,len = mStickerCoords.size();
1214

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

    
1217
    if( num>0 )
1218
      {
1219
      float[][] coords = new float[num][];
1220

    
1221
      for(int i=0; i<len; i++)
1222
        {
1223
        StickerCoords sticker = mStickerCoords.get(i);
1224
        if( sticker.outer ) coords[index++] = sticker.vertices;
1225
        }
1226

    
1227
      return coords;
1228
      }
1229

    
1230
    return null;
1231
    }
1232

    
1233
///////////////////////////////////////////////////////////////////////////////////////////////////
1234

    
1235
  public int[][] getStickerVariants()
1236
    {
1237
    int numvariants = 1; // there's one in the 'new' array
1238

    
1239
    int oldfaces = mOldFaceTransf.size();
1240

    
1241
    for(int f=0; f<oldfaces; f++)
1242
      {
1243
      FaceTransform ft = mOldFaceTransf.get(f);
1244
      if( ft.face==0 ) numvariants++;
1245
      }
1246

    
1247
    int[][] ret = new int[numvariants][];
1248
    int inner=0, index=-1;
1249

    
1250
    for(int f=0; f<oldfaces; f++)
1251
      {
1252
      FaceTransform ft = mOldFaceTransf.get(f);
1253
      if( ft.face==0 )
1254
        {
1255
        index++;
1256
        inner=0;
1257
        ret[index] = new int[ft.numFaces];
1258
        }
1259

    
1260
      ret[index][inner++] = ft.sticker;
1261
      }
1262

    
1263
    int newfaces = mNewFaceTransf.size();
1264

    
1265
    for(int f=0; f<newfaces; f++)
1266
      {
1267
      FaceTransform ft = mNewFaceTransf.get(f);
1268
      if( ft.face==0 )
1269
        {
1270
        index++;
1271
        inner=0;
1272
        ret[index] = new int[ft.numFaces];
1273
        }
1274

    
1275
      ret[index][inner++] = ft.sticker;
1276
      }
1277

    
1278
    int numStickers = mStickerCoords.size();
1279
    int numOuter=0;
1280

    
1281
    for(int i=0; i<numStickers; i++)
1282
      {
1283
      StickerCoords sc = mStickerCoords.get(i);
1284
      if( sc.outer )
1285
        {
1286
        changeStickerPointers(ret,i,numOuter);
1287
        numOuter++;
1288
        }
1289
      else
1290
        {
1291
        changeStickerPointers(ret,i,-1);
1292
        }
1293
      }
1294

    
1295
    return ret;
1296
    }
1297

    
1298
///////////////////////////////////////////////////////////////////////////////////////////////////
1299

    
1300
  public void clear()
1301
    {
1302
    mStickerCoords.clear();
1303
    mNewFaceTransf.clear();
1304
    mOldFaceTransf.clear();
1305
    }
1306

    
1307
///////////////////////////////////////////////////////////////////////////////////////////////////
1308
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
1309
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
1310
// been called.
1311

    
1312
  public Static4D getQuaternion(int face)
1313
    {
1314
    FaceTransform ft = mNewFaceTransf.get(face);
1315
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
1316
    }
1317

    
1318
///////////////////////////////////////////////////////////////////////////////////////////////////
1319

    
1320
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1321
    {
1322
    float[][] vertices = shape.getVertices();
1323
    int[][] indices = shape.getVertIndices();
1324
    int[][][] fullIndices = shape.getMultigonIndices();
1325
    boolean isMultigon = shape.isMultigon();
1326
    FaceTransform ft;
1327
    int numNew = mNewFaceTransf.size();
1328

    
1329
    for(int i=0; i<numNew; i++)
1330
      {
1331
      ft = mNewFaceTransf.remove(0);
1332
      mOldFaceTransf.add(ft);
1333
      }
1334

    
1335
    int numFaces = shape.getNumFaces();
1336
    int numOld = mOldFaceTransf.size();
1337

    
1338
    for (int face=0; face<numFaces; face++)
1339
      {
1340
      boolean collapsed = false;
1341
      boolean isOuter = (outer!=null && outer[face]>0);
1342
      FaceTransform newT;
1343

    
1344
      if( !isMultigon )
1345
        {
1346
        float[][] vert = constructVert(vertices, indices[face]);
1347
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1348
        }
1349
      else
1350
        {
1351
        float[][][] vert = constructVert(vertices, fullIndices[face]);
1352
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1353
        }
1354

    
1355
      for (int old=0; !collapsed && old<numOld; old++)
1356
        {
1357
        ft = mOldFaceTransf.get(old);
1358
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1359
        }
1360

    
1361
      for (int pre=0; !collapsed && pre<face; pre++)
1362
        {
1363
        ft = mNewFaceTransf.get(pre);
1364
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1365
        }
1366

    
1367
      mNewFaceTransf.add(newT);
1368
      }
1369
    }
1370

    
1371
///////////////////////////////////////////////////////////////////////////////////////////////////
1372

    
1373
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1374
                                     final ObjectVertexEffects effects, int meshState, int numComponents)
1375
    {
1376
    float[][] bands         = faceShape.getBands();
1377
    int[]   bandIndexes     = faceShape.getBandIndices();
1378
    float[] convexityCenter = faceShape.getConvexityCenter();
1379

    
1380
    int numFaces = shape.getNumFaces();
1381
    boolean multigonMode = shape.isMultigon();
1382
    float[] band, bandsComputed;
1383
    MeshBase[] meshes = new MeshBase[numFaces];
1384
    FaceTransform fInfo;
1385
    StickerCoords sInfo;
1386
    float[] convexXY = new float[4];
1387
    int exIndex=0, exVertices=0, alpha=0, N=0;
1388
    float height=0.0f, dist=0.0f, K=0.0f;
1389

    
1390
    for(int face=0; face<numFaces; face++)
1391
      {
1392
      fInfo = mNewFaceTransf.get(face);
1393
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1394

    
1395
      int index = bandIndexes[face];
1396
      band = bands[index];
1397

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

    
1419
      bandsComputed = computeBands(height,alpha,dist,K,N);
1420

    
1421
      sInfo = mStickerCoords.get(fInfo.sticker);
1422
      float[][] vertsF = sInfo.fullVertices;
1423

    
1424
      // i.e. multigon which hasn't been 'successfully collapsed'
1425
      // with a previously computed polygon sticker!
1426
      if( vertsF!=null )
1427
        {
1428
        int lenVerts = vertsF.length;
1429
        float[][] copiedVerts = new float[lenVerts][];
1430

    
1431
        for(int i=0; i<lenVerts; i++)
1432
          {
1433
          float[] v = vertsF[i];
1434
          int len = v.length;
1435
          copiedVerts[i] = new float[len];
1436
          System.arraycopy(v, 0, copiedVerts[i], 0, len);
1437
          }
1438

    
1439
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1440
        }
1441
      else
1442
        {
1443
        float[] verts = sInfo.vertices;
1444
        int lenVerts = verts.length;
1445
        float[] copiedVerts = new float[lenVerts];
1446
        System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1447
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1448
        }
1449

    
1450
      meshes[face].setEffectAssociation(0,0,face);
1451
      }
1452

    
1453
    MeshBase mesh = new MeshJoined(meshes);
1454
    Static3D center = new Static3D(0,0,0);
1455

    
1456
    for(int face=0; face<numFaces; face++)
1457
      {
1458
      fInfo = mNewFaceTransf.get(face);
1459

    
1460
      float vx = fInfo.vx;
1461
      float vy = fInfo.vy;
1462
      float vz = fInfo.vz;
1463
      float sc = fInfo.scale;
1464
      float qx = fInfo.qx;
1465
      float qy = fInfo.qy;
1466
      float qz = fInfo.qz;
1467
      float qw = fInfo.qw;
1468

    
1469
      Static3D scale = new Static3D(sc,sc,sc);
1470
      Static3D move3D= new Static3D(vx,vy,vz);
1471
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1472

    
1473
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1474
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1475
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1476
      }
1477

    
1478
    correctComponents(mesh,numComponents);
1479
    if( effects!=null ) applyVertexEffects(mesh,effects,meshState);
1480

    
1481
    return mesh;
1482
    }
1483
  }
(2-2/13)