summaryrefslogtreecommitdiff
path: root/collada_superbmd_export.py
blob: 5d6f83fc373dce4ac009aaeb8d89b0e9ad9ce7fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import bpy, math
from . import blender_funcs

# just a DAE exporter.
# it was supposed to only rotate the meshes around the X axis by -90 degrees
# but above that it now checks for armature and vertex group stuff
# only exports the armature object selected    

# write_bmd_bdl_collada function
# function to write custom collada file for
# SuperBMD conversion
def write_bmd_bdl_collada(context, filepath, triangulate):
    
  # this thing is always needed for stuff
  scene = bpy.context.scene
  
  # if nothing is selected end the exporter
  if (scene.objects.active == None or scene.objects.active.type != 'ARMATURE'):
    if (scene.objects.active == None):
      blender_funcs.disp_msg("No Armature selected. Select one and try again.")
    else:
      blender_funcs.disp_msg("No Armature selected. Currently selecting: \"%s\""
                             % (scene.objects.active.name))
    return {'FINISHED'}
  
  # get armature object
  armature = scene.objects.active  
  print("\nArmature found: \"%s\"" % (armature.name))
  
  # check if the armature contains only mesh objects inside
  for obj in armature.children:
    if (obj.type != 'MESH'):
      blender_funcs.disp_msg("\"%s\": contains non-mesh object (%s)."
                             % (armature.name, obj.name))
      return {'FINISHED'}
  
  # check if all meshes have an armature modifier that is
  # assigned to the armature object and it is binded to
  # vertex groups if none of those are just create them,
  # I don't think it is bad to automate that
  for mesh in armature.children:
    if("Armature" not in mesh.modifiers):
      blender_funcs.disp_msg("\"%s\": has no armature modifier. Adding one..." % (mesh.name))
      blender_funcs.select_obj(scene, mesh, False)
      bpy.ops.object.modifier_add(type = 'ARMATURE')
      mesh.modifiers["Armature"].object = armature
      mesh.modifiers["Armature"].use_vertex_groups = True
    else: # ensure bind is to a vertex group
      if (mesh.modifiers["Armature"].use_vertex_groups == False):
        blender_funcs.disp_msg("\"%s\": armature modifier wasn't binded to vertex groups"
                               % (mesh.name))
        mesh.modifiers["Armature"].use_vertex_groups = True
  
  # check if all the vertex groups in each mesh correspond to the name of a skeleton bone
  bone_name_list = []
  for bone in armature.data.bones:
    bone_name_list.append(bone.name)  
  # vertex group check
  for mesh in armature.children:
    for v_group in mesh.vertex_groups:
      if (v_group.name not in bone_name_list):
        blender_funcs.disp_msg(("\"%s\": contains non-valid vert group \"%s\"." 
                               % (mesh.name, v_group.name)) + " Unable to continue.")
        return {'FINISHED'}
  # vertex weight check
  for mesh in armature.children:
    for vertex in mesh.data.vertices:
      if (len(vertex.groups) == 0):
        blender_funcs.disp_msg(("\"%s\": contains unweighted vertices."
                               % (mesh.name)) + " Unable to continue.")
        return {'FINISHED'}
  
  # get the object names
  obj_name = armature.name
  child_names = []
  for child in armature.children:
    child_names.append(child.name)
  
  # change to object view and make a copy of the armature object (with its children)
  bpy.ops.object.mode_set(mode='OBJECT')  
  blender_funcs.select_obj(scene, armature, True)
  bpy.ops.object.duplicate(linked = True)
  bpy.ops.object.make_single_user(type = 'SELECTED_OBJECTS', object = True, obdata = True)
  old_armature = armature
  armature = scene.objects.active
  blender_funcs.select_obj(scene, armature, False)
  
  # apply the transformations to the armature
  armature.rotation_euler[0] = math.radians(-90)
  armature.scale = 100 * armature.scale
  bpy.ops.object.transform_apply(location = True, rotation = True, scale = True)
   
  # apply the transformations to the meshes inside the armature
  for i in range(0, len(armature.children)):
    blender_funcs.select_obj(scene, armature.children[i], False)
    bpy.ops.object.transform_apply(location = True, rotation = True, scale = True)
  blender_funcs.select_obj(scene, armature, False)
  
  # handle the object names so that they match the original model names
  armature.name = obj_name
  armature.data.name = obj_name
  for i in range(0, len(armature.children)):
    armature.children[i].name = child_names[i] 
    armature.children[i].data.name = child_names[i] 
  
  # export the object
  bpy.ops.wm.collada_export(filepath = filepath, use_blender_profile = False,
                            selected = True, include_children = True,
                            triangulate = triangulate)  
  
  # delete the duplicate object
  blender_funcs.select_obj(scene, armature, True)
  bpy.ops.object.delete(use_global = False)
  
  # re-assign the original object names
  armature = old_armature
  armature.name = obj_name
  armature.data.name = obj_name
  for i in range(0, len(armature.children)):
    armature.children[i].name = child_names[i] 
    armature.children[i].data.name = child_names[i] 
  
  # done!
  blender_funcs.select_obj(scene, armature, False)
  blender_funcs.disp_msg("Armature \"%s\" exported!" % (armature.name))
  return {'FINISHED'}

# Stuff down is for the menu appending
# of the exporter to work plus some setting stuff
# comes from a Blender importer template
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator

class export_superbmd_collada(Operator, ExportHelper):
  """Export a Collada file for SuperBMD (SuperBMD only)"""
  bl_idname = "export_scene.superbmd_collada"
  bl_label = "Export SuperBMD Collada (.DAE)"
  filename_ext = ".dae"
  filter_glob = StringProperty(default = "*.dae", options = {'HIDDEN'}, maxlen = 255)
    
  triangulate = BoolProperty(name = "Triangulate meshes",
                             description = "Triangulate meshes inside armatures",
                             default = False)
  def execute(self, context):
    return write_bmd_bdl_collada(context, self.filepath, self.triangulate)

# Only needed if you want to add into a dynamic menu
def menu_export_superbmd_collada(self, context):
  self.layout.operator(export_superbmd_collada.bl_idname, text="SuperBMD Collada (.dae)")

bpy.utils.register_class(export_superbmd_collada)
bpy.types.INFO_MT_file_export.append(menu_export_superbmd_collada)

# test call
bpy.ops.export_scene.superbmd_collada('INVOKE_DEFAULT')