Skip to content
Snippets Groups Projects
io_export_unreal_psk_psa.py 101 KiB
Newer Older
Luca Bonavita's avatar
Luca Bonavita committed
        set_position = (parent_tail - parent_head) + blender_bone.head
    else:
        # ROOT BONE
        #This for root 
        set_position = parent_matrix * blender_bone.head #ARMATURE OBJECT Locction
        rot_mat = blender_bone.matrix * parent_matrix.to_3x3() #ARMATURE OBJECT Rotation
Luca Bonavita's avatar
Luca Bonavita committed
        #print(dir(rot_mat))
        
        quat = make_fquat_default(rot_mat.to_quaternion())
Luca Bonavita's avatar
Luca Bonavita committed
        
    #print ("[[======= FINAL POSITION:", set_position)
    final_parent_id = parent_id
    
    #RG/RE -
    #if we are not separated by a small distance, create a dummy bone for the displacement
Luca Bonavita's avatar
Luca Bonavita committed
    #this is only needed for root bones, since UT assumes a connected skeleton, and from here
    #down the chain we just use "tail" as an endpoint
    #if(head.length > 0.001 and is_root_bone == 1):
    if(0):    
        pb = make_vbone("dummy_" + blender_bone.name, parent_id, 1, FQuat(), tail)
        psk_file.AddBone(pb)
        pbb = make_namedbonebinary("dummy_" + blender_bone.name, parent_id, 1, FQuat(), tail, 0)
        psa_file.StoreBone(pbb)
        final_parent_id = nbone
        nbone = nbone + 1
        #tail = tail-head
        
    my_id = nbone
    
    pb = make_vbone(blender_bone.name, final_parent_id, child_count, quat, set_position)
    psk_file.AddBone(pb)
    pbb = make_namedbonebinary(blender_bone.name, final_parent_id, child_count, quat, set_position, 1)
    psa_file.StoreBone(pbb)

    nbone = nbone + 1
    
    #RG - dump influences for this bone - use the data we collected in the mesh dump phase
    # to map our bones to vertex groups
    #print("///////////////////////")
    #print("set influence")
    if blender_bone.name in psk_file.VertexGroups:
        vertex_list = psk_file.VertexGroups[blender_bone.name]
        #print("vertex list:", len(vertex_list), " of >" ,blender_bone.name )
        for vertex_data in vertex_list:
            #print("set influence vettex")
            point_index = vertex_data[0]
            vertex_weight = vertex_data[1]
            influence = VRawBoneInfluence()
            influence.Weight = vertex_weight
            influence.BoneIndex = my_id
            influence.PointIndex = point_index
            #print ('Adding Bone Influence for [%s] = Point Index=%i, Weight=%f' % (blender_bone.name, point_index, vertex_weight))
            #print("adding influence")
            psk_file.AddInfluence(influence)
    
    #blender_bone.matrix_local
    #recursively dump child bones
    mainparent = parent_matrix
    #if len(blender_bone.children) > 0:
    for current_child_bone in blender_bone.children:
        parse_bone(current_child_bone, psk_file, psa_file, my_id, 0, mainparent, parent_root)

def parse_armature(blender_armature, psk_file, psa_file):
Luca Bonavita's avatar
Luca Bonavita committed
    print ("----- parsing armature -----")
    print ('blender_armature length: %i' % (len(blender_armature)))
    
    #magic 0 sized root bone for UT - this is where all armature dummy bones will attach
    #dont increment nbone here because we initialize it to 1 (hackity hackity hack)

    #count top level bones first. NOT EFFICIENT.
    child_count = 0
    for current_obj in blender_armature: 
        current_armature = current_obj.data
        bones = [x for x in current_armature.bones if not x.parent is None]
        child_count += len(bones)

    for current_obj in blender_armature:
        print ("Current Armature Name: " + current_obj.name)
        current_armature = current_obj.data
        #armature_id = make_armature_bone(current_obj, psk_file, psa_file)
        
        #we dont want children here - only the top level bones of the armature itself
        #we will recursively dump the child bones as we dump these bones
        """
        bones = [x for x in current_armature.bones if not x.parent is None]
        #will ingore this part of the ocde
        """
John Phan's avatar
John Phan committed
        if len(current_armature.bones) == 0:
            raise RuntimeError("Warning add two bones else it will crash the unreal editor.")
        if len(current_armature.bones) == 1:
            raise RuntimeError("Warning add one more bone else it will crash the unreal editor.")
John Phan's avatar
John Phan committed
        mainbonecount = 0;
        for current_bone in current_armature.bones: #list the bone. #note this will list all the bones.
            if(current_bone.parent is None):
                mainbonecount += 1
        print("Main Bone",mainbonecount)
        if mainbonecount > 1:
            #print("Warning there no main bone.")
            raise RuntimeError("There too many Main bones. Number main bones:",mainbonecount)
Luca Bonavita's avatar
Luca Bonavita committed
        for current_bone in current_armature.bones: #list the bone. #note this will list all the bones.
            if(current_bone.parent is None):
                parse_bone(current_bone, psk_file, psa_file, 0, 0, current_obj.matrix_local, None)
                break
