#!BPY

"""
Name: 'Skin_Armature'
Blender: 248
Group: 'Wizards'
Tooltip: 'Automatic Skinning of Armatures'
"""

__author__ = ["Leif Dehmelt"]
__url__ = ("blender", "elysiun", "http://www.gravity-music.net/skinny/")
__version__ = "0.8a"
__bpydoc__ = """\

Skinny 0.8alpha

This script automatically generates rigged and UV-mapped meshes for armatures.

Armatures need to be setup in a specific way for the skinning process to work correctly. Check out the tutorial
on http://www.gravity-music.net/skinny/ to find out what is possible.

The setup rules might seem highly restrictive, but in practice, many organic shapes can be formed with this
version of the script.

General script instructions:

1) Install by copying to the Blender scripts folder.
2) Start Skinny from the Scripts Window by clicking: Scripts > Wizards > Skinny
3) Set up an armature based on the rules described below - select it before starting the script
4) click on the Skinny button to bring up the options pop-up gui
5) setup the desired options
6) click OK to generate a rigged mesh

General mesh generation options:

The thickness of the resulting mesh can be setup by different options. By default, the values
"boneseg1-3 size" define the thickness in each of the three sub-segments assigned to each bone
segment. The values "boneseg1-3 pos" define the relative shift of these three sub-segments.
Alternatively, the segmentsize can be defined by changing the envelope size of the bone head and
tail, to enable full control over the mesh dimensions. THis mode is enabled by checking the
"envelope mod" button. Third, by checking the "length mod" button, the bone thickness is
modulated in proportion with the bone length.

Automatic mode can be used to generate meshes from armatures setup in all three dimensions (see
below for details on setup rules). The value "auto steps" defines the resolution of the mesh
optimization and is only relevant for automatic mode.

Armature setup rules:

1) Only three armature connectivities are allowed:
   -simple connections with one child bone
   -T-crossings, in which one bone has two children
   -X-crossings, in which one bone has three children

2) Bone Crossings need to be setup in the correct order:
   1. Bone: the child bone that forms a (more or less) straight line with the parent bone
   2. Bone: the child bone to the left side of the line from parent to the first child bone
   optional 3. Bone: the child bone to the right side of the line from parent to the first child bone

   If this order is not taken into account, the mesh will most likely be twisted in the crossing
   point.
   
3) In default mode, the armature needs to be confined in the x-y plane. In default mode, it is easier
   to get a clean, symmetric mesh, most useful for humanoid characters or other bilateral symmetrical
   figures (insects, mammals, etc). If the armature is best setup in three dimensions, automatic mode
   can be switched on in the pop-up gui, to enable easier modeling of non-bilateral structures, such
   as plants.

The above rules are fairly easy and sufficient for most simple armatures. The overall resolution of
the resulting figure can easily be increased by using the subsurf modifier. However, if you need
to have more control over the mesh resolution in particular parts of the mesh you can use the built-in
Edit Bones tool to optimize your mesh.

4) The default resolution of the resulting mesh is 3 rings made up of 6 circularly arranged vertices
   each per bone. If higher or lower resolution is desired, the resolution can be set using the edit bones
   tool. The following values can be set for each bone:
   
   name: the name of the bone

   res: the circular resolution in mesh segments (must be an even number)

   twist: a circular twist modifier to modulate attachemnet of branch segments to stem segements. Can maximally
          be 1/2 of the stem resolution.

   shift: a parallel shift to modulate attachement of branch segments to stem segements. Can only be used, if
          the resolution of the branch segement is lower than the resoltion of the stem segment.

   ori: orientation fix. can be L or R for left or right side attachement of a branch to a stem segment.
        Default value is L. If the skinny mesh is irregular in shape, try to change this modifier to R.
   

   the bone name: 6_1_arm1 tells the script, that this bone should recieve 6 vertices on each of the 3 rings,
       and additionally, if this bone is branching off from another bone in a crossing (i.e., if it is either
       2. Bone or 3. Bone accoring to rule 3 above), this bone should be be placed at position 1 in the parent
       mesh. The meaning of position is probably best understood by experimenting. In brief: if the parent bone
       has the same resolution as a branching child bone, the position cannot be different from 0. If the parent
       bone resolution is higher, than the child bone, the position value can be used to shift the linkage
       position of the branching child to the parent.

   If non-default resolution is used, you need to make sure, that only even mesh resolutions higher than 4 are
   used. This version allows resolution changes for all bone connections, except for Bone 1 (the bone
   straight to the parent bone) in a crossing. The resolution change in a crossing also needs to be symmetrical
   (i.e.) same resolution for both branches. Finally, only lower or equal resolutions in child bones of crossings
   is supported. I simple connections, both higher and lower resolutions can be choosen for child bone segments.
   However, the maximal size change allowed is 4 segments per bone segment.

"""

# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Leif Dehmelt
#
# This program 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.
#
# This program 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 this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------


######################################################
# Importing modules
######################################################

import Blender
from Blender import NMesh, Scene, Object, Draw, Image, Material, BGL
from Blender import Armature as A
from Blender.Mathutils import *
from Blender import *
#

import math
import string
from math import *

#globals:
#mesh_segs sets the standard mesh resolution for bones with unspecified resolution
#pos_segs sets the number of circular vertice arrays around each bone
#pos_segs cannot be any different from 3 in this version of the script

mesh_segs=6

pos_segs=3

seg_pos1=0.25
seg_pos2=0.5
seg_pos3=0.75

seg_size1=1.0
seg_size2=1.0
seg_size3=1.0

active_bone=0
active_vert=0

def_env=0
def_size=0
def_method=0
max_bones=0

#vert_dict holds the number of vertex 0 of the given bone_id
#bone_dict holds the bone name of the given bone_id

vert_dict=[]
bone_dict=[]
bone_stack=[]

Utiles=1
Vtiles=1

Utiles_space=0.0
Vtiles_space=0.0

#helper functions to extract linking information from the bone names

#return the bone_id of a given bone name

def get_bone_id(bone_name):
    bone_id=0
    return_value=-1
    for bone in armData.bones.values():
        if bone_dict[bone_id]==bone_name:
           return_value=bone_id
        bone_id=bone_id+1
    return return_value

def get_info(name_str,test_key):
    success=0
    test_val=0
    bone_name_list=name_str.split("_")
    for bone_name in bone_name_list:
        keyval=bone_name.split(":")
        if keyval[0]==test_key:
           success=1
           test_val=keyval[1]
    if success==0:
       if test_key=="n":
          test_val=name_str
       if test_key=="r":
          test_val=mesh_segs
       if test_key=="o":
          test_val="none"
       if test_key=="w":
          test_val=1
       if test_key=="x":
          test_val=1
    return test_val
    
def has_info(name_str,test_key):
    success=0
    bone_name_list=name_str.split("_")
    for bone_name in bone_name_list:
        keyval=bone_name.split(":")
        if keyval[0]==test_key:
           success=1
    return success

def segment_number(name_str):
    bone_name_list=name_str.split("_")
    segment_num=mesh_segs
    if len(bone_name_list)>1:
       if bone_name_list[1].isdigit():
          segment_num=int(bone_name_list[1])
    return segment_num

def segment_position(name_str):
    bone_name_list=name_str.split("_")
    segment_num=0
    if len(bone_name_list)>2:
       if bone_name_list[2].isdigit():
          segment_num=int(bone_name_list[2])
    return segment_num

def segment_twist(name_str):
    bone_name_list=name_str.split("_")
    segment_num=0
    if len(bone_name_list)>3:
       if bone_name_list[3].isdigit():
          segment_num=int(bone_name_list[3])
    return segment_num

def segment_ori(name_str):
    ori="none"
    bone_name_list=name_str.split("_")
    if len(bone_name_list)>4:
       if bone_name_list[4]=='L':
          ori="left"
       if bone_name_list[4]=='R':
          ori="right"
    return ori

def armature_origin(seed_bone):
    bone_test=seed_bone
    while bone_test.hasParent():
          bone_parent=bone_test.parent
          bone_test=bone_parent
    return bone_test

def is_not_origin(testbone):
    return_value=0
    if testbone.hasParent():
       return_value=1
    return return_value

#RotatePvec rotates a point(x,y,z) around a line drawn between (a,b,c) and (u,v,w) by the angle (ang)

def RotatePvec(x,y,z,a,b,c,u,v,w,ang):
    ux=u*x
    uy=u*y
    uz=u*z
    vx=v*x
    vy=v*y
    vz=v*z
    wx=w*x
    wy=w*y
    wz=w*z
    ax=a*x
    ay=a*y
    az=a*z
    bx=b*x
    by=b*y
    bz=b*z
    cx=c*x
    cy=c*y
    cz=c*z
    au=a*u
    av=a*v
    aw=a*w
    bu=b*u
    bv=b*v
    bw=b*w
    cu=c*u
    cv=c*v
    cw=c*w
    vvww=v*v+w*w
    uuww=u*u+w*w
    uuvv=u*u+v*v
    
    sa=math.sin(ang)
    ca=math.cos(ang)
    unit1=(u*u+v*v+w*w)
    unit2=math.sqrt(unit1)
    return [
    (a*vvww+u*(-bv-cw+ux+vy+wz)+((x-a)*vvww+u*(bv+cw-vy-wz))*ca+unit2*(bw-cv-wy+vz)*sa)/unit1,
    (b*uuww+v*(-au-cw+ux+vy+wz)+((y-b)*uuww+v*(au+cw-ux-wz))*ca+unit2*(-aw+cu+wx-uz)*sa)/unit1,
    (c*uuvv+w*(-au-bv+ux+vy+wz)+((z-c)*uuvv+w*(au+bv-ux-vy))*ca+unit2*(av-bu-vx+uy)*sa)/unit1,
    ]

