Project

General

Profile

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

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

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.MeshPolygon;
21
import org.distorted.library.type.Static3D;
22
import org.distorted.library.type.Static4D;
23

    
24
import java.util.ArrayList;
25

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

    
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

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

    
35
  private static final float MAX_CORE_DIFF = 0.01f;
36

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

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

    
44
  public static class StickerCoords
45
    {
46
    float[] vertices;
47
    float scale;
48
    boolean outer;
49
    }
50

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

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

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

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

    
68
  private FactoryCubit()
69
    {
70

    
71
    }
72

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

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109

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

    
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116

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

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

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

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

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

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

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

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

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

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

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

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

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

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

    
190
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
191
    {
192
    float minX = Float.MAX_VALUE;
193
    float maxX =-Float.MAX_VALUE;
194
    float minY = Float.MAX_VALUE;
195
    float maxY =-Float.MAX_VALUE;
196

    
197
    for (float[] vert : vert3D)
198
      {
199
      float x = vert[0];
200
      float y = vert[1];
201

    
202
      if (x > maxX) maxX = x;
203
      if (x < minX) minX = x;
204
      if (y > maxY) maxY = y;
205
      if (y < minY) minY = y;
206
      }
207

    
208
    minX = minX<0 ? -minX:minX;
209
    maxX = maxX<0 ? -maxX:maxX;
210
    minY = minY<0 ? -minY:minY;
211
    maxY = maxY<0 ? -maxY:maxY;
212

    
213
    float max1 = Math.max(minX,minY);
214
    float max2 = Math.max(maxX,maxY);
215
    float max3 = Math.max(max1,max2);
216

    
217
    info.scale = max3/0.5f;
218

    
219
    int len = vert3D.length;
220
    StickerCoords sInfo = new StickerCoords();
221
    sInfo.outer = isOuter;
222
    sInfo.scale = info.scale;
223
    sInfo.vertices = new float[2*len];
224

    
225
    for( int vertex=0; vertex<len; vertex++ )
226
      {
227
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
228
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
229
      }
230

    
231
    mStickerCoords.add(sInfo);
232

    
233
    info.sticker = mStickerCoords.size() -1;
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

    
238
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
239
    {
240
    FaceTransform ft = new FaceTransform();
241
    ft.face = face;
242
    ft.numFaces = numFaces;
243

    
244
    // compute center of gravity
245
    ft.vx = 0.0f;
246
    ft.vy = 0.0f;
247
    ft.vz = 0.0f;
248
    int len = vert3D.length;
249

    
250
    for (float[] vert : vert3D)
251
      {
252
      ft.vx += vert[0];
253
      ft.vy += vert[1];
254
      ft.vz += vert[2];
255
      }
256

    
257
    ft.vx /= len;
258
    ft.vy /= len;
259
    ft.vz /= len;
260

    
261
    // move all vertices so that their center of gravity is at (0,0,0)
262
    for (int i=0; i<len; i++)
263
      {
264
      vert3D[i][0] -= ft.vx;
265
      vert3D[i][1] -= ft.vy;
266
      vert3D[i][2] -= ft.vz;
267
      }
268

    
269
    // find 3 non-colinear vertices
270
    int foundIndex = -1;
271

    
272
    for(int vertex=2; vertex<len; vertex++)
273
      {
274
      if( !areColinear(vert3D,0,1,vertex) )
275
        {
276
        foundIndex = vertex;
277
        break;
278
        }
279
      }
280

    
281
    // compute the normal vector
282
    if( foundIndex==-1 )
283
      {
284
      StringBuilder sb = new StringBuilder();
285

    
286
      for (float[] floats : vert3D)
287
        {
288
        sb.append(' ');
289
        sb.append("(");
290
        sb.append(floats[0]);
291
        sb.append(" ");
292
        sb.append(floats[1]);
293
        sb.append(" ");
294
        sb.append(floats[2]);
295
        sb.append(")");
296
        }
297
      android.util.Log.e("D", "verts: "+sb);
298

    
299
      throw new RuntimeException("all vertices colinear");
300
      }
301

    
302
    computeNormalVector(vert3D,0,1,foundIndex);
303

    
304
    // rotate so that the normal vector becomes (0,0,1)
305
    float axisX, axisY, axisZ;
306

    
307
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
308
      {
309
      axisX = -mBuffer[1];
310
      axisY =  mBuffer[0];
311
      axisZ = 0.0f;
312

    
313
      float axiLen = axisX*axisX + axisY*axisY;
314
      axiLen = (float)Math.sqrt(axiLen);
315
      axisX /= axiLen;
316
      axisY /= axiLen;
317
      axisZ /= axiLen;
318
      }
319
    else
320
      {
321
      axisX = 0.0f;
322
      axisY = 1.0f;
323
      axisZ = 0.0f;
324
      }
325

    
326
    float cosTheta = mBuffer[2];
327
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
328
    float sinHalfTheta = computeSinHalf(cosTheta);
329
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
330

    
331
    mQuat1[0] = axisX*sinHalfTheta;
332
    mQuat1[1] = axisY*sinHalfTheta;
333
    mQuat1[2] = axisZ*sinHalfTheta;
334
    mQuat1[3] = cosHalfTheta;
335
    mQuat2[0] =-axisX*sinHalfTheta;
336
    mQuat2[1] =-axisY*sinHalfTheta;
337
    mQuat2[2] =-axisZ*sinHalfTheta;
338
    mQuat2[3] = cosHalfTheta;
339

    
340
    for (float[] vert : vert3D)
341
      {
342
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
343
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
344
      }
345

    
346
    // fit the whole thing in a square and remember the scale & 2D vertices
347
    fitInSquare(ft, vert3D, isOuter);
348

    
349
    // remember the rotation
350
    ft.qx =-mQuat1[0];
351
    ft.qy =-mQuat1[1];
352
    ft.qz =-mQuat1[2];
353
    ft.qw = mQuat1[3];
354

    
355
    return ft;
356
    }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359

    
360
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
361
    {
362
    for(int i=0; i<len; i++)
363
      {
364
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
365
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
366
      }
367
    }
368

    
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370

    
371
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
372
    {
373
    float v1x = v1[2*v1i];
374
    float v1y = v1[2*v1i+1];
375
    float v2x = v2[2*v2i];
376
    float v2y = v2[2*v2i+1];
377

    
378
    float lenSq1 = v1x*v1x + v1y*v1y;
379
    float lenSq2 = v2x*v2x + v2y*v2y;
380

    
381
    return (float)Math.sqrt(lenSq2/lenSq1);
382
    }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385
// valid for 0<angle<2*PI
386

    
387
  private float computeSinHalf(float cos)
388
    {
389
    return (float)Math.sqrt((1-cos)/2);
390
    }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393
// valid for 0<angle<2*PI
394

    
395
  private float computeCosHalf(float sin, float cos)
396
    {
397
    float cosHalf = (float)Math.sqrt((1+cos)/2);
398
    return sin<0 ? -cosHalf : cosHalf;
399
    }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

    
403
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
404
    {
405
    int v = (rotatedVertex + oldVertex);
406
    if( v>=len ) v-=len;
407
    if( v< 0   ) v+=len;
408

    
409
    return v;
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex)
415
    {
416
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
417
    float EPSILON = 0.001f;
418
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
419

    
420
    for(int i=1; i<len; i++)
421
      {
422
      int index = computeRotatedIndex(i,len,vertex);
423

    
424
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
425
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
426

    
427
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
428
      }
429

    
430
    return true;
431
    }
432

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

    
435
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
436
    {
437
    mStickerCoords.remove(info.sticker);
438

    
439
    info.sticker = oldSticker;
440
    info.scale  *= scale;
441

    
442
    mQuat1[0] = info.qx;
443
    mQuat1[1] = info.qy;
444
    mQuat1[2] = info.qz;
445
    mQuat1[3] = info.qw;
446

    
447
    float sinHalf = computeSinHalf(cos);
448
    float cosHalf = computeCosHalf(sin,cos);
449

    
450
    mQuat2[0] = 0.0f;
451
    mQuat2[1] = 0.0f;
452
    mQuat2[2] = sinHalf;
453
    mQuat2[3] = cosHalf;
454

    
455
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
456

    
457
    info.qx = mQuat3[0];
458
    info.qy = mQuat3[1];
459
    info.qz = mQuat3[2];
460
    info.qw = mQuat3[3];
461
    }
462

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

    
465
  private void printVert(double[] buffer)
466
    {
467
    int len = buffer.length/2;
468
    String str = "";
469

    
470
    for(int i=0; i<len; i++)
471
      {
472
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
473
      }
474

    
475
    android.util.Log.d("D", str);
476
    }
477

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479

    
480
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert, float[] oldVert, int oldSticker)
481
    {
482
    int lenVertOld = oldVert.length/2;
483
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
484

    
485
    for(int oldV=0; oldV<lenVertOld; oldV++)
486
      {
487
      oldX = oldVert[2*oldV];
488
      oldY = oldVert[2*oldV+1];
489
      lenOld = (float)Math.sqrt(oldX*oldX + oldY*oldY);
490

    
491
      if( lenOld!=0 ) break;
492
      }
493

    
494
    for(int vertex=0; vertex<len; vertex++)
495
      {
496
      float newX = newVert[2*vertex  ];
497
      float newY = newVert[2*vertex+1];
498
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
499

    
500
      if( lenNew!=0 )
501
        {
502
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
503
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
504

    
505
        rotateAllVertices(buffer,len,newVert,sin,cos);
506

    
507
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
508
          {
509
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
510
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
511
          correctInfo(info,scale,sin,cos,oldSticker);
512
          return true;
513
          }
514
        }
515
      }
516

    
517
    return false;
518
    }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521

    