Luca Bonavita's avatar
Luca Bonavita committed

# get blender objects by type        
Luca Bonavita's avatar
Luca Bonavita committed
    return [x for x in objects if x.type == intype]
            
#strips current extension (if any) from filename and replaces it with extension passed in
def make_filename_ext(filename, extension):
Luca Bonavita's avatar
Luca Bonavita committed
    new_filename = ''
    extension_index = filename.find('.')
    
    if extension_index == -1:
        new_filename = filename + extension
    else:
        new_filename = filename[0:extension_index] + extension
        
    return new_filename

# returns the quaternion Grassman product a*b
# this is the same as the rotation a(b(x)) 
# (ie. the same as B*A if A and B are matrices representing 
# the rotations described by quaternions a and b)
Luca Bonavita's avatar
Luca Bonavita committed
def grassman(a, b):    
Luca Bonavita's avatar
Luca Bonavita committed
    return mathutils.Quaternion(
        a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z,
        a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y,
        a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x,
        a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w)
        
def parse_animation(blender_scene, blender_armatures, psa_file):
Luca Bonavita's avatar
Luca Bonavita committed
    #to do list:
    #need to list the action sets
    #need to check if there animation
    #need to check if animation is has one frame then exit it
    print ('\n----- parsing animation -----')
    render_data = blender_scene.render
    bHaveAction = True
    
    anim_rate = render_data.fps
    
    print("==== Blender Settings ====")
Luca Bonavita's avatar
Luca Bonavita committed
    print ('Scene: %s Start Frame: %i, End Frame: %i' % (blender_scene.name, blender_scene.frame_start, blender_scene.frame_end))
    print ('Frames Per Sec: %i' % anim_rate)
    print ("Default FPS: 24" )
    
    cur_frame_index = 0
    if (bpy.context.scene.UEActionSetSettings == '1') or (bpy.context.scene.UEActionSetSettings == '2'):
        print("Action Set(s) Settings Idx:",bpy.context.scene.UEActionSetSettings)
        print("[==== Action list ====]")
Luca Bonavita's avatar
Luca Bonavita committed
        
        print("Number of Action set(s):",len(bpy.data.actions))
        
        for action in bpy.data.actions:#current number action sets
            print("+Action Name:",action.name)
            print("Group Count:",len(action.groups))
Luca Bonavita's avatar
Luca Bonavita committed
            #print("Groups:")
            #for bone in action.groups:
                #print("> Name: ",bone.name)
                #print(dir(bone))
Luca Bonavita's avatar
Luca Bonavita committed
        amatureobject = None #this is the armature set to none
        bonenames = [] #bone name of the armature bones list
        
        for arm in blender_armatures:
            amatureobject = arm
        #print(dir(amatureobject))
        collection = amatureobject.myCollectionUEA #collection of the object
Luca Bonavita's avatar
Luca Bonavita committed
        print("\n[==== Armature Object ====]")
        if amatureobject != None:
            print("+Name:",amatureobject.name)
            print("+Number of bones:", len(amatureobject.pose.bones),"\n")
Luca Bonavita's avatar
Luca Bonavita committed
            for bone in amatureobject.pose.bones:
                bonenames.append(bone.name)
        
        for ActionNLA in bpy.data.actions:
            FoundAction = True
            if bpy.context.scene.UEActionSetSettings == '2':                
                for c in collection:
                    if c.name == ActionNLA.name:
                        if c.mybool == True:
                            FoundAction = True
                        else:
                            FoundAction = False
                        break
                if FoundAction == False:
                    print("========================================")
                    print("Skipping Action Set!",ActionNLA.name)
                    print("Action Group Count:", len(ActionNLA.groups))
                    print("Bone Group Count:", len(amatureobject.pose.bones))
                    print("========================================")
                    #break
Luca Bonavita's avatar
Luca Bonavita committed
            nobone = 0
Luca Bonavita's avatar
Luca Bonavita committed
            baction = True
            #print("\nChecking actions matching groups with bone names...")
            #Check if the bone names matches the action groups names
            print("=================================")
            print("=================================")
            for abone in bonenames:         
                #print("bone name:",abone)
                bfound = False
                for group in ActionNLA.groups:
Luca Bonavita's avatar
Luca Bonavita committed
                    #print("name:>>",abone)
                    if abone == group.name:
                        nobone += 1
Luca Bonavita's avatar
Luca Bonavita committed
                        break
                if bfound == False:
                    #print("Not Found!:",abone)
                    nomatchbone += 1
                #else:
                    #print("Found!:",abone)
            
            print("Armature Bones Count:",nobone , " Action Groups Counts:",len(ActionNLA.groups)," Left Out Count:",nomatchbone)
            #if the bones are less some missing bones that were added to the action group names than export this
            if (nobone <= len(ActionNLA.groups)) and (bpy.context.scene.unrealignoreactionmatchcount == True) :
                #print("Action Set match: Pass")
                print("Ingore Action groups Count from Armature bones.")
                baction = True
Luca Bonavita's avatar
Luca Bonavita committed
            #if action groups matches the bones length and names matching the gourps do something
            elif ((len(ActionNLA.groups) == len(bonenames)) and (nobone == len(ActionNLA.groups))):
                #print("Action Set match: Pass")