#assign weights to a bone

def make_weights(bone1, seg1,bone_name, extend_segs):
    vertList = []
    for loop in range(0, extend_segs):
        vertList.append(blender_mesh.verts[vert_dict[bone1]+loop+(extend_segs*seg1)].index)
    blender_mesh.addVertGroup(bone_name)
    #print vertList
    blender_mesh.assignVertsToGroup(bone_name, vertList, 1, 'add')

#draw vertices around a bone in a circular fashion
#this function need the bone start and end position vstart, vend
#the bone_id, the current active vertex number for later referencing
#the bone name and the number of segments to be drawn around the bone
#each single bone always has a fixed circular mesh resolution

def draw_mesh(vstart, vend, bone_id, active_vert,bone_name, extend_segs, env_start, env_end, seg_pos1, seg_pos2, seg_pos3, seg_size1, seg_size2, seg_size3, def_env, def_size, def_method, this_bone, angle_mod, angle_steps):

    vbone=Vector(vend)-Vector(vstart)
    vbone_length=math.sqrt(vbone[0]*vbone[0]+vbone[1]*vbone[1]+vbone[2]*vbone[2])
    if def_method==1:
       norm1 = Vector([0,0,1])
       norm2 = Vector([0,1,0])
       if(AngleBetweenVecs(vbone,norm1)>0.1):
                                             vboneup=CrossVecs(vbone, norm1)
       else:
            vboneup=CrossVecs(vbone, norm2)
       vboneup.normalize()
       vboneup_normx=vboneup[0]
       vboneup_normy=vboneup[1]
       vboneup_normz=vboneup[2]
    else:
         vboneup_normx=0
         vboneup_normy=0
         vboneup_normz=1

    max_angle=0
    if def_method==1:
       #print "bone_id", bone_id
       #print "   bone_name", this_bone.name
       #print "   bone_parent_name", this_bone.parent.name
       if bone_id!=0:
          if is_not_origin(this_bone):
             extend_segs2=int(get_info(this_bone.parent.name,"r"))
             max_length=10000000
             vmid=vstart+vbone*0.5
             #print this_bone.name
             #print this_bone.parent.name
             #print "get_bone_id",get_bone_id(this_bone.parent.name)
             for angle_step in range(0, angle_steps):
                 cum_length=0
                 angle_shift=(angle_mod*6.283185307179586476925286766559/360)+angle_step*6.283185307179586476925286766559/angle_steps
                 for loop in range(0, extend_segs):
                     connect_seg=int(loop*(extend_segs2/extend_segs))
                     vmid2x=vmid[0]+vboneup_normx*(seg_size2)
                     vmid2y=vmid[1]+vboneup_normy*(seg_size2)
                     vmid2z=vmid[2]+vboneup_normz*(seg_size2)
                     connect_seg2=1
                     start_vec=RotatePvec(vmid2x,vmid2y,vmid2z,vstart[0],vstart[1],vstart[2],vstart[0]-vend[0],vstart[1]-vend[1],vstart[2]-vend[2],angle_shift+(loop+0.5)*(6.283185307179586476925286766559/extend_segs))
                     end_vec=blender_mesh.verts[vert_dict[get_bone_id(this_bone.parent.name)]+connect_seg+(int(get_info(this_bone.parent.name,"r"))*2)].co
                     connection=Vector(end_vec)-Vector(start_vec)
                     cum_length=cum_length+connection.length
                 #print "step", angle_step
                 #print "CUM_LENGTH", cum_length
                 if cum_length<max_length:
                    max_length=cum_length
                    max_angle=angle_shift
                 #print "max_angle", max_angle








    for positions in range(0, 3):
        if positions==0:
           vmid=vstart+vbone*float(seg_pos1)
           if def_env==1:
              shift_factor=env_start
           else:
                shift_factor=seg_size1
        if positions==1:
           vmid=vstart+vbone*float(seg_pos2)
           if def_env==1:
              shift_factor=(env_start+env_end)/2
           else:
                shift_factor=seg_size2
        if positions==2:
           vmid=vstart+vbone*float(seg_pos3)
           if def_env==1:
              shift_factor=env_end
           else:
                shift_factor=seg_size3
        if def_size==1:
           shift_factor=shift_factor*vbone_length*0.2
        else:
             if def_env==0:
                shift_factor=shift_factor*0.2
        for angle in range(0, extend_segs):
            if def_env==1:
                          vmid2x=vmid[0]+vboneup_normx*(shift_factor)
                          vmid2y=vmid[1]+vboneup_normy*(shift_factor)
                          vmid2z=vmid[2]+vboneup_normz*(shift_factor)
            else:
                 vmid2x=vmid[0]+vboneup_normx*(shift_factor)
                 vmid2y=vmid[1]+vboneup_normy*(shift_factor)
                 vmid2z=vmid[2]+vboneup_normz*(shift_factor)
            vrot=RotatePvec(vmid2x,vmid2y,vmid2z,vstart[0],vstart[1],vstart[2],vstart[0]-vend[0],vstart[1]-vend[1],vstart[2]-vend[2],max_angle+(angle+0.5)*(6.283185307179586476925286766559/extend_segs))
            v=NMesh.Vert(vrot[0], vrot[1], vrot[2])
            v.uvco[0]=(1*float(positions)/float(3))
            v.uvco[1]=(1*float(angle)/float(extend_segs))
            blender_mesh.verts.append(v)

#helper function to calculate the 'point-mirrored' segement position of a given
#circular vertec array
            
def m_op(point,e_seg):
    return (e_seg-1)-point
    
#helper function to calculate the 'point-mirrored' segement position of a given
#circular vertec array modified by a (circular) shift operation
    
def sm_op(point,e_seg,p_shift):
    calc_point=(e_seg-1)-point
    new_point=calc_point+p_shift
    if (new_point>e_seg-1):
       new_point=new_point-e_seg
    return new_point
    
#helper function to calculate the a (circular) shift operation of a given
#circular vertec array
    
def s_op(point,e_seg,p_shift):
    new_point=point+p_shift
    if (new_point>e_seg):
       new_point=new_point-e_seg
    if (new_point<0):
       new_point=new_point+e_seg
    return new_point
    
def s_op2(point,e_seg,p_shift):
    new_point=point+p_shift
    if (new_point>e_seg):
       new_point=new_point-e_seg
    if (new_point<0):
       new_point=new_point+e_seg
    return new_point
    
def s_op1(point,e_seg,p_shift):
    new_point=point+p_shift
    if (new_point>e_seg):
       new_point=new_point-e_seg
    if (new_point<0):
       new_point=new_point+e_seg
    if new_point==e_seg:
       new_point=0
    return new_point

#helper function to calculate the uv shiftfor tiled UV organization

def Ushift(bone,u):
    global Utiles
    global armData
    global Utiles_space
    u1=float(get_info(armData.bones.values()[bone].name,"u"))
    u2=float(get_info(armData.bones.values()[bone].name,"w"))
    return ((u*(u2-u1)+u1)/Utiles)
    
    
def Vshift(bone,v):
    global Vtiles
    global Vtiles_space
    global armData
    v1=float(get_info(armData.bones.values()[bone].name,"v"))
    v2=float(get_info(armData.bones.values()[bone].name,"x"))
    return ((v*(v2-v1)+v1)/Vtiles)
    
#function to connect two bones with different or equal mesh resolutions
#resolution of bone2 must be lower than the resolution of bone1