522
  private float computeCoreDistance(float[] verts)
523
    {
524
    float ret = 0.0f;
525
    float centerX=0.0f,centerY=0.0f;
526
    int len = verts.length/2;
527

    
528
    for(int i=0; i<len; i++)
529
      {
530
      centerX += verts[2*i  ];
531
      centerY += verts[2*i+1];
532
      }
533

    
534
    centerX /= (2*len);
535
    centerY /= (2*len);
536

    
537
    for(int i=0; i<len; i++)
538
      {
539
      float distX = centerX-verts[2*i  ];
540
      float distY = centerY-verts[2*i+1];
541
      ret += (float)Math.sqrt(distX*distX + distY*distY);
542
      }
543

    
544
    return ret;
545
    }
546

    
547
///////////////////////////////////////////////////////////////////////////////////////////////////
548

    
549
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
550
    {
551
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
552
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
553

    
554
    float[] newVert = sNewInfo.vertices;
555
    float[] oldVert = sOldInfo.vertices;
556
    int oldLen = oldVert.length;
557
    int newLen = newVert.length;
558

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

    
566
      int oldSticker = oldInfo.sticker;
567
      float[] buffer1 = new float[oldLen];
568

    
569
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, oldSticker) )
570
        {
571
        if( sNewInfo.outer ) sOldInfo.outer = true;
572
        return true;
573
        }