Luca Bonavita's avatar
Luca Bonavita committed
                baction = True
            else:
                #print("Action Name:",ActionNLA.name)
Luca Bonavita's avatar
Luca Bonavita committed
                baction = False
            
            if (baction == True) and (FoundAction == True):
Luca Bonavita's avatar
Luca Bonavita committed
                arm = amatureobject #set armature object
                if not arm.animation_data:
                    print("======================================")
                    print("Check Animation Data: None")
                    print("Armature has no animation, skipping...")
                    print("======================================")
                    break
                    
                if not arm.animation_data.action:
                    print("======================================")
                    print("Check Action: None")
                    print("Armature has no animation, skipping...")
                    print("======================================")
                    break
                #print("Last Action Name:",arm.animation_data.action.name)
Luca Bonavita's avatar
Luca Bonavita committed
                arm.animation_data.action = ActionNLA
                #print("Set Action Name:",arm.animation_data.action.name)
                bpy.context.scene.update()
Luca Bonavita's avatar
Luca Bonavita committed
                act = arm.animation_data.action
                action_name = act.name
                
                if not len(act.fcurves):
                    print("//===========================================================")
                    print("// None bone pose set keys for this action set... skipping...")
                    print("//===========================================================")
                    bHaveAction = False
                    
                #this deal with action export control
                if bHaveAction == True:
                    #print("------------------------------------")
                    print("[==== Action Set ====]")
Luca Bonavita's avatar
Luca Bonavita committed
                    print("Action Name:",action_name)
Luca Bonavita's avatar
Luca Bonavita committed
                    #look for min and max frame that current set keys
                    framemin, framemax = act.frame_range
                    #print("max frame:",framemax)
                    start_frame = int(framemin)
                    end_frame = int(framemax)
                    scene_frames = range(start_frame, end_frame+1)
                    frame_count = len(scene_frames)
                    #===================================================
                    anim = AnimInfoBinary()
                    anim.Name = action_name
                    anim.Group = "" #what is group?
                    anim.NumRawFrames = frame_count
                    anim.AnimRate = anim_rate
                    anim.FirstRawFrame = cur_frame_index
                    #===================================================
Campbell Barton's avatar
Campbell Barton committed
                    # count_previous_keys = len(psa_file.RawKeys.Data)  # UNUSED
Luca Bonavita's avatar
Luca Bonavita committed
                    print("Frame Key Set Count:",frame_count, "Total Frame:",frame_count)
                    #print("init action bones...")
                    unique_bone_indexes = {}
                    # bone lookup table
                    bones_lookup =  {}
                
                    #build bone node for animation keys needed to be set
                    for bone in arm.data.bones:
                        bones_lookup[bone.name] = bone
                    #print("bone name:",bone.name)
                    frame_count = len(scene_frames)
                    #print ('Frame Count: %i' % frame_count)
                    pose_data = arm.pose
                
                    #these must be ordered in the order the bones will show up in the PSA file!
                    ordered_bones = {}
                    ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones], key=operator.itemgetter(0))
                    
                    #############################
                    # ORDERED FRAME, BONE
                    #for frame in scene_frames:
                    
                    for i in range(frame_count):
                        frame = scene_frames[i]
                        #LOUD
                        #print ("==== outputting frame %i ===" % frame)
                        
                        if frame_count > i+1:
                            next_frame = scene_frames[i+1]
                            #print "This Frame: %i, Next Frame: %i" % (frame, next_frame)
                        else:
                            next_frame = -1
                            #print "This Frame: %i, Next Frame: NONE" % frame
                        
                        #frame start from 1 as number one from blender
                        blender_scene.frame_set(frame)
                        
                        cur_frame_index = cur_frame_index + 1
                        for bone_data in ordered_bones:
                            bone_index = bone_data[0]
                            pose_bone = bone_data[1]
                            #print("[=====POSE NAME:",pose_bone.name)
                            
                            #print("LENG >>.",len(bones_lookup))
Campbell Barton's avatar
Campbell Barton committed
                            # blender_bone = bones_lookup[pose_bone.name]  # UNUSED
Luca Bonavita's avatar
Luca Bonavita committed
                            
                            #just need the total unique bones used, later for this AnimInfoBinary
                            unique_bone_indexes[bone_index] = bone_index
                            #LOUD
                            #print ("-------------------", pose_bone.name)
                            head = pose_bone.head
                            
                            posebonemat = mathutils.Matrix(pose_bone.matrix)
                            #print("quat",posebonemat)
                            #
                            # Error looop action get None in matrix
                            # looping on each armature give invert and normalize for None
                            #
Luca Bonavita's avatar
Luca Bonavita committed
                            parent_pose = pose_bone.parent
Luca Bonavita's avatar
Luca Bonavita committed
                            if parent_pose != None:
                                parentposemat = mathutils.Matrix(parent_pose.matrix)
                                posebonemat = parentposemat.inverted() * posebonemat
                            head = posebonemat.to_translation()
                            quat = posebonemat.to_quaternion().normalized()

