Project

General

Profile

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

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

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
///////////////////////////////////////////////////////////////////////////////////////////////////
28

    
29
public class FactoryCubit
30
  {
31
  private static FactoryCubit mThis;
32

    
33
  private static final float MAX_CORE_DIFF = 0.01f;
34

    
35
  private static final float[] mBuffer = new float[3];
36
  private static final float[] mQuat1  = new float[4];
37
  private static final float[] mQuat2  = new float[4];
38
  private static final float[] mQuat3  = new float[4];
39

    
40
  public static final String NAME = EffectName.DEFORM.name();
41

    
42
  private static class StickerCoords
43
    {
44
    float[][][] outerVertices;
45
    float[][][] fullVertices;
46
    float scale;
47
    boolean outer;
48
    }
49

    
50
  private static class FaceTransform
51
    {
52
    int face;
53
    int numFaces;
54

    
55
    int sticker;
56
    float vx,vy,vz;
57
    float scale;
58
    float qx,qy,qz,qw;
59
    }
60

    
61
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
62
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
63
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  private FactoryCubit()
68
    {
69

    
70
    }
71

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

    
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

    
109
  private float f(float D, float B, float x)
110
    {
111
    return ((D-B)*x + B*(1-D))/(1-B);
112
    }
113

    
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115

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

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  private float h(float R, float sinAlpha, float x)
125
    {
126
    return R*(sinAlpha-(float)Math.sin(x));
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  private boolean areNotColinear(float[][] vertices, int index)
132
    {
133
    float x1 = vertices[0][0];
134
    float y1 = vertices[0][1];
135
    float z1 = vertices[0][2];
136
    float x2 = vertices[1][0];
137
    float y2 = vertices[1][1];
138
    float z2 = vertices[1][2];
139
    float x3 = vertices[index][0];
140
    float y3 = vertices[index][1];
141
    float z3 = vertices[index][2];
142

    
143
    float v1x = x2-x1;
144
    float v1y = y2-y1;
145
    float v1z = z2-z1;
146
    float v2x = x3-x1;
147
    float v2y = y3-y1;
148
    float v2z = z3-z1;
149

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

    
152
    return !(v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
153
    }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

    
157
  private void computeNormalVector(float[][] vertices, int index)
158
    {
159
    float x1 = vertices[0][0];
160
    float y1 = vertices[0][1];
161
    float z1 = vertices[0][2];
162
    float x2 = vertices[1][0];
163
    float y2 = vertices[1][1];
164
    float z2 = vertices[1][2];
165
    float x3 = vertices[index][0];
166
    float y3 = vertices[index][1];
167
    float z3 = vertices[index][2];
168

    
169
    float v1x = x2-x1;
170
    float v1y = y2-y1;
171
    float v1z = z2-z1;
172
    float v2x = x3-x1;
173
    float v2y = y3-y1;
174
    float v2z = z3-z1;
175

    
176
    mBuffer[0] = v1y*v2z - v2y*v1z;
177
    mBuffer[1] = v1z*v2x - v2z*v1x;
178
    mBuffer[2] = v1x*v2y - v2x*v1y;
179

    
180
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
181
    len = Math.sqrt(len);
182
    mBuffer[0] /= len;
183
    mBuffer[1] /= len;
184
    mBuffer[2] /= len;
185
    }
186

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

    
189
  private float[][][] computeOuterEdge(float[][][] vertices)
190
    {
191
    int[][] edgesUp = MeshMultigon.computeEdgesUp(vertices);
192
    return MeshMultigon.computeOuterAndHoleVertices(vertices,edgesUp);
193
    }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196
// polygon
197

    
198
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
199
    {
200
    float minX = Float.MAX_VALUE;
201
    float maxX =-Float.MAX_VALUE;
202
    float minY = Float.MAX_VALUE;
203
    float maxY =-Float.MAX_VALUE;
204

    
205
    for (float[] vert : vert3D)
206
      {
207
      float x = vert[0];
208
      float y = vert[1];
209

    
210
      if (x > maxX) maxX = x;
211
      if (x < minX) minX = x;
212
      if (y > maxY) maxY = y;
213
      if (y < minY) minY = y;
214
      }
215

    
216
    minX = minX<0 ? -minX:minX;
217
    maxX = maxX<0 ? -maxX:maxX;
218
    minY = minY<0 ? -minY:minY;
219
    maxY = maxY<0 ? -maxY:maxY;
220

    
221
    float max1 = Math.max(minX,minY);
222
    float max2 = Math.max(maxX,maxY);
223
    float max3 = Math.max(max1,max2);
224

    
225
    info.scale = max3/0.5f;
226

    
227
    int len = vert3D.length;
228
    StickerCoords sInfo = new StickerCoords();
229
    sInfo.outer = isOuter;
230
    sInfo.scale = info.scale;
231
    sInfo.outerVertices = new float[1][len][2];
232
    sInfo.fullVertices = null;
233

    
234
    float[][] t = sInfo.outerVertices[0];
235

    
236
    for( int vertex=0; vertex<len; vertex++ )
237
      {
238
      t[vertex][0] = vert3D[vertex][0] / info.scale;
239
      t[vertex][1] = vert3D[vertex][1] / info.scale;
240
      }
241

    
242
    mStickerCoords.add(sInfo);
243

    
244
    info.sticker = mStickerCoords.size() -1;
245
    }
246

    
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
// multigon
250

    
251
  private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
252
    {
253
    float minX = Float.MAX_VALUE;
254
    float maxX =-Float.MAX_VALUE;
255
    float minY = Float.MAX_VALUE;
256
    float maxY =-Float.MAX_VALUE;
257

    
258
    for( float[][] vert : vert3D)
259
      for( float[] v : vert)
260
        {
261
        float x = v[0];
262
        float y = v[1];
263

    
264
        if (x > maxX) maxX = x;
265
        if (x < minX) minX = x;
266
        if (y > maxY) maxY = y;
267
        if (y < minY) minY = y;
268
        }
269

    
270
    minX = minX<0 ? -minX:minX;
271
    maxX = maxX<0 ? -maxX:maxX;
272
    minY = minY<0 ? -minY:minY;
273
    maxY = maxY<0 ? -maxY:maxY;
274

    
275
    float max1 = Math.max(minX,minY);
276
    float max2 = Math.max(maxX,maxY);
277
    float max3 = Math.max(max1,max2);
278

    
279
    info.scale = max3/0.5f;
280

    
281
    int len = vert3D.length;
282
    StickerCoords sInfo = new StickerCoords();
283
    sInfo.outer = isOuter;
284
    sInfo.scale = info.scale;
285
    sInfo.fullVertices = new float[len][][];
286

    
287
    for( int comp=0; comp<len; comp++ )
288
      {
289
      float[][] vert = vert3D[comp];
290
      int num = vert.length;
291
      sInfo.fullVertices[comp] = new float[num][2];
292
      float[][] t = sInfo.fullVertices[comp];
293

    
294
      for( int vertex=0; vertex<num; vertex++)
295
        {
296
        t[vertex][0] = vert[vertex][0] / info.scale;
297
        t[vertex][1] = vert[vertex][1] / info.scale;
298
        }
299
      }
300

    
301
    sInfo.outerVertices = computeOuterEdge(sInfo.fullVertices);
302

    
303
    mStickerCoords.add(sInfo);
304

    
305
    info.sticker = mStickerCoords.size() -1;
306
    }
307

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309
// polygon
310

    
311
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
312
    {
313
    FaceTransform ft = new FaceTransform();
314
    ft.face = face;
315
    ft.numFaces = numFaces;
316

    
317
    // compute center of gravity
318
    ft.vx = 0.0f;
319
    ft.vy = 0.0f;
320
    ft.vz = 0.0f;
321
    int len = vert3D.length;
322

    
323
    for (float[] vert : vert3D)
324
      {
325
      ft.vx += vert[0];
326
      ft.vy += vert[1];
327
      ft.vz += vert[2];
328
      }
329

    
330
    ft.vx /= len;
331
    ft.vy /= len;
332
    ft.vz /= len;
333

    
334
    // move all vertices so that their center of gravity is at (0,0,0)
335
    for (int i=0; i<len; i++)
336
      {
337
      vert3D[i][0] -= ft.vx;
338
      vert3D[i][1] -= ft.vy;
339
      vert3D[i][2] -= ft.vz;
340
      }
341

    
342
    // find 3 non-colinear vertices
343
    int foundIndex = -1;
344

    
345
    for(int vertex=2; vertex<len; vertex++)
346
      {
347
      if( areNotColinear(vert3D,vertex) )
348
        {
349
        foundIndex = vertex;
350
        break;
351
        }
352
      }
353

    
354
    // compute the normal vector
355
    if( foundIndex==-1 )
356
      {
357
      StringBuilder sb = new StringBuilder();
358

    
359
      for (float[] floats : vert3D)
360
        {
361
        sb.append(' ');
362
        sb.append("(");
363
        sb.append(floats[0]);
364
        sb.append(" ");
365
        sb.append(floats[1]);
366
        sb.append(" ");
367
        sb.append(floats[2]);
368
        sb.append(")");
369
        }
370
      android.util.Log.e("D", "verts: "+sb);
371

    
372
      throw new RuntimeException("all vertices colinear");
373
      }
374

    
375
    computeNormalVector(vert3D,foundIndex);
376

    
377
    // rotate so that the normal vector becomes (0,0,1)
378
    float axisX, axisY, axisZ;
379

    
380
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
381
      {
382
      axisX = -mBuffer[1];
383
      axisY =  mBuffer[0];
384
      axisZ = 0.0f;
385

    
386
      float axiLen = axisX*axisX + axisY*axisY;
387
      axiLen = (float)Math.sqrt(axiLen);
388
      axisX /= axiLen;
389
      axisY /= axiLen;
390
      axisZ /= axiLen;
391
      }
392
    else
393
      {
394
      axisX = 0.0f;
395
      axisY = 1.0f;
396
      axisZ = 0.0f;
397
      }
398

    
399
    float cosTheta = mBuffer[2];
400
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
401
    float sinHalfTheta = computeSinHalf(cosTheta);
402
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
403

    
404
    mQuat1[0] = axisX*sinHalfTheta;
405
    mQuat1[1] = axisY*sinHalfTheta;
406
    mQuat1[2] = axisZ*sinHalfTheta;
407
    mQuat1[3] = cosHalfTheta;
408
    mQuat2[0] =-axisX*sinHalfTheta;
409
    mQuat2[1] =-axisY*sinHalfTheta;
410
    mQuat2[2] =-axisZ*sinHalfTheta;
411
    mQuat2[3] = cosHalfTheta;
412

    
413
    for (float[] vert : vert3D)
414
      {
415
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
416
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
417
      }
418

    
419
    // fit the whole thing in a square and remember the scale & 2D vertices
420
    fitInSquare(ft, vert3D, isOuter);
421

    
422
    // remember the rotation
423
    ft.qx =-mQuat1[0];
424
    ft.qy =-mQuat1[1];
425
    ft.qz =-mQuat1[2];
426
    ft.qw = mQuat1[3];
427

    
428
    return ft;
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432
// multigon
433

    
434
  private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
435
    {
436
    FaceTransform ft = new FaceTransform();
437
    ft.face = face;
438
    ft.numFaces = numFaces;
439

    
440
    // compute center of gravity
441
    ft.vx = 0.0f;
442
    ft.vy = 0.0f;
443
    ft.vz = 0.0f;
444
    int len = 0;
445

    
446
    for( float[][] vert : vert3D )
447
      for( float[] v : vert )
448
        {
449
        ft.vx += v[0];
450
        ft.vy += v[1];
451
        ft.vz += v[2];
452
        len++;
453
        }
454

    
455
    ft.vx /= len;
456
    ft.vy /= len;
457
    ft.vz /= len;
458

    
459
    // move all vertices so that their center of gravity is at (0,0,0)
460
    for( float[][] vert : vert3D )
461
      for( float[] v : vert )
462
        {
463
        v[0] -= ft.vx;
464
        v[1] -= ft.vy;
465
        v[2] -= ft.vz;
466
        }
467

    
468
    // find 3 non-colinear vertices
469
    int foundIndex = -1;
470
    len = vert3D[0].length;
471

    
472
    for(int vertex=2; vertex<len; vertex++)
473
      {
474
      if( areNotColinear(vert3D[0],vertex) )
475
        {
476
        foundIndex = vertex;
477
        break;
478
        }
479
      }
480

    
481
    // compute the normal vector
482
    if( foundIndex==-1 )
483
      {
484
      StringBuilder sb = new StringBuilder();
485

    
486
      for (float[] v : vert3D[0])
487
        {
488
        sb.append(' ');
489
        sb.append("(");
490
        sb.append(v[0]);
491
        sb.append(" ");
492
        sb.append(v[1]);
493
        sb.append(" ");
494
        sb.append(v[2]);
495
        sb.append(")");
496
        }
497
      android.util.Log.e("D", "verts: "+sb);
498

    
499
      throw new RuntimeException("all vertices colinear");
500
      }
501

    
502
    computeNormalVector(vert3D[0],foundIndex);
503

    
504
    // rotate so that the normal vector becomes (0,0,1)
505
    float axisX, axisY, axisZ;
506

    
507
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
508
      {
509
      axisX = -mBuffer[1];
510
      axisY =  mBuffer[0];
511
      axisZ = 0.0f;
512

    
513
      float axiLen = axisX*axisX + axisY*axisY;
514
      axiLen = (float)Math.sqrt(axiLen);
515
      axisX /= axiLen;
516
      axisY /= axiLen;
517
      axisZ /= axiLen;
518
      }
519
    else
520
      {
521
      axisX = 0.0f;
522
      axisY = 1.0f;
523
      axisZ = 0.0f;
524
      }
525

    
526
    float cosTheta = mBuffer[2];
527
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
528
    float sinHalfTheta = computeSinHalf(cosTheta);
529
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
530

    
531
    mQuat1[0] = axisX*sinHalfTheta;
532
    mQuat1[1] = axisY*sinHalfTheta;
533
    mQuat1[2] = axisZ*sinHalfTheta;
534
    mQuat1[3] = cosHalfTheta;
535
    mQuat2[0] =-axisX*sinHalfTheta;
536
    mQuat2[1] =-axisY*sinHalfTheta;
537
    mQuat2[2] =-axisZ*sinHalfTheta;
538
    mQuat2[3] = cosHalfTheta;
539

    
540
    for( float[][] vert : vert3D)
541
      for( float[] v : vert)
542
        {
543
        QuatHelper.quatMultiply(mQuat3, mQuat1, v  );
544
        QuatHelper.quatMultiply(  v, mQuat3, mQuat2);
545
        }
546

    
547
    // fit the whole thing in a square and remember the scale & 2D vertices
548
    fitInSquare(ft, vert3D, isOuter);
549

    
550
    // remember the rotation
551
    ft.qx =-mQuat1[0];
552
    ft.qy =-mQuat1[1];
553
    ft.qz =-mQuat1[2];
554
    ft.qw = mQuat1[3];
555

    
556
    return ft;
557
    }
558

    
559
///////////////////////////////////////////////////////////////////////////////////////////////////
560

    
561
  private void rotateAllVertices(float[][] result, int len, float[][] vertices, float sin, float cos)
562
    {
563
    for(int i=0; i<len; i++)
564
      {
565
      float x = vertices[i][0];
566
      float y = vertices[i][1];
567
      result[i][0] = x*cos - y*sin;
568
      result[i][1] = x*sin + y*cos;
569
      }
570
    }
571

    
572
///////////////////////////////////////////////////////////////////////////////////////////////////
573

    
574
  private float computeScale(float[][] v1, float[][] v2, int v1i, int v2i)
575
    {
576
    float v1x = v1[v1i][0];
577
    float v1y = v1[v1i][1];
578
    float v2x = v2[v2i][0];
579
    float v2y = v2[v2i][1];
580

    
581
    float lenSq1 = v1x*v1x + v1y*v1y;
582
    float lenSq2 = v2x*v2x + v2y*v2y;
583

    
584
    return (float)Math.sqrt(lenSq2/lenSq1);
585
    }
586

    
587
///////////////////////////////////////////////////////////////////////////////////////////////////
588
// valid for 0<angle<2*PI
589

    
590
  private float computeSinHalf(float cos)
591
    {
592
    return (float)Math.sqrt((1-cos)/2);
593
    }
594

    
595
///////////////////////////////////////////////////////////////////////////////////////////////////
596
// valid for 0<angle<2*PI
597

    
598
  private float computeCosHalf(float sin, float cos)
599
    {
600
    float cosHalf = (float)Math.sqrt((1+cos)/2);
601
    return sin<0 ? -cosHalf : cosHalf;
602
    }
603

    
604
///////////////////////////////////////////////////////////////////////////////////////////////////
605

    
606
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
607
    {
608
    int v = (rotatedVertex + oldVertex);
609
    if( v>=len ) v-=len;
610
    if( v< 0   ) v+=len;
611

    
612
    return v;
613
    }
614

    
615
///////////////////////////////////////////////////////////////////////////////////////////////////
616

    
617
  private boolean isScaledVersionOf(float[][] newVert, float[][] oldVert, int len, int vertex)
618
    {
619
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
620
    float EPSILON = 0.001f;
621
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
622

    
623
    for(int i=1; i<len; i++)
624
      {
625
      int index = computeRotatedIndex(i,len,vertex);
626

    
627
      float horz = oldVert[i][0] - scale*newVert[index][0];
628
      float vert = oldVert[i][1] - scale*newVert[index][1];
629

    
630
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
631
      }
632

    
633
    return true;
634
    }
635

    
636
///////////////////////////////////////////////////////////////////////////////////////////////////
637

    
638
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
639
    {
640
    mStickerCoords.remove(info.sticker);
641

    
642
    info.sticker = oldSticker;
643
    info.scale  *= scale;
644

    
645
    mQuat1[0] = info.qx;
646
    mQuat1[1] = info.qy;
647
    mQuat1[2] = info.qz;
648
    mQuat1[3] = info.qw;
649

    
650
    float sinHalf = computeSinHalf(cos);
651
    float cosHalf = computeCosHalf(sin,cos);
652

    
653
    mQuat2[0] = 0.0f;
654
    mQuat2[1] = 0.0f;
655
    mQuat2[2] = sinHalf;
656
    mQuat2[3] = cosHalf;
657

    
658
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
659

    
660
    info.qx = mQuat3[0];
661
    info.qy = mQuat3[1];
662
    info.qz = mQuat3[2];
663
    info.qw = mQuat3[3];
664
    }
665

    
666
///////////////////////////////////////////////////////////////////////////////////////////////////
667

    
668
  private boolean foundVertex(FaceTransform info, float[][] buffer, float[][] newVert, float[][] oldVert, int oldSticker)
669
    {
670
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
671
    int len = newVert.length;
672

    
673
    for(float[] ov : oldVert)
674
      {
675
      oldX = ov[0];
676
      oldY = ov[1];
677
      lenOld = (float) Math.sqrt(oldX*oldX+oldY*oldY);
678

    
679
      if(lenOld!=0) break;
680
      }
681

    
682
    for(int vertex=0; vertex<len; vertex++)
683
      {
684
      float newX = newVert[vertex][0];
685
      float newY = newVert[vertex][1];
686
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
687

    
688
      if( lenNew!=0 )
689
        {
690
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
691
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
692

    
693
        rotateAllVertices(buffer,len,newVert,sin,cos);
694

    
695
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
696
          {
697
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
698
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
699
          correctInfo(info,scale,sin,cos,oldSticker);
700
          return true;
701
          }
702
        }
703
      }
704

    
705
    return false;
706
    }
707

    
708
///////////////////////////////////////////////////////////////////////////////////////////////////
709

    
710
  private float computeCoreDistance(float[][] verts)
711
    {
712
    float ret = 0.0f;
713
    float centerX=0.0f,centerY=0.0f;
714
    int len = verts.length;
715

    
716
    for(float[] vert : verts)
717
      {
718
      centerX += vert[0];
719
      centerY += vert[1];
720
      }
721

    
722
    centerX /= len;
723
    centerY /= len;
724

    
725
    for(float[] vert : verts)
726
      {
727
      float distX = centerX-vert[0];
728
      float distY = centerY-vert[1];
729
      ret += (float) Math.sqrt(distX*distX+distY*distY);
730
      }
731

    
732
    return ret;
733
    }
734

    
735
///////////////////////////////////////////////////////////////////////////////////////////////////
736
// even if this is a multigon, then StickerCoords.outerVertices is the outer edge!
737
// (see fitInSquare multigon variant)
738

    
739
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
740
    {
741
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
742
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
743

    
744
    if( sNewInfo.outerVertices.length>1 || sOldInfo.outerVertices.length>1 ) // the 'outer' path is composed of more than
745
      {                                                                      // one segment, i.e. the sticker has holes.
746
      return false;                                                          // do not collapse such stickers.
747
      }
748

    
749
    float[][] newVert = sNewInfo.outerVertices[0];
750
    float[][] oldVert = sOldInfo.outerVertices[0];
751
    int oldLen = oldVert.length;
752
    int newLen = newVert.length;
753

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

    
761
      int oldSticker = oldInfo.sticker;
762
      float[][] buffer = new float[oldLen][2];
763

    
764
      if( foundVertex(newInfo, buffer, newVert, oldVert, oldSticker) )
765
        {
766
        if( sNewInfo.outer ) sOldInfo.outer = true;
767
        return true;
768
        }
769
      }
770

    
771
    return false;
772
    }
773

    
774
///////////////////////////////////////////////////////////////////////////////////////////////////
775
// polygon
776

    
777
  private float[][] constructVert(float[][] vertices, int[] index)
778
    {
779
    int len = index.length;
780
    float[][] ret = new float[len][4];
781

    
782
    for(int i=0; i<len; i++)
783
      {
784
      float[] tmp = vertices[index[i]];
785
      ret[i][0] = tmp[0];
786
      ret[i][1] = tmp[1];
787
      ret[i][2] = tmp[2];
788
      ret[i][3] = 1.0f;
789
      }
790

    
791
    return ret;
792
    }
793

    
794
///////////////////////////////////////////////////////////////////////////////////////////////////
795
// multigon
796

    
797
  private float[][][] constructVert(float[][] vertices, int[][] index)
798
    {
799
    int len = index.length;
800
    float[][][] ret = new float[len][][];
801

    
802
    for(int i=0; i<len; i++)
803
      {
804
      int[] ind = index[i];
805
      int num = ind.length;
806
      ret[i] = new float[num][4];
807

    
808
      for(int j=0; j<num; j++)
809
        {
810
        float[] r = ret[i][j];
811
        float[] v = vertices[ind[j]];
812
        r[0] = v[0];
813
        r[1] = v[1];
814
        r[2] = v[2];
815
        r[3] = 1.0f;
816
        }
817
      }
818

    
819
    return ret;
820
    }
821

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

    
824
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects)
825
    {
826
    boolean[] uses      = effects.getUses();
827
    String[] names      = effects.getNames();
828
    float[][] variables = effects.getVariables();
829
    float[][] centers   = effects.getCenters();
830
    float[][] regions   = effects.getRegions();
831
    int numEffects = uses.length;
832

    
833
    for(int eff=0; eff<numEffects; eff++)
834
      if( names[eff]!=null )
835
        {
836
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
837
        if( effect!=null ) mesh.apply(effect);
838
        }
839
    }
840

    
841
///////////////////////////////////////////////////////////////////////////////////////////////////
842

    
843
  private void correctComponents(MeshBase mesh, int numComponents)
844
    {
845
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
846

    
847
    mesh.mergeEffComponents();
848

    
849
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
850
    }
851

    
852
///////////////////////////////////////////////////////////////////////////////////////////////////
853

    
854
  private void printTransform(FaceTransform f)
855
    {
856
    android.util.Log.e("D", "face="+f.face+" sticker="+f.sticker+" scale="+f.scale+
857
                            " q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("+f.vx+", "+f.vy+", "+f.vz+")");
858
    }
859

    
860
///////////////////////////////////////////////////////////////////////////////////////////////////
861

    
862
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
863
    {
864
    float[] bands = new float[2*N];
865

    
866
    bands[0] = 1.0f;
867
    bands[1] = 0.0f;
868

    
869
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
870
    float sinBeta = (float)Math.sin(beta);
871
    float cosBeta = (float)Math.cos(beta);
872
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
873
    float D = R*sinBeta;
874
    float B = h(R,sinBeta,K*beta);
875

    
876
    if( D>1.0f )
877
      {
878
      for(int i=1; i<N; i++)
879
        {
880
        bands[2*i  ] = (float)(N-1-i)/(N-1);
881
        bands[2*i+1] = H*(1-bands[2*i]);
882
        }
883
      }
884
    else
885
      {
886
      int K2 = (int)((N-3)*K);
887
      int K1 = (N-3)-K2;
888

    
889
      for(int i=0; i<=K1; i++)
890
        {
891
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
892
        float x = h(R,sinBeta,angle);
893
        bands[2*i+2] = 1.0f - x;
894
        bands[2*i+3] = g(R,D,x,cosBeta);
895
        }
896

    
897
      for(int i=0; i<=K2; i++)
898
        {
899
        float x = (1-B)*(i+1)/(K2+1) + B;
900
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
901
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
902
        }
903
      }
904

    
905
    bands[2*N-2] = 0.0f;
906
    bands[2*N-1] =    H;
907

    
908
    return bands;
909
    }
910

    
911
///////////////////////////////////////////////////////////////////////////////////////////////////
912

    
913
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
914
    {
915
    if( in==null )
916
      {
917
      out[0] = out[1] = 0.0f;
918
      }
919
    else
920
      {
921
      out[0] = in[0] - ft.vx;
922
      out[1] = in[1] - ft.vy;
923
      out[2] = in[2] - ft.vz;
924
      out[3] = 1.0f;
925

    
926
      mQuat1[0] =-ft.qx;
927
      mQuat1[1] =-ft.qy;
928
      mQuat1[2] =-ft.qz;
929
      mQuat1[3] = ft.qw;
930

    
931
      mQuat2[0] = -mQuat1[0];
932
      mQuat2[1] = -mQuat1[1];
933
      mQuat2[2] = -mQuat1[2];
934
      mQuat2[3] =  mQuat1[3];
935

    
936
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
937
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
938

    
939
      out[0] /= ft.scale;
940
      out[1] /= ft.scale;
941
      out[2] /= ft.scale;
942
      }
943
    }
944

    
945
///////////////////////////////////////////////////////////////////////////////////////////////////
946

    
947
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
948
    {
949
    for(int[] tab : table)
950
      {
951
      int len = tab.length;
952

    
953
      for(int j=0; j<len; j++)
954
        if( tab[j]==oldPointer ) tab[j] = newPointer;
955
      }
956
    }
957

    
958
///////////////////////////////////////////////////////////////////////////////////////////////////
959

    
960
  private String printSticker(StickerCoords info)
961
    {
962
    String ret = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+"\n";
963

    
964
    int len = info.outerVertices.length;
965

    
966
    for(int l=0; l<len; l++)
967
      {
968
      float[][] outer = info.outerVertices[l];
969
      int numV = outer.length;
970

    
971
      ret += "  Loop "+l+" verts: "+numV+" { ";
972
      for(int v=0; v<numV; v++)
973
        {
974
        if(v!=0) ret += ", ";
975
        ret += (outer[v][0]+"f, "+outer[v][1]+"f");
976
        }
977

    
978
      ret += "}\n";
979
      }
980

    
981
    return ret;
982
    }
983

    
984
///////////////////////////////////////////////////////////////////////////////////////////////////
985
// INTERNAL API
986

    
987
  public int printStickerCoords()
988
    {
989
    int stickers = mStickerCoords.size();
990
    int ret = 0;
991

    
992
    android.util.Log.d("D", "---- STICKER COORDS ----");
993

    
994
    for(int s=0; s<stickers; s++)
995
      {
996
      StickerCoords info = mStickerCoords.get(s);
997
      if( info.outer )  ret++;
998
      String str = printSticker(info);
999
      android.util.Log.d("D", "Sticker "+s+" "+str);
1000
      }
1001

    
1002
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1003

    
1004
    return ret;
1005
    }
1006

    
1007
///////////////////////////////////////////////////////////////////////////////////////////////////
1008

    
1009
  public void printFaceTransform()
1010
    {
1011
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1012

    
1013
    int oldfaces = mOldFaceTransf.size();
1014

    
1015
    for(int f=0; f<oldfaces; f++)
1016
      {
1017
      printTransform(mOldFaceTransf.get(f));
1018
      }
1019

    
1020
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1021

    
1022
    int newfaces = mNewFaceTransf.size();
1023

    
1024
    for(int f=0; f<newfaces; f++)
1025
      {
1026
      printTransform(mNewFaceTransf.get(f));
1027
      }
1028
    }
1029

    
1030
///////////////////////////////////////////////////////////////////////////////////////////////////
1031

    
1032
  private void printVert(double[][] buffer)
1033
    {
1034
    StringBuilder str = new StringBuilder();
1035

    
1036
    for(double[] buf : buffer)
1037
      {
1038
      str.append(" (");
1039
      str.append(buf[0]);
1040
      str.append(" , ");
1041
      str.append(buf[1]);
1042
      str.append(" ) ");
1043
      }
1044

    
1045
    android.util.Log.d("D", str.toString());
1046
    }
1047

    
1048
///////////////////////////////////////////////////////////////////////////////////////////////////
1049
// PUBLIC API
1050

    
1051
  public static FactoryCubit getInstance()
1052
    {
1053
    if( mThis==null ) mThis = new FactoryCubit();
1054
    return mThis;
1055
    }
1056

    
1057
///////////////////////////////////////////////////////////////////////////////////////////////////
1058

    
1059
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
1060
                                                          float[][] corners, int[] cornerIndices,
1061
                                                          float[][] centers, int[] centerIndices )
1062
    {
1063
    int numVerts = vertices.length;
1064
    String[] names = new String[numVerts];
1065
    float[][] vars = new float[numVerts][];
1066
    float[][] cents= new float[numVerts][];
1067
    float[][] regs = new float[numVerts][];
1068
    boolean[] uses = new boolean[numVerts];
1069

    
1070
    for(int i=0; i<numVerts; i++)
1071
      {
1072
      int centerI = centerIndices[i];
1073
      int cornerI = cornerIndices[i];
1074

    
1075
      if( centerI>=0 && cornerI>=0 )
1076
        {
1077
        float[] ce = centers[centerI];
1078
        float[] ve = vertices[i];
1079
        float S = corners[cornerI][0];
1080
        float R = corners[cornerI][1];
1081

    
1082
        float CX = ve[0];
1083
        float CY = ve[1];
1084
        float CZ = ve[2];
1085
        float X = S*(ce[0]-CX);
1086
        float Y = S*(ce[1]-CY);
1087
        float Z = S*(ce[2]-CZ);
1088

    
1089
        names[i]= NAME;
1090
        vars[i] = new float[] { 0, X,Y,Z, 1 };
1091
        cents[i]= new float[] { CX, CY, CZ };
1092
        regs[i] = new float[] { 0,0,0, R };
1093
        uses[i] = false;
1094
        }
1095
      }
1096

    
1097
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1098
    }
1099

    
1100
///////////////////////////////////////////////////////////////////////////////////////////////////
1101

    
1102
  public float[] getStickerScales()
1103
    {
1104
    int index=0,num=0,len = mStickerCoords.size();
1105

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

    
1108
    if( num>0 )
1109
      {
1110
      float[] scales = new float[num];
1111

    
1112
      for(int i=0; i<len; i++)
1113
        {
1114
        StickerCoords sticker = mStickerCoords.get(i);
1115
        if( sticker.outer ) scales[index++] = sticker.scale;
1116
        }
1117

    
1118
      return scales;
1119
      }
1120

    
1121
    return null;
1122
    }
1123

    
1124
///////////////////////////////////////////////////////////////////////////////////////////////////
1125

    
1126
  public float[][][][] getStickerCoords()
1127
    {
1128
    int index=0,num=0,len = mStickerCoords.size();
1129

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

    
1132
    if( num>0 )
1133
      {
1134
      float[][][][] coords = new float[num][][][];
1135

    
1136
      for(int i=0; i<len; i++)
1137
        {
1138
        StickerCoords sticker = mStickerCoords.get(i);
1139
        if( sticker.outer ) coords[index++] = sticker.outerVertices;
1140
        }
1141

    
1142
      return coords;
1143
      }
1144

    
1145
    return null;
1146
    }
1147

    
1148
///////////////////////////////////////////////////////////////////////////////////////////////////
1149

    
1150
  public int[][] getStickerVariants()
1151
    {
1152
    int numvariants = 1; // there's one in the 'new' array
1153

    
1154
    int oldfaces = mOldFaceTransf.size();
1155

    
1156
    for(int f=0; f<oldfaces; f++)
1157
      {
1158
      FaceTransform ft = mOldFaceTransf.get(f);
1159
      if( ft.face==0 ) numvariants++;
1160
      }
1161

    
1162
    int[][] ret = new int[numvariants][];
1163
    int face=0, variant=-1;
1164

    
1165
    for(int f=0; f<oldfaces; f++)
1166
      {
1167
      FaceTransform ft = mOldFaceTransf.get(f);
1168
      if( ft.face==0 )
1169
        {
1170
        variant++;
1171
        face=0;
1172
        ret[variant] = new int[ft.numFaces];
1173
        }
1174

    
1175
      ret[variant][face++] = ft.sticker;
1176
      }
1177

    
1178
    int newfaces = mNewFaceTransf.size();
1179

    
1180
    for(int f=0; f<newfaces; f++)
1181
      {
1182
      FaceTransform ft = mNewFaceTransf.get(f);
1183
      if( ft.face==0 )
1184
        {
1185
        variant++;
1186
        face=0;
1187
        ret[variant] = new int[ft.numFaces];
1188
        }
1189

    
1190
      ret[variant][face++] = ft.sticker;
1191
      }
1192

    
1193
    int numStickers = mStickerCoords.size();
1194
    int numOuter=0;
1195

    
1196
    for(int i=0; i<numStickers; i++)
1197
      {
1198
      StickerCoords sc = mStickerCoords.get(i);
1199
      if( sc.outer )
1200
        {
1201
        changeStickerPointers(ret,i, numOuter);
1202
        numOuter++;
1203
        }
1204
      else
1205
        {
1206
        changeStickerPointers(ret,i,-1);
1207
        }
1208
      }
1209

    
1210
    return ret;
1211
    }
1212

    
1213
///////////////////////////////////////////////////////////////////////////////////////////////////
1214

    
1215
  public void clear()
1216
    {
1217
    mStickerCoords.clear();
1218
    mNewFaceTransf.clear();
1219
    mOldFaceTransf.clear();
1220
    }
1221

    
1222
///////////////////////////////////////////////////////////////////////////////////////////////////
1223
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
1224
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
1225
// been called.
1226

    
1227
  public Static4D getQuaternion(int face)
1228
    {
1229
    FaceTransform ft = mNewFaceTransf.get(face);
1230
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
1231
    }
1232

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

    
1235
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1236
    {
1237
    float[][] vertices = shape.getVertices();
1238
    int[][] indices = shape.getVertIndices();
1239
    int[][][] fullIndices = shape.getMultigonIndices();
1240
    boolean isMultigon = shape.isMultigon();
1241
    FaceTransform ft;
1242
    int numNew = mNewFaceTransf.size();
1243

    
1244
    for(int i=0; i<numNew; i++)
1245
      {
1246
      ft = mNewFaceTransf.remove(0);
1247
      mOldFaceTransf.add(ft);
1248
      }
1249

    
1250
    int numFaces = shape.getNumFaces();
1251
    int numOld = mOldFaceTransf.size();
1252

    
1253
    for (int face=0; face<numFaces; face++)
1254
      {
1255
      boolean collapsed = false;
1256
      boolean isOuter = (outer!=null && outer[face]>0);
1257
      FaceTransform newT;
1258

    
1259
      if( !isMultigon )
1260
        {
1261
        float[][] vert = constructVert(vertices, indices[face]);
1262
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1263
        }
1264
      else
1265
        {
1266
        float[][][] vert = constructVert(vertices, fullIndices[face]);
1267
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1268
        }
1269

    
1270
      for (int old=0; !collapsed && old<numOld; old++)
1271
        {
1272
        ft = mOldFaceTransf.get(old);
1273
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1274
        }
1275

    
1276
      for (int pre=0; !collapsed && pre<face; pre++)
1277
        {
1278
        ft = mNewFaceTransf.get(pre);
1279
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1280
        }
1281

    
1282
      mNewFaceTransf.add(newT);
1283
      }
1284
    }
1285

    
1286
///////////////////////////////////////////////////////////////////////////////////////////////////
1287

    
1288
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1289
                                     final ObjectVertexEffects effects, int numComponents)