574
      }
575

    
576
    return false;
577
    }
578

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

    
581
  private float[][] constructVert(float[][] vertices, int[] index)
582
    {
583
    int len = index.length;
584
    float[][] ret = new float[len][4];
585

    
586
    for(int i=0; i<len; i++)
587
      {
588
      float[] tmp = vertices[index[i]];
589
      ret[i][0] = tmp[0];
590
      ret[i][1] = tmp[1];
591
      ret[i][2] = tmp[2];
592
      ret[i][3] = 1.0f;
593
      }
594

    
595
    return ret;
596
    }
597

    
598
///////////////////////////////////////////////////////////////////////////////////////////////////
599

    
600
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects, int meshState)
601
    {
602
    boolean[] uses      = effects.getUses();
603
    String[] names      = effects.getNames();
604
    float[][] variables = effects.getVariables();
605
    float[][] centers   = effects.getCenters();
606
    float[][] regions   = effects.getRegions();
607
    int numEffects = uses.length;
608

    
609
    for(int eff=0; eff<numEffects; eff++)
610
      if( names[eff]!=null && (meshState==MESH_NICE || uses[eff]) )
611
        {
612
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
613
        if( effect!=null ) mesh.apply(effect);
614
        }
615
    }
616

    
617
///////////////////////////////////////////////////////////////////////////////////////////////////
618

    
619
  private void correctComponents(MeshBase mesh, int numComponents)
