class Kishimen extends Ribbon3D {
  public function new( p0_0:Array< Point3D >,
                       p0_1:Array< Point3D >,
                       p1_0:Array< Point3D >,
                       p1_1:Array< Point3D > ) {
    super( null, null );
    initKishimen( p0_0, p0_1, p1_0, p1_1 );
  }

  public function initKishimen( p0_0:Array< Point3D >,
                                p0_1:Array< Point3D >,
                                p1_0:Array< Point3D >,
                                p1_1:Array< Point3D > ) {
    if ( p0_0.length != p0_1.length ||
         p1_0.length != p1_1.length ||
         p0_0.length != p1_0.length ||
         p0_0 == null ) {
      trace( "NewRibbon: invalid call" );
      return;
    }
    var num = p0_0.length;
    // plane 0
    for ( p in p0_0 ) addVertexPos( p );
    for ( p in p1_0 ) addVertexPos( p );
    // plane 1
    for ( p in p0_1 ) addVertexPos( p );
    for ( p in p1_1 ) addVertexPos( p );
    // plane 2
    for ( p in p0_0 ) addVertexPos( p );
    for ( p in p0_1 ) addVertexPos( p );
    // plane 3
    for ( p in p1_0 ) addVertexPos( p );
    for ( p in p1_1 ) addVertexPos( p );
    // bottom
    addVertexPos( p0_0[0] );
    addVertexPos( p0_1[0] );
    addVertexPos( p1_0[0] );
    addVertexPos( p1_1[0] );
    // top
    addVertexPos( p0_0[num-1] );
    addVertexPos( p0_1[num-1] );
    addVertexPos( p1_0[num-1] );
    addVertexPos( p1_1[num-1] );

    var duv:Float = 1.0 / ( num - 1 );
    var u0:Array< UVCoord > = new Array< UVCoord >();
    var u1:Array< UVCoord > = new Array< UVCoord >();
    for ( i in 0 ... num ) {
      u0.push( new UVCoord( duv * i, 0.0 ) );
      u1.push( new UVCoord( duv * i, 1.0 ) );
    }
    for ( i in 0 ... num - 1 ) {
      var j = i + num;
      var k = j + num;
      var l = k + num;
      var m = l + num;
      var n = m + num;
      var o = n + num;
      var p = o + num;
      // plane 0
      addFace( new Face( i, j+1, i+1, u0[i], u1[i+1], u0[i+1] ) );
      addFace( new Face( j, j+1, i, u1[i], u1[i+1], u0[i] ) );
      // plane 1
      addFace( new Face( k, k+1, l+1, u0[i], u0[i+1], u1[i+1] ) );
      addFace( new Face( l, k, l+1, u1[i], u0[i], u1[i+1] ) );
      // plane 2
      addFace( new Face( m, m+1, n+1, u0[i], u0[i+1], u1[i+1] ) );
      addFace( new Face( n, m, n+1, u1[i], u0[i], u1[i+1] ) );
      // plane 3
      addFace( new Face( o, p+1, o+1, u0[i], u1[i+1], u0[i+1] ) );
      addFace( new Face( p, p+1, o, u1[i], u1[i+1], u0[i] ) );
    }
    var num8 = num * 8;
    var num8p4 = num8 + 4;
    // bottom
    addFace( new Face( num8, num8 + 1, num8 + 2, u0[0], u0[1], u1[0] ) );
    addFace( new Face( num8 + 2, num8 + 1, num8 + 3, u1[0], u0[1], u1[1] ) );
    addFace( new Face( num8p4, num8p4 + 2, num8p4 + 1, u0[num-2], u1[num-2], u0[num-1] ) );
    addFace( new Face( num8p4 + 2, num8p4 + 3, num8p4 + 1, u1[num-2], u1[num-1], u0[num-1] ) );
  }
}
