commit be56193c0b4297d7f8b9e08091a6058eb2bd9ab7
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Apr 20 00:28:00 2021 +0200

    Move all the special cubit-creating code out of FactoryCubit and to the Object classes, and thus hopefully finish implementing the new cubit creating engine.

diff --git a/src/main/java/org/distorted/helpers/FactoryCubit.java b/src/main/java/org/distorted/helpers/FactoryCubit.java
index ac101273..f4f3c248 100644
--- a/src/main/java/org/distorted/helpers/FactoryCubit.java
+++ b/src/main/java/org/distorted/helpers/FactoryCubit.java
@@ -24,9 +24,6 @@ import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.effect.MatrixEffectScale;
 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;
@@ -40,19 +37,9 @@ import java.util.ArrayList;
 
 public class FactoryCubit
   {
-  private static final float SQ2 = (float)Math.sqrt(2);
   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;
-
   private static final double[] mBuffer = new double[3];
   private static final double[] mQuat1  = new double[4];
   private static final double[] mQuat2  = new double[4];
@@ -150,581 +137,6 @@ public class FactoryCubit
     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 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);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  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[] 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[] 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
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  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 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;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private boolean areColinear(double[][] vertices, int index1, int index2, int index3)
@@ -1249,6 +661,78 @@ public class FactoryCubit
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC
 
+  public 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;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public 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);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
   public void printStickerCoords()
     {
     int stickers = mStickerCoords.size();
diff --git a/src/main/java/org/distorted/helpers/FactorySticker.java b/src/main/java/org/distorted/helpers/FactorySticker.java
index 53d780e6..2416e2f2 100644
--- a/src/main/java/org/distorted/helpers/FactorySticker.java
+++ b/src/main/java/org/distorted/helpers/FactorySticker.java
@@ -24,10 +24,10 @@ 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;
+import static org.distorted.objects.TwistyIvy.IVY_D;
+import static org.distorted.objects.TwistyIvy.IVY_C;
+import static org.distorted.objects.TwistyIvy.IVY_M;
+import static org.distorted.objects.TwistyRex.REX_D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java b/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
index a355f2fe..d4a048cf 100644
--- a/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
+++ b/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
@@ -26,10 +26,17 @@ import android.graphics.Paint;
 import org.distorted.helpers.FactoryCubit;
 import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
+import org.distorted.library.effect.VertexEffect;
+import org.distorted.library.effect.VertexEffectMove;
+import org.distorted.library.effect.VertexEffectRotate;
+import org.distorted.library.effect.VertexEffectScale;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshJoined;
+import org.distorted.library.mesh.MeshPolygon;
 import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
@@ -183,6 +190,157 @@ abstract class TwistyBandagedAbstract extends TwistyObject
     return ( cubit>=0 && cubit< indices.length ) ? indices[cubit] : 0;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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 };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private MeshBase createCuboid(int[] dimensions)
+    {
+    FactoryCubit factory = FactoryCubit.getInstance();
+
+    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 = factory.computeBands( defHeight/X,65,0.25f,0.5f,5);
+    float[] bandsY = factory.computeBands( defHeight/Y,65,0.25f,0.5f,5);
+    float[] bandsZ = factory.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);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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;
+    FactoryCubit factory = FactoryCubit.getInstance();
+
+    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));
+    factory.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));
+    factory.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));
+    factory.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));
+    factory.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));
+    factory.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));
+    factory.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));
+    factory.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));
+    factory.roundCorners(mesh, center, vertices, strength, radius);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MeshBase createCubitMesh(int cubit, int numLayers)
@@ -194,7 +352,7 @@ abstract class TwistyBandagedAbstract extends TwistyObject
 
       for(int i=0; i<LEN; i++)
         {
-        mMeshes[i] = FactoryCubit.getInstance().createCuboidMesh(mDimensions[i]);
+        mMeshes[i] = createCuboidMesh(mDimensions[i]);
         }
       }
 
