OSDN Git Service

a8439382d559bd760871ca5b94d29d6e786d19ef
[meshio/meshio.git] / swig / blender / bl24.py
1 # coding: utf-8
2 import sys
3 import os
4 import Blender
5 from Blender import Mathutils
6 import bpy
7
8
9 # ファイルシステムの文字コード
10 # 改造版との共用のため
11 FS_ENCODING=sys.getfilesystemencoding()
12 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
13     INTERNAL_ENCODING='utf-8'
14 else:
15     INTERNAL_ENCODING=FS_ENCODING
16
17
18 ###############################################################################
19 # Writer
20 ###############################################################################
21 class Writer(object):
22     def __init__(self, path, encoding):
23         self.io=open(path, "wb")
24         self.encoding=encoding
25
26     def write(self, s):
27         self.io.write(s)
28
29     def flush(self):
30         self.io.flush()
31
32     def close(self):
33         self.io.close()
34
35
36 ###############################################################################
37 # ProgressBar
38 ###############################################################################
39 class ProgressBar(object):
40     def __init__(self, base):
41         print("#### %s ####" % base)
42         self.base=base
43         self.start=Blender.sys.time() 
44         self.set('<start>', 0)
45
46     def advance(self, message, progress):
47         self.progress+=float(progress)
48         self._print(message)
49
50     def set(self, message, progress):
51         self.progress=float(progress)
52         self._print(message)
53
54     def _print(self, message):
55         print(message)
56         message="%s: %s" % (self.base, message)
57         if message.__class__ is unicode:
58             message=message.encode(FS_ENCODING)
59         Blender.Window.DrawProgressBar(self.progress, message)
60
61     def finish(self):
62         self.progress=1.0
63         message='finished in %.2f sec' % (Blender.sys.time()-self.start)
64         self.set(message, 1.0)
65
66
67 def progress_start(base):
68     global progressBar
69     progressBar=ProgressBar(base)
70
71 def progress_finish():
72     global progressBar
73     progressBar.finish()
74
75 def progress_print(message, progress=0.05):
76     global progressBar
77     progressBar.advance(message, progress)
78
79 def progress_set(message, progress):
80     global progressBar
81     progressBar.set(message, progress)
82
83
84 ###############################################################################
85 # for mqo mikoto bone.
86 ###############################################################################
87 class MikotoBone(object):
88     __slots__=[
89             'name',
90             'iHead', 'iTail', 'iUp',
91             'vHead', 'vTail', 'vUp',
92             'parent', 'isFloating',
93             'children',
94             ]
95     def __init__(self, face=None, vertices=None, materials=None):
96         self.parent=None
97         self.isFloating=False
98         self.children=[]
99         if not face:
100             self.name='root'
101             return
102
103         self.name=materials[face.material_index].name.encode('utf-8')
104
105         i0=face.indices[0]
106         i1=face.indices[1]
107         i2=face.indices[2]
108         v0=vertices[i0]
109         v1=vertices[i1]
110         v2=vertices[i2]
111         e01=v1-v0
112         e12=v2-v1
113         e20=v0-v2
114         sqNorm0=e01.getSqNorm()
115         sqNorm1=e12.getSqNorm()
116         sqNorm2=e20.getSqNorm()
117         if sqNorm0>sqNorm1:
118             if sqNorm1>sqNorm2:
119                 # e01 > e12 > e20
120                 self.iHead=i2
121                 self.iTail=i1
122                 self.iUp=i0
123             else:
124                 if sqNorm0>sqNorm2:
125                     # e01 > e20 > e12
126                     self.iHead=i2
127                     self.iTail=i0
128                     self.iUp=i1
129                 else:
130                     # e20 > e01 > e12
131                     self.iHead=i1
132                     self.iTail=i0
133                     self.iUp=i2
134         else:
135             # 0 < 1
136             if sqNorm1<sqNorm2:
137                 # e20 > e12 > e01
138                 self.iHead=i1
139                 self.iTail=i2
140                 self.iUp=i0
141             else:
142                 if sqNorm0<sqNorm2:
143                     # e12 > e20 > e01
144                     self.iHead=i0
145                     self.iTail=i2
146                     self.iUp=i1
147                 else:
148                     # e12 > e01 > e20
149                     self.iHead=i0
150                     self.iTail=i1
151                     self.iUp=i2
152         self.vHead=vertices[self.iHead]
153         self.vTail=vertices[self.iTail]
154         self.vUp=vertices[self.iUp]
155
156         if self.name.endswith('[]'):
157             basename=self.name[0:-2]
158             # expand LR name
159             if self.vTail.x>0:
160                 self.name="%s_L" % basename
161             else:
162                 self.name="%s_R" % basename
163
164
165     def setParent(self, parent, floating=False):
166         if floating:
167             self.isFloating=True
168         self.parent=parent
169         parent.children.append(self)
170
171     def printTree(self, indent=''):
172         print("%s%s" % (indent, self.name))
173         for child in self.children:
174             child.printTree(indent+'  ')
175
176
177 def build_armature(armature, mikotoBone, parent=None):
178     """
179     create a armature bone.
180     """
181     bone = Armature.Editbone()
182     bone.name = mikotoBone.name.encode('utf-8')
183     armature.bones[bone.name] = bone
184
185     bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())
186     bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())
187     if parent:
188         bone.parent=parent
189         if mikotoBone.isFloating:
190             pass
191         else:
192             bone.options=[Armature.CONNECTED]
193
194     for child in mikotoBone.children:
195         build_armature(armature, child, bone)
196
197
198 def create_armature(scene, mqo):
199     """
200     create armature
201     """
202     boneObject=None
203     for o in mqo.objects:
204         if o.name.startswith('bone'):
205             boneObject=o
206             break
207     if not boneObject:
208         return
209
210     tailMap={}
211     for f in boneObject.faces:
212         if f.index_count!=3:
213             print("invalid index_count: %d" % f.index_count)
214             continue
215         b=MikotoBone(f, boneObject.vertices, mqo.materials)
216         tailMap[b.iTail]=b
217
218     #################### 
219     # build mikoto bone tree
220     #################### 
221     mikotoRoot=MikotoBone()
222
223     for b in tailMap.values():
224         # each bone has unique parent or is root bone.
225         if b.iHead in tailMap:
226             b.setParent(tailMap[b.iHead])
227         else: 
228             isFloating=False
229             for e in boneObject.edges:
230                 if  b.iHead==e.indices[0]:
231                     # floating bone
232                     if e.indices[1] in tailMap:
233                         b.setParent(tailMap[e.indices[1]], True)
234                         isFloating=True
235                         break
236                 elif b.iHead==e.indices[1]:
237                     # floating bone
238                     if e.indices[0] in tailMap:
239                         b.setParent(tailMap[e.indices[0]], True)
240                         isFloating=True
241                         break
242             if isFloating:
243                 continue
244
245             # no parent bone
246             b.setParent(mikotoRoot, True)
247
248     if len(mikotoRoot.children)==0:
249         print("no root bone")
250         return
251
252     if len(mikotoRoot.children)==1:
253         # single root
254         mikotoRoot=mikotoRoot.children[0]
255         mikotoRoot.parent=None
256     else:
257         mikotoRoot.vHead=Vector3(0, 10, 0)
258         mikotoRoot.vTail=Vector3(0, 0, 0)
259
260     #################### 
261     # create armature
262     #################### 
263     armature = Armature.New()
264     # link to object
265     armature_object = scene.objects.new(armature)
266     # create action
267     act = Armature.NLA.NewAction()
268     act.setActive(armature_object)
269     # set XRAY
270     armature_object.drawMode |= Object.DrawModes.XRAY
271     # armature settings
272     armature.drawType = Armature.OCTAHEDRON
273     armature.envelopes = False
274     armature.vertexGroups = True
275     armature.mirrorEdit = True
276     armature.drawNames=True
277
278     # edit bones
279     armature.makeEditable()
280     build_armature(armature, mikotoRoot)
281     armature.update()
282
283     return armature_object
284         
285
286 class TrianglePlane(object):
287     """
288     mikoto方式ボーンのアンカーウェイト計算用。
289     (不完全)
290     """
291     __slots__=['normal', 
292             'v0', 'v1', 'v2',
293             ]
294     def __init__(self, v0, v1, v2):
295         self.v0=v0
296         self.v1=v1
297         self.v2=v2
298
299     def isInsideXY(self, p):
300         v0=Vector2(self.v0.x, self.v0.y)
301         v1=Vector2(self.v1.x, self.v1.y)
302         v2=Vector2(self.v2.x, self.v2.y)
303         e01=v1-v0
304         e12=v2-v1
305         e20=v0-v2
306         c0=Vector2.cross(e01, p-v0)
307         c1=Vector2.cross(e12, p-v1)
308         c2=Vector2.cross(e20, p-v2)
309         if c0>=0 and c1>=0 and c2>=0:
310             return True
311         if c0<=0 and c1<=0 and c2<=0:
312             return True
313
314     def isInsideYZ(self, p):
315         v0=Vector2(self.v0.y, self.v0.z)
316         v1=Vector2(self.v1.y, self.v1.z)
317         v2=Vector2(self.v2.y, self.v2.z)
318         e01=v1-v0
319         e12=v2-v1
320         e20=v0-v2
321         c0=Vector2.cross(e01, p-v0)
322         c1=Vector2.cross(e12, p-v1)
323         c2=Vector2.cross(e20, p-v2)
324         if c0>=0 and c1>=0 and c2>=0:
325             return True
326         if c0<=0 and c1<=0 and c2<=0:
327             return True
328
329     def isInsideZX(self, p):
330         v0=Vector2(self.v0.z, self.v0.x)
331         v1=Vector2(self.v1.z, self.v1.x)
332         v2=Vector2(self.v2.z, self.v2.x)
333         e01=v1-v0
334         e12=v2-v1
335         e20=v0-v2
336         c0=Vector2.cross(e01, p-v0)
337         c1=Vector2.cross(e12, p-v1)
338         c2=Vector2.cross(e20, p-v2)
339         if c0>=0 and c1>=0 and c2>=0:
340             return True
341         if c0<=0 and c1<=0 and c2<=0:
342             return True
343
344
345 class MikotoAnchor(object):
346     """
347     mikoto方式スケルトンのアンカー。
348     """
349     __slots__=[
350             "triangles", "bbox",
351             ]
352     def __init__(self):
353         self.triangles=[]
354         self.bbox=None
355
356     def push(self, face, vertices):
357         if face.index_count==3:
358             self.triangles.append(TrianglePlane(
359                 vertices[face.indices[0]],
360                 vertices[face.indices[1]],
361                 vertices[face.indices[2]]
362                 ))
363         elif face.index_count==4:
364             self.triangles.append(TrianglePlane(
365                 vertices[face.indices[0]],
366                 vertices[face.indices[1]],
367                 vertices[face.indices[2]]
368                 ))
369             self.triangles.append(TrianglePlane(
370                 vertices[face.indices[2]],
371                 vertices[face.indices[3]],
372                 vertices[face.indices[0]]
373                 ))
374         # bounding box
375         if not self.bbox:
376             self.bbox=BoundingBox(vertices[face.indices[0]])
377         for i in face.indices:
378             self.bbox.expand(vertices[i])
379
380
381     def calcWeight(self, v):
382         if not self.bbox.isInside(v):
383             return 0
384
385         if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):
386             return 1.0
387         else:
388             return 0
389         
390     def anyXY(self, x, y):
391         for t in self.triangles:
392             if t.isInsideXY(Vector2(x, y)):
393                 return True
394         return False
395
396     def anyYZ(self, y, z):
397         for t in self.triangles:
398             if t.isInsideYZ(Vector2(y, z)):
399                 return True
400         return False
401
402     def anyZX(self, z, x):
403         for t in self.triangles:
404             if t.isInsideZX(Vector2(z, x)):
405                 return True
406         return False
407
408
409 def create_bone_weight(scene, mqo, armature_object, objects):
410     """
411     create mikoto bone weight.
412     """
413     anchorMap={}
414     # setup mikoto anchors
415     for o in mqo.objects:
416         if o.name.startswith("anchor"):
417             for f in o.faces:
418                 name=mqo.materials[f.material_index].name
419                 if name.endswith('[]'):
420                     basename=name[0:-2]
421                     v=o.vertices[f.indices[0]]
422                     if(v.x>0):
423                         # L
424                         name_L=basename+'_L'
425                         if not name_L in anchorMap:
426                             anchorMap[name_L]=MikotoAnchor()
427                         anchorMap[name_L].push(f, o.vertices)
428                     elif(v.x<0):
429                         # R
430                         name_R=basename+'_R'
431                         if not name_R in anchorMap:
432                             anchorMap[name_R]=MikotoAnchor()
433                         anchorMap[name_R].push(f, o.vertices)
434                     else:
435                         print("no side", v)
436                 else:
437                     if not name in anchorMap:
438                         anchorMap[name]=MikotoAnchor()
439                     anchorMap[name].push(f, o.vertices)
440
441     for o in objects:
442         # add armature modifier
443         mod=o.modifiers.append(Modifier.Types.ARMATURE)
444         mod[Modifier.Settings.OBJECT] = armature_object
445         mod[Modifier.Settings.ENVELOPES] = False
446         o.makeDisplayList()
447         # create vertex group
448         mesh=o.getData(mesh=True)
449         for name in anchorMap.keys():
450             mesh.addVertGroup(name)
451         mesh.update()
452                  
453     # assing vertices to vertex group
454     for o in objects:
455         mesh=o.getData(mesh=True)
456         for i, mvert in enumerate(mesh.verts):
457             hasWeight=False
458             for name, anchor in anchorMap.items():
459                 weight=anchor.calcWeight(mvert.co)
460                 if weight>0:
461                     mesh.assignVertsToGroup(
462                             name, [i], weight, Mesh.AssignModes.ADD)
463                     hasWeight=True
464             if not hasWeight:
465                 # debug orphan vertex
466                 print('orphan', mvert)
467         mesh.update()
468
469 ###############################################################################
470 def createEmptyObject(scene, name):
471     empty=scene.objects.new("Empty")
472     empty.setName(name)
473     return empty
474
475 def createMaterial(name):
476     material = Blender.Material.New(name)
477     return material
478
479 def createMqoMaterial(m):
480     material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
481     material.mode |= Blender.Material.Modes.SHADELESS
482     material.rgbCol = [m.color.r, m.color.g, m.color.b]
483     material.alpha = m.color.a
484     material.amb = m.ambient
485     material.spec = m.specular
486     material.hard = int(255 * m.power)
487     return material
488
489 def createPmdMaterial(m):
490     material=Blender.Material.New()
491     material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
492     material.setRef(1)
493     material.diffuseSize = 3.14/2
494     material.setDiffuseSmooth(0)
495     material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
496     material.setSpecSize(0)
497     material.setSpec(0)
498     material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
499     material.setAlpha(m.diffuse.a)
500     material.setSpec(m.shinness*0.1)
501     material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
502     material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
503     material.enableSSS=True if m.flag==1 else False
504     return material
505
506 def createTexture(path):
507     image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
508     texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
509     texture.type = Blender.Texture.Types.IMAGE
510     texture.image = image
511     return texture, image
512
513 def materialAddTexture(material, texture):
514     material.mode = material.mode | Blender.Material.Modes.TEXFACE
515     material.setTexture(0, texture, Blender.Texture.TexCo.UV)
516
517
518 def createMesh(scene, name):
519     mesh = Blender.Mesh.New()
520     mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
521     return mesh, mesh_object
522
523
524 def objectMakeParent(parent, child):
525     parent.makeParent([child])
526
527
528 def meshAddMaterial(mesh, material):
529     mesh.materials+=[material]
530
531
532 def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
533     # add vertices
534     mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
535     mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
536     # add faces
537     mesh_faces=[]
538     for face in o.faces:
539         face_indices=[]
540         for i in xrange(face.index_count):
541             face_indices.append(face.getIndex(i)+1)
542         mesh_faces.append(face_indices)
543     #new_faces=mesh.faces.extend([face.indices for face in o.faces], 
544     new_faces=mesh.faces.extend(mesh_faces,
545             #ignoreDups=True, 
546             indexList=True)
547     mesh.update()
548     
549     # gather used materials
550     materialMap = {}
551     if new_faces:
552         for i in new_faces:
553             if type(i) is int:
554                 materialMap[o.faces[i].material_index]=True
555
556     # blender limits 16 materials per mesh
557     # separate mesh ?
558     for i, material_index in enumerate(materialMap.keys()):
559         if i>=16:
560             print("over 16 materials!")
561             break
562         mesh.materials+=[materials[material_index]]
563         materialMap[material_index]=i
564     
565     # set face params
566     for i, f in enumerate(o.faces):       
567         if not type(new_faces[i]) is int:
568             continue
569
570         face=mesh.faces[new_faces[i]]
571
572         uv_array=[]
573         for i in xrange(f.index_count):
574             uv_array.append(Blender.Mathutils.Vector(
575                 f.getUV(i).x, 
576                 1.0-f.getUV(i).y)
577                 )
578         try:
579             face.uv=uv_array
580         except Exception as msg:
581             #print msg
582             #print face.index, uv_array
583             pass
584     
585         if f.material_index in materialMap:
586             face.mat = materialMap[f.material_index]
587
588         face.smooth = 1
589
590     # rmeove dummy 0 vertex
591     mesh.verts.delete(0)
592         
593     mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
594     mesh.maxSmoothAngle = int(o.smoothing)
595     mesh.smooth()
596     mesh.calcNormals()
597     mesh.flipNormals()
598     mesh.update()
599
600     # mirror modifier
601     if o.mirror:
602         mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
603
604 def getTexture(m, dirname):
605     tex=""
606     aplane=""
607     # texture
608     for texture in m.getTextures():
609         if texture and texture.tex and texture.tex.getImage():
610             image=texture.tex.getImage()
611             if not image:
612                 continue
613             imagePath=Blender.sys.expandpath(image.getFilename())
614             if len(dirname)>0 and imagePath.startswith(dirname):
615                 # 相対パスに変換する
616                 imagePath=imagePath[len(dirname)+1:len(imagePath)]
617             if texture.mtCol>0:
618                 tex=" tex(\"%s\")" % imagePath
619             elif texture.mtAlpha>0:
620                 aplane=" aplane(\"%s\")" % imagePath
621     return tex, aplane
622
623 def objectDuplicate(scene, obj):
624     mesh, dumy=createMesh(scene, obj.name.decode(INTERNAL_ENCODING))
625     # not apply modifiers
626     mesh.getFromObject(obj.name, 1)
627     # apply matrix
628     dumy.setMatrix(obj.matrixWorld)
629     return mesh, dumy
630
631 def objectDelete(scene, obj):
632     scene.objects.unlink(obj)
633
634 def faceVertexCount(face):
635     return len(face.v)
636
637 def faceVertices(face):
638     # flip
639     return [v.index for v in reversed(face.v)]
640
641 def meshHasUV(mesh):
642     return mesh.faceUV
643
644 def faceHasUV(mesh, i, face):
645     return len(face.uv)>0
646
647 def faceGetUV(mesh, i, face, count):
648     # flip
649     return reversed(face.uv)
650
651 def materialToMqo(m):
652     return "\"%s\" shader(3) col(%f %f %f %f)" % (
653             m.name, m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha)
654
655 def faceMaterialIndex(face):
656     return face.mat
657
658 def objectGetData(o):
659     return o.getData(mesh=True)
660
661 def objectAddArmatureModifier(o, armature_object):
662     mod=o.modifiers.append(Blender.Modifier.Types.ARMATURE)
663     mod[Blender.Modifier.Settings.OBJECT] = armature_object
664     mod[Blender.Modifier.Settings.ENVELOPES] = False
665
666 def objectSelect(o):
667     o.select(True)
668
669 def objectGetPose(o):
670     return o.getPose()
671
672 def poseBoneLimit(n, b):
673     if n.endswith("_t"):
674         return
675     if n.startswith("knee_"):
676         b.lockYRot=True
677         b.lockZRot=True
678         b.limitX=True
679         b.limitMin=[0, 0, 0]
680         b.limitMax=[180, 0, 0]
681     elif n.startswith("ankle_"):
682         b.lockYRot=True
683
684 def enterEditMode():
685     Blender.Window.EditMode(1)
686
687 def exitEditMode():
688     Blender.Window.EditMode(0)
689
690 def objectDeselectAll():
691     for o in bpy.data.scenes.active.objects:
692         o.select(False)
693
694 def objectActivate(scene, o):
695     o.select(True )
696     scene.objects.active=o
697
698 def objectGetActive(scene):
699     return scene.objects.active
700
701 def meshAddVertexGroup(meshObject, name):
702     meshObject.getData(mesh=True).addVertGroup(name)
703
704 def meshUseVertexUv(mesh):
705     mesh.vertexUV = 1
706
707 def vertexSetNormal(mvert, normal):
708     mvert.no=Mathutils.Vector(*normal)
709
710 def vertexSetUv(mvert, uv):
711     mvert.uvco=uv
712
713 def meshAssignVertexGroup(meshObject, name, index, weight):
714     meshObject.getData(mesh=True).assignVertsToGroup(name, 
715             [index], weight, Blender.Mesh.AssignModes.ADD)
716
717 def meshCreateVerteicesAndFaces(mesh, vertices, faces):
718     mesh.verts.extend(vertices)
719     mesh.faces.extend(faces, ignoreDups=True)
720
721 def meshAddUV(mesh):
722     mesh.addUVLayer('NewUV')
723
724 def meshVertsDelete(mesh, remove_vertices):
725     mesh.verts.delete(remove_vertices)
726
727 def createArmature(scene):
728     armature = Blender.Armature.New()
729     armature_object = scene.objects.new(armature)
730
731     # set XRAY
732     armature_object.drawMode = (
733             armature_object.drawMode | Blender.Object.DrawModes.XRAY)
734     # armature settings
735     armature.drawType = Blender.Armature.OCTAHEDRON
736     armature.drawNames=True
737     armature.envelopes = False
738     armature.vertexGroups = True
739     armature.mirrorEdit = True
740
741     return armature, armature_object
742
743 def armatureMakeEditable(scene, armature_object):
744     # create armature
745     armature_object.getData().makeEditable()
746
747 def createIkConstraint(armature_object, p_bone, effector_name, ik):
748     cSetting = Blender.Constraint.Settings
749     # IK solver
750     constraint = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
751     constraint[cSetting.CHAINLEN]=len(ik.children)
752     constraint[cSetting.TARGET]=armature_object
753     constraint[cSetting.USETIP]=False
754     constraint[cSetting.BONE]=effector_name
755     # not used. place folder when export.
756     constraint[cSetting.ROTWEIGHT]=ik.weight
757     constraint[cSetting.ITERATIONS]=ik.iterations * 10
758     return constraint
759
760 def createArmatureBone(armature, name):
761     bone=Blender.Armature.Editbone()
762     bone.name=name.encode(INTERNAL_ENCODING)
763     armature.bones[name]=bone
764     return bone
765
766 def boneSetConnected(bone):
767     bone.options+=[Blender.Armature.CONNECTED]
768
769 def createVector(x, y, z):
770     return Mathutils.Vector(x, y, z)
771
772 def armatureUpdate(armature):
773     armature.update()
774
775 def boneLayerMask(bone, layers):
776     mask=0
777     for i, enable in enumerate(layers):
778         if enable!=0:
779             mask+=(1<<i)
780     bone.layerMask=mask
781
782 def objectPinShape(o):
783     o.pinShape=True
784
785 def objectAddShapeKey(o, name):
786     mesh=o.getData(mesh=True)
787     mesh.insertKey()
788     block=mesh.key.blocks[-1]
789     block.name=name.encode(INTERNAL_ENCODING)
790     return block
791
792 def objectActivateShapeKey(o, index):
793     o.activeShape=index
794
795 def shapeKeyAssign(shapeKey, index, pos):
796     shapeKey.data[index]=pos
797
798 def objectIsVisible(obj):
799     return obj.restrictDisplay
800
801 def meshVertexGroupNames(meshObject):
802     return meshObject.getData(mesh=True).getVertGroupNames()
803
804 def faceNormal(face):
805     return face.no
806
807 def meshFaceUv(mesh, i, face):
808     return face.uv
809
810 def armatureModifierGetObject(m):
811     return m[Blender.Modifier.Settings.OBJECT]
812
813 def objectHasShapeKey(o):
814     return o.getData(mesh=True).key
815
816 def objectShapeKeys(o):
817     return o.getData(mesh=True).key.blocks
818
819 def meshVertexGroup(meshObject, name):
820     indices=[]
821     for index in meshObject.getData(mesh=True).getVertsFromGroup(name):
822         indices.append(index)
823     return indices
824
825 def materialGet(scene, material_name):
826     return Blender.Material.Get(material_name)
827
828 def modifierIsArmature(m):
829     return m.name=="Armature"
830
831 def boneHeadLocal(b):
832     return b.head['ARMATURESPACE'][0:3]
833
834 def boneTailLocal(b):
835     return b.tail['ARMATURESPACE'][0:3]
836
837 def boneIsConnected(b):
838     return Blender.Armature.CONNECTED in b.options
839
840 def constraintIsIKSolver(c):
841     return c.type==Blender.Constraint.Type.IKSOLVER
842
843 def ikChainLen(c):
844     return c[Blender.Constraint.Settings.CHAINLEN]
845
846 def ikTarget(c):
847     return c[Blender.Constraint.Settings.BONE]
848
849 def ikItration(c):
850     return c[Blender.Constraint.Settings.ITERATIONS]
851
852 def ikRotationWeight(c):
853     return c[Blender.Constraint.Settings.ROTWEIGHT]
854
855 def shapeKeyGet(b, index):
856     return b.data[index]
857
858 def shapeKeys(b):
859     return b.data
860