OSDN Git Service

refactoring export_pmd
[meshio/pymeshio.git] / blender26-meshio / bl.py
1 # coding: utf-8
2 import os
3 import sys
4 import time
5 import functools
6
7 try:
8     import bpy
9     import mathutils
10 except:
11     pass
12
13 FS_ENCODING=sys.getfilesystemencoding()
14 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
15     INTERNAL_ENCODING='utf-8'
16 else:
17     INTERNAL_ENCODING=FS_ENCODING
18
19 def register():
20     pass
21
22 def unregister():
23     pass
24
25 SCENE=None
26 def initialize(name, scene):
27     global SCENE
28     SCENE=scene
29     progress_start(name)
30
31 def finalize():
32     scene.update(SCENE)
33     progress_finish()
34
35 def message(msg):
36     print(msg)
37
38 def enterEditMode():
39     bpy.ops.object.mode_set(mode='EDIT', toggle=False)
40
41 def enterObjectMode():
42     bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
43
44 def enterPoseMode():
45     bpy.ops.object.mode_set(mode='POSE', toggle=False)
46
47 def createVector(x, y, z):
48     return mathutils.Vector([x, y, z])
49
50
51 class Writer(object):
52     '''
53     io wrapper
54     '''
55     def __init__(self, path, encoding):
56         self.io=open(path, "wb")
57         self.encoding=encoding
58
59     def write(self, s):
60         self.io.write(s.encode(self.encoding))
61
62     def flush(self):
63         self.io.flush()
64
65     def close(self):
66         self.io.close()
67
68
69 progressBar=None
70 class ProgressBar(object):
71     '''
72     progress bar wrapper
73     '''
74     def __init__(self, base):
75         print("#### %s ####" % base)
76         self.base=base
77         self.start=time.time() 
78         self.set('<start>', 0)
79
80     def advance(self, message, progress):
81         self.progress+=float(progress)
82         self._print(message)
83
84     def set(self, message, progress):
85         self.progress=float(progress)
86         self._print(message)
87
88     def _print(self, message):
89         print(message)
90         message="%s: %s" % (self.base, message)
91         #Blender.Window.DrawProgressBar(self.progress, message)
92
93     def finish(self):
94         self.progress=1.0
95         message='finished in %.2f sec' % (time.time()-self.start)
96         self.set(message, 1.0)
97
98 def progress_start(base):
99     global progressBar
100     print("#### progressBar ####")
101     progressBar=ProgressBar(base)
102
103 def progress_finish():
104     global progressBar
105     progressBar.finish()
106
107 def progress_print(message, progress=0.05):
108     global progressBar
109     progressBar.advance(message, progress)
110
111 def progress_set(message, progress):
112     global progressBar
113     progressBar.set(message, progress)
114
115
116 class scene:
117     @staticmethod
118     def get():
119         global SCENE
120         return SCENE
121
122     def update(scene):
123         scene.update()
124
125
126 class object:
127     @staticmethod
128     def createEmpty(name):
129         global SCENE
130         empty=bpy.data.objects.new(name, None)
131         SCENE.objects.link(empty)
132         return empty
133
134     @staticmethod
135     def each():
136         for o in SCENE.objects:
137             yield o
138
139     @staticmethod
140     def makeParent(parent, child):
141         child.parent=parent
142
143     @staticmethod
144     def duplicate(o):
145         global SCENE
146         bpy.ops.object.select_all(action='DESELECT')
147         o.select=True
148         SCENE.objects.active=o
149         bpy.ops.object.duplicate()
150         dumy=SCENE.objects.active
151         #bpy.ops.object.rotation_apply()
152         #bpy.ops.object.scale_apply()
153         #bpy.ops.object.location_apply()
154         return dumy.data, dumy
155
156     @staticmethod
157     def delete(o):
158         global SCENE
159         SCENE.objects.unlink(o)
160
161     @staticmethod
162     def getData(o):
163         return o.data
164
165     @staticmethod
166     def select(o):
167         o.select=True
168
169     @staticmethod
170     def activate(o):
171         global SCENE
172         o.select=True 
173         SCENE.objects.active=o
174
175     @staticmethod
176     def getActive():
177         global SCENE 
178         return SCENE.objects.active
179
180     @staticmethod
181     def deselectAll():
182         bpy.ops.object.select_all(action='DESELECT')
183
184     @staticmethod
185     def setLayerMask(object, layers):
186         layer=[]
187         for i in range(20):
188             try:
189                 layer.append(True if layers[i]!=0 else False)
190             except IndexError:
191                 layer.append(False)
192         object.layers=layer
193
194     @staticmethod
195     def isVisible(o):
196         return False if o.hide else True
197
198     @staticmethod
199     def getShapeKeys(o):
200         return o.data.shape_keys.key_blocks
201
202     @staticmethod
203     def addShapeKey(o, name):
204         try:
205             return o.shape_key_add(name)
206         except:
207             return o.add_shape_key(name)
208
209     @staticmethod
210     def hasShapeKey(o):
211         return o.data.shape_keys
212
213     @staticmethod
214     def pinShape(o, enable):
215         o.show_only_shape_key=enable
216
217     @staticmethod
218     def setActivateShapeKey(o, index):
219         o.active_shape_key_index=index
220
221     @staticmethod
222     def getPose(o):
223         return o.pose
224
225     @staticmethod
226     def getVertexGroup(o, name):
227         indices=[]
228         for i, v in enumerate(o.data.vertices):
229             for g in v.groups:
230                 if o.vertex_groups[g.group].name==name:
231                     indices.append(i)
232         return indices
233
234     @staticmethod
235     def getVertexGroupNames(o):
236         for g in o.vertex_groups:
237             yield g.name
238
239     @staticmethod
240     def addVertexGroup(o, name):
241         o.vertex_groups.new(name)
242
243     @staticmethod
244     def assignVertexGroup(o, name, index, weight):
245         if name not in o.vertex_groups:
246             o.vertex_groups.new(name)
247         o.vertex_groups[name].add([index], weight, 'ADD')
248
249     @staticmethod
250     def createBoneGroup(o, name, color_set='DEFAULT'):
251         # create group
252         object.activate(o)
253         enterPoseMode()
254         bpy.ops.pose.group_add()
255         # set name
256         pose=object.getPose(o)
257         g=pose.bone_groups.active
258         g.name=name
259         g.color_set=color_set
260         return g
261
262     @staticmethod
263     def boneGroups(o):
264         return object.getPose(o).bone_groups
265
266
267 class modifier:
268     @staticmethod
269     def addMirror(mesh_object):
270         return mesh_object.modifiers.new("Modifier", "MIRROR")
271
272     @staticmethod
273     def addArmature(mesh_object, armature_object):
274         mod=mesh_object.modifiers.new("Modifier", "ARMATURE")
275         mod.object = armature_object
276         mod.use_bone_envelopes=False
277
278     @staticmethod
279     def hasType(mesh_object, type_name):
280         for mod in mesh_object.modifiers:
281                 if mod.type==type_name.upper():
282                     return True
283
284     @staticmethod
285     def isType(m, type_name):
286         return m.type==type_name.upper()
287
288     @staticmethod
289     def getArmatureObject(m):
290         return m.object
291
292
293 class shapekey:
294     @staticmethod
295     def assign(shapeKey, index, pos):
296         shapeKey.data[index].co=pos
297
298     @staticmethod
299     def getByIndex(b, index):
300         return b.data[index].co
301
302     @staticmethod
303     def get(b):
304         for k in b.data:
305             yield k.co
306
307
308 class texture:
309     @staticmethod
310     def create(path):
311         texture=bpy.data.textures.new(os.path.basename(path), 'IMAGE')
312         texture.use_mipmap=True
313         texture.use_interpolation=True
314         texture.use_alpha=True
315         try:
316             image=bpy.data.images.load(path)
317         except RuntimeError:
318             print('fail to create:', path)
319             image=bpy.data.images.new('Image', width=16, height=16)
320         texture.image=image
321         return texture, image
322
323     @staticmethod
324     def getPath(t):
325         if  t.type=="IMAGE":
326             image=t.image
327             if image:
328                 return image.filepath
329
330
331 class material:
332     @staticmethod
333     def create(name):
334         return bpy.data.materials.new(name)
335
336     @staticmethod
337     def get(material_name):
338         return bpy.data.materials[material_name]
339
340     @staticmethod
341     def addTexture(material, texture, enable=True):
342         # search free slot
343         index=None
344         for i, slot in enumerate(material.texture_slots):
345             if not slot:
346                 index=i
347                 break
348         if index==None:
349             return
350         #
351         #material.add_texture(texture, "UV", "COLOR")
352         #slot=material.texture_slots.add()
353         slot=material.texture_slots.create(index)
354         slot.texture=texture
355         slot.texture_coords='UV'
356         slot.blend_type='MULTIPLY'
357         slot.use_map_alpha=True
358         slot.use=enable
359         return index
360
361     @staticmethod
362     def getTexture(m, index):
363         return m.texture_slots[index].texture
364
365     @staticmethod
366     def hasTexture(m):
367         return m.texture_slots[0]
368
369     @staticmethod
370     def setUseTexture(m, index, enable):
371         m.use_textures[index]=enable
372
373     @staticmethod
374     def eachTexturePath(m):
375         for slot in m.texture_slots:
376             if slot and slot.texture:
377                 texture=slot.texture
378                 if  texture.type=="IMAGE":
379                     image=texture.image
380                     if not image:
381                         continue
382                     yield image.filepath
383
384     @staticmethod
385     def eachEnalbeTexturePath(m):
386         for i, slot in enumerate(m.texture_slots):
387             if m.use_textures[i] and slot and slot.texture:
388                 texture=slot.texture
389                 if  texture.type=="IMAGE":
390                     image=texture.image
391                     if not image:
392                         continue
393                     yield image.filepath
394
395
396 class mesh:
397     @staticmethod
398     def create(name):
399         global SCENE
400         mesh=bpy.data.meshes.new("Mesh")
401         mesh_object= bpy.data.objects.new(name, mesh)
402         SCENE.objects.link(mesh_object)
403         return mesh, mesh_object
404
405     @staticmethod
406     def addGeometry(mesh, vertices, faces):
407         mesh.from_pydata(vertices, [], faces)
408         """
409         mesh.add_geometry(len(vertices), 0, len(faces))
410         # add vertex
411         unpackedVertices=[]
412         for v in vertices:
413             unpackedVertices.extend(v)
414         mesh.vertices.foreach_set("co", unpackedVertices)
415         # add face
416         unpackedFaces = []
417         for face in faces:
418             if len(face) == 4:
419                 if face[3] == 0:
420                     # rotate indices if the 4th is 0
421                     face = [face[3], face[0], face[1], face[2]]
422             elif len(face) == 3:
423                 if face[2] == 0:
424                     # rotate indices if the 3rd is 0
425                     face = [face[2], face[0], face[1], 0]
426                 else:
427                     face.append(0)
428             unpackedFaces.extend(face)
429         mesh.faces.foreach_set("verts_raw", unpackedFaces)
430         """
431         assert(len(vertices)==len(mesh.vertices))
432         assert(len(faces)==len(mesh.faces))
433
434     @staticmethod
435     def hasUV(mesh):
436         return len(mesh.uv_textures)>0
437
438     @staticmethod
439     def useVertexUV(mesh):
440         pass
441
442     @staticmethod
443     def addUV(mesh):
444         mesh.uv_textures.new()
445
446     @staticmethod
447     def hasFaceUV(mesh, i, face):
448         active_uv_texture=None
449         for t in mesh.uv_textures:
450             if t.active:
451                 active_uv_texture=t
452                 break
453         return active_uv_texture and active_uv_texture.data[i]
454
455     @staticmethod
456     def getFaceUV(mesh, i, faces, count=3):
457         active_uv_texture=None
458         for t in mesh.uv_textures:
459             if t.active:
460                 active_uv_texture=t
461                 break
462         if active_uv_texture and active_uv_texture.data[i]:
463             uvFace=active_uv_texture.data[i]
464             if count==3:
465                 return (uvFace.uv1, uvFace.uv2, uvFace.uv3)
466             elif count==4:
467                 return (uvFace.uv1, uvFace.uv2, uvFace.uv3, uvFace.uv4)
468             else:
469                 print(count)
470                 assert(False)
471         else:
472             return ((0, 0), (0, 0), (0, 0), (0, 0))
473
474     @staticmethod
475     def setFaceUV(m, i, face, uv_array, image):
476         uv_face=m.uv_textures[0].data[i]
477         uv_face.uv=uv_array
478         if image:
479             uv_face.image=image
480             #uv_face.use_image=True
481
482     @staticmethod
483     def vertsDelete(m, remove_vertices):
484         enterEditMode()
485         bpy.ops.mesh.select_all(action='DESELECT')
486         enterObjectMode()
487
488         for i in remove_vertices:
489             m.vertices[i].select=True
490
491         enterEditMode()
492         bpy.ops.mesh.delete(type='VERT')
493         enterObjectMode()
494
495     @staticmethod
496     def setSmooth(m, smoothing):
497         m.auto_smooth_angle=int(smoothing)
498         m.use_auto_smooth=True
499
500     @staticmethod
501     def recalcNormals(mesh_object):
502         bpy.ops.object.select_all(action='DESELECT')
503         object.activate(mesh_object)
504         enterEditMode()
505         bpy.ops.mesh.normals_make_consistent()
506         enterObjectMode()
507
508     @staticmethod
509     def flipNormals(m):
510         m.flipNormals()
511
512     @staticmethod
513     def addMaterial(m, material):
514         m.materials.append(material)
515
516     @staticmethod
517     def getMaterial(m, index):
518         return m.materials[index]
519
520
521 class vertex:
522     @staticmethod
523     def setNormal(v, normal):
524         v.normal=mathutils.Vector(normal)
525
526     @staticmethod
527     def getNormal(v):
528         return v.normal
529
530     @staticmethod
531     def setUv(v, uv):
532         # sticky ?
533         pass
534
535
536 class face:
537     @staticmethod
538     def getVertexCount(face):
539         return len(face.vertices)
540
541     @staticmethod
542     def getVertices(face):
543         return face.vertices[:]
544
545     @staticmethod
546     def getIndices(face, count=3):
547         if count==3:
548             return [face.vertices[0], face.vertices[1], face.vertices[2]]
549         elif count==4:
550             return [face.vertices[0], face.vertices[1], face.vertices[2], face.vertices[3]]
551         else:
552             assert(False)
553
554     @staticmethod
555     def setMaterial(face, material_index):
556         face.material_index=material_index
557
558     @staticmethod
559     def getMaterialIndex(face):
560         return face.material_index
561
562     @staticmethod
563     def setNormal(face, normal):
564         face.normal=normal
565
566     @staticmethod
567     def getNormal(face):
568         return face.normal
569
570     @staticmethod
571     def setSmooth(face, isSmooth):
572         face.use_smooth=True if isSmooth else False
573
574
575 class armature:
576     @staticmethod
577     def create():
578         global SCENE
579         armature = bpy.data.armatures.new('Armature')
580         armature_object=bpy.data.objects.new('Armature', armature)
581         SCENE.objects.link(armature_object)
582
583         armature_object.show_x_ray=True
584         armature.show_names=True
585         #armature.draw_type='OCTAHEDRAL'
586         armature.draw_type='STICK'
587         armature.use_deform_envelopes=False
588         armature.use_deform_vertex_groups=True
589         armature.use_mirror_x=True
590
591         return armature, armature_object
592
593     @staticmethod
594     def makeEditable(armature_object):
595         global SCENE
596         # select only armature object and set edit mode
597         SCENE.objects.active=armature_object
598         bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
599         bpy.ops.object.mode_set(mode='EDIT', toggle=False)
600
601     @staticmethod
602     def createIkConstraint(armature_object, p_bone, effector_name, 
603             chain, weight, iterations):
604         constraint = p_bone.constraints.new('IK')
605         constraint.chain_count=len(chain)
606         constraint.target=armature_object
607         constraint.subtarget=effector_name
608         constraint.use_tail=False
609         # ToDo
610         # not used. place folder when export.
611         #constraint.weight=weight
612         #constraint.iterations=iterations * 10
613         return constraint
614
615     @staticmethod
616     def createBone(armature, name):
617         return armature.edit_bones.new(name)
618
619     @staticmethod
620     def update(armature):
621         pass
622
623
624 class bone:
625     @staticmethod
626     def setConnected(bone):
627         bone.use_connect=True
628
629     @staticmethod
630     def isConnected(bone):
631         return bone.use_connect
632
633     @staticmethod
634     def setLayerMask(bone, layers):
635         layer=[]
636         for i in range(32):
637             try:
638                 layer.append(True if layers[i]!=0 else False)
639             except IndexError:
640                 layer.append(False)
641         bone.layers=layer
642
643     @staticmethod
644     def getHeadLocal(b):
645         return b.head_local[0:3]
646
647     @staticmethod
648     def getTailLocal(b):
649         return b.tail_local[0:3]
650
651
652 class constraint:
653     @staticmethod
654     def ikChainLen(c):
655         return c.chain_count
656
657     @staticmethod
658     def ikTarget(c):
659         return c.subtarget
660
661     @staticmethod
662     def ikItration(c):
663         return c.iterations
664
665     @staticmethod
666     def ikRotationWeight(c):
667         return c.weight
668
669     @staticmethod
670     def isIKSolver(c):
671         return c.type=='IK'
672
673 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
674 MMD_MB_NAME='mb_name'
675 MMD_MB_COMMENT='mb_comment'
676 MMD_COMMENT='comment'
677 BASE_SHAPE_NAME='Basis'
678 RIGID_NAME='rigid_name'
679 RIGID_SHAPE_TYPE='rigid_shape_type'
680 RIGID_PROCESS_TYPE='rigid_process_type'
681 RIGID_BONE_NAME='rigid_bone_name'
682 RIGID_GROUP='ribid_group'
683 RIGID_INTERSECTION_GROUP='rigid_intersection_group'
684 RIGID_WEIGHT='rigid_weight'
685 RIGID_LINEAR_DAMPING='rigid_linear_damping'
686 RIGID_ANGULAR_DAMPING='rigid_angular_damping'
687 RIGID_RESTITUTION='rigid_restitution'
688 RIGID_FRICTION='rigid_friction'
689 CONSTRAINT_NAME='const_name'
690 CONSTRAINT_A='const_a'
691 CONSTRAINT_B='const_b'
692 CONSTRAINT_POS_MIN='const_pos_min'
693 CONSTRAINT_POS_MAX='const_pos_max'
694 CONSTRAINT_ROT_MIN='const_rot_min'
695 CONSTRAINT_ROT_MAX='const_rot_max'
696 CONSTRAINT_SPRING_POS='const_spring_pos'
697 CONSTRAINT_SPRING_ROT='const_spring_rot'
698 TOON_TEXTURE_OBJECT='ToonTextures'
699