def connect_bones(bone1,bone2,extend_segs1,extend_segs2):
    UVturn=int(get_info(armData.bones.values()[bone1].name,"a"))
    if extend_segs2<=extend_segs1:
       if(UVturn>0):
                    ext_dif=(extend_segs1-extend_segs2)/2
       else:
            ext_dif=0
       bottom_segs1=extend_segs1/2
       bottom_segs2=extend_segs2/2
       bottom_seg_diff=bottom_segs1-bottom_segs2
       for loop in range(0, extend_segs1-1):
           do_draw=0
           if(loop<bottom_segs2-1):
                              loop2=loop
                              do_draw=1
           if(loop>bottom_segs2+bottom_seg_diff-2):
                              if(loop<bottom_segs1+bottom_segs2-1):
                                                                 loop2=loop-bottom_seg_diff
                                                                 do_draw=1
           if(loop>bottom_segs2+bottom_segs1-1):
                                             loop2=extend_segs2-(extend_segs1-(bottom_segs2+bottom_segs1-1))
                                             do_draw=1
           if(loop>=bottom_segs2-1):
                                 if(loop<=bottom_segs2+bottom_seg_diff-2):
                                                                          loop2=bottom_segs2-1
                                                                          do_draw=2
           if(loop>=bottom_segs1+bottom_segs2-1):
                                 if(loop<=bottom_segs2+bottom_segs1):
                                                                       loop2=extend_segs2-1
                                                                       do_draw=2

           if(do_draw==1):
                       f=NMesh.Face()
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop+1+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop2+1+(extend_segs2*0)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop2+(extend_segs2*0)])
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op1(loop+ext_dif,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op2(loop+1+ext_dif,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op2(loop2+1,extend_segs2,UVturn))/float(extend_segs2))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op1(loop2,extend_segs2,UVturn))/float(extend_segs2))))
                       f.smooth = 1
                       blender_mesh.faces.append(f)
           if(do_draw==2):
                       f=NMesh.Face()
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop+1+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop2+(extend_segs2*0)])
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op1(loop+ext_dif,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op2(loop+1+ext_dif,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op1(loop2,extend_segs2,UVturn))/float(extend_segs2))))
                       f.smooth = 1
                       blender_mesh.faces.append(f)

       f=NMesh.Face()
       f.v.append(blender_mesh.verts[vert_dict[bone1]+extend_segs1-1+(extend_segs1*2)])
       f.v.append(blender_mesh.verts[vert_dict[bone1]+(extend_segs1*2)])
       f.v.append(blender_mesh.verts[vert_dict[bone2]+(extend_segs2*0)])
       f.v.append(blender_mesh.verts[vert_dict[bone2]+extend_segs2-1+(extend_segs2*0)])
       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op1(extend_segs1-1+ext_dif,extend_segs1,UVturn))/float(extend_segs1))))
       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op2(extend_segs1+ext_dif,extend_segs1,UVturn))/float(extend_segs1))))
       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op2(extend_segs2,extend_segs2,UVturn))/float(extend_segs2))))
       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op1(extend_segs2-1,extend_segs2,UVturn))/float(extend_segs2))))
       f.smooth = 1
       blender_mesh.faces.append(f)
    else:
       if(UVturn>0):
                    ext_dif=(extend_segs2-extend_segs1)/2
       else:
            ext_dif=0
       bottom_segs1=extend_segs1/2
       bottom_segs2=extend_segs2/2
       bottom_seg_diff=bottom_segs2-bottom_segs1
       for loop in range(0, extend_segs2-1):
           do_draw=0
           if(loop<bottom_segs1-1):
                              loop2=loop
                              do_draw=1
           if(loop>bottom_segs1+bottom_seg_diff-2):
                              if(loop<bottom_segs2+bottom_segs1-1):
                                                                 loop2=loop-bottom_seg_diff
                                                                 do_draw=1
           if(loop>bottom_segs1+bottom_segs2-1):
                                             loop2=extend_segs1-(extend_segs2-(bottom_segs1+bottom_segs2-1))
                                             do_draw=1
           if(loop>=bottom_segs1-1):
                                 if(loop<=bottom_segs1+bottom_seg_diff-2):
                                                                          loop2=bottom_segs1-1
                                                                          do_draw=2
           if(loop>=bottom_segs2+bottom_segs1-1):
                                 if(loop<=bottom_segs1+bottom_segs2):
                                                                       loop2=extend_segs1-1
                                                                       do_draw=2

           if(do_draw==1):
                       f=NMesh.Face()
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop2+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop2+1+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop+1+(extend_segs2*0)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop+(extend_segs2*0)])
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op1(loop2,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op2(loop2+1,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op2(loop+1+ext_dif,extend_segs2,UVturn))/float(extend_segs2))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op1(loop+ext_dif,extend_segs2,UVturn))/float(extend_segs2))))
                       f.smooth = 1
                       blender_mesh.faces.append(f)
           if(do_draw==2):
                       f=NMesh.Face()
                       f.v.append(blender_mesh.verts[vert_dict[bone1]+loop2+(extend_segs1*2)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop+1+(extend_segs2*0)])
                       f.v.append(blender_mesh.verts[vert_dict[bone2]+loop+(extend_segs2*0)])
                       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op1(loop2,extend_segs1,UVturn))/float(extend_segs1))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op2(loop+1+ext_dif,extend_segs2,UVturn))/float(extend_segs2))))
                       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op1(loop+ext_dif,extend_segs2,UVturn))/float(extend_segs2))))
                       f.smooth = 1
                       blender_mesh.faces.append(f)

       f=NMesh.Face()
       f.v.append(blender_mesh.verts[vert_dict[bone1]+extend_segs1-1+(extend_segs1*2)])
       f.v.append(blender_mesh.verts[vert_dict[bone1]+(extend_segs1*2)])
       f.v.append(blender_mesh.verts[vert_dict[bone2]+(extend_segs2*0)])
       f.v.append(blender_mesh.verts[vert_dict[bone2]+extend_segs2-1+(extend_segs2*0)])
       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op1(extend_segs1-1,extend_segs1,UVturn))/float(extend_segs1))))
       f.uv.append((Ushift(bone1,(float(2)/float(3))),Vshift(bone1,float(s_op2(extend_segs1,extend_segs1,UVturn))/float(extend_segs1))))
       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op2(extend_segs2+ext_dif,extend_segs2,UVturn))/float(extend_segs2))))
       f.uv.append((Ushift(bone1,(float(3)/float(3))),Vshift(bone1,float(s_op1(extend_segs2-1+ext_dif,extend_segs2,UVturn))/float(extend_segs2))))
       f.smooth = 1
       blender_mesh.faces.append(f)


#simple connection between equal segement resolutions - for example within a
#simple bone

def connect_straight(bone1, seg1, bone2, seg2, extend_segs):
    UVturn=int(get_info(armData.bones.values()[bone1].name,"a"))
    for loop in range(0, extend_segs-1):
        f=NMesh.Face()
        f.v.append(blender_mesh.verts[vert_dict[bone1]+loop+(extend_segs*seg1)])
        f.v.append(blender_mesh.verts[vert_dict[bone1]+loop+1+(extend_segs*seg1)])
        f.v.append(blender_mesh.verts[vert_dict[bone2]+loop+1+(extend_segs*seg2)])
        f.v.append(blender_mesh.verts[vert_dict[bone2]+loop+(extend_segs*seg2)])
        f.uv.append((Ushift(bone1,(float(seg1)/float(3))),Vshift(bone1,float(s_op1(loop,extend_segs,UVturn))/float(extend_segs))))
        f.uv.append((Ushift(bone1,(float(seg1)/float(3))),Vshift(bone1,float(s_op2(loop+1,extend_segs,UVturn))/float(extend_segs))))
        f.uv.append((Ushift(bone1,(float(seg1+1)/float(3))),Vshift(bone1,float(s_op2(loop+1,extend_segs,UVturn))/float(extend_segs))))
        f.uv.append((Ushift(bone1,(float(seg1+1)/float(3))),Vshift(bone1,float(s_op1(loop,extend_segs,UVturn))/float(extend_segs))))
        f.smooth = 1
        blender_mesh.faces.append(f)
    f=NMesh.Face()
    f.v.append(blender_mesh.verts[vert_dict[bone1]+extend_segs-1+(extend_segs*seg1)])
    f.v.append(blender_mesh.verts[vert_dict[bone1]+(extend_segs*seg1)])
    f.v.append(blender_mesh.verts[vert_dict[bone2]+(extend_segs*seg2)])
    f.v.append(blender_mesh.verts[vert_dict[bone2]+extend_segs-1+(extend_segs*seg2)])
    f.uv.append((Ushift(bone1,(float(seg1)/float(3))),Vshift(bone1,float(s_op1(extend_segs-1,extend_segs,UVturn))/float(extend_segs))))
    f.uv.append((Ushift(bone1,(float(seg1)/float(3))),Vshift(bone1,float(s_op2(extend_segs,extend_segs,UVturn))/float(extend_segs))))
    f.uv.append((Ushift(bone1,(float(seg1+1)/float(3))),Vshift(bone1,float(s_op2(extend_segs,extend_segs,UVturn))/float(extend_segs))))
    f.uv.append((Ushift(bone1,(float(seg1+1)/float(3))),Vshift(bone1,float(s_op1(extend_segs-1,extend_segs,UVturn))/float(extend_segs))))
    f.smooth = 1
    blender_mesh.faces.append(f)
    
#connect all faces withing a simple extended bone
    
def extend_skin(bone1,extend_segs):
    connect_straight(bone1, 0, bone1, 1, extend_segs)
    connect_straight(bone1, 1, bone1, 2, extend_segs)

#helper function for more complex mesh construction
#uses various subclasses to determine how the UV coordinates should be calculated