620
    {
621
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
622

    
623
    mesh.mergeEffComponents();
624

    
625
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
626
    }
627

    
628
///////////////////////////////////////////////////////////////////////////////////////////////////
629

    
630
  private void printTransform(FaceTransform f)
631
    {
632
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
633
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
634
    }
635

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

    
638
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
639
    {
640
    float[] bands = new float[2*N];
641

    
642
    bands[0] = 1.0f;
643
    bands[1] = 0.0f;
644

    
645
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
646
    float sinBeta = (float)Math.sin(beta);
647
    float cosBeta = (float)Math.cos(beta);
648
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
649
    float D = R*sinBeta;
650
    float B = h(R,sinBeta,K*beta);
651

    
652
    if( D>1.0f )
653
      {
654
      for(int i=1; i<N; i++)
655
        {
656
        bands[2*i  ] = (float)(N-1-i)/(N-1);
657
        bands[2*i+1] = H*(1-bands[2*i]);
658
        }
659
      }
660
    else
661
      {
662
      int K2 = (int)((N-3)*K);
663
      int K1 = (N-3)-K2;
664

    
665
      for(int i=0; i<=K1; i++)
666
        {
667
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
668
        float x = h(R,sinBeta,angle);
669
        bands[2*i+2] = 1.0f - x;
670
        bands[2*i+3] = g(R,D,x,cosBeta);
671
        }
672

    
673
      for(int i=0; i<=K2; i++)
674
        {
675
        float x = (1-B)*(i+1)/(K2+1) + B;
676
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
677
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
678
        }
679
      }
680

    
681
    bands[2*N-2] = 0.0f;
682
    bands[2*N-1] =    H;
683

    
684
    return bands;
685
    }
686

    
687
///////////////////////////////////////////////////////////////////////////////////////////////////
688

    
689
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
690
    {
691
    if( in==null )
692
      {
693
      out[0] = out[1] = 0.0f;
694
      }
695
    else
696
      {
697
      out[0] = in[0] - ft.vx;
698
      out[1] = in[1] - ft.vy;
699
      out[2] = in[2] - ft.vz;
700
      out[3] = 1.0f;
701

    
702
      mQuat1[0] =-ft.qx;
703
      mQuat1[1] =-ft.qy;
704
      mQuat1[2] =-ft.qz;
705
      mQuat1[3] = ft.qw;
706

    
707
      mQuat2[0] = -mQuat1[0];
708
      mQuat2[1] = -mQuat1[1];
709
      mQuat2[2] = -mQuat1[2];
710
      mQuat2[3] =  mQuat1[3];
711

    
712
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
713
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
714

    
715
      out[0] /= ft.scale;
716
      out[1] /= ft.scale;
717
      out[2] /= ft.scale;
718
      }
719
    }
720

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

    
723
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
724
    {
725
    int len = table.length;
726

    
727
    for(int i=0; i<len; i++)
728
      {
729
      int lenInner = table[i].length;
730

    
731
      for(int j=0; j<lenInner; j++)
732
        if( table[i][j]==oldPointer ) table[i][j] = newPointer;
733
      }
734
    }