Luca Bonavita's avatar
Luca Bonavita committed
                            vkey = VQuatAnimKey()
                            vkey.Position.X = head.x
                            vkey.Position.Y = head.y
                            vkey.Position.Z = head.z
                            
                            if parent_pose != None:
                                quat = make_fquat(quat)
                            else:
                                quat = make_fquat_default(quat)
                            
                            vkey.Orientation = quat
                            #print("Head:",head)
                            #print("Orientation",quat)
                            
                            #time from now till next frame = diff / framesPerSec
                            if next_frame >= 0:
                                diff = next_frame - frame
                            else:
                                diff = 1.0
                            
                            #print ("Diff = ", diff)
                            vkey.Time = float(diff)/float(anim_rate)
                            psa_file.AddRawKey(vkey)
                            
                    #done looping frames
                    #done looping armatures
                    #continue adding animInfoBinary counts here
                
                anim.TotalBones = len(unique_bone_indexes)
                print("Bones Count:",anim.TotalBones)
                anim.TrackTime = float(frame_count) / anim.AnimRate
                print("Time Track Frame:",anim.TrackTime)
                psa_file.AddAnimation(anim)
                print("------------------------------------\n")
            else:
                print("[==== Action Set ====]")
                print("Action Name:",ActionNLA.name)
                print("Action Group Count:", len(ActionNLA.groups))
                print("Bone Group Count:", len(amatureobject.pose.bones))
                print("Action set Skip!")
                print("------------------------------------\n")
Luca Bonavita's avatar
Luca Bonavita committed
        print("==== Finish Action Build(s) ====")
    else:
        print("[==== Action Set Single Export====]")
Luca Bonavita's avatar
Luca Bonavita committed
        #list of armature objects
        for arm in blender_armatures:
            #check if there animation data from armature or something
            
            if not arm.animation_data:
                print("======================================")
                print("Check Animation Data: None")
                print("Armature has no animation, skipping...")
                print("======================================")
                break
                
            if not arm.animation_data.action:
                print("======================================")
                print("Check Action: None")
                print("Armature has no animation, skipping...")
                print("======================================")
                break
            act = arm.animation_data.action
            #print(dir(act))
            action_name = act.name
            
            if not len(act.fcurves):
                print("//===========================================================")
                print("// None bone pose set keys for this action set... skipping...")
                print("//===========================================================")
                bHaveAction = False
                
            #this deal with action export control
            if bHaveAction == True:
                print("---- Action Start ----")
Luca Bonavita's avatar
Luca Bonavita committed
                print("Action Name:",action_name)
                #look for min and max frame that current set keys
                framemin, framemax = act.frame_range
                #print("max frame:",framemax)
                start_frame = int(framemin)
                end_frame = int(framemax)
                scene_frames = range(start_frame, end_frame+1)
                frame_count = len(scene_frames)
                #===================================================
                anim = AnimInfoBinary()
                anim.Name = action_name
                anim.Group = "" #what is group?
                anim.NumRawFrames = frame_count
                anim.AnimRate = anim_rate
                anim.FirstRawFrame = cur_frame_index
                #===================================================
Campbell Barton's avatar
Campbell Barton committed
                # count_previous_keys = len(psa_file.RawKeys.Data)  # UNUSED
Luca Bonavita's avatar
Luca Bonavita committed
                print("Frame Key Set Count:",frame_count, "Total Frame:",frame_count)
                #print("init action bones...")
                unique_bone_indexes = {}
                # bone lookup table
                bones_lookup =  {}
            
                #build bone node for animation keys needed to be set
                for bone in arm.data.bones:
                    bones_lookup[bone.name] = bone
                #print("bone name:",bone.name)
                frame_count = len(scene_frames)
                #print ('Frame Count: %i' % frame_count)
                pose_data = arm.pose
            
                #these must be ordered in the order the bones will show up in the PSA file!
                ordered_bones = {}
                ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones], key=operator.itemgetter(0))
                
                #############################
                # ORDERED FRAME, BONE
                #for frame in scene_frames:
                
                for i in range(frame_count):
                    frame = scene_frames[i]
                    #LOUD
                    #print ("==== outputting frame %i ===" % frame)
                    
                    if frame_count > i+1:
                        next_frame = scene_frames[i+1]
                        #print "This Frame: %i, Next Frame: %i" % (frame, next_frame)
                    else:
                        next_frame = -1
                        #print "This Frame: %i, Next Frame: NONE" % frame
                    
                    #frame start from 1 as number one from blender
                    blender_scene.frame_set(frame)
                    
                    cur_frame_index = cur_frame_index + 1
                    for bone_data in ordered_bones:
                        bone_index = bone_data[0]
                        pose_bone = bone_data[1]
                        #print("[=====POSE NAME:",pose_bone.name)
                        
                        #print("LENG >>.",len(bones_lookup))
Campbell Barton's avatar
Campbell Barton committed
                        # blender_bone = bones_lookup[pose_bone.name]  # UNUSED