1290
    {
1291
    float[][] bands         = faceShape.getBands();
1292
    int[]   bandIndexes     = faceShape.getBandIndices();
1293
    float[] convexityCenter = faceShape.getConvexityCenter();
1294

    
1295
    int numFaces = shape.getNumFaces();
1296
    float[] bandsComputed;
1297
    MeshBase[] meshes = new MeshBase[numFaces];
1298
    FaceTransform fInfo;
1299
    StickerCoords sInfo;
1300
    float[] convexXY = new float[4];
1301

    
1302
    for(int face=0; face<numFaces; face++)
1303
      {
1304
      fInfo = mNewFaceTransf.get(face);
1305
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1306

    
1307
      int index      = bandIndexes[face];
1308
      float[] band   = bands[index];
1309
      float height   = band[0];
1310
      int alpha      = (int)band[1];
1311
      float dist     = band[2];
1312
      float K        = band[3];
1313
      int N          = (int)band[4];
1314
      int exIndex    = (int)band[5];
1315
      int exVertices = (int)band[6];
1316

    
1317
      bandsComputed = computeBands(height,alpha,dist,K,N);
1318

    
1319
      sInfo = mStickerCoords.get(fInfo.sticker);
1320
      float[][][] vertsF = sInfo.fullVertices;
1321

    
1322
      // i.e. multigon which hasn't been 'successfully collapsed'
1323
      // with a previously computed polygon sticker!
1324
      if( vertsF!=null )
1325
        {
1326
        int lenVerts = vertsF.length;
1327
        float[][][] copiedVerts = new float[lenVerts][][];
1328

    
1329
        for(int i=0; i<lenVerts; i++)
1330
          {
1331
          float[][] v = vertsF[i];
1332
          int len = v.length;
1333
          copiedVerts[i] = new float[len][2];
1334

    
1335
          for(int j=0; j<len; j++)
1336
            {
1337
            copiedVerts[i][j][0] = v[j][0];
1338
            copiedVerts[i][j][1] = v[j][1];
1339
            }
1340
          }
1341

    
1342
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1343
        }
1344
      else
1345
        {
1346
        float[][] verts = sInfo.outerVertices[0];
1347
        int lenVerts = verts.length;
1348
        float[][] copiedVerts = new float[lenVerts][2];
1349

    
1350
        for(int v=0; v<lenVerts; v++)
1351
          {
1352
          float[] ve = verts[v];
1353
          copiedVerts[v][0] = ve[0];
1354
          copiedVerts[v][1] = ve[1];
1355
          }
1356

    
1357
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1358
        }
1359

    
1360
      meshes[face].setEffectAssociation(0,0,face);
1361
      }
1362

    
1363
    MeshBase mesh = new MeshJoined(meshes);
1364
    Static3D center = new Static3D(0,0,0);
1365

    
1366
    for(int face=0; face<numFaces; face++)
1367
      {
1368
      fInfo = mNewFaceTransf.get(face);
1369

    
1370
      float vx = fInfo.vx;
1371
      float vy = fInfo.vy;
1372
      float vz = fInfo.vz;
1373
      float sc = fInfo.scale;
1374
      float qx = fInfo.qx;
1375
      float qy = fInfo.qy;
1376
      float qz = fInfo.qz;
1377
      float qw = fInfo.qw;
1378

    
1379
      Static3D scale = new Static3D(sc,sc,sc);
1380
      Static3D move3D= new Static3D(vx,vy,vz);
1381
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1382

    
1383
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1384
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1385
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1386
      }
1387

    
1388
    correctComponents(mesh,numComponents);
1389
    if( effects!=null ) applyVertexEffects(mesh,effects);
1390

    
1391
    return mesh;
1392
    }
1393
  }
(2-2/13)