735

    
736
///////////////////////////////////////////////////////////////////////////////////////////////////
737
// INTERNAL API
738

    
739
  public int printStickerCoords()
740
    {
741
    int stickers = mStickerCoords.size();
742
    int ret = 0;
743

    
744
    android.util.Log.d("D", "---- STICKER COORDS ----");
745

    
746
    for(int s=0; s<stickers; s++)
747
      {
748
      StickerCoords info = mStickerCoords.get(s);
749

    
750
      if( info.outer )  ret++;
751

    
752
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
753
      int len = info.vertices.length/2;
754

    
755
      for(int i =0; i<len; i++)
756
        {
757
        if( i!=0 ) ver += ", ";
758
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
759
        }
760

    
761
      ver += " }";
762
      android.util.Log.d("D", ver);
763
      }
764

    
765
    android.util.Log.d("D", "---- END STICKER COORDS ----");
766

    
767
    return ret;
768
    }
769

    
770
///////////////////////////////////////////////////////////////////////////////////////////////////
771

    
772
  public void printFaceTransform()
773
    {
774
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
775

    
776
    int oldfaces = mOldFaceTransf.size();
777

    
778
    for(int f=0; f<oldfaces; f++)
779
      {
780
      printTransform(mOldFaceTransf.get(f));
781
      }
782

    
783
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
784

    
785
    int newfaces = mNewFaceTransf.size();
786

    
787
    for(int f=0; f<newfaces; f++)
788
      {
789
      printTransform(mNewFaceTransf.get(f));
790
      }
791
    }
792

    
793
///////////////////////////////////////////////////////////////////////////////////////////////////
794
// PUBLIC API
795

    
796
  public static FactoryCubit getInstance()
797
    {
798
    if( mThis==null ) mThis = new FactoryCubit();
799

    
800
    return mThis;
801
    }
802

    
803
///////////////////////////////////////////////////////////////////////////////////////////////////
804

    
805
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
806
                                                          float[][] corners, int[] cornerIndices,
807
                                                          float[][] centers, int[] centerIndices )
808
    {
809
    int numVerts = vertices.length;
810
    String[] names = new String[numVerts];
811
    float[][] vars = new float[numVerts][];
812
    float[][] cents= new float[numVerts][];
813
    float[][] regs = new float[numVerts][];
814
    boolean[] uses = new boolean[numVerts];
815

    
816
    for(int i=0; i<numVerts; i++)
817
      {
818
      int centerI = centerIndices[i];
819
      int cornerI = cornerIndices[i];
820

    
821
      if( centerI>=0 && cornerI>=0 )
822
        {
823
        float[] ce = centers[centerI];
824
        float[] ve = vertices[i];
825
        float S = corners[cornerI][0];
826
        float R = corners[cornerI][1];
827

    
828
        float CX = ve[0];
829
        float CY = ve[1];
830
        float CZ = ve[2];
831
        float X = S*(ce[0]-CX);
832
        float Y = S*(ce[1]-CY);
833
        float Z = S*(ce[2]-CZ);
834

    
835
        names[i]= NAME;
836
        vars[i] = new float[] { 0, X,Y,Z, 1 };
837
        cents[i]= new float[] { CX, CY, CZ };
838
        regs[i] = new float[] { 0,0,0, R };
839
        uses[i] = false;
840
        }
841
      }
842

    
843
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
844
    }
845

    
846
///////////////////////////////////////////////////////////////////////////////////////////////////
847

    
848
  public float[] getStickerScales()
849
    {
850
    int index=0,num=0,len = mStickerCoords.size();
851

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

    
854
    if( num>0 )
855
      {
856
      float[] scales = new float[num];
857

    
858
      for(int i=0; i<len; i++)
859
        {
860
        StickerCoords sticker = mStickerCoords.get(i);
861
        if( sticker.outer ) scales[index++] = sticker.scale;
862
        }
863

    
864
      return scales;
865
      }
866

    
867
    return null;
868
    }