diff --git a/src/main/java/org/distorted/objects/TwistyIvy.java b/src/main/java/org/distorted/objects/TwistyIvy.java
index 11269b32..7c978d33 100644
--- a/src/main/java/org/distorted/objects/TwistyIvy.java
+++ b/src/main/java/org/distorted/objects/TwistyIvy.java
@@ -26,10 +26,17 @@ import android.graphics.Paint;
 import org.distorted.helpers.FactoryCubit;
 import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
+import org.distorted.library.effect.VertexEffect;
+import org.distorted.library.effect.VertexEffectMove;
+import org.distorted.library.effect.VertexEffectRotate;
+import org.distorted.library.effect.VertexEffectScale;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshJoined;
+import org.distorted.library.mesh.MeshPolygon;
 import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 import org.distorted.main.R;
@@ -40,6 +47,11 @@ import java.util.Random;
 
 public class TwistyIvy extends TwistyObject
 {
+  public static final float IVY_D = 0.003f;
+  public static final float IVY_C = 0.59f;
+  public static final float IVY_M = 0.35f;
+  private static final int IVY_N = 8;
+
   private static final int FACES_PER_CUBIT =6;
 
   // the four rotation axis of a RubikIvy. Must be normalized.
@@ -198,6 +210,156 @@ public class TwistyIvy extends TwistyObject
     return 0;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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;
+      }
+
+    FactoryCubit factory = FactoryCubit.getInstance();
+    float[] bands0 = factory.computeBands(+0.012f,20,0.2f,0.5f,7);
+    float[] bands1 = factory.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);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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);
+      }
+
+    FactoryCubit factory = FactoryCubit.getInstance();
+    float[] bands0 = factory.computeBands(+0.03f,35,0.5f,0.5f,5);
+    float[] bands1 = factory.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);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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);
+
+    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.03f,0.10f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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);
+
+    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.03f,0.10f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MeshBase createCubitMesh(int cubit, int numLayers)
@@ -206,12 +368,12 @@ public class TwistyIvy extends TwistyObject
 
     if( cubit<4 )
       {
-      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createIvyCornerMesh();
+      if( mCornerMesh==null ) mCornerMesh = createIvyCornerMesh();
       mesh = mCornerMesh.copy(true);
       }
     else
       {
-      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createIvyFaceMesh();
+      if( mFaceMesh==null ) mFaceMesh = createIvyFaceMesh();
       mesh = mFaceMesh.copy(true);
       }
 
diff --git a/src/main/java/org/distorted/objects/TwistyRex.java b/src/main/java/org/distorted/objects/TwistyRex.java
index 7527e220..af03ceda 100644
--- a/src/main/java/org/distorted/objects/TwistyRex.java
+++ b/src/main/java/org/distorted/objects/TwistyRex.java
@@ -26,24 +26,31 @@ import android.graphics.Paint;
 import org.distorted.helpers.FactoryCubit;
 import org.distorted.helpers.FactorySticker;
 import org.distorted.library.effect.MatrixEffectQuaternion;
+import org.distorted.library.effect.VertexEffect;
+import org.distorted.library.effect.VertexEffectMove;
+import org.distorted.library.effect.VertexEffectRotate;
+import org.distorted.library.effect.VertexEffectScale;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshJoined;
+import org.distorted.library.mesh.MeshPolygon;
 import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 import org.distorted.main.R;
 
 import java.util.Random;
 
