Project

General

Profile

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

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

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