Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / touchcontrol / TouchControlShapeChanging.java @ 9ef0ad15

1 57ef6378 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 71f8a172 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 57ef6378 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10
package org.distorted.objectlib.touchcontrol;
11
12 aacf5e27 Leszek Koltunski
import org.distorted.library.helpers.QuatHelper;
13 92a6fc8b Leszek Koltunski
import org.distorted.library.type.Static3D;
14 57ef6378 Leszek Koltunski
import org.distorted.library.type.Static4D;
15
import org.distorted.objectlib.helpers.ObjectShape;
16
import org.distorted.objectlib.main.TwistyObject;
17
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20 3a1efb32 Leszek Koltunski
public class TouchControlShapeChanging extends TouchControl
21 57ef6378 Leszek Koltunski
  {
22 ede746af Leszek Koltunski
  private static final float NOT_TOUCHED = 1000000.0f;
23 0c5d8bf7 Leszek Koltunski
  static final float[] mTmp = new float[4];
24 57ef6378 Leszek Koltunski
25 0c5d8bf7 Leszek Koltunski
  static class FaceInfo
26 57ef6378 Leszek Koltunski
    {
27 0c5d8bf7 Leszek Koltunski
    private final float[] normal;      // vector normal to the surface of the face, pointing outside.
28
    private final float distance;      // distance from (0,0,0) to the surface of the face
29
    private final float[][] vertices;  // vertices of the face. Already rotated by the initQuat and
30
                                       // moved by 'position' (arithmetic average of all positions)
31
    private final float[][] rotated;   // temp array to store vertices times rotation quaternion.
32
33
    //////////////////////////////////////////////////////////
34 57ef6378 Leszek Koltunski
35 ede746af Leszek Koltunski
    FaceInfo(float[][] verts, float size)
36 57ef6378 Leszek Koltunski
      {
37 ede746af Leszek Koltunski
      int numV = verts.length;
38
39
      vertices = new float[numV][];
40
      rotated  = new float[numV][];
41 57ef6378 Leszek Koltunski
42 ede746af Leszek Koltunski
      for(int i=0; i<numV; i++)
43
        {
44
        int len = verts[i].length;
45
        vertices[i]= new float[len];
46
        rotated[i] = new float[len];
47
48
        for(int j=0; j<len; j++) vertices[i][j] = verts[i][j]/size;
49
        }
50 57ef6378 Leszek Koltunski
51
      // assuming the first three vertices are linearly independent
52
      float a1 = vertices[0][0] - vertices[1][0];
53 3a1efb32 Leszek Koltunski
      float a2 = vertices[0][1] - vertices[1][1];
54
      float a3 = vertices[0][2] - vertices[1][2];
55 57ef6378 Leszek Koltunski
      float b1 = vertices[1][0] - vertices[2][0];
56 3a1efb32 Leszek Koltunski
      float b2 = vertices[1][1] - vertices[2][1];
57
      float b3 = vertices[1][2] - vertices[2][2];
58 57ef6378 Leszek Koltunski
59
      float vx = a2*b3-a3*b2;
60
      float vy = a3*b1-a1*b3;
61
      float vz = a1*b2-a2*b1;
62
63
      float len = (float)Math.sqrt(vx*vx+vy*vy+vz*vz);
64
65
      vx/=len;
66
      vy/=len;
67
      vz/=len;
68
69 0c5d8bf7 Leszek Koltunski
      distance = vx*vertices[0][0] + vy*vertices[0][1] + vz*vertices[0][2];
70 57ef6378 Leszek Koltunski
71 0c5d8bf7 Leszek Koltunski
      normal = new float[4];
72
      normal[0] = vx;
73
      normal[1] = vy;
74
      normal[2] = vz;
75
      normal[3] = 0.0f;
76
      }
77 57ef6378 Leszek Koltunski
78 0c5d8bf7 Leszek Koltunski
    //////////////////////////////////////////////////////////
79 ede746af Leszek Koltunski
80 0c5d8bf7 Leszek Koltunski
    public float[] getNormal()
81
      {
82
      return normal;
83 57ef6378 Leszek Koltunski
      }
84
    }
85
86 dd0c5054 leszek
  private final float[] mTouch, mLastT;
87 0c5d8bf7 Leszek Koltunski
  private final Static4D mTmpAxis;
88 57ef6378 Leszek Koltunski
  private int mNumCubits;
89
  private int[] mNumFaces;
90
  private boolean mPreparationDone;
91 88411172 leszek
  private boolean[][] mRotatable;
92 dd0c5054 leszek
  private float[][] mCuts;
93 0c5d8bf7 Leszek Koltunski
94
  final float[] mCamera, mPoint;
95
  final Static3D[] mRotAxis;
96
  final TwistyObject mObject;
97 9ef0ad15 leszek
  int mTouchedCubit, mTouchedCubitFace, mNumAxis;
98 0c5d8bf7 Leszek Koltunski
  FaceInfo[][] mInfos;
99
  float[][] mQuats;
100 57ef6378 Leszek Koltunski
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102
103 3a1efb32 Leszek Koltunski
  public TouchControlShapeChanging(TwistyObject object)
104 57ef6378 Leszek Koltunski
    {
105 fb1e9a31 Leszek Koltunski
    super(object);
106 11fa413d Leszek Koltunski
107 57ef6378 Leszek Koltunski
    mPoint = new float[3];
108
    mCamera= new float[3];
109
    mTouch = new float[3];
110 dd0c5054 leszek
    mLastT = new float[3];
111 57ef6378 Leszek Koltunski
    mObject= object;
112
    mPreparationDone = false;
113 92a6fc8b Leszek Koltunski
    mTmpAxis = new Static4D(0,0,0,0);
114 93dc5a55 leszek
    mGhostAxisEnabled = -1;
115 69bd6b70 Leszek Koltunski
116
    if( object!=null )
117
      {
118 dd0c5054 leszek
      int[] numL  = object.getNumLayers();
119
      mRotAxis    = object.getRotationAxis() ;
120
      mNumAxis    = mRotAxis.length;
121
      mRotatable  = object.getLayerRotatable(numL);
122
      mCuts       = object.getCuts(numL);
123
      float size  = object.getSize();
124
      computeBorders(mCuts,mRotatable,size);
125 69bd6b70 Leszek Koltunski
      }
126
    else
127
      {
128
      mRotAxis = null;
129
      mNumAxis = 0;
130
      }
131 57ef6378 Leszek Koltunski
    }
132
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134 2beb0a96 leszek
// mesh multigon
135 57ef6378 Leszek Koltunski
136 2beb0a96 leszek
  private FaceInfo[] computeInfos(float[][] vertices, int[][][] indices, float[] position, Static4D quat, float size)
137 57ef6378 Leszek Koltunski
    {
138 2beb0a96 leszek
    int len = position.length/3;
139
    float avgX = 0.0f;
140
    float avgY = 0.0f;
141
    float avgZ = 0.0f;
142
143
    for(int i=0; i<len; i++)
144
      {
145
      avgX += position[3*i  ];
146
      avgY += position[3*i+1];
147
      avgZ += position[3*i+2];
148
      }
149
150
    avgX /= len;
151
    avgY /= len;
152
    avgZ /= len;
153
154 57ef6378 Leszek Koltunski
    int numFaces = indices.length;
155 2beb0a96 leszek
    FaceInfo[] infos = new FaceInfo[numFaces];
156
    Static4D tmp;
157
158
    for(int f=0; f<numFaces; f++)
159
      {
160
      int[][] inds = indices[f];
161
      int numSegments = inds.length;
162
      int numVerts = 0;
163
      for(int[] ind : inds) numVerts += ind.length;
164
165
      float[][] verts = new float[numVerts][4];
166
      int pointer = 0;
167 57ef6378 Leszek Koltunski
168 2beb0a96 leszek
      for(int s=0; s<numSegments; s++)
169
        {
170
        int numV = inds[s].length;
171
172
        for(int v=0; v<numV; v++)
173
          {
174
          int index = indices[f][s][v];
175
          float x = vertices[index][0];
176
          float y = vertices[index][1];
177
          float z = vertices[index][2];
178
          float w = 1.0f;
179
180
          tmp = QuatHelper.rotateVectorByQuat(x,y,z,w,quat);
181
182
          verts[pointer][0] = tmp.get0() + avgX;
183
          verts[pointer][1] = tmp.get1() + avgY;
184
          verts[pointer][2] = tmp.get2() + avgZ;
185
          verts[pointer][3] = 1.0f;
186
          pointer++;
187
          }
188
        }
189
190
      infos[f] = new FaceInfo(verts,size);
191
      }
192
193
    return infos;
194
    }
195
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
// mesh polygon
198
199
  private FaceInfo[] computeInfos(float[][] vertices, int[][] indices, float[] position, Static4D quat, float size)
200
    {
201 57ef6378 Leszek Koltunski
    int len = position.length/3;
202
    float avgX = 0.0f;
203
    float avgY = 0.0f;
204
    float avgZ = 0.0f;
205
206
    for(int i=0; i<len; i++)
207
      {
208
      avgX += position[3*i  ];
209
      avgY += position[3*i+1];
210
      avgZ += position[3*i+2];
211
      }
212
213
    avgX /= len;
214
    avgY /= len;
215
    avgZ /= len;
216
217 2beb0a96 leszek
    int numFaces = indices.length;
218 57ef6378 Leszek Koltunski
    FaceInfo[] infos = new FaceInfo[numFaces];
219
    Static4D tmp;
220
221 2beb0a96 leszek
    for(int f=0; f<numFaces; f++)
222 57ef6378 Leszek Koltunski
      {
223 2beb0a96 leszek
      int numVerts = indices[f].length;
224 3a1efb32 Leszek Koltunski
      float[][] verts = new float[numVerts][4];
225 57ef6378 Leszek Koltunski
226 2beb0a96 leszek
      for(int v=0; v<numVerts; v++)
227 57ef6378 Leszek Koltunski
        {
228 2beb0a96 leszek
        int index = indices[f][v];
229 57ef6378 Leszek Koltunski
        float x = vertices[index][0];
230
        float y = vertices[index][1];
231
        float z = vertices[index][2];
232
        float w = 1.0f;
233
234
        tmp = QuatHelper.rotateVectorByQuat(x,y,z,w,quat);
235
236 2beb0a96 leszek
        verts[v][0] = tmp.get0() + avgX;
237
        verts[v][1] = tmp.get1() + avgY;
238
        verts[v][2] = tmp.get2() + avgZ;
239
        verts[v][3] = 1.0f;
240 57ef6378 Leszek Koltunski
        }
241
242 2beb0a96 leszek
      infos[f] = new FaceInfo(verts,size);
243 57ef6378 Leszek Koltunski
      }
244
245
    return infos;
246
    }
247
248 b9c861cf Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
249
// software implementation of DistortedLibrary.mainVertexShader.degree() function.
250
// (limited to regions centered at [0,0,0])
251
252
  private float computeVertexDegree(float radius, float[] vert)
253
    {
254
    float x = vert[0];
255
    float y = vert[1];
256
    float z = vert[2];
257
258
    float len = (float)Math.sqrt(x*x + y*y + z*z);
259
    return len>radius ? 0.0f : 1.0f-len/radius;
260
    }
261
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263
// software implementation of DistortedLibrary.VertexEffectSink
264
265
  private float[] adjustVert(float pillow, float radius, float[] vert)
266
    {
267
    float[] output = new float[3];
268
    float deg = computeVertexDegree(radius,vert);
269
    float t = 1.0f - deg*(1.0f-pillow)/pillow;
270
    output[0] = t*vert[0];
271
    output[1] = t*vert[1];
272
    output[2] = t*vert[2];
273
274
    return output;
275
    }
276
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278
279
  private float[][] adjustVerticesForPillow(float pillow, float radius, float[][] verts)
280
    {
281
    int num = verts.length;
282
    float[][] output = new float[num][3];
283
    for(int i=0; i<num; i++) output[i] = adjustVert(pillow,radius,verts[i]);
284
    return output;
285
    }
286
287 57ef6378 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
288
289
  private void prepare()
290
    {
291
    int[] numLayers = mObject.getNumLayers();
292
    float[][] positions = mObject.getCubitPositions(numLayers);
293 ede746af Leszek Koltunski
    float size = mObject.getSize();
294 57ef6378 Leszek Koltunski
    mNumCubits = positions.length;
295
    mNumFaces  = new int[mNumCubits];
296
297
    mInfos = new FaceInfo[mNumCubits][];
298 b9c861cf Leszek Koltunski
    float pillow = mObject.getPillowCoeff();
299
    float radius = mObject.getCircumscribedRadius();
300 57ef6378 Leszek Koltunski
301
    for(int i=0; i<mNumCubits; i++)
302
      {
303
      int variant = mObject.getCubitVariant(i,numLayers);
304
      ObjectShape shape = mObject.getObjectShape(variant);
305 d0e6cf7f Leszek Koltunski
      Static4D quat = mObject.getCubitQuats(i,numLayers);
306 57ef6378 Leszek Koltunski
      float[][] vertices = shape.getVertices();
307 b9c861cf Leszek Koltunski
      if( pillow!=1.0f ) vertices = adjustVerticesForPillow(pillow,radius,vertices);
308 efa5bc1e leszek
      mNumFaces[i] =shape.getNumFaces();
309 2beb0a96 leszek
310
      int[][] indices = shape.getVertIndices();
311
312
      if( indices!=null )
313
        {
314
        mInfos[i] = computeInfos(vertices, indices, positions[i], quat, size);
315
        }
316
      else
317
        {
318
        int[][][] ind = shape.getMultigonIndices();
319
        mInfos[i] = computeInfos(vertices, ind, positions[i], quat, size);
320
        }
321 57ef6378 Leszek Koltunski
      }
322
323
    Static4D[] quats = mObject.getQuats();
324
    int numQuats = quats.length;
325
326
    mQuats = new float[numQuats][4];
327
328
    for(int i=0; i<numQuats; i++)
329
      {
330
      Static4D q = quats[i];
331
      mQuats[i][0] = q.get0();
332
      mQuats[i][1] = q.get1();
333
      mQuats[i][2] = q.get2();
334
      mQuats[i][3] = q.get3();
335
      }
336
337
    mPreparationDone = true;
338
    }
339
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341 a5bbbfb2 Leszek Koltunski
// points A, B, C are co-linear. Return true iff B is between A and C on this line.
342
// Compute D1 = A-B, D2=C-B. Then D1 and D2 are parallel vectors.
343
// They disagree in direction iff |D1+D2|<|D1-D2|
344 57ef6378 Leszek Koltunski
345 a5bbbfb2 Leszek Koltunski
  private boolean isBetween(float ax, float ay, float az,
346
                            float bx, float by, float bz,
347
                            float cx, float cy, float cz)
348 57ef6378 Leszek Koltunski
    {
349 a5bbbfb2 Leszek Koltunski
    float d1x = ax-bx;
350
    float d1y = ay-by;
351
    float d1z = az-bz;
352
353
    float d2x = cx-bx;
354
    float d2y = cy-by;
355
    float d2z = cz-bz;
356
357
    float sx = d1x+d2x;
358
    float sy = d1y+d2y;
359
    float sz = d1z+d2z;
360
361
    float dx = d1x-d2x;
362
    float dy = d1y-d2y;
363
    float dz = d1z-d2z;
364 57ef6378 Leszek Koltunski
365
    return sx*sx+sy*sy+sz*sz < dx*dx+dy*dy+dz*dz;
366
    }
367
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369 a5bbbfb2 Leszek Koltunski
// General algorithm: shoot a half-line from the 'point' and count how many
370
// sides of the polygon it intersects with. The point is inside iff this number
371
// is odd. Note that this works also in case of concave polygons.
372
//
373
// Arbitrarily take point P on the plane ( we have decided on P=(vert[0]+vert[1])/2 )
374
// as the other point defining the half-line.
375
// 'point' and 'P' define a line L1 in 3D. Then for each side the pair of its vertices
376
// defines a line L2. If L1||L2 return false. Otherwise, the lines are skew so it's
377
// possible to compute points C1 and C2 on lines L1 and L2 which are closest to the
378
// other line and check if
379
//
380
// a) C1 and P are on the same side of 'point'
381
//    (which happens iff 'point' is not in between of C1 and P)
382
// b) C2 is between the two vertices.
383
//
384
// Both a) and b) together mean that the half-line intersects with side defined by (p2,d2)
385
//
386
// C1 and C2 can be computed in the following way:
387
// Let n = d1 x d2 - then vector n is perpendicular to both d1 and d2 --> (c1-c2) is
388
// parallel to n.
389
// There exist real numbers A,B,C such that
390
// c1 = p1 + A*d1
391
// c2 = p2 + B*d2 and
392
// c2 = c1 + C*n so that
393
// p1 + A*d1 + C*n = p2 + B*d2  --> (p1-p2) + A*d1 = B*d2 - C*n (*)
394
// Let n2 = n x d2. Let's multiply both sides of (*) by n2. Then
395
// (p1-p2)*n2 + A*(d1*n2) = 0 (0 because d1*n2 = n*n2 = 0)
396
// and from that A = [(p1-p2)*n2]/[d1*n2]
397
// Similarly     B = [(p2-p1)*n1]/[d2*n1]  where n1 = n x d1.
398 57ef6378 Leszek Koltunski
399 11fa413d Leszek Koltunski
  private boolean isInside(float[] point, float[][] vertices)
400 57ef6378 Leszek Koltunski
    {
401 a5bbbfb2 Leszek Koltunski
    float e1x = (vertices[0][0]+vertices[1][0])/2;
402
    float e1y = (vertices[0][1]+vertices[1][1])/2;
403
    float e1z = (vertices[0][2]+vertices[1][2])/2;
404
405
    float d1x = e1x - point[0];
406
    float d1y = e1y - point[1];
407
    float d1z = e1z - point[2];
408
409
    float ax = vertices[0][0] - vertices[1][0];
410
    float ay = vertices[0][1] - vertices[1][1];
411
    float az = vertices[0][2] - vertices[1][2];
412
413
    float normX = d1y*az - d1z*ay;
414
    float normY = d1z*ax - d1x*az;
415
    float normZ = d1x*ay - d1y*ax;
416
417
    float n1x = d1y*normZ - d1z*normY;
418
    float n1y = d1z*normX - d1x*normZ;
419
    float n1z = d1x*normY - d1y*normX;
420
421
    float p1x = point[0];
422
    float p1y = point[1];
423
    float p1z = point[2];
424
425
    int len = vertices.length;
426
    int numCrossings = 0;
427 57ef6378 Leszek Koltunski
428 a5bbbfb2 Leszek Koltunski
    for(int side=0; side<len; side++)
429 57ef6378 Leszek Koltunski
      {
430 a5bbbfb2 Leszek Koltunski
      float p2x = vertices[side][0];
431
      float p2y = vertices[side][1];
432
      float p2z = vertices[side][2];
433
434
      int next = side==len-1 ? 0 : side+1;
435
436
      float e2x = vertices[next][0];
437
      float e2y = vertices[next][1];
438
      float e2z = vertices[next][2];
439
440
      float d2x = e2x-p2x;
441
      float d2y = e2y-p2y;
442
      float d2z = e2z-p2z;
443
444
      float nx = d2y*d1z - d2z*d1y;
445
      float ny = d2z*d1x - d2x*d1z;
446
      float nz = d2x*d1y - d2y*d1x;
447
448
      float n2x = d2y*nz - d2z*ny;
449
      float n2y = d2z*nx - d2x*nz;
450
      float n2z = d2x*ny - d2y*nx;
451
452
      float dpx = p1x-p2x;
453
      float dpy = p1y-p2y;
454
      float dpz = p1z-p2z;
455
456
      float A1 =-dpx*n2x-dpy*n2y-dpz*n2z;
457
      float B1 = d1x*n2x+d1y*n2y+d1z*n2z;
458
459
      float A2 = dpx*n1x+dpy*n1y+dpz*n1z;
460
      float B2 = d2x*n1x+d2y*n1y+d2z*n1z;
461
462
      if( B1==0 || B2==0 ) continue;
463
464
      float C1 = A1/B1;
465
      float C2 = A2/B2;
466
467
      float c1x = p1x + C1*d1x;
468
      float c1y = p1y + C1*d1y;
469
      float c1z = p1z + C1*d1z;
470
471
      float c2x = p2x + C2*d2x;
472
      float c2y = p2y + C2*d2y;
473
      float c2z = p2z + C2*d2z;
474
475
      if( !isBetween(c1x,c1y,c1z, p1x,p1y,p1z, e1x,e1y,e1z ) &&
476
           isBetween(p2x,p2y,p2z, c2x,c2y,c2z, e2x,e2y,e2z )  )
477
        {
478
        numCrossings++;
479
        }
480 57ef6378 Leszek Koltunski
      }
481
482 a5bbbfb2 Leszek Koltunski
    return (numCrossings%2)==1;
483 57ef6378 Leszek Koltunski
    }
484
485
///////////////////////////////////////////////////////////////////////////////////////////////////
486
487
  private void rotateVertices(float[][] points, float[][] rotated, float[] quat)
488
    {
489
    int numPoints = points.length;
490
491
    for(int i=0; i<numPoints; i++)
492
      {
493
      QuatHelper.rotateVectorByQuat(rotated[i],points[i],quat);
494
      }
495
    }
496
497
///////////////////////////////////////////////////////////////////////////////////////////////////
498
// given precomputed mCamera and mPoint, respectively camera and touch point positions in ScreenSpace,
499
// a normalVec (nx,ny,nz) and distance (which together define a plane) compute point 'output[]' which:
500
// 1) lies on this plane
501
// 2) is co-linear with mCamera and mPoint
502
//
503
// output = camera + alpha*(point-camera), where alpha = [dist-normalVec*camera] / [normalVec*(point-camera)]
504
505 0c5d8bf7 Leszek Koltunski
  void castTouchPointOntoFace(float nx, float ny, float nz, float distance, float[] output)
506 57ef6378 Leszek Koltunski
    {
507
    float d0 = mPoint[0]-mCamera[0];
508
    float d1 = mPoint[1]-mCamera[1];
509
    float d2 = mPoint[2]-mCamera[2];
510
511
    float denom = nx*d0 + ny*d1 + nz*d2;
512
513
    if( denom != 0.0f )
514
      {
515
      float axisCam = nx*mCamera[0] + ny*mCamera[1] + nz*mCamera[2];
516
      float alpha = (distance-axisCam)/denom;
517
518
      output[0] = mCamera[0] + d0*alpha;
519
      output[1] = mCamera[1] + d1*alpha;
520
      output[2] = mCamera[2] + d2*alpha;
521
      }
522
    }
523
524
///////////////////////////////////////////////////////////////////////////////////////////////////
525
526 0c5d8bf7 Leszek Koltunski
  private boolean cubitFaceIsVisible(float nx, float ny, float nz, float distance)
527 57ef6378 Leszek Koltunski
    {
528
    return mCamera[0]*nx + mCamera[1]*ny + mCamera[2]*nz > distance;
529
    }
530
531
///////////////////////////////////////////////////////////////////////////////////////////////////
532
// FaceInfo defines a 3D plane (by means of a unit normal vector 'vector' and distance from the origin
533
// 'distance') and a list of points on the plane ('vertices').
534
//
535
// 0) rotate the face normal vector by quat
536
// 1) see if the face is visible. If not, return NOT_TOUCHED
537
// 2) else, cast the line passing through mPoint and mCamera onto this plane
538
// 3) if Z of this point is further from us than the already computed closestSoFar, return NOT_TOUCHED
539
// 4) else, rotate 'vertices' by quat and see if the casted point lies inside the polygon defined by them
540 efa5bc1e leszek
// 5) if yes, return the distance from this point to the camera; otherwise, return NOT_TOUCHED
541 57ef6378 Leszek Koltunski
542 11fa413d Leszek Koltunski
  private float cubitFaceTouched(FaceInfo info, float[] quat, float closestSoFar)
543 57ef6378 Leszek Koltunski
    {
544 0c5d8bf7 Leszek Koltunski
    QuatHelper.rotateVectorByQuat(mTmp,info.normal,quat);
545 57ef6378 Leszek Koltunski
    float nx = mTmp[0];
546
    float ny = mTmp[1];
547
    float nz = mTmp[2];
548
549 0c5d8bf7 Leszek Koltunski
    if( cubitFaceIsVisible(nx,ny,nz,info.distance) )
550 57ef6378 Leszek Koltunski
      {
551
      castTouchPointOntoFace(nx,ny,nz,info.distance,mTouch);
552
553 ede746af Leszek Koltunski
      float dx = mTouch[0]-mCamera[0];
554
      float dy = mTouch[1]-mCamera[1];
555
      float dz = mTouch[2]-mCamera[2];
556
      float dist = dx*dx + dy*dy + dz*dz;
557
558
      if( dist<closestSoFar )
559 57ef6378 Leszek Koltunski
        {
560
        rotateVertices(info.vertices,info.rotated,quat);
561 ede746af Leszek Koltunski
        if( isInside(mTouch,info.rotated) ) return dist;
562 57ef6378 Leszek Koltunski
        }
563
      }
564
565
    return NOT_TOUCHED;
566
    }
567
568 88411172 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
569
// This is in order to support non-rotatable rows.
570
// If mTouchedCubit ( as computed by objectTouched() ) turns out to be not rotatable with respect to
571
// the rotAxis, we need to figure out which of the neighbouring 'rotatable' cubits is the closest.
572
//
573
// Note that we cannot do it in objectTouched(), because then we do not yet know which axis we are
574
// going to be rotating along.
575
576
  private float distanceToRow(int rotIndex, int row)
577
    {
578
    float closestSoFar = NOT_TOUCHED;
579
    int numQuats = mQuats.length;
580
    int bmp = (1<<row);
581
582
    for(int cubit=0; cubit<mNumCubits; cubit++)
583
      {
584
      int rowBitmap = mObject.getCubitRotRow(cubit,rotIndex);
585
586
      if( (rowBitmap&bmp) != 0 )
587
        {
588
        int quatIndex = mObject.getCubitQuatIndex(cubit);
589
590
        if( quatIndex<numQuats )
591
          {
592
          float[] quat = mQuats[quatIndex];
593
594
          for(int face=0; face<mNumFaces[cubit]; face++)
595
            {
596
            float dist = cubitFaceTouched(mInfos[cubit][face],quat,closestSoFar);
597
            if( dist!=NOT_TOUCHED ) closestSoFar = dist;
598
            }
599
          }
600
        }
601
      }
602
603
    return closestSoFar;
604
    }
605
606 92a6fc8b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
607
608 dd0c5054 leszek
  private int notRotatable(int axis)
609 92a6fc8b Leszek Koltunski
    {
610 dd0c5054 leszek
    Static3D a = mRotAxis[axis];
611
    float x = mLastT[0]*a.get0() + mLastT[1]*a.get1() + mLastT[2]*a.get2();
612
    x *= mObject.getSize();
613
    float[] cuts = mCuts[axis];
614 92a6fc8b Leszek Koltunski
615 dd0c5054 leszek
    if( cuts==null ) return -1;
616
    int l = cuts.length;
617 88411172 leszek
618 dd0c5054 leszek
    if( l>0 && x<=cuts[0]   ) return (l>=2 && x>=(3*cuts[  0]-cuts[  1])/2) ?   1 : -1;
619
    if( l>0 && x>=cuts[l-1] ) return (l>=2 && x<=(3*cuts[l-2]-cuts[l-1])/2) ? l-1 : -1;
620 88411172 leszek
621 dd0c5054 leszek
    for(int i=1; i<l; i++)
622
      if( x<=cuts[i] )
623
        return x<((cuts[i-1]+cuts[i])/2) ? i-1 : i+1;
624 88411172 leszek
625 dd0c5054 leszek
    return -1;
626 88411172 leszek
    }
627
628
///////////////////////////////////////////////////////////////////////////////////////////////////
629
630
  int computeRow(int cubit, int axis)
631
    {
632
    int row = mObject.getCubitRotRow(cubit,axis);
633
634
    for(int r=0; r<32; r++)
635 92a6fc8b Leszek Koltunski
      {
636 88411172 leszek
      if( (row&1)==1 )
637 dd0c5054 leszek
        return mRotatable[axis][r] ? r : notRotatable(axis);
638 88411172 leszek
639 92a6fc8b Leszek Koltunski
      row>>=1;
640
      }
641
642 88411172 leszek
    return -1;
643 92a6fc8b Leszek Koltunski
    }
644
645 57ef6378 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
646
// PUBLIC API
647
///////////////////////////////////////////////////////////////////////////////////////////////////
648
649
  public boolean objectTouched(Static4D rotatedTouchPoint, Static4D rotatedCamera)
650
    {
651
    if( !mPreparationDone ) prepare();
652
653
    mPoint[0]  = rotatedTouchPoint.get0()/mObjectRatio;
654
    mPoint[1]  = rotatedTouchPoint.get1()/mObjectRatio;
655
    mPoint[2]  = rotatedTouchPoint.get2()/mObjectRatio;
656
657
    mCamera[0] = rotatedCamera.get0()/mObjectRatio;
658
    mCamera[1] = rotatedCamera.get1()/mObjectRatio;
659
    mCamera[2] = rotatedCamera.get2()/mObjectRatio;
660
661
    float closestSoFar = NOT_TOUCHED;
662
    mTouchedCubit = -1;
663 9ef0ad15 leszek
    mTouchedCubitFace = -1;
664 3a0a23bf Leszek Koltunski
    int numQuats = mQuats.length;
665 57ef6378 Leszek Koltunski
666 ede746af Leszek Koltunski
    for(int cubit=0; cubit<mNumCubits; cubit++)
667 57ef6378 Leszek Koltunski
      {
668 ede746af Leszek Koltunski
      int quatIndex = mObject.getCubitQuatIndex(cubit);
669 57ef6378 Leszek Koltunski
670 3a0a23bf Leszek Koltunski
      if( quatIndex<numQuats )
671 57ef6378 Leszek Koltunski
        {
672 3a0a23bf Leszek Koltunski
        float[] quat = mQuats[quatIndex];
673 ede746af Leszek Koltunski
674 3a0a23bf Leszek Koltunski
        for(int face=0; face<mNumFaces[cubit]; face++)
675 57ef6378 Leszek Koltunski
          {
676 3a0a23bf Leszek Koltunski
          float dist = cubitFaceTouched(mInfos[cubit][face],quat,closestSoFar);
677
678
          if( dist!=NOT_TOUCHED )
679
            {
680
            mTouchedCubit= cubit;
681 9ef0ad15 leszek
            mTouchedCubitFace = face;
682 3a0a23bf Leszek Koltunski
            closestSoFar = dist;
683 dd0c5054 leszek
            mLastT[0] = mTouch[0];
684
            mLastT[1] = mTouch[1];
685
            mLastT[2] = mTouch[2];
686 3a0a23bf Leszek Koltunski
            }
687 57ef6378 Leszek Koltunski
          }
688
        }
689
      }
690 dd0c5054 leszek
691 57ef6378 Leszek Koltunski
    return closestSoFar!=NOT_TOUCHED;
692
    }
693
694
///////////////////////////////////////////////////////////////////////////////////////////////////
695 0c5d8bf7 Leszek Koltunski
// really implemented in derived classes; here present only because we need to be able to
696
// instantiate an object of this class for MODE_REPLACE.
697 57ef6378 Leszek Koltunski
698 cd2e8d4c Leszek Koltunski
  public void newRotation(int[] output, Static4D rotatedTouchPoint, Static4D quat)
699 57ef6378 Leszek Koltunski
    {
700
701
    }
702
703
///////////////////////////////////////////////////////////////////////////////////////////////////
704
705 5caf2641 Leszek Koltunski
  public void getCastedRotAxis(float[] output, Static4D quat, int axisIndex)
706 57ef6378 Leszek Koltunski
    {
707 5caf2641 Leszek Koltunski
    Static3D rotAxis = mRotAxis[axisIndex];
708 92a6fc8b Leszek Koltunski
    float rx = rotAxis.get0();
709
    float ry = rotAxis.get1();
710
    float rz = rotAxis.get2();
711
712
    mTmpAxis.set(rx,ry,rz,0);
713
    Static4D result = QuatHelper.rotateVectorByQuat(mTmpAxis, quat);
714
715
    float cx =result.get0();
716
    float cy =result.get1();
717
718
    float len = (float)Math.sqrt(cx*cx+cy*cy);
719
720
    if( len!=0 )
721
      {
722
      output[0] = cx/len;
723
      output[1] = cy/len;
724
      }
725
    else
726
      {
727
      output[0] = 1;
728
      output[1] = 0;
729
      }
730 57ef6378 Leszek Koltunski
    }
731
732 a6aa9a47 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
733
734
  public boolean axisAndFaceAgree(int axisIndex)
735
    {
736
    return false;
737
    }
738
739 b88ef2f2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
740
741 644c217a Leszek Koltunski
  public float[] getTouchedPuzzleCenter()
742 b88ef2f2 Leszek Koltunski
    {
743 644c217a Leszek Koltunski
    return null;
744 b88ef2f2 Leszek Koltunski
    }
745
746 57ef6378 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
747
748 11fa413d Leszek Koltunski
  public int getTouchedCubitFace()
749 57ef6378 Leszek Koltunski
    {
750 9ef0ad15 leszek
    return mTouchedCubitFace;
751 57ef6378 Leszek Koltunski
    }
752
753
///////////////////////////////////////////////////////////////////////////////////////////////////
754
755 11fa413d Leszek Koltunski
  public int getTouchedCubit()
756 57ef6378 Leszek Koltunski
    {
757 11fa413d Leszek Koltunski
    return mTouchedCubit;
758 57ef6378 Leszek Koltunski
    }
759
  }