Luca Bonavita's avatar
Luca Bonavita committed
                        
                        #just need the total unique bones used, later for this AnimInfoBinary
                        unique_bone_indexes[bone_index] = bone_index
                        #LOUD
                        #print ("-------------------", pose_bone.name)
                        head = pose_bone.head
                        
                        posebonemat = mathutils.Matrix(pose_bone.matrix)
                        parent_pose = pose_bone.parent
                        if parent_pose != None:
                            parentposemat = mathutils.Matrix(parent_pose.matrix)
                            #blender 2.4X it been flip around with new 2.50 (mat1 * mat2) should now be (mat2 * mat1)
John Phan's avatar
John Phan committed
                            posebonemat = parentposemat.inverted() * posebonemat
                        head = posebonemat.to_translation()
John Phan's avatar
John Phan committed
                        quat = posebonemat.to_quaternion().normalized()
Luca Bonavita's avatar
Luca Bonavita committed
                        vkey = VQuatAnimKey()
                        vkey.Position.X = head.x
                        vkey.Position.Y = head.y
                        vkey.Position.Z = head.z
John Phan's avatar
John Phan committed
                        #print("quat:",quat)
Luca Bonavita's avatar
Luca Bonavita committed
                        if parent_pose != None:
                            quat = make_fquat(quat)
                        else:
                            quat = make_fquat_default(quat)
                        
                        vkey.Orientation = quat
                        #print("Head:",head)
                        #print("Orientation",quat)
                        
                        #time from now till next frame = diff / framesPerSec
                        if next_frame >= 0:
                            diff = next_frame - frame
                        else:
                            diff = 1.0
                        
                        #print ("Diff = ", diff)
                        vkey.Time = float(diff)/float(anim_rate)
                        psa_file.AddRawKey(vkey)
                        
                #done looping frames
                #done looping armatures
                #continue adding animInfoBinary counts here
            
                anim.TotalBones = len(unique_bone_indexes)
                print("Bones Count:",anim.TotalBones)
                anim.TrackTime = float(frame_count) / anim.AnimRate
                print("Time Track Frame:",anim.TrackTime)
                psa_file.AddAnimation(anim)
                print("---- Action End ----")
                print("==== Finish Action Build ====")
Luca Bonavita's avatar
Luca Bonavita committed
    
John Phan's avatar
John Phan committed
def meshmerge(selectedobjects):
    bpy.ops.object.mode_set(mode='OBJECT')
    cloneobjects = []
    if len(selectedobjects) > 1:
        print("selectedobjects:",len(selectedobjects))
        count = 0 #reset count
        for count in range(len( selectedobjects)):
            #print("Index:",count)
John Phan's avatar
John Phan committed
            if selectedobjects[count] != None:
                me_da = selectedobjects[count].data.copy() #copy data
                me_ob = selectedobjects[count].copy() #copy object
                #note two copy two types else it will use the current data or mesh
                me_ob.data = me_da
                bpy.context.scene.objects.link(me_ob)#link the object to the scene #current object location
                print("Index:",count,"clone object",me_ob.name)
John Phan's avatar
John Phan committed
                cloneobjects.append(me_ob)
        #bpy.ops.object.mode_set(mode='OBJECT')
        for i in bpy.data.objects: i.select = False #deselect all objects
        count = 0 #reset count
        #bpy.ops.object.mode_set(mode='OBJECT')
        for count in range(len( cloneobjects)):
            if count == 0:
                bpy.context.scene.objects.active = cloneobjects[count]
                print("Set Active Object:",cloneobjects[count].name)
            cloneobjects[count].select = True
        bpy.ops.object.join()
        return cloneobjects[0]
Luca Bonavita's avatar
Luca Bonavita committed
        
def fs_callback(filename, context):
Luca Bonavita's avatar
Luca Bonavita committed
    #this deal with repeat export and the reset settings
    global nbone, exportmessage, bDeleteMergeMesh
Luca Bonavita's avatar
Luca Bonavita committed
    nbone = 0
    
    start_time = time.clock()
    
    print ("========EXPORTING TO UNREAL SKELETAL MESH FORMATS========\r\n")
    print("Blender Version:", bpy.app.version[1],"-")
Luca Bonavita's avatar
Luca Bonavita committed
    
    psk = PSKFile()
    psa = PSAFile()
    
    #sanity check - this should already have the extension, but just in case, we'll give it one if it doesn't
    psk_filename = make_filename_ext(filename, '.psk')
    
    #make the psa filename
    psa_filename = make_filename_ext(filename, '.psa')
    
    print ('PSK File: ' +  psk_filename)
    print ('PSA File: ' +  psa_filename)
    
    barmature = True
    bmesh = True
    blender_meshes = []
    blender_armature = []
    selectmesh = []
    selectarmature = []
    
    current_scene = context.scene
    cur_frame = current_scene.frame_current #store current frame before we start walking them during animation parse
    objects = current_scene.objects
    
    print("Checking object count...")
    for next_obj in objects:
        if next_obj.type == 'MESH':
            blender_meshes.append(next_obj)
            if (next_obj.select):
                #print("mesh object select")
                selectmesh.append(next_obj)
        if next_obj.type == 'ARMATURE':
            blender_armature.append(next_obj)
            if (next_obj.select):
                #print("armature object select")
                selectarmature.append(next_obj)
    
    print("Mesh Count:",len(blender_meshes)," Armature Count:",len(blender_armature))
    print("====================================")
    print("Checking Mesh Condtion(s):")
