Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlijenstina <lijenstina@gmail.com>2017-07-16 16:36:10 +0300
committerlijenstina <lijenstina@gmail.com>2017-07-16 16:36:10 +0300
commit766887ce0c1f46dfcf0ca47df27b9f638bb0952e (patch)
treefbb377408b9d4f78f68d84b2f6ea9e9af456921f
parente93499db2ffc93f41d7374004f002b5b0813e1ad (diff)
Export Unreal Engine Format: Update panel Rename, cleanup, fixes
Bumped version to 2.7.1 As a part of the task T50726: Update the Panel rename code to more generic one Pep8 cleanup Replace star imports Consistent property definitions Update wiki link move the register of properties and collections to register function, proper removal on unregister Refactor the exporter as it assigned the operator properties from the scene ones cmp is deprecated in Python 3.x
-rw-r--r--io_export_unreal_psk_psa.py2114
1 files changed, 1206 insertions, 908 deletions
diff --git a/io_export_unreal_psk_psa.py b/io_export_unreal_psk_psa.py
index 7ecef29b..ca22ca46 100644
--- a/io_export_unreal_psk_psa.py
+++ b/io_export_unreal_psk_psa.py
@@ -1,4 +1,4 @@
-#====================== BEGIN GPL LICENSE BLOCK ============================
+# ##### 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
@@ -14,17 +14,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# All rights reserved.
#
-#======================= END GPL LICENSE BLOCK =============================
+# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Export Unreal Engine Format(.psk/.psa)",
"author": "Darknet/Optimus_P-Fat/Active_Trash/Sinsoft/VendorX/Spoof",
- "version": (2, 7),
+ "version": (2, 7, 1),
"blender": (2, 65, 4),
"location": "File > Export > Skeletal Mesh/Animation Data (.psk/.psa)",
"description": "Export Skeleletal Mesh/Animation Data",
"warning": "",
- "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
+ "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Import-Export/Unreal_psk_psa",
"category": "Import-Export",
}
@@ -47,7 +47,8 @@ bl_info = {
- This will work on UT3 and it is a stable version that work with vehicle for testing.
- Main Bone fix no dummy needed to be there.
- Just bone issues position, rotation, and offset for psk.
-- The armature bone position, rotation, and the offset of the bone is fix. It was to deal with skeleton mesh export for psk.
+- The armature bone position, rotation, and the offset of the bone is fix.
+ It was to deal with skeleton mesh export for psk.
- Animation is fix for position, offset, rotation bone support one rotation direction when armature build.
- It will convert your mesh into triangular when exporting to psk file.
- Did not work with psa export yet.
@@ -78,7 +79,7 @@ Credit to:
"""
-#===========================================================================
+# ===========================================================================
"""
NOTES for Jan 2012 refactor (Spoof)
@@ -135,7 +136,7 @@ deformer bones (bad for optimising a game character). I had partial success
writing a parser for the structure, but it was taking too much time and,
considering the other issues with Rigify, it was abandoned.
"""
-#===========================================================================
+# ===========================================================================
import bmesh
import os
@@ -143,12 +144,26 @@ import time
import bpy
import mathutils
import math
-import random
import operator
import sys
-from bpy.props import *
+from bpy.props import (
+ BoolProperty,
+ CollectionProperty,
+ EnumProperty,
+ FloatProperty,
+ IntProperty,
+ StringProperty,
+ )
+from bpy.types import (
+ Operator,
+ Panel,
+ UIList,
+ PropertyGroup,
+ AddonPreferences,
+ )
from struct import pack
+
# REFERENCE MATERIAL JUST IN CASE:
#
# U = x / sqrt(x^2 + y^2 + z^2)
@@ -157,36 +172,43 @@ from struct import pack
# Triangles specifed counter clockwise for front face
#
# defines for sizeofs
-SIZE_FQUAT = 16
-SIZE_FVECTOR = 12
-SIZE_VJOINTPOS = 44
-SIZE_ANIMINFOBINARY = 168
-SIZE_VCHUNKHEADER = 32
-SIZE_VMATERIAL = 88
-SIZE_VBONE = 120
-SIZE_FNAMEDBONEBINARY = 120
-SIZE_VRAWBONEINFLUENCE = 12
-SIZE_VQUATANIMKEY = 32
-SIZE_VVERTEX = 16
-SIZE_VPOINT = 12
-SIZE_VTRIANGLE = 12
-
-MaterialName = []
-
-#===========================================================================
+SIZE_FQUAT = 16
+SIZE_FVECTOR = 12
+SIZE_VJOINTPOS = 44
+SIZE_ANIMINFOBINARY = 168
+SIZE_VCHUNKHEADER = 32
+SIZE_VMATERIAL = 88
+SIZE_VBONE = 120
+SIZE_FNAMEDBONEBINARY = 120
+SIZE_VRAWBONEINFLUENCE = 12
+SIZE_VQUATANIMKEY = 32
+SIZE_VVERTEX = 16
+SIZE_VPOINT = 12
+SIZE_VTRIANGLE = 12
+
+MaterialName = []
+
+
+# Python 3 doesn't have cmp anymore
+def cmp(a, b):
+ return (a > b) - (a < b)
+
+
+# ===========================================================================
# Custom exception class
-#===========================================================================
-class Error( Exception ):
+# ===========================================================================
+class Error(Exception):
def __init__(self, message):
self.message = message
-#===========================================================================
+
+# ===========================================================================
# Verbose logging with loop truncation
-#===========================================================================
-def verbose( msg, iteration=-1, max_iterations=4, msg_truncated="..." ):
+# ===========================================================================
+def verbose(msg, iteration=-1, max_iterations=4, msg_truncated="..."):
- if bpy.context.scene.udk_option_verbose == True:
+ if bpy.context.scene.udk_option_verbose is True:
# limit the number of times a loop can output messages
if iteration > max_iterations:
return
@@ -196,26 +218,28 @@ def verbose( msg, iteration=-1, max_iterations=4, msg_truncated="..." ):
print(msg)
-#===========================================================================
+
+# ===========================================================================
# Log header/separator
-#===========================================================================
-def header( msg, justify='LEFT', spacer='_', cols=78 ):
+# ===========================================================================
+def header(msg, justify='LEFT', spacer='_', cols=78):
if justify == 'LEFT':
- s = '{:{spacer}<{cols}}'.format(msg+" ", spacer=spacer, cols=cols)
+ s = '{:{spacer}<{cols}}'.format(msg + " ", spacer=spacer, cols=cols)
elif justify == 'RIGHT':
- s = '{:{spacer}>{cols}}'.format(" "+msg, spacer=spacer, cols=cols)
+ s = '{:{spacer}>{cols}}'.format(" " + msg, spacer=spacer, cols=cols)
else:
- s = '{:{spacer}^{cols}}'.format(" "+msg+" ", spacer=spacer, cols=cols)
+ s = '{:{spacer}^{cols}}'.format(" " + msg + " ", spacer=spacer, cols=cols)
return "\n" + s + "\n"
-#===========================================================================
+
+# ===========================================================================
# Generic Object->Integer mapping
# the object must be usable as a dictionary key
-#===========================================================================
+# ===========================================================================
class ObjMap:
def __init__(self):
@@ -236,11 +260,12 @@ class ObjMap:
getkey = operator.itemgetter(1)
return map(getval, sorted(self.dict.items(), key=getkey))
-#===========================================================================
+
+# ===========================================================================
# RG - UNREAL DATA STRUCTS - CONVERTED FROM C STRUCTS GIVEN ON UDN SITE
# provided here: http://udn.epicgames.com/Two/BinaryFormatSpecifications.html
# updated UDK (Unreal Engine 3): http://udn.epicgames.com/Three/BinaryFormatSpecifications.html
-#===========================================================================
+# ===========================================================================
class FQuat:
def __init__(self):
@@ -253,10 +278,10 @@ class FQuat:
return pack('ffff', self.X, self.Y, self.Z, self.W)
def __cmp__(self, other):
- return cmp(self.X, other.X) \
- or cmp(self.Y, other.Y) \
- or cmp(self.Z, other.Z) \
- or cmp(self.W, other.W)
+ return cmp(self.X, other.X) or \
+ cmp(self.Y, other.Y) or \
+ cmp(self.Z, other.Z) or \
+ cmp(self.W, other.W)
def __hash__(self):
return hash(self.X) ^ hash(self.Y) ^ hash(self.Z) ^ hash(self.W)
@@ -264,6 +289,7 @@ class FQuat:
def __str__(self):
return "[%f,%f,%f,%f](FQuat)" % (self.X, self.Y, self.Z, self.W)
+
class FVector(object):
def __init__(self, X=0.0, Y=0.0, Z=0.0):
@@ -275,9 +301,9 @@ class FVector(object):
return pack('fff', self.X, self.Y, self.Z)
def __cmp__(self, other):
- return cmp(self.X, other.X) \
- or cmp(self.Y, other.Y) \
- or cmp(self.Z, other.Z)
+ return cmp(self.X, other.X) or \
+ cmp(self.Y, other.Y) or \
+ cmp(self.Z, other.Z)
def _key(self):
return (type(self).__name__, self.X, self.Y, self.Z)
@@ -303,130 +329,146 @@ class FVector(object):
self.Y - other.Y,
self.Z - other.Z)
+
class VJointPos:
def __init__(self):
- self.Orientation = FQuat()
- self.Position = FVector()
- self.Length = 0.0
- self.XSize = 0.0
- self.YSize = 0.0
- self.ZSize = 0.0
+ self.Orientation = FQuat()
+ self.Position = FVector()
+ self.Length = 0.0
+ self.XSize = 0.0
+ self.YSize = 0.0
+ self.ZSize = 0.0
def dump(self):
- return self.Orientation.dump() + self.Position.dump() + pack('4f', self.Length, self.XSize, self.YSize, self.ZSize)
+ return self.Orientation.dump() + self.Position.dump() + \
+ pack('4f', self.Length, self.XSize, self.YSize, self.ZSize)
+
class AnimInfoBinary:
def __init__(self):
- self.Name = "" # length=64
- self.Group = "" # length=64
- self.TotalBones = 0
- self.RootInclude = 0
+ self.Name = "" # length=64
+ self.Group = "" # length=64
+ self.TotalBones = 0
+ self.RootInclude = 0
self.KeyCompressionStyle = 0
- self.KeyQuotum = 0
- self.KeyPrediction = 0.0
- self.TrackTime = 0.0
- self.AnimRate = 0.0
- self.StartBone = 0
- self.FirstRawFrame = 0
- self.NumRawFrames = 0
+ self.KeyQuotum = 0
+ self.KeyPrediction = 0.0
+ self.TrackTime = 0.0
+ self.AnimRate = 0.0
+ self.StartBone = 0
+ self.FirstRawFrame = 0
+ self.NumRawFrames = 0
def dump(self):
- return pack('64s64siiiifffiii', str.encode(self.Name), str.encode(self.Group), self.TotalBones, self.RootInclude, self.KeyCompressionStyle, self.KeyQuotum, self.KeyPrediction, self.TrackTime, self.AnimRate, self.StartBone, self.FirstRawFrame, self.NumRawFrames)
+ return pack('64s64siiiifffiii', str.encode(self.Name), str.encode(self.Group),
+ self.TotalBones, self.RootInclude, self.KeyCompressionStyle, self.KeyQuotum,
+ self.KeyPrediction, self.TrackTime, self.AnimRate, self.StartBone,
+ self.FirstRawFrame, self.NumRawFrames)
+
class VChunkHeader:
def __init__(self, name, type_size):
- self.ChunkID = str.encode(name) # length=20
- self.TypeFlag = 1999801 # special value
- self.DataSize = type_size
- self.DataCount = 0
+ self.ChunkID = str.encode(name) # length=20
+ self.TypeFlag = 1999801 # special value
+ self.DataSize = type_size
+ self.DataCount = 0
def dump(self):
return pack('20siii', self.ChunkID, self.TypeFlag, self.DataSize, self.DataCount)
+
class VMaterial:
def __init__(self):
- self.MaterialName = "" # length=64
- self.TextureIndex = 0
- self.PolyFlags = 0 # DWORD
- self.AuxMaterial = 0
- self.AuxFlags = 0 # DWORD
- self.LodBias = 0
- self.LodStyle = 0
+ self.MaterialName = "" # length=64
+ self.TextureIndex = 0
+ self.PolyFlags = 0 # DWORD
+ self.AuxMaterial = 0
+ self.AuxFlags = 0 # DWORD
+ self.LodBias = 0
+ self.LodStyle = 0
def dump(self):
- #print("DATA MATERIAL:",self.MaterialName)
- return pack('64siLiLii', str.encode(self.MaterialName), self.TextureIndex, self.PolyFlags, self.AuxMaterial, self.AuxFlags, self.LodBias, self.LodStyle)
+ # print("DATA MATERIAL:",self.MaterialName)
+ return pack('64siLiLii', str.encode(self.MaterialName), self.TextureIndex,
+ self.PolyFlags, self.AuxMaterial, self.AuxFlags, self.LodBias, self.LodStyle)
+
class VBone:
def __init__(self):
- self.Name = "" # length = 64
- self.Flags = 0 # DWORD
- self.NumChildren = 0
- self.ParentIndex = 0
- self.BonePos = VJointPos()
+ self.Name = "" # length = 64
+ self.Flags = 0 # DWORD
+ self.NumChildren = 0
+ self.ParentIndex = 0
+ self.BonePos = VJointPos()
def dump(self):
- return pack('64sLii', str.encode(self.Name), self.Flags, self.NumChildren, self.ParentIndex) + self.BonePos.dump()
+ return pack('64sLii', str.encode(self.Name), self.Flags,
+ self.NumChildren, self.ParentIndex) + self.BonePos.dump()
-#same as above - whatever - this is how Epic does it...
+
+# same as above - whatever - this is how Epic does it...
class FNamedBoneBinary:
def __init__(self):
- self.Name = "" # length = 64
- self.Flags = 0 # DWORD
- self.NumChildren = 0
- self.ParentIndex = 0
- self.BonePos = VJointPos()
- self.IsRealBone = 0 # this is set to 1 when the bone is actually a bone in the mesh and not a dummy
+ self.Name = "" # length = 64
+ self.Flags = 0 # DWORD
+ self.NumChildren = 0
+ self.ParentIndex = 0
+ self.BonePos = VJointPos()
+ self.IsRealBone = 0 # this is set to 1 when the bone is actually a bone in the mesh and not a dummy
def dump(self):
- return pack('64sLii', str.encode(self.Name), self.Flags, self.NumChildren, self.ParentIndex) + self.BonePos.dump()
+ return pack('64sLii', str.encode(self.Name), self.Flags,
+ self.NumChildren, self.ParentIndex) + self.BonePos.dump()
+
class VRawBoneInfluence:
def __init__(self):
- self.Weight = 0.0
- self.PointIndex = 0
- self.BoneIndex = 0
+ self.Weight = 0.0
+ self.PointIndex = 0
+ self.BoneIndex = 0
def dump(self):
return pack('fii', self.Weight, self.PointIndex, self.BoneIndex)
+
class VQuatAnimKey:
def __init__(self):
- self.Position = FVector()
- self.Orientation = FQuat()
- self.Time = 0.0
+ self.Position = FVector()
+ self.Orientation = FQuat()
+ self.Time = 0.0
def dump(self):
return self.Position.dump() + self.Orientation.dump() + pack('f', self.Time)
+
class VVertex(object):
def __init__(self):
- self.PointIndex = 0 # WORD
- self.U = 0.0
- self.V = 0.0
- self.MatIndex = 0 # BYTE
- self.Reserved = 0 # BYTE
- self.SmoothGroup = 0
+ self.PointIndex = 0 # WORD
+ self.U = 0.0
+ self.V = 0.0
+ self.MatIndex = 0 # BYTE
+ self.Reserved = 0 # BYTE
+ self.SmoothGroup = 0
def dump(self):
return pack('HHffBBH', self.PointIndex, 0, self.U, self.V, self.MatIndex, self.Reserved, 0)
def __cmp__(self, other):
- return cmp(self.PointIndex, other.PointIndex) \
- or cmp(self.U, other.U) \
- or cmp(self.V, other.V) \
- or cmp(self.MatIndex, other.MatIndex) \
- or cmp(self.Reserved, other.Reserved) \
- or cmp(self.SmoothGroup, other.SmoothGroup )
+ return cmp(self.PointIndex, other.PointIndex) or\
+ cmp(self.U, other.U) or \
+ cmp(self.V, other.V) or \
+ cmp(self.MatIndex, other.MatIndex) or \
+ cmp(self.Reserved, other.Reserved) or \
+ cmp(self.SmoothGroup, other.SmoothGroup)
def _key(self):
return (type(self).__name__, self.PointIndex, self.U, self.V, self.MatIndex, self.Reserved)
@@ -439,6 +481,7 @@ class VVertex(object):
return False
return self._key() == other._key()
+
class VPointSimple:
def __init__(self):
@@ -458,6 +501,7 @@ class VPointSimple:
return False
return self._key() == other._key()
+
class VPoint(object):
def __init__(self):
@@ -483,33 +527,38 @@ class VPoint(object):
return False
return self._key() == other._key()
+
class VTriangle:
def __init__(self):
- self.WedgeIndex0 = 0 # WORD
- self.WedgeIndex1 = 0 # WORD
- self.WedgeIndex2 = 0 # WORD
- self.MatIndex = 0 # BYTE
- self.AuxMatIndex = 0 # BYTE
+ self.WedgeIndex0 = 0 # WORD
+ self.WedgeIndex1 = 0 # WORD
+ self.WedgeIndex2 = 0 # WORD
+ self.MatIndex = 0 # BYTE
+ self.AuxMatIndex = 0 # BYTE
self.SmoothingGroups = 0 # DWORD
def dump(self):
- return pack('HHHBBL', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2, self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
- #print("smooth",self.SmoothingGroups)
- #return pack('HHHBBI', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2, self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
-
+ return pack('HHHBBL', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2,
+ self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
+ """
+ print("smooth",self.SmoothingGroups)
+ return pack('HHHBBI', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2,
+ self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
+ """
# END UNREAL DATA STRUCTS
-#===========================================================================
+# ===========================================================================
+
-#===========================================================================
+# ===========================================================================
# RG - helper class to handle the normal way the UT files are stored
# as sections consisting of a header and then a list of data structures
-#===========================================================================
+# ===========================================================================
class FileSection:
def __init__(self, name, type_size):
self.Header = VChunkHeader(name, type_size)
- self.Data = [] # list of datatypes
+ self.Data = [] # list of datatypes
def dump(self):
data = self.Header.dump()
@@ -520,21 +569,22 @@ class FileSection:
def UpdateHeader(self):
self.Header.DataCount = len(self.Data)
-#===========================================================================
+
+# ===========================================================================
# PSK
-#===========================================================================
+# ===========================================================================
class PSKFile:
def __init__(self):
- self.GeneralHeader = VChunkHeader("ACTRHEAD", 0)
- self.Points = FileSection("PNTS0000", SIZE_VPOINT) # VPoint
- self.Wedges = FileSection("VTXW0000", SIZE_VVERTEX) # VVertex
- self.Faces = FileSection("FACE0000", SIZE_VTRIANGLE) # VTriangle
- self.Materials = FileSection("MATT0000", SIZE_VMATERIAL) # VMaterial
- self.Bones = FileSection("REFSKELT", SIZE_VBONE) # VBone
- self.Influences = FileSection("RAWWEIGHTS", SIZE_VRAWBONEINFLUENCE) # VRawBoneInfluence
-
- #RG - this mapping is not dumped, but is used internally to store the new point indices
+ self.GeneralHeader = VChunkHeader("ACTRHEAD", 0)
+ self.Points = FileSection("PNTS0000", SIZE_VPOINT) # VPoint
+ self.Wedges = FileSection("VTXW0000", SIZE_VVERTEX) # VVertex
+ self.Faces = FileSection("FACE0000", SIZE_VTRIANGLE) # VTriangle
+ self.Materials = FileSection("MATT0000", SIZE_VMATERIAL) # VMaterial
+ self.Bones = FileSection("REFSKELT", SIZE_VBONE) # VBone
+ self.Influences = FileSection("RAWWEIGHTS", SIZE_VRAWBONEINFLUENCE) # VRawBoneInfluence
+
+ # RG - this mapping is not dumped, but is used internally to store the new point indices
# for vertex groups calculated during the mesh dump, so they can be used again
# to dump bone influences during the armature dump
#
@@ -545,7 +595,7 @@ class PSKFile:
# { groupname : [ (index, weight), ... ], ... }
#
# example:
- # { 'MyVertexGroup' : [ (0, 1.0), (5, 1.0), (3, 0.5) ] , 'OtherGroup' : [(2, 1.0)] }
+ # {'MyVertexGroup' : [ (0, 1.0), (5, 1.0), (3, 0.5) ] , 'OtherGroup' : [(2, 1.0)]}
self.VertexGroups = {}
@@ -577,7 +627,8 @@ class PSKFile:
def dump(self):
self.UpdateHeaders()
- data = self.GeneralHeader.dump() + self.Points.dump() + self.Wedges.dump() + self.Faces.dump() + self.Materials.dump() + self.Bones.dump() + self.Influences.dump()
+ data = self.GeneralHeader.dump() + self.Points.dump() + self.Wedges.dump() + \
+ self.Faces.dump() + self.Materials.dump() + self.Bones.dump() + self.Influences.dump()
return data
def GetMatByIndex(self, mat_index):
@@ -591,14 +642,15 @@ class PSKFile:
return m
def PrintOut(self):
- print( "{:>16} {:}".format( "Points", len(self.Points.Data) ) )
- print( "{:>16} {:}".format( "Wedges", len(self.Wedges.Data) ) )
- print( "{:>16} {:}".format( "Faces", len(self.Faces.Data) ) )
- print( "{:>16} {:}".format( "Materials", len(self.Materials.Data) ) )
- print( "{:>16} {:}".format( "Bones", len(self.Bones.Data) ) )
- print( "{:>16} {:}".format( "Influences", len(self.Influences.Data) ) )
-
-#===========================================================================
+ print("{:>16} {:}".format("Points", len(self.Points.Data)))
+ print("{:>16} {:}".format("Wedges", len(self.Wedges.Data)))
+ print("{:>16} {:}".format("Faces", len(self.Faces.Data)))
+ print("{:>16} {:}".format("Materials", len(self.Materials.Data)))
+ print("{:>16} {:}".format("Bones", len(self.Bones.Data)))
+ print("{:>16} {:}".format("Influences", len(self.Influences.Data)))
+
+
+# ===========================================================================
# PSA
#
# Notes from UDN:
@@ -613,14 +665,14 @@ class PSKFile:
# bones are linked up by name. Any bone in a skeleton (from the PSK) that finds no partner in
# the animation sequence (from the PSA) will assume its reference pose stance ( as defined in
# the offsets & rotations that are in the VBones making up the reference skeleton from the PSK)
-#===========================================================================
+# ===========================================================================
class PSAFile:
def __init__(self):
- self.GeneralHeader = VChunkHeader("ANIMHEAD", 0)
- self.Bones = FileSection("BONENAMES", SIZE_FNAMEDBONEBINARY) #FNamedBoneBinary
- self.Animations = FileSection("ANIMINFO", SIZE_ANIMINFOBINARY) #AnimInfoBinary
- self.RawKeys = FileSection("ANIMKEYS", SIZE_VQUATANIMKEY) #VQuatAnimKey
+ self.GeneralHeader = VChunkHeader("ANIMHEAD", 0)
+ self.Bones = FileSection("BONENAMES", SIZE_FNAMEDBONEBINARY) # FNamedBoneBinary
+ self.Animations = FileSection("ANIMINFO", SIZE_ANIMINFOBINARY) # AnimInfoBinary
+ self.RawKeys = FileSection("ANIMKEYS", SIZE_VQUATANIMKEY) # VQuatAnimKey
# this will take the format of key=Bone Name, value = (BoneIndex, Bone Object)
# THIS IS NOT DUMPED
self.BoneLookup = {}
@@ -656,7 +708,7 @@ class PSAFile:
if bone_data[0] == -1:
bone_data[0] = len(self.Bones.Data)
self.AddBone(bone_data[1])
- #self.Bones.Data.append(bone_data[1])
+ # self.Bones.Data.append(bone_data[1])
return bone_data[0]
@@ -675,92 +727,100 @@ class PSAFile:
return self.GeneralHeader.dump() + self.Bones.dump() + self.Animations.dump() + self.RawKeys.dump()
def PrintOut(self):
- print( "{:>16} {:}".format( "Bones", len(self.Bones.Data) ) )
- print( "{:>16} {:}".format( "Animations", len(self.Animations.Data) ) )
- print( "{:>16} {:}".format( "Raw keys", len(self.RawKeys.Data) ) )
-
-#===========================================================================
-# Helpers to create bone structs
-#===========================================================================
-def make_vbone( name, parent_index, child_count, orientation_quat, position_vect ):
- bone = VBone()
- bone.Name = name
- bone.ParentIndex = parent_index
- bone.NumChildren = child_count
- bone.BonePos.Orientation = orientation_quat
- bone.BonePos.Position.X = position_vect.x
- bone.BonePos.Position.Y = position_vect.y
- bone.BonePos.Position.Z = position_vect.z
- #these values seem to be ignored?
- #bone.BonePos.Length = tail.length
- #bone.BonePos.XSize = tail.x
- #bone.BonePos.YSize = tail.y
- #bone.BonePos.ZSize = tail.z
+ print("{:>16} {:}".format("Bones", len(self.Bones.Data)))
+ print("{:>16} {:}".format("Animations", len(self.Animations.Data)))
+ print("{:>16} {:}".format("Raw keys", len(self.RawKeys.Data)))
+
+
+# ===========================================================================
+# Helpers to create bone structs
+# ===========================================================================
+def make_vbone(name, parent_index, child_count, orientation_quat, position_vect):
+ bone = VBone()
+ bone.Name = name
+ bone.ParentIndex = parent_index
+ bone.NumChildren = child_count
+ bone.BonePos.Orientation = orientation_quat
+ bone.BonePos.Position.X = position_vect.x
+ bone.BonePos.Position.Y = position_vect.y
+ bone.BonePos.Position.Z = position_vect.z
+ # these values seem to be ignored?
+ # bone.BonePos.Length = tail.length
+ # bone.BonePos.XSize = tail.x
+ # bone.BonePos.YSize = tail.y
+ # bone.BonePos.ZSize = tail.z
return bone
-def make_namedbonebinary( name, parent_index, child_count, orientation_quat, position_vect, is_real ):
- bone = FNamedBoneBinary()
- bone.Name = name
- bone.ParentIndex = parent_index
- bone.NumChildren = child_count
- bone.BonePos.Orientation = orientation_quat
- bone.BonePos.Position.X = position_vect.x
- bone.BonePos.Position.Y = position_vect.y
- bone.BonePos.Position.Z = position_vect.z
- bone.IsRealBone = is_real
+
+def make_namedbonebinary(name, parent_index, child_count, orientation_quat, position_vect, is_real):
+ bone = FNamedBoneBinary()
+ bone.Name = name
+ bone.ParentIndex = parent_index
+ bone.NumChildren = child_count
+ bone.BonePos.Orientation = orientation_quat
+ bone.BonePos.Position.X = position_vect.x
+ bone.BonePos.Position.Y = position_vect.y
+ bone.BonePos.Position.Z = position_vect.z
+ bone.IsRealBone = is_real
return bone
-def make_fquat( bquat ):
- quat = FQuat()
- #flip handedness for UT = set x,y,z to negative (rotate in other direction)
- quat.X = -bquat.x
- quat.Y = -bquat.y
- quat.Z = -bquat.z
- quat.W = bquat.w
+
+def make_fquat(bquat):
+ quat = FQuat()
+ # flip handedness for UT = set x,y,z to negative (rotate in other direction)
+ quat.X = -bquat.x
+ quat.Y = -bquat.y
+ quat.Z = -bquat.z
+ quat.W = bquat.w
+
return quat
-def make_fquat_default( bquat ):
- quat = FQuat()
- #print(dir(bquat))
- quat.X = bquat.x
- quat.Y = bquat.y
- quat.Z = bquat.z
- quat.W = bquat.w
+
+def make_fquat_default(bquat):
+ quat = FQuat()
+ # print(dir(bquat))
+ quat.X = bquat.x
+ quat.Y = bquat.y
+ quat.Z = bquat.z
+ quat.W = bquat.w
+
return quat
-#===========================================================================
-#RG - check to make sure face isnt a line
-#===========================================================================
-def is_1d_face( face, mesh ):
- #ID Vertex of id point
+
+# ===========================================================================
+# RG - check to make sure face isnt a line
+# ===========================================================================
+def is_1d_face(face, mesh):
+ # ID Vertex of id point
v0 = face.vertices[0]
v1 = face.vertices[1]
v2 = face.vertices[2]
- return (mesh.vertices[v0].co == mesh.vertices[v1].co \
- or mesh.vertices[v1].co == mesh.vertices[v2].co \
- or mesh.vertices[v2].co == mesh.vertices[v0].co)
+ return (mesh.vertices[v0].co == mesh.vertices[v1].co or
+ mesh.vertices[v1].co == mesh.vertices[v2].co or
+ mesh.vertices[v2].co == mesh.vertices[v0].co)
return False
-#===========================================================================
+
+# ===========================================================================
# Smoothing group
# (renamed to seperate it from VVertex.SmoothGroup)
-#===========================================================================
+# ===========================================================================
class SmoothingGroup:
static_id = 1
def __init__(self):
- self.faces = []
- self.neighboring_faces = []
+ self.faces = []
+ self.neighboring_faces = []
self.neighboring_groups = []
- self.id = -1
- self.local_id = SmoothingGroup.static_id
+ self.id = -1
+ self.local_id = SmoothingGroup.static_id
SmoothingGroup.static_id += 1
def __cmp__(self, other):
if isinstance(other, SmoothingGroup):
- return cmp( self.local_id, other.local_id )
+ return cmp(self.local_id, other.local_id)
return -1
def __hash__(self):
@@ -774,27 +834,29 @@ class SmoothingGroup:
if temp_id < 0x80000000:
temp_id = temp_id << 1
else:
- raise Error("Smoothing Group ID Overflowed, Smoothing Group evidently has more than 31 neighboring groups")
+ raise Error("Smoothing Group ID Overflowed, "
+ "Smoothing Group evidently has more than 31 neighboring groups")
self.id = temp_id
return self.id
def make_neighbor(self, new_neighbor):
if new_neighbor not in self.neighboring_groups:
- self.neighboring_groups.append( new_neighbor )
+ self.neighboring_groups.append(new_neighbor)
def contains_face(self, face):
return (face in self.faces)
def add_neighbor_face(self, face):
- if not face in self.neighboring_faces:
- self.neighboring_faces.append( face )
+ if face not in self.neighboring_faces:
+ self.neighboring_faces.append(face)
def add_face(self, face):
- if not face in self.faces:
- self.faces.append( face )
+ if face not in self.faces:
+ self.faces.append(face)
-def determine_edge_sharing( mesh ):
+
+def determine_edge_sharing(mesh):
edge_sharing_list = dict()
@@ -803,12 +865,13 @@ def determine_edge_sharing( mesh ):
for face in mesh.tessfaces:
for key in face.edge_keys:
- if not face in edge_sharing_list[key]:
- edge_sharing_list[key].append(face) # mark this face as sharing this edge
+ if face not in edge_sharing_list[key]:
+ edge_sharing_list[key].append(face) # mark this face as sharing this edge
return edge_sharing_list
-def find_edges( mesh, key ):
+
+def find_edges(mesh, key):
""" Temp replacement for mesh.findEdges().
This is painfully slow.
"""
@@ -817,7 +880,8 @@ def find_edges( mesh, key ):
if key[0] == v[0] and key[1] == v[1]:
return edge.index
-def add_face_to_smoothgroup( mesh, face, edge_sharing_list, smoothgroup ):
+
+def add_face_to_smoothgroup(mesh, face, edge_sharing_list, smoothgroup):
if face in smoothgroup.faces:
return
@@ -831,62 +895,68 @@ def add_face_to_smoothgroup( mesh, face, edge_sharing_list, smoothgroup ):
if edge_id is not None:
# not sharp
- if not( mesh.edges[edge_id].use_edge_sharp):
+ if not (mesh.edges[edge_id].use_edge_sharp):
for shared_face in edge_sharing_list[key]:
if shared_face != face:
# recursive
- add_face_to_smoothgroup( mesh, shared_face, edge_sharing_list, smoothgroup )
+ add_face_to_smoothgroup(mesh, shared_face, edge_sharing_list, smoothgroup)
# sharp
else:
for shared_face in edge_sharing_list[key]:
if shared_face != face:
- smoothgroup.add_neighbor_face( shared_face )
+ smoothgroup.add_neighbor_face(shared_face)
+
-def determine_smoothgroup_for_face( mesh, face, edge_sharing_list, smoothgroup_list ):
+def determine_smoothgroup_for_face(mesh, face, edge_sharing_list, smoothgroup_list):
for group in smoothgroup_list:
if (face in group.faces):
return
- smoothgroup = SmoothingGroup();
- add_face_to_smoothgroup( mesh, face, edge_sharing_list, smoothgroup )
+ smoothgroup = SmoothingGroup()
+ add_face_to_smoothgroup(mesh, face, edge_sharing_list, smoothgroup)
+
+ if smoothgroup not in smoothgroup_list:
+ smoothgroup_list.append(smoothgroup)
- if not smoothgroup in smoothgroup_list:
- smoothgroup_list.append( smoothgroup )
-def build_neighbors_tree( smoothgroup_list ):
+def build_neighbors_tree(smoothgroup_list):
for group in smoothgroup_list:
for face in group.neighboring_faces:
for neighbor_group in smoothgroup_list:
- if neighbor_group.contains_face( face ) and neighbor_group not in group.neighboring_groups:
- group.make_neighbor( neighbor_group )
- neighbor_group.make_neighbor( group )
+ if neighbor_group.contains_face(face) and neighbor_group not in group.neighboring_groups:
+ group.make_neighbor(neighbor_group)
+ neighbor_group.make_neighbor(group)
-#===========================================================================
+
+# ===========================================================================
# parse_smooth_groups
-#===========================================================================
-def parse_smooth_groups( mesh ):
+# ===========================================================================
+def parse_smooth_groups(mesh):
print("Parsing smooth groups...")
- t = time.clock()
- smoothgroup_list = []
- edge_sharing_list = determine_edge_sharing(mesh)
- #print("faces:",len(mesh.tessfaces))
- interval = math.floor(len(mesh.tessfaces) / 100)
- if interval == 0: #if the faces are few do this
- interval = math.floor(len(mesh.tessfaces) / 10)
- #print("FACES:",len(mesh.tessfaces),"//100 =" "interval:",interval)
+ t = time.clock()
+ smoothgroup_list = []
+ edge_sharing_list = determine_edge_sharing(mesh)
+
+ # print("faces:",len(mesh.tessfaces))
+ interval = math.floor(len(mesh.tessfaces) / 100)
+
+ if interval == 0: # if the faces are few do this
+ interval = math.floor(len(mesh.tessfaces) / 10)
+ # print("FACES:",len(mesh.tessfaces),"//100 =" "interval:",interval)
+
for face in mesh.tessfaces:
- #print(dir(face))
+ # print(dir(face))
determine_smoothgroup_for_face(mesh, face, edge_sharing_list, smoothgroup_list)
# progress indicator, writes to console without scrolling
if face.index > 0 and (face.index % interval) == 0:
- print("Processing... {}%\r".format( int(face.index / len(mesh.tessfaces) * 100) ), end='')
+ print("Processing... {}%\r".format(int(face.index / len(mesh.tessfaces) * 100)), end='')
sys.stdout.flush()
- print("Completed" , ' '*20)
+ print("Completed", ' ' * 20)
verbose("len(smoothgroup_list)={}".format(len(smoothgroup_list)))
@@ -898,31 +968,33 @@ def parse_smooth_groups( mesh ):
print("Smooth group parsing completed in {:.2f}s".format(time.clock() - t))
return smoothgroup_list
-#===========================================================================
+
+# ===========================================================================
# http://en.wikibooks.org/wiki/Blender_3D:_Blending_Into_Python/Cookbook#Triangulate_NMesh
# blender 2.50 format using the Operators/command convert the mesh to tri mesh
-#===========================================================================
-def triangulate_mesh( object ):
+# ===========================================================================
+def triangulate_mesh(object):
verbose(header("triangulateNMesh"))
- #print(type(object))
+ # print(type(object))
scene = bpy.context.scene
- me_ob = object.copy()
- me_ob.data = object.to_mesh(bpy.context.scene, True, 'PREVIEW') #write data object
+ me_ob = object.copy()
+ me_ob.data = object.to_mesh(bpy.context.scene, True, 'PREVIEW') # write data object
bpy.context.scene.objects.link(me_ob)
bpy.context.scene.update()
bpy.ops.object.mode_set(mode='OBJECT')
+
for i in scene.objects:
- i.select = False # deselect all objects
+ i.select = False # deselect all objects
- me_ob.select = True
- scene.objects.active = me_ob
+ me_ob.select = True
+ scene.objects.active = me_ob
print("Copy and Convert mesh just incase any way...")
bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='SELECT')# select all the face/vertex/edge
+ bpy.ops.mesh.select_all(action='SELECT') # select all the face/vertex/edge
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.quads_convert_to_tris()
bpy.context.scene.update()
@@ -933,81 +1005,99 @@ def triangulate_mesh( object ):
verbose("Triangulated mesh")
- me_ob.data = me_ob.to_mesh(bpy.context.scene, True, 'PREVIEW') #write data object
+ me_ob.data = me_ob.to_mesh(bpy.context.scene, True, 'PREVIEW') # write data object
bpy.context.scene.update()
return me_ob
-#copy mesh data and then merge them into one object
+
+# copy mesh data and then merge them into one object
def meshmerge(selectedobjects):
- bpy.ops.object.mode_set(mode='OBJECT') #object mode and not edit mode
- cloneobjects = [] #object holder for copying object data
+ bpy.ops.object.mode_set(mode='OBJECT') # object mode and not edit mode
+ cloneobjects = [] # object holder for copying object data
+
if len(selectedobjects) > 1:
- print("selectedobjects:",len(selectedobjects)) #print select object
- count = 0 #reset count
- for count in range(len( selectedobjects)):
- #print("Index:",count)
+ print("selectedobjects:", len(selectedobjects)) # print select object
+ count = 0 # reset count
+
+ for count in range(len(selectedobjects)):
+ # print("Index:",count)
if selectedobjects[count] is not 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 #assign the data
- bpy.context.scene.objects.link(me_ob)#link the object to the scene #current object location
- print("Index:",count,"clone object",me_ob.name) #print clone object
- cloneobjects.append(me_ob) #add object to the array
- for i in bpy.data.objects: i.select = False #deselect all objects
- count = 0 #reset count
- #begin merging the mesh together as one
- for count in range(len( cloneobjects)):
+ 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 # assign the data
+ bpy.context.scene.objects.link(me_ob) # link the object to the scene #current object location
+ print("Index:", count, "clone object", me_ob.name) # print clone object
+ cloneobjects.append(me_ob) # add object to the array
+
+ for i in bpy.data.objects:
+ i.select = False # deselect all objects
+ count = 0 # reset count
+ # begin merging the mesh together as one
+ for count in range(len(cloneobjects)):
if count == 0:
bpy.context.scene.objects.active = cloneobjects[count]
- print("Set Active Object:",cloneobjects[count].name)
+ print("Set Active Object:", cloneobjects[count].name)
cloneobjects[count].select = True
- bpy.ops.object.join() #join object together
+ bpy.ops.object.join() # join object together
if len(cloneobjects) > 1:
bpy.types.Scene.udk_copy_merge = True
return cloneobjects[0]
-#sort the mesh center top list and not center at the last array. Base on order while select to merge mesh to make them center.
+
+# sort the mesh center top list and not center at the last array.
+# Base on order while select to merge mesh to make them center.
def sortmesh(selectmesh):
print("MESH SORTING...")
centermesh = []
notcentermesh = []
for countm in range(len(selectmesh)):
- #if object are center add here
- if selectmesh[countm].location.x == 0 and selectmesh[countm].location.y == 0 and selectmesh[countm].location.z == 0:
+ # if object are center add here
+ if selectmesh[countm].location.x == 0 and \
+ selectmesh[countm].location.y == 0 and \
+ selectmesh[countm].location.z == 0:
centermesh.append(selectmesh[countm])
- else:#if not add here for not center
+ else: # if not add here for not center
notcentermesh.append(selectmesh[countm])
selectmesh = []
- #add mesh object in order for merge object
+ # add mesh object in order for merge object
for countm in range(len(centermesh)):
selectmesh.append(centermesh[countm])
for countm in range(len(notcentermesh)):
selectmesh.append(notcentermesh[countm])
- if len(selectmesh) == 1: #if there one mesh just do some here
- return selectmesh[0] #return object mesh
+ if len(selectmesh) == 1: # if there one mesh just do some here
+ return selectmesh[0] # return object mesh
else:
- return meshmerge(selectmesh) #return merge object mesh
+ return meshmerge(selectmesh) # return merge object mesh
+
+
import binascii
-#===========================================================================
+
+
+# ===========================================================================
# parse_mesh
-#===========================================================================
-def parse_mesh( mesh, psk ):
- #bpy.ops.object.mode_set(mode='OBJECT')
- #error ? on commands for select object?
+# ===========================================================================
+def parse_mesh(mesh, psk):
+ # bpy.ops.object.mode_set(mode='OBJECT')
+ # error ? on commands for select object?
print(header("MESH", 'RIGHT'))
print("Mesh object:", mesh.name)
scene = bpy.context.scene
- for i in scene.objects: i.select = False # deselect all objects
- scene.objects.active = mesh
+
+ for i in scene.objects:
+ i.select = False # deselect all objects
+
+ scene.objects.active = mesh
setmesh = mesh
mesh = triangulate_mesh(mesh)
- if bpy.types.Scene.udk_copy_merge == True:
+
+ if bpy.types.Scene.udk_copy_merge is True:
bpy.context.scene.objects.unlink(setmesh)
- #print("FACES----:",len(mesh.data.tessfaces))
+
+ # print("FACES----:",len(mesh.data.tessfaces))
verbose("Working mesh object: {}".format(mesh.name))
- #collect a list of the material names
+ # collect a list of the material names
print("Materials...")
mat_slot_index = 0
@@ -1016,26 +1106,30 @@ def parse_mesh( mesh, psk ):
print(" Material {} '{}'".format(mat_slot_index, slot.name))
MaterialName.append(slot.name)
- #if slot.material.texture_slots[0] is not None:
- #if slot.material.texture_slots[0].texture.image.filepath is not None:
- #print(" Texture path {}".format(slot.material.texture_slots[0].texture.image.filepath))
- #create the current material
- v_material = psk.GetMatByIndex(mat_slot_index)
+
+ """
+ if slot.material.texture_slots[0] is not None:
+ if slot.material.texture_slots[0].texture.image.filepath is not None:
+ print(" Texture path {}".format(slot.material.texture_slots[0].texture.image.filepath))
+ """
+
+ # create the current material
+ v_material = psk.GetMatByIndex(mat_slot_index)
v_material.MaterialName = slot.name
v_material.TextureIndex = mat_slot_index
- v_material.AuxMaterial = mat_slot_index
+ v_material.AuxMaterial = mat_slot_index
mat_slot_index += 1
verbose(" PSK index {}".format(v_material.TextureIndex))
- #END slot in mesh.material_slots
+ # END slot in mesh.material_slots
# object_mat = mesh.materials[0]
- #object_material_index = mesh.active_material_index
- #FIXME ^ this is redundant due to "= face.material_index" in face loop
+ # object_material_index = mesh.active_material_index
+ # FIXME ^ this is redundant due to "= face.material_index" in face loop
- wedges = ObjMap()
- points = ObjMap() #vertex
- points_linked = {}
+ wedges = ObjMap()
+ points = ObjMap() # vertex
+ points_linked = {}
discarded_face_count = 0
sys.setrecursionlimit(1000000)
@@ -1054,15 +1148,13 @@ def parse_mesh( mesh, psk ):
smoothgroup_id = smooth_group.id
break
- #print ' -- Dumping UVs -- '
- #print current_face.uv_textures
# modified by VendorX
object_material_index = face.material_index
if len(face.vertices) != 3:
raise Error("Non-triangular face (%i)" % len(face.vertices))
- #RG - apparently blender sometimes has problems when you do quad to triangle
+ # RG - apparently blender sometimes has problems when you do quad to triangle
# conversion, and ends up creating faces that have only TWO points -
# one of the points is simply in the vertex list for the face twice.
# This is bad, since we can't get a real face normal for a LINE, we need
@@ -1073,40 +1165,40 @@ def parse_mesh( mesh, psk ):
if not is_1d_face(face, mesh.data):
- wedge_list = []
- vect_list = []
+ wedge_list = []
+ vect_list = []
- #get or create the current material
+ # get or create the current material
psk.GetMatByIndex(object_material_index)
- face_index = face.index
- has_uv = False
- face_uv = None
+ face_index = face.index
+ has_uv = False
+ face_uv = None
if len(mesh.data.uv_textures) > 0:
- has_uv = True
- uv_layer = mesh.data.tessface_uv_textures.active
- face_uv = uv_layer.data[face_index]
- #size(data) is number of texture faces. Each face has UVs
- #print("DATA face uv: ",len(faceUV.uv), " >> ",(faceUV.uv[0][0]))
+ has_uv = True
+ uv_layer = mesh.data.tessface_uv_textures.active
+ face_uv = uv_layer.data[face_index]
+ # size(data) is number of texture faces. Each face has UVs
+ # print("DATA face uv: ",len(faceUV.uv), " >> ",(faceUV.uv[0][0]))
for i in range(3):
- vert_index = face.vertices[i]
- vert = mesh.data.vertices[vert_index]
- uv = []
- #assumes 3 UVs Per face (for now)
+ vert_index = face.vertices[i]
+ vert = mesh.data.vertices[vert_index]
+ uv = []
+ # assumes 3 UVs Per face (for now)
if (has_uv):
if len(face_uv.uv) != 3:
print("WARNING: face has more or less than 3 UV coordinates - writing 0,0...")
uv = [0.0, 0.0]
else:
- uv = [face_uv.uv[i][0],face_uv.uv[i][1]] #OR bottom works better # 24 for cube
+ uv = [face_uv.uv[i][0], face_uv.uv[i][1]] # OR bottom works better # 24 for cube
else:
- #print ("No UVs?")
+ # print ("No UVs?")
uv = [0.0, 0.0]
- #flip V coordinate because UEd requires it and DOESN'T flip it on its own like it
- #does with the mesh Y coordinates. this is otherwise known as MAGIC-2
+ # flip V coordinate because UEd requires it and DOESN'T flip it on its own like it
+ # does with the mesh Y coordinates. this is otherwise known as MAGIC-2
uv[1] = 1.0 - uv[1]
# clamp UV coords if udk_option_clamp_uv is True
@@ -1122,31 +1214,32 @@ def parse_mesh( mesh, psk ):
# RE - Append untransformed vector (for normal calc below)
# TODO: convert to Blender.Mathutils
- vect_list.append( FVector(vert.co.x, vert.co.y, vert.co.z) )
+ vect_list.append(FVector(vert.co.x, vert.co.y, vert.co.z))
# Transform position for export
- #vpos = vert.co * object_material_index
+ # vpos = vert.co * object_material_index
- #should fixed this!!
+ # should fixed this!!
vpos = mesh.matrix_local * vert.co
if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
- #print("OK!")
+ # print("OK!")
vpos.x = vpos.x * bpy.context.scene.udk_option_scale
vpos.y = vpos.y * bpy.context.scene.udk_option_scale
vpos.z = vpos.z * bpy.context.scene.udk_option_scale
- #print("scale pos:", vpos)
+
+ # print("scale pos:", vpos)
# Create the point
- p = VPoint()
- p.Point.X = vpos.x
- p.Point.Y = vpos.y
- p.Point.Z = vpos.z
- if bpy.context.scene.udk_option_smoothing_groups:#is this necessary?
+ p = VPoint()
+ p.Point.X = vpos.x
+ p.Point.Y = vpos.y
+ p.Point.Z = vpos.z
+ if bpy.context.scene.udk_option_smoothing_groups: # is this necessary?
p.SmoothGroup = smoothgroup_id
- lPoint = VPointSimple()
- lPoint.Point.X = vpos.x
- lPoint.Point.Y = vpos.y
- lPoint.Point.Z = vpos.z
+ lPoint = VPointSimple()
+ lPoint.Point.X = vpos.x
+ lPoint.Point.Y = vpos.y
+ lPoint.Point.Z = vpos.z
if lPoint in points_linked:
if not(p in points_linked[lPoint]):
@@ -1155,24 +1248,24 @@ def parse_mesh( mesh, psk ):
points_linked[lPoint] = [p]
# Create the wedge
- w = VVertex()
- w.MatIndex = object_material_index
- w.PointIndex = points.get(p) # store keys
- w.U = uv[0]
- w.V = uv[1]
- if bpy.context.scene.udk_option_smoothing_groups:#is this necessary?
+ w = VVertex()
+ w.MatIndex = object_material_index
+ w.PointIndex = points.get(p) # store keys
+ w.U = uv[0]
+ w.V = uv[1]
+ if bpy.context.scene.udk_option_smoothing_groups: # is this necessary?
w.SmoothGroup = smoothgroup_id
index_wedge = wedges.get(w)
wedge_list.append(index_wedge)
- #print results
- #print("result PointIndex={}, U={:.6f}, V={:.6f}, wedge_index={}".format(
+ # print results
+ # print("result PointIndex={}, U={:.6f}, V={:.6f}, wedge_index={}".format(
# w.PointIndex,
# w.U,
# w.V,
# index_wedge))
- #END for i in range(3)
+ # END for i in range(3)
# Determine face vertex order
@@ -1198,9 +1291,9 @@ def parse_mesh( mesh, psk ):
elif dot < 0:
(tri.WedgeIndex0, tri.WedgeIndex1, tri.WedgeIndex2) = wedge_list
else:
- dindex0 = face.vertices[0];
- dindex1 = face.vertices[1];
- dindex2 = face.vertices[2];
+ dindex0 = face.vertices[0]
+ dindex1 = face.vertices[1]
+ dindex2 = face.vertices[2]
mesh.data.vertices[dindex0].select = True
mesh.data.vertices[dindex1].select = True
@@ -1211,7 +1304,7 @@ def parse_mesh( mesh, psk ):
str(mesh.data.vertices[dindex2].co)))
face.select = True
- if face.use_smooth == True:
+ if face.use_smooth is True:
tri.SmoothingGroups = 1
else:
tri.SmoothingGroups = 0
@@ -1223,12 +1316,12 @@ def parse_mesh( mesh, psk ):
psk.AddFace(tri)
- #END if not is_1d_face(current_face, mesh.data)
+ # END if not is_1d_face(current_face, mesh.data)
else:
discarded_face_count += 1
- #END face in mesh.data.faces
+ # END face in mesh.data.faces
print("{} points".format(len(points.dict)))
@@ -1236,7 +1329,7 @@ def parse_mesh( mesh, psk ):
psk.AddPoint(point)
if len(points.dict) > 32767:
- raise Error("Mesh vertex limit exceeded! {} > 32767".format(len(points.dict)))
+ raise Error("Mesh vertex limit exceeded! {} > 32767".format(len(points.dict)))
print("{} wedges".format(len(wedges.dict)))
@@ -1248,73 +1341,75 @@ def parse_mesh( mesh, psk ):
print("WARNING: Mesh contained degenerate faces (non-planar)")
print(" Discarded {} faces".format(discarded_face_count))
- #RG - walk through the vertex groups and find the indexes into the PSK points array
- #for them, then store that index and the weight as a tuple in a new list of
- #verts for the group that we can look up later by bone name, since Blender matches
- #verts to bones for influences by having the VertexGroup named the same thing as
- #the bone
+ # RG - walk through the vertex groups and find the indexes into the PSK points array
+ # for them, then store that index and the weight as a tuple in a new list of
+ # verts for the group that we can look up later by bone name, since Blender matches
+ # verts to bones for influences by having the VertexGroup named the same thing as
+ # the bone
- #[print(x, len(points_linked[x])) for x in points_linked]
- #print("pointsindex length ",len(points_linked))
- #vertex group
+ # [print(x, len(points_linked[x])) for x in points_linked]
+ # print("pointsindex length ",len(points_linked))
+ # vertex group
# all vertex groups of the mesh (obj)...
for obj_vertex_group in mesh.vertex_groups:
- #print(" bone group build:",obj_vertex_group.name)#print bone name
- #print(dir(obj_vertex_group))
+ # print(" bone group build:",obj_vertex_group.name)#print bone name
+ # print(dir(obj_vertex_group))
verbose("obj_vertex_group.name={}".format(obj_vertex_group.name))
vertex_list = []
# all vertices in the mesh...
for vertex in mesh.data.vertices:
- #print(dir(vertex))
+ # print(dir(vertex))
# all groups this vertex is a member of...
for vgroup in vertex.groups:
if vgroup.group == obj_vertex_group.index:
- vertex_weight = vgroup.weight
- p = VPointSimple()
- vpos = mesh.matrix_local * vertex.co
+ vertex_weight = vgroup.weight
+ p = VPointSimple()
+ vpos = mesh.matrix_local * vertex.co
+
if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
vpos.x = vpos.x * bpy.context.scene.udk_option_scale
vpos.y = vpos.y * bpy.context.scene.udk_option_scale
vpos.z = vpos.z * bpy.context.scene.udk_option_scale
- p.Point.X = vpos.x
- p.Point.Y = vpos.y
- p.Point.Z = vpos.z
- #print(p)
- #print(len(points_linked[p]))
- try: #check if point doesn't give error
+ p.Point.X = vpos.x
+ p.Point.Y = vpos.y
+ p.Point.Z = vpos.z
+ # print(p)
+ # print(len(points_linked[p]))
+ try: # check if point doesn't give error
for point in points_linked[p]:
- point_index = points.get(point) #point index
- v_item = (point_index, vertex_weight)
+ point_index = points.get(point) # point index
+ v_item = (point_index, vertex_weight)
vertex_list.append(v_item)
- except Exception:#if get error ignore them #not safe I think
+ except Exception: # if get error ignore them # not safe I think
print("Error link points!")
pass
- #bone name, [point id and wieght]
- #print("Add Vertex Group:",obj_vertex_group.name, " No. Points:",len(vertex_list))
+ # bone name, [point id and wieght]
+ # print("Add Vertex Group:",obj_vertex_group.name, " No. Points:",len(vertex_list))
psk.VertexGroups[obj_vertex_group.name] = vertex_list
# remove the temporary triangulated mesh
- if bpy.context.scene.udk_option_triangulate == True:
+ if bpy.context.scene.udk_option_triangulate is True:
verbose("Removing temporary triangle mesh: {}".format(mesh.name))
bpy.ops.object.mode_set(mode='OBJECT') # OBJECT mode
mesh.parent = None # unparent to avoid phantom links
bpy.context.scene.objects.unlink(mesh) # unlink
-#===========================================================================
+
+# ===========================================================================
# Collate bones that belong to the UDK skeletal mesh
-#===========================================================================
-def parse_armature( armature, psk, psa ):
+# ===========================================================================
+def parse_armature(armature, psk, psa):
print(header("ARMATURE", 'RIGHT'))
verbose("Armature object: {} Armature data: {}".format(armature.name, armature.data.name))
# generate a list of root bone candidates
- root_candidates = [b for b in armature.data.bones if b.parent is None and b.use_deform == True]
+ root_candidates = [b for b in armature.data.bones if b.parent is None and b.use_deform is True]
# should be a single, unambiguous result
if len(root_candidates) == 0:
@@ -1324,9 +1419,9 @@ def parse_armature( armature, psk, psa ):
raise Error("Ambiguous root for UDK. More than one root bone is using deform.")
# prep for bone collection
- udk_root_bone = root_candidates[0]
- udk_bones = []
- BoneUtil.static_bone_id = 0 # replaces global
+ udk_root_bone = root_candidates[0]
+ udk_bones = []
+ BoneUtil.static_bone_id = 0 # replaces global
# traverse bone chain
print("{: <3} {: <48} {: <20}".format("ID", "Bone", "Status"))
@@ -1341,7 +1436,8 @@ def parse_armature( armature, psk, psa ):
# this is passed to parse_animation instead of working from keyed bones in the action
return udk_bones
-#===========================================================================
+
+# ===========================================================================
# bone current bone
# bones bone list
# psk the PSK file object
@@ -1349,19 +1445,18 @@ def parse_armature( armature, psk, psa ):
# parent_id
# parent_matrix
# indent text indent for recursive log
-#===========================================================================
-def recurse_bone( bone, bones, psk, psa, parent_id, parent_matrix, indent="" ):
+# ===========================================================================
+def recurse_bone(bone, bones, psk, psa, parent_id, parent_matrix, indent=""):
status = "Ok"
-
- bones.append(bone);
+ bones.append(bone)
if not bone.use_deform:
status = "No effect"
# calc parented bone transform
if bone.parent is not None:
- quat = make_fquat(bone.matrix.to_quaternion())
+ quat = make_fquat(bone.matrix.to_quaternion())
quat_parent = bone.parent.matrix.to_quaternion().inverted()
parent_head = quat_parent * bone.parent.head
parent_tail = quat_parent * bone.parent.tail
@@ -1370,73 +1465,81 @@ def recurse_bone( bone, bones, psk, psa, parent_id, parent_matrix, indent="" ):
# calc root bone transform
else:
translation = parent_matrix * bone.head # ARMATURE OBJECT Location
- rot_matrix = bone.matrix * parent_matrix.to_3x3() # ARMATURE OBJECT Rotation
- quat = make_fquat_default(rot_matrix.to_quaternion())
- #udk_option_scale bones here?
+ rot_matrix = bone.matrix * parent_matrix.to_3x3() # ARMATURE OBJECT Rotation
+ quat = make_fquat_default(rot_matrix.to_quaternion())
+
+ # udk_option_scale bones here?
if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
translation.x = translation.x * bpy.context.scene.udk_option_scale
translation.y = translation.y * bpy.context.scene.udk_option_scale
translation.z = translation.z * bpy.context.scene.udk_option_scale
- bone_id = BoneUtil.static_bone_id # ALT VERS
+ bone_id = BoneUtil.static_bone_id # ALT VERS
BoneUtil.static_bone_id += 1 # ALT VERS
child_count = len(bone.children)
- psk.AddBone( make_vbone(bone.name, parent_id, child_count, quat, translation) )
- psa.StoreBone( make_namedbonebinary(bone.name, parent_id, child_count, quat, translation, 1) )
+ psk.AddBone(make_vbone(bone.name, parent_id, child_count, quat, translation))
+ psa.StoreBone(make_namedbonebinary(bone.name, parent_id, child_count, quat, translation, 1))
- #RG - dump influences for this bone - use the data we collected in the mesh dump phase to map our bones to vertex groups
+ # RG - dump influences for this bone - use the data we collected
+ # in the mesh dump phase to map our bones to vertex groups
if bone.name in psk.VertexGroups:
vertex_list = psk.VertexGroups[bone.name]
- #print("vertex list:", len(vertex_list), " of >" ,bone.name )
+ # print("vertex list:", len(vertex_list), " of >" ,bone.name)
+
for vertex_data in vertex_list:
- point_index = vertex_data[0]
- vertex_weight = vertex_data[1]
- influence = VRawBoneInfluence()
- influence.Weight = vertex_weight
- influence.BoneIndex = bone_id
- influence.PointIndex = point_index
- #print (" AddInfluence to vertex {}, weight={},".format(point_index, vertex_weight))
+ point_index = vertex_data[0]
+ vertex_weight = vertex_data[1]
+ influence = VRawBoneInfluence()
+ influence.Weight = vertex_weight
+ influence.BoneIndex = bone_id
+ influence.PointIndex = point_index
+ # print (" AddInfluence to vertex {}, weight={},".format(point_index, vertex_weight))
psk.AddInfluence(influence)
else:
status = "No vertex group"
- #FIXME overwriting previous status error?
+ # FIXME overwriting previous status error?
- print("{:<3} {:<48} {:<20}".format(bone_id, indent+bone.name, status))
+ print("{:<3} {:<48} {:<20}".format(bone_id, indent + bone.name, status))
- #bone.matrix_local
- #recursively dump child bones
+ # bone.matrix_local
+ # recursively dump child bones
for child_bone in bone.children:
- recurse_bone(child_bone, bones, psk, psa, bone_id, parent_matrix, " "+indent)
+ recurse_bone(child_bone, bones, psk, psa, bone_id, parent_matrix, " " + indent)
+
# FIXME rename? remove?
class BoneUtil:
- static_bone_id = 0 # static property to replace global
+ static_bone_id = 0 # static property to replace global
-#===========================================================================
+
+# ===========================================================================
# armature the armature
# udk_bones list of bones to be exported
# actions_to_export list of actions to process for export
# psa the PSA file object
-#===========================================================================
-def parse_animation( armature, udk_bones, actions_to_export, psa ):
+# ===========================================================================
+def parse_animation(armature, udk_bones, actions_to_export, psa):
print(header("ANIMATION", 'RIGHT'))
- context = bpy.context
- anim_rate = context.scene.render.fps
+ context = bpy.context
+ anim_rate = context.scene.render.fps
verbose("Armature object: {}".format(armature.name))
- print("Scene: {} FPS: {} Frames: {} to {}".format(context.scene.name, anim_rate, context.scene.frame_start, context.scene.frame_end))
- print("Processing {} action(s)".format(len(actions_to_export)))
- print()
- if armature.animation_data is None: #if animation data was not create for the armature it will skip the exporting action set(s)
+ print("Scene: {} FPS: {} Frames: {} to {}".format(context.scene.name, anim_rate,
+ context.scene.frame_start, context.scene.frame_end)
+ )
+ print("Processing {} action(s)\n".format(len(actions_to_export)))
+
+ # if animation data was not create for the armature it will skip the exporting action set(s)
+ if armature.animation_data is None:
print("None Actions Set! skipping...")
return
- restoreAction = armature.animation_data.action # Q: is animation_data always valid?
-
- restoreFrame = context.scene.frame_current # we already do this in export_proxy, but we'll do it here too for now
+ restoreAction = armature.animation_data.action # Q: is animation_data always valid?
+ # we already do this in export_proxy, but we'll do it here too for now
+ restoreFrame = context.scene.frame_current
raw_frame_index = 0 # used to set FirstRawFrame, seperating actions in the raw keyframe array
# action loop...
@@ -1449,24 +1552,24 @@ def parse_animation( armature, udk_bones, actions_to_export, psa ):
continue
# apply action to armature and update scene
- # note if loop all actions that is not armature it will override and will break armature animation.
+ # note if loop all actions that is not armature it will override and will break armature animation
armature.animation_data.action = action
context.scene.update()
# min/max frames define range
- framemin, framemax = action.frame_range
- start_frame = int(framemin)
- end_frame = int(framemax)
- scene_range = range(start_frame, end_frame + 1)
- frame_count = len(scene_range)
+ framemin, framemax = action.frame_range
+ start_frame = int(framemin)
+ end_frame = int(framemax)
+ scene_range = range(start_frame, end_frame + 1)
+ frame_count = len(scene_range)
# create the AnimInfoBinary
- anim = AnimInfoBinary()
- anim.Name = action.name
- anim.Group = "" # unused?
- anim.NumRawFrames = frame_count
- anim.AnimRate = anim_rate
- anim.FirstRawFrame = raw_frame_index
+ anim = AnimInfoBinary()
+ anim.Name = action.name
+ anim.Group = "" # unused?
+ anim.NumRawFrames = frame_count
+ anim.AnimRate = anim_rate
+ anim.FirstRawFrame = raw_frame_index
print("{}, frames {} to {} ({} frames)".format(action.name, start_frame, end_frame, frame_count))
@@ -1479,7 +1582,7 @@ def parse_animation( armature, udk_bones, actions_to_export, psa ):
for pb in armature.pose.bones:
if b.name == pb.name:
udk_pose_bones.append(pb)
- break;
+ break
# sort in the order the bones appear in the PSA file
ordered_bones = {}
@@ -1493,7 +1596,7 @@ def parse_animation( armature, udk_bones, actions_to_export, psa ):
frame = scene_range[i]
- #verbose("FRAME {}".format(i), i) # test loop sampling
+ # verbose("FRAME {}".format(i), i) # test loop sampling
# advance to frame (automatically updates the pose)
context.scene.frame_set(frame)
@@ -1501,36 +1604,36 @@ def parse_animation( armature, udk_bones, actions_to_export, psa ):
# compute the key for each bone
for bone_data in ordered_bones:
- bone_index = bone_data[0]
- pose_bone = bone_data[1]
- pose_bone_matrix = mathutils.Matrix(pose_bone.matrix)
+ bone_index = bone_data[0]
+ pose_bone = bone_data[1]
+ pose_bone_matrix = mathutils.Matrix(pose_bone.matrix)
if pose_bone.parent is not None:
pose_bone_parent_matrix = mathutils.Matrix(pose_bone.parent.matrix)
- pose_bone_matrix = pose_bone_parent_matrix.inverted() * pose_bone_matrix
+ pose_bone_matrix = pose_bone_parent_matrix.inverted() * pose_bone_matrix
- head = pose_bone_matrix.to_translation()
- quat = pose_bone_matrix.to_quaternion().normalized()
+ head = pose_bone_matrix.to_translation()
+ quat = pose_bone_matrix.to_quaternion().normalized()
if pose_bone.parent is not None:
quat = make_fquat(quat)
else:
quat = make_fquat_default(quat)
- #scale animation position here?
+ # scale animation position here?
if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
head.x = head.x * bpy.context.scene.udk_option_scale
head.y = head.y * bpy.context.scene.udk_option_scale
head.z = head.z * bpy.context.scene.udk_option_scale
- vkey = VQuatAnimKey()
- vkey.Position.X = head.x
- vkey.Position.Y = head.y
- vkey.Position.Z = head.z
- vkey.Orientation = quat
+ vkey = VQuatAnimKey()
+ vkey.Position.X = head.x
+ vkey.Position.Y = head.y
+ vkey.Position.Z = head.z
+ vkey.Orientation = quat
# frame delta = 1.0 / fps
- vkey.Time = 1.0 / anim_rate # according to C++ header this is "disregarded"
+ vkey.Time = 1.0 / anim_rate # according to C++ header this is "disregarded"
psa.AddRawKey(vkey)
@@ -1540,8 +1643,10 @@ def parse_animation( armature, udk_bones, actions_to_export, psa ):
# END for i in range(frame_count)
- anim.TotalBones = len(ordered_bones) # REMOVED len(unique_bone_indexes)
- anim.TrackTime = float(frame_count) # frame_count/anim.AnimRate makes more sense, but this is what actually works in UDK
+ # REMOVED len(unique_bone_indexes)
+ anim.TotalBones = len(ordered_bones)
+ # frame_count/anim.AnimRate makes more sense, but this is what actually works in UDK
+ anim.TrackTime = float(frame_count)
verbose("anim.TotalBones={}, anim.TrackTime={}".format(anim.TotalBones, anim.TrackTime))
@@ -1553,52 +1658,54 @@ def parse_animation( armature, udk_bones, actions_to_export, psa ):
armature.animation_data.action = restoreAction
context.scene.frame_set(restoreFrame)
-#===========================================================================
+
+# ===========================================================================
# Collate actions to be exported
# Modify this to filter for one, some or all actions. For now use all.
# RETURNS list of actions
-#===========================================================================
+# ===========================================================================
def collate_actions():
verbose(header("collate_actions"))
actions_to_export = []
for action in bpy.data.actions:
- if bpy.context.scene.udk_option_selectanimations: # check if needed to select actions set for exporting it
+ if bpy.context.scene.udk_option_selectanimations: # check if needed to select actions set for exporting it
print("Action Set is selected!")
bready = False
- for actionlist in bpy.context.scene.udkas_list: #list the action set from the list
- if actionlist.name == action.name and actionlist.bmatch == True and actionlist.bexport == True:
+ for actionlist in bpy.context.scene.udkas_list: # list the action set from the list
+ if actionlist.name == action.name and actionlist.bmatch is True and actionlist.bexport is True:
bready = True
- print("Added Action Set:",action.name)
+ print("Added Action Set:", action.name)
break
- if bready == False:#don't export it
- print("Skipping Action Set:",action.name)
+ if bready is False: # don't export it
+ print("Skipping Action Set:", action.name)
continue
- verbose(" + {}".format(action.name)) #action set name
- actions_to_export.append(action) #add to the action array
+ verbose(" + {}".format(action.name)) # action set name
+ actions_to_export.append(action) # add to the action array
return actions_to_export
-#===========================================================================
+
+# ===========================================================================
# Locate the target armature and mesh for export
# RETURNS armature, mesh
-#===========================================================================
+# ===========================================================================
def find_armature_and_mesh():
verbose(header("find_armature_and_mesh", 'LEFT', '<', 60))
- context = bpy.context
- active_object = context.active_object
- armature = None
- mesh = None
+ context = bpy.context
+ active_object = context.active_object
+ armature = None
+ mesh = None
# TODO:
# this could be more intuitive
- #bpy.ops.object.mode_set(mode='OBJECT')
+ # bpy.ops.object.mode_set(mode='OBJECT')
- if bpy.context.scene.udk_option_selectobjects: #if checked select object true do list object on export
+ if bpy.context.scene.udk_option_selectobjects: # if checked select object true do list object on export
print("select mode:")
if len(bpy.context.scene.udkArm_list) > 0:
- print("Armature Name:",bpy.context.scene.udkArm_list[bpy.context.scene.udkArm_list_idx].name)
+ print("Armature Name:", bpy.context.scene.udkArm_list[bpy.context.scene.udkArm_list_idx].name)
for obj in bpy.context.scene.objects:
if obj.name == bpy.context.scene.udkArm_list[bpy.context.scene.udkArm_list_idx].name:
armature = obj
@@ -1606,21 +1713,22 @@ def find_armature_and_mesh():
else:
raise Error("There is no Armature in the list!")
meshselected = []
- #parented_meshes = [obj for obj in armature.children if obj.type == 'MESH']
+ # parented_meshes = [obj for obj in armature.children if obj.type == 'MESH']
meshes = [obj for obj in bpy.context.scene.objects if obj.type == 'MESH']
for obj in meshes:
- #print(dir(obj))
+ # print(dir(obj))
if obj.type == 'MESH':
bexportmesh = False
- #print("PARENT MESH:",obj.name)
+ # print("PARENT MESH:",obj.name)
for udkmeshlist in bpy.context.scene.udkmesh_list:
- if obj.name == udkmeshlist.name and udkmeshlist.bexport == True:
+ if obj.name == udkmeshlist.name and udkmeshlist.bexport is True:
bexportmesh = True
break
- if bexportmesh == True:
- print("Mesh Name:",obj.name," < SELECT TO EXPORT!")
+ if bexportmesh is True:
+ print("Mesh Name:", obj.name, " < SELECT TO EXPORT!")
meshselected.append(obj)
- print("MESH COUNT:",len(meshselected))
+
+ print("MESH COUNT:", len(meshselected))
# try the active object
if active_object and active_object.type == 'MESH' and len(meshselected) == 0:
if active_object.parent == armature:
@@ -1630,8 +1738,8 @@ def find_armature_and_mesh():
# otherwise, expect a single mesh parented to the armature (other object types are ignored)
else:
- print("Number of meshes:",len(meshes))
- print("Number of meshes (selected):",len(meshes))
+ print("Number of meshes:", len(meshes))
+ print("Number of meshes (selected):", len(meshes))
if len(meshes) == 1:
mesh = meshes[0]
@@ -1642,7 +1750,7 @@ def find_armature_and_mesh():
raise Error("More than one mesh(s) parented to armature. Select object(s)!")
else:
raise Error("No mesh parented to armature")
- else: #if not check for select function from the list work the code here
+ else: # if not check for select function from the list work the code here
print("normal mode:")
# try the active object
if active_object and active_object.type == 'ARMATURE':
@@ -1650,19 +1758,19 @@ def find_armature_and_mesh():
bpy.ops.object.mode_set(mode='OBJECT')
# otherwise, try for a single armature in the scene
else:
- #bpy.ops.object.mode_set(mode='OBJECT')
+ # bpy.ops.object.mode_set(mode='OBJECT')
all_armatures = [obj for obj in bpy.context.scene.objects if obj.type == 'ARMATURE']
- if len(all_armatures) == 1:#if armature has one scene just assign it
+ if len(all_armatures) == 1: # if armature has one scene just assign it
armature = all_armatures[0]
- elif len(all_armatures) > 1:#if there more armature then find the select armature
+ elif len(all_armatures) > 1: # if there more armature then find the select armature
barmselect = False
for _armobj in all_armatures:
if _armobj.select:
armature = _armobj
barmselect = True
break
- if barmselect == False:
+ if barmselect is False:
raise Error("Please select an armatures in the scene")
else:
raise Error("No armatures in scene")
@@ -1676,8 +1784,8 @@ def find_armature_and_mesh():
raise Error("The selected Armature has no mesh parented to the Armature Object!")
for obj in armature.children:
- #print(dir(obj))
- if obj.type == 'MESH' and obj.select == True:
+ # print(dir(obj))
+ if obj.type == 'MESH' and obj.select is True:
meshselected.append(obj)
# try the active object
if active_object and active_object.type == 'MESH' and len(meshselected) == 0:
@@ -1688,8 +1796,8 @@ def find_armature_and_mesh():
# otherwise, expect a single mesh parented to the armature (other object types are ignored)
else:
- print("Number of meshes:",len(parented_meshes))
- print("Number of meshes (selected):",len(meshselected))
+ print("Number of meshes:", len(parented_meshes))
+ print("Number of meshes (selected):", len(meshselected))
if len(parented_meshes) == 1:
mesh = parented_meshes[0]
@@ -1704,28 +1812,33 @@ def find_armature_and_mesh():
verbose("Found mesh: {}".format(mesh.name))
if mesh is None or armature is None:
raise Error("Check Mesh and Armature are list!")
- #if len(armature.pose.bones) == len(mesh.vertex_groups):
- #print("Armature and Mesh Vertex Groups matches Ok!")
- #else:
- #raise Error("Armature bones:" + str(len(armature.pose.bones)) + " Mesh Vertex Groups:" + str(len(mesh.vertex_groups)) +" doesn't match!")
- #this will check if object need to be rebuild.
+ """
+ if len(armature.pose.bones) == len(mesh.vertex_groups):
+ print("Armature and Mesh Vertex Groups matches Ok!")
+ else:
+ raise Error("Armature bones:" + str(len(armature.pose.bones)) +
+ " Mesh Vertex Groups:" + str(len(mesh.vertex_groups)) +" doesn't match!")
+ """
+ # this will check if object need to be rebuild
if bpy.context.scene.udk_option_rebuildobjects:
- #print("INIT... REBUILDING...")
+ # print("INIT... REBUILDING...")
print("REBUILDING ARMATURE...")
- #if deform mesh
- armature = rebuildarmature(armature) #rebuild the armature to raw . If there IK constraint it will ignore it.
+ # if deform mesh
+ # rebuild the armature to raw. If there IK constraint it will ignore it
+ armature = rebuildarmature(armature)
print("REBUILDING MESH...")
- mesh = rebuildmesh(mesh) #rebuild the mesh to raw data format.
+ mesh = rebuildmesh(mesh) # rebuild the mesh to raw data format.
return armature, mesh
-#===========================================================================
+
+# ===========================================================================
# Returns a list of vertex groups in the mesh. Can be modified to filter
# groups as necessary.
# UNUSED
-#===========================================================================
-def collate_vertex_groups( mesh ):
+# ===========================================================================
+def collate_vertex_groups(mesh):
verbose("collate_vertex_groups")
groups = []
@@ -1736,13 +1849,14 @@ def collate_vertex_groups( mesh ):
return groups
-#===========================================================================
+
+# ===========================================================================
# Main
-#===========================================================================
+# ===========================================================================
def export(filepath):
print(header("Export", 'RIGHT'))
- bpy.types.Scene.udk_copy_merge = False #in case fail to export set this to default
- t = time.clock()
+ bpy.types.Scene.udk_copy_merge = False # in case fail to export set this to default
+ t = time.clock()
context = bpy.context
print("Blender Version {}.{}.{}".format(bpy.app.version[0], bpy.app.version[1], bpy.app.version[2]))
@@ -1778,7 +1892,7 @@ def export(filepath):
udk_bones = parse_armature(udk_armature, psk, psa)
# step 3
- if context.scene.udk_option_export_psa == True:
+ if context.scene.udk_option_export_psa is True:
actions = collate_actions()
parse_animation(udk_armature, udk_bones, actions, psa)
@@ -1788,7 +1902,7 @@ def export(filepath):
psk_filename = filepath + '.psk'
psa_filename = filepath + '.psa'
- if context.scene.udk_option_export_psk == True:
+ if context.scene.udk_option_export_psk is True:
print("Skeletal mesh data...")
psk.PrintOut()
file = open(psk_filename, "wb")
@@ -1797,7 +1911,7 @@ def export(filepath):
print("Exported: " + psk_filename)
print()
- if context.scene.udk_option_export_psa == True:
+ if context.scene.udk_option_export_psa is True:
print("Animation data...")
if not psa.IsEmpty():
psa.PrintOut()
@@ -1810,27 +1924,27 @@ def export(filepath):
print()
- #if objects are rebuild do the unlink
+ # if objects are rebuild do the unlink
if bpy.context.scene.udk_option_rebuildobjects:
print("Unlinking Objects")
- print("Armature Object Name:",udk_armature.name) #display object name
- bpy.context.scene.objects.unlink(udk_armature) #remove armature from the scene
- print("Mesh Object Name:",udk_mesh.name) #display object name
- bpy.context.scene.objects.unlink(udk_mesh) #remove mesh from the scene
+ print("Armature Object Name:", udk_armature.name) # display object name
+ bpy.context.scene.objects.unlink(udk_armature) # remove armature from the scene
+ print("Mesh Object Name:", udk_mesh.name) # display object name
+ bpy.context.scene.objects.unlink(udk_mesh) # remove mesh from the scene
print("Export completed in {:.2f} seconds".format((time.clock() - t)))
-#===========================================================================
+
+# ===========================================================================
# Operator
-#===========================================================================
-class Operator_UDKExport( bpy.types.Operator ):
+# ===========================================================================
+class Operator_UDKExport(Operator):
"""Export to UDK"""
- bl_idname = "object.udk_export"
- bl_label = "Export now"
+ bl_idname = "object.udk_export"
+ bl_label = "Export now"
def execute(self, context):
- print( "\n"*8 )
-
+ print("\n" * 8)
scene = bpy.context.scene
scene.udk_option_export_psk = (scene.udk_option_export == '0' or scene.udk_option_export == '2')
@@ -1840,8 +1954,7 @@ class Operator_UDKExport( bpy.types.Operator ):
# cache settings
restore_frame = scene.frame_current
-
- message = "Finish Export!"
+ message = "Object(s) exported to: {}".format(filepath)
try:
export(filepath)
@@ -1852,144 +1965,80 @@ class Operator_UDKExport( bpy.types.Operator ):
# restore settings
scene.frame_set(restore_frame)
- self.report({'ERROR'}, message)
+ def draw(self, context):
+ self.layout.label(text="Export Finished")
+ try:
+ context.window_manager.popup_menu(draw, title=message, icon="INFO")
+ except:
+ pass
+
+ self.report({'INFO'}, message)
# restore settings
scene.frame_set(restore_frame)
return {'FINISHED'}
-#===========================================================================
+
+# ===========================================================================
# Operator
-#===========================================================================
-class Operator_ToggleConsole( bpy.types.Operator ):
+# ===========================================================================
+class Operator_ToggleConsole(Operator):
"""Show or hide the console"""
- bl_idname = "object.toggle_console"
- bl_label = "Toggle console"
+ bl_idname = "object.toggle_console"
+ bl_label = "Toggle console"
- #def invoke(self, context, event):
- # bpy.ops.wm.console_toggle()
- # return{'FINISHED'}
def execute(self, context):
bpy.ops.wm.console_toggle()
return {'FINISHED'}
-#===========================================================================
+
+# ===========================================================================
# Get filepath for export
-#===========================================================================
+# ===========================================================================
def get_dst_path():
if bpy.context.scene.udk_option_filename_src == '0':
if bpy.context.active_object:
- path = os.path.split(bpy.data.filepath)[0] + "\\" + bpy.context.active_object.name# + ".psk"
+ path = os.path.split(bpy.data.filepath)[0] + "\\" + bpy.context.active_object.name # + ".psk"
else:
- #path = os.path.split(bpy.data.filepath)[0] + "\\" + "Unknown";
- path = os.path.splitext(bpy.data.filepath)[0]# + ".psk"
+ # path = os.path.split(bpy.data.filepath)[0] + "\\" + "Unknown";
+ path = os.path.splitext(bpy.data.filepath)[0] # + ".psk"
else:
- path = os.path.splitext(bpy.data.filepath)[0]# + ".psk"
+ path = os.path.splitext(bpy.data.filepath)[0] # + ".psk"
return path
-#Added by [MGVS]
-bpy.types.Scene.udk_option_filename_src = EnumProperty(
- name = "Filename",
- description = "Sets the name for the files",
- items = [ ('0', "From object", "Name will be taken from object name"),
- ('1', "From Blend", "Name will be taken from .blend file name") ],
- default = '0')
-
-bpy.types.Scene.udk_option_export_psk = BoolProperty(
- name = "bool export psa",
- description = "Boolean for exporting psk format (Skeleton Mesh)",
- default = True)
-
-bpy.types.Scene.udk_option_export_psa = BoolProperty(
- name = "bool export psa",
- description = "Boolean for exporting psa format (Animation Data)",
- default = True)
-
-bpy.types.Scene.udk_option_clamp_uv = BoolProperty(
- name = "Clamp UV",
- description = "True is to limit Clamp UV co-ordinates to [0-1]. False is unrestricted (x,y). ",
- default = False)
-
-bpy.types.Scene.udk_copy_merge = BoolProperty(
- name = "Merge Mesh",
- description = "This will copy the mesh(s) and merge the object together and unlink the mesh to be remove while exporting the object",
- default = False)
-
-bpy.types.Scene.udk_option_export = EnumProperty(
- name = "Export",
- description = "What to export",
- items = [ ('0', "Mesh only", "Exports the PSK file for the Skeletal Mesh"),
- ('1', "Animation only", "Export the PSA file for Action Set(s)(Animations Data)"),
- ('2', "Mesh & Animation", "Export both PSK and PSA files(Skeletal Mesh/Animation(s) Data)") ],
- default = '2')
-
-bpy.types.Scene.udk_option_verbose = BoolProperty(
- name = "Verbose",
- description = "Verbose console output",
- default = False)
-
-bpy.types.Scene.udk_option_smoothing_groups = BoolProperty(
- name = "Smooth Groups",
- description = "Activate hard edges as smooth groups",
- default = True)
-
-bpy.types.Scene.udk_option_triangulate = BoolProperty(
- name = "Triangulate Mesh",
- description = "Convert Quads to Triangles",
- default = False)
-
-bpy.types.Scene.udk_option_selectanimations = BoolProperty(
- name = "Select Animation(s)",
- description = "Select animation(s) for export to psa file",
- default = False)
-
-bpy.types.Scene.udk_option_selectobjects = BoolProperty(
- name = "Select Object(s)",
- description = "Select Armature and Mesh(s). Just make sure mesh(s) is parent to armature",
- default = False)
-
-bpy.types.Scene.udk_option_rebuildobjects = BoolProperty(
- name = "Rebuild Objects",
- description = "In case of deform skeleton mesh and animations data - This will rebuild objects from raw format on export when checked",
- default = False)
-
-bpy.types.Scene.udk_option_ignoreactiongroupnames = BoolProperty(
- name = "Ignore Action Group Names",
- description = "This will Ignore Action Set Group Names Check With Armature Bones. It will override armature to set action set",
- default = False)
-
-bpy.types.Scene.udk_option_scale = FloatProperty(
- name = "UDK Scale",
- description = "In case you don't want to scale objects manually - This will just scale position when on export for the skeleton mesh and animation data",
- default = 1)
-
-#===========================================================================
+
+# ===========================================================================
# User interface
-#===========================================================================
-class OBJECT_OT_UTSelectedFaceSmooth(bpy.types.Operator):
+# ===========================================================================
+class OBJECT_OT_UTSelectedFaceSmooth(Operator):
"""It will only select smooth faces that is select mesh"""
bl_idname = "object.utselectfacesmooth" # XXX, name???
- bl_label = "Select Smooth Faces"#"Select Smooth faces"
+ bl_label = "Select Smooth Faces" # "Select Smooth faces"
def invoke(self, context, event):
print("----------------------------------------")
print("Init Select Face(s):")
bselected = False
for obj in bpy.data.objects:
- if obj.type == 'MESH' and obj.select == True:
+ if obj.type == 'MESH' and obj.select is True:
smoothcount = 0
flatcount = 0
- bpy.ops.object.mode_set(mode='OBJECT')#it need to go into object mode to able to select the faces
- for i in bpy.context.scene.objects: i.select = False #deselect all objects
- obj.select = True #set current object select
- bpy.context.scene.objects.active = obj #set active object
- mesh = bmesh.new();
+ bpy.ops.object.mode_set(mode='OBJECT') # it need to go into object mode to able to select the faces
+
+ for i in bpy.context.scene.objects:
+ i.select = False # deselect all objects
+
+ obj.select = True # set current object select
+ bpy.context.scene.objects.active = obj # set active object
+ mesh = bmesh.new()
mesh.from_mesh(obj.data)
+
for face in mesh.faces:
face.select = False
+
for face in mesh.faces:
- if face.smooth == True:
+ if face.smooth is True:
face.select = True
smoothcount += 1
else:
@@ -1998,173 +2047,195 @@ class OBJECT_OT_UTSelectedFaceSmooth(bpy.types.Operator):
mesh.to_mesh(obj.data)
bpy.context.scene.update()
bpy.ops.object.mode_set(mode='EDIT')
- print("Select Smooth Count(s):",smoothcount," Flat Count(s):",flatcount)
+ print("Select Smooth Count(s):", smoothcount, " Flat Count(s):", flatcount)
bselected = True
break
if bselected:
- print("Selected Face(s) Exectue!")
- self.report({'INFO'}, "Selected Face(s) Exectue!")
+ self.report({'INFO'}, "Selected Face(s) Executed")
else:
- print("Didn't select Mesh Object!")
- self.report({'INFO'}, "Didn't Select Mesh Object!")
+ self.report({'INFO'}, "Mesh Object is not selected")
print("----------------------------------------")
+
return{'FINISHED'}
-class OBJECT_OT_MeshClearWeights(bpy.types.Operator):
+
+class OBJECT_OT_MeshClearWeights(Operator):
"""Remove all mesh vertex groups weights for the bones"""
bl_idname = "object.meshclearweights" # XXX, name???
- bl_label = "Remove Vertex Weights"#"Remove Mesh vertex weights"
+ bl_label = "Remove Vertex Weights" # "Remove Mesh vertex weights"
def invoke(self, context, event):
for obj in bpy.data.objects:
- if obj.type == 'MESH' and obj.select == True:
+ if obj.type == 'MESH' and obj.select is True:
for vg in obj.vertex_groups:
obj.vertex_groups.remove(vg)
- self.report({'INFO'}, "Mesh Vertex Groups Remove!")
+ self.report({'INFO'}, "Mesh Vertex Groups Removed")
break
return{'FINISHED'}
+
def unpack_list(list_of_tuples):
l = []
for t in list_of_tuples:
l.extend(t)
return l
+
def rebuildmesh(obj):
- #make sure it in object mode
- print("Mesh Object Name:",obj.name)
+ # make sure it in object mode
+ print("Mesh Object Name:", obj.name)
bpy.ops.object.mode_set(mode='OBJECT')
- for i in bpy.context.scene.objects: i.select = False #deselect all objects
+
+ for i in bpy.context.scene.objects:
+ i.select = False # deselect all objects
obj.select = True
bpy.context.scene.objects.active = obj
- me_ob = bpy.data.meshes.new(("Re_"+obj.name))
+ me_ob = bpy.data.meshes.new(("Re_" + obj.name))
mesh = obj.data
faces = []
verts = []
smoothings = []
uvfaces = []
- #print("creating array build mesh...")
- mmesh = obj.to_mesh(bpy.context.scene,True,'PREVIEW')
+ # print("creating array build mesh...")
+ mmesh = obj.to_mesh(bpy.context.scene, True, 'PREVIEW')
uv_layer = mmesh.tessface_uv_textures.active
+
for face in mmesh.tessfaces:
- smoothings.append(face.use_smooth)#smooth or flat in boolean
- if uv_layer is not None:#check if there texture data exist
+ smoothings.append(face.use_smooth) # smooth or flat in boolean
+ if uv_layer is not None: # check if there texture data exist
faceUV = uv_layer.data[face.index]
uvs = []
for uv in faceUV.uv:
- uvs.append((uv[0],uv[1]))
+ uvs.append((uv[0], uv[1]))
uvfaces.append(uvs)
- #print((face.vertices[:]))
+ # print((face.vertices[:]))
if len(face.vertices) == 3:
- faces.extend([(face.vertices[0],face.vertices[1],face.vertices[2],0)])
+ faces.extend([(face.vertices[0], face.vertices[1], face.vertices[2], 0)])
else:
- faces.extend([(face.vertices[0],face.vertices[1],face.vertices[2],face.vertices[3])])
- #vertex positions
+ faces.extend([(face.vertices[0], face.vertices[1], face.vertices[2], face.vertices[3])])
+
+ # vertex positions
for vertex in mesh.vertices:
verts.append(vertex.co.to_tuple())
- #vertices weight groups into array
- vertGroups = {} #array in strings
+ # vertices weight groups into array
+ vertGroups = {} # array in strings
+
for vgroup in obj.vertex_groups:
vlist = []
for v in mesh.vertices:
for vg in v.groups:
if vg.group == vgroup.index:
- vlist.append((v.index,vg.weight))
- #print((v.index,vg.weight))
+ vlist.append((v.index, vg.weight))
+ # print((v.index,vg.weight))
vertGroups[vgroup.name] = vlist
- #print("creating mesh object...")
- #me_ob.from_pydata(verts, [], faces)
+ # print("creating mesh object...")
+ # me_ob.from_pydata(verts, [], faces)
me_ob.vertices.add(len(verts))
me_ob.tessfaces.add(len(faces))
me_ob.vertices.foreach_set("co", unpack_list(verts))
- me_ob.tessfaces.foreach_set("vertices_raw",unpack_list( faces))
- me_ob.tessfaces.foreach_set("use_smooth", smoothings)#smooth array from face
+ me_ob.tessfaces.foreach_set("vertices_raw", unpack_list(faces))
+ me_ob.tessfaces.foreach_set("use_smooth", smoothings) # smooth array from face
- #check if there is uv faces
+ # check if there is uv faces
if len(uvfaces) > 0:
uvtex = me_ob.tessface_uv_textures.new(name="retex")
for i, face in enumerate(me_ob.tessfaces):
- blender_tface = uvtex.data[i] #face
+ blender_tface = uvtex.data[i] # face
mfaceuv = uvfaces[i]
if len(mfaceuv) == 3:
- blender_tface.uv1 = mfaceuv[0];
- blender_tface.uv2 = mfaceuv[1];
- blender_tface.uv3 = mfaceuv[2];
+ blender_tface.uv1 = mfaceuv[0]
+ blender_tface.uv2 = mfaceuv[1]
+ blender_tface.uv3 = mfaceuv[2]
if len(mfaceuv) == 4:
- blender_tface.uv1 = mfaceuv[0];
- blender_tface.uv2 = mfaceuv[1];
- blender_tface.uv3 = mfaceuv[2];
- blender_tface.uv4 = mfaceuv[3];
+ blender_tface.uv1 = mfaceuv[0]
+ blender_tface.uv2 = mfaceuv[1]
+ blender_tface.uv3 = mfaceuv[2]
+ blender_tface.uv4 = mfaceuv[3]
- me_ob.update()#need to update the information to able to see into the secne
- obmesh = bpy.data.objects.new(("Re_"+obj.name),me_ob)
+ me_ob.update() # need to update the information to able to see into the secne
+ obmesh = bpy.data.objects.new(("Re_" + obj.name), me_ob)
bpy.context.scene.update()
- #Build tmp materials
+
+ # Build tmp materials
materialname = "ReMaterial"
for matcount in mesh.materials:
matdata = bpy.data.materials.new(materialname)
me_ob.materials.append(matdata)
- #assign face to material id
+
+ # assign face to material id
for face in mesh.tessfaces:
me_ob.faces[face.index].material_index = face.material_index
- #vertices weight groups
+
+ # vertices weight groups
for vgroup in vertGroups:
group = obmesh.vertex_groups.new(vgroup)
for v in vertGroups[vgroup]:
- group.add([v[0]], v[1], 'ADD')# group.add(array[vertex id],weight,add)
+ group.add([v[0]], v[1], 'ADD') # group.add(array[vertex id],weight,add)
bpy.context.scene.objects.link(obmesh)
- #print("Mesh Material Count:",len(me_ob.materials))
+ # print("Mesh Material Count:",len(me_ob.materials))
matcount = 0
- #print("MATERIAL ID OREDER:")
+ # print("MATERIAL ID OREDER:")
for mat in me_ob.materials:
- #print("-Material:",mat.name,"INDEX:",matcount)
+ # print("-Material:",mat.name,"INDEX:",matcount)
matcount += 1
- print("Mesh Object Name:",obmesh.name)
+
+ print("Mesh Object Name:", obmesh.name)
bpy.context.scene.update()
+
return obmesh
-class OBJECT_OT_UTRebuildMesh(bpy.types.Operator):
+
+class OBJECT_OT_UTRebuildMesh(Operator):
"""It rebuild the mesh from scrape from the selected mesh object. """ \
"""Note the scale will be 1:1 for object mode. To keep from deforming"""
bl_idname = "object.utrebuildmesh" # XXX, name???
- bl_label = "Rebuild Mesh"#"Rebuild Mesh"
+ bl_label = "Rebuild Mesh" # "Rebuild Mesh"
def invoke(self, context, event):
print("----------------------------------------")
print("Init Mesh Bebuild...")
bselected = False
bpy.ops.object.mode_set(mode='OBJECT')
+
for obj in bpy.data.objects:
- if obj.type == 'MESH' and obj.select == True:
+ if obj.type == 'MESH' and obj.select is True:
rebuildmesh(obj)
- self.report({'INFO'}, "Rebuild Mesh Finish!")
+
+ self.report({'INFO'}, "Rebuild Mesh Finished!")
print("Finish Mesh Build...")
print("----------------------------------------")
return{'FINISHED'}
+
def rebuildarmature(obj):
- currentbone = [] #select armature for roll copy
- print("Armature Name:",obj.name)
+ currentbone = [] # select armature for roll copy
+ print("Armature Name:", obj.name)
objectname = "ArmatureDataPSK"
- meshname ="ArmatureObjectPSK"
+ meshname = "ArmatureObjectPSK"
armdata = bpy.data.armatures.new(objectname)
ob_new = bpy.data.objects.new(meshname, 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
+ # bpy.ops.object.mode_set(mode='OBJECT')
+
+ for i in bpy.context.scene.objects:
+ i.select = False # deselect all objects
+
ob_new.select = True
bpy.context.scene.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
for bone in obj.data.edit_bones:
if bone.parent is not None:
- currentbone.append([bone.name,bone.roll])
+ currentbone.append([bone.name, bone.roll])
else:
- currentbone.append([bone.name,bone.roll])
+ currentbone.append([bone.name, bone.roll])
bpy.ops.object.mode_set(mode='OBJECT')
- for i in bpy.context.scene.objects: i.select = False #deselect all objects
+
+ for i in bpy.context.scene.objects:
+ i.select = False # deselect all objects
+
bpy.context.scene.objects.active = ob_new
bpy.ops.object.mode_set(mode='EDIT')
@@ -2181,135 +2252,185 @@ def rebuildarmature(obj):
parentbone = ob_new.data.edit_bones[bone.parent.name]
newbone.parent = parentbone
- ob_new.animation_data_create()#create animation data
- if obj.animation_data is not None:#check for animation
- ob_new.animation_data.action = obj.animation_data.action #just make sure it here to do the animations if exist
- print("Armature Object Name:",ob_new.name)
+ ob_new.animation_data_create() # create animation data
+ if obj.animation_data is not None: # check for animation
+ # just make sure it here to do the animations if exist
+ ob_new.animation_data.action = obj.animation_data.action
+
+ print("Armature Object Name:", ob_new.name)
return ob_new
-class OBJECT_OT_UTRebuildArmature(bpy.types.Operator):
+
+class OBJECT_OT_UTRebuildArmature(Operator):
"""If mesh is deform when importing to unreal engine try this. """ \
"""It rebuild the bones one at the time by select one armature object scrape to raw setup build. """ \
"""Note the scale will be 1:1 for object mode. To keep from deforming"""
bl_idname = "object.utrebuildarmature" # XXX, name???
- bl_label = "Rebuild Armature" #Rebuild Armature
+ bl_label = "Rebuild Armature" # Rebuild Armature
def invoke(self, context, event):
print("----------------------------------------")
print("Init Rebuild Armature...")
bselected = False
for obj in bpy.data.objects:
- if obj.type == 'ARMATURE' and obj.select == True:
+ if obj.type == 'ARMATURE' and obj.select is True:
rebuildarmature(obj)
self.report({'INFO'}, "Rebuild Armature Finish!")
print("End of Rebuild Armature.")
print("----------------------------------------")
return{'FINISHED'}
-class UDKActionSetListPG(bpy.types.PropertyGroup):
- bool = BoolProperty(default=False)
- string = StringProperty()
- actionname = StringProperty()
- bmatch = BoolProperty(default=False,name="Match", options={"HIDDEN"},description = "This check against bone names and action group names matches and override boolean if true")
- bexport = BoolProperty(default=False,name="Export",description = "Check this to export the animation")
-bpy.utils.register_class(UDKActionSetListPG)
-bpy.types.Scene.udkas_list = CollectionProperty(type=UDKActionSetListPG)
-bpy.types.Scene.udkas_list_idx = IntProperty()
+class UDKActionSetListPG(PropertyGroup):
+ bool = BoolProperty(default=False)
+ string = StringProperty()
+ actionname = StringProperty()
+ bmatch = BoolProperty(
+ default=False,
+ name="Match",
+ options={"HIDDEN"},
+ description="This check against bone names and action group "
+ "names matches and override boolean if true"
+ )
+ bexport = BoolProperty(
+ default=False,
+ name="Export",
+ description="Check this to export the animation"
+ )
+
-class UL_UDKActionSetList(bpy.types.UIList):
+class UL_UDKActionSetList(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.label(item.name)
layout.prop(item, "bmatch", text="Match")
layout.prop(item, "bexport", text="Export")
-class UDKObjListPG(bpy.types.PropertyGroup):
- bool = BoolProperty(default=False)
- string = StringProperty()
- bexport = BoolProperty(default=False,name="Export", options={"HIDDEN"},description = "This will be ignore when exported")
- bselect = BoolProperty(default=False,name="Select", options={"HIDDEN"},description = "This will be ignore when exported")
- otype = StringProperty(name="Type",description = "This will be ignore when exported")
-bpy.utils.register_class(UDKObjListPG)
-bpy.types.Scene.udkobj_list = CollectionProperty(type=UDKObjListPG)
-bpy.types.Scene.udkobj_list_idx = IntProperty()
+class UDKObjListPG(PropertyGroup):
+ bool = BoolProperty(default=False)
+ string = StringProperty()
+ bexport = BoolProperty(
+ default=False,
+ name="Export",
+ options={"HIDDEN"},
+ description="This will be ignore when exported"
+ )
+ bselect = BoolProperty(
+ default=False,
+ name="Select",
+ options={"HIDDEN"},
+ description="This will be ignore when exported"
+ )
+ otype = StringProperty(
+ name="Type",
+ description="This will be ignore when exported"
+ )
-class UL_UDKObjList(bpy.types.UIList):
+
+class UL_UDKObjList(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.label(item.name)
layout.prop(item, "otype", text="")
layout.prop(item, "bselect", text="")
-class UDKMeshListPG(bpy.types.PropertyGroup):
- bool = BoolProperty(default=False)
- string = StringProperty()
- bexport = BoolProperty(default=False,name="Export", options={"HIDDEN"},description = "This object will be export when true")
- bselect = BoolProperty(default=False,name="Select", options={"HIDDEN"},description = "Make sure you have Mesh is parent to Armature")
- otype = StringProperty(name="Type",description = "This will be ignore when exported")
-bpy.utils.register_class(UDKMeshListPG)
-bpy.types.Scene.udkmesh_list = CollectionProperty(type=UDKMeshListPG)
-bpy.types.Scene.udkmesh_list_idx = IntProperty()
+class UDKMeshListPG(PropertyGroup):
+ bool = BoolProperty(
+ default=False
+ )
+ string = StringProperty()
+ bexport = BoolProperty(
+ default=False,
+ name="Export",
+ options={"HIDDEN"},
+ description="This object will be export when true"
+ )
+ bselect = BoolProperty(
+ default=False,
+ name="Select",
+ options={"HIDDEN"},
+ description="Make sure you have Mesh is parent to Armature"
+ )
+ otype = StringProperty(
+ name="Type",
+ description="This will be ignore when exported"
+ )
+
-class UL_UDKMeshList(bpy.types.UIList):
+class UL_UDKMeshList(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.label(item.name)
- #layout.prop(item, "bselect", text="Select")
+ # layout.prop(item, "bselect", text="Select")
layout.prop(item, "bexport", text="Export")
-class UDKArmListPG(bpy.types.PropertyGroup):
- bool = BoolProperty(default=False)
- string = StringProperty()
- bexport = BoolProperty(default=False,name="Export", options={"HIDDEN"},description = "This will be ignore when exported")
- bselect = BoolProperty(default=False,name="Select", options={"HIDDEN"},description = "This will be ignore when exported")
- otype = StringProperty(name="Type",description = "This will be ignore when exported")
-bpy.utils.register_class(UDKArmListPG)
-bpy.types.Scene.udkArm_list = CollectionProperty(type=UDKArmListPG)
-bpy.types.Scene.udkArm_list_idx = IntProperty()
+class UDKArmListPG(PropertyGroup):
+ bool = BoolProperty(default=False)
+ string = StringProperty()
+ bexport = BoolProperty(
+ default=False,
+ name="Export",
+ options={"HIDDEN"},
+ description="This will be ignore when exported"
+ )
+ bselect = BoolProperty(
+ default=False,
+ name="Select",
+ options={"HIDDEN"},
+ description="This will be ignore when exported"
+ )
+ otype = StringProperty(
+ name="Type",
+ description="This will be ignore when exported"
+ )
+
-class UL_UDKArmList(bpy.types.UIList):
+class UL_UDKArmList(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.label(item.name)
-class Panel_UDKExport( bpy.types.Panel ):
- bl_label = "UDK Export"
- bl_idname = "OBJECT_PT_udk_tools"
- bl_category = "File I/O"
- bl_space_type = "VIEW_3D"
- bl_region_type = "TOOLS"
+class Panel_UDKExport(Panel):
+ bl_label = "UDK Export"
+ bl_idname = "OBJECT_PT_udk_tools"
+ bl_category = "File I/O"
+ bl_space_type = "VIEW_3D"
+ bl_region_type = "TOOLS"
bl_context = "objectmode"
- #def draw_header(self, context):
- # layout = self.layout
- #obj = context.object
- #layout.prop(obj, "select", text="")
+ """
+ def draw_header(self, context):
+ layout = self.layout
+ obj = context.object
+ layout.prop(obj, "select", text="")
- #@classmethod
- #def poll(cls, context):
- # return context.active_object
+ @classmethod
+ def poll(cls, context):
+ return context.active_object
+ """
def draw(self, context):
layout = self.layout
path = get_dst_path()
object_name = ""
- #if context.object:
- # object_name = context.object.name
+ """
+ if context.object:
+ object_name = context.object.name
+ """
if context.active_object:
object_name = context.active_object.name
row10 = layout.row()
row10.prop(context.scene, "udk_option_smoothing_groups")
row10.prop(context.scene, "udk_option_clamp_uv")
row10.prop(context.scene, "udk_option_verbose")
+
row = layout.row()
row.label(text="Active object: " + object_name)
- #layout.separator()
layout.prop(context.scene, "udk_option_filename_src")
row = layout.row()
row.label(text=path)
- #layout.separator()
+
layout.prop(context.scene, "udk_option_export")
layout.prop(context.scene, "udk_option_selectobjects")
@@ -2322,15 +2443,17 @@ class Panel_UDKExport( bpy.types.Panel ):
layout.template_list("UL_UDKMeshList", "", context.scene, "udkmesh_list",
context.scene, "udkmesh_list_idx", rows=5)
layout.prop(context.scene, "udk_option_selectanimations")
+
if context.scene.udk_option_selectanimations:
layout.operator("action.setanimupdate")
layout.label(text="Action Set(s) - Match / Export")
layout.template_list("UL_UDKActionSetList", "", context.scene, "udkas_list",
context.scene, "udkas_list_idx", rows=5)
- test = layout.separator()
+ layout.separator()
layout.prop(context.scene, "udk_option_scale")
layout.prop(context.scene, "udk_option_rebuildobjects")
- #layout.prop(context.scene, "udk_option_ignoreactiongroupnames")
+ # layout.prop(context.scene, "udk_option_ignoreactiongroupnames")
+
row11 = layout.row()
row11.operator("object.udk_export")
row11.operator("object.toggle_console")
@@ -2341,79 +2464,85 @@ class Panel_UDKExport( bpy.types.Panel ):
layout.operator(OBJECT_OT_UTRebuildMesh.bl_idname)
layout.operator(OBJECT_OT_UDKCheckMeshLines.bl_idname)
+
def udkupdateobjects():
- my_objlist = bpy.context.scene.udkArm_list
- objectl = []
- for objarm in bpy.context.scene.objects:#list and filter only mesh and armature
- if objarm.type == 'ARMATURE':
- objectl.append(objarm)
- for _objd in objectl:#check if list has in udk list
- bfound_obj = False
- for _obj in my_objlist:
- if _obj.name == _objd.name and _obj.otype == _objd.type:
- _obj.bselect = _objd.select
- bfound_obj = True
- break
- if bfound_obj == False:
- #print("ADD ARMATURE...")
- my_item = my_objlist.add()
- my_item.name = _objd.name
- my_item.bselect = _objd.select
- my_item.otype = _objd.type
- removeobject = []
- for _udkobj in my_objlist:
- bfound_objv = False
- for _objd in bpy.context.scene.objects: #check if there no existing object from sense to remove it
- if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
- bfound_objv = True
- break
- if bfound_objv == False:
- removeobject.append(_udkobj)
- #print("remove check...")
- for _item in removeobject: #loop remove object from udk list object
- count = 0
- for _obj in my_objlist:
- if _obj.name == _item.name and _obj.otype == _item.otype:
- my_objlist.remove(count)
- break
- count += 1
-
- my_objlist = bpy.context.scene.udkmesh_list
- objectl = []
- for objarm in bpy.context.scene.objects:#list and filter only mesh and armature
- if objarm.type == 'MESH':
- objectl.append(objarm)
- for _objd in objectl:#check if list has in udk list
- bfound_obj = False
- for _obj in my_objlist:
- if _obj.name == _objd.name and _obj.otype == _objd.type:
- _obj.bselect = _objd.select
- bfound_obj = True
- break
- if bfound_obj == False:
- my_item = my_objlist.add()
- my_item.name = _objd.name
- my_item.bselect = _objd.select
- my_item.otype = _objd.type
- removeobject = []
- for _udkobj in my_objlist:
- bfound_objv = False
- for _objd in bpy.context.scene.objects: #check if there no existing object from sense to remove it
- if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
- bfound_objv = True
- break
- if bfound_objv == False:
- removeobject.append(_udkobj)
- #print("remove check...")
- for _item in removeobject: #loop remove object from udk list object
- count = 0
- for _obj in my_objlist:
- if _obj.name == _item.name and _obj.otype == _item.otype:
- my_objlist.remove(count)
- break
- count += 1
+ my_objlist = bpy.context.scene.udkArm_list
+ objectl = []
+ for objarm in bpy.context.scene.objects: # list and filter only mesh and armature
+ if objarm.type == 'ARMATURE':
+ objectl.append(objarm)
+
+ for _objd in objectl: # check if list has in udk list
+ bfound_obj = False
+ for _obj in my_objlist:
+ if _obj.name == _objd.name and _obj.otype == _objd.type:
+ _obj.bselect = _objd.select
+ bfound_obj = True
+ break
+
+ if bfound_obj is False:
+ # print("ADD ARMATURE...")
+ my_item = my_objlist.add()
+ my_item.name = _objd.name
+ my_item.bselect = _objd.select
+ my_item.otype = _objd.type
+ removeobject = []
+ for _udkobj in my_objlist:
+ bfound_objv = False
+
+ for _objd in bpy.context.scene.objects: # check if there no existing object from sense to remove it
+ if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
+ bfound_objv = True
+ break
-class OBJECT_OT_UDKObjUpdate(bpy.types.Operator):
+ if bfound_objv is False:
+ removeobject.append(_udkobj)
+ # print("remove check...")
+ for _item in removeobject: # loop remove object from udk list object
+ count = 0
+ for _obj in my_objlist:
+ if _obj.name == _item.name and _obj.otype == _item.otype:
+ my_objlist.remove(count)
+ break
+ count += 1
+
+ my_objlist = bpy.context.scene.udkmesh_list
+ objectl = []
+ for objarm in bpy.context.scene.objects: # list and filter only mesh and armature
+ if objarm.type == 'MESH':
+ objectl.append(objarm)
+ for _objd in objectl: # check if list has in udk list
+ bfound_obj = False
+ for _obj in my_objlist:
+ if _obj.name == _objd.name and _obj.otype == _objd.type:
+ _obj.bselect = _objd.select
+ bfound_obj = True
+ break
+ if bfound_obj is False:
+ my_item = my_objlist.add()
+ my_item.name = _objd.name
+ my_item.bselect = _objd.select
+ my_item.otype = _objd.type
+ removeobject = []
+ for _udkobj in my_objlist:
+ bfound_objv = False
+ for _objd in bpy.context.scene.objects: # check if there no existing object from sense to remove it
+ if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
+ bfound_objv = True
+ break
+ if bfound_objv is False:
+ removeobject.append(_udkobj)
+ # print("remove check...")
+ for _item in removeobject: # loop remove object from udk list object
+ count = 0
+ for _obj in my_objlist:
+ if _obj.name == _item.name and _obj.otype == _item.otype:
+ my_objlist.remove(count)
+ break
+ count += 1
+
+
+class OBJECT_OT_UDKObjUpdate(Operator):
"""This will update the filter of the mesh and armature"""
bl_idname = "object.selobjectpdate"
bl_label = "Update Object(s)"
@@ -2424,21 +2553,26 @@ class OBJECT_OT_UDKObjUpdate(bpy.types.Operator):
udkupdateobjects()
return{'FINISHED'}
+
def udkcheckmeshline():
objmesh = None
for obj in bpy.context.scene.objects:
- if obj.type == 'MESH' and obj.select == True:
+ if obj.type == 'MESH' and obj.select is True:
objmesh = obj
- objmesh = triangulate_mesh(objmesh) #create a copy of the mesh
+
+ objmesh = triangulate_mesh(objmesh) # create a copy of the mesh
bpy.ops.object.mode_set(mode='OBJECT')
- for i in bpy.context.scene.objects: i.select = False # deselect all objects
+
+ for i in bpy.context.scene.objects:
+ i.select = False # deselect all objects
+
objmesh.select = True
- bpy.context.scene.objects.active = objmesh #set active mesh
- wedges = ObjMap()
- points = ObjMap()
- bpy.ops.object.mode_set(mode='EDIT') #set in edit mode
+ bpy.context.scene.objects.active = objmesh # set active mesh
+ wedges = ObjMap()
+ points = ObjMap()
+ bpy.ops.object.mode_set(mode='EDIT') # set in edit mode
bpy.ops.mesh.select_all(action='DESELECT')
- bpy.context.tool_settings.mesh_select_mode = (True, False, False) #select vertices
+ bpy.context.tool_settings.mesh_select_mode = (True, False, False) # select vertices
if objmesh is not None:
print("found mesh")
@@ -2446,19 +2580,19 @@ def udkcheckmeshline():
print(objmesh.data.tessfaces)
vertex_list = []
for face in objmesh.data.tessfaces:
- wedge_list = []
- vect_list = []
+ wedge_list = []
+ vect_list = []
for i in range(3):
- vert_index = face.vertices[i]
- vert = objmesh.data.vertices[vert_index]
- vect_list.append( FVector(vert.co.x, vert.co.y, vert.co.z) )
+ vert_index = face.vertices[i]
+ vert = objmesh.data.vertices[vert_index]
+ vect_list.append(FVector(vert.co.x, vert.co.y, vert.co.z))
vpos = objmesh.matrix_local * vert.co
- p = VPoint()
- p.Point.X = vpos.x
- p.Point.Y = vpos.y
- p.Point.Z = vpos.z
- w = VVertex()
- w.PointIndex = points.get(p) # store keys
+ p = VPoint()
+ p.Point.X = vpos.x
+ p.Point.Y = vpos.y
+ p.Point.Z = vpos.z
+ w = VVertex()
+ w.PointIndex = points.get(p) # store keys
index_wedge = wedges.get(w)
wedge_list.append(index_wedge)
no = face.normal
@@ -2472,28 +2606,29 @@ def udkcheckmeshline():
elif dot < 0:
(tri.WedgeIndex0, tri.WedgeIndex1, tri.WedgeIndex2) = wedge_list
else:
- dindex0 = face.vertices[0];
- dindex1 = face.vertices[1];
- dindex2 = face.vertices[2];
+ dindex0 = face.vertices[0]
+ dindex1 = face.vertices[1]
+ dindex2 = face.vertices[2]
vertex_list.append(dindex0)
vertex_list.append(dindex1)
vertex_list.append(dindex2)
bpy.ops.object.mode_set(mode='OBJECT')
- for vertex in objmesh.data.vertices: #loop all vertex in the mesh list
- for vl in vertex_list: #loop for error vertex
- if vertex.index == vl: #if match set to select
+ for vertex in objmesh.data.vertices: # loop all vertex in the mesh list
+ for vl in vertex_list: # loop for error vertex
+ if vertex.index == vl: # if match set to select
vertex.select = True
break
- bpy.ops.object.mode_set(mode='EDIT') #set in edit mode to see the select vertex
- objmesh.data.update() # update object
- bpy.context.scene.update() #update scene
+ bpy.ops.object.mode_set(mode='EDIT') # set in edit mode to see the select vertex
+ objmesh.data.update() # update object
+ bpy.context.scene.update() # update scene
message = "MESH PASS"
if len(vertex_list) > 0:
message = "MESH FAIL"
return message
-class OBJECT_OT_UDKCheckMeshLines(bpy.types.Operator):
+
+class OBJECT_OT_UDKCheckMeshLines(Operator):
"""Select the mesh for export test. This will create dummy mesh to see which area are broken. """ \
"""If the vertices share the same position it will cause a bug"""
bl_idname = "object.udkcheckmeshline"
@@ -2504,7 +2639,8 @@ class OBJECT_OT_UDKCheckMeshLines(bpy.types.Operator):
self.report({'ERROR'}, message)
return{'FINISHED'}
-class OBJECT_OT_ActionSetAnimUpdate(bpy.types.Operator):
+
+class OBJECT_OT_ActionSetAnimUpdate(Operator):
"""Select Armture to match the action set groups. """ \
"""All bones keys must be set to match with number of bones"""
bl_idname = "action.setanimupdate"
@@ -2521,9 +2657,9 @@ class OBJECT_OT_ActionSetAnimUpdate(bpy.types.Operator):
armatureselected = []
for objarm in bpy.context.scene.objects:
if objarm.type == 'ARMATURE':
- #print("ADDED ARMATURE...")
+ # print("ADDED ARMATURE...")
armatures.append(objarm)
- if objarm.select == True:
+ if objarm.select is True:
armatureselected.append(objarm)
if len(armatureselected) == len(armatures) == 1:
@@ -2537,15 +2673,15 @@ class OBJECT_OT_ActionSetAnimUpdate(bpy.types.Operator):
for bone in armature.pose.bones:
bones.append(bone.name)
- for action in bpy.data.actions:#action list
+ for action in bpy.data.actions: # action list
bfound = False
count = 0
for actionbone in action.groups:
- #print("Pose bone name: ",actionbone.name)
+ # print("Pose bone name: ",actionbone.name)
for b in bones:
if b == actionbone.name:
count += 1
- #print(b," : ",actionbone.name)
+ # print(b," : ",actionbone.name)
break
for actionlist in my_sett:
if action.name == actionlist.name:
@@ -2556,17 +2692,17 @@ class OBJECT_OT_ActionSetAnimUpdate(bpy.types.Operator):
actionlist.bmatch = False
bfound = True
break
- if bfound != True:
+ if bfound is not True:
my_item = my_sett.add()
- #print(dir(my_item.bmatch))
+ # print(dir(my_item.bmatch))
my_item.name = action.name
- #my_item.template_list_controls = "bmatch:bexport"
+ # my_item.template_list_controls = "bmatch:bexport"
if len(bones) == len(action.groups) == count:
my_item.bmatch = True
else:
my_item.bmatch = False
removeactions = []
- #check action list and data actions
+ # check action list and data actions
for actionlist in bpy.context.scene.udkas_list:
bfind = False
notfound = 0
@@ -2575,26 +2711,27 @@ class OBJECT_OT_ActionSetAnimUpdate(bpy.types.Operator):
bfind = True
else:
notfound += 1
- #print("ACT NAME:",actionlist.name," COUNT",notfound)
+ # print("ACT NAME:",actionlist.name," COUNT",notfound)
if notfound == len(bpy.data.actions):
- #print("remove :",actionlist.name)
+ # print("remove :",actionlist.name)
removeactions.append(actionlist.name)
- #print("Not in the action data list:",len(removeactions))
- #remove list or chnages in the name the template list
+ # print("Not in the action data list:",len(removeactions))
+ # remove list or chnages in the name the template list
for actname in removeactions:
actioncount = 0
for actionlist in my_sett:
- #print("action name:",actionlist.name)
+ # print("action name:",actionlist.name)
if actionlist.name == actname:
- my_sett.remove(actioncount);
+ my_sett.remove(actioncount)
break
actioncount += 1
return{'FINISHED'}
-class ExportUDKAnimData(bpy.types.Operator):
+
+class ExportUDKAnimData(Operator):
"""Export Skeleton Mesh / Animation Data file(s). """ \
"""One mesh and one armature else select one mesh or armature to be exported"""
- bl_idname = "export_anim.udk" # this is important since its how bpy.ops.export.udk_anim_data is constructed
+ bl_idname = "export_anim.udk" # this is important since its how bpy.ops.export.udk_anim_data is constructed
bl_label = "Export PSK/PSA"
# List of operator properties, the attributes will be assigned
@@ -2607,13 +2744,18 @@ class ExportUDKAnimData(bpy.types.Operator):
default="*.psk;*.psa",
options={'HIDDEN'},
)
- udk_option_smoothing_groups = bpy.types.Scene.udk_option_smoothing_groups
- udk_option_clamp_uv = bpy.types.Scene.udk_option_clamp_uv
- udk_option_verbose = bpy.types.Scene.udk_option_verbose
- udk_option_filename_src = bpy.types.Scene.udk_option_filename_src
- udk_option_export = bpy.types.Scene.udk_option_export
- udk_option_scale = bpy.types.Scene.udk_option_scale
- udk_option_rebuildobjects = bpy.types.Scene.udk_option_rebuildobjects
+ udk_option_scale = FloatProperty(
+ name="UDK Scale",
+ description="In case you don't want to scale objects manually - "
+ "This will just scale position when on export for the skeleton mesh and animation data",
+ default=1
+ )
+ udk_option_rebuildobjects = BoolProperty(
+ name="Rebuild Objects",
+ description="In case of deform skeleton mesh and animations data - "
+ "This will rebuild objects from raw format on export when checked",
+ default=False
+ )
@classmethod
def poll(cls, context):
@@ -2645,61 +2787,217 @@ class ExportUDKAnimData(bpy.types.Operator):
self.report({'WARNING', 'INFO'}, message)
return {'FINISHED'}
+ def draw(self, context):
+ layout = self.layout
+ scene = context.scene
+
+ layout.prop(scene, "udk_option_smoothing_groups")
+ layout.prop(scene, "udk_option_clamp_uv")
+ layout.prop(scene, "udk_option_verbose")
+ layout.prop(scene, "udk_option_filename_src")
+ layout.prop(scene, "udk_option_export")
+ layout.prop(self, "udk_option_scale")
+ layout.prop(self, "udk_option_rebuildobjects")
+
def invoke(self, context, event):
+ self.udk_option_scale = bpy.context.scene.udk_option_scale
+ self.udk_option_rebuildobjects = bpy.context.scene.udk_option_rebuildobjects
+
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
+
def menu_func(self, context):
default_path = os.path.splitext(bpy.data.filepath)[0] + ".psk"
- self.layout.operator(ExportUDKAnimData.bl_idname, text="Skeleton Mesh / Animation Data (.psk/.psa)").filepath = default_path
+ self.layout.operator(ExportUDKAnimData.bl_idname,
+ text="Skeleton Mesh / Animation Data (.psk/.psa)").filepath = default_path
+
+
+# Add-ons Preferences Update Panel
+
+# Define Panel classes for updating
+panels = (
+ Panel_UDKExport,
+ )
+
-## Addons Preferences Update Panel
def update_panel(self, context):
+ message = "Export Unreal Engine Format(.psk/.psa): Updating Panel locations has failed"
try:
- bpy.utils.unregister_class(Panel_UDKExport)
- except:
+ for panel in panels:
+ if "bl_rna" in panel.__dict__:
+ bpy.utils.unregister_class(panel)
+
+ for panel in panels:
+ panel.bl_category = context.user_preferences.addons[__name__].preferences.category
+ bpy.utils.register_class(panel)
+
+ except Exception as e:
+ print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
pass
- Panel_UDKExport.bl_category = context.user_preferences.addons[__name__].preferences.category
- bpy.utils.register_class(Panel_UDKExport)
-class PskAddonPreferences(bpy.types.AddonPreferences):
+
+class PskAddonPreferences(AddonPreferences):
# this must match the addon name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __name__
- category = bpy.props.StringProperty(
+ category = StringProperty(
name="Tab Category",
description="Choose a name for the category of the panel",
default="File I/O",
- update=update_panel)
+ update=update_panel
+ )
def draw(self, context):
-
layout = self.layout
+
row = layout.row()
col = row.column()
col.label(text="Tab Category:")
col.prop(self, "category", text="")
-#===========================================================================
+
+
+# ===========================================================================
# Entry
-#===========================================================================
+# ===========================================================================
def register():
- #print("REGISTER")
+
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_export.append(menu_func)
update_panel(None, bpy.context)
+ # Added by [MGVS]
+ bpy.types.Scene.udk_option_filename_src = EnumProperty(
+ name="Filename",
+ description="Sets the name for the files",
+ items=[
+ ('0', "From object", "Name will be taken from object name"),
+ ('1', "From Blend", "Name will be taken from .blend file name")
+ ],
+ default='0'
+ )
+ bpy.types.Scene.udk_option_export_psk = BoolProperty(
+ name="bool export psa",
+ description="Boolean for exporting psk format (Skeleton Mesh)",
+ default=True
+ )
+ bpy.types.Scene.udk_option_export_psa = BoolProperty(
+ name="bool export psa",
+ description="Boolean for exporting psa format (Animation Data)",
+ default=True
+ )
+ bpy.types.Scene.udk_option_clamp_uv = BoolProperty(
+ name="Clamp UV",
+ description="True is to limit Clamp UV co-ordinates to [0-1]. False is unrestricted (x,y)",
+ default=False
+ )
+ bpy.types.Scene.udk_copy_merge = BoolProperty(
+ name="Merge Mesh",
+ description="This will copy the mesh(s) and merge the object together "
+ "and unlink the mesh to be remove while exporting the object",
+ default=False
+ )
+ bpy.types.Scene.udk_option_export = EnumProperty(
+ name="Export",
+ description="What to export",
+ items=[
+ ('0', "Mesh only", "Exports the PSK file for the Skeletal Mesh"),
+ ('1', "Animation only", "Export the PSA file for Action Set(s)(Animations Data)"),
+ ('2', "Mesh & Animation", "Export both PSK and PSA files(Skeletal Mesh/Animation(s) Data)")
+ ],
+ default='2'
+ )
+ bpy.types.Scene.udk_option_verbose = BoolProperty(
+ name="Verbose",
+ description="Verbose console output",
+ default=False
+ )
+ bpy.types.Scene.udk_option_smoothing_groups = BoolProperty(
+ name="Smooth Groups",
+ description="Activate hard edges as smooth groups",
+ default=True
+ )
+ bpy.types.Scene.udk_option_triangulate = BoolProperty(
+ name="Triangulate Mesh",
+ description="Convert Quads to Triangles",
+ default=False
+ )
+ bpy.types.Scene.udk_option_selectanimations = BoolProperty(
+ name="Select Animation(s)",
+ description="Select animation(s) for export to psa file",
+ default=False
+ )
+ bpy.types.Scene.udk_option_selectobjects = BoolProperty(
+ name="Select Object(s)",
+ description="Select Armature and Mesh(s). Just make sure mesh(s) is parent to armature",
+ default=False
+ )
+ bpy.types.Scene.udk_option_rebuildobjects = BoolProperty(
+ name="Rebuild Objects",
+ description="In case of deform skeleton mesh and animations data - "
+ "This will rebuild objects from raw format on export when checked",
+ default=False
+ )
+ bpy.types.Scene.udk_option_ignoreactiongroupnames = BoolProperty(
+ name="Ignore Action Group Names",
+ description="This will Ignore Action Set Group Names Check With Armature Bones. "
+ "It will override armature to set action set",
+ default=False
+ )
+ bpy.types.Scene.udk_option_scale = FloatProperty(
+ name="UDK Scale",
+ description="In case you don't want to scale objects manually - "
+ "This will just scale position when on export for the skeleton mesh and animation data",
+ default=1
+ )
+ bpy.types.Scene.udkas_list = CollectionProperty(
+ type=UDKActionSetListPG
+ )
+ bpy.types.Scene.udkas_list_idx = IntProperty()
+ bpy.types.Scene.udkobj_list = CollectionProperty(
+ type=UDKObjListPG
+ )
+ bpy.types.Scene.udkobj_list_idx = IntProperty()
+ bpy.types.Scene.udkmesh_list = CollectionProperty(
+ type=UDKMeshListPG
+ )
+ bpy.types.Scene.udkmesh_list_idx = IntProperty()
+ bpy.types.Scene.udkArm_list = CollectionProperty(
+ type=UDKArmListPG
+ )
+ bpy.types.Scene.udkArm_list_idx = IntProperty()
+
+
def unregister():
- #print("UNREGISTER")
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_export.remove(menu_func)
+ del bpy.types.Scene.udk_option_filename_src
+ del bpy.types.Scene.udk_option_export_psk
+ del bpy.types.Scene.udk_option_export_psa
+ del bpy.types.Scene.udk_option_clamp_uv
+ del bpy.types.Scene.udk_copy_merge
+ del bpy.types.Scene.udk_option_export
+ del bpy.types.Scene.udk_option_verbose
+ del bpy.types.Scene.udk_option_smoothing_groups
+ del bpy.types.Scene.udk_option_triangulate
+ del bpy.types.Scene.udk_option_selectanimations
+ del bpy.types.Scene.udk_option_selectobjects
+ del bpy.types.Scene.udk_option_rebuildobjects
+ del bpy.types.Scene.udk_option_ignoreactiongroupnames
+ del bpy.types.Scene.udk_option_scale
+ del bpy.types.Scene.udkas_list
+ del bpy.types.Scene.udkas_list_idx
+ del bpy.types.Scene.udkobj_list
+ del bpy.types.Scene.udkobj_list_idx
+ del bpy.types.Scene.udkmesh_list
+ del bpy.types.Scene.udkmesh_list_idx
+ del bpy.types.Scene.udkArm_list
+ del bpy.types.Scene.udkArm_list_idx
+
+
if __name__ == "__main__":
- #print("\n"*4)
print(header("UDK Export PSK/PSA 2.6", 'CENTER'))
register()
-
-#loader
-#filename = "D:/Projects/BlenderScripts/io_export_udk_psa_psk_alpha.py"
-#exec(compile(open(filename).read(), filename, 'exec'))