commit 749ef882835e8bea771e378f356a95705a1fc2df
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Apr 14 10:01:46 2021 +0200

    Move Factories to the 'helpers' package.

diff --git a/src/main/java/org/distorted/helpers/FactoryCubit.java b/src/main/java/org/distorted/helpers/FactoryCubit.java
new file mode 100644
index 00000000..55cffb57
--- /dev/null
+++ b/src/main/java/org/distorted/helpers/FactoryCubit.java
@@ -0,0 +1,2207 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is free software: you can redistribute it and/or modify                            //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Magic Cube is distributed in the hope that it will be useful,                                 //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.helpers;
+
+import org.distorted.library.effect.VertexEffect;
+import org.distorted.library.effect.VertexEffectDeform;
+import org.distorted.library.effect.VertexEffectMove;
+import org.distorted.library.effect.VertexEffectRotate;
+import org.distorted.library.effect.VertexEffectScale;
+import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshJoined;
+import org.distorted.library.mesh.MeshPolygon;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class FactoryCubit
+  {
+  private static final float SQ2 = (float)Math.sqrt(2);
+  private static final float SQ3 = (float)Math.sqrt(3);
+  private static final float SQ5 = (float)Math.sqrt(5);
+  private static final float SQ6 = (float)Math.sqrt(6);
+
+  private static final Static1D RADIUS = new Static1D(1);
+  private static FactoryCubit mThis;
+
+  // IVY
+  static final float IVY_D = 0.003f;
+  static final float IVY_C = 0.59f;
+  static final float IVY_M = 0.35f;
+  private static final int IVY_N = 8;
+
+  // REX
+  public static final float REX_D = 0.2f;
+
+  // KILO / MEGAMINX
+  public static final float SIN54    = (SQ5+1)/4;
+  public static final float COS54    = (float)(Math.sqrt(10-2*SQ5)/4);
+  public static final float SIN18    = (SQ5-1)/4;
+  public static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
+  public static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
+  public static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
+  public static final float DIHEDRAL1= (float)(Math.acos(-SQ5/5)*180/Math.PI);
+  public static final float DIHEDRAL2= (float)((180/Math.PI)*Math.asin((2*SIN54*SIN54-1)/COS54) - 90);
+  public static final float MINX_SC  = 0.5f;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private FactoryCubit()
+    {
+
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static FactoryCubit getInstance()
+    {
+    if( mThis==null ) mThis = new FactoryCubit();
+
+    return mThis;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// H - height of the band in the middle
+// alpha - angle of the edge  [0,90]
+// dist - often in a polygon the distance from edge to center is not 1, but something else.
+// This is the distance.
+// K - where to begin the second, much more flat part of the band. [0,1]
+// N - number of bands. N>=3
+//
+// theory: two distinct parts to the band:
+// 1) (0,B) - steep
+// 2) (B,1) - flat
+//
+// In first part, we have y = g(x) ; in second - y = g(f(x)) where
+//
+// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
+// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
+// h(x) = R*(sin(alpha) - sin(x))
+// R = H/(1-cos(alpha))
+// D = H*sin(alpha)
+// B = h(K*alpha)
+//
+// The N points are taken at:
+//
+// 1) in the second part, there are K2 = (N-3)/3 such points
+// 2) in the first - K1 = (N-3) - K2
+// 3) also, the 3 points 0,B,1
+//
+// so we have the sequence A[i] of N points
+//
+// 0
+// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
+// B
+// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
+// 1
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float f(float D, float B, float x)
+    {
+    return ((D-B)*x + B*(1-D))/(1-B);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float g(float R, float D, float x, float cosAlpha)
+    {
+    float d = x-D;
+    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float h(float R, float sinAlpha, float x)
+    {
+    return R*(sinAlpha-(float)Math.sin(x));
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float[] computeBands(float H, int alpha, float dist, float K, int N)
+    {
+    float[] bands = new float[2*N];
+
+    bands[0] = 1.0f;
+    bands[1] = 0.0f;
+
+    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
+    float sinBeta = (float)Math.sin(beta);
+    float cosBeta = (float)Math.cos(beta);
+    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
+    float D = R*sinBeta;
+    float B = h(R,sinBeta,K*beta);
+
+    if( D>1.0f )
+      {
+      for(int i=1; i<N; i++)
+        {
+        bands[2*i  ] = (float)(N-1-i)/(N-1);
+        bands[2*i+1] = H*(1-bands[2*i]);
+        }
+      }
+    else
+      {
+      int K2 = (int)((N-3)*K);
+      int K1 = (N-3)-K2;
+
+      for(int i=0; i<=K1; i++)
+        {
+        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
+        float x = h(R,sinBeta,angle);
+        bands[2*i+2] = 1.0f - x;
+        bands[2*i+3] = g(R,D,x,cosBeta);
+        }
+
+      for(int i=0; i<=K2; i++)
+        {
+        float x = (1-B)*(i+1)/(K2+1) + B;
+        bands[2*K1+2 + 2*i+2] = 1.0f - x;
+        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
+        }
+      }
+
+    bands[2*N-2] = 0.0f;
+    bands[2*N-1] =    H;
+
+    return bands;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
+    {
+    Static4D reg= new Static4D(0,0,0,regionRadius);
+
+    float centX = center.get0();
+    float centY = center.get1();
+    float centZ = center.get2();
+
+    for (Static3D vertex : vertices)
+      {
+      float x = strength*(centX - vertex.get0());
+      float y = strength*(centY - vertex.get1());
+      float z = strength*(centZ - vertex.get2());
+
+      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
+      mesh.apply(effect);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesCube(int sizeIndex)
+    {
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    float E = 0.5f;
+    int extraI, extraV, num;
+
+    switch(sizeIndex)
+      {
+      case 0 : num = 6; extraI = 2; extraV = 2; break;
+      case 1 : num = 5; extraI = 2; extraV = 2; break;
+      case 2 : num = 5; extraI = 1; extraV = 2; break;
+      default: num = 4; extraI = 1; extraV = 1; break;
+      }
+
+    float[] vertices = { -E,-E, +E,-E, +E,+E, -E,+E };
+    float[] bands = computeBands(0.048f,35,E,0.7f,num);
+
+    meshes[0] = new MeshPolygon(vertices,bands,extraI,extraV);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[0].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[0].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[0].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesSkewbCorner()
+    {
+    MeshBase[] meshes = new MeshBase[6];
+
+    float E = 0.5f;
+    float F = SQ2/2;
+    float G = SQ6/16;
+    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
+    float[] bands0 = computeBands(0.028f,35,E/3,0.7f,7);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+
+    float[] vertices1 = { -F/2,-2*G, F/2,-2*G, 3*F/8,-G, 1*F/8,G, 0,2*G };
+    float[] bands1 = computeBands(0,0,1,0,3);
+
+    meshes[3] = new MeshPolygon(vertices1,bands1,1,5);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[3].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[3].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesSkewbFace()
+    {
+    MeshBase[] meshes = new MeshBase[5];
+
+    float E = SQ2/4;
+    float[] vertices0 = { -E,-E, +E,-E, +E,+E, -E,+E };
+    float[] bands0 = computeBands(0.051f,35,E/2,0.9f,7);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
+    meshes[0].setEffectAssociation(0,1,0);
+
+    float[] vertices1 = { -E,-SQ3*E, -E*0.7f,-SQ3*E, +E*0.7f,-SQ3*E, +E,-SQ3*E, 0,0 };
+    float[] bands1 = computeBands(0,0,1,0,3);
+
+    meshes[1] = new MeshPolygon(vertices1,bands1,0,0);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[1].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[1].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[1].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesOcta()
+    {
+    MeshBase[] meshes = new MeshPolygon[8];
+
+    float E = 0.75f;
+    float F = 0.5f;
+    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
+    float[] bands = computeBands(0.05f,35,F,0.8f,6);
+
+    meshes[0] = new MeshPolygon(vertices, bands, 2,2);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[0].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[0].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[0].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+    meshes[6] = meshes[0].copy(true);
+    meshes[6].setEffectAssociation(0,64,0);
+    meshes[7] = meshes[0].copy(true);
+    meshes[7].setEffectAssociation(0,128,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesTetra()
+    {
+    MeshBase[] meshes = new MeshBase[4];
+
+    float E = 0.75f;
+    float F = 0.5f;
+    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
+    float[] bands = computeBands(0.05f,35,F,0.8f,6);
+
+    meshes[0] = new MeshPolygon(vertices, bands, 2,2);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[0].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesDino()
+    {
+    MeshBase[] meshes = new MeshPolygon[4];
+
+    float E = 0.5f*SQ2;
+    float F = 0.5f;
+    float[] vertices0 = { -F,F/3, 0,-2*F/3, +F,F/3 };
+    float[] bands0 = computeBands(0.028f,30,F/3,0.8f,7);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 5);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    float[] vertices1 = { -E/2,-E*(SQ3/6), E/2,-E*(SQ3/6), 0,E*(SQ3/3) };
+    float[] bands1 = computeBands(0.02f,45,F/3,0.2f,3);
+
+    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesHelicopterCorner()
+    {
+    MeshBase[] meshes = new MeshBase[6];
+
+    float E = 0.5f;
+    float F = SQ2/4;
+    float G = 1.0f/12;
+    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
+    float[] bands0 = computeBands(0.028f,35,E/4,0.7f,7);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+
+    float[] vertices1 = { -F,-G, 0,-G, +F,-G, 0,2*G };
+    float[] bands1 = computeBands(0.00f,0,0,0.0f,3);
+    meshes[3] = new MeshPolygon(vertices1,bands1,1,5);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[3].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[3].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesHelicopterFace()
+    {
+    MeshBase[] meshes = new MeshBase[4];
+
+    float E = 0.5f;
+    float F = SQ2/4;
+    float G = 1.0f/12;
+    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
+    float[] bands0 = computeBands(0.028f,35,E/4,0.7f,7);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
+    meshes[0].setEffectAssociation(0,1,0);
+
+    float[] vertices1 = { -F,-G, +F,-G, 0,2*G};
+    float[] bands1 = computeBands(0.01f,45,F,0.0f,3);
+
+    meshes[1] = new MeshPolygon(vertices1, bands1, 1, 3);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    float[] vertices2 = { -E/2,-F/3, +E/2,-F/3, 0,2*F/3};
+
+    meshes[2] = new MeshPolygon(vertices2, bands1, 1, 3);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesRediEdge()
+    {
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    float F = 0.25f;
+    float[] vertices0 = { -F,+F, -F,-F, 0, -2*F, +F,-F, +F,+F };
+    float[] bands0 = computeBands(0.038f,35,F,0.7f,7);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 2);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    float[] bands1 = computeBands(0.02f,35,F/2,0.2f,3);
+    float[] vertices1 = { -F/2, +F/2, -F/2, -1.5f*F, 1.5f*F, +F/2 };
+
+    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+
+    float X = 0.25f*SQ2;
+    float Y = SQ6/16;
+    float[] vertices2 = { -X, Y, -1.5f*X, -Y, +1.5f*X, -Y, +X, Y };
+
+    meshes[4] = new MeshPolygon(vertices2, bands1, 1, 1);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[4].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesRediCorner()
+    {
+    MeshBase[] meshes = new MeshBase[6];
+
+    float E = 0.5f;
+    float[] vertices0 = { -E,-E, +E,-E, +E,+E, -E,+E };
+    float[] bands0 = computeBands(0.06f,35,E,0.7f,6);
+
+    meshes[0] = new MeshPolygon(vertices0,bands0,2,2);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+
+    float F = 0.5f;
+    float X = 0.5f;
+    float G = 0.72f;
+    float[] vertices1 = { -E,+F, -E+X,0, -E,-F, -E*G,-F, +E*G,-F, +E,-F, +E-X,0, +E,+F, +E*G,+F, -E*G,+F };
+    float[] bands1 = computeBands(0.0f,0,1.0f,0.0f,2);
+
+    meshes[3] = new MeshPolygon(vertices1,bands1,0,0);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[3].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[3].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesIvyCorner()
+    {
+    MeshBase[] meshes = new MeshBase[6];
+
+    final float angle = (float)Math.PI/(2*IVY_N);
+    final float CORR  = 1.0f - 2*IVY_D;
+    final float DIST  = -0.5f*CORR + IVY_D;
+    float[] vertices  = new float[2*(IVY_N+1)+6];
+
+    vertices[0] = (0.5f-IVY_M) * IVY_C;
+    vertices[1] = (DIST-IVY_M) * IVY_C;
+    vertices[2] = (0.5f-IVY_M) * IVY_C;
+    vertices[3] = (0.5f-IVY_M) * IVY_C;
+    vertices[4] = (DIST-IVY_M) * IVY_C;
+    vertices[5] = (0.5f-IVY_M) * IVY_C;
+
+    for(int i=0; i<=IVY_N; i++)
+      {
+      float ang = (IVY_N-i)*angle;
+      float sin = (float)Math.sin(ang);
+      float cos = (float)Math.cos(ang);
+
+      vertices[2*i+6] = (CORR*(cos-0.5f)-IVY_M)*IVY_C;
+      vertices[2*i+7] = (CORR*(sin-0.5f)-IVY_M)*IVY_C;
+      }
+
+    float[] bands0 = computeBands(+0.012f,20,0.2f,0.5f,7);
+    float[] bands1 = computeBands(-0.100f,20,0.2f,0.0f,2);
+
+    meshes[0] = new MeshPolygon(vertices,bands0,1,2);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = new MeshPolygon(vertices,bands1,1,2);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[3].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[3].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesIvyFace()
+    {
+    MeshBase[] meshes = new MeshBase[2];
+
+    final float angle = (float)Math.PI/(2*IVY_N);
+    final float CORR  = 1.0f - 2*IVY_D;
+    float[] vertices = new float[4*IVY_N];
+
+    for(int i=0; i<IVY_N; i++)
+      {
+      float sin = (float)Math.sin(i*angle);
+      float cos = (float)Math.cos(i*angle);
+
+      vertices[2*i          ] = CORR*(0.5f-cos);
+      vertices[2*i+1        ] = CORR*(0.5f-sin);
+      vertices[2*i  +2*IVY_N] = CORR*(cos-0.5f);
+      vertices[2*i+1+2*IVY_N] = CORR*(sin-0.5f);
+      }
+
+    float[] bands0 = computeBands(+0.03f,35,0.5f,0.5f,5);
+    float[] bands1 = computeBands(-0.10f,45,0.5f,0.0f,2);
+
+    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesRexCorner()
+    {
+    MeshBase[] meshes = new MeshBase[2];
+
+    float F = REX_D*SQ2;
+    float G = (1-REX_D)*SQ2/2;
+    float H = 0.1f;
+    float J = +2*G/3 - H*G;
+
+    float[] vertices = { -F/2, -G/3, +F/2, -G/3, H*F/2, J, -H*F/2, J};
+
+    float[] bands0 = computeBands(+0.016f,10,G/3,0.5f,5);
+    float[] bands1 = computeBands(-0.230f,45,G/3,0.0f,2);
+
+    meshes[0] = new MeshPolygon(vertices,bands0,1,1);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesRexFace()
+    {
+    MeshBase[] meshes = new MeshBase[2];
+
+    float[] vertices = { -REX_D,0.0f, 0.0f, -REX_D, +REX_D, 0.0f, 0.0f, +REX_D};
+
+    float[] bands0 = computeBands(0.016f,10,REX_D/2,0.5f,5);
+    float[] bands1 = computeBands(0.000f,45,REX_D/2,0.0f,2);
+
+    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesRexEdge()
+    {
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    float E = 0.5f - REX_D;
+    float F = 0.5f;
+    float[] vertices0 = { -F,E/3, 0,-2*E/3, +F,E/3 };
+    float[] bands0 = computeBands(0.03f,27,F/3,0.8f,5);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 3);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    float G = (float)Math.sqrt(E*E+F*F);
+    float[] vertices1 = { -2*G/3, -E/3, G/3, -E/3, G/3, 2*E/3 };
+    float[] bands1 = computeBands(0.00f,45,G/3,0.2f,3);
+
+    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = meshes[2].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[2].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesKilominxCenter()
+    {
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    float X1= 0.5f*SIN54;
+    float Y1= 0.5f*SIN_HALFD;
+    float Y2= Y1 - 0.5f*COS54;
+    float H = 0.5f* SIN54 /COS54  ;
+    float X2= MINX_SC*H* SIN_HALFD;
+    float Y3= MINX_SC*H/(2*COS_HALFD);
+    float Y4= MINX_SC*H*(1/(2*COS_HALFD) - COS_HALFD);
+
+    float[] vertices0 = { -X1, Y2, 0, -Y1, X1, Y2, 0, Y1 };
+    float[] bands0 = computeBands(0.04f,17,0.3f,0.2f,5);
+    float[] vertices1 = { -X2, Y4, 0, -Y3, X2, Y4, 0, Y3 };
+    float[] bands1 = computeBands(0.00f, 0,0.25f,0.5f,2);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
+    meshes[0].setEffectAssociation(0, 1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0, 2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0, 4,0);
+    meshes[3] = new MeshPolygon(vertices1, bands1, 0, 0);
+    meshes[3].setEffectAssociation(0, 8,0);
+    meshes[4] = meshes[3].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[3].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesMinxCorner(int numLayers)
+    {
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    float Y = COS54/(2*SIN54);
+
+    float[] vertices0 = { -0.5f, 0.0f, 0.0f, -Y, 0.5f, 0.0f, 0.0f, Y };
+
+    int numBands0 = numLayers==3 ? 5 : 3;
+    int numBands1 = numLayers==3 ? 2 : 2;
+    float h       = numLayers==3 ? 0.04f : 0.03f;
+    int   e       = numLayers==3 ? 4 : 1;
+
+    float[] bands0 = computeBands(h    ,34,0.3f,0.2f, numBands0);
+    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f, numBands1);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
+    meshes[0].setEffectAssociation(0, 1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0, 2,0);
+    meshes[2] = meshes[0].copy(true);
+    meshes[2].setEffectAssociation(0, 4,0);
+    meshes[3] = new MeshPolygon(vertices0, bands1, 1, e);
+    meshes[3].setEffectAssociation(0, 8,0);
+    meshes[4] = meshes[3].copy(true);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[3].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesKilominxEdge(int numLayers, float width, float height)
+    {
+     MeshBase[] meshes = new MeshPolygon[6];
+
+    float D = height/COS18;
+    float W = D*SIN18;
+    float X1 = height/2;
+    float Y1 = width/2;
+    float Y2 = (width+W)/2;
+    float X3 = D*SIN54;
+    float Y3 = D*COS54;
+    float X4 = height*SIN_HALFD;
+    float Y4 = height*COS_HALFD;
+
+    float[] vertices0 = { -X1,-Y1, X1, -Y1, X1, Y1+W,-X1, Y1 };
+    float[] vertices1 = { -X1,-Y2, X1, -Y2, X1, Y2+W,-X1, Y2 };
+    float[] vertices2 = { -X3, 0.0f, 0.0f, -Y3, X3, 0.0f, 0.0f, Y3 };
+    float[] vertices3 = { -X4, 0.0f, 0.0f, -Y4, X4, 0.0f, 0.0f, Y4 };
+
+    int numBands0 = numLayers<=5 ? 5 : 3;
+    int numBands1 = numLayers<=5 ? 3 : 2;
+    float h       = numLayers<=5 ? 0.03f : 0.03f;
+
+    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
+    float[] bands1 = computeBands(0.01f,34,0.3f,0.2f,numBands1);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
+    meshes[0].setEffectAssociation(0, 1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0, 2,0);
+    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
+    meshes[2].setEffectAssociation(0, 4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0, 8,0);
+    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = new MeshPolygon(vertices3, bands1, 0, 0);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesMegaminxEdge(int numLayers, float width, float height)
+    {
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    float D = height/COS18;
+    float W = D*SIN18;
+
+    float Y1 = 0.5f*width;
+    float Y2 = 0.5f*width + W;
+    float Y3 = 0.5f*width + 2*W;
+    float X2 = D*SIN54;
+    float X1 = 0.5f*height;
+    float Y4 = D*COS54;
+
+    float[] vertices0 = { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
+    float[] vertices1 = { -X1, Y3, -X1, -Y3, X1, -Y2, X1, Y2 };
+    float[] vertices2 = { -X2, 0.0f, 0.0f, -Y4, X2, 0.0f, 0.0f, Y4 };
+
+    int numBands0 = numLayers==3 ? 5 : 3;
+    int numBands1 = numLayers==3 ? 2 : 2;
+    float h       = numLayers==3 ? 0.03f : 0.03f;
+
+    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
+    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f,numBands1);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
+    meshes[0].setEffectAssociation(0, 1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0, 2,0);
+    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
+    meshes[2].setEffectAssociation(0, 4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0, 8,0);
+    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[4].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createFacesMegaminxCenter(int numLayers)
+    {
+    MeshBase[] meshes = new MeshPolygon[2];
+
+    float R  = 0.5f;
+    float X1 = R*COS54;
+    float Y1 = R*SIN54;
+    float X2 = R*COS18;
+    float Y2 = R*SIN18;
+
+    float[] vertices0 = { -X1,+Y1, -X2,-Y2, 0.0f,-R, +X2,-Y2, +X1,+Y1 };
+
+    int numBands0 = numLayers==3 ? 4 : 3;
+    int numBands1 = numLayers==3 ? 2 : 2;
+    float h       = numLayers==3 ? 0.04f : 0.04f;
+
+    float[] bands0 = computeBands( h    ,45, R/3,0.2f, numBands0);
+    float[] bands1 = computeBands( 0.00f,34, R/3,0.2f, numBands1);
+
+    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = new MeshPolygon(vertices0, bands1, 0, 0);
+    meshes[1].setEffectAssociation(0,2,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float[] createVertices(int A, int B)
+    {
+    float E = 0.5f / Math.max(A,B);
+    return new float[] { -A*E,-B*E, +A*E,-B*E, +A*E,+B*E, -A*E,+B*E };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createCuboid(int[] dimensions)
+    {
+    int X = dimensions[0];
+    int Y = dimensions[1];
+    int Z = dimensions[2];
+
+    float[] verticesXY = createVertices(X,Y);
+    float[] verticesXZ = createVertices(X,Z);
+    float[] verticesYZ = createVertices(Z,Y);
+
+    float defHeight = 0.048f;
+
+    float[] bandsX = computeBands( defHeight/X,65,0.25f,0.5f,5);
+    float[] bandsY = computeBands( defHeight/Y,65,0.25f,0.5f,5);
+    float[] bandsZ = computeBands( defHeight/Z,65,0.25f,0.5f,5);
+
+    MeshBase[] meshes = new MeshPolygon[6];
+
+    meshes[0] = new MeshPolygon(verticesYZ,bandsX,1,2);
+    meshes[0].setEffectAssociation(0,1,0);
+    meshes[1] = meshes[0].copy(true);
+    meshes[1].setEffectAssociation(0,2,0);
+    meshes[2] = new MeshPolygon(verticesXZ,bandsY,1,2);
+    meshes[2].setEffectAssociation(0,4,0);
+    meshes[3] = meshes[2].copy(true);
+    meshes[3].setEffectAssociation(0,8,0);
+    meshes[4] = new MeshPolygon(verticesXY,bandsZ,1,2);
+    meshes[4].setEffectAssociation(0,16,0);
+    meshes[5] = meshes[4].copy(true);
+    meshes[5].setEffectAssociation(0,32,0);
+
+    return new MeshJoined(meshes);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// EFFECTS
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsCube()
+    {
+    Static3D axisY   = new Static3D(0,1,0);
+    Static3D axisX   = new Static3D(1,0,0);
+    Static3D center  = new Static3D(0,0,0);
+    Static1D angle90 = new Static1D(90);
+    Static1D angle180= new Static1D(180);
+    Static1D angle270= new Static1D(270);
+
+    VertexEffect[] effect = new VertexEffect[6];
+
+    effect[0] = new VertexEffectMove(new Static3D(0,0,+0.5f));
+    effect[1] = new VertexEffectRotate( angle180, axisX, center );
+    effect[2] = new VertexEffectRotate( angle90 , axisX, center );
+    effect[3] = new VertexEffectRotate( angle270, axisX, center );
+    effect[4] = new VertexEffectRotate( angle270, axisY, center );
+    effect[5] = new VertexEffectRotate( angle90 , axisY, center );
+
+    effect[0].setMeshAssociation(63,-1);  // all 6 sides
+    effect[1].setMeshAssociation(32,-1);  // back
+    effect[2].setMeshAssociation( 8,-1);  // bottom
+    effect[3].setMeshAssociation( 4,-1);  // top
+    effect[4].setMeshAssociation( 2,-1);  // left
+    effect[5].setMeshAssociation( 1,-1);  // right
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsSkewbCorner()
+    {
+    float E = 0.5f;
+
+    Static3D axisX  = new Static3D(1,0,0);
+    Static3D axisY  = new Static3D(0,1,0);
+    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
+    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
+    Static1D angle1 = new Static1D(+90);
+    Static1D angle2 = new Static1D(-90);
+    Static1D angle3 = new Static1D(-15);
+    Static1D angle4 = new Static1D((float)((180.0f/Math.PI)*Math.acos(SQ3/3)));
+    Static1D angle5 = new Static1D(120);
+    Static1D angle6 = new Static1D(240);
+    Static3D center1= new Static3D(0,0,0);
+    Static3D center2= new Static3D(-0.5f,-0.5f,-0.5f);
+    Static3D move1  = new Static3D(-E/4,-E/4,0);
+    Static3D move2  = new Static3D(-0.5f+SQ2/4,-0.5f+SQ6/8,-0.5f);
+
+    VertexEffect[] effect = new VertexEffect[10];
+
+    effect[0] = new VertexEffectMove(move1);
+    effect[1] = new VertexEffectScale(new Static3D(1,1,-1));
+    effect[2] = new VertexEffectRotate(angle1,axisX,center1);
+    effect[3] = new VertexEffectRotate(angle2,axisY,center1);
+    effect[4] = new VertexEffectMove(move2);
+    effect[5] = new VertexEffectRotate(angle1,axisX,center2);
+    effect[6] = new VertexEffectRotate(angle3,axisY,center2);
+    effect[7] = new VertexEffectRotate(angle4,axis0,center2);
+    effect[8] = new VertexEffectRotate(angle5,axis1,center2);
+    effect[9] = new VertexEffectRotate(angle6,axis1,center2);
+
+    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
+    effect[1].setMeshAssociation( 6,-1);  // meshes 1,2
+    effect[2].setMeshAssociation( 2,-1);  // mesh 1
+    effect[3].setMeshAssociation( 4,-1);  // mesh 2
+    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[7].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[8].setMeshAssociation(16,-1);  // mesh 4
+    effect[9].setMeshAssociation(32,-1);  // mesh 5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsSkewbFace()
+    {
+    Static3D center = new Static3D(0,0,0);
+    Static3D axisX  = new Static3D(1,0,0);
+    Static3D axisZ  = new Static3D(0,0,1);
+    float angle = -(float)((180.0f/Math.PI)*Math.acos(SQ3/3));
+
+    VertexEffect[] effect = new VertexEffect[6];
+
+    effect[0] = new VertexEffectRotate( new Static1D(angle), axisX, center);
+    effect[1] = new VertexEffectRotate( new Static1D(  135), axisZ, center);
+    effect[2] = new VertexEffectRotate( new Static1D(   45), axisZ, center);
+    effect[3] = new VertexEffectRotate( new Static1D(  -45), axisZ, center);
+    effect[4] = new VertexEffectRotate( new Static1D( -135), axisZ, center);
+    effect[5] = new VertexEffectMove( new Static3D(0,0,-0.5f) );
+
+    effect[0].setMeshAssociation(30,-1);  // meshes 1,2,3,4
+    effect[1].setMeshAssociation( 2,-1);  // mesh 1
+    effect[2].setMeshAssociation( 5,-1);  // meshes 0,2
+    effect[3].setMeshAssociation( 8,-1);  // mesh 3
+    effect[4].setMeshAssociation(16,-1);  // mesh 4
+    effect[5].setMeshAssociation(30,-1);  // meshes 1,2,3,4
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsOcta()
+    {
+    Static1D alpha = new Static1D((float)(-(180/Math.PI)*Math.asin(SQ3/3)));
+    Static1D angle1= new Static1D( 90);
+    Static1D angle2= new Static1D(180);
+    Static1D angle3= new Static1D(270);
+    Static3D move1 = new Static3D(0,SQ2/2-SQ3/3,0);
+    Static3D axisX = new Static3D(1,0,0);
+    Static3D axisY = new Static3D(0,1,0);
+    Static3D cent0 = new Static3D(0,0,0);
+    Static3D cent1 = new Static3D(0,SQ2/2,0);
+    Static3D flipY = new Static3D( 1,-1, 1);
+    Static3D scale = new Static3D( 1, 2*SQ3/3, 1);
+
+    VertexEffect[] effect = new VertexEffect[7];
+
+    effect[0] = new VertexEffectScale(scale);
+    effect[1] = new VertexEffectMove(move1);
+    effect[2] = new VertexEffectRotate(alpha , axisX, cent1);
+    effect[3] = new VertexEffectRotate(angle1, axisY, cent0);
+    effect[4] = new VertexEffectRotate(angle2, axisY, cent0);
+    effect[5] = new VertexEffectRotate(angle3, axisY, cent0);
+    effect[6] = new VertexEffectScale(flipY);
+
+    effect[3].setMeshAssociation ( 34,-1); // apply to meshes 1 & 5
+    effect[4].setMeshAssociation ( 68,-1); // apply to meshes 2 & 6
+    effect[5].setMeshAssociation (136,-1); // apply to meshes 3 & 7
+    effect[6].setMeshAssociation (240,-1); // apply to meshes 4,5,6,7
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsTetra()
+    {
+    Static3D flipZ = new Static3D( 1, 1,-1);
+    Static1D alpha = new Static1D((float)(-(180/Math.PI)*Math.asin(SQ3/3)));
+    Static1D angle1= new Static1D( 90);
+    Static1D angle2= new Static1D(180);
+    Static3D move1 = new Static3D(0,SQ2/4-SQ3/6,0);
+    Static3D axisX = new Static3D(1,0,0);
+    Static3D axisY = new Static3D(0,1,0);
+    Static3D axisZ = new Static3D(0,0,1);
+    Static3D cent0 = new Static3D(0,0,0);
+    Static3D cent1 = new Static3D(0,SQ2/4,0);
+    Static3D scale = new Static3D( 1, 2*SQ3/3, 1);
+
+    VertexEffect[] effect = new VertexEffect[7];
+
+    effect[0] = new VertexEffectScale(scale);
+    effect[1] = new VertexEffectRotate(angle2, axisZ, cent0);
+    effect[2] = new VertexEffectMove(move1);
+    effect[3] = new VertexEffectRotate(alpha , axisX, cent1);
+    effect[4] = new VertexEffectScale(flipZ);
+    effect[5] = new VertexEffectRotate(angle1, axisY, cent0);
+    effect[6] = new VertexEffectRotate(angle2, axisZ, cent0);
+
+    effect[4].setMeshAssociation(10,-1); // meshes 1 & 3
+    effect[5].setMeshAssociation(12,-1); // meshes 2 & 3
+    effect[6].setMeshAssociation(12,-1); // meshes 2 & 3
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsDino()
+    {
+    float E = 0.5f*SQ2;
+    float F = 0.5f;
+    final float ANGLE = (float)((180/Math.PI)*(Math.atan(SQ2)));
+
+    Static1D angle1 = new Static1D(-ANGLE);
+    Static1D angle2 = new Static1D(+ANGLE);
+    Static3D axisX  = new Static3D(1,0,0);
+    Static3D axisY  = new Static3D(0,1,0);
+    Static3D axisZ  = new Static3D(0,-1,1);
+    Static3D center0= new Static3D(0,0,0);
+    Static3D center1= new Static3D(0,-3*F,0);
+
+    VertexEffect[] effect = new VertexEffect[10];
+
+    effect[0] = new VertexEffectScale ( new Static3D(3,3,3) );
+    effect[1] = new VertexEffectMove  ( new Static3D(0,-F,0) );
+    effect[2] = new VertexEffectRotate( new Static1D(90), axisX, center0 );
+    effect[3] = new VertexEffectScale ( new Static3D(1,-1,1) );
+    effect[4] = new VertexEffectMove  ( new Static3D(3*E/2,E*(SQ3/2)-3*F,0) );
+    effect[5] = new VertexEffectRotate( new Static1D(+90), axisY, center1 );
+    effect[6] = new VertexEffectScale ( new Static3D(-1,1,1) );
+    effect[7] = new VertexEffectRotate( new Static1D( 45), axisX, center1 );
+    effect[8] = new VertexEffectRotate( angle1           , axisZ, center1 );
+    effect[9] = new VertexEffectRotate( angle2           , axisZ, center1 );
+
+    effect[0].setMeshAssociation(15,-1);  // apply to meshes 0,1,2,3
+    effect[1].setMeshAssociation( 3,-1);  // apply to meshes 0,1
+    effect[2].setMeshAssociation( 2,-1);  // apply to mesh 1
+    effect[3].setMeshAssociation( 2,-1);  // apply to mesh 1
+    effect[4].setMeshAssociation(12,-1);  // apply to meshes 2,3
+    effect[5].setMeshAssociation(12,-1);  // apply to meshes 2,3
+    effect[6].setMeshAssociation( 8,-1);  // apply to mesh 3
+    effect[7].setMeshAssociation(12,-1);  // apply to meshes 2,3
+    effect[8].setMeshAssociation( 4,-1);  // apply to mesh 2
+    effect[9].setMeshAssociation( 8,-1);  // apply to mesh 3
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsHelicopterCorner()
+    {
+    float E = 0.5f;
+
+    Static3D axisX  = new Static3D(1,0,0);
+    Static3D axisY  = new Static3D(0,1,0);
+    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
+    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
+    Static1D angle1 = new Static1D(+90);
+    Static1D angle2 = new Static1D(-90);
+    Static1D angle3 = new Static1D(-135);
+    Static1D angle4 = new Static1D(90);
+    Static1D angle5 = new Static1D(120);
+    Static1D angle6 = new Static1D(240);
+    Static3D center1= new Static3D(0,0,0);
+    Static3D center2= new Static3D(-0.25f,-0.25f,-0.25f);
+    Static3D move1  = new Static3D(-E/4,-E/4,0);
+    Static3D move2  = new Static3D(-0.25f,(-1.0f/6)-0.25f,-0.25f);
+
+    VertexEffect[] effect = new VertexEffect[10];
+
+    effect[0] = new VertexEffectMove(move1);
+    effect[1] = new VertexEffectScale(new Static3D(1,1,-1));
+    effect[2] = new VertexEffectRotate(angle1,axisX,center1);
+    effect[3] = new VertexEffectRotate(angle2,axisY,center1);
+    effect[4] = new VertexEffectMove(move2);
+    effect[5] = new VertexEffectRotate(angle1,axisX,center2);
+    effect[6] = new VertexEffectRotate(angle3,axisY,center2);
+    effect[7] = new VertexEffectRotate(angle4,axis0,center2);
+    effect[8] = new VertexEffectRotate(angle5,axis1,center2);
+    effect[9] = new VertexEffectRotate(angle6,axis1,center2);
+
+    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
+    effect[1].setMeshAssociation( 6,-1);  // meshes 1,2
+    effect[2].setMeshAssociation( 2,-1);  // mesh 1
+    effect[3].setMeshAssociation( 4,-1);  // mesh 2
+    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[7].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[8].setMeshAssociation(16,-1);  // mesh 4
+    effect[9].setMeshAssociation(32,-1);  // mesh 5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsHelicopterFace()
+    {
+    float E = 0.5f;
+    float F = SQ2/4;
+
+    Static3D move0  = new Static3D(-E/4, -E/4, 0);
+    Static3D move1  = new Static3D(-(SQ2/24)-E/2, -(SQ2/24)-E/2, 0);
+    Static3D move2  = new Static3D(-E/2, F/3, 0);
+    Static3D move3  = new Static3D(+E/2, F/3, 0);
+    Static3D move4  = new Static3D(+E/3,+E/3, 0);
+    Static1D angle1 = new Static1D(135);
+    Static1D angle2 = new Static1D(90);
+    Static1D angle3 = new Static1D(-90);
+    Static1D angle4 = new Static1D(-135);
+    Static3D axisX  = new Static3D(1,0,0);
+    Static3D axisY  = new Static3D(0,1,0);
+    Static3D axisZ  = new Static3D(0,0,1);
+    Static3D axis1  = new Static3D(1,-1,0);
+    Static3D center = new Static3D(0,0,0);
+    Static3D center1= new Static3D(-E/2,-E/2,0);
+
+    VertexEffect[] effect = new VertexEffect[10];
+
+    effect[0] = new VertexEffectMove(move0);
+    effect[1] = new VertexEffectRotate(angle1, axisZ, center);
+    effect[2] = new VertexEffectMove(move1);
+    effect[3] = new VertexEffectRotate(angle2, axis1, center1);
+    effect[4] = new VertexEffectMove(move2);
+    effect[5] = new VertexEffectMove(move3);
+    effect[6] = new VertexEffectRotate(angle3, axisZ, center);
+    effect[7] = new VertexEffectRotate(angle4, axisX, center);
+    effect[8] = new VertexEffectRotate(angle1, axisY, center);
+    effect[9] = new VertexEffectMove(move4);
+
+    effect[0].setMeshAssociation( 1,-1);  // mesh 0
+    effect[1].setMeshAssociation( 2,-1);  // mesh 1
+    effect[2].setMeshAssociation( 2,-1);  // mesh 1
+    effect[3].setMeshAssociation( 2,-1);  // mesh 1
+    effect[4].setMeshAssociation( 4,-1);  // mesh 2
+    effect[5].setMeshAssociation( 8,-1);  // mesh 3
+    effect[6].setMeshAssociation( 8,-1);  // mesh 3
+    effect[7].setMeshAssociation( 4,-1);  // mesh 2
+    effect[8].setMeshAssociation( 8,-1);  // mesh 3
+    effect[9].setMeshAssociation(15,-1);  // meshes 0,1,2,3
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsRediEdge()
+    {
+    Static3D move0 = new Static3D(0.0f, -0.5f, 0.0f);
+    Static3D move1 = new Static3D(0.25f, -0.25f, 0.0f);
+    Static3D move2 = new Static3D(0.5f, 0.0f, 0.0f);
+    Static3D move3 = new Static3D(0.0f, (SQ3-6)/8, (SQ3-6)/8);
+    Static3D flipZ = new Static3D(1,1,-1);
+    Static3D flipX = new Static3D(-1,1,1);
+    Static3D scale = new Static3D(2,2,2);
+    Static3D cent0 = new Static3D(0,0, 0);
+    Static3D cent1 = new Static3D(0,0, -1.5f);
+    Static3D axisX = new Static3D(1,0, 0);
+    Static3D axisY = new Static3D(0,1, 0);
+    Static3D axis  = new Static3D(0,SQ2/2,-SQ2/2);
+    Static1D angle1= new Static1D(90);
+    Static1D angle2= new Static1D(45);
+    Static1D angle3= new Static1D( (float)(180/Math.PI*Math.acos(SQ3/3)) );
+
+    VertexEffect[] effect = new VertexEffect[12];
+
+    effect[0] = new VertexEffectScale(scale);
+    effect[1] = new VertexEffectMove(move0);
+    effect[2] = new VertexEffectScale(flipZ);
+    effect[3] = new VertexEffectRotate(angle1,axisX,cent0);
+    effect[4] = new VertexEffectMove(move1);
+    effect[5] = new VertexEffectRotate(angle1,axisY,cent0);
+    effect[6] = new VertexEffectMove(move2);
+    effect[7] = new VertexEffectScale(flipX);
+    effect[8] = new VertexEffectRotate(angle2,axisX,cent0);
+    effect[9] = new VertexEffectMove(move3);
+    effect[10]= new VertexEffectRotate(angle3,axis ,cent1);
+    effect[11]= new VertexEffectScale(flipX);
+
+    effect[0].setMeshAssociation(63,-1);  // meshes 0,1,2,3,4,5
+    effect[1].setMeshAssociation( 3,-1);  // meshes 0,1
+    effect[2].setMeshAssociation( 2,-1);  // mesh 1
+    effect[3].setMeshAssociation( 2,-1);  // mesh 1
+    effect[4].setMeshAssociation(12,-1);  // meshes 2,3
+    effect[5].setMeshAssociation(60,-1);  // meshes 2,3,4,5
+    effect[6].setMeshAssociation(12,-1);  // meshes 2,3
+    effect[7].setMeshAssociation( 8,-1);  // mesh 3
+    effect[8].setMeshAssociation(48,-1);  // meshes 4,5
+    effect[9].setMeshAssociation(48,-1);  // meshes 4,5
+    effect[10].setMeshAssociation(48,-1); // meshes 4,5
+    effect[11].setMeshAssociation(32,-1); // mesh 5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsRediCorner()
+    {
+    Static3D axisY   = new Static3D(0,1,0);
+    Static3D axisX   = new Static3D(1,0,0);
+    Static3D axisZ   = new Static3D(0,0,1);
+    Static3D center  = new Static3D(0,0,0);
+    Static1D angle90 = new Static1D(90);
+    Static1D angle270= new Static1D(270);
+    Static1D angle45 = new Static1D(-45);
+    Static3D scale   = new Static3D(1.0f, SQ2, 1.0f);
+
+    VertexEffect[] effect = new VertexEffect[7];
+
+    effect[0] = new VertexEffectMove(new Static3D(0,0,+0.5f));
+    effect[1] = new VertexEffectRotate( angle270, axisX, center );
+    effect[2] = new VertexEffectRotate( angle90 , axisY, center );
+    effect[3] = new VertexEffectScale(scale);
+    effect[4] = new VertexEffectRotate( angle45 , axisX, center );
+    effect[5] = new VertexEffectRotate( angle90 , axisY, center );
+    effect[6] = new VertexEffectRotate( angle270, axisZ, center );
+
+    effect[0].setMeshAssociation( 7,-1);  // 0,1,2
+    effect[1].setMeshAssociation( 2,-1);  // 1
+    effect[2].setMeshAssociation( 4,-1);  // 2
+    effect[3].setMeshAssociation(56,-1);  // 3,4,5
+    effect[4].setMeshAssociation(56,-1);  // 3,4,5
+    effect[5].setMeshAssociation(16,-1);  // 4
+    effect[6].setMeshAssociation(32,-1);  // 5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsIvyCorner()
+    {
+    Static3D axisX  = new Static3D(1,0,0);
+    Static3D axisY  = new Static3D(0,1,0);
+    Static1D angle1 = new Static1D(+90);
+    Static1D angle2 = new Static1D(-90);
+    Static3D center = new Static3D(0,0,0);
+    Static3D move1  = new Static3D(IVY_M-0.5f,IVY_M-0.5f,0);
+
+    VertexEffect[] effect = new VertexEffect[5];
+
+    effect[0] = new VertexEffectScale(1/IVY_C);
+    effect[1] = new VertexEffectMove(move1);
+    effect[2] = new VertexEffectScale(new Static3D(1,1,-1));
+    effect[3] = new VertexEffectRotate(angle1,axisX,center);
+    effect[4] = new VertexEffectRotate(angle2,axisY,center);
+
+    effect[2].setMeshAssociation(54,-1);  // meshes 1,2,4,5
+    effect[3].setMeshAssociation(18,-1);  // meshes 1,4
+    effect[4].setMeshAssociation(36,-1);  // meshes 2,5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsRexEdge()
+    {
+    float E = 0.5f - REX_D;
+    float F = 0.5f;
+    float G = (float)Math.sqrt(E*E+F*F);
+    float A = (float)((180/Math.PI)*Math.asin(E/G));
+
+    Static3D move1 = new Static3D(    0.0f, -E/3, 0.0f);
+    Static3D move2 = new Static3D(2*G/3 -F, +E/3, 0.0f);
+
+    Static3D center0= new Static3D(0.0f, 0.0f, 0.0f);
+    Static3D center1= new Static3D(  -F, 0.0f, 0.0f);
+    Static3D center2= new Static3D(  +F, 0.0f, 0.0f);
+    Static3D axisX  = new Static3D(1.0f, 0.0f, 0.0f);
+    Static3D axisY  = new Static3D(0.0f, 1.0f, 0.0f);
+    Static3D axisZ  = new Static3D(0.0f, 0.0f, 1.0f);
+
+    Static1D angle180 = new Static1D(180);
+    Static1D angle90  = new Static1D( 90);
+    Static1D angle270 = new Static1D(270);
+    Static1D angle1   = new Static1D(+A);
+    Static1D angle2   = new Static1D(-A);
+
+    VertexEffect[] effect = new VertexEffect[12];
+
+    effect[0] = new VertexEffectMove(move1);
+    effect[1] = new VertexEffectMove(move2);
+    effect[2] = new VertexEffectRotate(  angle90, axisX, center0 );
+    effect[3] = new VertexEffectRotate( angle270, axisX, center0 );
+    effect[4] = new VertexEffectRotate( angle180, axisX, center0 );
+    effect[5] = new VertexEffectRotate( angle180, axisY, center0 );
+    effect[6] = new VertexEffectScale ( new Static3D(-1, 1, 1) );
+    effect[7] = new VertexEffectScale ( new Static3D( 1,-1, 1) );
+    effect[8] = new VertexEffectRotate(   angle1, axisY, center1);
+    effect[9] = new VertexEffectRotate(   angle2, axisY, center2);
+    effect[10]= new VertexEffectRotate(   angle2, axisZ, center1);
+    effect[11]= new VertexEffectRotate(   angle1, axisZ, center2);
+
+    effect[0].setMeshAssociation( 3,-1);  // meshes 0 & 1
+    effect[1].setMeshAssociation(60,-1);  // meshes 2,3,4,5
+    effect[2].setMeshAssociation( 2,-1);  // meshes 1
+    effect[3].setMeshAssociation(12,-1);  // meshes 2,3
+    effect[4].setMeshAssociation(48,-1);  // meshes 4,5
+    effect[5].setMeshAssociation(32,-1);  // mesh 5
+    effect[6].setMeshAssociation( 8,-1);  // apply to mesh 3
+    effect[7].setMeshAssociation( 2,-1);  // apply to mesh 1
+    effect[8].setMeshAssociation(16,-1);  // apply to mesh 4
+    effect[9].setMeshAssociation(32,-1);  // apply to mesh 5
+    effect[10].setMeshAssociation(4,-1);  // apply to mesh 2
+    effect[11].setMeshAssociation(8,-1);  // apply to mesh 3
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsRexCorner()
+    {
+    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
+    Static3D axisZ = new Static3D(0.0f, 0.0f, 1.0f);
+    Static1D angle = new Static1D(225);
+
+    VertexEffect[] effect = new VertexEffect[1];
+    effect[0] = new VertexEffectRotate(angle, axisZ, center);
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsKilominxCenter(float width)
+    {
+    VertexEffect[] effect = new VertexEffect[11];
+
+    float H = 0.5f*(SIN54/COS54);
+    float Y1= 0.5f*SIN_HALFD;
+    float Y2= H/(2*COS_HALFD);
+    float cos18 = (float)(Math.sqrt(1- SIN18 * SIN18));
+    float LEN   = (float)Math.sqrt(H*H/(COS_HALFD*COS_HALFD) + 0.25f);
+
+    Static3D axisZ = new Static3D(0.0f  , 0.0f , 1.0f);
+    Static3D axisY = new Static3D(0.0f  , 1.0f , 0.0f);
+    Static3D axisA = new Static3D(-SIN18, cos18, 0.0f);
+    Static3D axisC = new Static3D( H/LEN, -0.5f/LEN,-H* SIN_HALFD /(COS_HALFD*LEN));
+
+    Static3D move1 = new Static3D(0,-Y1,0);
+    Static3D move2 = new Static3D(0,-Y2,0);
+    Static3D move3 = new Static3D(0.5f*cos18,0.5f*SIN18,0);
+    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
+
+    Static1D angle1 = new Static1D(54);
+    Static1D angle2 = new Static1D(DIHEDRAL1/2+18);
+    Static1D angle3 = new Static1D(90);
+    Static1D angle4 = new Static1D(120);
+    Static1D angle5 = new Static1D(240);
+    Static1D angle6 = new Static1D(90-DIHEDRAL1/2);
+
+    effect[0] = new VertexEffectMove(move1);
+    effect[1] = new VertexEffectScale(1/MINX_SC);
+    effect[2] = new VertexEffectMove(move2);
+    effect[3] = new VertexEffectRotate(angle1, axisZ, center);
+    effect[4] = new VertexEffectRotate(angle2, axisZ, center);
+    effect[5] = new VertexEffectRotate(angle3, axisA, center);
+    effect[6] = new VertexEffectMove(move3);
+    effect[7] = new VertexEffectRotate(angle4, axisC, center);
+    effect[8] = new VertexEffectRotate(angle5, axisC, center);
+    effect[9] = new VertexEffectRotate(angle6, axisY, center);
+    effect[10]= new VertexEffectScale(width/0.5f);
+
+    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
+    effect[1].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[2].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[3].setMeshAssociation( 7,-1);  // meshes 0,1,2
+    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
+    effect[7].setMeshAssociation(18,-1);  // meshes 1,4
+    effect[8].setMeshAssociation(36,-1);  // meshes 2,5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsMinxCorner(float width)
+    {
+    VertexEffect[] effect = new VertexEffect[9];
+
+    float Y = COS54/(2*SIN54);
+
+    float sinA = (2*SIN54*SIN54-1)/COS54;
+    float cosA = (float)Math.sqrt(1-sinA*sinA);
+    float LEN  = 0.5f/SIN54;
+    float scale= width/LEN;
+
+    Static3D axisA = new Static3D( SIN54, COS54, 0.0f);
+    Static3D axisB = new Static3D(-SIN54, COS54, 0.0f);
+    Static3D axisX = new Static3D(  1.0f,  0.0f, 0.0f);
+
+    Static3D centerU = new Static3D( 0.0f, Y, 0.0f);
+    Static3D centerD = new Static3D( 0.0f,-Y, 0.0f);
+
+    Static3D move1= new Static3D(0.0f, -sinA*LEN, -cosA*LEN );
+    Static3D move2= new Static3D(0.0f, Y , 0.0f );
+
+    Static1D angleD = new Static1D(DIHEDRAL1);
+    Static1D angleE = new Static1D(360-DIHEDRAL1);
+    Static1D angleF = new Static1D(DIHEDRAL2);
+
+    effect[0] = new VertexEffectScale ( new Static3D( 1, 1,-1) );
+    effect[1] = new VertexEffectRotate(angleE, axisA, centerU);
+    effect[2] = new VertexEffectRotate(angleD, axisB, centerU);
+    effect[3] = new VertexEffectMove(move1);
+    effect[4] = new VertexEffectRotate(angleE, axisA, centerD);
+    effect[5] = new VertexEffectRotate(angleD, axisB, centerD);
+    effect[6] = new VertexEffectRotate(angleF, axisX, centerD);
+    effect[7] = new VertexEffectMove(move2);
+    effect[8] = new VertexEffectScale(scale);
+
+    effect[0].setMeshAssociation(  3,-1);  // meshes 0,1
+    effect[1].setMeshAssociation( 16,-1);  // mesh 4
+    effect[2].setMeshAssociation( 32,-1);  // mesh 5
+    effect[3].setMeshAssociation( 56,-1);  // meshes 3,4,5
+    effect[4].setMeshAssociation(  1,-1);  // mesh 0
+    effect[5].setMeshAssociation(  2,-1);  // mesh 1
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsKilominxEdge(float width, float height, boolean left)
+    {
+    VertexEffect[] effect = new VertexEffect[11 + (left ? 0:1)];
+
+    float D = height/COS18;
+    float W = D*SIN18;
+    float X1 = height/2;
+    float Y1 = width/2;
+    float Y2 = (width+W)/2;
+    float Y3 = D*COS54;
+    float Y4 = height*COS_HALFD;
+    float Z = 2*height*COS_HALFD;
+    float alpha = 90-DIHEDRAL1/2;
+
+    Static1D angle1 = new Static1D(alpha);
+    Static1D angle2 = new Static1D(180-alpha);
+    Static1D angle3 = new Static1D(DIHEDRAL2);
+    Static1D angle4 = new Static1D(90);
+
+    Static3D move1 = new Static3D(+X1,-Y1,0);
+    Static3D move2 = new Static3D(-X1,-Y2+W,-Z);
+    Static3D move3 = new Static3D(0,+Y3,0);
+    Static3D move4 = new Static3D(0,-Y4-width,0);
+    Static3D scale = new Static3D(+1,+1,-1);
+
+    Static3D axisXplus = new Static3D(+1, 0, 0);
+    Static3D axisYplus = new Static3D( 0,+1, 0);
+
+    Static3D center1= new Static3D( 0, 0, 0);
+    Static3D center2= new Static3D( 0, 0,-Z);
+    Static3D center3= new Static3D( 0,-width, 0);
+
+    effect[ 0] = new VertexEffectMove(move1);
+    effect[ 1] = new VertexEffectMove(move2);
+    effect[ 2] = new VertexEffectMove(move3);
+    effect[ 3] = new VertexEffectMove(move4);
+    effect[ 4] = new VertexEffectScale(scale);
+    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
+    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
+    effect[ 7] = new VertexEffectRotate(angle1, axisYplus , center2);
+    effect[ 8] = new VertexEffectRotate(angle2, axisYplus , center2);
+    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center1);
+    effect[10] = new VertexEffectRotate(angle4, axisXplus , center3);
+
+    if( !left )
+      {
+      Static3D scale1 = new Static3D(+1,-1,+1);
+      effect[11] = new VertexEffectScale(scale1);
+      }
+
+    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
+    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
+    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
+    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
+    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
+    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
+    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
+    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
+    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
+    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
+    effect[10].setMeshAssociation(32,-1);  // mesh 5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsMegaminxEdge(float width, float height)
+    {
+    VertexEffect[] effect = new VertexEffect[11];
+
+    float X = 0.5f*height;
+    float Y = height*(COS54/COS18) + width*0.5f;
+    float Z = 2*height*COS_HALFD;
+
+    float alpha = 90-DIHEDRAL1/2;
+    float beta  = DIHEDRAL2;
+
+    Static1D angle1 = new Static1D(alpha);
+    Static1D angle2 = new Static1D(180-alpha);
+    Static1D angle3 = new Static1D(beta);
+
+    Static3D move1 = new Static3D(X,0,0);
+    Static3D move2 = new Static3D(X,0,-Z);
+    Static3D move3 = new Static3D(0,+Y,0);
+    Static3D move4 = new Static3D(0,-Y,0);
+    Static3D scale = new Static3D(+1,+1,-1);
+
+    Static3D axisXplus = new Static3D(+1, 0, 0);
+    Static3D axisXminus= new Static3D(-1, 0, 0);
+    Static3D axisYplus = new Static3D( 0,+1, 0);
+    Static3D axisYminus= new Static3D( 0,-1, 0);
+
+    Static3D center1= new Static3D( 0, 0, 0);
+    Static3D center2= new Static3D( 0, 0,-Z);
+    Static3D center3= new Static3D( 0,+width*0.5f, 0);
+    Static3D center4= new Static3D( 0,-width*0.5f, 0);
+
+    effect[ 0] = new VertexEffectMove(move1);
+    effect[ 1] = new VertexEffectMove(move2);
+    effect[ 2] = new VertexEffectMove(move3);
+    effect[ 3] = new VertexEffectMove(move4);
+    effect[ 4] = new VertexEffectScale(scale);
+    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
+    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
+    effect[ 7] = new VertexEffectRotate(angle1, axisYminus, center2);
+    effect[ 8] = new VertexEffectRotate(angle2, axisYminus, center2);
+    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center3);
+    effect[10] = new VertexEffectRotate(angle3, axisXminus, center4);
+
+    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
+    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
+    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
+    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
+    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
+    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
+    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
+    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
+    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
+    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
+    effect[10].setMeshAssociation(32,-1);  // mesh 5
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createVertexEffectsMegaminxCenter(float width)
+    {
+    VertexEffect[] effect = new VertexEffect[2];
+
+    Static1D angle = new Static1D(DIHEDRAL2);
+    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
+    Static3D center= new Static3D( 0, 0, 0);
+
+    effect[0] = new VertexEffectScale(width/COS54);
+    effect[1] = new VertexEffectRotate(angle, axisX, center);
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  VertexEffect[] createCuboidEffects(int[] dimensions)
+    {
+    float X = dimensions[0];
+    float Y = dimensions[1];
+    float Z = dimensions[2];
+
+    float MAX_XY = Math.max(X,Y);
+    float MAX_XZ = Math.max(X,Z);
+    float MAX_YZ = Math.max(Z,Y);
+
+    Static1D angle = new Static1D(90);
+    Static3D move  = new Static3D( 0.0f, 0.0f, 0.5f);
+    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
+    Static3D axisY = new Static3D( 0.0f, 1.0f, 0.0f);
+    Static3D center= new Static3D( 0.0f, 0.0f, 0.0f);
+
+    Static3D scale3 = new Static3D(MAX_XY,MAX_XY,+Z);
+    Static3D scale4 = new Static3D(MAX_XY,MAX_XY,-Z);
+    Static3D scale5 = new Static3D(MAX_XZ,+Y,MAX_XZ);
+    Static3D scale6 = new Static3D(MAX_XZ,-Y,MAX_XZ);
+    Static3D scale7 = new Static3D(+X,MAX_YZ,MAX_YZ);
+    Static3D scale8 = new Static3D(-X,MAX_YZ,MAX_YZ);
+
+    VertexEffect[] effect = new VertexEffect[9];
+
+    effect[0] = new VertexEffectMove(move);
+    effect[1] = new VertexEffectRotate(angle, axisX, center);
+    effect[2] = new VertexEffectRotate(angle, axisY, center);
+    effect[3] = new VertexEffectScale(scale3);
+    effect[4] = new VertexEffectScale(scale4);
+    effect[5] = new VertexEffectScale(scale5);
+    effect[6] = new VertexEffectScale(scale6);
+    effect[7] = new VertexEffectScale(scale7);
+    effect[8] = new VertexEffectScale(scale8);
+
+    effect[1].setMeshAssociation(12,-1);  // meshes 2,3
+    effect[2].setMeshAssociation( 3,-1);  // meshes 0,1
+    effect[3].setMeshAssociation(16,-1);  // mesh 4
+    effect[4].setMeshAssociation(32,-1);  // mesh 5
+    effect[5].setMeshAssociation( 8,-1);  // mesh 3
+    effect[6].setMeshAssociation( 4,-1);  // mesh 2
+    effect[7].setMeshAssociation( 1,-1);  // mesh 0
+    effect[8].setMeshAssociation( 2,-1);  // mesh 1
+
+    return effect;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OBJECTS
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// CUBE
+
+  public MeshBase createCubeMesh(int index)
+    {
+    MeshBase mesh = createFacesCube(index);
+    VertexEffect[] effects = createVertexEffectsCube();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D roundingCenter  = new Static3D(0,0,0);
+    Static3D[] vertices = new Static3D[8];
+    vertices[0] = new Static3D(+0.5f,+0.5f,+0.5f);
+    vertices[1] = new Static3D(+0.5f,+0.5f,-0.5f);
+    vertices[2] = new Static3D(+0.5f,-0.5f,+0.5f);
+    vertices[3] = new Static3D(+0.5f,-0.5f,-0.5f);
+    vertices[4] = new Static3D(-0.5f,+0.5f,+0.5f);
+    vertices[5] = new Static3D(-0.5f,+0.5f,-0.5f);
+    vertices[6] = new Static3D(-0.5f,-0.5f,+0.5f);
+    vertices[7] = new Static3D(-0.5f,-0.5f,-0.5f);
+
+    roundCorners(mesh,roundingCenter,vertices,0.06f,0.12f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// SKEWB
+
+  public MeshBase createSkewbCornerMesh()
+    {
+    MeshBase mesh = createFacesSkewbCorner();
+    VertexEffect[] effects = createVertexEffectsSkewbCorner();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    float E = 0.5f;
+    Static3D roundingCenter = new Static3D(-E/2,-E/2,-E/2);
+
+    Static3D[] verticesType1 = new Static3D[1];
+    verticesType1[0] = new Static3D(0.0f,0.0f,0.0f);
+    roundCorners(mesh,roundingCenter,verticesType1,0.08f,0.15f);
+
+    Static3D[] verticesType2 = new Static3D[3];
+    verticesType2[0] = new Static3D(-E, 0, 0);
+    verticesType2[1] = new Static3D( 0,-E, 0);
+    verticesType2[2] = new Static3D( 0, 0,-E);
+    roundCorners(mesh,roundingCenter,verticesType2,0.08f,0.20f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createSkewbFaceMesh()
+    {
+    MeshBase mesh = createFacesSkewbFace();
+    VertexEffect[] effects = createVertexEffectsSkewbFace();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D roundingCenter = new Static3D(0,0,-0.2f);
+    float E = SQ2/4;
+    Static3D[] vertices = new Static3D[4];
+    vertices[0] = new Static3D(-E*SQ2,      0, 0);
+    vertices[1] = new Static3D(+E*SQ2,      0, 0);
+    vertices[2] = new Static3D(     0, -E*SQ2, 0);
+    vertices[3] = new Static3D(     0, +E*SQ2, 0);
+    roundCorners(mesh,roundingCenter,vertices,0.06f,0.10f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// SKEWB DIAMOND / PYRAMINX
+
+  public MeshBase createOctaMesh()
+    {
+    MeshBase mesh = createFacesOcta();
+    VertexEffect[] effects = createVertexEffectsOcta();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D roundingCenter = new Static3D(0,0,0);
+    Static3D[] vertices = new Static3D[6];
+    vertices[0] = new Static3D(    0, SQ2/2,    0 );
+    vertices[1] = new Static3D( 0.5f,     0, 0.5f );
+    vertices[2] = new Static3D(-0.5f,     0, 0.5f );
+    vertices[3] = new Static3D(    0,-SQ2/2,    0 );
+    vertices[4] = new Static3D(-0.5f,     0,-0.5f );
+    vertices[5] = new Static3D( 0.5f,     0,-0.5f );
+
+    roundCorners(mesh,roundingCenter,vertices,0.06f,0.20f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createTetraMesh()
+    {
+    MeshBase mesh = createFacesTetra();
+    VertexEffect[] effects = createVertexEffectsTetra();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D roundingCenter = new Static3D(0,0,0);
+    Static3D[] verticesRound = new Static3D[4];
+    verticesRound[0] = new Static3D(-0.5f,+SQ2/4,   0 );
+    verticesRound[1] = new Static3D(+0.5f,+SQ2/4,   0 );
+    verticesRound[2] = new Static3D(    0,-SQ2/4,+0.5f);
+    verticesRound[3] = new Static3D(    0,-SQ2/4,-0.5f);
+    roundCorners(mesh,roundingCenter,verticesRound,0.08f,0.15f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// DINO
+
+  public MeshBase createDinoMesh()
+    {
+    MeshBase mesh = createFacesDino();
+    VertexEffect[] effects = createVertexEffectsDino();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    float F = 0.5f;
+    Static3D roundingCenter = new Static3D(0.0f, -1.5f*F, -1.5f*F);
+    Static3D[] verticesRound = new Static3D[4];
+    verticesRound[0] = new Static3D(     0,-3*F,    0 );
+    verticesRound[1] = new Static3D(     0,   0, -3*F );
+    verticesRound[2] = new Static3D(  -3*F,   0,    0 );
+    verticesRound[3] = new Static3D(  +3*F,   0,    0 );
+    roundCorners(mesh,roundingCenter,verticesRound,0.10f,0.40f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Helicopter
+
+  public MeshBase createHelicopterCornerMesh()
+    {
+    MeshBase mesh = createFacesHelicopterCorner();
+    VertexEffect[] effects = createVertexEffectsHelicopterCorner();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    float E = 0.5f;
+    Static3D roundingCenter = new Static3D(-E/2,-E/2,-E/2);
+
+    Static3D[] verticesType1 = new Static3D[1];
+    verticesType1[0] = new Static3D(0.0f,0.0f,0.0f);
+    roundCorners(mesh,roundingCenter,verticesType1,0.08f,0.15f);
+
+    Static3D[] verticesType2 = new Static3D[3];
+    verticesType2[0] = new Static3D(-E, 0, 0);
+    verticesType2[1] = new Static3D( 0,-E, 0);
+    verticesType2[2] = new Static3D( 0, 0,-E);
+    roundCorners(mesh,roundingCenter,verticesType2,0.08f,0.20f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createHelicopterFaceMesh()
+    {
+    MeshBase mesh = createFacesHelicopterFace();
+    VertexEffect[] effects = createVertexEffectsHelicopterFace();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    float E = 0.5f;
+    Static3D roundingCenter = new Static3D(-E/2 + E/3,-E/2 + E/3,-E/2);
+
+    Static3D[] verticesType1 = new Static3D[1];
+    verticesType1[0] = new Static3D(E/3,E/3,0.0f);
+    roundCorners(mesh,roundingCenter,verticesType1,0.06f,0.15f);
+
+    Static3D[] verticesType2 = new Static3D[2];
+    verticesType2[0] = new Static3D(-E+E/3, E/3  , 0);
+    verticesType2[1] = new Static3D( E/3  ,-E+E/3, 0);
+    roundCorners(mesh,roundingCenter,verticesType2,0.08f,0.20f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Redi cube
+
+  public MeshBase createRediEdgeMesh()
+    {
+    MeshBase mesh = createFacesRediEdge();
+    VertexEffect[] effects = createVertexEffectsRediEdge();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D center = new Static3D(0.0f,-0.75f,-0.75f);
+    Static3D[] vertices = new Static3D[2];
+    vertices[0] = new Static3D( 0.5f, 0.0f, 0.0f);
+    vertices[1] = new Static3D(-0.5f, 0.0f, 0.0f);
+    roundCorners(mesh,center,vertices,0.06f,0.20f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createRediCornerMesh()
+    {
+    MeshBase mesh = createFacesRediCorner();
+    VertexEffect[] effects = createVertexEffectsRediCorner();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D center = new Static3D(0,0,0);
+    Static3D[] vertices = new Static3D[8];
+    vertices[0] = new Static3D(+0.5f,+0.5f,+0.5f);
+    vertices[1] = new Static3D(+0.5f,+0.5f,-0.5f);
+    vertices[2] = new Static3D(+0.5f,-0.5f,+0.5f);
+    vertices[3] = new Static3D(+0.5f,-0.5f,-0.5f);
+    vertices[4] = new Static3D(-0.5f,+0.5f,+0.5f);
+    vertices[5] = new Static3D(-0.5f,+0.5f,-0.5f);
+    vertices[6] = new Static3D(-0.5f,-0.5f,+0.5f);
+    vertices[7] = new Static3D(-0.5f,-0.5f,-0.5f);
+
+    roundCorners(mesh,center,vertices,0.06f,0.12f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createIvyCornerMesh()
+    {
+    MeshBase mesh = createFacesIvyCorner();
+    VertexEffect[] effects = createVertexEffectsIvyCorner();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D center = new Static3D(-0.5f,-0.5f,-0.5f);
+    Static3D[] vertices = new Static3D[4];
+    vertices[0] = new Static3D(+0.0f,+0.0f,+0.0f);
+    vertices[1] = new Static3D(-1.0f,+0.0f,+0.0f);
+    vertices[2] = new Static3D(+0.0f,-1.0f,+0.0f);
+    vertices[3] = new Static3D(+0.0f,+0.0f,-1.0f);
+
+    roundCorners(mesh,center,vertices,0.03f,0.10f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createIvyFaceMesh()
+    {
+    MeshBase mesh = createFacesIvyFace();
+
+    Static3D center = new Static3D(-0.0f,-0.0f,-0.5f);
+    Static3D[] vertices = new Static3D[2];
+    vertices[0] = new Static3D(-0.5f,+0.5f,+0.0f);
+    vertices[1] = new Static3D(+0.5f,-0.5f,+0.0f);
+
+    roundCorners(mesh,center,vertices,0.03f,0.10f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createRexCornerMesh()
+    {
+    MeshBase mesh = createFacesRexCorner();
+    VertexEffect[] effects = createVertexEffectsRexCorner();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    final float G = (1-REX_D)/3;
+    Static3D center = new Static3D(0.0f,0.0f,-G*SQ2/2);
+    Static3D[] vertices = new Static3D[1];
+    vertices[0] = new Static3D(+G,-G,+0.0f);
+    roundCorners(mesh,center,vertices,0.10f,0.10f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createRexFaceMesh()
+    {
+    MeshBase mesh = createFacesRexFace();
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createRexEdgeMesh()
+    {
+    MeshBase mesh = createFacesRexEdge();
+    VertexEffect[] effects = createVertexEffectsRexEdge();
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    Static3D center = new Static3D(0.0f,-0.5f,-0.5f);
+    Static3D[] vertices = new Static3D[2];
+    vertices[0] = new Static3D(+0.5f,+0.0f,+0.0f);
+    vertices[1] = new Static3D(-0.5f,+0.0f,+0.0f);
+    roundCorners(mesh,center,vertices,0.06f,0.10f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createKilominxCenterMesh(float width)
+    {
+    MeshBase mesh = createFacesKilominxCenter();
+    VertexEffect[] effects = createVertexEffectsKilominxCenter(width);
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    float A = (2*SQ3/3)* SIN54;
+    float B = 0.4f;
+    float X = SIN_HALFD * SIN54 *COS54  ;
+    float Y = SIN54 * SIN54 - 0.5f;
+    float Z = COS_HALFD* SIN54 *COS54  ;
+
+    Static3D center = new Static3D(0.0f, -(float)Math.sqrt(1-A*A)*B,-A*B);
+
+    Static3D[] vertices = new Static3D[4];
+    vertices[0] = new Static3D( 0.0f, 0.0f, 0.0f);
+    vertices[1] = new Static3D( 0.0f,-0.5f, 0.0f);
+    vertices[2] = new Static3D(-X   , Y   ,-Z   );
+    vertices[3] = new Static3D(+X   , Y   ,-Z   );
+
+    roundCorners(mesh,center,vertices,0.03f,0.10f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
+// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
+
+  public MeshBase createKilominxEdgeMesh(int numLayers, float width, float height, boolean left)
+    {
+    MeshBase mesh = createFacesKilominxEdge(numLayers,width,height);
+    VertexEffect[] effects = createVertexEffectsKilominxEdge(width,height,left);
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+// round...
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createMinxCornerMesh(int numLayers, float width)
+    {
+    MeshBase mesh = createFacesMinxCorner(numLayers);
+    VertexEffect[] effects = createVertexEffectsMinxCorner(width);
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    float A = (2*SQ3/3)* SIN54;
+    float B = 0.4f;
+/*
+    float X = SIN_HALFD* SIN54 * COS54;
+    float Y = SIN54 * SIN54 - 0.5f;
+    float Z = COS_HALFD* SIN54 * COS54;
+    float S = 2*width;
+*/
+    Static3D center = new Static3D(0.0f, -(float)Math.sqrt(1-A*A)*B,-A*B);
+    Static3D[] vertices = new Static3D[1];
+    vertices[0] = new Static3D( 0.0f, 0.0f  , 0.0f);
+/*
+    vertices[1] = new Static3D( 0.0f,-0.5f*S, 0.0f);
+    vertices[2] = new Static3D(-X*S , Y*S   ,-Z*S );
+    vertices[3] = new Static3D(+X*S , Y*S   ,-Z*S );
+*/
+    roundCorners(mesh,center,vertices,0.04f,0.10f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
+// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
+
+  public MeshBase createMegaminxEdgeMesh(int numLayers, float width, float height)
+    {
+    MeshBase mesh = createFacesMegaminxEdge(numLayers,width,height);
+    VertexEffect[] effects = createVertexEffectsMegaminxEdge(width,height);
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createMegaminxCenterMesh(int numLayers, float width)
+    {
+    MeshBase mesh = createFacesMegaminxCenter(numLayers);
+    VertexEffect[] effects = createVertexEffectsMegaminxCenter(width);
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public MeshBase createCuboidMesh(int[] dimensions)
+    {
+    MeshBase mesh = createCuboid(dimensions);
+    VertexEffect[] effects = createCuboidEffects(dimensions);
+    for( VertexEffect effect : effects ) mesh.apply(effect);
+
+    int X = dimensions[0];
+    int Y = dimensions[1];
+    int Z = dimensions[2];
+
+    float strength = 0.04f;
+    float radius   = 0.15f;
+
+    Static3D[] vertices = new Static3D[1];
+    Static3D center;
+
+    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,+0.5f*Z);
+    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,-0.5f*Z);
+    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,+0.5f*Z);
+    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,-0.5f*Z);
+    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,+0.5f*Z);
+    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,-0.5f*Z);
+    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,+0.5f*Z);
+    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,-0.5f*Z);
+    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
+    roundCorners(mesh, center, vertices, strength, radius);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+  }
diff --git a/src/main/java/org/distorted/helpers/FactorySticker.java b/src/main/java/org/distorted/helpers/FactorySticker.java
new file mode 100644
index 00000000..53d780e6
--- /dev/null
+++ b/src/main/java/org/distorted/helpers/FactorySticker.java
@@ -0,0 +1,351 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is free software: you can redistribute it and/or modify                            //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Magic Cube is distributed in the hope that it will be useful,                                 //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.helpers;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import static org.distorted.objects.TwistyObject.TEXTURE_HEIGHT;
+import static org.distorted.objects.TwistyObject.COLOR_BLACK;
+import static org.distorted.helpers.FactoryCubit.IVY_D;
+import static org.distorted.helpers.FactoryCubit.IVY_C;
+import static org.distorted.helpers.FactoryCubit.IVY_M;
+import static org.distorted.helpers.FactoryCubit.REX_D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class FactorySticker
+  {
+  private static final float SQ2 = (float)Math.sqrt(2);
+  private static final float REX_X,REX_R,REX_B,REX_A, REX_P, REX_T, REX_C, REX_S;
+  private static FactorySticker mThis;
+
+  static
+    {
+    float F = REX_D*SQ2;
+    float G = (1-REX_D)*SQ2/2;
+
+    REX_X = (0.5f-REX_D*REX_D)/(2*REX_D);
+    REX_R = (float)Math.sqrt(2*REX_X*REX_X+0.5f);
+    REX_B = (float) ((180/Math.PI)*(2*Math.asin( Math.sqrt(REX_D*REX_D-REX_D+0.5f) / (2*REX_R) )));
+    REX_A = (float) ((180/Math.PI)*Math.acos(REX_X/REX_R)) - 45;
+    REX_P = 45 + REX_B/2 + REX_A;
+    REX_T = (float) ( Math.tan( (Math.PI/180)*(45-REX_P/2) ) );
+    REX_C = (float)(REX_R/Math.cos((Math.PI/180)*REX_B/2) );
+    REX_S = (float)(1/Math.sqrt(1+4*G*G/(F*F)));
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private FactorySticker()
+    {
+
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static FactorySticker getInstance()
+    {
+    if( mThis==null ) mThis = new FactorySticker();
+
+    return mThis;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float computeAngle(float dx, float dy)
+    {
+    float PI = (float)Math.PI;
+    double angle = Math.atan2(dy,dx);
+    float ret = (float)(3*PI/2-angle);
+
+    if( ret>2*PI ) ret-= 2*PI;
+
+    return ret;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void drawCurrVertex(Canvas canvas, Paint paint, int left, int top, float r, float stroke, float pX, float pY, float cX, float cY, float nX, float nY)
+    {
+    pX = (0.5f+pX)*TEXTURE_HEIGHT;
+    pY = (0.5f-pY)*TEXTURE_HEIGHT;
+    cX = (0.5f+cX)*TEXTURE_HEIGHT;
+    cY = (0.5f-cY)*TEXTURE_HEIGHT;
+    nX = (0.5f+nX)*TEXTURE_HEIGHT;
+    nY = (0.5f-nY)*TEXTURE_HEIGHT;
+
+    canvas.drawLine(left+pX,top+pY,left+cX,top+cY,paint);
+
+    float aX = pX-cX;
+    float aY = pY-cY;
+    float bX = cX-nX;
+    float bY = cY-nY;
+
+    float aLen = (float)Math.sqrt(aX*aX+aY*aY);
+    float bLen = (float)Math.sqrt(bX*bX+bY*bY);
+
+    aX /= aLen;
+    aY /= aLen;
+    bX /= bLen;
+    bY /= bLen;
+
+    float sX = (aX-bX)/2;
+    float sY = (aY-bY)/2;
+    float sLen = (float)Math.sqrt(sX*sX+sY*sY);
+    sX /= sLen;
+    sY /= sLen;
+
+    float startAngle = computeAngle(bX,-bY);
+    float endAngle   = computeAngle(aX,-aY);
+    float sweepAngle = endAngle-startAngle;
+    if( sweepAngle<0 ) sweepAngle += 2*Math.PI;
+
+    float R = r*TEXTURE_HEIGHT+stroke/2;
+
+    float A = (float)(R/(Math.cos(sweepAngle/2)));
+
+    float rX = cX + A*sX;
+    float rY = cY + A*sY;
+
+    startAngle *= 180/(Math.PI);
+    sweepAngle *= 180/(Math.PI);
+
+    canvas.drawArc( left+rX-R, top+rY-R, left+rX+R, top+rY+R, startAngle, sweepAngle, false, paint);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC
+
+  public void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int top, float[] vertices, float stroke, int color, float radius)
+    {
+    stroke *= TEXTURE_HEIGHT;
+
+    paint.setAntiAlias(true);
+    paint.setStrokeWidth(stroke);
+    paint.setColor(color);
+    paint.setStyle(Paint.Style.FILL);
+
+    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
+
+    paint.setColor(COLOR_BLACK);
+    paint.setStyle(Paint.Style.STROKE);
+
+    int length = vertices.length;
+    int numVertices = length/2;
+
+    float prevX = vertices[length-2];
+    float prevY = vertices[length-1];
+    float currX = vertices[0];
+    float currY = vertices[1];
+    float nextX = vertices[2];
+    float nextY = vertices[3];
+
+    for(int vert=0; vert<numVertices; vert++)
+      {
+      drawCurrVertex(canvas, paint, left, top, radius, stroke, prevX,prevY,currX,currY,nextX,nextY);
+
+      prevX = currX;
+      prevY = currY;
+      currX = nextX;
+      currY = nextY;
+
+      if( 2*(vert+2)+1 < length )
+        {
+        nextX = vertices[2*(vert+2)  ];
+        nextY = vertices[2*(vert+2)+1];
+        }
+      else
+        {
+        nextX = vertices[0];
+        nextY = vertices[1];
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void drawIvyCornerSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius)
+    {
+    paint.setAntiAlias(true);
+    paint.setColor(color);
+    paint.setStyle(Paint.Style.FILL);
+    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
+
+    paint.setColor(COLOR_BLACK);
+    paint.setStyle(Paint.Style.STROKE);
+    paint.setStrokeWidth(IVY_C*stroke*TEXTURE_HEIGHT);
+
+    float tmp1 = ((IVY_D-0.5f)-IVY_M)*IVY_C;
+    float cx1 = TEXTURE_HEIGHT*(tmp1 + 0.5f);
+    float cy1 = TEXTURE_HEIGHT*(0.5f - tmp1);
+
+    float halfL1 = IVY_C*TEXTURE_HEIGHT*(1.0f-2*IVY_D);
+
+    canvas.drawArc( left+cx1-halfL1, top+cy1-halfL1, left+cx1+halfL1, top+cy1+halfL1, 270, 90, false, paint);
+
+    float tmp2 = (+0.5f-IVY_M)*IVY_C;
+    float tmp3 = (-0.5f-IVY_M)*IVY_C;
+
+    float x0 = TEXTURE_HEIGHT*(+tmp2 + 0.5f);
+    float y0 = TEXTURE_HEIGHT*(-tmp3 + 0.5f);
+    float x1 = TEXTURE_HEIGHT*(+tmp2 + 0.5f);
+    float y1 = TEXTURE_HEIGHT*(-tmp2 + 0.5f);
+    float x2 = TEXTURE_HEIGHT*(+tmp3 + 0.5f);
+    float y2 = TEXTURE_HEIGHT*(-tmp2 + 0.5f);
+
+    canvas.drawLine(left+x0,top+y0,left+x1,top+y1,paint);
+    canvas.drawLine(left+x1,top+y1,left+x2,top+y2,paint);
+
+    float tmp4 = ((0.5f-stroke/2-radius/2)-IVY_M)*IVY_C;
+    float cx2 = TEXTURE_HEIGHT*(tmp4 + 0.5f);
+    float cy2 = TEXTURE_HEIGHT*(0.5f - tmp4);
+
+    float halfL2 = IVY_C*TEXTURE_HEIGHT*radius;
+
+    paint.setStrokeWidth(IVY_C*radius*TEXTURE_HEIGHT);
+    canvas.drawArc( left+cx2-halfL2, top+cy2-halfL2, left+cx2+halfL2, top+cy2+halfL2, 270, 90, false, paint);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void drawIvyCenterSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius)
+    {
+    paint.setAntiAlias(true);
+    paint.setColor(color);
+    paint.setStyle(Paint.Style.FILL);
+    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
+
+    paint.setColor(COLOR_BLACK);
+    paint.setStyle(Paint.Style.STROKE);
+    paint.setStrokeWidth(stroke*TEXTURE_HEIGHT);
+
+    float cx1 = TEXTURE_HEIGHT*IVY_D;
+    float cy1 = TEXTURE_HEIGHT*(1-IVY_D);
+    float cx2 = TEXTURE_HEIGHT*(1.0f-IVY_D);
+    float cy2 = TEXTURE_HEIGHT*IVY_D;
+
+    float halfL = TEXTURE_HEIGHT*(1.0f - 2*IVY_D);
+
+    canvas.drawArc( left+cx1-halfL, top+cy1-halfL, left+cx1+halfL, top+cy1+halfL, 270, 90, false, paint);
+    canvas.drawArc( left+cx2-halfL, top+cy2-halfL, left+cx2+halfL, top+cy2+halfL,  90, 90, false, paint);
+
+    float tmp = TEXTURE_HEIGHT*(IVY_D+stroke*0.5f+radius*0.5f);
+    float cx3 = tmp;
+    float cy3 = tmp;
+    float cx4 = TEXTURE_HEIGHT - cx3;
+    float cy4 = TEXTURE_HEIGHT - cy3;
+    float halfR = TEXTURE_HEIGHT*radius;
+
+    paint.setStrokeWidth(radius*TEXTURE_HEIGHT);
+    canvas.drawArc( left+cx3-halfR, top+cy3-halfR, left+cx3+halfR, top+cy3+halfR, 180, 90, false, paint);
+    canvas.drawArc( left+cx4-halfR, top+cy4-halfR, left+cx4+halfR, top+cy4+halfR,   0, 90, false, paint);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void drawRexCornerSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius1, float radius2)
+    {
+    paint.setColor(color);
+    paint.setStyle(Paint.Style.FILL);
+    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
+
+    paint.setColor(COLOR_BLACK);
+    paint.setStyle(Paint.Style.STROKE);
+    paint.setStrokeWidth(stroke*TEXTURE_HEIGHT);
+
+    float F = REX_D*SQ2;
+    float G = (1-REX_D)*SQ2/2;
+
+    float cx1 = left + (0.5f-F/2)*TEXTURE_HEIGHT;
+    float cx2 = left + (0.5f+F/2)*TEXTURE_HEIGHT;
+    float cy  = top  + (0.5f+G/3)*TEXTURE_HEIGHT;
+
+    canvas.drawLine(cx1, cy, cx2, cy, paint);
+
+    float X   = REX_C-F/2;
+    float R1  = TEXTURE_HEIGHT*(REX_R + 0.5f*stroke);
+    float cx3 = left + (0.5f-X)*TEXTURE_HEIGHT;
+    float cx4 = left + (0.5f+X)*TEXTURE_HEIGHT;
+
+    canvas.drawArc( cx3-R1, cy-R1, cx3+R1, cy+R1, 360-REX_B/2, REX_B/2, false ,paint);
+    canvas.drawArc( cx4-R1, cy-R1, cx4+R1, cy+R1, 180        , REX_B/2, false ,paint);
+
+    float cx5 = left + (0.5f+F/2-radius2)*TEXTURE_HEIGHT;
+    float cx6 = left + (0.5f-F/2+radius2)*TEXTURE_HEIGHT;
+    float cy1 = top  + (0.5f+G/3-radius2)*TEXTURE_HEIGHT;
+    float R2  = TEXTURE_HEIGHT*radius2;
+
+    canvas.drawArc( cx5-R2, cy1-R2, cx5+R2, cy1+R2,  0, 90, false ,paint);
+    canvas.drawArc( cx6-R2, cy1-R2, cx6+R2, cy1+R2, 90, 90, false ,paint);
+
+    float cx7 = left + 0.5f*TEXTURE_HEIGHT;
+    float cy2 = top  + (0.5f-2*G/3 + radius1/REX_S)*TEXTURE_HEIGHT;
+    float R3  = TEXTURE_HEIGHT*(radius1 + 0.5f*stroke);
+    canvas.drawArc( cx7-R3, cy2-R3, cx7+R3, cy2+R3, 270-(90-REX_B/2), 180-REX_B, false ,paint);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void drawRexEdgeSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius)
+    {
+    paint.setColor(color);
+    paint.setStyle(Paint.Style.FILL);
+    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
+
+    paint.setColor(COLOR_BLACK);
+    paint.setStyle(Paint.Style.STROKE);
+    paint.setStrokeWidth(stroke*TEXTURE_HEIGHT);
+
+    final float D = ( 0.5f - (0.5f-REX_D)/3);
+    float cx1 = left+ TEXTURE_HEIGHT*(0.5f-REX_X);
+    float cy1 = top + TEXTURE_HEIGHT*(0.5f+REX_X+D);
+    float cx2 = left+ TEXTURE_HEIGHT*(0.5f+REX_X);
+    float R1  = TEXTURE_HEIGHT*REX_R;
+
+    canvas.drawArc( cx1-R1, cy1-R1, cx1+R1, cy1+R1, 315-REX_A-REX_B, REX_B, false ,paint);
+    canvas.drawArc( cx2-R1, cy1-R1, cx2+R1, cy1+R1, 225+REX_A      , REX_B, false ,paint);
+
+    float CORR_Y = radius/12;
+    float CORR_A = 10;
+    float sin = (float)Math.sin(Math.PI*REX_P/180);
+    float cx = left + 0.5f*TEXTURE_HEIGHT;
+    float cy = top  + ( 0.5f + 2*(0.5f-REX_D)/3 -CORR_Y -radius/sin )*TEXTURE_HEIGHT;
+    float R2  = TEXTURE_HEIGHT*radius;
+
+    canvas.drawArc( cx-R2, cy-R2, cx+R2, cy+R2, 90-(REX_P-CORR_A), 2*(REX_P-CORR_A), false ,paint);
+
+    float F = 0.1f;
+    float G = 0.6f;
+    float R3  = TEXTURE_HEIGHT*radius*G*0.9f;
+    float X = G*radius/REX_T;
+    float cx4 = left + X*TEXTURE_HEIGHT;
+    float cx3 = left + (1-X)*TEXTURE_HEIGHT;
+    float cy3 = top + (0.5f - (0.5f-REX_D)/3 + G*radius - F*stroke)*TEXTURE_HEIGHT;
+
+    canvas.drawArc( cx3-R3, cy3-R3, cx3+R3, cy3+R3, 270           , 90+REX_P, false ,paint);
+    canvas.drawArc( cx4-R3, cy3-R3, cx4+R3, cy3+R3, 270-(90+REX_P), 90+REX_P, false ,paint);
+
+    float cy5 = top + D*TEXTURE_HEIGHT;
+
+    paint.setStrokeWidth((1-2*F)*stroke*TEXTURE_HEIGHT);
+    canvas.drawLine(left, cy5, left+TEXTURE_HEIGHT, cy5, paint);
+    }
+  }
diff --git a/src/main/java/org/distorted/objects/FactoryCubit.java b/src/main/java/org/distorted/objects/FactoryCubit.java
deleted file mode 100644
index ab7ad695..00000000
--- a/src/main/java/org/distorted/objects/FactoryCubit.java
+++ /dev/null
@@ -1,2207 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2020 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Magic Cube.                                                              //
-//                                                                                               //
-// Magic Cube is free software: you can redistribute it and/or modify                            //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Magic Cube is distributed in the hope that it will be useful,                                 //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.objects;
-
-import org.distorted.library.effect.VertexEffect;
-import org.distorted.library.effect.VertexEffectDeform;
-import org.distorted.library.effect.VertexEffectMove;
-import org.distorted.library.effect.VertexEffectRotate;
-import org.distorted.library.effect.VertexEffectScale;
-import org.distorted.library.mesh.MeshBase;
-import org.distorted.library.mesh.MeshJoined;
-import org.distorted.library.mesh.MeshPolygon;
-import org.distorted.library.type.Static1D;
-import org.distorted.library.type.Static3D;
-import org.distorted.library.type.Static4D;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class FactoryCubit
-  {
-  private static final float SQ2 = (float)Math.sqrt(2);
-  private static final float SQ3 = (float)Math.sqrt(3);
-  private static final float SQ5 = (float)Math.sqrt(5);
-  private static final float SQ6 = (float)Math.sqrt(6);
-
-  private static final Static1D RADIUS = new Static1D(1);
-  private static FactoryCubit mThis;
-
-  // IVY
-  static final float IVY_D = 0.003f;
-  static final float IVY_C = 0.59f;
-  static final float IVY_M = 0.35f;
-  private static final int IVY_N = 8;
-
-  // REX
-  static final float REX_D = 0.2f;
-
-  // KILO / MEGAMINX
-  static final float SIN54    = (SQ5+1)/4;
-  static final float COS54    = (float)(Math.sqrt(10-2*SQ5)/4);
-  static final float SIN18    = (SQ5-1)/4;
-  static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
-  static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
-  static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
-  static final float DIHEDRAL1= (float)(Math.acos(-SQ5/5)*180/Math.PI);
-  static final float DIHEDRAL2= (float)((180/Math.PI)*Math.asin((2*SIN54*SIN54-1)/COS54) - 90);
-  static final float MINX_SC  = 0.5f;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private FactoryCubit()
-    {
-
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static FactoryCubit getInstance()
-    {
-    if( mThis==null ) mThis = new FactoryCubit();
-
-    return mThis;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// H - height of the band in the middle
-// alpha - angle of the edge  [0,90]
-// dist - often in a polygon the distance from edge to center is not 1, but something else.
-// This is the distance.
-// K - where to begin the second, much more flat part of the band. [0,1]
-// N - number of bands. N>=3
-//
-// theory: two distinct parts to the band:
-// 1) (0,B) - steep
-// 2) (B,1) - flat
-//
-// In first part, we have y = g(x) ; in second - y = g(f(x)) where
-//
-// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
-// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
-// h(x) = R*(sin(alpha) - sin(x))
-// R = H/(1-cos(alpha))
-// D = H*sin(alpha)
-// B = h(K*alpha)
-//
-// The N points are taken at:
-//
-// 1) in the second part, there are K2 = (N-3)/3 such points
-// 2) in the first - K1 = (N-3) - K2
-// 3) also, the 3 points 0,B,1
-//
-// so we have the sequence A[i] of N points
-//
-// 0
-// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
-// B
-// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
-// 1
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float f(float D, float B, float x)
-    {
-    return ((D-B)*x + B*(1-D))/(1-B);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float g(float R, float D, float x, float cosAlpha)
-    {
-    float d = x-D;
-    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float h(float R, float sinAlpha, float x)
-    {
-    return R*(sinAlpha-(float)Math.sin(x));
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float[] computeBands(float H, int alpha, float dist, float K, int N)
-    {
-    float[] bands = new float[2*N];
-
-    bands[0] = 1.0f;
-    bands[1] = 0.0f;
-
-    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
-    float sinBeta = (float)Math.sin(beta);
-    float cosBeta = (float)Math.cos(beta);
-    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
-    float D = R*sinBeta;
-    float B = h(R,sinBeta,K*beta);
-
-    if( D>1.0f )
-      {
-      for(int i=1; i<N; i++)
-        {
-        bands[2*i  ] = (float)(N-1-i)/(N-1);
-        bands[2*i+1] = H*(1-bands[2*i]);
-        }
-      }
-    else
-      {
-      int K2 = (int)((N-3)*K);
-      int K1 = (N-3)-K2;
-
-      for(int i=0; i<=K1; i++)
-        {
-        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
-        float x = h(R,sinBeta,angle);
-        bands[2*i+2] = 1.0f - x;
-        bands[2*i+3] = g(R,D,x,cosBeta);
-        }
-
-      for(int i=0; i<=K2; i++)
-        {
-        float x = (1-B)*(i+1)/(K2+1) + B;
-        bands[2*K1+2 + 2*i+2] = 1.0f - x;
-        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
-        }
-      }
-
-    bands[2*N-2] = 0.0f;
-    bands[2*N-1] =    H;
-
-    return bands;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
-    {
-    Static4D reg= new Static4D(0,0,0,regionRadius);
-
-    float centX = center.get0();
-    float centY = center.get1();
-    float centZ = center.get2();
-
-    for (Static3D vertex : vertices)
-      {
-      float x = strength*(centX - vertex.get0());
-      float y = strength*(centY - vertex.get1());
-      float z = strength*(centZ - vertex.get2());
-
-      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
-      mesh.apply(effect);
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesCube(int sizeIndex)
-    {
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    float E = 0.5f;
-    int extraI, extraV, num;
-
-    switch(sizeIndex)
-      {
-      case 0 : num = 6; extraI = 2; extraV = 2; break;
-      case 1 : num = 5; extraI = 2; extraV = 2; break;
-      case 2 : num = 5; extraI = 1; extraV = 2; break;
-      default: num = 4; extraI = 1; extraV = 1; break;
-      }
-
-    float[] vertices = { -E,-E, +E,-E, +E,+E, -E,+E };
-    float[] bands = computeBands(0.048f,35,E,0.7f,num);
-
-    meshes[0] = new MeshPolygon(vertices,bands,extraI,extraV);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[0].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[0].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[0].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesSkewbCorner()
-    {
-    MeshBase[] meshes = new MeshBase[6];
-
-    float E = 0.5f;
-    float F = SQ2/2;
-    float G = SQ6/16;
-    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
-    float[] bands0 = computeBands(0.028f,35,E/3,0.7f,7);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-
-    float[] vertices1 = { -F/2,-2*G, F/2,-2*G, 3*F/8,-G, 1*F/8,G, 0,2*G };
-    float[] bands1 = computeBands(0,0,1,0,3);
-
-    meshes[3] = new MeshPolygon(vertices1,bands1,1,5);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[3].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[3].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesSkewbFace()
-    {
-    MeshBase[] meshes = new MeshBase[5];
-
-    float E = SQ2/4;
-    float[] vertices0 = { -E,-E, +E,-E, +E,+E, -E,+E };
-    float[] bands0 = computeBands(0.051f,35,E/2,0.9f,7);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
-    meshes[0].setEffectAssociation(0,1,0);
-
-    float[] vertices1 = { -E,-SQ3*E, -E*0.7f,-SQ3*E, +E*0.7f,-SQ3*E, +E,-SQ3*E, 0,0 };
-    float[] bands1 = computeBands(0,0,1,0,3);
-
-    meshes[1] = new MeshPolygon(vertices1,bands1,0,0);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[1].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[1].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[1].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesOcta()
-    {
-    MeshBase[] meshes = new MeshPolygon[8];
-
-    float E = 0.75f;
-    float F = 0.5f;
-    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
-    float[] bands = computeBands(0.05f,35,F,0.8f,6);
-
-    meshes[0] = new MeshPolygon(vertices, bands, 2,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[0].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[0].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[0].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-    meshes[6] = meshes[0].copy(true);
-    meshes[6].setEffectAssociation(0,64,0);
-    meshes[7] = meshes[0].copy(true);
-    meshes[7].setEffectAssociation(0,128,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesTetra()
-    {
-    MeshBase[] meshes = new MeshBase[4];
-
-    float E = 0.75f;
-    float F = 0.5f;
-    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
-    float[] bands = computeBands(0.05f,35,F,0.8f,6);
-
-    meshes[0] = new MeshPolygon(vertices, bands, 2,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[0].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesDino()
-    {
-    MeshBase[] meshes = new MeshPolygon[4];
-
-    float E = 0.5f*SQ2;
-    float F = 0.5f;
-    float[] vertices0 = { -F,F/3, 0,-2*F/3, +F,F/3 };
-    float[] bands0 = computeBands(0.028f,30,F/3,0.8f,7);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 5);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    float[] vertices1 = { -E/2,-E*(SQ3/6), E/2,-E*(SQ3/6), 0,E*(SQ3/3) };
-    float[] bands1 = computeBands(0.02f,45,F/3,0.2f,3);
-
-    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesHelicopterCorner()
-    {
-    MeshBase[] meshes = new MeshBase[6];
-
-    float E = 0.5f;
-    float F = SQ2/4;
-    float G = 1.0f/12;
-    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
-    float[] bands0 = computeBands(0.028f,35,E/4,0.7f,7);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-
-    float[] vertices1 = { -F,-G, 0,-G, +F,-G, 0,2*G };
-    float[] bands1 = computeBands(0.00f,0,0,0.0f,3);
-    meshes[3] = new MeshPolygon(vertices1,bands1,1,5);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[3].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[3].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesHelicopterFace()
-    {
-    MeshBase[] meshes = new MeshBase[4];
-
-    float E = 0.5f;
-    float F = SQ2/4;
-    float G = 1.0f/12;
-    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
-    float[] bands0 = computeBands(0.028f,35,E/4,0.7f,7);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
-    meshes[0].setEffectAssociation(0,1,0);
-
-    float[] vertices1 = { -F,-G, +F,-G, 0,2*G};
-    float[] bands1 = computeBands(0.01f,45,F,0.0f,3);
-
-    meshes[1] = new MeshPolygon(vertices1, bands1, 1, 3);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    float[] vertices2 = { -E/2,-F/3, +E/2,-F/3, 0,2*F/3};
-
-    meshes[2] = new MeshPolygon(vertices2, bands1, 1, 3);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesRediEdge()
-    {
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    float F = 0.25f;
-    float[] vertices0 = { -F,+F, -F,-F, 0, -2*F, +F,-F, +F,+F };
-    float[] bands0 = computeBands(0.038f,35,F,0.7f,7);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    float[] bands1 = computeBands(0.02f,35,F/2,0.2f,3);
-    float[] vertices1 = { -F/2, +F/2, -F/2, -1.5f*F, 1.5f*F, +F/2 };
-
-    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-
-    float X = 0.25f*SQ2;
-    float Y = SQ6/16;
-    float[] vertices2 = { -X, Y, -1.5f*X, -Y, +1.5f*X, -Y, +X, Y };
-
-    meshes[4] = new MeshPolygon(vertices2, bands1, 1, 1);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[4].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesRediCorner()
-    {
-    MeshBase[] meshes = new MeshBase[6];
-
-    float E = 0.5f;
-    float[] vertices0 = { -E,-E, +E,-E, +E,+E, -E,+E };
-    float[] bands0 = computeBands(0.06f,35,E,0.7f,6);
-
-    meshes[0] = new MeshPolygon(vertices0,bands0,2,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-
-    float F = 0.5f;
-    float X = 0.5f;
-    float G = 0.72f;
-    float[] vertices1 = { -E,+F, -E+X,0, -E,-F, -E*G,-F, +E*G,-F, +E,-F, +E-X,0, +E,+F, +E*G,+F, -E*G,+F };
-    float[] bands1 = computeBands(0.0f,0,1.0f,0.0f,2);
-
-    meshes[3] = new MeshPolygon(vertices1,bands1,0,0);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[3].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[3].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesIvyCorner()
-    {
-    MeshBase[] meshes = new MeshBase[6];
-
-    final float angle = (float)Math.PI/(2*IVY_N);
-    final float CORR  = 1.0f - 2*IVY_D;
-    final float DIST  = -0.5f*CORR + IVY_D;
-    float[] vertices  = new float[2*(IVY_N+1)+6];
-
-    vertices[0] = (0.5f-IVY_M) * IVY_C;
-    vertices[1] = (DIST-IVY_M) * IVY_C;
-    vertices[2] = (0.5f-IVY_M) * IVY_C;
-    vertices[3] = (0.5f-IVY_M) * IVY_C;
-    vertices[4] = (DIST-IVY_M) * IVY_C;
-    vertices[5] = (0.5f-IVY_M) * IVY_C;
-
-    for(int i=0; i<=IVY_N; i++)
-      {
-      float ang = (IVY_N-i)*angle;
-      float sin = (float)Math.sin(ang);
-      float cos = (float)Math.cos(ang);
-
-      vertices[2*i+6] = (CORR*(cos-0.5f)-IVY_M)*IVY_C;
-      vertices[2*i+7] = (CORR*(sin-0.5f)-IVY_M)*IVY_C;
-      }
-
-    float[] bands0 = computeBands(+0.012f,20,0.2f,0.5f,7);
-    float[] bands1 = computeBands(-0.100f,20,0.2f,0.0f,2);
-
-    meshes[0] = new MeshPolygon(vertices,bands0,1,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = new MeshPolygon(vertices,bands1,1,2);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[3].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[3].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesIvyFace()
-    {
-    MeshBase[] meshes = new MeshBase[2];
-
-    final float angle = (float)Math.PI/(2*IVY_N);
-    final float CORR  = 1.0f - 2*IVY_D;
-    float[] vertices = new float[4*IVY_N];
-
-    for(int i=0; i<IVY_N; i++)
-      {
-      float sin = (float)Math.sin(i*angle);
-      float cos = (float)Math.cos(i*angle);
-
-      vertices[2*i          ] = CORR*(0.5f-cos);
-      vertices[2*i+1        ] = CORR*(0.5f-sin);
-      vertices[2*i  +2*IVY_N] = CORR*(cos-0.5f);
-      vertices[2*i+1+2*IVY_N] = CORR*(sin-0.5f);
-      }
-
-    float[] bands0 = computeBands(+0.03f,35,0.5f,0.5f,5);
-    float[] bands1 = computeBands(-0.10f,45,0.5f,0.0f,2);
-
-    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesRexCorner()
-    {
-    MeshBase[] meshes = new MeshBase[2];
-
-    float F = REX_D*SQ2;
-    float G = (1-REX_D)*SQ2/2;
-    float H = 0.1f;
-    float J = +2*G/3 - H*G;
-
-    float[] vertices = { -F/2, -G/3, +F/2, -G/3, H*F/2, J, -H*F/2, J};
-
-    float[] bands0 = computeBands(+0.016f,10,G/3,0.5f,5);
-    float[] bands1 = computeBands(-0.230f,45,G/3,0.0f,2);
-
-    meshes[0] = new MeshPolygon(vertices,bands0,1,1);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesRexFace()
-    {
-    MeshBase[] meshes = new MeshBase[2];
-
-    float[] vertices = { -REX_D,0.0f, 0.0f, -REX_D, +REX_D, 0.0f, 0.0f, +REX_D};
-
-    float[] bands0 = computeBands(0.016f,10,REX_D/2,0.5f,5);
-    float[] bands1 = computeBands(0.000f,45,REX_D/2,0.0f,2);
-
-    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesRexEdge()
-    {
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    float E = 0.5f - REX_D;
-    float F = 0.5f;
-    float[] vertices0 = { -F,E/3, 0,-2*E/3, +F,E/3 };
-    float[] bands0 = computeBands(0.03f,27,F/3,0.8f,5);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 3);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    float G = (float)Math.sqrt(E*E+F*F);
-    float[] vertices1 = { -2*G/3, -E/3, G/3, -E/3, G/3, 2*E/3 };
-    float[] bands1 = computeBands(0.00f,45,G/3,0.2f,3);
-
-    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[2].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[2].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesKilominxCenter()
-    {
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    float X1= 0.5f*SIN54;
-    float Y1= 0.5f*SIN_HALFD;
-    float Y2= Y1 - 0.5f*COS54;
-    float H = 0.5f* SIN54 /COS54  ;
-    float X2= MINX_SC*H* SIN_HALFD;
-    float Y3= MINX_SC*H/(2*COS_HALFD);
-    float Y4= MINX_SC*H*(1/(2*COS_HALFD) - COS_HALFD);
-
-    float[] vertices0 = { -X1, Y2, 0, -Y1, X1, Y2, 0, Y1 };
-    float[] bands0 = computeBands(0.04f,17,0.3f,0.2f,5);
-    float[] vertices1 = { -X2, Y4, 0, -Y3, X2, Y4, 0, Y3 };
-    float[] bands1 = computeBands(0.00f, 0,0.25f,0.5f,2);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
-    meshes[0].setEffectAssociation(0, 1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0, 2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0, 4,0);
-    meshes[3] = new MeshPolygon(vertices1, bands1, 0, 0);
-    meshes[3].setEffectAssociation(0, 8,0);
-    meshes[4] = meshes[3].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[3].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesMinxCorner(int numLayers)
-    {
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    float Y = COS54/(2*SIN54);
-
-    float[] vertices0 = { -0.5f, 0.0f, 0.0f, -Y, 0.5f, 0.0f, 0.0f, Y };
-
-    int numBands0 = numLayers==3 ? 5 : 3;
-    int numBands1 = numLayers==3 ? 2 : 2;
-    float h       = numLayers==3 ? 0.04f : 0.03f;
-    int   e       = numLayers==3 ? 4 : 1;
-
-    float[] bands0 = computeBands(h    ,34,0.3f,0.2f, numBands0);
-    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f, numBands1);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
-    meshes[0].setEffectAssociation(0, 1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0, 2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0, 4,0);
-    meshes[3] = new MeshPolygon(vertices0, bands1, 1, e);
-    meshes[3].setEffectAssociation(0, 8,0);
-    meshes[4] = meshes[3].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[3].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesKilominxEdge(int numLayers, float width, float height)
-    {
-     MeshBase[] meshes = new MeshPolygon[6];
-
-    float D = height/COS18;
-    float W = D*SIN18;
-    float X1 = height/2;
-    float Y1 = width/2;
-    float Y2 = (width+W)/2;
-    float X3 = D*SIN54;
-    float Y3 = D*COS54;
-    float X4 = height*SIN_HALFD;
-    float Y4 = height*COS_HALFD;
-
-    float[] vertices0 = { -X1,-Y1, X1, -Y1, X1, Y1+W,-X1, Y1 };
-    float[] vertices1 = { -X1,-Y2, X1, -Y2, X1, Y2+W,-X1, Y2 };
-    float[] vertices2 = { -X3, 0.0f, 0.0f, -Y3, X3, 0.0f, 0.0f, Y3 };
-    float[] vertices3 = { -X4, 0.0f, 0.0f, -Y4, X4, 0.0f, 0.0f, Y4 };
-
-    int numBands0 = numLayers<=5 ? 5 : 3;
-    int numBands1 = numLayers<=5 ? 3 : 2;
-    float h       = numLayers<=5 ? 0.03f : 0.03f;
-
-    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
-    float[] bands1 = computeBands(0.01f,34,0.3f,0.2f,numBands1);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 1, 1);
-    meshes[0].setEffectAssociation(0, 1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0, 2,0);
-    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
-    meshes[2].setEffectAssociation(0, 4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0, 8,0);
-    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = new MeshPolygon(vertices3, bands1, 0, 0);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesMegaminxEdge(int numLayers, float width, float height)
-    {
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    float D = height/COS18;
-    float W = D*SIN18;
-
-    float Y1 = 0.5f*width;
-    float Y2 = 0.5f*width + W;
-    float Y3 = 0.5f*width + 2*W;
-    float X2 = D*SIN54;
-    float X1 = 0.5f*height;
-    float Y4 = D*COS54;
-
-    float[] vertices0 = { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
-    float[] vertices1 = { -X1, Y3, -X1, -Y3, X1, -Y2, X1, Y2 };
-    float[] vertices2 = { -X2, 0.0f, 0.0f, -Y4, X2, 0.0f, 0.0f, Y4 };
-
-    int numBands0 = numLayers==3 ? 5 : 3;
-    int numBands1 = numLayers==3 ? 2 : 2;
-    float h       = numLayers==3 ? 0.03f : 0.03f;
-
-    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
-    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f,numBands1);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
-    meshes[0].setEffectAssociation(0, 1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0, 2,0);
-    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
-    meshes[2].setEffectAssociation(0, 4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0, 8,0);
-    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[4].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesMegaminxCenter(int numLayers)
-    {
-    MeshBase[] meshes = new MeshPolygon[2];
-
-    float R  = 0.5f;
-    float X1 = R*COS54;
-    float Y1 = R*SIN54;
-    float X2 = R*COS18;
-    float Y2 = R*SIN18;
-
-    float[] vertices0 = { -X1,+Y1, -X2,-Y2, 0.0f,-R, +X2,-Y2, +X1,+Y1 };
-
-    int numBands0 = numLayers==3 ? 4 : 3;
-    int numBands1 = numLayers==3 ? 2 : 2;
-    float h       = numLayers==3 ? 0.04f : 0.04f;
-
-    float[] bands0 = computeBands( h    ,45, R/3,0.2f, numBands0);
-    float[] bands1 = computeBands( 0.00f,34, R/3,0.2f, numBands1);
-
-    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = new MeshPolygon(vertices0, bands1, 0, 0);
-    meshes[1].setEffectAssociation(0,2,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float[] createVertices(int A, int B)
-    {
-    float E = 0.5f / Math.max(A,B);
-    return new float[] { -A*E,-B*E, +A*E,-B*E, +A*E,+B*E, -A*E,+B*E };
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createCuboid(int[] dimensions)
-    {
-    int X = dimensions[0];
-    int Y = dimensions[1];
-    int Z = dimensions[2];
-
-    float[] verticesXY = createVertices(X,Y);
-    float[] verticesXZ = createVertices(X,Z);
-    float[] verticesYZ = createVertices(Z,Y);
-
-    float defHeight = 0.048f;
-
-    float[] bandsX = computeBands( defHeight/X,65,0.25f,0.5f,5);
-    float[] bandsY = computeBands( defHeight/Y,65,0.25f,0.5f,5);
-    float[] bandsZ = computeBands( defHeight/Z,65,0.25f,0.5f,5);
-
-    MeshBase[] meshes = new MeshPolygon[6];
-
-    meshes[0] = new MeshPolygon(verticesYZ,bandsX,1,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = new MeshPolygon(verticesXZ,bandsY,1,2);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[2].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = new MeshPolygon(verticesXY,bandsZ,1,2);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[4].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// EFFECTS
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsCube()
-    {
-    Static3D axisY   = new Static3D(0,1,0);
-    Static3D axisX   = new Static3D(1,0,0);
-    Static3D center  = new Static3D(0,0,0);
-    Static1D angle90 = new Static1D(90);
-    Static1D angle180= new Static1D(180);
-    Static1D angle270= new Static1D(270);
-
-    VertexEffect[] effect = new VertexEffect[6];
-
-    effect[0] = new VertexEffectMove(new Static3D(0,0,+0.5f));
-    effect[1] = new VertexEffectRotate( angle180, axisX, center );
-    effect[2] = new VertexEffectRotate( angle90 , axisX, center );
-    effect[3] = new VertexEffectRotate( angle270, axisX, center );
-    effect[4] = new VertexEffectRotate( angle270, axisY, center );
-    effect[5] = new VertexEffectRotate( angle90 , axisY, center );
-
-    effect[0].setMeshAssociation(63,-1);  // all 6 sides
-    effect[1].setMeshAssociation(32,-1);  // back
-    effect[2].setMeshAssociation( 8,-1);  // bottom
-    effect[3].setMeshAssociation( 4,-1);  // top
-    effect[4].setMeshAssociation( 2,-1);  // left
-    effect[5].setMeshAssociation( 1,-1);  // right
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsSkewbCorner()
-    {
-    float E = 0.5f;
-
-    Static3D axisX  = new Static3D(1,0,0);
-    Static3D axisY  = new Static3D(0,1,0);
-    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
-    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
-    Static1D angle1 = new Static1D(+90);
-    Static1D angle2 = new Static1D(-90);
-    Static1D angle3 = new Static1D(-15);
-    Static1D angle4 = new Static1D((float)((180.0f/Math.PI)*Math.acos(SQ3/3)));
-    Static1D angle5 = new Static1D(120);
-    Static1D angle6 = new Static1D(240);
-    Static3D center1= new Static3D(0,0,0);
-    Static3D center2= new Static3D(-0.5f,-0.5f,-0.5f);
-    Static3D move1  = new Static3D(-E/4,-E/4,0);
-    Static3D move2  = new Static3D(-0.5f+SQ2/4,-0.5f+SQ6/8,-0.5f);
-
-    VertexEffect[] effect = new VertexEffect[10];
-
-    effect[0] = new VertexEffectMove(move1);
-    effect[1] = new VertexEffectScale(new Static3D(1,1,-1));
-    effect[2] = new VertexEffectRotate(angle1,axisX,center1);
-    effect[3] = new VertexEffectRotate(angle2,axisY,center1);
-    effect[4] = new VertexEffectMove(move2);
-    effect[5] = new VertexEffectRotate(angle1,axisX,center2);
-    effect[6] = new VertexEffectRotate(angle3,axisY,center2);
-    effect[7] = new VertexEffectRotate(angle4,axis0,center2);
-    effect[8] = new VertexEffectRotate(angle5,axis1,center2);
-    effect[9] = new VertexEffectRotate(angle6,axis1,center2);
-
-    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
-    effect[1].setMeshAssociation( 6,-1);  // meshes 1,2
-    effect[2].setMeshAssociation( 2,-1);  // mesh 1
-    effect[3].setMeshAssociation( 4,-1);  // mesh 2
-    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[7].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[8].setMeshAssociation(16,-1);  // mesh 4
-    effect[9].setMeshAssociation(32,-1);  // mesh 5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsSkewbFace()
-    {
-    Static3D center = new Static3D(0,0,0);
-    Static3D axisX  = new Static3D(1,0,0);
-    Static3D axisZ  = new Static3D(0,0,1);
-    float angle = -(float)((180.0f/Math.PI)*Math.acos(SQ3/3));
-
-    VertexEffect[] effect = new VertexEffect[6];
-
-    effect[0] = new VertexEffectRotate( new Static1D(angle), axisX, center);
-    effect[1] = new VertexEffectRotate( new Static1D(  135), axisZ, center);
-    effect[2] = new VertexEffectRotate( new Static1D(   45), axisZ, center);
-    effect[3] = new VertexEffectRotate( new Static1D(  -45), axisZ, center);
-    effect[4] = new VertexEffectRotate( new Static1D( -135), axisZ, center);
-    effect[5] = new VertexEffectMove( new Static3D(0,0,-0.5f) );
-
-    effect[0].setMeshAssociation(30,-1);  // meshes 1,2,3,4
-    effect[1].setMeshAssociation( 2,-1);  // mesh 1
-    effect[2].setMeshAssociation( 5,-1);  // meshes 0,2
-    effect[3].setMeshAssociation( 8,-1);  // mesh 3
-    effect[4].setMeshAssociation(16,-1);  // mesh 4
-    effect[5].setMeshAssociation(30,-1);  // meshes 1,2,3,4
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsOcta()
-    {
-    Static1D alpha = new Static1D((float)(-(180/Math.PI)*Math.asin(SQ3/3)));
-    Static1D angle1= new Static1D( 90);
-    Static1D angle2= new Static1D(180);
-    Static1D angle3= new Static1D(270);
-    Static3D move1 = new Static3D(0,SQ2/2-SQ3/3,0);
-    Static3D axisX = new Static3D(1,0,0);
-    Static3D axisY = new Static3D(0,1,0);
-    Static3D cent0 = new Static3D(0,0,0);
-    Static3D cent1 = new Static3D(0,SQ2/2,0);
-    Static3D flipY = new Static3D( 1,-1, 1);
-    Static3D scale = new Static3D( 1, 2*SQ3/3, 1);
-
-    VertexEffect[] effect = new VertexEffect[7];
-
-    effect[0] = new VertexEffectScale(scale);
-    effect[1] = new VertexEffectMove(move1);
-    effect[2] = new VertexEffectRotate(alpha , axisX, cent1);
-    effect[3] = new VertexEffectRotate(angle1, axisY, cent0);
-    effect[4] = new VertexEffectRotate(angle2, axisY, cent0);
-    effect[5] = new VertexEffectRotate(angle3, axisY, cent0);
-    effect[6] = new VertexEffectScale(flipY);
-
-    effect[3].setMeshAssociation ( 34,-1); // apply to meshes 1 & 5
-    effect[4].setMeshAssociation ( 68,-1); // apply to meshes 2 & 6
-    effect[5].setMeshAssociation (136,-1); // apply to meshes 3 & 7
-    effect[6].setMeshAssociation (240,-1); // apply to meshes 4,5,6,7
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsTetra()
-    {
-    Static3D flipZ = new Static3D( 1, 1,-1);
-    Static1D alpha = new Static1D((float)(-(180/Math.PI)*Math.asin(SQ3/3)));
-    Static1D angle1= new Static1D( 90);
-    Static1D angle2= new Static1D(180);
-    Static3D move1 = new Static3D(0,SQ2/4-SQ3/6,0);
-    Static3D axisX = new Static3D(1,0,0);
-    Static3D axisY = new Static3D(0,1,0);
-    Static3D axisZ = new Static3D(0,0,1);
-    Static3D cent0 = new Static3D(0,0,0);
-    Static3D cent1 = new Static3D(0,SQ2/4,0);
-    Static3D scale = new Static3D( 1, 2*SQ3/3, 1);
-
-    VertexEffect[] effect = new VertexEffect[7];
-
-    effect[0] = new VertexEffectScale(scale);
-    effect[1] = new VertexEffectRotate(angle2, axisZ, cent0);
-    effect[2] = new VertexEffectMove(move1);
-    effect[3] = new VertexEffectRotate(alpha , axisX, cent1);
-    effect[4] = new VertexEffectScale(flipZ);
-    effect[5] = new VertexEffectRotate(angle1, axisY, cent0);
-    effect[6] = new VertexEffectRotate(angle2, axisZ, cent0);
-
-    effect[4].setMeshAssociation(10,-1); // meshes 1 & 3
-    effect[5].setMeshAssociation(12,-1); // meshes 2 & 3
-    effect[6].setMeshAssociation(12,-1); // meshes 2 & 3
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsDino()
-    {
-    float E = 0.5f*SQ2;
-    float F = 0.5f;
-    final float ANGLE = (float)((180/Math.PI)*(Math.atan(SQ2)));
-
-    Static1D angle1 = new Static1D(-ANGLE);
-    Static1D angle2 = new Static1D(+ANGLE);
-    Static3D axisX  = new Static3D(1,0,0);
-    Static3D axisY  = new Static3D(0,1,0);
-    Static3D axisZ  = new Static3D(0,-1,1);
-    Static3D center0= new Static3D(0,0,0);
-    Static3D center1= new Static3D(0,-3*F,0);
-
-    VertexEffect[] effect = new VertexEffect[10];
-
-    effect[0] = new VertexEffectScale ( new Static3D(3,3,3) );
-    effect[1] = new VertexEffectMove  ( new Static3D(0,-F,0) );
-    effect[2] = new VertexEffectRotate( new Static1D(90), axisX, center0 );
-    effect[3] = new VertexEffectScale ( new Static3D(1,-1,1) );
-    effect[4] = new VertexEffectMove  ( new Static3D(3*E/2,E*(SQ3/2)-3*F,0) );
-    effect[5] = new VertexEffectRotate( new Static1D(+90), axisY, center1 );
-    effect[6] = new VertexEffectScale ( new Static3D(-1,1,1) );
-    effect[7] = new VertexEffectRotate( new Static1D( 45), axisX, center1 );
-    effect[8] = new VertexEffectRotate( angle1           , axisZ, center1 );
-    effect[9] = new VertexEffectRotate( angle2           , axisZ, center1 );
-
-    effect[0].setMeshAssociation(15,-1);  // apply to meshes 0,1,2,3
-    effect[1].setMeshAssociation( 3,-1);  // apply to meshes 0,1
-    effect[2].setMeshAssociation( 2,-1);  // apply to mesh 1
-    effect[3].setMeshAssociation( 2,-1);  // apply to mesh 1
-    effect[4].setMeshAssociation(12,-1);  // apply to meshes 2,3
-    effect[5].setMeshAssociation(12,-1);  // apply to meshes 2,3
-    effect[6].setMeshAssociation( 8,-1);  // apply to mesh 3
-    effect[7].setMeshAssociation(12,-1);  // apply to meshes 2,3
-    effect[8].setMeshAssociation( 4,-1);  // apply to mesh 2
-    effect[9].setMeshAssociation( 8,-1);  // apply to mesh 3
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsHelicopterCorner()
-    {
-    float E = 0.5f;
-
-    Static3D axisX  = new Static3D(1,0,0);
-    Static3D axisY  = new Static3D(0,1,0);
-    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
-    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
-    Static1D angle1 = new Static1D(+90);
-    Static1D angle2 = new Static1D(-90);
-    Static1D angle3 = new Static1D(-135);
-    Static1D angle4 = new Static1D(90);
-    Static1D angle5 = new Static1D(120);
-    Static1D angle6 = new Static1D(240);
-    Static3D center1= new Static3D(0,0,0);
-    Static3D center2= new Static3D(-0.25f,-0.25f,-0.25f);
-    Static3D move1  = new Static3D(-E/4,-E/4,0);
-    Static3D move2  = new Static3D(-0.25f,(-1.0f/6)-0.25f,-0.25f);
-
-    VertexEffect[] effect = new VertexEffect[10];
-
-    effect[0] = new VertexEffectMove(move1);
-    effect[1] = new VertexEffectScale(new Static3D(1,1,-1));
-    effect[2] = new VertexEffectRotate(angle1,axisX,center1);
-    effect[3] = new VertexEffectRotate(angle2,axisY,center1);
-    effect[4] = new VertexEffectMove(move2);
-    effect[5] = new VertexEffectRotate(angle1,axisX,center2);
-    effect[6] = new VertexEffectRotate(angle3,axisY,center2);
-    effect[7] = new VertexEffectRotate(angle4,axis0,center2);
-    effect[8] = new VertexEffectRotate(angle5,axis1,center2);
-    effect[9] = new VertexEffectRotate(angle6,axis1,center2);
-
-    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
-    effect[1].setMeshAssociation( 6,-1);  // meshes 1,2
-    effect[2].setMeshAssociation( 2,-1);  // mesh 1
-    effect[3].setMeshAssociation( 4,-1);  // mesh 2
-    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[7].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[8].setMeshAssociation(16,-1);  // mesh 4
-    effect[9].setMeshAssociation(32,-1);  // mesh 5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsHelicopterFace()
-    {
-    float E = 0.5f;
-    float F = SQ2/4;
-
-    Static3D move0  = new Static3D(-E/4, -E/4, 0);
-    Static3D move1  = new Static3D(-(SQ2/24)-E/2, -(SQ2/24)-E/2, 0);
-    Static3D move2  = new Static3D(-E/2, F/3, 0);
-    Static3D move3  = new Static3D(+E/2, F/3, 0);
-    Static3D move4  = new Static3D(+E/3,+E/3, 0);
-    Static1D angle1 = new Static1D(135);
-    Static1D angle2 = new Static1D(90);
-    Static1D angle3 = new Static1D(-90);
-    Static1D angle4 = new Static1D(-135);
-    Static3D axisX  = new Static3D(1,0,0);
-    Static3D axisY  = new Static3D(0,1,0);
-    Static3D axisZ  = new Static3D(0,0,1);
-    Static3D axis1  = new Static3D(1,-1,0);
-    Static3D center = new Static3D(0,0,0);
-    Static3D center1= new Static3D(-E/2,-E/2,0);
-
-    VertexEffect[] effect = new VertexEffect[10];
-
-    effect[0] = new VertexEffectMove(move0);
-    effect[1] = new VertexEffectRotate(angle1, axisZ, center);
-    effect[2] = new VertexEffectMove(move1);
-    effect[3] = new VertexEffectRotate(angle2, axis1, center1);
-    effect[4] = new VertexEffectMove(move2);
-    effect[5] = new VertexEffectMove(move3);
-    effect[6] = new VertexEffectRotate(angle3, axisZ, center);
-    effect[7] = new VertexEffectRotate(angle4, axisX, center);
-    effect[8] = new VertexEffectRotate(angle1, axisY, center);
-    effect[9] = new VertexEffectMove(move4);
-
-    effect[0].setMeshAssociation( 1,-1);  // mesh 0
-    effect[1].setMeshAssociation( 2,-1);  // mesh 1
-    effect[2].setMeshAssociation( 2,-1);  // mesh 1
-    effect[3].setMeshAssociation( 2,-1);  // mesh 1
-    effect[4].setMeshAssociation( 4,-1);  // mesh 2
-    effect[5].setMeshAssociation( 8,-1);  // mesh 3
-    effect[6].setMeshAssociation( 8,-1);  // mesh 3
-    effect[7].setMeshAssociation( 4,-1);  // mesh 2
-    effect[8].setMeshAssociation( 8,-1);  // mesh 3
-    effect[9].setMeshAssociation(15,-1);  // meshes 0,1,2,3
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsRediEdge()
-    {
-    Static3D move0 = new Static3D(0.0f, -0.5f, 0.0f);
-    Static3D move1 = new Static3D(0.25f, -0.25f, 0.0f);
-    Static3D move2 = new Static3D(0.5f, 0.0f, 0.0f);
-    Static3D move3 = new Static3D(0.0f, (SQ3-6)/8, (SQ3-6)/8);
-    Static3D flipZ = new Static3D(1,1,-1);
-    Static3D flipX = new Static3D(-1,1,1);
-    Static3D scale = new Static3D(2,2,2);
-    Static3D cent0 = new Static3D(0,0, 0);
-    Static3D cent1 = new Static3D(0,0, -1.5f);
-    Static3D axisX = new Static3D(1,0, 0);
-    Static3D axisY = new Static3D(0,1, 0);
-    Static3D axis  = new Static3D(0,SQ2/2,-SQ2/2);
-    Static1D angle1= new Static1D(90);
-    Static1D angle2= new Static1D(45);
-    Static1D angle3= new Static1D( (float)(180/Math.PI*Math.acos(SQ3/3)) );
-
-    VertexEffect[] effect = new VertexEffect[12];
-
-    effect[0] = new VertexEffectScale(scale);
-    effect[1] = new VertexEffectMove(move0);
-    effect[2] = new VertexEffectScale(flipZ);
-    effect[3] = new VertexEffectRotate(angle1,axisX,cent0);
-    effect[4] = new VertexEffectMove(move1);
-    effect[5] = new VertexEffectRotate(angle1,axisY,cent0);
-    effect[6] = new VertexEffectMove(move2);
-    effect[7] = new VertexEffectScale(flipX);
-    effect[8] = new VertexEffectRotate(angle2,axisX,cent0);
-    effect[9] = new VertexEffectMove(move3);
-    effect[10]= new VertexEffectRotate(angle3,axis ,cent1);
-    effect[11]= new VertexEffectScale(flipX);
-
-    effect[0].setMeshAssociation(63,-1);  // meshes 0,1,2,3,4,5
-    effect[1].setMeshAssociation( 3,-1);  // meshes 0,1
-    effect[2].setMeshAssociation( 2,-1);  // mesh 1
-    effect[3].setMeshAssociation( 2,-1);  // mesh 1
-    effect[4].setMeshAssociation(12,-1);  // meshes 2,3
-    effect[5].setMeshAssociation(60,-1);  // meshes 2,3,4,5
-    effect[6].setMeshAssociation(12,-1);  // meshes 2,3
-    effect[7].setMeshAssociation( 8,-1);  // mesh 3
-    effect[8].setMeshAssociation(48,-1);  // meshes 4,5
-    effect[9].setMeshAssociation(48,-1);  // meshes 4,5
-    effect[10].setMeshAssociation(48,-1); // meshes 4,5
-    effect[11].setMeshAssociation(32,-1); // mesh 5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsRediCorner()
-    {
-    Static3D axisY   = new Static3D(0,1,0);
-    Static3D axisX   = new Static3D(1,0,0);
-    Static3D axisZ   = new Static3D(0,0,1);
-    Static3D center  = new Static3D(0,0,0);
-    Static1D angle90 = new Static1D(90);
-    Static1D angle270= new Static1D(270);
-    Static1D angle45 = new Static1D(-45);
-    Static3D scale   = new Static3D(1.0f, SQ2, 1.0f);
-
-    VertexEffect[] effect = new VertexEffect[7];
-
-    effect[0] = new VertexEffectMove(new Static3D(0,0,+0.5f));
-    effect[1] = new VertexEffectRotate( angle270, axisX, center );
-    effect[2] = new VertexEffectRotate( angle90 , axisY, center );
-    effect[3] = new VertexEffectScale(scale);
-    effect[4] = new VertexEffectRotate( angle45 , axisX, center );
-    effect[5] = new VertexEffectRotate( angle90 , axisY, center );
-    effect[6] = new VertexEffectRotate( angle270, axisZ, center );
-
-    effect[0].setMeshAssociation( 7,-1);  // 0,1,2
-    effect[1].setMeshAssociation( 2,-1);  // 1
-    effect[2].setMeshAssociation( 4,-1);  // 2
-    effect[3].setMeshAssociation(56,-1);  // 3,4,5
-    effect[4].setMeshAssociation(56,-1);  // 3,4,5
-    effect[5].setMeshAssociation(16,-1);  // 4
-    effect[6].setMeshAssociation(32,-1);  // 5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsIvyCorner()
-    {
-    Static3D axisX  = new Static3D(1,0,0);
-    Static3D axisY  = new Static3D(0,1,0);
-    Static1D angle1 = new Static1D(+90);
-    Static1D angle2 = new Static1D(-90);
-    Static3D center = new Static3D(0,0,0);
-    Static3D move1  = new Static3D(IVY_M-0.5f,IVY_M-0.5f,0);
-
-    VertexEffect[] effect = new VertexEffect[5];
-
-    effect[0] = new VertexEffectScale(1/IVY_C);
-    effect[1] = new VertexEffectMove(move1);
-    effect[2] = new VertexEffectScale(new Static3D(1,1,-1));
-    effect[3] = new VertexEffectRotate(angle1,axisX,center);
-    effect[4] = new VertexEffectRotate(angle2,axisY,center);
-
-    effect[2].setMeshAssociation(54,-1);  // meshes 1,2,4,5
-    effect[3].setMeshAssociation(18,-1);  // meshes 1,4
-    effect[4].setMeshAssociation(36,-1);  // meshes 2,5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsRexEdge()
-    {
-    float E = 0.5f - REX_D;
-    float F = 0.5f;
-    float G = (float)Math.sqrt(E*E+F*F);
-    float A = (float)((180/Math.PI)*Math.asin(E/G));
-
-    Static3D move1 = new Static3D(    0.0f, -E/3, 0.0f);
-    Static3D move2 = new Static3D(2*G/3 -F, +E/3, 0.0f);
-
-    Static3D center0= new Static3D(0.0f, 0.0f, 0.0f);
-    Static3D center1= new Static3D(  -F, 0.0f, 0.0f);
-    Static3D center2= new Static3D(  +F, 0.0f, 0.0f);
-    Static3D axisX  = new Static3D(1.0f, 0.0f, 0.0f);
-    Static3D axisY  = new Static3D(0.0f, 1.0f, 0.0f);
-    Static3D axisZ  = new Static3D(0.0f, 0.0f, 1.0f);
-
-    Static1D angle180 = new Static1D(180);
-    Static1D angle90  = new Static1D( 90);
-    Static1D angle270 = new Static1D(270);
-    Static1D angle1   = new Static1D(+A);
-    Static1D angle2   = new Static1D(-A);
-
-    VertexEffect[] effect = new VertexEffect[12];
-
-    effect[0] = new VertexEffectMove(move1);
-    effect[1] = new VertexEffectMove(move2);
-    effect[2] = new VertexEffectRotate(  angle90, axisX, center0 );
-    effect[3] = new VertexEffectRotate( angle270, axisX, center0 );
-    effect[4] = new VertexEffectRotate( angle180, axisX, center0 );
-    effect[5] = new VertexEffectRotate( angle180, axisY, center0 );
-    effect[6] = new VertexEffectScale ( new Static3D(-1, 1, 1) );
-    effect[7] = new VertexEffectScale ( new Static3D( 1,-1, 1) );
-    effect[8] = new VertexEffectRotate(   angle1, axisY, center1);
-    effect[9] = new VertexEffectRotate(   angle2, axisY, center2);
-    effect[10]= new VertexEffectRotate(   angle2, axisZ, center1);
-    effect[11]= new VertexEffectRotate(   angle1, axisZ, center2);
-
-    effect[0].setMeshAssociation( 3,-1);  // meshes 0 & 1
-    effect[1].setMeshAssociation(60,-1);  // meshes 2,3,4,5
-    effect[2].setMeshAssociation( 2,-1);  // meshes 1
-    effect[3].setMeshAssociation(12,-1);  // meshes 2,3
-    effect[4].setMeshAssociation(48,-1);  // meshes 4,5
-    effect[5].setMeshAssociation(32,-1);  // mesh 5
-    effect[6].setMeshAssociation( 8,-1);  // apply to mesh 3
-    effect[7].setMeshAssociation( 2,-1);  // apply to mesh 1
-    effect[8].setMeshAssociation(16,-1);  // apply to mesh 4
-    effect[9].setMeshAssociation(32,-1);  // apply to mesh 5
-    effect[10].setMeshAssociation(4,-1);  // apply to mesh 2
-    effect[11].setMeshAssociation(8,-1);  // apply to mesh 3
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsRexCorner()
-    {
-    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
-    Static3D axisZ = new Static3D(0.0f, 0.0f, 1.0f);
-    Static1D angle = new Static1D(225);
-
-    VertexEffect[] effect = new VertexEffect[1];
-    effect[0] = new VertexEffectRotate(angle, axisZ, center);
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsKilominxCenter(float width)
-    {
-    VertexEffect[] effect = new VertexEffect[11];
-
-    float H = 0.5f*(SIN54/COS54);
-    float Y1= 0.5f*SIN_HALFD;
-    float Y2= H/(2*COS_HALFD);
-    float cos18 = (float)(Math.sqrt(1- SIN18 * SIN18));
-    float LEN   = (float)Math.sqrt(H*H/(COS_HALFD*COS_HALFD) + 0.25f);
-
-    Static3D axisZ = new Static3D(0.0f  , 0.0f , 1.0f);
-    Static3D axisY = new Static3D(0.0f  , 1.0f , 0.0f);
-    Static3D axisA = new Static3D(-SIN18, cos18, 0.0f);
-    Static3D axisC = new Static3D( H/LEN, -0.5f/LEN,-H* SIN_HALFD /(COS_HALFD*LEN));
-
-    Static3D move1 = new Static3D(0,-Y1,0);
-    Static3D move2 = new Static3D(0,-Y2,0);
-    Static3D move3 = new Static3D(0.5f*cos18,0.5f*SIN18,0);
-    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
-
-    Static1D angle1 = new Static1D(54);
-    Static1D angle2 = new Static1D(DIHEDRAL1/2+18);
-    Static1D angle3 = new Static1D(90);
-    Static1D angle4 = new Static1D(120);
-    Static1D angle5 = new Static1D(240);
-    Static1D angle6 = new Static1D(90-DIHEDRAL1/2);
-
-    effect[0] = new VertexEffectMove(move1);
-    effect[1] = new VertexEffectScale(1/MINX_SC);
-    effect[2] = new VertexEffectMove(move2);
-    effect[3] = new VertexEffectRotate(angle1, axisZ, center);
-    effect[4] = new VertexEffectRotate(angle2, axisZ, center);
-    effect[5] = new VertexEffectRotate(angle3, axisA, center);
-    effect[6] = new VertexEffectMove(move3);
-    effect[7] = new VertexEffectRotate(angle4, axisC, center);
-    effect[8] = new VertexEffectRotate(angle5, axisC, center);
-    effect[9] = new VertexEffectRotate(angle6, axisY, center);
-    effect[10]= new VertexEffectScale(width/0.5f);
-
-    effect[0].setMeshAssociation( 7,-1);  // meshes 0,1,2
-    effect[1].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[2].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[3].setMeshAssociation( 7,-1);  // meshes 0,1,2
-    effect[4].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[5].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[6].setMeshAssociation(56,-1);  // meshes 3,4,5
-    effect[7].setMeshAssociation(18,-1);  // meshes 1,4
-    effect[8].setMeshAssociation(36,-1);  // meshes 2,5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsMinxCorner(float width)
-    {
-    VertexEffect[] effect = new VertexEffect[9];
-
-    float Y = COS54/(2*SIN54);
-
-    float sinA = (2*SIN54*SIN54-1)/COS54;
-    float cosA = (float)Math.sqrt(1-sinA*sinA);
-    float LEN  = 0.5f/SIN54;
-    float scale= width/LEN;
-
-    Static3D axisA = new Static3D( SIN54, COS54, 0.0f);
-    Static3D axisB = new Static3D(-SIN54, COS54, 0.0f);
-    Static3D axisX = new Static3D(  1.0f,  0.0f, 0.0f);
-
-    Static3D centerU = new Static3D( 0.0f, Y, 0.0f);
-    Static3D centerD = new Static3D( 0.0f,-Y, 0.0f);
-
-    Static3D move1= new Static3D(0.0f, -sinA*LEN, -cosA*LEN );
-    Static3D move2= new Static3D(0.0f, Y , 0.0f );
-
-    Static1D angleD = new Static1D(DIHEDRAL1);
-    Static1D angleE = new Static1D(360-DIHEDRAL1);
-    Static1D angleF = new Static1D(DIHEDRAL2);
-
-    effect[0] = new VertexEffectScale ( new Static3D( 1, 1,-1) );
-    effect[1] = new VertexEffectRotate(angleE, axisA, centerU);
-    effect[2] = new VertexEffectRotate(angleD, axisB, centerU);
-    effect[3] = new VertexEffectMove(move1);
-    effect[4] = new VertexEffectRotate(angleE, axisA, centerD);
-    effect[5] = new VertexEffectRotate(angleD, axisB, centerD);
-    effect[6] = new VertexEffectRotate(angleF, axisX, centerD);
-    effect[7] = new VertexEffectMove(move2);
-    effect[8] = new VertexEffectScale(scale);
-
-    effect[0].setMeshAssociation(  3,-1);  // meshes 0,1
-    effect[1].setMeshAssociation( 16,-1);  // mesh 4
-    effect[2].setMeshAssociation( 32,-1);  // mesh 5
-    effect[3].setMeshAssociation( 56,-1);  // meshes 3,4,5
-    effect[4].setMeshAssociation(  1,-1);  // mesh 0
-    effect[5].setMeshAssociation(  2,-1);  // mesh 1
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsKilominxEdge(float width, float height, boolean left)
-    {
-    VertexEffect[] effect = new VertexEffect[11 + (left ? 0:1)];
-
-    float D = height/COS18;
-    float W = D*SIN18;
-    float X1 = height/2;
-    float Y1 = width/2;
-    float Y2 = (width+W)/2;
-    float Y3 = D*COS54;
-    float Y4 = height*COS_HALFD;
-    float Z = 2*height*COS_HALFD;
-    float alpha = 90-DIHEDRAL1/2;
-
-    Static1D angle1 = new Static1D(alpha);
-    Static1D angle2 = new Static1D(180-alpha);
-    Static1D angle3 = new Static1D(DIHEDRAL2);
-    Static1D angle4 = new Static1D(90);
-
-    Static3D move1 = new Static3D(+X1,-Y1,0);
-    Static3D move2 = new Static3D(-X1,-Y2+W,-Z);
-    Static3D move3 = new Static3D(0,+Y3,0);
-    Static3D move4 = new Static3D(0,-Y4-width,0);
-    Static3D scale = new Static3D(+1,+1,-1);
-
-    Static3D axisXplus = new Static3D(+1, 0, 0);
-    Static3D axisYplus = new Static3D( 0,+1, 0);
-
-    Static3D center1= new Static3D( 0, 0, 0);
-    Static3D center2= new Static3D( 0, 0,-Z);
-    Static3D center3= new Static3D( 0,-width, 0);
-
-    effect[ 0] = new VertexEffectMove(move1);
-    effect[ 1] = new VertexEffectMove(move2);
-    effect[ 2] = new VertexEffectMove(move3);
-    effect[ 3] = new VertexEffectMove(move4);
-    effect[ 4] = new VertexEffectScale(scale);
-    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
-    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
-    effect[ 7] = new VertexEffectRotate(angle1, axisYplus , center2);
-    effect[ 8] = new VertexEffectRotate(angle2, axisYplus , center2);
-    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center1);
-    effect[10] = new VertexEffectRotate(angle4, axisXplus , center3);
-
-    if( !left )
-      {
-      Static3D scale1 = new Static3D(+1,-1,+1);
-      effect[11] = new VertexEffectScale(scale1);
-      }
-
-    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
-    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
-    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
-    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
-    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
-    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
-    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
-    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
-    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
-    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
-    effect[10].setMeshAssociation(32,-1);  // mesh 5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsMegaminxEdge(float width, float height)
-    {
-    VertexEffect[] effect = new VertexEffect[11];
-
-    float X = 0.5f*height;
-    float Y = height*(COS54/COS18) + width*0.5f;
-    float Z = 2*height*COS_HALFD;
-
-    float alpha = 90-DIHEDRAL1/2;
-    float beta  = DIHEDRAL2;
-
-    Static1D angle1 = new Static1D(alpha);
-    Static1D angle2 = new Static1D(180-alpha);
-    Static1D angle3 = new Static1D(beta);
-
-    Static3D move1 = new Static3D(X,0,0);
-    Static3D move2 = new Static3D(X,0,-Z);
-    Static3D move3 = new Static3D(0,+Y,0);
-    Static3D move4 = new Static3D(0,-Y,0);
-    Static3D scale = new Static3D(+1,+1,-1);
-
-    Static3D axisXplus = new Static3D(+1, 0, 0);
-    Static3D axisXminus= new Static3D(-1, 0, 0);
-    Static3D axisYplus = new Static3D( 0,+1, 0);
-    Static3D axisYminus= new Static3D( 0,-1, 0);
-
-    Static3D center1= new Static3D( 0, 0, 0);
-    Static3D center2= new Static3D( 0, 0,-Z);
-    Static3D center3= new Static3D( 0,+width*0.5f, 0);
-    Static3D center4= new Static3D( 0,-width*0.5f, 0);
-
-    effect[ 0] = new VertexEffectMove(move1);
-    effect[ 1] = new VertexEffectMove(move2);
-    effect[ 2] = new VertexEffectMove(move3);
-    effect[ 3] = new VertexEffectMove(move4);
-    effect[ 4] = new VertexEffectScale(scale);
-    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
-    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
-    effect[ 7] = new VertexEffectRotate(angle1, axisYminus, center2);
-    effect[ 8] = new VertexEffectRotate(angle2, axisYminus, center2);
-    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center3);
-    effect[10] = new VertexEffectRotate(angle3, axisXminus, center4);
-
-    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
-    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
-    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
-    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
-    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
-    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
-    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
-    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
-    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
-    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
-    effect[10].setMeshAssociation(32,-1);  // mesh 5
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsMegaminxCenter(float width)
-    {
-    VertexEffect[] effect = new VertexEffect[2];
-
-    Static1D angle = new Static1D(DIHEDRAL2);
-    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
-    Static3D center= new Static3D( 0, 0, 0);
-
-    effect[0] = new VertexEffectScale(width/COS54);
-    effect[1] = new VertexEffectRotate(angle, axisX, center);
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createCuboidEffects(int[] dimensions)
-    {
-    float X = dimensions[0];
-    float Y = dimensions[1];
-    float Z = dimensions[2];
-
-    float MAX_XY = Math.max(X,Y);
-    float MAX_XZ = Math.max(X,Z);
-    float MAX_YZ = Math.max(Z,Y);
-
-    Static1D angle = new Static1D(90);
-    Static3D move  = new Static3D( 0.0f, 0.0f, 0.5f);
-    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
-    Static3D axisY = new Static3D( 0.0f, 1.0f, 0.0f);
-    Static3D center= new Static3D( 0.0f, 0.0f, 0.0f);
-
-    Static3D scale3 = new Static3D(MAX_XY,MAX_XY,+Z);
-    Static3D scale4 = new Static3D(MAX_XY,MAX_XY,-Z);
-    Static3D scale5 = new Static3D(MAX_XZ,+Y,MAX_XZ);
-    Static3D scale6 = new Static3D(MAX_XZ,-Y,MAX_XZ);
-    Static3D scale7 = new Static3D(+X,MAX_YZ,MAX_YZ);
-    Static3D scale8 = new Static3D(-X,MAX_YZ,MAX_YZ);
-
-    VertexEffect[] effect = new VertexEffect[9];
-
-    effect[0] = new VertexEffectMove(move);
-    effect[1] = new VertexEffectRotate(angle, axisX, center);
-    effect[2] = new VertexEffectRotate(angle, axisY, center);
-    effect[3] = new VertexEffectScale(scale3);
-    effect[4] = new VertexEffectScale(scale4);
-    effect[5] = new VertexEffectScale(scale5);
-    effect[6] = new VertexEffectScale(scale6);
-    effect[7] = new VertexEffectScale(scale7);
-    effect[8] = new VertexEffectScale(scale8);
-
-    effect[1].setMeshAssociation(12,-1);  // meshes 2,3
-    effect[2].setMeshAssociation( 3,-1);  // meshes 0,1
-    effect[3].setMeshAssociation(16,-1);  // mesh 4
-    effect[4].setMeshAssociation(32,-1);  // mesh 5
-    effect[5].setMeshAssociation( 8,-1);  // mesh 3
-    effect[6].setMeshAssociation( 4,-1);  // mesh 2
-    effect[7].setMeshAssociation( 1,-1);  // mesh 0
-    effect[8].setMeshAssociation( 2,-1);  // mesh 1
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// OBJECTS
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// CUBE
-
-  MeshBase createCubeMesh(int index)
-    {
-    MeshBase mesh = createFacesCube(index);
-    VertexEffect[] effects = createVertexEffectsCube();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D roundingCenter  = new Static3D(0,0,0);
-    Static3D[] vertices = new Static3D[8];
-    vertices[0] = new Static3D(+0.5f,+0.5f,+0.5f);
-    vertices[1] = new Static3D(+0.5f,+0.5f,-0.5f);
-    vertices[2] = new Static3D(+0.5f,-0.5f,+0.5f);
-    vertices[3] = new Static3D(+0.5f,-0.5f,-0.5f);
-    vertices[4] = new Static3D(-0.5f,+0.5f,+0.5f);
-    vertices[5] = new Static3D(-0.5f,+0.5f,-0.5f);
-    vertices[6] = new Static3D(-0.5f,-0.5f,+0.5f);
-    vertices[7] = new Static3D(-0.5f,-0.5f,-0.5f);
-
-    roundCorners(mesh,roundingCenter,vertices,0.06f,0.12f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// SKEWB
-
-  MeshBase createSkewbCornerMesh()
-    {
-    MeshBase mesh = createFacesSkewbCorner();
-    VertexEffect[] effects = createVertexEffectsSkewbCorner();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    float E = 0.5f;
-    Static3D roundingCenter = new Static3D(-E/2,-E/2,-E/2);
-
-    Static3D[] verticesType1 = new Static3D[1];
-    verticesType1[0] = new Static3D(0.0f,0.0f,0.0f);
-    roundCorners(mesh,roundingCenter,verticesType1,0.08f,0.15f);
-
-    Static3D[] verticesType2 = new Static3D[3];
-    verticesType2[0] = new Static3D(-E, 0, 0);
-    verticesType2[1] = new Static3D( 0,-E, 0);
-    verticesType2[2] = new Static3D( 0, 0,-E);
-    roundCorners(mesh,roundingCenter,verticesType2,0.08f,0.20f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createSkewbFaceMesh()
-    {
-    MeshBase mesh = createFacesSkewbFace();
-    VertexEffect[] effects = createVertexEffectsSkewbFace();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D roundingCenter = new Static3D(0,0,-0.2f);
-    float E = SQ2/4;
-    Static3D[] vertices = new Static3D[4];
-    vertices[0] = new Static3D(-E*SQ2,      0, 0);
-    vertices[1] = new Static3D(+E*SQ2,      0, 0);
-    vertices[2] = new Static3D(     0, -E*SQ2, 0);
-    vertices[3] = new Static3D(     0, +E*SQ2, 0);
-    roundCorners(mesh,roundingCenter,vertices,0.06f,0.10f);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// SKEWB DIAMOND / PYRAMINX
-
-  MeshBase createOctaMesh()
-    {
-    MeshBase mesh = createFacesOcta();
-    VertexEffect[] effects = createVertexEffectsOcta();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D roundingCenter = new Static3D(0,0,0);
-    Static3D[] vertices = new Static3D[6];
-    vertices[0] = new Static3D(    0, SQ2/2,    0 );
-    vertices[1] = new Static3D( 0.5f,     0, 0.5f );
-    vertices[2] = new Static3D(-0.5f,     0, 0.5f );
-    vertices[3] = new Static3D(    0,-SQ2/2,    0 );
-    vertices[4] = new Static3D(-0.5f,     0,-0.5f );
-    vertices[5] = new Static3D( 0.5f,     0,-0.5f );
-
-    roundCorners(mesh,roundingCenter,vertices,0.06f,0.20f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createTetraMesh()
-    {
-    MeshBase mesh = createFacesTetra();
-    VertexEffect[] effects = createVertexEffectsTetra();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D roundingCenter = new Static3D(0,0,0);
-    Static3D[] verticesRound = new Static3D[4];
-    verticesRound[0] = new Static3D(-0.5f,+SQ2/4,   0 );
-    verticesRound[1] = new Static3D(+0.5f,+SQ2/4,   0 );
-    verticesRound[2] = new Static3D(    0,-SQ2/4,+0.5f);
-    verticesRound[3] = new Static3D(    0,-SQ2/4,-0.5f);
-    roundCorners(mesh,roundingCenter,verticesRound,0.08f,0.15f);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// DINO
-
-  MeshBase createDinoMesh()
-    {
-    MeshBase mesh = createFacesDino();
-    VertexEffect[] effects = createVertexEffectsDino();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    float F = 0.5f;
-    Static3D roundingCenter = new Static3D(0.0f, -1.5f*F, -1.5f*F);
-    Static3D[] verticesRound = new Static3D[4];
-    verticesRound[0] = new Static3D(     0,-3*F,    0 );
-    verticesRound[1] = new Static3D(     0,   0, -3*F );
-    verticesRound[2] = new Static3D(  -3*F,   0,    0 );
-    verticesRound[3] = new Static3D(  +3*F,   0,    0 );
-    roundCorners(mesh,roundingCenter,verticesRound,0.10f,0.40f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Helicopter
-
-  MeshBase createHelicopterCornerMesh()
-    {
-    MeshBase mesh = createFacesHelicopterCorner();
-    VertexEffect[] effects = createVertexEffectsHelicopterCorner();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    float E = 0.5f;
-    Static3D roundingCenter = new Static3D(-E/2,-E/2,-E/2);
-
-    Static3D[] verticesType1 = new Static3D[1];
-    verticesType1[0] = new Static3D(0.0f,0.0f,0.0f);
-    roundCorners(mesh,roundingCenter,verticesType1,0.08f,0.15f);
-
-    Static3D[] verticesType2 = new Static3D[3];
-    verticesType2[0] = new Static3D(-E, 0, 0);
-    verticesType2[1] = new Static3D( 0,-E, 0);
-    verticesType2[2] = new Static3D( 0, 0,-E);
-    roundCorners(mesh,roundingCenter,verticesType2,0.08f,0.20f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createHelicopterFaceMesh()
-    {
-    MeshBase mesh = createFacesHelicopterFace();
-    VertexEffect[] effects = createVertexEffectsHelicopterFace();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    float E = 0.5f;
-    Static3D roundingCenter = new Static3D(-E/2 + E/3,-E/2 + E/3,-E/2);
-
-    Static3D[] verticesType1 = new Static3D[1];
-    verticesType1[0] = new Static3D(E/3,E/3,0.0f);
-    roundCorners(mesh,roundingCenter,verticesType1,0.06f,0.15f);
-
-    Static3D[] verticesType2 = new Static3D[2];
-    verticesType2[0] = new Static3D(-E+E/3, E/3  , 0);
-    verticesType2[1] = new Static3D( E/3  ,-E+E/3, 0);
-    roundCorners(mesh,roundingCenter,verticesType2,0.08f,0.20f);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Redi cube
-
-  MeshBase createRediEdgeMesh()
-    {
-    MeshBase mesh = createFacesRediEdge();
-    VertexEffect[] effects = createVertexEffectsRediEdge();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D center = new Static3D(0.0f,-0.75f,-0.75f);
-    Static3D[] vertices = new Static3D[2];
-    vertices[0] = new Static3D( 0.5f, 0.0f, 0.0f);
-    vertices[1] = new Static3D(-0.5f, 0.0f, 0.0f);
-    roundCorners(mesh,center,vertices,0.06f,0.20f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createRediCornerMesh()
-    {
-    MeshBase mesh = createFacesRediCorner();
-    VertexEffect[] effects = createVertexEffectsRediCorner();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D center = new Static3D(0,0,0);
-    Static3D[] vertices = new Static3D[8];
-    vertices[0] = new Static3D(+0.5f,+0.5f,+0.5f);
-    vertices[1] = new Static3D(+0.5f,+0.5f,-0.5f);
-    vertices[2] = new Static3D(+0.5f,-0.5f,+0.5f);
-    vertices[3] = new Static3D(+0.5f,-0.5f,-0.5f);
-    vertices[4] = new Static3D(-0.5f,+0.5f,+0.5f);
-    vertices[5] = new Static3D(-0.5f,+0.5f,-0.5f);
-    vertices[6] = new Static3D(-0.5f,-0.5f,+0.5f);
-    vertices[7] = new Static3D(-0.5f,-0.5f,-0.5f);
-
-    roundCorners(mesh,center,vertices,0.06f,0.12f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createIvyCornerMesh()
-    {
-    MeshBase mesh = createFacesIvyCorner();
-    VertexEffect[] effects = createVertexEffectsIvyCorner();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D center = new Static3D(-0.5f,-0.5f,-0.5f);
-    Static3D[] vertices = new Static3D[4];
-    vertices[0] = new Static3D(+0.0f,+0.0f,+0.0f);
-    vertices[1] = new Static3D(-1.0f,+0.0f,+0.0f);
-    vertices[2] = new Static3D(+0.0f,-1.0f,+0.0f);
-    vertices[3] = new Static3D(+0.0f,+0.0f,-1.0f);
-
-    roundCorners(mesh,center,vertices,0.03f,0.10f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createIvyFaceMesh()
-    {
-    MeshBase mesh = createFacesIvyFace();
-
-    Static3D center = new Static3D(-0.0f,-0.0f,-0.5f);
-    Static3D[] vertices = new Static3D[2];
-    vertices[0] = new Static3D(-0.5f,+0.5f,+0.0f);
-    vertices[1] = new Static3D(+0.5f,-0.5f,+0.0f);
-
-    roundCorners(mesh,center,vertices,0.03f,0.10f);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createRexCornerMesh()
-    {
-    MeshBase mesh = createFacesRexCorner();
-    VertexEffect[] effects = createVertexEffectsRexCorner();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    final float G = (1-REX_D)/3;
-    Static3D center = new Static3D(0.0f,0.0f,-G*SQ2/2);
-    Static3D[] vertices = new Static3D[1];
-    vertices[0] = new Static3D(+G,-G,+0.0f);
-    roundCorners(mesh,center,vertices,0.10f,0.10f);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createRexFaceMesh()
-    {
-    MeshBase mesh = createFacesRexFace();
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createRexEdgeMesh()
-    {
-    MeshBase mesh = createFacesRexEdge();
-    VertexEffect[] effects = createVertexEffectsRexEdge();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D center = new Static3D(0.0f,-0.5f,-0.5f);
-    Static3D[] vertices = new Static3D[2];
-    vertices[0] = new Static3D(+0.5f,+0.0f,+0.0f);
-    vertices[1] = new Static3D(-0.5f,+0.0f,+0.0f);
-    roundCorners(mesh,center,vertices,0.06f,0.10f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createKilominxCenterMesh(float width)
-    {
-    MeshBase mesh = createFacesKilominxCenter();
-    VertexEffect[] effects = createVertexEffectsKilominxCenter(width);
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    float A = (2*SQ3/3)* SIN54;
-    float B = 0.4f;
-    float X = SIN_HALFD * SIN54 *COS54  ;
-    float Y = SIN54 * SIN54 - 0.5f;
-    float Z = COS_HALFD* SIN54 *COS54  ;
-
-    Static3D center = new Static3D(0.0f, -(float)Math.sqrt(1-A*A)*B,-A*B);
-
-    Static3D[] vertices = new Static3D[4];
-    vertices[0] = new Static3D( 0.0f, 0.0f, 0.0f);
-    vertices[1] = new Static3D( 0.0f,-0.5f, 0.0f);
-    vertices[2] = new Static3D(-X   , Y   ,-Z   );
-    vertices[3] = new Static3D(+X   , Y   ,-Z   );
-
-    roundCorners(mesh,center,vertices,0.03f,0.10f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
-// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
-
-  MeshBase createKilominxEdgeMesh(int numLayers, float width, float height, boolean left)
-    {
-    MeshBase mesh = createFacesKilominxEdge(numLayers,width,height);
-    VertexEffect[] effects = createVertexEffectsKilominxEdge(width,height,left);
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-// round...
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createMinxCornerMesh(int numLayers, float width)
-    {
-    MeshBase mesh = createFacesMinxCorner(numLayers);
-    VertexEffect[] effects = createVertexEffectsMinxCorner(width);
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    float A = (2*SQ3/3)* SIN54;
-    float B = 0.4f;
-/*
-    float X = SIN_HALFD* SIN54 * COS54;
-    float Y = SIN54 * SIN54 - 0.5f;
-    float Z = COS_HALFD* SIN54 * COS54;
-    float S = 2*width;
-*/
-    Static3D center = new Static3D(0.0f, -(float)Math.sqrt(1-A*A)*B,-A*B);
-    Static3D[] vertices = new Static3D[1];
-    vertices[0] = new Static3D( 0.0f, 0.0f  , 0.0f);
-/*
-    vertices[1] = new Static3D( 0.0f,-0.5f*S, 0.0f);
-    vertices[2] = new Static3D(-X*S , Y*S   ,-Z*S );
-    vertices[3] = new Static3D(+X*S , Y*S   ,-Z*S );
-*/
-    roundCorners(mesh,center,vertices,0.04f,0.10f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
-// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
-
-  MeshBase createMegaminxEdgeMesh(int numLayers, float width, float height)
-    {
-    MeshBase mesh = createFacesMegaminxEdge(numLayers,width,height);
-    VertexEffect[] effects = createVertexEffectsMegaminxEdge(width,height);
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createMegaminxCenterMesh(int numLayers, float width)
-    {
-    MeshBase mesh = createFacesMegaminxCenter(numLayers);
-    VertexEffect[] effects = createVertexEffectsMegaminxCenter(width);
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createCuboidMesh(int[] dimensions)
-    {
-    MeshBase mesh = createCuboid(dimensions);
-    VertexEffect[] effects = createCuboidEffects(dimensions);
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    int X = dimensions[0];
-    int Y = dimensions[1];
-    int Z = dimensions[2];
-
-    float strength = 0.04f;
-    float radius   = 0.15f;
-
-    Static3D[] vertices = new Static3D[1];
-    Static3D center;
-
-    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,+0.5f*Z);
-    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,-0.5f*Z);
-    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,+0.5f*Z);
-    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,-0.5f*Z);
-    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,+0.5f*Z);
-    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,-0.5f*Z);
-    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,+0.5f*Z);
-    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,-0.5f*Z);
-    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
-    roundCorners(mesh, center, vertices, strength, radius);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-  }
diff --git a/src/main/java/org/distorted/objects/FactorySticker.java b/src/main/java/org/distorted/objects/FactorySticker.java
deleted file mode 100644
index 7e5d4e31..00000000
--- a/src/main/java/org/distorted/objects/FactorySticker.java
+++ /dev/null
@@ -1,350 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2020 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Magic Cube.                                                              //
-//                                                                                               //
-// Magic Cube is free software: you can redistribute it and/or modify                            //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Magic Cube is distributed in the hope that it will be useful,                                 //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.objects;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-
-import static org.distorted.objects.TwistyObject.TEXTURE_HEIGHT;
-import static org.distorted.objects.TwistyObject.COLOR_BLACK;
-import static org.distorted.objects.FactoryCubit.IVY_D;
-import static org.distorted.objects.FactoryCubit.IVY_C;
-import static org.distorted.objects.FactoryCubit.IVY_M;
-import static org.distorted.objects.FactoryCubit.REX_D;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class FactorySticker
-  {
-  private static final float SQ2 = (float)Math.sqrt(2);
-  private static final float REX_X,REX_R,REX_B,REX_A, REX_P, REX_T, REX_C, REX_S;
-  private static FactorySticker mThis;
-
-  static
-    {
-    float F = REX_D*SQ2;
-    float G = (1-REX_D)*SQ2/2;
-
-    REX_X = (0.5f-REX_D*REX_D)/(2*REX_D);
-    REX_R = (float)Math.sqrt(2*REX_X*REX_X+0.5f);
-    REX_B = (float) ((180/Math.PI)*(2*Math.asin( Math.sqrt(REX_D*REX_D-REX_D+0.5f) / (2*REX_R) )));
-    REX_A = (float) ((180/Math.PI)*Math.acos(REX_X/REX_R)) - 45;
-    REX_P = 45 + REX_B/2 + REX_A;
-    REX_T = (float) ( Math.tan( (Math.PI/180)*(45-REX_P/2) ) );
-    REX_C = (float)(REX_R/Math.cos((Math.PI/180)*REX_B/2) );
-    REX_S = (float)(1/Math.sqrt(1+4*G*G/(F*F)));
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private FactorySticker()
-    {
-
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static FactorySticker getInstance()
-    {
-    if( mThis==null ) mThis = new FactorySticker();
-
-    return mThis;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float computeAngle(float dx, float dy)
-    {
-    float PI = (float)Math.PI;
-    double angle = Math.atan2(dy,dx);
-    float ret = (float)(3*PI/2-angle);
-
-    if( ret>2*PI ) ret-= 2*PI;
-
-    return ret;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void drawCurrVertex(Canvas canvas, Paint paint, int left, int top, float r, float stroke, float pX, float pY, float cX, float cY, float nX, float nY)
-    {
-    pX = (0.5f+pX)*TEXTURE_HEIGHT;
-    pY = (0.5f-pY)*TEXTURE_HEIGHT;
-    cX = (0.5f+cX)*TEXTURE_HEIGHT;
-    cY = (0.5f-cY)*TEXTURE_HEIGHT;
-    nX = (0.5f+nX)*TEXTURE_HEIGHT;
-    nY = (0.5f-nY)*TEXTURE_HEIGHT;
-
-    canvas.drawLine(left+pX,top+pY,left+cX,top+cY,paint);
-
-    float aX = pX-cX;
-    float aY = pY-cY;
-    float bX = cX-nX;
-    float bY = cY-nY;
-
-    float aLen = (float)Math.sqrt(aX*aX+aY*aY);
-    float bLen = (float)Math.sqrt(bX*bX+bY*bY);
-
-    aX /= aLen;
-    aY /= aLen;
-    bX /= bLen;
-    bY /= bLen;
-
-    float sX = (aX-bX)/2;
-    float sY = (aY-bY)/2;
-    float sLen = (float)Math.sqrt(sX*sX+sY*sY);
-    sX /= sLen;
-    sY /= sLen;
-
-    float startAngle = computeAngle(bX,-bY);
-    float endAngle   = computeAngle(aX,-aY);
-    float sweepAngle = endAngle-startAngle;
-    if( sweepAngle<0 ) sweepAngle += 2*Math.PI;
-
-    float R = r*TEXTURE_HEIGHT+stroke/2;
-
-    float A = (float)(R/(Math.cos(sweepAngle/2)));
-
-    float rX = cX + A*sX;
-    float rY = cY + A*sY;
-
-    startAngle *= 180/(Math.PI);
-    sweepAngle *= 180/(Math.PI);
-
-    canvas.drawArc( left+rX-R, top+rY-R, left+rX+R, top+rY+R, startAngle, sweepAngle, false, paint);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int top, float[] vertices, float stroke, int color, float radius)
-    {
-    stroke *= TEXTURE_HEIGHT;
-
-    paint.setAntiAlias(true);
-    paint.setStrokeWidth(stroke);
-    paint.setColor(color);
-    paint.setStyle(Paint.Style.FILL);
-
-    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
-
-    paint.setColor(COLOR_BLACK);
-    paint.setStyle(Paint.Style.STROKE);
-
-    int length = vertices.length;
-    int numVertices = length/2;
-
-    float prevX = vertices[length-2];
-    float prevY = vertices[length-1];
-    float currX = vertices[0];
-    float currY = vertices[1];
-    float nextX = vertices[2];
-    float nextY = vertices[3];
-
-    for(int vert=0; vert<numVertices; vert++)
-      {
-      drawCurrVertex(canvas, paint, left, top, radius, stroke, prevX,prevY,currX,currY,nextX,nextY);
-
-      prevX = currX;
-      prevY = currY;
-      currX = nextX;
-      currY = nextY;
-
-      if( 2*(vert+2)+1 < length )
-        {
-        nextX = vertices[2*(vert+2)  ];
-        nextY = vertices[2*(vert+2)+1];
-        }
-      else
-        {
-        nextX = vertices[0];
-        nextY = vertices[1];
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void drawIvyCornerSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius)
-    {
-    paint.setAntiAlias(true);
-    paint.setColor(color);
-    paint.setStyle(Paint.Style.FILL);
-    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
-
-    paint.setColor(COLOR_BLACK);
-    paint.setStyle(Paint.Style.STROKE);
-    paint.setStrokeWidth(IVY_C*stroke*TEXTURE_HEIGHT);
-
-    float tmp1 = ((IVY_D-0.5f)-IVY_M)*IVY_C;
-    float cx1 = TEXTURE_HEIGHT*(tmp1 + 0.5f);
-    float cy1 = TEXTURE_HEIGHT*(0.5f - tmp1);
-
-    float halfL1 = IVY_C*TEXTURE_HEIGHT*(1.0f-2*IVY_D);
-
-    canvas.drawArc( left+cx1-halfL1, top+cy1-halfL1, left+cx1+halfL1, top+cy1+halfL1, 270, 90, false, paint);
-
-    float tmp2 = (+0.5f-IVY_M)*IVY_C;
-    float tmp3 = (-0.5f-IVY_M)*IVY_C;
-
-    float x0 = TEXTURE_HEIGHT*(+tmp2 + 0.5f);
-    float y0 = TEXTURE_HEIGHT*(-tmp3 + 0.5f);
-    float x1 = TEXTURE_HEIGHT*(+tmp2 + 0.5f);
-    float y1 = TEXTURE_HEIGHT*(-tmp2 + 0.5f);
-    float x2 = TEXTURE_HEIGHT*(+tmp3 + 0.5f);
-    float y2 = TEXTURE_HEIGHT*(-tmp2 + 0.5f);
-
-    canvas.drawLine(left+x0,top+y0,left+x1,top+y1,paint);
-    canvas.drawLine(left+x1,top+y1,left+x2,top+y2,paint);
-
-    float tmp4 = ((0.5f-stroke/2-radius/2)-IVY_M)*IVY_C;
-    float cx2 = TEXTURE_HEIGHT*(tmp4 + 0.5f);
-    float cy2 = TEXTURE_HEIGHT*(0.5f - tmp4);
-
-    float halfL2 = IVY_C*TEXTURE_HEIGHT*radius;
-
-    paint.setStrokeWidth(IVY_C*radius*TEXTURE_HEIGHT);
-    canvas.drawArc( left+cx2-halfL2, top+cy2-halfL2, left+cx2+halfL2, top+cy2+halfL2, 270, 90, false, paint);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void drawIvyCenterSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius)
-    {
-    paint.setAntiAlias(true);
-    paint.setColor(color);
-    paint.setStyle(Paint.Style.FILL);
-    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
-
-    paint.setColor(COLOR_BLACK);
-    paint.setStyle(Paint.Style.STROKE);
-    paint.setStrokeWidth(stroke*TEXTURE_HEIGHT);
-
-    float cx1 = TEXTURE_HEIGHT*IVY_D;
-    float cy1 = TEXTURE_HEIGHT*(1-IVY_D);
-    float cx2 = TEXTURE_HEIGHT*(1.0f-IVY_D);
-    float cy2 = TEXTURE_HEIGHT*IVY_D;
-
-    float halfL = TEXTURE_HEIGHT*(1.0f - 2*IVY_D);
-
-    canvas.drawArc( left+cx1-halfL, top+cy1-halfL, left+cx1+halfL, top+cy1+halfL, 270, 90, false, paint);
-    canvas.drawArc( left+cx2-halfL, top+cy2-halfL, left+cx2+halfL, top+cy2+halfL,  90, 90, false, paint);
-
-    float tmp = TEXTURE_HEIGHT*(IVY_D+stroke*0.5f+radius*0.5f);
-    float cx3 = tmp;
-    float cy3 = tmp;
-    float cx4 = TEXTURE_HEIGHT - cx3;
-    float cy4 = TEXTURE_HEIGHT - cy3;
-    float halfR = TEXTURE_HEIGHT*radius;
-
-    paint.setStrokeWidth(radius*TEXTURE_HEIGHT);
-    canvas.drawArc( left+cx3-halfR, top+cy3-halfR, left+cx3+halfR, top+cy3+halfR, 180, 90, false, paint);
-    canvas.drawArc( left+cx4-halfR, top+cy4-halfR, left+cx4+halfR, top+cy4+halfR,   0, 90, false, paint);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void drawRexCornerSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius1, float radius2)
-    {
-    paint.setColor(color);
-    paint.setStyle(Paint.Style.FILL);
-    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
-
-    paint.setColor(COLOR_BLACK);
-    paint.setStyle(Paint.Style.STROKE);
-    paint.setStrokeWidth(stroke*TEXTURE_HEIGHT);
-
-    float F = REX_D*SQ2;
-    float G = (1-REX_D)*SQ2/2;
-
-    float cx1 = left + (0.5f-F/2)*TEXTURE_HEIGHT;
-    float cx2 = left + (0.5f+F/2)*TEXTURE_HEIGHT;
-    float cy  = top  + (0.5f+G/3)*TEXTURE_HEIGHT;
-
-    canvas.drawLine(cx1, cy, cx2, cy, paint);
-
-    float X   = REX_C-F/2;
-    float R1  = TEXTURE_HEIGHT*(REX_R + 0.5f*stroke);
-    float cx3 = left + (0.5f-X)*TEXTURE_HEIGHT;
-    float cx4 = left + (0.5f+X)*TEXTURE_HEIGHT;
-
-    canvas.drawArc( cx3-R1, cy-R1, cx3+R1, cy+R1, 360-REX_B/2, REX_B/2, false ,paint);
-    canvas.drawArc( cx4-R1, cy-R1, cx4+R1, cy+R1, 180        , REX_B/2, false ,paint);
-
-    float cx5 = left + (0.5f+F/2-radius2)*TEXTURE_HEIGHT;
-    float cx6 = left + (0.5f-F/2+radius2)*TEXTURE_HEIGHT;
-    float cy1 = top  + (0.5f+G/3-radius2)*TEXTURE_HEIGHT;
-    float R2  = TEXTURE_HEIGHT*radius2;
-
-    canvas.drawArc( cx5-R2, cy1-R2, cx5+R2, cy1+R2,  0, 90, false ,paint);
-    canvas.drawArc( cx6-R2, cy1-R2, cx6+R2, cy1+R2, 90, 90, false ,paint);
-
-    float cx7 = left + 0.5f*TEXTURE_HEIGHT;
-    float cy2 = top  + (0.5f-2*G/3 + radius1/REX_S)*TEXTURE_HEIGHT;
-    float R3  = TEXTURE_HEIGHT*(radius1 + 0.5f*stroke);
-    canvas.drawArc( cx7-R3, cy2-R3, cx7+R3, cy2+R3, 270-(90-REX_B/2), 180-REX_B, false ,paint);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void drawRexEdgeSticker(Canvas canvas, Paint paint, int left, int top, int color, float stroke, float radius)
-    {
-    paint.setColor(color);
-    paint.setStyle(Paint.Style.FILL);
-    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
-
-    paint.setColor(COLOR_BLACK);
-    paint.setStyle(Paint.Style.STROKE);
-    paint.setStrokeWidth(stroke*TEXTURE_HEIGHT);
-
-    final float D = ( 0.5f - (0.5f-REX_D)/3);
-    float cx1 = left+ TEXTURE_HEIGHT*(0.5f-REX_X);
-    float cy1 = top + TEXTURE_HEIGHT*(0.5f+REX_X+D);
-    float cx2 = left+ TEXTURE_HEIGHT*(0.5f+REX_X);
-    float R1  = TEXTURE_HEIGHT*REX_R;
-
-    canvas.drawArc( cx1-R1, cy1-R1, cx1+R1, cy1+R1, 315-REX_A-REX_B, REX_B, false ,paint);
-    canvas.drawArc( cx2-R1, cy1-R1, cx2+R1, cy1+R1, 225+REX_A      , REX_B, false ,paint);
-
-    float CORR_Y = radius/12;
-    float CORR_A = 10;
-    float sin = (float)Math.sin(Math.PI*REX_P/180);
-    float cx = left + 0.5f*TEXTURE_HEIGHT;
-    float cy = top  + ( 0.5f + 2*(0.5f-REX_D)/3 -CORR_Y -radius/sin )*TEXTURE_HEIGHT;
-    float R2  = TEXTURE_HEIGHT*radius;
-
-    canvas.drawArc( cx-R2, cy-R2, cx+R2, cy+R2, 90-(REX_P-CORR_A), 2*(REX_P-CORR_A), false ,paint);
-
-    float F = 0.1f;
-    float G = 0.6f;
-    float R3  = TEXTURE_HEIGHT*radius*G*0.9f;
-    float X = G*radius/REX_T;
-    float cx4 = left + X*TEXTURE_HEIGHT;
-    float cx3 = left + (1-X)*TEXTURE_HEIGHT;
-    float cy3 = top + (0.5f - (0.5f-REX_D)/3 + G*radius - F*stroke)*TEXTURE_HEIGHT;
-
-    canvas.drawArc( cx3-R3, cy3-R3, cx3+R3, cy3+R3, 270           , 90+REX_P, false ,paint);
-    canvas.drawArc( cx4-R3, cy3-R3, cx4+R3, cy3+R3, 270-(90+REX_P), 90+REX_P, false ,paint);
-
-    float cy5 = top + D*TEXTURE_HEIGHT;
-
-    paint.setStrokeWidth((1-2*F)*stroke*TEXTURE_HEIGHT);
-    canvas.drawLine(left, cy5, left+TEXTURE_HEIGHT, cy5, paint);
-    }
-  }
diff --git a/src/main/java/org/distorted/objects/MovementMinx.java b/src/main/java/org/distorted/objects/MovementMinx.java
index 2975df64..80ff2e91 100644
--- a/src/main/java/org/distorted/objects/MovementMinx.java
+++ b/src/main/java/org/distorted/objects/MovementMinx.java
@@ -23,8 +23,8 @@ import org.distorted.library.type.Static3D;
 import static org.distorted.objects.TwistyKilominx.C1;
 import static org.distorted.objects.TwistyKilominx.C2;
 import static org.distorted.objects.TwistyKilominx.LEN;
-import static org.distorted.objects.FactoryCubit.SIN54;
-import static org.distorted.objects.FactoryCubit.COS54;
+import static org.distorted.helpers.FactoryCubit.SIN54;
+import static org.distorted.helpers.FactoryCubit.COS54;
 import static org.distorted.objects.TwistyObject.SQ5;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java b/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
index 0cdcf2e6..a355f2fe 100644
--- a/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
+++ b/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
diff --git a/src/main/java/org/distorted/objects/TwistyCube.java b/src/main/java/org/distorted/objects/TwistyCube.java
index 74f8e90d..ab20c361 100644
--- a/src/main/java/org/distorted/objects/TwistyCube.java
+++ b/src/main/java/org/distorted/objects/TwistyCube.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
diff --git a/src/main/java/org/distorted/objects/TwistyDiamond.java b/src/main/java/org/distorted/objects/TwistyDiamond.java
index cfbde6aa..021865c2 100644
--- a/src/main/java/org/distorted/objects/TwistyDiamond.java
+++ b/src/main/java/org/distorted/objects/TwistyDiamond.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
diff --git a/src/main/java/org/distorted/objects/TwistyDino.java b/src/main/java/org/distorted/objects/TwistyDino.java
index 1afcf646..bf3cf4bc 100644
--- a/src/main/java/org/distorted/objects/TwistyDino.java
+++ b/src/main/java/org/distorted/objects/TwistyDino.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
diff --git a/src/main/java/org/distorted/objects/TwistyHelicopter.java b/src/main/java/org/distorted/objects/TwistyHelicopter.java
index 2553b7cd..408393c5 100644
--- a/src/main/java/org/distorted/objects/TwistyHelicopter.java
+++ b/src/main/java/org/distorted/objects/TwistyHelicopter.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
diff --git a/src/main/java/org/distorted/objects/TwistyIvy.java b/src/main/java/org/distorted/objects/TwistyIvy.java
index 9ddc5b6c..146aaa60 100644
--- a/src/main/java/org/distorted/objects/TwistyIvy.java
+++ b/src/main/java/org/distorted/objects/TwistyIvy.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
diff --git a/src/main/java/org/distorted/objects/TwistyKilominx.java b/src/main/java/org/distorted/objects/TwistyKilominx.java
index d5e01ea8..34befa71 100644
--- a/src/main/java/org/distorted/objects/TwistyKilominx.java
+++ b/src/main/java/org/distorted/objects/TwistyKilominx.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
@@ -33,10 +35,10 @@ import org.distorted.library.type.Static4D;
 import org.distorted.main.R;
 import org.distorted.main.RubikSurfaceView;
 
-import static org.distorted.objects.FactoryCubit.COS18;
-import static org.distorted.objects.FactoryCubit.COS54;
-import static org.distorted.objects.FactoryCubit.SIN18;
-import static org.distorted.objects.FactoryCubit.SIN54;
+import static org.distorted.helpers.FactoryCubit.COS18;
+import static org.distorted.helpers.FactoryCubit.COS54;
+import static org.distorted.helpers.FactoryCubit.SIN18;
+import static org.distorted.helpers.FactoryCubit.SIN54;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/objects/TwistyMegaminx.java b/src/main/java/org/distorted/objects/TwistyMegaminx.java
index 8fe9b057..66372391 100644
--- a/src/main/java/org/distorted/objects/TwistyMegaminx.java
+++ b/src/main/java/org/distorted/objects/TwistyMegaminx.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
@@ -33,10 +35,10 @@ import org.distorted.library.type.Static4D;
 import org.distorted.main.R;
 import org.distorted.main.RubikSurfaceView;
 
-import static org.distorted.objects.FactoryCubit.COS18;
-import static org.distorted.objects.FactoryCubit.COS54;
-import static org.distorted.objects.FactoryCubit.SIN18;
-import static org.distorted.objects.FactoryCubit.SIN54;
+import static org.distorted.helpers.FactoryCubit.COS18;
+import static org.distorted.helpers.FactoryCubit.COS54;
+import static org.distorted.helpers.FactoryCubit.SIN18;
+import static org.distorted.helpers.FactoryCubit.SIN54;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/objects/TwistyObject.java b/src/main/java/org/distorted/objects/TwistyObject.java
index d3c784f9..cb9b2e10 100644
--- a/src/main/java/org/distorted/objects/TwistyObject.java
+++ b/src/main/java/org/distorted/objects/TwistyObject.java
@@ -58,17 +58,17 @@ import java.util.Random;
 
 public abstract class TwistyObject extends DistortedNode
   {
-  static final int COLOR_YELLOW = 0xffffff00;
-  static final int COLOR_WHITE  = 0xffffffff;
-  static final int COLOR_BLUE   = 0xff0000ff;
-  static final int COLOR_GREEN  = 0xff00bb00;
-  static final int COLOR_RED    = 0xff990000;
-  static final int COLOR_ORANGE = 0xffff6200;
-  static final int COLOR_GREY   = 0xff727c7b;
-  static final int COLOR_VIOLET = 0xff7700bb;
-  static final int COLOR_BLACK  = 0xff000000;
-
-  static final int TEXTURE_HEIGHT = 256;
+  public static final int COLOR_YELLOW = 0xffffff00;
+  public static final int COLOR_WHITE  = 0xffffffff;
+  public static final int COLOR_BLUE   = 0xff0000ff;
+  public static final int COLOR_GREEN  = 0xff00bb00;
+  public static final int COLOR_RED    = 0xff990000;
+  public static final int COLOR_ORANGE = 0xffff6200;
+  public static final int COLOR_GREY   = 0xff727c7b;
+  public static final int COLOR_VIOLET = 0xff7700bb;
+  public static final int COLOR_BLACK  = 0xff000000;
+
+  public static final int TEXTURE_HEIGHT = 256;
   static final int NUM_STICKERS_IN_ROW = 4;
 
   static final float SQ2 = (float)Math.sqrt(2);
diff --git a/src/main/java/org/distorted/objects/TwistyPyraminx.java b/src/main/java/org/distorted/objects/TwistyPyraminx.java
index c892a99b..f0bc098d 100644
--- a/src/main/java/org/distorted/objects/TwistyPyraminx.java
+++ b/src/main/java/org/distorted/objects/TwistyPyraminx.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
diff --git a/src/main/java/org/distorted/objects/TwistyRedi.java b/src/main/java/org/distorted/objects/TwistyRedi.java
index 2853dd87..a256174f 100644
--- a/src/main/java/org/distorted/objects/TwistyRedi.java
+++ b/src/main/java/org/distorted/objects/TwistyRedi.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
diff --git a/src/main/java/org/distorted/objects/TwistyRex.java b/src/main/java/org/distorted/objects/TwistyRex.java
index e634f275..0e84e025 100644
--- a/src/main/java/org/distorted/objects/TwistyRex.java
+++ b/src/main/java/org/distorted/objects/TwistyRex.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
@@ -35,7 +37,7 @@ import org.distorted.main.RubikSurfaceView;
 
 import java.util.Random;
 
-import static org.distorted.objects.FactoryCubit.REX_D;
+import static org.distorted.helpers.FactoryCubit.REX_D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/objects/TwistySkewb.java b/src/main/java/org/distorted/objects/TwistySkewb.java
index 925e9634..9fef5f5c 100644
--- a/src/main/java/org/distorted/objects/TwistySkewb.java
+++ b/src/main/java/org/distorted/objects/TwistySkewb.java
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffect;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.effect.MatrixEffectScale;