John Phan's avatar
John Phan committed
    #if there 1 mesh in scene add to the array
Luca Bonavita's avatar
Luca Bonavita committed
    if len(blender_meshes) == 1:
        print(" - One Mesh Scene")
John Phan's avatar
John Phan committed
    #if there more than one mesh and one mesh select add to array
Luca Bonavita's avatar
Luca Bonavita committed
    elif (len(blender_meshes) > 1) and (len(selectmesh) == 1):
        blender_meshes = []
        blender_meshes.append(selectmesh[0])
Luca Bonavita's avatar
Luca Bonavita committed
        print(" - One Mesh [Select]")
John Phan's avatar
John Phan committed
    elif (len(blender_meshes) > 1) and (len(selectmesh) >= 1):
        #code build check for merge mesh before ops
        print("More than one mesh is selected!")
        centermesh = []
        notcentermesh = []
        countm = 0
        for countm in range(len(selectmesh)):
            #selectmesh[]
            if selectmesh[countm].location.x == 0 and selectmesh[countm].location.y == 0 and selectmesh[countm].location.z == 0:
                centermesh.append(selectmesh[countm])
            else:
                notcentermesh.append(selectmesh[countm])
        if len(centermesh) > 0:
            print("Center Object Found!")
John Phan's avatar
John Phan committed
            blender_meshes = []
            selectmesh = []
            countm = 0
            for countm in range(len(centermesh)):
                selectmesh.append(centermesh[countm])
            for countm in range(len(notcentermesh)):
                selectmesh.append(notcentermesh[countm])
            blender_meshes.append(meshmerge(selectmesh))
            bDeleteMergeMesh = True
        else:
            bDeleteMergeMesh = False
            bmesh = False
            print("Center Object Not Found")
Luca Bonavita's avatar
Luca Bonavita committed
    else:
        print(" - Too Many Meshes!")
        print(" - Select One Mesh Object!")
        bmesh = False
John Phan's avatar
John Phan committed
        bDeleteMergeMesh = False
		
Luca Bonavita's avatar
Luca Bonavita committed
    print("====================================")
    print("Checking Armature Condtion(s):")
    if len(blender_armature) == 1:
        print(" - One Armature Scene")
    elif (len(blender_armature) > 1) and (len(selectarmature) == 1):
        print(" - One Armature [Select]")
    else:
        print(" - Too Armature Meshes!")
        print(" - Select One Armature Object Only!")
        barmature = False
John Phan's avatar
John Phan committed
    bMeshScale = True
    bMeshCenter = True
John Phan's avatar
John Phan committed
    if len(blender_meshes) > 0:
John Phan's avatar
John Phan committed
        if blender_meshes[0].scale.x == 1 and blender_meshes[0].scale.y == 1 and blender_meshes[0].scale.z == 1:
            #print("Okay")
            bMeshScale = True
        else:
            print("Error, Mesh Object not scale right should be (1,1,1).")
            bMeshScale = False
        if blender_meshes[0].location.x == 0 and blender_meshes[0].location.y == 0 and blender_meshes[0].location.z == 0:
            #print("Okay")
            bMeshCenter = True
        else:
            print("Error, Mesh Object not center.",blender_meshes[0].location)
John Phan's avatar
John Phan committed
            bMeshCenter = False
John Phan's avatar
John Phan committed
    else:
        bmesh = False
John Phan's avatar
John Phan committed
    bArmatureScale = True
    bArmatureCenter = True
    if blender_armature and blender_armature[0] is not None:
John Phan's avatar
John Phan committed
        if blender_armature[0].scale.x == 1 and blender_armature[0].scale.y == 1 and blender_armature[0].scale.z == 1:
            #print("Okay")
            bArmatureScale = True
        else:
            print("Error, Armature Object not scale right should be (1,1,1).")
John Phan's avatar
John Phan committed
            bArmatureScale = False
        if blender_armature[0].location.x == 0 and blender_armature[0].location.y == 0 and blender_armature[0].location.z == 0:
            #print("Okay")
            bArmatureCenter = True
        else:
            print("Error, Armature Object not center.",blender_armature[0].location)
John Phan's avatar
John Phan committed
            bArmatureCenter = False
			
		
			
    #print("location:",blender_armature[0].location.x)
Luca Bonavita's avatar
Luca Bonavita committed
    
John Phan's avatar
John Phan committed
    if (bmesh == False) or (barmature == False) or (bArmatureCenter == False) or (bArmatureScale == False)or (bMeshScale == False) or (bMeshCenter == False):
Luca Bonavita's avatar
Luca Bonavita committed
        exportmessage = "Export Fail! Check Log."
        print("=================================")
        print("= Export Fail!                  =")
        print("=================================")
    else:
        exportmessage = "Export Finish!"
John Phan's avatar
John Phan committed
        #print("blender_armature:",dir(blender_armature[0]))
        #print(blender_armature[0].scale)
