17 |
17 |
import org.distorted.library.helpers.QuatHelper;
|
18 |
18 |
import org.distorted.library.mesh.MeshBase;
|
19 |
19 |
import org.distorted.library.mesh.MeshJoined;
|
|
20 |
import org.distorted.library.mesh.MeshMultigon;
|
20 |
21 |
import org.distorted.library.mesh.MeshPolygon;
|
21 |
22 |
import org.distorted.library.type.Static3D;
|
22 |
23 |
import org.distorted.library.type.Static4D;
|
... | ... | |
41 |
42 |
|
42 |
43 |
public static final String NAME = EffectName.DEFORM.name();
|
43 |
44 |
|
44 |
|
public static class StickerCoords
|
|
45 |
private static class StickerCoords
|
45 |
46 |
{
|
46 |
47 |
float[] vertices;
|
|
48 |
float[][] fullVertices;
|
47 |
49 |
float scale;
|
48 |
50 |
boolean outer;
|
49 |
51 |
}
|
... | ... | |
187 |
189 |
|
188 |
190 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
189 |
191 |
|
|
192 |
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 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
224 |
|
|
225 |
private float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
|
|
226 |
{
|
|
227 |
double minAngle = 2*Math.PI;
|
|
228 |
float x=0, y=0;
|
|
229 |
|
|
230 |
for( float[] v : vertices )
|
|
231 |
{
|
|
232 |
int num = v.length/2;
|
|
233 |
|
|
234 |
for( int j=0; j<num; j++)
|
|
235 |
{
|
|
236 |
float xc = v[2*j];
|
|
237 |
float yc = v[2*j+1];
|
|
238 |
|
|
239 |
if( xc==curr[0] && yc==curr[1])
|
|
240 |
{
|
|
241 |
int n = (j==num-1 ? 0 : j+1);
|
|
242 |
float xn = v[2*n];
|
|
243 |
float yn = v[2*n+1];
|
|
244 |
|
|
245 |
double angle = computeAngle(vect[0], vect[1], xn-xc, yn-yc);
|
|
246 |
|
|
247 |
if (angle < minAngle)
|
|
248 |
{
|
|
249 |
minAngle = angle;
|
|
250 |
x = xn;
|
|
251 |
y = yn;
|
|
252 |
}
|
|
253 |
|
|
254 |
break;
|
|
255 |
}
|
|
256 |
}
|
|
257 |
}
|
|
258 |
|
|
259 |
return new float[] {x,y};
|
|
260 |
}
|
|
261 |
|
|
262 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
263 |
// same as in MeshMultigon
|
|
264 |
|
|
265 |
private float[] computeOuterEdge(float[][] vertices)
|
|
266 |
{
|
|
267 |
ArrayList<float[]> tmp = new ArrayList<>();
|
|
268 |
|
|
269 |
float[] vect = new float[] {1,0};
|
|
270 |
float[] first= detectFirstOuterVertex(vertices);
|
|
271 |
float[] next = first;
|
|
272 |
|
|
273 |
do
|
|
274 |
{
|
|
275 |
float[] prev = next;
|
|
276 |
next = detectNextOuterVertex(vertices,next,vect);
|
|
277 |
vect[0] = prev[0]-next[0];
|
|
278 |
vect[1] = prev[1]-next[1];
|
|
279 |
tmp.add(next);
|
|
280 |
}
|
|
281 |
while( next[0]!=first[0] || next[1]!=first[1] );
|
|
282 |
|
|
283 |
int num = tmp.size();
|
|
284 |
float[] ret = new float[2*num];
|
|
285 |
|
|
286 |
for(int i=0; i<num; i++)
|
|
287 |
{
|
|
288 |
float[] t = tmp.remove(0);
|
|
289 |
ret[2*i ] = t[0];
|
|
290 |
ret[2*i+1] = t[1];
|
|
291 |
}
|
|
292 |
|
|
293 |
return ret;
|
|
294 |
}
|
|
295 |
|
|
296 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
297 |
// polygon
|
|
298 |
|
190 |
299 |
private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
|
191 |
300 |
{
|
192 |
301 |
float minX = Float.MAX_VALUE;
|
... | ... | |
221 |
330 |
sInfo.outer = isOuter;
|
222 |
331 |
sInfo.scale = info.scale;
|
223 |
332 |
sInfo.vertices = new float[2*len];
|
|
333 |
sInfo.fullVertices = null;
|
224 |
334 |
|
225 |
335 |
for( int vertex=0; vertex<len; vertex++ )
|
226 |
336 |
{
|
... | ... | |
233 |
343 |
info.sticker = mStickerCoords.size() -1;
|
234 |
344 |
}
|
235 |
345 |
|
|
346 |
|
236 |
347 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
348 |
// multigon
|
|
349 |
|
|
350 |
private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
|
|
351 |
{
|
|
352 |
float minX = Float.MAX_VALUE;
|
|
353 |
float maxX =-Float.MAX_VALUE;
|
|
354 |
float minY = Float.MAX_VALUE;
|
|
355 |
float maxY =-Float.MAX_VALUE;
|
|
356 |
|
|
357 |
for( float[][] vert : vert3D)
|
|
358 |
for( float[] v : vert)
|
|
359 |
{
|
|
360 |
float x = v[0];
|
|
361 |
float y = v[1];
|
|
362 |
|
|
363 |
if (x > maxX) maxX = x;
|
|
364 |
if (x < minX) minX = x;
|
|
365 |
if (y > maxY) maxY = y;
|
|
366 |
if (y < minY) minY = y;
|
|
367 |
}
|
|
368 |
|
|
369 |
minX = minX<0 ? -minX:minX;
|
|
370 |
maxX = maxX<0 ? -maxX:maxX;
|
|
371 |
minY = minY<0 ? -minY:minY;
|
|
372 |
maxY = maxY<0 ? -maxY:maxY;
|
|
373 |
|
|
374 |
float max1 = Math.max(minX,minY);
|
|
375 |
float max2 = Math.max(maxX,maxY);
|
|
376 |
float max3 = Math.max(max1,max2);
|
|
377 |
|
|
378 |
info.scale = max3/0.5f;
|
|
379 |
|
|
380 |
int len = vert3D.length;
|
|
381 |
StickerCoords sInfo = new StickerCoords();
|
|
382 |
sInfo.outer = isOuter;
|
|
383 |
sInfo.scale = info.scale;
|
|
384 |
sInfo.fullVertices = new float[len][];
|
|
385 |
|
|
386 |
for( int comp=0; comp<len; comp++ )
|
|
387 |
{
|
|
388 |
float[][] vert = vert3D[comp];
|
|
389 |
int num = vert.length;
|
|
390 |
sInfo.fullVertices[comp] = new float[2*num];
|
|
391 |
float[] t = sInfo.fullVertices[comp];
|
|
392 |
|
|
393 |
for( int vertex=0; vertex<num; vertex++)
|
|
394 |
{
|
|
395 |
t[2*vertex ] = vert[vertex][0] / info.scale;
|
|
396 |
t[2*vertex+1] = vert[vertex][1] / info.scale;
|
|
397 |
}
|
|
398 |
}
|
|
399 |
|
|
400 |
sInfo.vertices = computeOuterEdge(sInfo.fullVertices);
|
|
401 |
|
|
402 |
mStickerCoords.add(sInfo);
|
|
403 |
|
|
404 |
info.sticker = mStickerCoords.size() -1;
|
|
405 |
}
|
|
406 |
|
|
407 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
408 |
// polygon
|
237 |
409 |
|
238 |
410 |
private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
|
239 |
411 |
{
|
... | ... | |
355 |
527 |
return ft;
|
356 |
528 |
}
|
357 |
529 |
|
|
530 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
531 |
// multigon
|
|
532 |
|
|
533 |
private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
|
|
534 |
{
|
|
535 |
FaceTransform ft = new FaceTransform();
|
|
536 |
ft.face = face;
|
|
537 |
ft.numFaces = numFaces;
|
|
538 |
|
|
539 |
// compute center of gravity
|
|
540 |
ft.vx = 0.0f;
|
|
541 |
ft.vy = 0.0f;
|
|
542 |
ft.vz = 0.0f;
|
|
543 |
int len = 0;
|
|
544 |
|
|
545 |
for( float[][] vert : vert3D )
|
|
546 |
for( float[] v : vert )
|
|
547 |
{
|
|
548 |
ft.vx += v[0];
|
|
549 |
ft.vy += v[1];
|
|
550 |
ft.vz += v[2];
|
|
551 |
len++;
|
|
552 |
}
|
|
553 |
|
|
554 |
ft.vx /= len;
|
|
555 |
ft.vy /= len;
|
|
556 |
ft.vz /= len;
|
|
557 |
|
|
558 |
// move all vertices so that their center of gravity is at (0,0,0)
|
|
559 |
for( float[][] vert : vert3D )
|
|
560 |
for( float[] v : vert )
|
|
561 |
{
|
|
562 |
v[0] -= ft.vx;
|
|
563 |
v[1] -= ft.vy;
|
|
564 |
v[2] -= ft.vz;
|
|
565 |
}
|
|
566 |
|
|
567 |
// find 3 non-colinear vertices
|
|
568 |
int foundIndex = -1;
|
|
569 |
len = vert3D[0].length;
|
|
570 |
|
|
571 |
for(int vertex=2; vertex<len; vertex++)
|
|
572 |
{
|
|
573 |
if( !areColinear(vert3D[0],0,1,vertex) )
|
|
574 |
{
|
|
575 |
foundIndex = vertex;
|
|
576 |
break;
|
|
577 |
}
|
|
578 |
}
|
|
579 |
|
|
580 |
// compute the normal vector
|
|
581 |
if( foundIndex==-1 )
|
|
582 |
{
|
|
583 |
StringBuilder sb = new StringBuilder();
|
|
584 |
|
|
585 |
for (float[] v : vert3D[0])
|
|
586 |
{
|
|
587 |
sb.append(' ');
|
|
588 |
sb.append("(");
|
|
589 |
sb.append(v[0]);
|
|
590 |
sb.append(" ");
|
|
591 |
sb.append(v[1]);
|
|
592 |
sb.append(" ");
|
|
593 |
sb.append(v[2]);
|
|
594 |
sb.append(")");
|
|
595 |
}
|
|
596 |
android.util.Log.e("D", "verts: "+sb);
|
|
597 |
|
|
598 |
throw new RuntimeException("all vertices colinear");
|
|
599 |
}
|
|
600 |
|
|
601 |
computeNormalVector(vert3D[0],0,1,foundIndex);
|
|
602 |
|
|
603 |
// rotate so that the normal vector becomes (0,0,1)
|
|
604 |
float axisX, axisY, axisZ;
|
|
605 |
|
|
606 |
if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
|
|
607 |
{
|
|
608 |
axisX = -mBuffer[1];
|
|
609 |
axisY = mBuffer[0];
|
|
610 |
axisZ = 0.0f;
|
|
611 |
|
|
612 |
float axiLen = axisX*axisX + axisY*axisY;
|
|
613 |
axiLen = (float)Math.sqrt(axiLen);
|
|
614 |
axisX /= axiLen;
|
|
615 |
axisY /= axiLen;
|
|
616 |
axisZ /= axiLen;
|
|
617 |
}
|
|
618 |
else
|
|
619 |
{
|
|
620 |
axisX = 0.0f;
|
|
621 |
axisY = 1.0f;
|
|
622 |
axisZ = 0.0f;
|
|
623 |
}
|
|
624 |
|
|
625 |
float cosTheta = mBuffer[2];
|
|
626 |
float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
|
|
627 |
float sinHalfTheta = computeSinHalf(cosTheta);
|
|
628 |
float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
|
|
629 |
|
|
630 |
mQuat1[0] = axisX*sinHalfTheta;
|
|
631 |
mQuat1[1] = axisY*sinHalfTheta;
|
|
632 |
mQuat1[2] = axisZ*sinHalfTheta;
|
|
633 |
mQuat1[3] = cosHalfTheta;
|
|
634 |
mQuat2[0] =-axisX*sinHalfTheta;
|
|
635 |
mQuat2[1] =-axisY*sinHalfTheta;
|
|
636 |
mQuat2[2] =-axisZ*sinHalfTheta;
|
|
637 |
mQuat2[3] = cosHalfTheta;
|
|
638 |
|
|
639 |
for( float[][] vert : vert3D)
|
|
640 |
for( float[] v : vert)
|
|
641 |
{
|
|
642 |
QuatHelper.quatMultiply(mQuat3, mQuat1, v );
|
|
643 |
QuatHelper.quatMultiply( v, mQuat3, mQuat2);
|
|
644 |
}
|
|
645 |
|
|
646 |
// fit the whole thing in a square and remember the scale & 2D vertices
|
|
647 |
fitInSquare(ft, vert3D, isOuter);
|
|
648 |
|
|
649 |
// remember the rotation
|
|
650 |
ft.qx =-mQuat1[0];
|
|
651 |
ft.qy =-mQuat1[1];
|
|
652 |
ft.qz =-mQuat1[2];
|
|
653 |
ft.qw = mQuat1[3];
|
|
654 |
|
|
655 |
return ft;
|
|
656 |
}
|
|
657 |
|
358 |
658 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
359 |
659 |
|
360 |
660 |
private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
|
361 |
661 |
{
|
362 |
662 |
for(int i=0; i<len; i++)
|
363 |
663 |
{
|
364 |
|
result[2*i ] = vertices[2*i ]*cos - vertices[2*i+1]*sin;
|
365 |
|
result[2*i+1] = vertices[2*i ]*sin + vertices[2*i+1]*cos;
|
|
664 |
float x = vertices[2*i];
|
|
665 |
float y = vertices[2*i+1];
|
|
666 |
result[2*i ] = x*cos - y*sin;
|
|
667 |
result[2*i+1] = x*sin + y*cos;
|
366 |
668 |
}
|
367 |
669 |
}
|
368 |
670 |
|
... | ... | |
577 |
879 |
}
|
578 |
880 |
|
579 |
881 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
882 |
// polygon
|
580 |
883 |
|
581 |
884 |
private float[][] constructVert(float[][] vertices, int[] index)
|
582 |
885 |
{
|
... | ... | |
595 |
898 |
return ret;
|
596 |
899 |
}
|
597 |
900 |
|
|
901 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
902 |
// multigon
|
|
903 |
|
|
904 |
private float[][][] constructVert(float[][] vertices, int[][] index)
|
|
905 |
{
|
|
906 |
int len = index.length;
|
|
907 |
float[][][] ret = new float[len][][];
|
|
908 |
|
|
909 |
for(int i=0; i<len; i++)
|
|
910 |
{
|
|
911 |
int[] ind = index[i];
|
|
912 |
int num = ind.length;
|
|
913 |
ret[i] = new float[num][4];
|
|
914 |
|
|
915 |
for(int j=0; j<num; j++)
|
|
916 |
{
|
|
917 |
float[] r = ret[i][j];
|
|
918 |
float[] v = vertices[ind[j]];
|
|
919 |
r[0] = v[0];
|
|
920 |
r[1] = v[1];
|
|
921 |
r[2] = v[2];
|
|
922 |
r[3] = 1.0f;
|
|
923 |
}
|
|
924 |
}
|
|
925 |
|
|
926 |
return ret;
|
|
927 |
}
|
|
928 |
|
598 |
929 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
599 |
930 |
|
600 |
931 |
private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects, int meshState)
|
... | ... | |
796 |
1127 |
public static FactoryCubit getInstance()
|
797 |
1128 |
{
|
798 |
1129 |
if( mThis==null ) mThis = new FactoryCubit();
|
799 |
|
|
800 |
1130 |
return mThis;
|
801 |
1131 |
}
|
802 |
1132 |
|
... | ... | |
982 |
1312 |
{
|
983 |
1313 |
float[][] vertices = shape.getVertices();
|
984 |
1314 |
int[][] indices = shape.getVertIndices();
|
|
1315 |
int[][][] fullIndices = shape.getMultigonIndices();
|
|
1316 |
boolean isMultigon = shape.isMultigon();
|
985 |
1317 |
FaceTransform ft;
|
986 |
1318 |
int numNew = mNewFaceTransf.size();
|
987 |
1319 |
|
... | ... | |
991 |
1323 |
mOldFaceTransf.add(ft);
|
992 |
1324 |
}
|
993 |
1325 |
|
994 |
|
int numFaces = indices.length;
|
|
1326 |
int numFaces = shape.getNumFaces();
|
995 |
1327 |
int numOld = mOldFaceTransf.size();
|
996 |
1328 |
|
997 |
1329 |
for (int face=0; face<numFaces; face++)
|
998 |
1330 |
{
|
999 |
1331 |
boolean collapsed = false;
|
1000 |
1332 |
boolean isOuter = (outer!=null && outer[face]>0);
|
1001 |
|
float[][] vert = constructVert(vertices, indices[face]);
|
1002 |
|
FaceTransform newT = constructNewTransform(vert,isOuter,face,numFaces);
|
|
1333 |
FaceTransform newT;
|
|
1334 |
|
|
1335 |
if( !isMultigon )
|
|
1336 |
{
|
|
1337 |
float[][] vert = constructVert(vertices, indices[face]);
|
|
1338 |
newT = constructNewTransform(vert,isOuter,face,numFaces);
|
|
1339 |
}
|
|
1340 |
else
|
|
1341 |
{
|
|
1342 |
float[][][] vert = constructVert(vertices, fullIndices[face]);
|
|
1343 |
newT = constructNewTransform(vert,isOuter,face,numFaces);
|
|
1344 |
}
|
1003 |
1345 |
|
1004 |
1346 |
for (int old=0; !collapsed && old<numOld; old++)
|
1005 |
1347 |
{
|
... | ... | |
1022 |
1364 |
public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
|
1023 |
1365 |
final ObjectVertexEffects effects, int meshState, int numComponents)
|
1024 |
1366 |
{
|
1025 |
|
int[][] vertIndexes = shape.getVertIndices();
|
1026 |
1367 |
float[][] bands = faceShape.getBands();
|
1027 |
1368 |
int[] bandIndexes = faceShape.getBandIndices();
|
1028 |
1369 |
float[] convexityCenter = faceShape.getConvexityCenter();
|
1029 |
1370 |
|
1030 |
|
int numFaces = vertIndexes.length;
|
|
1371 |
int numFaces = shape.getNumFaces();
|
|
1372 |
boolean multigonMode = shape.isMultigon();
|
1031 |
1373 |
float[] band, bandsComputed;
|
1032 |
1374 |
MeshBase[] meshes = new MeshBase[numFaces];
|
1033 |
1375 |
FaceTransform fInfo;
|
... | ... | |
1039 |
1381 |
for(int face=0; face<numFaces; face++)
|
1040 |
1382 |
{
|
1041 |
1383 |
fInfo = mNewFaceTransf.get(face);
|
1042 |
|
sInfo = mStickerCoords.get(fInfo.sticker);
|
1043 |
|
|
1044 |
|
float[] verts = sInfo.vertices;
|
1045 |
|
int lenVerts = verts.length;
|
1046 |
|
float[] copiedVerts = new float[lenVerts];
|
1047 |
|
System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
|
1048 |
|
|
1049 |
1384 |
computeConvexityCenter(convexXY,convexityCenter,fInfo);
|
1050 |
1385 |
|
1051 |
1386 |
int index = bandIndexes[face];
|
... | ... | |
1073 |
1408 |
}
|
1074 |
1409 |
|
1075 |
1410 |
bandsComputed = computeBands(height,alpha,dist,K,N);
|
1076 |
|
meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,null,null,exIndex,exVertices, convexXY[0], convexXY[1]);
|
|
1411 |
|
|
1412 |
if( !multigonMode )
|
|
1413 |
{
|
|
1414 |
sInfo = mStickerCoords.get(fInfo.sticker);
|
|
1415 |
float[] verts = sInfo.vertices;
|
|
1416 |
int lenVerts = verts.length;
|
|
1417 |
float[] copiedVerts = new float[lenVerts];
|
|
1418 |
System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
|
|
1419 |
meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,null,null,exIndex,exVertices, convexXY[0], convexXY[1]);
|
|
1420 |
}
|
|
1421 |
else
|
|
1422 |
{
|
|
1423 |
sInfo = mStickerCoords.get(fInfo.sticker);
|
|
1424 |
float[][] verts = sInfo.fullVertices;
|
|
1425 |
int lenVerts = verts.length;
|
|
1426 |
float[][] copiedVerts = new float[lenVerts][];
|
|
1427 |
|
|
1428 |
for(int i=0; i<lenVerts; i++)
|
|
1429 |
{
|
|
1430 |
float[] v = verts[i];
|
|
1431 |
int len = v.length;
|
|
1432 |
copiedVerts[i] = new float[len];
|
|
1433 |
System.arraycopy(v, 0, copiedVerts[i], 0, len);
|
|
1434 |
}
|
|
1435 |
|
|
1436 |
meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
|
|
1437 |
}
|
|
1438 |
|
1077 |
1439 |
meshes[face].setEffectAssociation(0,0,face);
|
1078 |
1440 |
}
|
1079 |
1441 |
|
use MeshMultigon in puzzle cubits (FactoryCubit)