Project

General

Profile

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

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

1 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 a7a40b3c Leszek Koltunski
// 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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 198c5bf0 Leszek Koltunski
package org.distorted.objectlib.helpers;
11 29b82486 Leszek Koltunski
12 84a17011 Leszek Koltunski
import org.distorted.library.effect.EffectName;
13 29b82486 Leszek Koltunski
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 aacf5e27 Leszek Koltunski
import org.distorted.library.helpers.QuatHelper;
18 29b82486 Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
19
import org.distorted.library.mesh.MeshJoined;
20 fe3dec09 Leszek Koltunski
import org.distorted.library.mesh.MeshMultigon;
21 29b82486 Leszek Koltunski
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 c3a033e9 Leszek Koltunski
import static org.distorted.objectlib.main.TwistyObject.MESH_FAST;
28
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
29
30 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
31
32
public class FactoryCubit
33
  {
34
  private static FactoryCubit mThis;
35
36 d99de43c Leszek Koltunski
  private static final float MAX_CORE_DIFF = 0.01f;
37
38 57ef6378 Leszek Koltunski
  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 29b82486 Leszek Koltunski
43 80fd07aa Leszek Koltunski
  public static final String NAME = EffectName.DEFORM.name();
44 84a17011 Leszek Koltunski
45 fe3dec09 Leszek Koltunski
  private static class StickerCoords
46 29b82486 Leszek Koltunski
    {
47 57ef6378 Leszek Koltunski
    float[] vertices;
48 fe3dec09 Leszek Koltunski
    float[][] fullVertices;
49 1561a74f Leszek Koltunski
    float scale;
50 2617d26b Leszek Koltunski
    boolean outer;
51 29b82486 Leszek Koltunski
    }
52
53
  private static class FaceTransform
54
    {
55 7af68038 Leszek Koltunski
    int face;
56
    int numFaces;
57
58 29b82486 Leszek Koltunski
    int sticker;
59 57ef6378 Leszek Koltunski
    float vx,vy,vz;
60
    float scale;
61
    float qx,qy,qz,qw;
62 29b82486 Leszek Koltunski
    }
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 3bf19410 Leszek Koltunski
73 29b82486 Leszek Koltunski
    }
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 57ef6378 Leszek Koltunski
  private boolean areColinear(float[][] vertices, int index1, int index2, int index3)
