Skip to content
Snippets Groups Projects
io_import_scene_unreal_psa_psk.py 48.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    bl_info = {
        "name": "Import Unreal Skeleton Mesh (.psk)/Animation Set (psa)",
        "author": "Darknet, flufy3d, camg188",
    
        "version": (2, 2),
    
        "blender": (2, 64, 0),
    
        "location": "File > Import > Skeleton Mesh (.psk)/Animation Set (psa)",
        "description": "Import Skeleleton Mesh/Animation Data",
        "warning": "",
        "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"
            "Scripts/Import-Export/Unreal_psk_psa",
        "tracker_url": "https://projects.blender.org/tracker/index.php?"\
            "func=detail&aid=21366",
        "category": "Import-Export"}
    
    """
    Version': '2.0' ported by Darknet
    
    Unreal Tournament PSK file to Blender mesh converter V1.0
    Author: D.M. Sturgeon (camg188 at the elYsium forum), ported by Darknet
    Imports a *psk file to a new mesh
    
    -No UV Texutre
    -No Weight
    -No Armature Bones
    -No Material ID
    -Export Text Log From Current Location File (Bool )
    """
    
    import bpy
    import mathutils
    import math
    
    # XXX Yuck! 'from foo import *' is really bad!
    
    from mathutils import *
    from math import *
    from bpy.props import *
    from string import *
    from struct import *
    from math import *
    from bpy.props import *
    
    bpy.types.Scene.unrealbonesize = FloatProperty(
        name="Bone Length",
        description="Bone Length from head to tail distance",
    
    
    #output log in to txt file
    DEBUGLOG = False
    
    scale = 1.0
    bonesize = 1.0
    from bpy_extras.io_utils import unpack_list, unpack_face_list
    
    class md5_bone:
    
        bone_index = 0
        name = ""
        bindpos = []
        bindmat = []
        origmat = []
        head = []
        tail = []
    
        parent = ""
        parent_index = 0
        blenderbone = None
        roll = 0
    
            self.bone_index = 0
            self.name = ""
            self.bindpos = [0.0] * 3
            self.scale = [0.0] * 3
            self.head = [0.0] * 3
            self.tail = [0.0] * 3
            self.bindmat = [None] * 3  # is this how you initilize a 2d-array
            for i in range(3):
                self.bindmat[i] = [0.0] * 3
            self.origmat = [None] * 3  #is this how you initilize a 2d-array
            for i in range(3):
                self.origmat[i] = [0.0] * 3
            self.parent = ""
            self.parent_index = 0
            self.blenderbone = None
    
    
        def dump(self):
            print ("bone index: ", self.bone_index)
            print ("name: ", self.name)
            print ("bind position: ", self.bindpos)
            print ("bind translation matrix: ", self.bindmat)
            print ("parent: ", self.parent)
            print ("parent index: ", self.parent_index)
            print ("blenderbone: ", self.blenderbone)
    
    
        #pos = mathutils.Vector((x,y,z)) * pbone.origmat
        pos = pbone.bindmat.to_translation()
    
        """
        tmp_bone = pbone
        while tmp_bone.name != tmp_bone.parent.name:
            pos = pos * tmp_bone.parent.bindmat
            tmp_bone = tmp_bone.parent
        """
    
        pos_head[0] = pos.x
        pos_head[1] = pos.y
        pos_head[2] = pos.z
    
        ischildfound = False
        childbone = None
        childbonelist = []
        for bone in bones:
            if bone.parent.name == pbone.name:
                ischildfound = True
                childbone = bone
                childbonelist.append(bone)
                
        if ischildfound:
    
            for bone in childbonelist:
                tmp_head[0] += bone.head[0]
                tmp_head[1] += bone.head[1]
                tmp_head[2] += bone.head[2]
            tmp_head[0] /= len(childbonelist)
            tmp_head[1] /= len(childbonelist)
            tmp_head[2] /= len(childbonelist)
            return tmp_head
        else:
            tmp_len = 0.0
    
            tmp_len += (pbone.head[0] - pbone.parent.head[0]) ** 2
            tmp_len += (pbone.head[1] - pbone.parent.head[1]) ** 2
            tmp_len += (pbone.head[2] - pbone.parent.head[2]) ** 2
            tmp_len = tmp_len ** 0.5 * 0.5
    
            pos_tail[0] = pbone.head[0] + tmp_len * pbone.bindmat[0][0]
            pos_tail[1] = pbone.head[1] + tmp_len * pbone.bindmat[1][0]
            pos_tail[2] = pbone.head[2] + tmp_len * pbone.bindmat[2][0]
    
        return pos_tail
    
    def pskimport(infile,importmesh,importbone,bDebugLogPSK,importmultiuvtextures):
        global DEBUGLOG
        DEBUGLOG = bDebugLogPSK
        print ("--------------------------------------------------")
        print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------")
        print ("--------------------------------------------------")
        print (" DEBUG Log:",bDebugLogPSK)
        print ("Importing file: ", infile)
    
        pskfile = open(infile,'rb')
        if (DEBUGLOG):
            logpath = infile.replace(".psk", ".txt")
            print("logpath:",logpath)
            logf = open(logpath,'w')
    
        def printlog(strdata):
            if (DEBUGLOG):
                logf.write(strdata)
    
        objName = infile.split('\\')[-1].split('.')[0]
    
        me_ob = bpy.data.meshes.new(objName)
        print("objName:",objName)
        printlog(("New Mesh = " + me_ob.name + "\n"))
        #read general header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        #not using the general header at this time
        #================================================================================================== 
        # vertex point
        #================================================================================================== 
        #read the PNTS0000 header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        printlog(("Nbr of PNTS0000 records: " + str(recCount) + "\n"))
    
        counter = 0
        verts = []
        verts2 = []
        while counter < recCount:
            counter = counter + 1
    
            indata = unpack('3f', pskfile.read(12))
            #print(indata[0], indata[1], indata[2])
            verts.extend([(indata[0], indata[1], indata[2])])
            verts2.extend([(indata[0], indata[1], indata[2])])
            #print([(indata[0], indata[1], indata[2])])
            printlog(str(indata[0]) + "|" + str(indata[1]) + "|" + str(indata[2]) + "\n")
            #Tmsh.vertices.append(NMesh.Vert(indata[0], indata[1], indata[2]))
    
    
        #================================================================================================== 
        # UV
        #================================================================================================== 
        #read the VTXW0000 header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        printlog("Nbr of VTXW0000 records: " + str(recCount)+ "\n")
    
        counter = 0
        UVCoords = []
        #UVCoords record format = [index to PNTS, U coord, v coord]
        printlog("[index to PNTS, U coord, v coord]\n");
        while counter < recCount:
            counter = counter + 1
    
            indata = unpack('hhffhh', pskfile.read(16))
            UVCoords.append([indata[0], indata[2], indata[3]])
            printlog(str(indata[0]) + "|" + str(indata[2]) + "|" + str(indata[3]) + "\n")
            #print('mat index %i', indata(4))
            #print([indata[0], indata[2], indata[3]])
            #print([indata[1], indata[2], indata[3]])
    
    
        #================================================================================================== 
        # Face
        #================================================================================================== 
        #read the FACE0000 header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        printlog("Nbr of FACE0000 records: " + str(recCount) + "\n")
    
        #PSK FACE0000 fields: WdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp
        #associate MatIdx to an image, associate SmthGrp to a material
        SGlist = []
        counter = 0
        faces = []
        faceuv = []
        facesmooth = []
        #the psk values are: nWdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp
        printlog("nWdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp \n")
        while counter < recCount:
            counter = counter + 1
    
            indata = unpack('hhhbbi', pskfile.read(12))
            printlog(str(indata[0]) + "|" + str(indata[1]) + "|" + str(indata[2]) + "|" + str(indata[3]) + "|" +
                     str(indata[4]) + "|" + str(indata[5]) + "\n")
    
            #indata[0] = index of UVCoords
            #UVCoords[indata[0]]=[index to PNTS, U coord, v coord]
            #UVCoords[indata[0]][0] = index to PNTS
            PNTSA = UVCoords[indata[2]][0]
            PNTSB = UVCoords[indata[1]][0]
            PNTSC = UVCoords[indata[0]][0]
    
            #print(PNTSA, PNTSB, PNTSC) #face id vertex
            #faces.extend([0, 1, 2, 0])
            faces.extend([(PNTSA, PNTSB, PNTSC, 0)])
    
            uv = []
            u0 = UVCoords[indata[2]][1]
            v0 = UVCoords[indata[2]][2]
    
            u1 = UVCoords[indata[1]][1]
            v1 = UVCoords[indata[1]][2]
    
            u2 = UVCoords[indata[0]][1]
            v2 = UVCoords[indata[0]][2]
    
            uv.append([u2, 1.0 - v2])
            faceuv.append([uv, indata[3], indata[4], indata[5]])
    
            #print("material:", indata[3])
            #print("UV: ", u0, v0)
    
            #update the uv var of the last item in the Tmsh.faces list
            # which is the face just added above
    
            ##Tmsh.faces[-1].uv = [(u0, v0), (u1, v1), (u2, v2)]
    
            #print("smooth:",indata[5])
            #collect a list of the smoothing groups
            facesmooth.append(indata[5])
            #print(indata[5])
            if SGlist.count(indata[5]) == 0:
                SGlist.append(indata[5])
    
            #assign a material index to the face
            #Tmsh.faces[-1].materialIndex = SGlist.index(indata[5])
    
        printlog("Using Materials to represent PSK Smoothing Groups...\n")
    
        #==========
        # skip something...
        #==========
    
        #================================================================================================== 
        # Material
        #================================================================================================== 
        ##
        #read the MATT0000 header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        recCount = indata[3]
        printlog("Nbr of MATT0000 records: " +  str(recCount) + "\n" )
        printlog(" - Not importing any material data now. PSKs are texture wrapped! \n")
        counter = 0
        materialcount = 0
        while counter < recCount:
            counter = counter + 1
    
            indata = unpack('64s6i', pskfile.read(88))
    
            print("Material", counter)
            print("Mat name %s", indata[0])
    
    
        ##
        #================================================================================================== 
        # Bones (Armature)
        #================================================================================================== 
        #read the REFSKEL0 header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        recCount = indata[3]
        printlog( "Nbr of REFSKEL0 records: " + str(recCount) + "\n")
        #REFSKEL0 fields - Name|Flgs|NumChld|PrntIdx|Qw|Qx|Qy|Qz|LocX|LocY|LocZ|Lngth|XSize|YSize|ZSize
    
        md5_bones = []
        bni_dict = {}
        #================================================================================================== 
        # Bone Data 
        #==================================================================================================
        counter = 0
        print ("---PRASE--BONES---")
        printlog("Name|Flgs|NumChld|PrntIdx|Qx|Qy|Qz|Qw|LocX|LocY|LocZ|Lngth|XSize|YSize|ZSize\n")
        while counter < recCount:
    
            indata = unpack('64s3i11f', pskfile.read(120))
    
            createbone = md5_bone()
            #temp_name = indata[0][:30]
            temp_name = indata[0]
            temp_name = bytes.decode(temp_name)
            temp_name = temp_name.lstrip(" ")
            temp_name = temp_name.rstrip(" ")
            temp_name = temp_name.strip()
            temp_name = temp_name.strip( bytes.decode(b'\x00'))
    
            printlog(temp_name + "|" + str(indata[1]) + "|" + str(indata[2]) + "|" + str(indata[3]) + "|" +
                     str(indata[4]) + "|" + str(indata[5]) + "|" + str(indata[6]) + "|" + str(indata[7]) + "|" +
                     str(indata[8]) + "|" + str(indata[9]) + "|" + str(indata[10]) + "|" + str(indata[11]) + "|" +
                     str(indata[12]) + "|" + str(indata[13]) + "|" + str(indata[14]) + "\n")
    
            createbone.name = temp_name
            createbone.bone_index = counter
            createbone.parent_index = indata[3]
            createbone.bindpos[0] = indata[8]
            createbone.bindpos[1] = indata[9]
            createbone.bindpos[2] = indata[10]
            createbone.scale[0] = indata[12]
            createbone.scale[1] = indata[13]
            createbone.scale[2] = indata[14]
    
            bni_dict[createbone.name] = createbone.bone_index
    
            #w,x,y,z
            if (counter == 0):#main parent
    
                 createbone.bindmat = mathutils.Quaternion((indata[7], -indata[4], -indata[5], -indata[6])).to_matrix()
                 createbone.origmat = mathutils.Quaternion((indata[7], -indata[4], -indata[5], -indata[6])).to_matrix()
    
                 createbone.bindmat = mathutils.Quaternion((indata[7], -indata[4], -indata[5], -indata[6])).to_matrix()
                 createbone.origmat = mathutils.Quaternion((indata[7], -indata[4], -indata[5], -indata[6])).to_matrix()
    
            createbone.bindmat = mathutils.Matrix.Translation(mathutils.Vector((indata[8], indata[9], indata[10]))) * \
                                 createbone.bindmat.to_4x4()
    
    
            md5_bones.append(createbone)
            counter = counter + 1
            bnstr = (str(indata[0]))
            Bns.append(bnstr)
    
            pbone.parent = md5_bones[pbone.parent_index]
    
        for pbone in md5_bones:
            if pbone.name != pbone.parent.name:
    
                pbone.bindmat = pbone.parent.bindmat * pbone.bindmat 
    
                #print(pbone.name)
                #print(pbone.bindmat)
                #print("end")
            else:
                pbone.bindmat = pbone.bindmat
    
            pbone.tail = gettailpos(pbone, md5_bones)
    
    
        for pbone in md5_bones:
            pbone.parent =  md5_bones[pbone.parent_index].name
    
        bonecount = 0
        for armbone in bone:
            temp_name = armbone[0][:30]
    
            temp_name=str((temp_name))
            #temp_name = temp_name[1]
    
            #print ("BONE NAME: ", temp_name)
            bonecount += 1
    
        print ("-------------------------")
        print ("----Creating--Armature---")
        print ("-------------------------")
    
        #================================================================================================
        #Check armature if exist if so create or update or remove all and addnew bone
        #================================================================================================
        #bpy.ops.object.mode_set(mode='OBJECT')
        meshname ="ArmObject"
        objectname = "armaturedata"
        # arm = None  # UNUSED
        if importbone:
            obj = bpy.data.objects.get(meshname)
            # arm = obj  # UNUSED
    
            if not obj:
                armdata = bpy.data.armatures.new(objectname)
                ob_new = bpy.data.objects.new(meshname, armdata)
                #ob_new = bpy.data.objects.new(meshname, 'ARMATURE')
                #ob_new.data = armdata
                bpy.context.scene.objects.link(ob_new)
                #bpy.ops.object.mode_set(mode='OBJECT')
    
                for i in bpy.context.scene.objects:
                    i.select = False #deselect all objects
    
                ob_new.select = True
                #set current armature to edit the bone
                bpy.context.scene.objects.active = ob_new
                #set mode to able to edit the bone
                if bpy.ops.object.mode_set.poll():
                    bpy.ops.object.mode_set(mode='EDIT')
    
                #newbone = ob_new.data.edit_bones.new('test')
                #newbone.tail.y = 1
                print("creating bone(s)")
                bpy.ops.object.mode_set(mode='OBJECT')
                for bone in md5_bones:
                    #print(dir(bone))
                    bpy.ops.object.mode_set(mode='EDIT')#Go to edit mode for the bones
                    newbone = ob_new.data.edit_bones.new(bone.name)
                    #parent the bone
    
                    parentbone = None
                    #note bone location is set in the real space or global not local
                    bonesize = bpy.types.Scene.unrealbonesize
                    if bone.name != bone.parent:
                        pos_x = bone.bindpos[0]
                        pos_y = bone.bindpos[1]
                        pos_z = bone.bindpos[2]
    
                        parentbone = ob_new.data.edit_bones[bone.parent]
                        newbone.parent = parentbone
                        rotmatrix = bone.bindmat
                        newbone.head.x = bone.head[0]
                        newbone.head.y = bone.head[1]
                        newbone.head.z = bone.head[2]
                        newbone.tail.x = bone.tail[0]
                        newbone.tail.y = bone.tail[1]
                        newbone.tail.z = bone.tail[2]
    
                        vecp = parentbone.tail - parentbone.head
                        vecc = newbone.tail - newbone.head
                        vecc.normalize()
                        vecp.normalize()
                        if vecp.dot(vecc) > -0.8:
                            newbone.roll = parentbone.roll
                        else:
                            newbone.roll = - parentbone.roll
                    else:
                        rotmatrix = bone.bindmat
                        newbone.head.x = bone.head[0]
                        newbone.head.y = bone.head[1]
                        newbone.head.z = bone.head[2]
                        newbone.tail.x = bone.tail[0]
                        newbone.tail.y = bone.tail[1]
                        newbone.tail.z = bone.tail[2]
                        newbone.roll = math.radians(90.0)
                    """
                    vec = newbone.tail - newbone.head 
                    if vec.z > 0.0:
                        newbone.roll = math.radians(90.0)
                    else:
                        newbone.roll = math.radians(-90.0)
                    """
        bpy.context.scene.update()
    
        #==================================================================================================
        #END BONE DATA BUILD
        #==================================================================================================
        VtxCol = []
        for x in range(len(Bns)):
            #change the overall darkness of each material in a range between 0.1 and 0.9
    
            tmpVal = ((float(x) + 1.0) / (len(Bns)) * 0.7) + 0.1
    
            #Change the color of each material slightly
            if x % 3 == 0:
    
                if tmpCol[0] < 128:
                    tmpCol[0] += 60
                else:
                    tmpCol[0] -= 60
    
                if tmpCol[1] < 128:
                    tmpCol[1] += 60
                else:
                    tmpCol[1] -= 60
    
                if tmpCol[2] < 128:
                    tmpCol[2] += 60
                else:
                    tmpCol[2] -= 60
    
            #Add the material to the mesh
            VtxCol.append(tmpCol)
    
        #================================================================================================== 
        # Bone Weight
        #================================================================================================== 
        #read the RAWW0000 header
    
        indata = unpack('20s3i', pskfile.read(32))
    
        printlog("Nbr of RAWW0000 records: " + str(recCount) +"\n")
    
        #RAWW0000 fields: Weight|PntIdx|BoneIdx
        RWghts = []
        counter = 0
        while counter < recCount:
            counter = counter + 1
    
            indata = unpack('fii', pskfile.read(12))
            RWghts.append([indata[1], indata[2], indata[0]])
            #print("weight:", [indata[1], indata[2], indata[0]])
    
        #RWghts fields = PntIdx|BoneIdx|Weight
        RWghts.sort()
    
        printlog("Vertex point and groups count =" + str(len(RWghts)) + "\n")
    
        printlog("PntIdx|BoneIdx|Weight")
        for vg in RWghts:
    
            printlog(str(vg[0]) + "|" + str(vg[1]) + "|" + str(vg[2]) + "\n")
    
    
        #set the Vertex Colors of the faces
        #face.v[n] = RWghts[0]
        #RWghts[1] = index of VtxCol
        """
        for x in range(len(Tmsh.faces)):
            for y in range(len(Tmsh.faces[x].v)):
                #find v in RWghts[n][0]
                findVal = Tmsh.faces[x].v[y].index
                n = 0
                while findVal != RWghts[n][0]:
                    n = n + 1
                TmpCol = VtxCol[RWghts[n][1]]
                #check if a vertex has more than one influence
    
                if n != len(RWghts) - 1:
                    if RWghts[n][0] == RWghts[n + 1][0]:
    
                        #if there is more than one influence, use the one with the greater influence
                        #for simplicity only 2 influences are checked, 2nd and 3rd influences are usually very small
    
                        if RWghts[n][2] < RWghts[n + 1][2]:
                            TmpCol = VtxCol[RWghts[n + 1][1]]
            Tmsh.faces[x].col.append(NMesh.Col(TmpCol[0], TmpCol[1], TmpCol[2], 0))
    
        """
        if (DEBUGLOG):
            logf.close()
        #================================================================================================== 
        #Building Mesh
        #================================================================================================== 
    
        print("vertex:", len(verts), "faces:", len(faces))
        print("vertex2:", len(verts2))
    
        me_ob.vertices.add(len(verts2))
        me_ob.tessfaces.add(len(faces))
        me_ob.vertices.foreach_set("co", unpack_list(verts2))
    
        me_ob.tessfaces.foreach_set("vertices_raw", unpack_list( faces))
    
    
        """
        Material setup coding.
        First the mesh has to be create first to get the uv texture setup working.
        -Create material(s) list in the psk pack data from the list.(to do list)
        -Append the material to the from create the mesh object.
        -Create Texture(s)
    
        -face loop for uv assign and assign material index
    
        """
        bpy.ops.object.mode_set(mode='OBJECT')
        #===================================================================================================
        #Material Setup
        #===================================================================================================
        print ("-------------------------")
        print ("----Creating--Materials--")
        print ("-------------------------")
        materialname = "pskmat"
        materials = []
    
        for matcount in range(materialcount):
            #if texturedata != None:
            matdata = bpy.data.materials.new(materialname + str(matcount))
            #mtex = matdata.texture_slots.new()
            #mtex.texture = texture[matcount].data
            #print(type(texture[matcount].data))
            #print(dir(mtex))
            #print(dir(matdata))
            #for texno in range(len( bpy.data.textures)):
    
                #print(dir(bpy.data.textures[texno]))
    
            #matdata.active_texture = bpy.data.textures[matcount - 1]
    
            #matdata.texture_coords = 'UV'
            #matdata.active_texture = texturedata
            materials.append(matdata)
    
        for material in materials:
            #add material to the mesh list of materials
            me_ob.materials.append(material)
        #===================================================================================================
        #UV Setup
        #===================================================================================================
        print ("-------------------------")
        print ("-- Creating UV Texture --")
        print ("-------------------------") 
        texture = []
        # texturename = "text1"  # UNUSED
        countm = 0
        for countm in range(materialcount):
    
            me_ob.uv_textures.new(name=psktexname)
            countm += 1
        print("INIT UV TEXTURE...")
        _matcount = 0
        #for mattexcount in materials:
    
        _textcount = 0
        for uv in me_ob.tessface_uv_textures: # uv texture
            print("UV TEXTURE ID:",_textcount)
            print(dir(uv))
            for face in me_ob.tessfaces:# face, uv
                #print(dir(face))
                if faceuv[face.index][1] == _textcount: #if face index and texture index matches assign it
                    mfaceuv = faceuv[face.index] #face index
                    _uv1 = mfaceuv[0][0] #(0,0)
    
                    uv.data[face.index].uv1 = mathutils.Vector((_uv1[0], _uv1[1])) #set them
    
                    uv.data[face.index].uv2 = mathutils.Vector((_uv2[0], _uv2[1])) #set them
    
                    uv.data[face.index].uv3 = mathutils.Vector((_uv3[0], _uv3[1])) #set them
    
                else: #if not match zero them
    
                    uv.data[face.index].uv1 = mathutils.Vector((0, 0)) #zero them 
                    uv.data[face.index].uv2 = mathutils.Vector((0, 0)) #zero them 
                    uv.data[face.index].uv3 = mathutils.Vector((0, 0)) #zero them 
    
            _textcount += 1
            #_matcount += 1
            #print(matcount)
        print("END UV TEXTURE...")
    
    
            #for tex in me_ob.uv_textures:
    
        #for face in me_ob.faces:
            #print(dir(face))
    
        #===================================================================================================
        #
        #===================================================================================================
        obmesh = bpy.data.objects.new(objName,me_ob)
        #===================================================================================================
        #Mesh Vertex Group bone weight
        #===================================================================================================
        print("---- building bone weight mesh ----")
        #print(dir(ob_new.data.bones))
        #create bone vertex group #deal with bone id for index number
        for bone in ob_new.data.bones:
    
            #print("names:", bone.name, ":", dir(bone))
            #print("names:", bone.name)
    
            group = obmesh.vertex_groups.new(bone.name)
    
        for vgroup in obmesh.vertex_groups:
    
            for vgp in RWghts:
                #bone index
                if vgp[1] == bni_dict[vgroup.name]:
                    #print(vgp)
                    #[vertex id],weight
                    vgroup.add([vgp[0]], vgp[2], 'ADD')
    
        #check if there is a material to set to
        if len(materials) > 0:
            obmesh.active_material = materials[0] #material setup tmp
        print("---- adding mesh to the scene ----")
    
        bpy.ops.object.mode_set(mode='OBJECT')
        #bpy.ops.object.select_pattern(extend=True, pattern=obmesh.name, case_sensitive=True)
        #bpy.ops.object.select_pattern(extend=True, pattern=ob_new.name, case_sensitive=True)
    
        #bpy.ops.object.select_name(name=str(obmesh.name))
        #bpy.ops.object.select_name(name=str(ob_new.name))
        #bpy.context.scene.objects.active = ob_new
        me_ob.update()
        bpy.context.scene.objects.link(obmesh)   
        bpy.context.scene.update()
        obmesh.select = False
        ob_new.select = False
        obmesh.select = True
        ob_new.select = True
        bpy.ops.object.parent_set(type="ARMATURE")
    
        print ("PSK2Blender completed")
    #End of def pskimport#########################
    
    
    def getInputFilenamepsk(self, filename, importmesh, importbone, bDebugLogPSK, importmultiuvtextures):
    
        checktype = filename.split('\\')[-1].split('.')[1]
        print ("------------",filename)
        if checktype.lower() != 'psk':
    
            raise (IOError, "The selected input file is not a *.psk file")
            #self.report({'INFO'}, ("Selected file:"+ filename))
        else:
    
            pskimport(filename, importmesh, importbone, bDebugLogPSK, importmultiuvtextures)
    
    def getInputFilenamepsa(self, filename, context):
    
        checktype = filename.split('\\')[-1].split('.')[1]
        if checktype.lower() != 'psa':
    
            raise (IOError, "The selected input file is not a *.psa file")
    
            #self.report({'INFO'}, ("Selected file:" + filename))
    
        else:
            psaimport(filename,context)
    
    class IMPORT_OT_psk(bpy.types.Operator):
        '''Load a skeleton mesh psk File'''
        bl_idname = "import_scene.psk"
        bl_label = "Import PSK"
        bl_space_type = "PROPERTIES"
        bl_region_type = "WINDOW"
        bl_options = {'UNDO'}
    
        # List of operator properties, the attributes will be assigned
        # to the class instance from the operator settings before calling.
        filepath = StringProperty(
                subtype='FILE_PATH',
                )
        filter_glob = StringProperty(
                default="*.psk",
                options={'HIDDEN'},
                )
        importmesh = BoolProperty(
                name="Mesh",
                description="Import mesh only. (not yet build.)",
                default=True,
                )
        importbone = BoolProperty(
                name="Bones",
                description="Import bones only. Current not working yet",
                default=True,
                )
        importmultiuvtextures = BoolProperty(
                name="Single UV Texture(s)",
                description="Single or Multi uv textures",
                default=True,
                )
        bDebugLogPSK = BoolProperty(
                name="Debug Log.txt",
    
                description="Log the output of raw format. It will save in "
    
                            "current file dir. Note this just for testing",
                default=False,
                )
        unrealbonesize = FloatProperty(
                name="Bone Length",
                description="Bone Length from head to tail distance",
                default=1,
                min=0.001,
                max=1000,
                )
    
        def execute(self, context):
            bpy.types.Scene.unrealbonesize = self.unrealbonesize
    
            getInputFilenamepsk(self, self.filepath, self.importmesh, self.importbone, self.bDebugLogPSK,
                                self.importmultiuvtextures)
    
            return {'FINISHED'}
    
        def invoke(self, context, event):
            wm = context.window_manager
            wm.fileselect_add(self)
    
    
    class psa_bone:
        name=""
        Transform=None
        parent=None
        def __init__(self):
            self.name=""
            self.Transform=None
            self.parent=None
    
    def psaimport(filename,context):
        print ("--------------------------------------------------")
        print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------")
        print ("--------------------------------------------------")
        print ("Importing file: ", filename)
        psafile = open(filename,'rb')
        debug = True
        if (debug):
            logpath = filename.replace(".psa", ".txt")
    
            print("logpath:", logpath)
            logf = open(logpath, 'w')
    
        def printlog(strdata):
            if (debug):
                logf.write(strdata)
    
                logf.write(str(name) + '\n')
                if isinstance(data, bytes):
    
                    logf.write(str(bytes.decode(data).strip(bytes.decode(b'\x00'))))
                else:
                    logf.write(str(data))
                logf.write('\n')
    
        printlog('-----------Log File------------\n')
        #General Header
    
        indata = unpack('20s3i', psafile.read(32))
        printlogplus('ChunkID', indata[0])
        printlogplus('TypeFlag', indata[1])
        printlogplus('DataSize', indata[2])
        printlogplus('DataCount', indata[3])
    
        indata = unpack('20s3i', psafile.read(32))
        printlogplus('ChunkID', indata[0])
        printlogplus('TypeFlag', indata[1])
        printlogplus('DataSize', indata[2])
        printlogplus('DataCount', indata[3])
    
        #Bones Data
        BoneIndex2NamePairMap = {}
        BoneNotFoundList = []
        printlog("Name|Flgs|NumChld|PrntIdx|Qx|Qy|Qz|Qw|LocX|LocY|LocZ|Length|XSize|YSize|ZSize\n")
        recCount = indata[3]
        counter = 0
        nobonematch = True
        while counter < recCount:
    
            indata = unpack('64s3i11f', psafile.read(120))
            #printlogplus('bone', indata[0])
    
            bonename = str(bytes.decode(indata[0]).strip(bytes.decode(b'\x00')))
            if bonename in bpy.data.armatures['armaturedata'].bones.keys():
                BoneIndex2NamePairMap[counter] = bonename
    
                print('can not find the bone:', bonename)
    
                BoneNotFoundList.append(counter)
            counter += 1
    
        if nobonematch:
            print('no bone was match so skip import!')
            return
    
        indata = unpack('20s3i', psafile.read(32))
        printlogplus('ChunkID', indata[0])
        printlogplus('TypeFlag', indata[1])
        printlogplus('DataSize', indata[2])
        printlogplus('DataCount', indata[3])
    
        #Animations Data
        recCount = indata[3]
        counter = 0
        Raw_Key_Nums = 0
        Action_List = []
        while counter < recCount:
    
            indata = unpack('64s64s4i3f3i', psafile.read(64 + 64 + 4 * 4 + 3 * 4 + 3 * 4))
            printlogplus('Name', indata[0])
            printlogplus('Group', indata[1])
            printlogplus('totalbones', indata[2])
            printlogplus('NumRawFrames', indata[-1])
    
            Name = str(bytes.decode(indata[0]).strip(bytes.decode(b'\x00')))
            Group = str(bytes.decode(indata[1]).strip(bytes.decode(b'\x00')))
            totalbones = indata[2]
            NumRawFrames = indata[-1]
    
            Raw_Key_Nums += indata[2] * indata[-1]
            Action_List.append((Name,Group,totalbones,NumRawFrames))
    
        #Raw keys Header
        Raw_Key_List = []
    
        indata = unpack('20s3i', psafile.read(32))
        printlogplus('ChunkID', indata[0])
        printlogplus('TypeFlag', indata[1])
        printlogplus('DataSize', indata[2])
        printlogplus('DataCount', indata[3])
    
        if(Raw_Key_Nums != indata[3]):
            print('error! Raw_Key_Nums Inconsistent')
            return
        #Raw keys Data
        recCount = Raw_Key_Nums
        counter = 0
        while counter < recCount:
    
            indata = unpack('3f4f1f', psafile.read(3 * 4 + 4 * 4 + 4))
    
            pos = mathutils.Vector((indata[0], indata[1], indata[2]))
            quat = mathutils.Quaternion((indata[6], indata[3], indata[4], indata[5]))
            time = indata[7]
    
            counter += 1
        #Scale keys Header,Scale keys Data,Curve keys Header,Curve keys Data
        curFilePos = psafile.tell()
    
        endFilePos = psafile.tell()
        if curFilePos == endFilePos:
            print('no Scale keys,Curve keys')
    
        #build the animation line
        if bpy.ops.object.mode_set.poll():
            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
        ARMATURE_OBJ = 'ArmObject'
        ARMATURE_DATA = 'armaturedata'
        if bpy.context.scene.udk_importarmatureselect:
            if len(bpy.context.scene.udkas_list) > 0:
                print("CHECKING ARMATURE...")
    
                #for bone in bpy.data.objects[ARMATURE_OBJ].pose.bones:
    
                #for objd in bpy.data.objects:
    
                    #print("NAME:", objd.name, " TYPE:", objd.type)
    
                    #if objd.type == 'ARMARURE':
                        #print(dir(objd))
                armature_list = bpy.context.scene.udkas_list #armature list array
                armature_idx = bpy.context.scene.udkimportarmature_list_idx #armature index selected
                ARMATURE_OBJ = bpy.data.objects[armature_list[armature_idx]].name #object armature
                ARMATURE_DATA = bpy.data.objects[armature_list[armature_idx]].data.name #object data
    
        for bone in bpy.data.armatures[ARMATURE_DATA].bones:
    
            name = bone.name
            ori_matrix = bone.matrix
            matrix = bone.matrix_local.to_3x3()
            bone_rest_matrix = Matrix(matrix)
            #bone_rest_matrix = bone.matrix_local.to_3x3()
            #bone_rest_matrix = bone.matrix_local.to_quaternion().conjugated().to_matrix()
            bone_rest_matrix_inv = Matrix(bone_rest_matrix)
            bone_rest_matrix_inv.invert()
            bone_rest_matrix_inv.resize_4x4()
            bone_rest_matrix.resize_4x4()
            NeededBoneMatrix[name] = (bone_rest_matrix,bone_rest_matrix_inv,ori_matrix)
    
        #build tmp pose bone tree
        psa_bones = {}
    
        for bone in bpy.data.objects[ARMATURE_OBJ].pose.bones:
    
            _psa_bone = psa_bone()
            _psa_bone.name = bone.name
            _psa_bone.Transform = bone.matrix
            if bone.parent != None:
                _psa_bone.parent = psa_bones[bone.parent.name]
            else:
                _psa_bone.parent = None
            psa_bones[bone.name] = _psa_bone
    
        raw_key_index = 0
    
        for raw_action in Action_List:
    
            Name = raw_action[0]
            Group = raw_action[1]
            Totalbones = raw_action[2]
            NumRawFrames = raw_action[3]
    
            context.scene.update()
            object = bpy.data.objects['ArmObject']
            object.animation_data_create()
    
            action = bpy.data.actions.new(name=Name)
    
            object.animation_data.action = action
            for i in range(NumRawFrames):
    
                pose_bones = object.pose.bones
                for j in range(Totalbones):
                    if j not in BoneNotFoundList:
                        bName = BoneIndex2NamePairMap[j]
    
                        pos = Raw_Key_List[raw_key_index][0]
                        quat = Raw_Key_List[raw_key_index][1]
    
                        mat = Matrix()
                        if pbone.parent != None:
                            quat = quat.conjugated()
                            mat = Matrix.Translation(pos) * quat.to_matrix().to_4x4()
                            mat = pose_bones[bName].parent.matrix * mat 
                            #mat = pbone.parent.Transform * mat
                        else:
                            mat = pbone.Transform * Matrix.Translation(pos) * quat.to_matrix().to_4x4()
    
                        pose_bones[bName].matrix = mat
                        pbone.Transform = mat
    
                    raw_key_index += 1
    
                #bpy.data.meshes[1]
    
                    bone.matrix = psa_bones[bone.name].Transform
                    bone.keyframe_insert("rotation_quaternion")
                    bone.keyframe_insert("location")
    
                def whirlSingleBone(pose_bone,quat):
                    bpy.context.scene.update()
                    #record child's matrix and origin rotate