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:
authorChris Foster <cdbfoster@gmail.com>2013-03-17 23:27:11 +0400
committerChris Foster <cdbfoster@gmail.com>2013-03-17 23:27:11 +0400
commitf3366818c0796ba057361abb26caa157b4d16453 (patch)
treecbcf413c9627720ca92a3b545efcd520392bb4db /io_export_directx_x.py
parente56284b89d7a3c68f234a8c7c12aa7f1e620404c (diff)
- A ground-up rewrite of the DirectX .x exporter for better design and extensibility.
- Optimized vertex, normal, and skin weight export where possible. - Largely decoupled data gathering and data writing. This will make it much easier to provide binary file support in the future. - Added animation option to export each action of each object as a separate AnimationSet and another option to export unused actions as if used by the first armature object. - Added vertex color export support.
Diffstat (limited to 'io_export_directx_x.py')
-rw-r--r--io_export_directx_x.py1299
1 files changed, 0 insertions, 1299 deletions
diff --git a/io_export_directx_x.py b/io_export_directx_x.py
deleted file mode 100644
index 4532600c..00000000
--- a/io_export_directx_x.py
+++ /dev/null
@@ -1,1299 +0,0 @@
-# ***** GPL LICENSE BLOCK *****
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# All rights reserved.
-# ***** GPL LICENSE BLOCK *****
-
-bl_info = {
- "name": "DirectX Model Format (.x)",
- "author": "Chris Foster (Kira Vakaan)",
- "version": (2, 1, 3),
- "blender": (2, 63, 0),
- "location": "File > Export > DirectX (.x)",
- "description": "Export DirectX Model Format (.x)",
- "warning": "",
- "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"\
- "Scripts/Import-Export/DirectX_Exporter",
- "tracker_url": "https://projects.blender.org/tracker/index.php?"\
- "func=detail&aid=22795",
- "category": "Import-Export"}
-
-import os
-from math import radians
-
-import bpy
-from mathutils import *
-
-#Container for the exporter settings
-class DirectXExporterSettings:
- def __init__(self,
- context,
- FilePath,
- CoordinateSystem=1,
- RotateX=True,
- FlipNormals=False,
- ApplyModifiers=False,
- IncludeFrameRate=False,
- ExportTextures=True,
- ExportArmatures=False,
- ExportAnimation=0,
- ExportMode=1,
- Verbose=False):
- self.context = context
- self.FilePath = FilePath
- self.CoordinateSystem = int(CoordinateSystem)
- self.RotateX = RotateX
- self.FlipNormals = FlipNormals
- self.ApplyModifiers = ApplyModifiers
- self.IncludeFrameRate = IncludeFrameRate
- self.ExportTextures = ExportTextures
- self.ExportArmatures = ExportArmatures
- self.ExportAnimation = int(ExportAnimation)
- self.ExportMode = int(ExportMode)
- self.Verbose = Verbose
-
-
-def LegalName(Name):
-
- def ReplaceSet(String, OldSet, NewChar):
- for OldChar in OldSet:
- String = String.replace(OldChar, NewChar)
- return String
-
- import string
-
- NewName = ReplaceSet(Name, string.punctuation + " ", "_")
- if NewName[0].isdigit() or NewName in ["ARRAY",
- "DWORD",
- "UCHAR",
- "BINARY",
- "FLOAT",
- "ULONGLONG",
- "BINARY_RESOURCE",
- "SDWORD",
- "UNICODE",
- "CHAR",
- "STRING",
- "WORD",
- "CSTRING",
- "SWORD",
- "DOUBLE",
- "TEMPLATE"]:
- NewName = "_" + NewName
- return NewName
-
-
-def ExportDirectX(Config):
- print("----------\nExporting to {}".format(Config.FilePath))
- if Config.Verbose:
- print("Opening File...")
- Config.File = open(Config.FilePath, "w")
- if Config.Verbose:
- print("Done")
-
- if Config.Verbose:
- print("Generating Object list for export... (Root parents only)")
- if Config.ExportMode == 1:
- Config.ExportList = [Object for Object in Config.context.scene.objects
- if Object.type in {'ARMATURE', 'EMPTY', 'MESH'}
- and Object.parent is None]
- else:
- ExportList = [Object for Object in Config.context.selected_objects
- if Object.type in {'ARMATURE', 'EMPTY', 'MESH'}]
- Config.ExportList = [Object for Object in ExportList
- if Object.parent not in ExportList]
- if Config.Verbose:
- print(" List: {}\nDone".format(Config.ExportList))
-
- if Config.Verbose:
- print("Setting up...")
- Config.SystemMatrix = Matrix()
- if Config.RotateX:
- Config.SystemMatrix *= Matrix.Rotation(radians(-90), 4, "X")
- if Config.CoordinateSystem == 1:
- Config.SystemMatrix *= Matrix.Scale(-1, 4, Vector((0, 1, 0)))
-
- if Config.ExportAnimation:
- CurrentFrame = bpy.context.scene.frame_current
- bpy.context.scene.frame_current = bpy.context.scene.frame_current
- if Config.Verbose:
- print("Done")
-
- if Config.Verbose:
- print("Writing Header...")
- WriteHeader(Config)
- if Config.Verbose:
- print("Done")
-
- Config.Whitespace = 0
- if Config.Verbose:
- print("Writing Root Frame...")
- WriteRootFrame(Config)
- if Config.Verbose:
- print("Done")
-
- Config.ObjectList = []
- if Config.Verbose:
- print("Writing Objects...")
- WriteObjects(Config, Config.ExportList)
- if Config.Verbose:
- print("Done")
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of Root Frame\n".format(" " * Config.Whitespace))
-
- if Config.Verbose:
- print("Objects Exported: {}".format(Config.ExportList))
-
- if Config.ExportAnimation:
- if Config.IncludeFrameRate:
- if Config.Verbose:
- print("Writing Frame Rate...")
- Config.File.write("{}AnimTicksPerSecond {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{};\n".format(" " * Config.Whitespace, int(bpy.context.scene.render.fps / bpy.context.scene.render.fps_base)))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print("Done")
- if Config.Verbose:
- print("Writing Animation...")
- if Config.ExportAnimation==1:
- WriteKeyedAnimationSet(Config)
- else:
- WriteFullAnimationSet(Config)
- bpy.context.scene.frame_current = CurrentFrame
- if Config.Verbose:
- print("Done")
-
- CloseFile(Config)
- print("Finished")
-
-
-def GetObjectChildren(Parent):
- return [Object for Object in Parent.children
- if Object.type in {'ARMATURE', 'EMPTY', 'MESH'}]
-
-#Returns the vertex count of Mesh, counting each vertex for every face.
-def GetMeshVertexCount(Mesh):
- VertexCount = 0
- for Polygon in Mesh.polygons:
- VertexCount += len(Polygon.vertices)
- return VertexCount
-
-#Returns the file path of first image texture from Material.
-def GetMaterialTextureFileName(Material):
- if Material:
- #Create a list of Textures that have type "IMAGE"
- ImageTextures = [Material.texture_slots[TextureSlot].texture for TextureSlot in Material.texture_slots.keys() if Material.texture_slots[TextureSlot].texture.type == "IMAGE"]
- #Refine a new list with only image textures that have a file source
- ImageFiles = [bpy.path.basename(Texture.image.filepath) for Texture in ImageTextures if getattr(Texture.image, "source", "") == "FILE"]
- if ImageFiles:
- return ImageFiles[0]
- return None
-
-
-def WriteHeader(Config):
- Config.File.write("xof 0303txt 0032\n\n")
-
- if Config.IncludeFrameRate:
- Config.File.write("template AnimTicksPerSecond {\n\
- <9E415A43-7BA6-4a73-8743-B73D47E88476>\n\
- DWORD AnimTicksPerSecond;\n\
-}\n\n")
-
- if Config.ExportArmatures:
- Config.File.write("template XSkinMeshHeader {\n\
- <3cf169ce-ff7c-44ab-93c0-f78f62d172e2>\n\
- WORD nMaxSkinWeightsPerVertex;\n\
- WORD nMaxSkinWeightsPerFace;\n\
- WORD nBones;\n\
-}\n\n\
-template SkinWeights {\n\
- <6f0d123b-bad2-4167-a0d0-80224f25fabb>\n\
- STRING transformNodeName;\n\
- DWORD nWeights;\n\
- array DWORD vertexIndices[nWeights];\n\
- array float weights[nWeights];\n\
- Matrix4x4 matrixOffset;\n\
-}\n\n")
-
-def WriteRootFrame(Config):
- Config.File.write("{}Frame Root {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
-
- Config.File.write("{}FrameTransformMatrix {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, Config.SystemMatrix[0][0], Config.SystemMatrix[1][0], Config.SystemMatrix[2][0], Config.SystemMatrix[3][0]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, Config.SystemMatrix[0][1], Config.SystemMatrix[1][1], Config.SystemMatrix[2][1], Config.SystemMatrix[3][1]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, Config.SystemMatrix[0][2], Config.SystemMatrix[1][2], Config.SystemMatrix[2][2], Config.SystemMatrix[3][2]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, Config.SystemMatrix[0][3], Config.SystemMatrix[1][3], Config.SystemMatrix[2][3], Config.SystemMatrix[3][3]))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
-
-def WriteObjects(Config, ObjectList):
- Config.ObjectList += ObjectList
-
- for Object in ObjectList:
- if Config.Verbose:
- print(" Writing Object: {}...".format(Object.name))
- Config.File.write("{}Frame {} {{\n".format(" " * Config.Whitespace, LegalName(Object.name)))
-
- Config.Whitespace += 1
- if Config.Verbose:
- print(" Writing Local Matrix...")
- WriteLocalMatrix(Config, Object)
- if Config.Verbose:
- print(" Done")
-
- if Config.ExportArmatures and Object.type == "ARMATURE":
- Armature = Object.data
- ParentList = [Bone for Bone in Armature.bones if Bone.parent is None]
- if Config.Verbose:
- print(" Writing Armature Bones...")
- WriteArmatureBones(Config, Object, ParentList)
- if Config.Verbose:
- print(" Done")
-
- ChildList = GetObjectChildren(Object)
- if Config.ExportMode == 2: #Selected Objects Only
- ChildList = [Child for Child in ChildList
- if Child in Config.context.selected_objects]
- if Config.Verbose:
- print(" Writing Children...")
- WriteObjects(Config, ChildList)
- if Config.Verbose:
- print(" Done Writing Children")
-
- if Object.type == "MESH":
- if Config.Verbose:
- print(" Generating Mesh...")
- if Config.ApplyModifiers:
- if Config.ExportArmatures:
- #Create a copy of the object and remove all armature modifiers so an unshaped
- #mesh can be created from it.
- Object2 = Object.copy()
- for Modifier in [Modifier for Modifier in Object2.modifiers if Modifier.type == "ARMATURE"]:
- Object2.modifiers.remove(Modifier)
- Mesh = Object2.to_mesh(bpy.context.scene, True, "PREVIEW")
- else:
- Mesh = Object.to_mesh(bpy.context.scene, True, "PREVIEW")
- else:
- Mesh = Object.to_mesh(bpy.context.scene, False, "PREVIEW")
- if Config.Verbose:
- print(" Done")
- print(" Writing Mesh...")
- WriteMesh(Config, Object, Mesh)
- if Config.Verbose:
- print(" Done")
- if Config.ApplyModifiers and Config.ExportArmatures:
- bpy.data.objects.remove(Object2)
- bpy.data.meshes.remove(Mesh)
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of {}\n".format(" " * Config.Whitespace, LegalName(Object.name)))
- if Config.Verbose:
- print(" Done Writing Object: {}".format(Object.name))
-
-
-def WriteLocalMatrix(Config, Object):
- LocalMatrix = Object.matrix_local
-
- Config.File.write("{}FrameTransformMatrix {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, LocalMatrix[0][0], LocalMatrix[1][0], LocalMatrix[2][0], LocalMatrix[3][0]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, LocalMatrix[0][1], LocalMatrix[1][1], LocalMatrix[2][1], LocalMatrix[3][1]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, LocalMatrix[0][2], LocalMatrix[1][2], LocalMatrix[2][2], LocalMatrix[3][2]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, LocalMatrix[0][3], LocalMatrix[1][3], LocalMatrix[2][3], LocalMatrix[3][3]))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
-
-
-def WriteArmatureBones(Config, Object, ChildList):
- PoseBones = Object.pose.bones
- for Bone in ChildList:
- if Config.Verbose:
- print(" Writing Bone: {}...".format(Bone.name))
- Config.File.write("{}Frame {} {{\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name)))
- Config.Whitespace += 1
-
- PoseBone = PoseBones[Bone.name]
-
- if Bone.parent:
- BoneMatrix = PoseBone.parent.matrix.inverted()
- else:
- BoneMatrix = Matrix()
-
- BoneMatrix *= PoseBone.matrix
-
- Config.File.write("{}FrameTransformMatrix {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][0], BoneMatrix[1][0], BoneMatrix[2][0], BoneMatrix[3][0]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][1], BoneMatrix[1][1], BoneMatrix[2][1], BoneMatrix[3][1]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][2], BoneMatrix[1][2], BoneMatrix[2][2], BoneMatrix[3][2]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, BoneMatrix[0][3], BoneMatrix[1][3], BoneMatrix[2][3], BoneMatrix[3][3]))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
-
- if Config.Verbose:
- print(" Done")
- WriteArmatureBones(Config, Object, Bone.children)
- Config.Whitespace -= 1
-
- Config.File.write("{}}} //End of {}\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name)))
-
-
-def WriteMesh(Config, Object, Mesh):
- Config.File.write("{}Mesh {{ //{} Mesh\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
- Config.Whitespace += 1
-
- if Config.Verbose:
- print(" Writing Mesh Vertices...")
- WriteMeshVertices(Config, Mesh)
- if Config.Verbose:
- print(" Done\n Writing Mesh Normals...")
- WriteMeshNormals(Config, Mesh)
- if Config.Verbose:
- print(" Done\n Writing Mesh Materials...")
- WriteMeshMaterials(Config, Mesh)
- if Config.Verbose:
- print(" Done")
- if Mesh.uv_textures:
- if Config.Verbose:
- print(" Writing Mesh UV Coordinates...")
- WriteMeshUVCoordinates(Config, Mesh)
- if Config.Verbose:
- print(" Done")
- if Config.ExportArmatures:
- if Config.Verbose:
- print(" Writing Mesh Skin Weights...")
- WriteMeshSkinWeights(Config, Object, Mesh)
- if Config.Verbose:
- print(" Done")
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of {} Mesh\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
-
-
-def WriteMeshVertices(Config, Mesh):
- Index = 0
- VertexCount = GetMeshVertexCount(Mesh)
- Config.File.write("{}{};\n".format(" " * Config.Whitespace, VertexCount))
-
- for Polygon in Mesh.polygons:
- Vertices = list(Polygon.vertices)
-
- if Config.CoordinateSystem == 1:
- Vertices = Vertices[::-1]
-
- for Vertex in [Mesh.vertices[Vertex] for Vertex in Vertices]:
- Position = Vertex.co
- Config.File.write("{}{:9f};{:9f};{:9f};".format(" " * Config.Whitespace, Position[0], Position[1], Position[2]))
- Index += 1
- if Index == VertexCount:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
-
- Index = 0
- Config.File.write("{}{};\n".format(" " * Config.Whitespace, len(Mesh.polygons)))
-
- for Polygon in Mesh.polygons:
- Config.File.write("{}{};".format(" " * Config.Whitespace, len(Polygon.vertices)))
- for Vertex in Polygon.vertices:
- Config.File.write("{};".format(Index))
- Index += 1
- if Index == VertexCount:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
-
-
-def WriteMeshNormals(Config, Mesh):
- Config.File.write("{}MeshNormals {{ //{} Normals\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
- Config.Whitespace += 1
-
- Index = 0
- VertexCount = GetMeshVertexCount(Mesh)
- Config.File.write("{}{};\n".format(" " * Config.Whitespace, VertexCount))
-
- for Polygon in Mesh.polygons:
- Vertices = list(Polygon.vertices)
-
- if Config.CoordinateSystem == 1:
- Vertices = Vertices[::-1]
- for Vertex in [Mesh.vertices[Vertex] for Vertex in Vertices]:
- if Polygon.use_smooth:
- Normal = Vertex.normal
- else:
- Normal = Polygon.normal
- if Config.FlipNormals:
- Normal = -Normal
- Config.File.write("{}{:9f};{:9f};{:9f};".format(" " * Config.Whitespace, Normal[0], Normal[1], Normal[2]))
- Index += 1
- if Index == VertexCount:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
-
- Index = 0
- Config.File.write("{}{};\n".format(" " * Config.Whitespace, len(Mesh.polygons)))
-
- for Polygon in Mesh.polygons:
- Config.File.write("{}{};".format(" " * Config.Whitespace, len(Polygon.vertices)))
- for Vertex in Polygon.vertices:
- Config.File.write("{};".format(Index))
- Index += 1
- if Index == VertexCount:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of {} Normals\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
-
-
-def WriteMeshMaterials(Config, Mesh):
- Config.File.write("{}MeshMaterialList {{ //{} Material List\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
- Config.Whitespace += 1
-
- Materials = Mesh.materials
- if Materials.keys():
- MaterialIndexes = {}
- for Polygon in Mesh.polygons:
- if Materials[Polygon.material_index] not in MaterialIndexes:
- MaterialIndexes[Materials[Polygon.material_index]] = len(MaterialIndexes)
-
- PolygonCount = len(Mesh.polygons)
- Index = 0
- Config.File.write("{}{};\n{}{};\n".format(" " * Config.Whitespace, len(MaterialIndexes), " " * Config.Whitespace, PolygonCount))
- for Polygon in Mesh.polygons:
- Config.File.write("{}{}".format(" " * Config.Whitespace, MaterialIndexes[Materials[Polygon.material_index]]))
- Index += 1
- if Index == PolygonCount:
- Config.File.write(";;\n")
- else:
- Config.File.write(",\n")
-
- Materials = [Item[::-1] for Item in MaterialIndexes.items()]
- Materials.sort()
- for Material in Materials:
- WriteMaterial(Config, Material[1])
- else:
- Config.File.write("{}1;\n{}1;\n{}0;;\n".format(" " * Config.Whitespace, " " * Config.Whitespace, " " * Config.Whitespace))
- WriteMaterial(Config)
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of {} Material List\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
-
-
-def WriteMaterial(Config, Material=None):
- if Material:
- Config.File.write("{}Material {} {{\n".format(" " * Config.Whitespace, LegalName(Material.name)))
- Config.Whitespace += 1
-
- Diffuse = list(Vector(Material.diffuse_color) * Material.diffuse_intensity)
- Diffuse.append(Material.alpha)
- Specularity = 1000 * (Material.specular_hardness - 1.0) / (511.0 - 1.0) # Map Blender's range of 1 - 511 to 0 - 1000
- Specular = list(Vector(Material.specular_color) * Material.specular_intensity)
-
- Config.File.write("{}{:9f};{:9f};{:9f};{:9f};;\n".format(" " * Config.Whitespace, Diffuse[0], Diffuse[1], Diffuse[2], Diffuse[3]))
- Config.File.write("{} {:9f};\n".format(" " * Config.Whitespace, Specularity))
- Config.File.write("{}{:9f};{:9f};{:9f};;\n".format(" " * Config.Whitespace, Specular[0], Specular[1], Specular[2]))
- else:
- Config.File.write("{}Material Default_Material {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{} 0.800000; 0.800000; 0.800000; 0.800000;;\n".format(" " * Config.Whitespace))
- Config.File.write("{} 96.078431;\n".format(" " * Config.Whitespace)) # 1000 * (50 - 1) / (511 - 1)
- Config.File.write("{} 0.500000; 0.500000; 0.500000;;\n".format(" " * Config.Whitespace))
- Config.File.write("{} 0.000000; 0.000000; 0.000000;;\n".format(" " * Config.Whitespace))
- if Config.ExportTextures:
- TextureFileName = GetMaterialTextureFileName(Material)
- if TextureFileName:
- Config.File.write("{}TextureFilename {{\"{}\";}}\n".format(" " * Config.Whitespace, TextureFileName))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
-
-
-def WriteMeshUVCoordinates(Config, Mesh):
- Config.File.write("{}MeshTextureCoords {{ //{} UV Coordinates\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
- Config.Whitespace += 1
-
- UVCoordinates = Mesh.uv_layers.active.data
-
- Index = 0
- VertexCount = GetMeshVertexCount(Mesh)
- Config.File.write("{}{};\n".format(" " * Config.Whitespace, VertexCount))
-
- for Polygon in Mesh.polygons:
- Vertices = []
- for Vertex in [UVCoordinates[Vertex] for Vertex in Polygon.loop_indices]:
- Vertices.append(tuple(Vertex.uv))
- if Config.CoordinateSystem == 1:
- Vertices = Vertices[::-1]
- for Vertex in Vertices:
- Config.File.write("{}{:9f};{:9f};".format(" " * Config.Whitespace, Vertex[0], 1 - Vertex[1]))
- Index += 1
- if Index == VertexCount:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of {} UV Coordinates\n".format(" " * Config.Whitespace, LegalName(Mesh.name)))
-
-
-def WriteMeshSkinWeights(Config, Object, Mesh):
- ArmatureList = [Modifier for Modifier in Object.modifiers if Modifier.type == "ARMATURE"]
- if ArmatureList:
- ArmatureObject = ArmatureList[0].object
- ArmatureBones = ArmatureObject.data.bones
-
- PoseBones = ArmatureObject.pose.bones
-
- MaxInfluences = 0
- UsedBones = set()
- #Maps bones to a list of vertices they affect
- VertexGroups = {}
- ObjectVertexGroups = {i: Group.name for (i, Group) in enumerate(Object.vertex_groups)}
- for Vertex in Mesh.vertices:
- #BoneInfluences contains the bones of the armature that affect the current vertex
- BoneInfluences = [PoseBone for Group in Vertex.groups
- for PoseBone in (PoseBones.get(ObjectVertexGroups.get(Group.group, "")), )
- if PoseBone is not None
- ]
-
- if len(BoneInfluences) > MaxInfluences:
- MaxInfluences = len(BoneInfluences)
- for Bone in BoneInfluences:
- UsedBones.add(Bone)
- if Bone not in VertexGroups:
- VertexGroups[Bone] = [Vertex]
- else:
- VertexGroups[Bone].append(Vertex)
- BoneCount = len(UsedBones)
-
- Config.File.write("{}XSkinMeshHeader {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{};\n{}{};\n{}{};\n".format(" " * Config.Whitespace, MaxInfluences, " " * Config.Whitespace, MaxInfluences * 3, " " * Config.Whitespace, BoneCount))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
-
- for Bone in UsedBones:
- VertexCount = 0
- VertexIndexes = [Vertex.index for Vertex in VertexGroups[Bone]]
- for Polygon in Mesh.polygons:
- for Vertex in Polygon.vertices:
- if Vertex in VertexIndexes:
- VertexCount += 1
-
- Config.File.write("{}SkinWeights {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}\"{}\";\n{}{};\n".format(" " * Config.Whitespace, LegalName(ArmatureObject.name) + "_" + LegalName(Bone.name), " " * Config.Whitespace, VertexCount))
-
- VertexWeights = []
- Index = 0
- WrittenIndexes = 0
- for Polygon in Mesh.polygons:
- PolygonVertices = list(Polygon.vertices)
- if Config.CoordinateSystem == 1:
- PolygonVertices = PolygonVertices[::-1]
- for Vertex in PolygonVertices:
- if Vertex in VertexIndexes:
- Config.File.write("{}{}".format(" " * Config.Whitespace, Index))
-
- GroupIndexes = {ObjectVertexGroups.get(Group.group): Index
- for Index, Group in enumerate(Mesh.vertices[Vertex].groups)
- if ObjectVertexGroups.get(Group.group, "") in PoseBones}
-
- WeightTotal = 0.0
- for Weight in (Group.weight for Group in Mesh.vertices[Vertex].groups if ObjectVertexGroups.get(Group.group, "") in PoseBones):
- WeightTotal += Weight
-
- if WeightTotal:
- VertexWeights.append(Mesh.vertices[Vertex].groups[GroupIndexes[Bone.name]].weight / WeightTotal)
- else:
- VertexWeights.append(0.0)
-
- WrittenIndexes += 1
- if WrittenIndexes == VertexCount:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Index += 1
-
- for Index, Weight in enumerate(VertexWeights):
- Config.File.write("{}{:8f}".format(" " * Config.Whitespace, Weight))
- if Index == (VertexCount - 1):
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
-
- RestBone = ArmatureBones[Bone.name]
-
- #BoneMatrix transforms mesh vertices into the space of the bone.
- #Here are the final transformations in order:
- # - Object Space to World Space
- # - World Space to Armature Space
- # - Armature Space to Bone Space (The bone matrix needs to be rotated 90 degrees to align with Blender's world axes)
- #This way, when BoneMatrix is transformed by the bone's Frame matrix, the vertices will be in their final world position.
-
- BoneMatrix = RestBone.matrix_local.inverted()
- BoneMatrix *= ArmatureObject.matrix_world.inverted()
- BoneMatrix *= Object.matrix_world
-
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][0], BoneMatrix[1][0], BoneMatrix[2][0], BoneMatrix[3][0]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][1], BoneMatrix[1][1], BoneMatrix[2][1], BoneMatrix[3][1]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f},\n".format(" " * Config.Whitespace, BoneMatrix[0][2], BoneMatrix[1][2], BoneMatrix[2][2], BoneMatrix[3][2]))
- Config.File.write("{}{:9f},{:9f},{:9f},{:9f};;\n".format(" " * Config.Whitespace, BoneMatrix[0][3], BoneMatrix[1][3], BoneMatrix[2][3], BoneMatrix[3][3]))
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of {} Skin Weights\n".format(" " * Config.Whitespace, LegalName(ArmatureObject.name) + "_" + LegalName(Bone.name)))
-
-
-def WriteKeyedAnimationSet(Config):
- Config.File.write("{}AnimationSet {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- for Object in [Object for Object in Config.ObjectList if Object.animation_data]:
- if Config.Verbose:
- print(" Writing Animation Data for Object: {}".format(Object.name))
- Action = Object.animation_data.action
- if Action:
- PositionFCurves = [None, None, None]
- RotationFCurves = [None, None, None]
- ScaleFCurves = [None, None, None]
- for FCurve in Action.fcurves:
- if FCurve.data_path == "location":
- PositionFCurves[FCurve.array_index] = FCurve
- elif FCurve.data_path == "rotation_euler":
- RotationFCurves[FCurve.array_index] = FCurve
- elif FCurve.data_path == "scale":
- ScaleFCurves[FCurve.array_index] = FCurve
- if [FCurve for FCurve in PositionFCurves + RotationFCurves + ScaleFCurves if FCurve]:
- Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name)))
-
- #Position
- if Config.Verbose:
- print(" Writing Position...")
- AllKeyframes = set()
- for Index, FCurve in enumerate(PositionFCurves):
- if FCurve:
- Keyframes = []
- for Keyframe in FCurve.keyframe_points:
- if Keyframe.co[0] < bpy.context.scene.frame_start:
- AllKeyframes.add(bpy.context.scene.frame_start)
- elif Keyframe.co[0] > bpy.context.scene.frame_end:
- AllKeyframes.add(bpy.context.scene.frame_end)
- else:
- Keyframes.append(Keyframe.co)
- AllKeyframes.add(int(Keyframe.co[0]))
- PositionFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes}
- Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- AllKeyframes = list(AllKeyframes)
- AllKeyframes.sort()
- if len(AllKeyframes):
- Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes)))
- for Keyframe in AllKeyframes:
- bpy.context.scene.frame_set(Keyframe)
- Position = Vector()
- Position[0] = ((PositionFCurves[0][Keyframe] if Keyframe in PositionFCurves[0] else Object.location[0]) if PositionFCurves[0] else Object.location[0])
- Position[1] = ((PositionFCurves[1][Keyframe] if Keyframe in PositionFCurves[1] else Object.location[1]) if PositionFCurves[1] else Object.location[1])
- Position[2] = ((PositionFCurves[2][Keyframe] if Keyframe in PositionFCurves[2] else Object.location[2]) if PositionFCurves[2] else Object.location[2])
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Position[0], Position[1], Position[2]))
- if Keyframe == AllKeyframes[-1]:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
-
- else:
- Config.File.write("{}2;\n{}1;\n".format(" " * Config.Whitespace, " " * Config.Whitespace))
- bpy.context.scene.frame_set(bpy.context.scene.frame_start)
- Position = Object.matrix_local.to_translation()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;;\n".format(" " * Config.Whitespace, ("0;3;").ljust(8), Position[0], Position[1], Position[2]))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Rotation
- if Config.Verbose:
- print(" Writing Rotation...")
- AllKeyframes = set()
- for Index, FCurve in enumerate(RotationFCurves):
- if FCurve:
- Keyframes = []
- for Keyframe in FCurve.keyframe_points:
- if Keyframe.co[0] < bpy.context.scene.frame_start:
- AllKeyframes.add(bpy.context.scene.frame_start)
- elif Keyframe.co[0] > bpy.context.scene.frame_end:
- AllKeyframes.add(bpy.context.scene.frame_end)
- else:
- Keyframes.append(Keyframe.co)
- AllKeyframes.add(int(Keyframe.co[0]))
- RotationFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes}
- Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- AllKeyframes = list(AllKeyframes)
- AllKeyframes.sort()
- if len(AllKeyframes):
- Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes)))
- for Keyframe in AllKeyframes:
- bpy.context.scene.frame_set(Keyframe)
- Rotation = Euler()
- Rotation[0] = ((RotationFCurves[0][Keyframe] if Keyframe in RotationFCurves[0] else Object.rotation_euler[0]) if RotationFCurves[0] else Object.rotation_euler[0])
- Rotation[1] = ((RotationFCurves[1][Keyframe] if Keyframe in RotationFCurves[1] else Object.rotation_euler[1]) if RotationFCurves[1] else Object.rotation_euler[1])
- Rotation[2] = ((RotationFCurves[2][Keyframe] if Keyframe in RotationFCurves[2] else Object.rotation_euler[2]) if RotationFCurves[2] else Object.rotation_euler[2])
- Rotation = Rotation.to_quaternion()
- Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3]))
- if Keyframe == AllKeyframes[-1]:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- else:
- Config.File.write("{}0;\n{}1;\n".format(" " * Config.Whitespace, " " * Config.Whitespace))
- bpy.context.scene.frame_set(bpy.context.scene.frame_start)
- Rotation = Object.rotation_euler.to_quaternion()
- Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;;\n".format(" " * Config.Whitespace, ("0;4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3]))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Scale
- if Config.Verbose:
- print(" Writing Scale...")
- AllKeyframes = set()
- for Index, FCurve in enumerate(ScaleFCurves):
- if FCurve:
- Keyframes = []
- for Keyframe in FCurve.keyframe_points:
- if Keyframe.co[0] < bpy.context.scene.frame_start:
- AllKeyframes.add(bpy.context.scene.frame_start)
- elif Keyframe.co[0] > bpy.context.scene.frame_end:
- AllKeyframes.add(bpy.context.scene.frame_end)
- else:
- Keyframes.append(Keyframe.co)
- AllKeyframes.add(int(Keyframe.co[0]))
- ScaleFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes}
- Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- AllKeyframes = list(AllKeyframes)
- AllKeyframes.sort()
- if len(AllKeyframes):
- Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes)))
- for Keyframe in AllKeyframes:
- bpy.context.scene.frame_set(Keyframe)
- Scale = Vector()
- Scale[0] = ((ScaleFCurves[0][Keyframe] if Keyframe in ScaleFCurves[0] else Object.scale[0]) if ScaleFCurves[0] else Object.scale[0])
- Scale[1] = ((ScaleFCurves[1][Keyframe] if Keyframe in ScaleFCurves[1] else Object.scale[1]) if ScaleFCurves[1] else Object.scale[1])
- Scale[2] = ((ScaleFCurves[2][Keyframe] if Keyframe in ScaleFCurves[2] else Object.scale[2]) if ScaleFCurves[2] else Object.scale[2])
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2]))
- if Keyframe == AllKeyframes[-1]:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- else:
- Config.File.write("{}1;\n{}1;\n".format(" " * Config.Whitespace, " " * Config.Whitespace))
- bpy.context.scene.frame_set(bpy.context.scene.frame_start)
- Scale = Object.matrix_local.to_scale()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;;\n".format(" " * Config.Whitespace, ("0;3;").ljust(8), Scale[0], Scale[1], Scale[2]))
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- else:
- if Config.Verbose:
- print(" Object has no useable animation data.")
-
- if Config.ExportArmatures and Object.type == "ARMATURE":
- if Config.Verbose:
- print(" Writing Armature Bone Animation Data...")
- PoseBones = Object.pose.bones
- for Bone in PoseBones:
- if Config.Verbose:
- print(" Writing Bone: {}...".format(Bone.name))
- PositionFCurves = [None, None, None]
- RotationFCurves = [None, None, None, None]
- ScaleFCurves = [None, None, None]
- for FCurve in Action.fcurves:
- if FCurve.data_path == "pose.bones[\"{}\"].location".format(Bone.name):
- PositionFCurves[FCurve.array_index] = FCurve
- elif FCurve.data_path == "pose.bones[\"{}\"].rotation_quaternion".format(Bone.name):
- RotationFCurves[FCurve.array_index] = FCurve
- elif FCurve.data_path == "pose.bones[\"{}\"].scale".format(Bone.name):
- ScaleFCurves[FCurve.array_index] = FCurve
- if not [FCurve for FCurve in PositionFCurves + RotationFCurves + ScaleFCurves if FCurve]:
- if Config.Verbose:
- print(" Bone has no useable animation data.\n Done")
- continue
-
- Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name)))
-
- #Position
- if Config.Verbose:
- print(" Writing Position...")
- AllKeyframes = set()
- for Index, FCurve in enumerate(PositionFCurves):
- if FCurve:
- Keyframes = []
- for Keyframe in FCurve.keyframe_points:
- if Keyframe.co[0] < bpy.context.scene.frame_start:
- AllKeyframes.add(bpy.context.scene.frame_start)
- elif Keyframe.co[0] > bpy.context.scene.frame_end:
- AllKeyframes.add(bpy.context.scene.frame_end)
- else:
- Keyframes.append(Keyframe.co)
- AllKeyframes.add(int(Keyframe.co[0]))
- PositionFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes}
- Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- AllKeyframes = list(AllKeyframes)
- AllKeyframes.sort()
- if not len(AllKeyframes):
- AllKeyframes = [bpy.context.scene.frame_start]
- Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes)))
- for Keyframe in AllKeyframes:
- bpy.context.scene.frame_set(Keyframe)
-
- if Bone.parent:
- PoseMatrix = Bone.parent.matrix.inverted()
- else:
- PoseMatrix = Matrix()
- PoseMatrix *= Bone.matrix
-
- Position = PoseMatrix.to_translation()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Position[0], Position[1], Position[2]))
- if Keyframe == AllKeyframes[-1]:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Rotation
- if Config.Verbose:
- print(" Writing Rotation...")
- AllKeyframes = set()
- for Index, FCurve in enumerate(RotationFCurves):
- if FCurve:
- Keyframes = []
- for Keyframe in FCurve.keyframe_points:
- if Keyframe.co[0] < bpy.context.scene.frame_start:
- AllKeyframes.add(bpy.context.scene.frame_start)
- elif Keyframe.co[0] > bpy.context.scene.frame_end:
- AllKeyframes.add(bpy.context.scene.frame_end)
- else:
- Keyframes.append(Keyframe.co)
- AllKeyframes.add(int(Keyframe.co[0]))
- RotationFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes}
- Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- AllKeyframes = list(AllKeyframes)
- AllKeyframes.sort()
- if not len(AllKeyframes):
- AllKeyframes = [bpy.context.scene.frame_start]
- Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes)))
- for Keyframe in AllKeyframes:
- bpy.context.scene.frame_set(Keyframe)
-
- if Bone.parent:
- PoseMatrix = Bone.parent.matrix.inverted()
- else:
- PoseMatrix = Matrix()
- PoseMatrix *= Bone.matrix
-
- Rotation = PoseMatrix.to_3x3().to_quaternion()
- Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3]))
- if Keyframe == AllKeyframes[-1]:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Scale
- if Config.Verbose:
- print(" Writing Scale...")
- AllKeyframes = set()
- for Index, FCurve in enumerate(ScaleFCurves):
- if FCurve:
- Keyframes = []
- for Keyframe in FCurve.keyframe_points:
- if Keyframe.co[0] < bpy.context.scene.frame_start:
- AllKeyframes.add(bpy.context.scene.frame_start)
- elif Keyframe.co[0] > bpy.context.scene.frame_end:
- AllKeyframes.add(bpy.context.scene.frame_end)
- else:
- Keyframes.append(Keyframe.co)
- AllKeyframes.add(int(Keyframe.co[0]))
- ScaleFCurves[Index] = {int(Keyframe): Value for Keyframe, Value in Keyframes}
- Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- AllKeyframes = list(AllKeyframes)
- AllKeyframes.sort()
- if not len(AllKeyframes):
- AllKeyframes = [bpy.context.scene.frame_start]
- Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, len(AllKeyframes)))
- for Keyframe in AllKeyframes:
- bpy.context.scene.frame_set(Keyframe)
-
- if Bone.parent:
- PoseMatrix = Bone.parent.matrix.inverted()
- else:
- PoseMatrix = Matrix()
- PoseMatrix *= Bone.matrix
-
- Scale = PoseMatrix.to_scale()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Keyframe - bpy.context.scene.frame_start) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2]))
- if Keyframe == AllKeyframes[-1]:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done") #Done with Armature Bone
- if Config.Verbose:
- print(" Done") #Done with Armature Bone data
- if Config.Verbose:
- print(" Done") #Done with Object
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of AnimationSet\n".format(" " * Config.Whitespace))
-
-def WriteFullAnimationSet(Config):
- Config.File.write("{}AnimationSet {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
-
- KeyframeCount = bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1
-
- for Object in Config.ObjectList:
- if Config.Verbose:
- print(" Writing Animation Data for Object: {}".format(Object.name))
-
- Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name)))
-
- #Position
- if Config.Verbose:
- print(" Writing Position...")
- Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount))
- for Frame in range(0, KeyframeCount):
- bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start)
- Position = Object.matrix_local.to_translation()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Position[0], Position[1], Position[2]))
- if Frame == KeyframeCount-1:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Rotation
- if Config.Verbose:
- print(" Writing Rotation...")
- Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount))
- for Frame in range(0, KeyframeCount):
- bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start)
- Rotation = Object.rotation_euler.to_quaternion()
- Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Frame) + ";4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3]))
- if Frame == KeyframeCount-1:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Scale
- if Config.Verbose:
- print(" Writing Scale...")
- Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount))
- for Frame in range(0, KeyframeCount):
- bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start)
- Scale = Object.matrix_local.to_scale()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2]))
- if Frame == KeyframeCount-1:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
-
- if Config.ExportArmatures and Object.type == "ARMATURE":
- if Config.Verbose:
- print(" Writing Armature Bone Animation Data...")
- PoseBones = Object.pose.bones
- Bones = Object.data.bones
- for Bone in PoseBones:
- if Config.Verbose:
- print(" Writing Bone: {}...".format(Bone.name))
-
- Config.File.write("{}Animation {{\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}{{{}}}\n".format(" " * Config.Whitespace, LegalName(Object.name) + "_" + LegalName(Bone.name)))
-
- #Position
- if Config.Verbose:
- print(" Writing Position...")
- Config.File.write("{}AnimationKey {{ //Position\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}2;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount))
- for Frame in range(0, KeyframeCount):
- bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start)
-
- if Bone.parent:
- PoseMatrix = Bone.parent.matrix.inverted()
- else:
- PoseMatrix = Matrix()
- PoseMatrix *= Bone.matrix
-
- Position = PoseMatrix.to_translation()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Position[0], Position[1], Position[2]))
- if Frame == KeyframeCount-1:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Rotation
- if Config.Verbose:
- print(" Writing Rotation...")
- Config.File.write("{}AnimationKey {{ //Rotation\n".format(" " * Config.Whitespace))
- Config.Whitespace += 1
- Config.File.write("{}0;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount))
- for Frame in range(0, KeyframeCount):
- bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start)
-
- Rotation = Bones[Bone.name].matrix.to_quaternion() * Bone.rotation_quaternion
-
- Config.File.write("{}{}{:9f},{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Frame) + ";4;").ljust(8), -Rotation[0], Rotation[1], Rotation[2], Rotation[3]))
- if Frame == KeyframeCount-1:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- #Scale
- if Config.Verbose:
- print(" Writing Scale...")
- Config.File.write("{}AnimationKey {{ //Scale\n".format(" " * Config.Whitespace, KeyframeCount))
- Config.Whitespace += 1
- Config.File.write("{}1;\n{}{};\n".format(" " * Config.Whitespace, " " * Config.Whitespace, KeyframeCount))
- for Frame in range(0, KeyframeCount):
- bpy.context.scene.frame_set(Frame + bpy.context.scene.frame_start)
-
- if Bone.parent:
- PoseMatrix = Bone.parent.matrix.inverted()
- else:
- PoseMatrix = Matrix()
- PoseMatrix *= Bone.matrix
-
- Scale = PoseMatrix.to_scale()
- Config.File.write("{}{}{:9f},{:9f},{:9f};;".format(" " * Config.Whitespace, (str(Frame) + ";3;").ljust(8), Scale[0], Scale[1], Scale[2]))
- if Frame == KeyframeCount-1:
- Config.File.write(";\n")
- else:
- Config.File.write(",\n")
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done")
-
- Config.Whitespace -= 1
- Config.File.write("{}}}\n".format(" " * Config.Whitespace))
- if Config.Verbose:
- print(" Done") #Done with Armature Bone
- if Config.Verbose:
- print(" Done") #Done with Armature Bone data
- if Config.Verbose:
- print(" Done") #Done with Object
-
- Config.Whitespace -= 1
- Config.File.write("{}}} //End of AnimationSet\n".format(" " * Config.Whitespace))
-
-
-def CloseFile(Config):
- if Config.Verbose:
- print("Closing File...")
- Config.File.close()
- if Config.Verbose:
- print("Done")
-
-
-CoordinateSystems = (
- ("1", "Left-Handed", ""),
- ("2", "Right-Handed", ""),
- )
-
-
-AnimationModes = (
- ("0", "None", ""),
- ("1", "Keyframes Only", ""),
- ("2", "Full Animation", ""),
- )
-
-ExportModes = (
- ("1", "All Objects", ""),
- ("2", "Selected Objects", ""),
- )
-
-
-from bpy.props import StringProperty, EnumProperty, BoolProperty
-
-
-class DirectXExporter(bpy.types.Operator):
- """Export to the DirectX model format (.x)"""
-
- bl_idname = "export.directx"
- bl_label = "Export DirectX"
-
- filepath = StringProperty(subtype='FILE_PATH')
-
- #Coordinate System
- CoordinateSystem = EnumProperty(
- name="System",
- description="Select a coordinate system to export to",
- items=CoordinateSystems,
- default="1")
-
- #General Options
- RotateX = BoolProperty(
- name="Rotate X 90 Degrees",
- description="Rotate the entire scene 90 degrees around the X axis so Y is up",
- default=True)
- FlipNormals = BoolProperty(
- name="Flip Normals",
- description="",
- default=False)
- ApplyModifiers = BoolProperty(
- name="Apply Modifiers",
- description="Apply object modifiers before export",
- default=False)
- IncludeFrameRate = BoolProperty(
- name="Include Frame Rate",
- description="Include the AnimTicksPerSecond template which is used by " \
- "some engines to control animation speed",
- default=False)
- ExportTextures = BoolProperty(
- name="Export Textures",
- description="Reference external image files to be used by the model",
- default=True)
- ExportArmatures = BoolProperty(
- name="Export Armatures",
- description="Export the bones of any armatures to deform meshes",
- default=False)
- ExportAnimation = EnumProperty(
- name="Animations",
- description="Select the type of animations to export. Only object " \
- "and armature bone animations can be exported. Full " \
- "Animation exports every frame",
- items=AnimationModes,
- default="0")
-
- #Export Mode
- ExportMode = EnumProperty(
- name="Export",
- description="Select which objects to export. Only Mesh, Empty, " \
- "and Armature objects will be exported",
- items=ExportModes,
- default="1")
-
- Verbose = BoolProperty(
- name="Verbose",
- description="Run the exporter in debug mode. Check the console for output",
- default=False)
-
- def execute(self, context):
- #Append .x
- FilePath = bpy.path.ensure_ext(self.filepath, ".x")
-
- Config = DirectXExporterSettings(context,
- FilePath,
- CoordinateSystem=self.CoordinateSystem,
- RotateX=self.RotateX,
- FlipNormals=self.FlipNormals,
- ApplyModifiers=self.ApplyModifiers,
- IncludeFrameRate=self.IncludeFrameRate,
- ExportTextures=self.ExportTextures,
- ExportArmatures=self.ExportArmatures,
- ExportAnimation=self.ExportAnimation,
- ExportMode=self.ExportMode,
- Verbose=self.Verbose)
-
- ExportDirectX(Config)
- return {'FINISHED'}
-
- def invoke(self, context, event):
- if not self.filepath:
- self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".x")
- WindowManager = context.window_manager
- WindowManager.fileselect_add(self)
- return {"RUNNING_MODAL"}
-
-
-def menu_func(self, context):
- self.layout.operator(DirectXExporter.bl_idname, text="DirectX (.x)")
-
-
-def register():
- bpy.utils.register_module(__name__)
-
- bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
- bpy.utils.unregister_module(__name__)
-
- bpy.types.INFO_MT_file_export.remove(menu_func)
-
-
-if __name__ == "__main__":
- register()