135 29b82486 Leszek Koltunski
    {
136 57ef6378 Leszek Koltunski
    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 29b82486 Leszek Koltunski
146 57ef6378 Leszek Koltunski
    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 29b82486 Leszek Koltunski
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 57ef6378 Leszek Koltunski
  private void computeNormalVector(float[][] vertices, int index1, int index2, int index3)
161 29b82486 Leszek Koltunski
    {
162 57ef6378 Leszek Koltunski
    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 29b82486 Leszek Koltunski
172 57ef6378 Leszek Koltunski
    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 29b82486 Leszek Koltunski
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 fe3dec09 Leszek Koltunski
  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 b394a751 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
224
225
  private boolean pointsTheSame(float dx, float dy)
226
    {
227
    return dx*dx + dy*dy < 0.000001f;
228
    }
229
230 fe3dec09 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 b394a751 leszek
        if( pointsTheSame(xc-curr[0],yc-curr[1]) )
247 fe3dec09 Leszek Koltunski
          {
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 b394a751 leszek
    while( !pointsTheSame(next[0]-first[0],next[1]-first[1]) );
289 fe3dec09 Leszek Koltunski
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 2617d26b Leszek Koltunski
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
307 29b82486 Leszek Koltunski
    {
308 57ef6378 Leszek Koltunski
    float minX = Float.MAX_VALUE;
309
    float maxX =-Float.MAX_VALUE;
310
    float minY = Float.MAX_VALUE;
311
    float maxY =-Float.MAX_VALUE;
312 29b82486 Leszek Koltunski
313 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
314 29b82486 Leszek Koltunski
      {
315 57ef6378 Leszek Koltunski
      float x = vert[0];
316
      float y = vert[1];
317 29b82486 Leszek Koltunski
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 57ef6378 Leszek Koltunski
    float max1 = Math.max(minX,minY);
330
    float max2 = Math.max(maxX,maxY);
331
    float max3 = Math.max(max1,max2);
332 29b82486 Leszek Koltunski
333 57ef6378 Leszek Koltunski
    info.scale = max3/0.5f;
334 29b82486 Leszek Koltunski
335
    int len = vert3D.length;
336
    StickerCoords sInfo = new StickerCoords();
337 2617d26b Leszek Koltunski
    sInfo.outer = isOuter;
338 1561a74f Leszek Koltunski
    sInfo.scale = info.scale;
339 57ef6378 Leszek Koltunski
    sInfo.vertices = new float[2*len];
340 fe3dec09 Leszek Koltunski
    sInfo.fullVertices = null;
341 29b82486 Leszek Koltunski
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 fe3dec09 Leszek Koltunski
354 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
355 fe3dec09 Leszek Koltunski
// 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 29b82486 Leszek Koltunski
417 7af68038 Leszek Koltunski
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
418 29b82486 Leszek Koltunski
    {
419
    FaceTransform ft = new FaceTransform();
420 7af68038 Leszek Koltunski
    ft.face = face;
421
    ft.numFaces = numFaces;
422 29b82486 Leszek Koltunski
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 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
430 29b82486 Leszek Koltunski
      {
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 03410dc1 Leszek Koltunski
      StringBuilder sb = new StringBuilder();
464
465 8e80135b Leszek Koltunski
      for (float[] floats : vert3D)
466 03410dc1 Leszek Koltunski
        {
467
        sb.append(' ');
468
        sb.append("(");
469 8e80135b Leszek Koltunski
        sb.append(floats[0]);
470 03410dc1 Leszek Koltunski
        sb.append(" ");
471 8e80135b Leszek Koltunski
        sb.append(floats[1]);
472 03410dc1 Leszek Koltunski
        sb.append(" ");
473 8e80135b Leszek Koltunski
        sb.append(floats[2]);
474 03410dc1 Leszek Koltunski
        sb.append(")");
475
        }
476
      android.util.Log.e("D", "verts: "+sb);
477
478 29b82486 Leszek Koltunski
      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 57ef6378 Leszek Koltunski
    float axisX, axisY, axisZ;
485 29b82486 Leszek Koltunski
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 57ef6378 Leszek Koltunski
      float axiLen = axisX*axisX + axisY*axisY;
493
      axiLen = (float)Math.sqrt(axiLen);
494 29b82486 Leszek Koltunski
      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 57ef6378 Leszek Koltunski
    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 29b82486 Leszek Koltunski
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 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
520 29b82486 Leszek Koltunski
      {
521 d809bf6f Leszek Koltunski
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
522
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
523 29b82486 Leszek Koltunski
      }
524
525
    // fit the whole thing in a square and remember the scale & 2D vertices
526 2617d26b Leszek Koltunski
    fitInSquare(ft, vert3D, isOuter);
527 29b82486 Leszek Koltunski
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 fe3dec09 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
666
667 57ef6378 Leszek Koltunski
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
668 29b82486 Leszek Koltunski
    {
669
    for(int i=0; i<len; i++)
670
      {
671 fe3dec09 Leszek Koltunski
      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 29b82486 Leszek Koltunski
      }
676
    }
677
678
///////////////////////////////////////////////////////////////////////////////////////////////////
679
680 57ef6378 Leszek Koltunski
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
681 29b82486 Leszek Koltunski
    {
682 57ef6378 Leszek Koltunski
    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 29b82486 Leszek Koltunski
687 57ef6378 Leszek Koltunski
    float lenSq1 = v1x*v1x + v1y*v1y;
688
    float lenSq2 = v2x*v2x + v2y*v2y;
689 29b82486 Leszek Koltunski
690 57ef6378 Leszek Koltunski
    return (float)Math.sqrt(lenSq2/lenSq1);
691 29b82486 Leszek Koltunski
    }
692
693
///////////////////////////////////////////////////////////////////////////////////////////////////
694
// valid for 0<angle<2*PI
695
696 57ef6378 Leszek Koltunski
  private float computeSinHalf(float cos)
697 29b82486 Leszek Koltunski
    {
698 57ef6378 Leszek Koltunski
    return (float)Math.sqrt((1-cos)/2);
699 29b82486 Leszek Koltunski
    }
700
701
///////////////////////////////////////////////////////////////////////////////////////////////////
702
// valid for 0<angle<2*PI
703
704 57ef6378 Leszek Koltunski
  private float computeCosHalf(float sin, float cos)
705 29b82486 Leszek Koltunski
    {
706 57ef6378 Leszek Koltunski
    float cosHalf = (float)Math.sqrt((1+cos)/2);
707 29b82486 Leszek Koltunski
    return sin<0 ? -cosHalf : cosHalf;
708
    }
709
710
///////////////////////////////////////////////////////////////////////////////////////////////////
711
712 846b69f3 Leszek Koltunski
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
713 29b82486 Leszek Koltunski
    {
714 846b69f3 Leszek Koltunski
    int v = (rotatedVertex + oldVertex);
715 29b82486 Leszek Koltunski
    if( v>=len ) v-=len;
716
    if( v< 0   ) v+=len;
717
718
    return v;
719
    }
720
721
///////////////////////////////////////////////////////////////////////////////////////////////////
722
723 846b69f3 Leszek Koltunski
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex)
724 29b82486 Leszek Koltunski
    {
725 846b69f3 Leszek Koltunski
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
726 57ef6378 Leszek Koltunski
    float EPSILON = 0.001f;
727
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
728 29b82486 Leszek Koltunski
729
    for(int i=1; i<len; i++)
730
      {
731 846b69f3 Leszek Koltunski
      int index = computeRotatedIndex(i,len,vertex);
732 29b82486 Leszek Koltunski
733 57ef6378 Leszek Koltunski
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
734
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
735 29b82486 Leszek Koltunski
736
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
737
      }
738
739
    return true;
740
    }
741
742
///////////////////////////////////////////////////////////////////////////////////////////////////
743
744 846b69f3 Leszek Koltunski
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
745 29b82486 Leszek Koltunski
    {
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 57ef6378 Leszek Koltunski
    float sinHalf = computeSinHalf(cos);
757
    float cosHalf = computeCosHalf(sin,cos);
758 29b82486 Leszek Koltunski
759 846b69f3 Leszek Koltunski
    mQuat2[0] = 0.0f;
760
    mQuat2[1] = 0.0f;
761
    mQuat2[2] = sinHalf;
762
    mQuat2[3] = cosHalf;
763 29b82486 Leszek Koltunski
764 d809bf6f Leszek Koltunski
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
765 29b82486 Leszek Koltunski
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 bf4e7e68 Leszek Koltunski
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert, float[] oldVert, int oldSticker)
790 29b82486 Leszek Koltunski
    {
791 bf4e7e68 Leszek Koltunski
    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 29b82486 Leszek Koltunski
    for(int vertex=0; vertex<len; vertex++)
804
      {
805 57ef6378 Leszek Koltunski
      float newX = newVert[2*vertex  ];
806
      float newY = newVert[2*vertex+1];
807 bf4e7e68 Leszek Koltunski
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
808 29b82486 Leszek Koltunski
809 bf4e7e68 Leszek Koltunski
      if( lenNew!=0 )
810 29b82486 Leszek Koltunski
        {
811 bf4e7e68 Leszek Koltunski
        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 29b82486 Leszek Koltunski
        }
824
      }
825
826
    return false;
827
    }
828
829 d99de43c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
857 8aceea06 leszek
// even if this is a multigon, then FaceTransform.vertices is the outer edge!
858
// (see fitInSquare multigon variant)
859 29b82486 Leszek Koltunski
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 d99de43c Leszek Koltunski
865 57ef6378 Leszek Koltunski
    float[] newVert = sNewInfo.vertices;
866
    float[] oldVert = sOldInfo.vertices;
867 29b82486 Leszek Koltunski
    int oldLen = oldVert.length;
868
    int newLen = newVert.length;
869
870 f7d2e0e1 Leszek Koltunski
    if( oldLen==newLen )
871 29b82486 Leszek Koltunski
      {
872 bf4e7e68 Leszek Koltunski
      float coreDistOld = computeCoreDistance(oldVert);                     // the two stickers are at different scales,
873 d99de43c Leszek Koltunski
      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 29b82486 Leszek Koltunski
      int oldSticker = oldInfo.sticker;
878 57ef6378 Leszek Koltunski
      float[] buffer1 = new float[oldLen];
879 bf4e7e68 Leszek Koltunski
880
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, oldSticker) )
881 f7d2e0e1 Leszek Koltunski
        {
882 d99de43c Leszek Koltunski
        if( sNewInfo.outer ) sOldInfo.outer = true;
883 f7d2e0e1 Leszek Koltunski
        return true;
884
        }
885 29b82486 Leszek Koltunski
      }
886
887
    return false;
888
    }
889
890
///////////////////////////////////////////////////////////////////////////////////////////////////
891 fe3dec09 Leszek Koltunski
// polygon
892 29b82486 Leszek Koltunski
893 57ef6378 Leszek Koltunski
  private float[][] constructVert(float[][] vertices, int[] index)
894 29b82486 Leszek Koltunski
    {
895
    int len = index.length;
896 57ef6378 Leszek Koltunski
    float[][] ret = new float[len][4];
897 29b82486 Leszek Koltunski
898
    for(int i=0; i<len; i++)
899
      {
900 84a17011 Leszek Koltunski
      float[] tmp = vertices[index[i]];
901
      ret[i][0] = tmp[0];
902
      ret[i][1] = tmp[1];
903
      ret[i][2] = tmp[2];
904 29b82486 Leszek Koltunski
      ret[i][3] = 1.0f;
905
      }
906
907
    return ret;
908
    }
909
910 fe3dec09 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
939
940 84a17011 Leszek Koltunski
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects, int meshState)
941 29b82486 Leszek Koltunski
    {
942 84a17011 Leszek Koltunski
    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 29b82486 Leszek Koltunski
        {
952 84a17011 Leszek Koltunski
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
953
        if( effect!=null ) mesh.apply(effect);
954 29b82486 Leszek Koltunski
        }
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 7af68038 Leszek Koltunski
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
973 846b69f3 Leszek Koltunski
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
974 29b82486 Leszek Koltunski
    }
975
976
///////////////////////////////////////////////////////////////////////////////////////////////////
977
978 b2c77ec3 Leszek Koltunski
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
979 29b82486 Leszek Koltunski
    {
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 b2c77ec3 Leszek Koltunski
  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 84a17011 Leszek Koltunski
      mQuat2[3] =  mQuat1[3];
1051 b2c77ec3 Leszek Koltunski
1052 d809bf6f Leszek Koltunski
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1053
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1054 b2c77ec3 Leszek Koltunski
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 f7d2e0e1 Leszek Koltunski
  public int printStickerCoords()
1080 29b82486 Leszek Koltunski
    {
1081
    int stickers = mStickerCoords.size();
1082 f7d2e0e1 Leszek Koltunski
    int ret = 0;
1083 29b82486 Leszek Koltunski
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 f7d2e0e1 Leszek Koltunski
      if( info.outer )  ret++;
1091 29b82486 Leszek Koltunski
1092 1561a74f Leszek Koltunski
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
1093 f7d2e0e1 Leszek Koltunski
      int len = info.vertices.length/2;
1094 2617d26b Leszek Koltunski
1095 f7d2e0e1 Leszek Koltunski
      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 2617d26b Leszek Koltunski
        }
1100 f7d2e0e1 Leszek Koltunski
1101
      ver += " }";
1102
      android.util.Log.d("D", ver);
1103 29b82486 Leszek Koltunski
      }
1104
1105
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1106 f7d2e0e1 Leszek Koltunski
1107
    return ret;
1108 29b82486 Leszek Koltunski
    }
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 b2c77ec3 Leszek Koltunski
// PUBLIC API
1135 29b82486 Leszek Koltunski
1136 b2c77ec3 Leszek Koltunski
  public static FactoryCubit getInstance()
1137 29b82486 Leszek Koltunski
    {
1138 b2c77ec3 Leszek Koltunski
    if( mThis==null ) mThis = new FactoryCubit();
1139
    return mThis;
1140 29b82486 Leszek Koltunski
    }
1141
1142 84a17011 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 1561a74f Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1186
1187 3d2493ea Leszek Koltunski
  public float[] getStickerScales()
1188 1561a74f Leszek Koltunski
    {
1189
    int index=0,num=0,len = mStickerCoords.size();
1190
1191 3d2493ea Leszek Koltunski
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
1192 1561a74f Leszek Koltunski
1193
    if( num>0 )
1194
      {
1195 b2c77ec3 Leszek Koltunski
      float[] scales = new float[num];
1196 1561a74f Leszek Koltunski
1197
      for(int i=0; i<len; i++)
1198
        {
1199
        StickerCoords sticker = mStickerCoords.get(i);
1200 3d2493ea Leszek Koltunski
        if( sticker.outer ) scales[index++] = sticker.scale;
1201 1561a74f Leszek Koltunski
        }
1202
1203 b2c77ec3 Leszek Koltunski
      return scales;
1204 1561a74f Leszek Koltunski
      }
1205
1206
    return null;
1207
    }
1208
1209
///////////////////////////////////////////////////////////////////////////////////////////////////
1210
1211 3d2493ea Leszek Koltunski
  public float[][] getStickerCoords()
1212 1561a74f Leszek Koltunski
    {
1213
    int index=0,num=0,len = mStickerCoords.size();
1214
1215 3d2493ea Leszek Koltunski
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
1216 1561a74f Leszek Koltunski
1217
    if( num>0 )
1218
      {
1219 b2c77ec3 Leszek Koltunski
      float[][] coords = new float[num][];
1220 1561a74f Leszek Koltunski
1221
      for(int i=0; i<len; i++)
1222
        {
1223
        StickerCoords sticker = mStickerCoords.get(i);
1224 3d2493ea Leszek Koltunski
        if( sticker.outer ) coords[index++] = sticker.vertices;
1225 1561a74f Leszek Koltunski
        }
1226
1227 b2c77ec3 Leszek Koltunski
      return coords;
1228 1561a74f Leszek Koltunski
      }
1229
1230
    return null;
1231
    }
1232
1233 7af68038 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1299
1300 b2c77ec3 Leszek Koltunski
  public void clear()
1301 29b82486 Leszek Koltunski
    {
1302 b2c77ec3 Leszek Koltunski
    mStickerCoords.clear();
1303
    mNewFaceTransf.clear();
1304
    mOldFaceTransf.clear();
1305
    }
1306
1307 df781f1d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 b2c77ec3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1319
1320 59a971c1 Leszek Koltunski
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1321 b2c77ec3 Leszek Koltunski
    {
1322
    float[][] vertices = shape.getVertices();
1323
    int[][] indices = shape.getVertIndices();
1324 fe3dec09 Leszek Koltunski
    int[][][] fullIndices = shape.getMultigonIndices();
1325
    boolean isMultigon = shape.isMultigon();
1326 b2c77ec3 Leszek Koltunski
    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 fe3dec09 Leszek Koltunski
    int numFaces = shape.getNumFaces();
1336 b2c77ec3 Leszek Koltunski
    int numOld = mOldFaceTransf.size();
1337
1338
    for (int face=0; face<numFaces; face++)
1339
      {
1340
      boolean collapsed = false;
1341 59a971c1 Leszek Koltunski
      boolean isOuter = (outer!=null && outer[face]>0);
1342 fe3dec09 Leszek Koltunski
      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 b2c77ec3 Leszek Koltunski
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 29b82486 Leszek Koltunski
    }
1370
1371
///////////////////////////////////////////////////////////////////////////////////////////////////
1372
1373 84a17011 Leszek Koltunski
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1374
                                     final ObjectVertexEffects effects, int meshState, int numComponents)
1375 29b82486 Leszek Koltunski
    {
1376 b2c77ec3 Leszek Koltunski
    float[][] bands         = faceShape.getBands();
1377
    int[]   bandIndexes     = faceShape.getBandIndices();
1378
    float[] convexityCenter = faceShape.getConvexityCenter();
1379
1380 fe3dec09 Leszek Koltunski
    int numFaces = shape.getNumFaces();
1381 50fb62bf Leszek Koltunski
    float[] band, bandsComputed;
1382 29b82486 Leszek Koltunski
    MeshBase[] meshes = new MeshBase[numFaces];
1383
    FaceTransform fInfo;
1384
    StickerCoords sInfo;
1385 57ef6378 Leszek Koltunski
    float[] convexXY = new float[4];
1386 50fb62bf Leszek Koltunski
    int exIndex=0, exVertices=0, alpha=0, N=0;
1387
    float height=0.0f, dist=0.0f, K=0.0f;
1388 29b82486 Leszek Koltunski
1389
    for(int face=0; face<numFaces; face++)
1390
      {
1391
      fInfo = mNewFaceTransf.get(face);
1392
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1393
1394 82bc272d Leszek Koltunski
      int index = bandIndexes[face];
1395
      band = bands[index];
1396 c3a033e9 Leszek Koltunski
1397
      switch(meshState)
1398
        {
1399 50fb62bf Leszek Koltunski
        case MESH_NICE: height     = band[0];
1400
                        alpha      = (int)band[1];
1401
                        dist       = band[2];
1402
                        K          = band[3];
1403
                        N          = (int)band[4];
1404 c3a033e9 Leszek Koltunski
                        exIndex    = (int)band[5];
1405
                        exVertices = (int)band[6];
1406
                        break;
1407 50fb62bf Leszek Koltunski
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
1408
                                                               // (example: Ivy cube center and edge cubits!)
1409
                        alpha      = 0;
1410
                        dist       = 0;
1411
                        K          = 0;
1412
                        N          = 2;
1413 c3a033e9 Leszek Koltunski
                        exIndex    = 0;
1414
                        exVertices = 0;
1415
                        break;
1416
        }
1417
1418 50fb62bf Leszek Koltunski
      bandsComputed = computeBands(height,alpha,dist,K,N);
1419 fe3dec09 Leszek Koltunski
1420 8aceea06 leszek
      sInfo = mStickerCoords.get(fInfo.sticker);
1421
      float[][] vertsF = sInfo.fullVertices;
1422
1423
      // i.e. multigon which hasn't been 'successfully collapsed'
1424
      // with a previously computed polygon sticker!
1425
      if( vertsF!=null )
1426 fe3dec09 Leszek Koltunski
        {
1427 8aceea06 leszek
        int lenVerts = vertsF.length;
1428 fe3dec09 Leszek Koltunski
        float[][] copiedVerts = new float[lenVerts][];
1429
1430
        for(int i=0; i<lenVerts; i++)
1431
          {
1432 8aceea06 leszek
          float[] v = vertsF[i];
1433 fe3dec09 Leszek Koltunski
          int len = v.length;
1434
          copiedVerts[i] = new float[len];
1435
          System.arraycopy(v, 0, copiedVerts[i], 0, len);
1436
          }
1437
1438
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1439
        }
1440 8aceea06 leszek
      else
1441
        {
1442
        float[] verts = sInfo.vertices;
1443
        int lenVerts = verts.length;
1444
        float[] copiedVerts = new float[lenVerts];
1445
        System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1446
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1447
        }
1448 fe3dec09 Leszek Koltunski
1449 0b5d4a7b Leszek Koltunski
      meshes[face].setEffectAssociation(0,0,face);
1450 29b82486 Leszek Koltunski
      }
1451
1452
    MeshBase mesh = new MeshJoined(meshes);
1453
    Static3D center = new Static3D(0,0,0);
1454
1455
    for(int face=0; face<numFaces; face++)
1456
      {
1457
      fInfo = mNewFaceTransf.get(face);
1458
1459 57ef6378 Leszek Koltunski
      float vx = fInfo.vx;
1460
      float vy = fInfo.vy;
1461
      float vz = fInfo.vz;
1462
      float sc = fInfo.scale;
1463
      float qx = fInfo.qx;
1464
      float qy = fInfo.qy;
1465
      float qz = fInfo.qz;
1466
      float qw = fInfo.qw;
1467 29b82486 Leszek Koltunski
1468 846b69f3 Leszek Koltunski
      Static3D scale = new Static3D(sc,sc,sc);
1469 29b82486 Leszek Koltunski
      Static3D move3D= new Static3D(vx,vy,vz);
1470
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1471
1472 0b5d4a7b Leszek Koltunski
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1473
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1474
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1475 29b82486 Leszek Koltunski
      }
1476
1477 18d97487 Leszek Koltunski
    correctComponents(mesh,numComponents);
1478 84a17011 Leszek Koltunski
    if( effects!=null ) applyVertexEffects(mesh,effects,meshState);
1479 29b82486 Leszek Koltunski
1480
    return mesh;
1481
    }
1482
  }