-import static org.distorted.helpers.FactoryCubit.REX_D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class TwistyRex extends TwistyObject
 {
   private static final int FACES_PER_CUBIT =6;
 
+  public static final float REX_D = 0.2f;
+
   // the four rotation axis of a RubikRex. Must be normalized.
   static final Static3D[] ROT_AXIS = new Static3D[]
          {
@@ -299,6 +306,211 @@ public class TwistyRex extends TwistyObject
     return QUATS[0];
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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};
+
+    FactoryCubit factory = FactoryCubit.getInstance();
+    float[] bands0 = factory.computeBands(+0.016f,10,G/3,0.5f,5);
+    float[] bands1 = factory.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};
+
+    FactoryCubit factory = FactoryCubit.getInstance();
+    float[] bands0 = factory.computeBands(0.016f,10,REX_D/2,0.5f,5);
+    float[] bands1 = factory.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];
+    FactoryCubit factory = FactoryCubit.getInstance();
+
+    float E = 0.5f - REX_D;
+    float F = 0.5f;
+    float[] vertices0 = { -F,E/3, 0,-2*E/3, +F,E/3 };
+    float[] bands0 = factory.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 = factory.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);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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);
+    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.10f,0.10f);
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private MeshBase createRexFaceMesh()
+    {
+    MeshBase mesh = createFacesRexFace();
+
+    mesh.mergeEffComponents();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+    mesh.addEmptyTexComponent();
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private 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);
+    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.06f,0.10f);
+
+    mesh.mergeEffComponents();
+
+    return mesh;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MeshBase createCubitMesh(int cubit, int numLayers)
@@ -307,17 +519,17 @@ public class TwistyRex extends TwistyObject
 
     if( cubit<24 )
       {
-      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createRexCornerMesh();
+      if( mCornerMesh==null ) mCornerMesh = createRexCornerMesh();
       mesh = mCornerMesh.copy(true);
       }
     else if( cubit<30 )
       {
-      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createRexFaceMesh();
+      if( mFaceMesh==null ) mFaceMesh = createRexFaceMesh();
       mesh = mFaceMesh.copy(true);
       }
     else
       {
-      if( mEdgeMesh==null ) mEdgeMesh = FactoryCubit.getInstance().createRexEdgeMesh();
+      if( mEdgeMesh==null ) mEdgeMesh = createRexEdgeMesh();
       mesh = mEdgeMesh.copy(true);
       }
 
diff --git a/src/main/java/org/distorted/objects/TwistySkewb.java b/src/main/java/org/distorted/objects/TwistySkewb.java
index 7fff3572..cbd862ad 100644
--- a/src/main/java/org/distorted/objects/TwistySkewb.java
+++ b/src/main/java/org/distorted/objects/TwistySkewb.java
@@ -167,12 +167,10 @@ public class TwistySkewb extends TwistyObject
              {4,0,3}
           };
 
-
   private static final float[][] STICKERS = new float[][]
           {
-             { -0.5f,   0.25f, 0.25f,  -0.5f, 0.25f, 0.25f  },
-             {  0.0f, -1.0f/3, 0.50f, 1.0f/6, -0.5f, 1.0f/6 },
-             { -0.5f,    0.0f, 0.00f,  -0.5f, 0.50f, 0.0f, 0.0f, 0.5f }
+             { -0.5f, 0.25f, 0.25f,  -0.5f, 0.25f, 0.25f  },
+             { -0.5f, 0.00f, 0.00f,  -0.5f, 0.50f, 0.0f, 0.0f, 0.5f }
           };
 
   private static MeshBase[] mMeshes;
@@ -583,17 +581,17 @@ public class TwistySkewb extends TwistyObject
     {
     int COLORS = FACE_COLORS.length;
     float R=0.0f,S=0.0f;
-    int cubitType = face/COLORS;
+    int index=0, cubitType = face/COLORS;
 
     switch(cubitType)
       {
-      case 0: R = 0.025f; S = 0.045f; break;
-      case 1: R = 0.025f; S = 0.035f; break;
-      case 2: R = 0.055f; S = 0.035f; break;
+      case 0: R = 0.025f; S = 0.045f; index= 0; break;
+      case 1: R = 0.025f; S = 0.035f; index= 0; break;
+      case 2: R = 0.055f; S = 0.035f; index= 1; break;
       }
 
     FactorySticker factory = FactorySticker.getInstance();
-    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[cubitType], S, FACE_COLORS[face%COLORS], R);
+    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[index], S, FACE_COLORS[face%COLORS], R);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