Luca Bonavita's avatar
Luca Bonavita committed

        try:
            #######################
            # STEP 1: MESH DUMP
            # we build the vertexes, wedges, and faces in here, as well as a vertexgroup lookup table
            # for the armature parse
            print("//===============================")
            print("// STEP 1")
            print("//===============================")
            parse_meshes(blender_meshes, psk)
        except:
            context.scene.frame_set(cur_frame) #set frame back to original frame
            print ("Exception during Mesh Parse")
            raise
        
        try:
            #######################
            # STEP 2: ARMATURE DUMP
            # IMPORTANT: do this AFTER parsing meshes - we need to use the vertex group data from 
            # the mesh parse in here to generate bone influences
            print("//===============================")
            print("// STEP 2")
            print("//===============================")
            parse_armature(blender_armature, psk, psa) 
            
        except:
            context.scene.frame_set(cur_frame) #set frame back to original frame
            print ("Exception during Armature Parse")
            raise

        try:
            #######################
            # STEP 3: ANIMATION DUMP
            # IMPORTANT: do AFTER parsing bones - we need to do bone lookups in here during animation frames
            print("//===============================")
            print("// STEP 3")
            print("//===============================")
            parse_animation(current_scene, blender_armature, psa) 
            
        except:
            context.scene.frame_set(cur_frame) #set frame back to original frame
            print ("Exception during Animation Parse")
            raise

        # reset current frame
        
        context.scene.frame_set(cur_frame) #set frame back to original frame
        
        ##########################
        # FILE WRITE
        print("//===========================================")
        print("// bExportPsk:",bpy.context.scene.unrealexportpsk," bExportPsa:",bpy.context.scene.unrealexportpsa)
        print("//===========================================")
        if bpy.context.scene.unrealexportpsk == True:
            print("Writing Skeleton Mesh Data...")
            #RG - dump psk file
            psk.PrintOut()
            file = open(psk_filename, "wb") 
            file.write(psk.dump())
            file.close() 
            print ("Successfully Exported File: " + psk_filename)
        if bpy.context.scene.unrealexportpsa == True:
            print("Writing Animaiton Data...")
            #RG - dump psa file
            if not psa.IsEmpty():
                psa.PrintOut()
                file = open(psa_filename, "wb") 
                file.write(psa.dump())
                file.close() 
                print ("Successfully Exported File: " + psa_filename)
            else:
                print ("No Animations (.psa file) to Export")

        print ('PSK/PSA Export Script finished in %.2f seconds' % (time.clock() - start_time))
        print( "Current Script version: ",bl_info['version'])
Luca Bonavita's avatar
Luca Bonavita committed
        #MSG BOX EXPORT COMPLETE
        #...

        #DONE
        print ("PSK/PSA Export Complete")
Luca Bonavita's avatar
Luca Bonavita committed
    print("//============================")
    print("// running psk/psa export...")
    print("//============================")
    fs_callback(path, context)
    pass
bpy.types.Scene.unrealfpsrate = IntProperty(
Luca Bonavita's avatar
Luca Bonavita committed
    name="fps rate",
    description="Set the frame per second (fps) for unreal",
Luca Bonavita's avatar
Luca Bonavita committed
    default=24,min=1,max=100)
    
bpy.types.Scene.unrealexport_settings = EnumProperty(
Luca Bonavita's avatar
Luca Bonavita committed
    name="Export:",
    description="Select a export settings (psk/psa/all)...",
    items = [("0","PSK","Export PSK"),
             ("1","PSA","Export PSA"),
             ("2","ALL","Export ALL")],
    default = '0')

bpy.types.Scene.UEActionSetSettings = EnumProperty(
    name="Action Set(s) Export Type",
    description="For Exporting Single, All, and Select Action Set(s)",
    items = [("0","Single","Single Action Set Export"),
             ("1","All","All Action Sets Export"),
             ("2","Select","Select Action Set(s) Export")],
    default = '0')        

bpy.types.Scene.unrealtriangulatebool = BoolProperty(
Luca Bonavita's avatar
Luca Bonavita committed
    name="Triangulate Mesh",
    description="Convert Quad to Tri Mesh Boolean...",
    default=False)