869

    
870
///////////////////////////////////////////////////////////////////////////////////////////////////
871

    
872
  public float[][] getStickerCoords()
873
    {
874
    int index=0,num=0,len = mStickerCoords.size();
875

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

    
878
    if( num>0 )
879
      {
880
      float[][] coords = new float[num][];
881

    
882
      for(int i=0; i<len; i++)
883
        {
884
        StickerCoords sticker = mStickerCoords.get(i);
885
        if( sticker.outer ) coords[index++] = sticker.vertices;
886
        }
887

    
888
      return coords;
889
      }
890

    
891
    return null;
892
    }
893

    
894
///////////////////////////////////////////////////////////////////////////////////////////////////
895

    
896
  public int[][] getStickerVariants()
897
    {
898
    int numvariants = 1; // there's one in the 'new' array
899

    
900
    int oldfaces = mOldFaceTransf.size();
901

    
902
    for(int f=0; f<oldfaces; f++)
903
      {
904
      FaceTransform ft = mOldFaceTransf.get(f);
905
      if( ft.face==0 ) numvariants++;
906
      }
907

    
908
    int[][] ret = new int[numvariants][];
909
    int inner=0, index=-1;
910

    
911
    for(int f=0; f<oldfaces; f++)
912
      {
913
      FaceTransform ft = mOldFaceTransf.get(f);
914
      if( ft.face==0 )
915
        {
916
        index++;
917
        inner=0;
918
        ret[index] = new int[ft.numFaces];
919
        }
920

    
921
      ret[index][inner++] = ft.sticker;
922
      }
923

    
924
    int newfaces = mNewFaceTransf.size();
925

    
926
    for(int f=0; f<newfaces; f++)
927
      {
928
      FaceTransform ft = mNewFaceTransf.get(f);
929
      if( ft.face==0 )
930
        {
931
        index++;
932
        inner=0;
933
        ret[index] = new int[ft.numFaces];
934
        }
935

    
936
      ret[index][inner++] = ft.sticker;
937
      }
938

    
939
    int numStickers = mStickerCoords.size();
940
    int numOuter=0;
941

    
942
    for(int i=0; i<numStickers; i++)
943
      {
944
      StickerCoords sc = mStickerCoords.get(i);
945
      if( sc.outer )
946
        {
947
        changeStickerPointers(ret,i,numOuter);
948
        numOuter++;
949
        }
950
      else
951
        {
952
        changeStickerPointers(ret,i,-1);
953
        }
954
      }
955

    
956
    return ret;
957
    }
958

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

    
961
  public void clear()
962
    {
963
    mStickerCoords.clear();
964
    mNewFaceTransf.clear();
965
    mOldFaceTransf.clear();
966
    }
967

    
968
///////////////////////////////////////////////////////////////////////////////////////////////////
969
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
970
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
971
// been called.
972

    
973
  public Static4D getQuaternion(int face)
974
    {
975
    FaceTransform ft = mNewFaceTransf.get(face);
976
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
977
    }
978

    
979
///////////////////////////////////////////////////////////////////////////////////////////////////
980

    
981
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
982
    {
983
    float[][] vertices = shape.getVertices();
984
    int[][] indices = shape.getVertIndices();
985
    FaceTransform ft;
986
    int numNew = mNewFaceTransf.size();
987

    
988
    for(int i=0; i<numNew; i++)
989
      {
990
      ft = mNewFaceTransf.remove(0);
991
      mOldFaceTransf.add(ft);
992
      }
993

    
994
    int numFaces = indices.length;
995
    int numOld = mOldFaceTransf.size();
996

    
997
    for (int face=0; face<numFaces; face++)
998
      {
999
      boolean collapsed = false;
1000
      boolean isOuter = (outer!=null && outer[face]>0);
1001
      float[][] vert = constructVert(vertices, indices[face]);
1002
      FaceTransform newT = constructNewTransform(vert,isOuter,face,numFaces);
1003

    
1004
      for (int old=0; !collapsed && old<numOld; old++)
1005
        {
1006
        ft = mOldFaceTransf.get(old);
1007
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1008
        }
1009

    
1010
      for (int pre=0; !collapsed && pre<face; pre++)
1011
        {
1012
        ft = mNewFaceTransf.get(pre);
1013
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1014
        }
1015

    
1016
      mNewFaceTransf.add(newT);
1017
      }
1018
    }