def connect_face(mother,c_class,bone1,num1,seg1,extend_segs1,bone2,num2,seg2,extend_segs2,bone3,num3,seg3,extend_segs3,bone4,num4,seg4,extend_segs4):

    UVturn=int(get_info(armData.bones.values()[mother].name,"a"))

    #connect the vertices

    f=NMesh.Face()
    f.v.append(blender_mesh.verts[vert_dict[bone1]+num1+(extend_segs1*seg1)])
    f.v.append(blender_mesh.verts[vert_dict[bone2]+num2+(extend_segs2*seg2)])
    f.v.append(blender_mesh.verts[vert_dict[bone3]+num3+(extend_segs3*seg3)])
    f.v.append(blender_mesh.verts[vert_dict[bone4]+num4+(extend_segs4*seg4)])
    
    #calculate the distance between vertices
    
    cum_dist=0
    start_vec=blender_mesh.verts[vert_dict[bone1]+num1+(extend_segs1*seg1)].co
    end_vec=blender_mesh.verts[vert_dict[bone2]+num2+(extend_segs2*seg2)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    start_vec=blender_mesh.verts[vert_dict[bone2]+num2+(extend_segs2*seg2)].co
    end_vec=blender_mesh.verts[vert_dict[bone3]+num3+(extend_segs3*seg3)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    start_vec=blender_mesh.verts[vert_dict[bone3]+num3+(extend_segs3*seg3)].co
    end_vec=blender_mesh.verts[vert_dict[bone4]+num4+(extend_segs4*seg4)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    start_vec=blender_mesh.verts[vert_dict[bone4]+num4+(extend_segs4*seg4)].co
    end_vec=blender_mesh.verts[vert_dict[bone1]+num1+(extend_segs1*seg1)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    
    #build the UV map - make sure that faces are seamlessly connected in armature crossings
    #to ensure this, various additional UV-classes are defined, which ensure correct connectivity
    
    #class I (subclasses 1)
    #class II (UV subclasses 5-10)
    #class III (UV subclasses 3,4)
    subtype=0
    if(c_class==1):
                   subtype=1
                   shift1=1
                   shift2=1
                   shift3=0
    if(c_class==3):
                   subtype=4
                   shift1=0
                   shift2=-0.5
                   shift3=-0.5
    if(c_class==4):
                   subtype=5
                   shift1=0
                   shift2=0.5
                   shift3=0.5
    if(c_class==5):
                   subtype=2
                   shift1=1
                   shift2=1
                   shift3=0
    if(c_class==6):
                   subtype=3
                   shift1=-1
                   shift2=-1
                   shift3=0
    if(c_class==7):
                   subtype=2
                   shift1=1
                   shift2=1
                   shift3=0.5
    if(c_class==8):
                   subtype=3
                   shift1=-1
                   shift2=-1
                   shift3=-0.5
    if(c_class==9):
                   subtype=2
                   shift1=1
                   shift2=0.5
                   shift3=0
    if(c_class==10):
                   subtype=3
                   shift1=-1
                   shift2=-0.5
                   shift3=0
    #print num1,extent_segs1
    if(subtype==1):
                  f.uv.append((Ushift(mother,(float(2)/float(3))),Vshift(mother,float(s_op1(num1,extend_segs1,UVturn))/float(extend_segs1))))
                  f.uv.append((Ushift(mother,(float(2)/float(3))),Vshift(mother,float(s_op2(num1+shift1,extend_segs1,UVturn))/float(extend_segs1))))
                  f.uv.append((Ushift(mother,(float(3)/float(3))),Vshift(mother,float(s_op2(num1+shift2,extend_segs1,UVturn))/float(extend_segs3))))
                  f.uv.append((Ushift(mother,(float(3)/float(3))),Vshift(mother,float(s_op1(num1+shift3,extend_segs1,UVturn))/float(extend_segs4))))
    if(subtype==2):
                  f.uv.append((Ushift(mother,(float(2)/float(3))),Vshift(mother,float(s_op1(num1,extend_segs1,UVturn))/float(extend_segs1))))
                  f.uv.append((Ushift(mother,(float(2)/float(3))),Vshift(mother,float(s_op2(num1+shift1,extend_segs1,UVturn))/float(extend_segs1))))
                  f.uv.append((Ushift(mother,(float(2.333)/float(3))),Vshift(mother,float(s_op2(num1+shift2,extend_segs1,UVturn))/float(extend_segs1))))
                  f.uv.append((Ushift(mother,(float(2.333)/float(3))),Vshift(mother,float(s_op1(num1+shift3,extend_segs1,UVturn))/float(extend_segs1))))
    if(subtype==3):
                   if num1==0:
                      num1=num1+extend_segs1
                   f.uv.append((Ushift(mother,(float(3)/float(3))),Vshift(mother,float(s_op2(num1,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(3)/float(3))),Vshift(mother,float(s_op1(num1+shift1,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2.666)/float(3))),Vshift(mother,float(s_op1(num1+shift2,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2.666)/float(3))),Vshift(mother,float(s_op2(num1+shift3,extend_segs1,UVturn))/float(extend_segs1))))
    if(subtype==4):
                   if num1==0:
                      num1=num1+extend_segs1
                   f.uv.append((Ushift(mother,(float(2)/float(3))),Vshift(mother,float(s_op2(num1,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(3)/float(3))),Vshift(mother,float(s_op2(num1+shift1,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2.666)/float(3))),Vshift(mother,float(s_op1(num1+shift2,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2.333)/float(3))),Vshift(mother,float(s_op1(num1+shift3,extend_segs1,UVturn))/float(extend_segs1))))
    if(subtype==5):
                   f.uv.append((Ushift(mother,(float(3)/float(3))),Vshift(mother,float(s_op1(num1,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2)/float(3))),Vshift(mother,float(s_op1(num1+shift1,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2.333)/float(3))),Vshift(mother,float(s_op2(num1+shift2,extend_segs1,UVturn))/float(extend_segs1))))
                   f.uv.append((Ushift(mother,(float(2.666)/float(3))),Vshift(mother,float(s_op2(num1+shift3,extend_segs1,UVturn))/float(extend_segs1))))

    f.smooth = 1
    blender_mesh.faces.append(f)
    return cum_dist
    
def calc_face(c_class,bone1,num1,seg1,extend_segs1,bone2,num2,seg2,extend_segs2,bone3,num3,seg3,extend_segs3,bone4,num4,seg4,extend_segs4):

    #calculate the distance between vertices

    cum_dist=0
    start_vec=blender_mesh.verts[vert_dict[bone1]+num1+(extend_segs1*seg1)].co
    end_vec=blender_mesh.verts[vert_dict[bone2]+num2+(extend_segs2*seg2)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    start_vec=blender_mesh.verts[vert_dict[bone2]+num2+(extend_segs2*seg2)].co
    end_vec=blender_mesh.verts[vert_dict[bone3]+num3+(extend_segs3*seg3)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    start_vec=blender_mesh.verts[vert_dict[bone3]+num3+(extend_segs3*seg3)].co
    end_vec=blender_mesh.verts[vert_dict[bone4]+num4+(extend_segs4*seg4)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    start_vec=blender_mesh.verts[vert_dict[bone4]+num4+(extend_segs4*seg4)].co
    end_vec=blender_mesh.verts[vert_dict[bone1]+num1+(extend_segs1*seg1)].co
    connection=Vector(end_vec)-Vector(start_vec)
    cum_dist=cum_dist+connection.length
    return cum_dist
    
#not currently used

def connect_center(bone1,bone2,extend_segs):
    #class IV?
    connect_face(bone1,4,bone1,1,0,extend_segs,bone1,0,0,extend_segs,bone2,5,0,extend_segs,bone2,4,0,extend_segs)
    connect_face(bone1,4,bone1,2,0,extend_segs,bone1,1,0,extend_segs,bone2,4,0,extend_segs,bone2,3,0,extend_segs)
    connect_face(bone1,4,bone1,3,0,extend_segs,bone1,2,0,extend_segs,bone2,3,0,extend_segs,bone2,2,0,extend_segs)
    connect_face(bone1,4,bone1,4,0,extend_segs,bone1,3,0,extend_segs,bone2,2,0,extend_segs,bone2,1,0,extend_segs)
    connect_face(bone1,4,bone1,5,0,extend_segs,bone1,4,0,extend_segs,bone2,1,0,extend_segs,bone2,0,0,extend_segs)
    connect_face(bone1,4,bone1,6,0,extend_segs,bone1,5,0,extend_segs,bone2,0,0,extend_segs,bone2,5,0,extend_segs)

#do a cross connection between four bones bone1-4

#s_segs is the stem resolution and b_segs is the branch resolution

#p_pos determines the shift for attachment of the branch bones

#p_shift determines an additional twist and can be any number between 0 and 1/4
#of s_segs

def connect_cross(bone1, bone2, bone3, bone4, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    cum_dist=0
    cum_dist=cum_dist+connect_face(bone1,1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    cum_dist=cum_dist+connect_face(bone1,1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         cum_dist=cum_dist+connect_face(bone1,1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         cum_dist=cum_dist+connect_face(bone1,1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          cum_dist=cum_dist+connect_face(bone1,1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          cum_dist=cum_dist+connect_face(bone1,1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        cum_dist=cum_dist+connect_face(bone1,temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p+1,0,b_segs,bone4,p,0,b_segs)
        cum_dist=cum_dist+connect_face(bone1,temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p+1,0,b_segs,bone3,p,0,b_segs)
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        cum_dist=cum_dist+connect_face(bone1,temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,m_op(p,b_segs),0,b_segs,bone4,m_op(p+1,b_segs),0,b_segs)
        cum_dist=cum_dist+connect_face(bone1,temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,m_op(p,b_segs),0,b_segs,bone3,m_op(p+1,b_segs),0,b_segs)

    #class III
    cum_dist=cum_dist+connect_face(bone1,3,bone1,s_op(s_segs-1-b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(s_segs-1-b_pos,s_segs,p_sft),0,s_segs,bone3,0,0,b_segs,bone3,b_segs-1,0,b_segs)
    cum_dist=cum_dist+connect_face(bone1,4,bone2,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),0,s_segs,bone1,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),2,s_segs,bone3,(b_segs/2),0,b_segs,bone3,(b_segs/2)-1,0,b_segs)
    cum_dist=cum_dist+connect_face(bone1,3,bone1,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),0,s_segs,bone4,(b_segs/2),0,b_segs,bone4,(b_segs/2)-1,0,b_segs)
    cum_dist=cum_dist+connect_face(bone1,4,bone2,s_op(b_pos,s_segs,p_sft),0,s_segs,bone1,s_op(b_pos,s_segs,p_sft),2,s_segs,bone4,0,0,b_segs,bone4,b_segs-1,0,b_segs)
    return cum_dist
    
def opt_cross(bone1, bone2, bone3, bone4, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    connect_face(bone1,1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    connect_face(bone1,1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         connect_face(1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         connect_face(1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          connect_face(bone1,1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          connect_face(bone1,1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    dist_max=100000
    shift_max=0
    for shift_test in range(0,b_segs):
        cum_dist=0
        for p in range(0,(b_segs/2)-1):
            p2=s_op(p,b_segs,shift_test)
            temp_class1=5
            temp_class2=6
            if(p==0):
                 temp_class1=7
                 temp_class2=8
            else:
                 if(p==(b_segs/2)-2):
                                     temp_class1=9
                                     temp_class2=10
            cum_dist=cum_dist+calc_face(temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p2+1,0,b_segs,bone4,p2,0,b_segs)
            cum_dist=cum_dist+calc_face(temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p2+1,0,b_segs,bone3,p2,0,b_segs)
        for p in range(0,(b_segs/2)-1):
            p2=s_op(p,b_segs,shift_test)
            temp_class1=5
            temp_class2=6
            if(p==0):
                 temp_class1=9
                 temp_class2=10
            else:
                 if(p==(b_segs/2)-2):
                                     temp_class1=7
                                     temp_class2=8
            cum_dist=cum_dist+calc_face(temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,sm_op(p,b_segs,shift_max),0,b_segs,bone4,sm_op(p+1,b_segs,shift_max),0,b_segs)
            cum_dist=cum_dist+calc_face(temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,sm_op(p,b_segs,shift_max),0,b_segs,bone3,sm_op(p+1,b_segs,shift_max),0,b_segs)

        if cum_dist<dist_max:
                        dist_max=cum_dist
                        shift_max=shift_test
    #class II
    for p in range(0,(b_segs/2)-1):
        p2=s_op(p,b_segs,shift_max)
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        connect_face(bone1,temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p2+1,0,b_segs,bone4,p2,0,b_segs)
        connect_face(bone1,temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p2+1,0,b_segs,bone3,p2,0,b_segs)
    for p in range(0,(b_segs/2)-1):
        p2=s_op(p,b_segs,shift_max)
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        connect_face(bone1,temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,sm_op(p,b_segs,shift_max),0,b_segs,bone4,sm_op(p+1,b_segs,shift_max),0,b_segs)
        connect_face(bone1,temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,sm_op(p,b_segs,shift_max),0,b_segs,bone3,sm_op(p+1,b_segs,shift_max),0,b_segs)


    #class III
    connect_face(bone1,3,bone1,s_op(s_segs-1-b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(s_segs-1-b_pos,s_segs,p_sft),0,s_segs,bone3,s_op(0,s_segs,shift_max),0,b_segs,bone3,s_op(b_segs-1,s_segs,shift_max),0,b_segs)
    connect_face(bone1,4,bone2,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),0,s_segs,bone1,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),2,s_segs,bone3,s_op((b_segs/2),s_segs,shift_max),0,b_segs,bone3,s_op((b_segs/2)-1,s_segs,shift_max),0,b_segs)
    connect_face(bone1,3,bone1,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),0,s_segs,bone4,s_op((b_segs/2),s_segs,shift_max),0,b_segs,bone4,s_op((b_segs/2)-1,s_segs,shift_max),0,b_segs)
    connect_face(bone1,4,bone2,s_op(b_pos,s_segs,p_sft),0,s_segs,bone1,s_op(b_pos,s_segs,p_sft),2,s_segs,bone4,s_op(0,s_segs,shift_max),0,b_segs,bone4,s_op(b_segs-1,s_segs,shift_max),0,b_segs)
    return cum_dist
    
def calc_cross(bone1, bone2, bone3, bone4, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    cum_dist=0
    cum_dist=cum_dist+calc_face(1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    cum_dist=cum_dist+calc_face(1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         cum_dist=cum_dist+calc_face(1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         cum_dist=cum_dist+calc_face(1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          cum_dist=cum_dist+calc_face(1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          cum_dist=cum_dist+calc_face(1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        cum_dist=cum_dist+calc_face(temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p+1,0,b_segs,bone4,p,0,b_segs)
        cum_dist=cum_dist+calc_face(temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p+1,0,b_segs,bone3,p,0,b_segs)
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        cum_dist=cum_dist+calc_face(temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,m_op(p,b_segs),0,b_segs,bone4,m_op(p+1,b_segs),0,b_segs)
        cum_dist=cum_dist+calc_face(temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,m_op(p,b_segs),0,b_segs,bone3,m_op(p+1,b_segs),0,b_segs)

    #class III
    cum_dist=cum_dist+calc_face(3,bone1,s_op(s_segs-1-b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(s_segs-1-b_pos,s_segs,p_sft),0,s_segs,bone3,0,0,b_segs,bone3,b_segs-1,0,b_segs)
    cum_dist=cum_dist+calc_face(4,bone2,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),0,s_segs,bone1,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),2,s_segs,bone3,(b_segs/2),0,b_segs,bone3,(b_segs/2)-1,0,b_segs)
    cum_dist=cum_dist+calc_face(3,bone1,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),0,s_segs,bone4,(b_segs/2),0,b_segs,bone4,(b_segs/2)-1,0,b_segs)
    cum_dist=cum_dist+calc_face(4,bone2,s_op(b_pos,s_segs,p_sft),0,s_segs,bone1,s_op(b_pos,s_segs,p_sft),2,s_segs,bone4,0,0,b_segs,bone4,b_segs-1,0,b_segs)
    return cum_dist

def connect_t_left(bone1, bone2, bone4, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    connect_face(bone1,1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    connect_face(bone1,1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         connect_face(bone1,1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         connect_face(bone1,1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          connect_face(bone1,1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          connect_face(bone1,1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        connect_face(bone1,temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p+1,0,b_segs,bone4,p,0,b_segs)

    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=1
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=1
                                   temp_class2=8
        connect_face(bone1,temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,m_op(p,b_segs),0,b_segs,bone4,m_op(p+1,b_segs),0,b_segs)
        connect_face(bone1,temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs)

    #class III
    connect_face(bone1,3,bone1,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),0,s_segs,bone4,(b_segs/2),0,b_segs,bone4,(b_segs/2)-1,0,b_segs)
    connect_face(bone1,4,bone2,s_op(b_pos,s_segs,p_sft),0,s_segs,bone1,s_op(b_pos,s_segs,p_sft),2,s_segs,bone4,0,0,b_segs,bone4,b_segs-1,0,b_segs)


def connect_t_right(bone1, bone2, bone3, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    connect_face(bone1,1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    connect_face(bone1,1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         connect_face(bone1,1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         connect_face(bone1,1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          connect_face(bone1,1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          connect_face(bone1,1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=1
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=1
                                   temp_class2=10
        connect_face(bone1,temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p+1,0,b_segs,bone3,p,0,b_segs)
        connect_face(bone1,temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs)
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        connect_face(bone1,temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,m_op(p,b_segs),0,b_segs,bone3,m_op(p+1,b_segs),0,b_segs)

    #class III
    connect_face(bone1,3,bone1,s_op(s_segs-1-b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(s_segs-1-b_pos,s_segs,p_sft),0,s_segs,bone3,0,0,b_segs,bone3,b_segs-1,0,b_segs)
    connect_face(bone1,4,bone2,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),0,s_segs,bone1,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),2,s_segs,bone3,(b_segs/2),0,b_segs,bone3,(b_segs/2)-1,0,b_segs)

def opt_t_left(bone1, bone2, bone4, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    connect_face(bone1,1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    connect_face(bone1,1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         connect_face(bone1,1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         connect_face(bone1,1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          connect_face(bone1,1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          connect_face(bone1,1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    dist_max=100000
    shift_max=0
    for shift_test in range(0,b_segs):
        cum_dist=0
        for p in range(0,(b_segs/2)-1):
            p2=s_op(p,b_segs,shift_test)
            temp_class1=5
            temp_class2=6
            if(p==0):
                 temp_class1=7
                 temp_class2=8
            else:
                 if(p==(b_segs/2)-2):
                                     temp_class1=9
                                     temp_class2=10
            cum_dist=cum_dist+calc_face(temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p2+1,0,b_segs,bone4,p2,0,b_segs)
        for p in range(0,(b_segs/2)-1):
            p2=s_op(p,b_segs,shift_test)
            temp_class1=5
            temp_class2=6
            if(p==0):
                 temp_class1=9
                 temp_class2=10
            else:
                 if(p==(b_segs/2)-2):
                                     temp_class1=7
                                     temp_class2=8
            cum_dist=cum_dist+calc_face(temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,sm_op(p,b_segs,shift_max),0,b_segs,bone4,sm_op(p+1,b_segs,shift_max),0,b_segs)
        if cum_dist<dist_max:
                        dist_max=cum_dist
                        shift_max=shift_test

    #class II
    for p in range(0,(b_segs/2)-1):
        p2=s_op(p,b_segs,shift_max)
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        connect_face(bone1,temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p2+1,0,b_segs,bone4,p2,0,b_segs)

    for p in range(0,(b_segs/2)-1):
        p2=s_op(p,b_segs,shift_max)
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=1
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=1
                                   temp_class2=8
        connect_face(bone1,temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,sm_op(p,b_segs,shift_max),0,b_segs,bone4,sm_op(p+1,b_segs,shift_max),0,b_segs)
        connect_face(bone1,temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs)

    #class III
    connect_face(bone1,3,bone1,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),0,s_segs,bone4,s_op((b_segs/2),s_segs,shift_max),0,b_segs,bone4,s_op((b_segs/2)-1,s_segs,shift_max),0,b_segs)
    connect_face(bone1,4,bone2,s_op(b_pos,s_segs,p_sft),0,s_segs,bone1,s_op(b_pos,s_segs,p_sft),2,s_segs,bone4,s_op(0,s_segs,shift_max),0,b_segs,bone4,s_op(b_segs-1,s_segs,shift_max),0,b_segs)


def opt_t_right(bone1, bone2, bone3, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    #top and bottom
    connect_face(bone1,1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    connect_face(bone1,1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         connect_face(bone1,1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         connect_face(bone1,1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          connect_face(bone1,1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          connect_face(bone1,1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    dist_max=100000
    shift_max=0
    for shift_test in range(0,b_segs):
        cum_dist=0
        for p in range(0,(b_segs/2)-1):
            p2=s_op(p,b_segs,shift_test)
            temp_class1=5
            temp_class2=6
            if(p==0):
                 temp_class1=7
                 temp_class2=8
            else:
                 if(p==(b_segs/2)-2):
                                     temp_class1=9
                                     temp_class2=10
            cum_dist=cum_dist+calc_face(temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p2+1,0,b_segs,bone3,p2,0,b_segs)
        for p in range(0,(b_segs/2)-1):
            p2=s_op(p,b_segs,shift_test)
            temp_class1=5
            temp_class2=6
            if(p==0):
                 temp_class1=9
                 temp_class2=10
            else:
                 if(p==(b_segs/2)-2):
                                     temp_class1=7
                                     temp_class2=8
            cum_dist=cum_dist+calc_face(temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,sm_op(p,b_segs,shift_max),0,b_segs,bone3,sm_op(p+1,b_segs,shift_max),0,b_segs)

        if cum_dist<dist_max:
                        dist_max=cum_dist
                        shift_max=shift_test
    #class II
    for p in range(0,(b_segs/2)-1):
        p2=s_op(p,b_segs,shift_max)
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=1
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=1
                                   temp_class2=10
        connect_face(bone1,temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p2+1,0,b_segs,bone3,p2,0,b_segs)
        connect_face(bone1,temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs)
    for p in range(0,(b_segs/2)-1):
        p2=s_op(p,b_segs,shift_max)
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        connect_face(bone1,temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,sm_op(p,b_segs,shift_max),0,b_segs,bone3,sm_op(p+1,b_segs,shift_max),0,b_segs)

    #class III
    connect_face(bone1,3,bone1,s_op(s_segs-1-b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(s_segs-1-b_pos,s_segs,p_sft),0,s_segs,bone3,s_op(0,s_segs,shift_max),0,b_segs,bone3,s_op(b_segs-1,s_segs,shift_max),0,b_segs)
    connect_face(bone1,4,bone2,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),0,s_segs,bone1,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),2,s_segs,bone3,s_op((b_segs/2),s_segs,shift_max),0,b_segs,bone3,s_op((b_segs/2)-1,s_segs,shift_max),0,b_segs)


def calc_t_left(bone1, bone2, bone4, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    cum_dist=0
    #top and bottom
    cum_dist=cum_dist+calc_face(1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    cum_dist=cum_dist+calc_face(1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         cum_dist=cum_dist+calc_face(1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         cum_dist=cum_dist+calc_face(1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          cum_dist=cum_dist+calc_face(1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          cum_dist=cum_dist+calc_face(1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        cum_dist=cum_dist+calc_face(temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone4,p+1,0,b_segs,bone4,p,0,b_segs)

    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        cum_dist=cum_dist+calc_face(temp_class2,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs,bone4,m_op(p,b_segs),0,b_segs,bone4,m_op(p+1,b_segs),0,b_segs)
        cum_dist=cum_dist+calc_face(temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs)

    #class III
    cum_dist=cum_dist+calc_face(3,bone1,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2)-1-bottom_segs,s_segs,p_sft),0,s_segs,bone4,(b_segs/2),0,b_segs,bone4,(b_segs/2)-1,0,b_segs)
    cum_dist=cum_dist+calc_face(4,bone2,s_op(b_pos,s_segs,p_sft),0,s_segs,bone1,s_op(b_pos,s_segs,p_sft),2,s_segs,bone4,0,0,b_segs,bone4,b_segs-1,0,b_segs)
    return cum_dist

def calc_t_right(bone1, bone2, bone3, s_segs, b_segs, b_pos,p_sft):
    a=extend_segs
    cum_dist=0
    #top and bottom
    cum_dist=cum_dist+calc_face(1,bone1,s_op(s_segs-1,s_segs,p_sft),2,s_segs,bone1,s_op(0,s_segs,p_sft),2,s_segs,bone2,s_op(0,s_segs,p_sft),0,s_segs,bone2,s_op(s_segs-1,s_segs,p_sft),0,s_segs)
    cum_dist=cum_dist+calc_face(1,bone1,s_op((s_segs/2)-1,s_segs,p_sft),2,s_segs,bone1,s_op((s_segs/2),s_segs,p_sft),2,s_segs,bone2,s_op((s_segs/2),s_segs,p_sft),0,s_segs,bone2,s_op((s_segs/2)-1,s_segs,p_sft),0,s_segs)
    #top filler for resolution change
    for p in range(0,b_pos):
         cum_dist=cum_dist+calc_face(1,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone1,s_op(p+1,s_segs,p_sft),2,s_segs,bone2,s_op(p+1,s_segs,p_sft),0,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs)
         cum_dist=cum_dist+calc_face(1,bone1,sm_op(p+1,s_segs,p_sft),2,s_segs,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1,s_segs,p_sft),0,s_segs)

    #bottom filler for resolution change
    bottom_segs=s_op((s_segs/2)-(b_pos+(b_segs/2)),s_segs,p_sft)-p_sft
    for p in range((s_segs/2)-bottom_segs,(s_segs/2)):
          cum_dist=cum_dist+calc_face(1,bone1,s_op(p-1,s_segs,p_sft),2,s_segs,bone1,s_op(p,s_segs,p_sft),2,s_segs,bone2,s_op(p,s_segs,p_sft),0,s_segs,bone2,s_op(p-1,s_segs,p_sft),0,s_segs)
          cum_dist=cum_dist+calc_face(1,bone1,sm_op(p,s_segs,p_sft),2,s_segs,bone1,sm_op(p-1,s_segs,p_sft),2,s_segs,bone2,sm_op(p-1,s_segs,p_sft),0,s_segs,bone2,sm_op(p,s_segs,p_sft),0,s_segs)
    #class II
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=7
                 temp_class2=8
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=9
                                   temp_class2=10
        cum_dist=cum_dist+calc_face(temp_class2,bone2,sm_op(p+b_pos,s_segs,p_sft),0,s_segs,bone2,sm_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone3,p+1,0,b_segs,bone3,p,0,b_segs)
        cum_dist=cum_dist+calc_face(temp_class1,bone1,s_op(p+b_pos,s_segs,p_sft),2,s_segs,bone1,s_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(p+1+b_pos,s_segs,p_sft),0,s_segs,bone2,s_op(p+b_pos,s_segs,p_sft),0,s_segs)
    for p in range(0,(b_segs/2)-1):
        temp_class1=5
        temp_class2=6
        if(p==0):
                 temp_class1=9
                 temp_class2=10
        else:
             if(p==(b_segs/2)-2):
                                   temp_class1=7
                                   temp_class2=8
        cum_dist=cum_dist+calc_face(temp_class1,bone1,sm_op(p+1+b_pos,s_segs,p_sft),2,s_segs,bone1,sm_op(p+b_pos,s_segs,p_sft),2,s_segs,bone3,m_op(p,b_segs),0,b_segs,bone3,m_op(p+1,b_segs),0,b_segs)

    #class III
    cum_dist=cum_dist+calc_face(3,bone1,s_op(s_segs-1-b_pos,s_segs,p_sft),2,s_segs,bone2,s_op(s_segs-1-b_pos,s_segs,p_sft),0,s_segs,bone3,0,0,b_segs,bone3,b_segs-1,0,b_segs)
    cum_dist=cum_dist+calc_face(4,bone2,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),0,s_segs,bone1,s_op((s_segs/2)+bottom_segs,s_segs,p_sft),2,s_segs,bone3,(b_segs/2),0,b_segs,bone3,(b_segs/2)-1,0,b_segs)
    return cum_dist
    
#user interface stuff:
def run_skinny():
    global vert_dict
    global bone_dict
    global active_bone
    global active_vert
    global mesh_segs
    global bone_id
    global extend_segs
    global armObj
    global armData
    global scene
    global blender_mesh
    global seg_pos1
    global seg_pos2
    global seg_pos3
    global seg_size1
    global seg_size2
    global seg_size3
    global def_env
    global def_size
    global def_method
    global max_bones
    global Utiles
    global Vtiles
    global Utiles_space
    global Vtiles_space
    angle_mod=0.0
    angle_steps=36
    
    Window.EditMode(0)

    #get the armature object/data

    scene = Blender.Scene.getCurrent()
    armObj = scene.objects.active
    if not armObj or armObj.type!='Armature':
        Draw.PupMenu('You need to select an Armature first')
        return
    armData = armObj.getData()
    armData.drawAxes = True
    armObj.link(armData)

    active_vert=0
    
    vert_dict=[]
    bone_dict=[]

    #make the skin object

    blender_mesh=NMesh.New('skin')

    block = []
    mesh_segs_b = Blender.Draw.Create(mesh_segs)
    seg_pos1_b=Blender.Draw.Create(seg_pos1)
    seg_pos2_b=Blender.Draw.Create(seg_pos2)
    seg_pos3_b=Blender.Draw.Create(seg_pos3)

    seg_size1_b=Blender.Draw.Create(seg_size1)
    seg_size2_b=Blender.Draw.Create(seg_size2)
    seg_size3_b=Blender.Draw.Create(seg_size3)

    def_env_b = Blender.Draw.Create(def_env)
    def_size_b = Blender.Draw.Create(def_size)
    def_method_b = Blender.Draw.Create(def_method)
    #angle_mod_b = Blender.Draw.Create(angle_mod)
    angle_steps_b = Blender.Draw.Create(angle_steps)
    Utiles_b =  Blender.Draw.Create(Utiles)
    Vtiles_b =  Blender.Draw.Create(Vtiles)
    Utiles_space_b =  Blender.Draw.Create(Utiles_space)
    Vtiles_space_b =  Blender.Draw.Create(Vtiles_space)
    #block.append(("Name: ", text, 0, 30, "this is some tool tip"))
    block.append(("mesh resolution ", mesh_segs_b, 6, 100.0, "this is some tool tip"))
    block.append(("boneseg1 size ", seg_size1_b, 0.0, 10.0, "this is some tool tip"))
    block.append(("boneseg2 size ", seg_size2_b, 0.0, 10.0, "this is some tool tip"))
    block.append(("boneseg3 size ", seg_size3_b, 0.0, 10.0, "this is some tool tip"))
    block.append(("boneseg1 pos ", seg_pos1_b, 0.0, 1.0, "this is some tool tip"))
    block.append(("boneseg2 pos ", seg_pos2_b, 0.0, 1.0, "this is some tool tip"))
    block.append(("boneseg3 pos ", seg_pos3_b, 0.0, 1.0, "this is some tool tip"))
    block.append("")
    block.append(("envelope mod", def_env_b, "Use bone envelop values to shape the local mesh size. Overrides boneseg1-3 size values."))
    block.append(("length mod", def_size_b, "Modify local mesh size using bone length."))
    block.append(("automatic", def_method_b, "Use automatic bone connection welding."))
    #block.append(("auto angle", angle_mod_b, 0.0, 360.0, "Angle mod for automatic connection welding."))
    block.append(("auto steps", angle_steps_b, 10, 360, "Connection welding resolution."))
    block.append(("Utiles", Utiles_b, 1, 50, "Connection welding resolution."))
    block.append(("Vtiles", Vtiles_b, 1, 50, "Connection welding resolution."))
    block.append(("Ugap", Utiles_space_b, 0.0, 0.5, "Connection welding resolution."))
    block.append(("Vgap", Vtiles_space_b, 0.0, 0.5, "Connection welding resolution."))
    block.append("")
    block.append("Warning: only even mesh")
    block.append("resolutions are supported.")
    
    retval = Blender.Draw.PupBlock("Skinny 0.8alpha", block)
    
    if retval==0:
       return

    print "PupBlock returned", retval

    seg_pos1=seg_pos1_b.val
    seg_pos2=seg_pos2_b.val
    seg_pos3=seg_pos3_b.val
    seg_size1=seg_size1_b.val
    seg_size2=seg_size2_b.val
    seg_size3=seg_size3_b.val
    mesh_segs=mesh_segs_b.val
    def_env=def_env_b.val
    def_size=def_size_b.val
    def_method=def_method_b.val
    #angle_mod=angle_mod_b.val
    angle_steps=angle_steps_b.val
    Utiles=Utiles_b.val
    Vtiles=Vtiles_b.val
    Utiles_space=Utiles_space_b.val
    Vtiles_space=Vtiles_space_b.val
    #Draw.PupFloatInput('res:', 0.2, 0.05, 2.0)
    


    #build the mesh vertices and build the vert_dict and bone_dict dictionaries

    bone_id=0
    
    for bone in armData.bones.values():
        vstart=bone.head['ARMATURESPACE']
        vend=bone.tail['ARMATURESPACE']
        vert_dict.append(1)
        bone_dict.append(bone.name)
        bone_id=bone_id+1
        max_bones=bone_id

        
    current_bone=get_bone_id(armature_origin(bone).name)

    active_vert=0
    #bone_stack_id=0
    
    for bone_count in range(0,max_bones):
        bone=armData.bones.values()[current_bone]
        extend_segs=int(get_info(bone.name,"r"))
        vert_dict[current_bone]=active_vert
        active_vert=active_vert+(extend_segs*3)
        if bone.hasChildren():
           if len(bone.children)==1:
              current_bone=get_bone_id(bone.children[0].name)
           if len(bone.children)==2:
              current_bone=get_bone_id(bone.children[0].name)
              bone_stack.append(get_bone_id(bone.children[1].name))
           if len(bone.children)==3:
              current_bone=get_bone_id(bone.children[0].name)
              bone_stack.append(get_bone_id(bone.children[1].name))
              bone_stack.append(get_bone_id(bone.children[2].name))
        else:
             if bone_count!=max_bones-1:
                current_bone=bone_stack.pop()
             
    current_bone=get_bone_id(armature_origin(bone).name)

    for bone_count in range(0,max_bones):
        bone=armData.bones.values()[current_bone]
        vstart=bone.head['ARMATURESPACE']
        vend=bone.tail['ARMATURESPACE']
        extend_segs=int(get_info(bone.name,"r"))
        draw_mesh(vstart, vend, current_bone, vert_dict[current_bone], bone.name,extend_segs, bone.headRadius, bone.tailRadius, seg_pos1, seg_pos2, seg_pos3, seg_size1, seg_size2, seg_size3, def_env, def_size, def_method, bone, angle_mod, angle_steps)
        if bone.hasChildren():
           if len(bone.children)==1:
              current_bone=get_bone_id(bone.children[0].name)
           if len(bone.children)==2:
              current_bone=get_bone_id(bone.children[0].name)
              bone_stack.append(get_bone_id(bone.children[1].name))
           if len(bone.children)==3:
              current_bone=get_bone_id(bone.children[0].name)
              bone_stack.append(get_bone_id(bone.children[1].name))
              bone_stack.append(get_bone_id(bone.children[2].name))
        else:
             if bone_count!=max_bones-1:
                current_bone=bone_stack.pop()
           

    #connect the vertices based on the armature hirarchie
    
    bone_id=0
    for bone in armData.bones.values():
        if bone.hasChildren():
           if len(bone.children)==1:
              if bone.name!='origin':
                 #print bone.children[0].name
                 extend_skin(bone_id,int(get_info(bone.name,"r")))
                 if int(get_info(bone.name,"r"))%2!=0:
                    Draw.PupMenu("Error: uneven resolution on bone "+bone.name)
                 if int(get_info(bone.children[0].name,"r"))%2!=0:
                    Draw.PupMenu("Error: uneven resolution on bone "+bone.children[0].name)
                 if int(get_info(bone.name,"r"))>int(get_info(bone.children[0].name,"r"))+4:
                    Draw.PupMenu("Error: resolution change > 4 on bones "+bone.name+" and "+bone.children[0].name)
                 if int(get_info(bone.name,"r"))<int(get_info(bone.children[0].name,"r"))-4:
                    Draw.PupMenu("Error: resolution change > 4 on bones "+bone.name+" and "+bone.children[0].name)
                 connect_bones(bone_id,get_bone_id(bone.children[0].name), int(get_info(bone.name,"r")),int(get_info(bone.children[0].name,"r")))
           if len(bone.children)==2:
              extend_segs=int(get_info(bone.name,"r"))
              extend_skin(bone_id,extend_segs)
              if int(get_info(bone.name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.name)
              if int(get_info(bone.children[0].name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.children[0].name)
              if int(get_info(bone.children[1].name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.children[1].name)
              if int(get_info(bone.name,"r"))!=int(get_info(bone.children[0].name,"r")):
                    Draw.PupMenu("Error: resolution change in T-crossing between bones "+bone.name+" and "+bone.children[0].name+" is not allowed")
              if int(get_info(bone.name,"r"))<int(get_info(bone.children[1].name,"r")):
                    Draw.PupMenu("Error: branching bone cannot be larger than stem bones ("+bone.name+" and "+bone.children[1].name+")")
              if int(get_info(bone.name,"r"))>int(get_info(bone.children[1].name,"r"))+4:
                    Draw.PupMenu("Error: resolution change > 4 on bones "+bone.name+" and "+bone.children[1].name)
              if int(get_info(bone.children[1].name,"s"))!=0:
                      Draw.PupMenu("Warning: unusual shift in "+bone.children[1].name+" Twist modifier recommended for T-crossings")
              if def_method==1:
                 dist_max=100000
                 twist_max=0
                 for twist in range(0,extend_segs/2):
                     if get_info(bone.children[1].name,"o")=="R":
                        dist_test=calc_t_right(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),twist)
                     else:
                         dist_test=calc_t_left(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),twist)
                     if dist_test<dist_max:
                        dist_max=dist_test
                        twist_max=twist
                     print twist,dist_test,dist_max,twist_max
                 #twist_max=3
                 print twist_max
                 if get_info(bone.children[1].name,"o")=="R":
                    opt_t_right(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),twist_max)
                 else:
                      opt_t_left(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),twist_max)
              else:
                   if int(get_info(bone.children[1].name,"t"))>int(get_info(bone.name,"r"))/2:
                      Draw.PupMenu("Error: twist in "+bone.children[1].name+" exceeded 1/2 mesh resolution of stem "+bone.name)
                   if get_info(bone.children[1].name,"o")=="R":
                      connect_t_right(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),int(get_info(bone.children[1].name,"t")))
                   else:
                        connect_t_left(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),int(get_info(bone.children[1].name,"t")))
           if len(bone.children)==3:
              extend_segs=int(get_info(bone.name,"r"))
              extend_skin(bone_id,extend_segs)
              if int(get_info(bone.name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.name)
              if int(get_info(bone.children[0].name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.children[0].name)
              if int(get_info(bone.children[1].name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.children[1].name)
              if int(get_info(bone.children[2].name,"r"))%2!=0:
                 Draw.PupMenu("Error: uneven resolution on bone "+bone.children[2].name)
              if int(get_info(bone.name,"r"))!=int(get_info(bone.children[0].name,"r")):
                    Draw.PupMenu("Error: resolution change in X-crossing between bones "+bone.name+" and "+bone.children[0].name+" is not allowed")
              if int(get_info(bone.children[1].name,"r"))!=int(get_info(bone.children[2].name,"r")):
                    Draw.PupMenu("Error: resolution of branches in X-crossing ("+bone.children[1].name+" and "+bone.children[2].name+") must be equal")
              if int(get_info(bone.name,"r"))<int(get_info(bone.children[1].name,"r")):
                    Draw.PupMenu("Error: branching bones cannot be larger than stem bones ("+bone.name+", "+bone.children[1].name+" and "+bone.children[2].name+")")
              if int(get_info(bone.name,"r"))>int(get_info(bone.children[1].name,"r"))+4:
                    Draw.PupMenu("Error: resolution change > 4 on bones "+bone.name+" and "+bone.children[1].name)
              if int(get_info(bone.children[1].name,"s"))>(int(get_info(bone.name,"r"))-int(get_info(bone.children[1].name,"r")))/2:
                      Draw.PupMenu("Error: shift in "+bone.children[1].name+" exceeded maximally allowed value (stem_res-branch_res/2)")
              if int(get_info(bone.children[1].name,"s"))!=int(get_info(bone.children[2].name,"s")):
                      Draw.PupMenu("Warning: shift in "+bone.children[1].name+" and "+bone.children[2].name+" are not equal. Using shift in "+bone.children[1].name)
              if int(get_info(bone.children[1].name,"t"))!=int(get_info(bone.children[2].name,"t")):
                      Draw.PupMenu("Warning: twist in "+bone.children[1].name+" and "+bone.children[2].name+" are not equal. Using twist in "+bone.children[1].name)
              if def_method==1:
                 dist_max=100000
                 twist_max=0
                 for twist in range(0,extend_segs/2):
                     dist_test=calc_cross(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[2].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),twist)
                     if dist_test<dist_max:
                        dist_max=dist_test
                        twist_max=twist
                 #twist_max=3
                 print twist_max
                 opt_cross(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[2].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),twist_max)
              else:
                   if int(get_info(bone.children[1].name,"t"))>int(get_info(bone.name,"r"))/2:
                      Draw.PupMenu("Error: twist in "+bone.children[1].name+" exceeded 1/2 mesh resolution of stem "+bone.name)
                   connect_cross(bone_id,get_bone_id(bone.children[0].name),get_bone_id(bone.children[2].name),get_bone_id(bone.children[1].name),int(get_info(bone.name,"r")),int(get_info(bone.children[1].name,"r")),int(get_info(bone.children[1].name,"s")),int(get_info(bone.children[1].name,"t")))
        else:
          extend_segs=int(get_info(bone.name,"r"))
          extend_skin(bone_id,extend_segs)
          #make_cap(bone_id)
        bone_id=bone_id+1

    mesh_obj=NMesh.PutRaw(blender_mesh,'skin_obj')

    #assign bone weights

    bone_id=0
    for bone in armData.bones.values():
        extend_segs=int(get_info(bone.name,"r"))
        make_weights(bone_id,0,bone_dict[bone_id],extend_segs)
        make_weights(bone_id,1,bone_dict[bone_id],extend_segs)
        make_weights(bone_id,2,bone_dict[bone_id],extend_segs)
        bone_id=bone_id+1
    
    #link armature and mesh

    armObj.makeParentDeform([mesh_obj], 0, 0)

    for vert in vert_dict:
        #print vert
        blender_mesh.verts[vert].sel=1
    blender_mesh.update();
    scene.update();
    
def run_bonemod():
    global mesh_segs
    Window.EditMode(0)
    
    scene = Blender.Scene.getCurrent()
    armObj = scene.objects.active
    if not armObj or armObj.type!='Armature':
        Draw.PupMenu('You need to select an Armature first')
        return
    armData = armObj.getData()
    armData.drawAxes = True
    armObj.link(armData)
    
    found_bone=0
    bone_count=1
    for bone in armData.bones.values():
        print bone.name
        for B_option in bone.options:
            print B_option.value
            if B_option.value == 1:
               selected_bone=bone
               found_bone=1
               bone_id=bone_count
               break
        bone_count=bone_count+1
    if found_bone==0:
       Window.EditMode(1)
       Draw.PupMenu('No Bone selected for editing')
       return
    block = []
    bonename_b = Blender.Draw.Create(str(bone_id))
    boneres_b=Blender.Draw.Create(int(get_info(selected_bone.name,"r")))
    bonetwist_b=Blender.Draw.Create(int(get_info(selected_bone.name,"t")))
    boneshift_b=Blender.Draw.Create(int(get_info(selected_bone.name,"s")))
    boneori_b=Blender.Draw.Create(get_info(selected_bone.name,"o"))
    boneu1_b=Blender.Draw.Create(int(get_info(selected_bone.name,"u")))
    boneu2_b=Blender.Draw.Create(int(get_info(selected_bone.name,"w")))
    bonev1_b=Blender.Draw.Create(int(get_info(selected_bone.name,"v")))
    bonev2_b=Blender.Draw.Create(int(get_info(selected_bone.name,"x")))
    boneuvturn_b=Blender.Draw.Create(int(get_info(selected_bone.name,"a")))
    block.append(("ID: ", bonename_b, 0, 30, "this is some tool tip"))
    block.append(("res: ", boneres_b, 4, 100, "this is some tool tip"))
    block.append(("twist: ", bonetwist_b, 0, 100, "this is some tool tip"))
    block.append(("shift: ", boneshift_b, 0, 100, "this is some tool tip"))
    block.append(("ori (R or L): ", boneori_b, 0, 30, "this is some tool tip"))
    block.append(("Ustart: ", boneu1_b, 0, 50, "this is some tool tip"))
    block.append(("Uend: ", boneu2_b, 0, 50, "this is some tool tip"))
    block.append(("Vstart: ", bonev1_b, 0, 50, "this is some tool tip"))
    block.append(("Vend: ", bonev2_b, 0, 50, "this is some tool tip"))
    block.append(("UVcshift: ", boneuvturn_b, 0, 50, "this is some tool tip"))
    
    retval = Blender.Draw.PupBlock("Skinny 0.8alpha", block)

    if retval==0:
       Window.EditMode(1)
       return
       
    armData.makeEditable()
    new_name="n:"+str(bone_id)
    if boneres_b.val!=mesh_segs:
       new_name=new_name+"_r:"+str(boneres_b.val)
    if boneshift_b!=0:
       new_name=new_name+"_s:"+str(boneshift_b.val)
    if bonetwist_b!=0:
       new_name=new_name+"_t:"+str(bonetwist_b.val)
    if boneori_b!="none":
       new_name=new_name+"_o:"+boneori_b.val
    if boneu1_b!=0:
       new_name=new_name+"_u:"+str(boneu1_b.val)
    if boneu2_b!=1:
       new_name=new_name+"_w:"+str(boneu2_b.val)
    if bonev1_b!=0:
       new_name=new_name+"_v:"+str(bonev1_b.val)
    if bonev2_b!=1:
       new_name=new_name+"_x:"+str(bonev2_b.val)
    if boneuvturn_b!=0:
       new_name=new_name+"_a:"+str(boneuvturn_b.val)
    armData.bones[selected_bone.name].name = new_name
    armData.update()
    armObj.getPose().update()
    Window.EditMode(1)

#gui stuff
    
mystring = ""
mymsg = ""
toggle = 0
    
def event(evt, val):    # the function to handle input events
  global mystring, mymsg

  if not val:  # val = 0: it's a key/mbutton release
    if evt in [Draw.LEFTMOUSE, Draw.MIDDLEMOUSE, Draw.RIGHTMOUSE]:
      Draw.Redraw(1)
    return

  if evt == Draw.ESCKEY:
    Draw.Exit()                 # exit when user presses ESC
    return

  elif Draw.AKEY <= evt <= Draw.ZKEY: mystring += chr(evt)
  elif evt == Draw.SPACEKEY: mystring += ' '
  elif evt == Draw.BACKSPACEKEY and len(mystring):
    mystring = mystring[:-1]
  else: return # no need to redraw if nothing changed

  Draw.Redraw(1)

def button_event(evt):  # the function to handle Draw Button events
  if evt == 1:
    Draw.Redraw(1)
    run_skinny()
  if evt == 2:
    Draw.Redraw(1)
    run_bonemod()

def gui():              # the function to draw the screen
  global mystring, mymsg, toggle
  BGL.glClearColor(0,0,0,1)
  BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
  BGL.glColor3f(1,1,1)
  Draw.PushButton("Skinny", 1, 10, 10, 70, 20, "Run the Skinny Script")
  BGL.glClearColor(0,0,0,1)
  BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
  BGL.glColor3f(1,1,1)
  Draw.PushButton("Edit Bone", 2, 90, 10, 70, 20, "Load Bone Options")

Draw.Register(gui, event, button_event)  # registering the 3 callbacks