bpy.types.Scene.unrealignoreactionmatchcount = BoolProperty(
    name="Acion Group Ignore Count",
    description="It will ingore Action group count as long is matches the " \
                "Armature bone count to match and over ride the armature " \
                "animation data",
Luca Bonavita's avatar
Luca Bonavita committed
    
John Phan's avatar
John Phan committed
bpy.types.Scene.unrealdisplayactionsets = BoolProperty(
    name="Show Action Set(s)",
    description="Display Action Sets Information",
Luca Bonavita's avatar
Luca Bonavita committed
    default=False)    
    
bpy.types.Scene.unrealexportpsk = BoolProperty(
Luca Bonavita's avatar
Luca Bonavita committed
    name="bool export psa",
    description="bool for exporting this psk format",
    default=True)
    
bpy.types.Scene.unrealexportpsa = BoolProperty(
Luca Bonavita's avatar
Luca Bonavita committed
    name="bool export psa",
    description="bool for exporting this psa format",
    default=True)

bpy.types.Scene.limituv = BoolProperty(
    name="bool limit UV",
    description="limit UV co-ordinates to [0-1]",
    default=False)
	
class UEAPropertyGroup(bpy.types.PropertyGroup):
    ## create Properties for the collection entries:
    mystring = bpy.props.StringProperty()
    mybool = bpy.props.BoolProperty(
        name="Export",
        description="Check if you want to export the action set",
        default = False)

bpy.utils.register_class(UEAPropertyGroup)

## create CollectionProperty and link it to the property class
bpy.types.Object.myCollectionUEA = bpy.props.CollectionProperty(type = UEAPropertyGroup)
bpy.types.Object.myCollectionUEA_index = bpy.props.IntProperty(min = -1, default = -1)

## create operator to add or remove entries to/from  the Collection
class OBJECT_OT_add_remove_Collection_Items_UE(bpy.types.Operator):
    bl_label = "Add or Remove"
    bl_idname = "collection.add_remove_ueactions"
    __doc__ = """Button for Add, Remove, Refresh Action Set(s) list."""
    set = bpy.props.StringProperty()
 
    def invoke(self, context, event):
        obj = context.object
        collection = obj.myCollectionUEA
        if self.set == "remove":
            print("remove")
            index = obj.myCollectionUEA_index
            collection.remove(index)       # This remove on item in the collection list function of index value
        if self.set == "add":
            print("add")
            added = collection.add()        # This add at the end of the collection list
            added.name = "Action"+ str(random.randrange(0, 101, 2))
        if self.set == "refresh":
            print("refresh")
Campbell Barton's avatar
Campbell Barton committed
            # ArmatureSelect = None  # UNUSED
            ActionNames = []
            BoneNames = []
            for obj in bpy.data.objects:
                if obj.type == 'ARMATURE' and obj.select == True:
                    print("Armature Name:",obj.name)
Campbell Barton's avatar
Campbell Barton committed
                    # ArmatureSelect = obj  # UNUSED
                    for bone in obj.pose.bones:
                        BoneNames.append(bone.name)
                    break
            actionsetmatchcount = 0	
            for ActionNLA in bpy.data.actions:
                nobone = 0
                for group in ActionNLA.groups:	
                    for abone in BoneNames:
                        if abone == group.name:
                            nobone += 1
                            break
                    if (len(ActionNLA.groups) == len(BoneNames)) and (nobone == len(ActionNLA.groups)):
                        actionsetmatchcount += 1
                        ActionNames.append(ActionNLA.name)
            #print(dir(collection))
            #print("collection:",len(collection))
            print("action list check")
            for action in ActionNames:
                BfoundAction = False
                #print("action:",action)
                for c in collection:
                    #print(c.name)
                    if c.name == action:
                        BfoundAction = True
                        break
                if BfoundAction == False:
                    added = collection.add()        # This add at the end of the collection list
                    added.name = action
        #print("finish...")
        return {'FINISHED'} 
Luca Bonavita's avatar
Luca Bonavita committed
    global exportmessage
    '''Export Skeleton Mesh / Animation Data file(s)'''
    bl_idname = "export_anim.udk" # this is important since its how bpy.ops.export.udk_anim_data is constructed
Luca Bonavita's avatar
Luca Bonavita committed
    bl_label = "Export PSK/PSA"
    __doc__ = """One mesh and one armature else select one mesh or armature to be exported."""
Luca Bonavita's avatar
Luca Bonavita committed

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator settings before calling.

    filepath = StringProperty(
            name="File Path",
            description="Filepath used for exporting the PSA file",
            maxlen= 1024,
            subtype='FILE_PATH',
            )
    filter_glob = StringProperty(
            default="*.psk;*.psa",
            options={'HIDDEN'},
            )
    pskexportbool = BoolProperty(
            name="Export PSK",
            description="Export Skeletal Mesh",
            default= True,
            )
    psaexportbool = BoolProperty(
            name="Export PSA",
            description="Export Action Set (Animation Data)",
            default= True,
            )
    actionexportall = BoolProperty(
            name="All Actions",
            description="This will export all the actions that matches the " \
                        "current armature",
            default=False,
            )
    ignoreactioncountexportbool = BoolProperty(
            name="Ignore Action Group Count",
            description="It will ignore action group count but as long it " \
                        "matches the armature bone count to over ride the " \
                        "animation data",
    limituvbool = BoolProperty(
            name="Limit UV Co-ordinates",
            description="Limit UV co-ordinates to [0-1]",
            default= False,
            ) 
Luca Bonavita's avatar
Luca Bonavita committed

    @classmethod
    def poll(cls, context):
        return context.active_object != None

    def execute(self, context):
        #check if  skeleton mesh is needed to be exported
        if (self.pskexportbool):
            bpy.context.scene.unrealexportpsk = True
        else:
            bpy.context.scene.unrealexportpsk = False
        #check if  animation data is needed to be exported
        if (self.psaexportbool):
            bpy.context.scene.unrealexportpsa = True
        else:
            bpy.context.scene.unrealexportpsa = False
            
        if (self.actionexportall):
            bpy.context.scene.UEActionSetSettings = '1'#export one action set
Luca Bonavita's avatar
Luca Bonavita committed
        else:
            bpy.context.scene.UEActionSetSettings = '0'#export all action sets
Luca Bonavita's avatar
Luca Bonavita committed