1019

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

    
1022
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1023
                                     final ObjectVertexEffects effects, int meshState, int numComponents)
1024
    {
1025
    int[][] vertIndexes     = shape.getVertIndices();
1026
    float[][] bands         = faceShape.getBands();
1027
    int[]   bandIndexes     = faceShape.getBandIndices();
1028
    float[] convexityCenter = faceShape.getConvexityCenter();
1029

    
1030
    int numFaces = vertIndexes.length;
1031
    float[] band, bandsComputed;
1032
    MeshBase[] meshes = new MeshBase[numFaces];
1033
    FaceTransform fInfo;
1034
    StickerCoords sInfo;
1035
    float[] convexXY = new float[4];
1036
    int exIndex=0, exVertices=0, alpha=0, N=0;
1037
    float height=0.0f, dist=0.0f, K=0.0f;
1038

    
1039
    for(int face=0; face<numFaces; face++)
1040
      {
1041
      fInfo = mNewFaceTransf.get(face);
1042
      sInfo = mStickerCoords.get(fInfo.sticker);
1043

    
1044
      float[] verts = sInfo.vertices;
1045
      int lenVerts = verts.length;
1046
      float[] copiedVerts = new float[lenVerts];
1047
      System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1048

    
1049
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1050

    
1051
      int index = bandIndexes[face];
1052
      band = bands[index];
1053

    
1054
      switch(meshState)
1055
        {
1056
        case MESH_NICE: height     = band[0];
1057
                        alpha      = (int)band[1];
1058
                        dist       = band[2];
1059
                        K          = band[3];
1060
                        N          = (int)band[4];
1061
                        exIndex    = (int)band[5];
1062
                        exVertices = (int)band[6];
1063
                        break;
1064
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
1065
                                                               // (example: Ivy cube center and edge cubits!)
1066
                        alpha      = 0;
1067
                        dist       = 0;
1068
                        K          = 0;
1069
                        N          = 2;
1070
                        exIndex    = 0;
1071
                        exVertices = 0;
1072
                        break;
1073
        }
1074

    
1075
      bandsComputed = computeBands(height,alpha,dist,K,N);
1076
      meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,null,exIndex,exVertices, convexXY[0], convexXY[1]);
1077
      meshes[face].setEffectAssociation(0,0,face);
1078
      }
1079

    
1080
    MeshBase mesh = new MeshJoined(meshes);
1081
    Static3D center = new Static3D(0,0,0);
1082

    
1083
    for(int face=0; face<numFaces; face++)
1084
      {
1085
      fInfo = mNewFaceTransf.get(face);
1086

    
1087
      float vx = fInfo.vx;
1088
      float vy = fInfo.vy;
1089
      float vz = fInfo.vz;
1090
      float sc = fInfo.scale;
1091
      float qx = fInfo.qx;
1092
      float qy = fInfo.qy;
1093
      float qz = fInfo.qz;
1094
      float qw = fInfo.qw;
1095

    
1096
      Static3D scale = new Static3D(sc,sc,sc);
1097
      Static3D move3D= new Static3D(vx,vy,vz);
1098
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1099

    
1100
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1101
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1102
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1103
      }
1104

    
1105
    correctComponents(mesh,numComponents);
1106
    if( effects!=null ) applyVertexEffects(mesh,effects,meshState);
1107

    
1108
    return mesh;
1109
    }
1110
  }
(5-5/16)