Scripts:
[blender.git] / release / scripts / mod_meshtools.py
1 # $Id$
2 #
3 # +---------------------------------------------------------+
4 # | Copyright (c) 2001 Anthony D'Agostino                   |
5 # | http://www.redrival.com/scorpius                        |
6 # | scorpius@netzero.com                                    |
7 # | September 28, 2002                                      |
8 # | Released under the Blender Artistic Licence (BAL)       |
9 # | Import Export Suite v0.5                                |
10 # +---------------------------------------------------------+
11 # | Common Functions & Global Variables For All IO Modules  |
12 # +---------------------------------------------------------+
13
14 import Blender
15 import sys
16
17 show_progress = 1                       # Set to 0 for faster performance
18 average_vcols = 1                       # Off for per-face, On for per-vertex
19 overwrite_mesh_name = 0         # Set to 0 to increment object-name version
20
21 blender_version = Blender.Get('version')
22 blender_version_str = `blender_version`[0] + '.' + `blender_version`[1:]
23
24 try:
25         import operator
26 except:
27         msg = "Error: you need a full Python install to run this script."
28         mod_meshtools.print_boxed(msg)
29         Blender.Draw.PupMenu("ERROR%t|"+msg)
30
31 # =================================
32 # === Append Faces To Face List ===
33 # =================================
34 def append_faces(mesh, faces, facesuv, uvcoords):
35         for i in range(len(faces)):
36                 if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Generating Faces")
37                 numfaceverts=len(faces[i])
38                 if numfaceverts <= 4:                           # This face is a triangle or quad
39                         face = Blender.NMesh.Face()
40                         for j in range(numfaceverts):
41                                 index = faces[i][j]
42                                 face.v.append(mesh.verts[index])
43                                 if len(uvcoords) > 1:
44                                         uvidx = facesuv[i][j]
45                                         face.uv.append(uvcoords[uvidx])
46                                         face.mode = 0
47                                         face.col = [Blender.NMesh.Col()]*4
48                         mesh.faces.append(face)
49                 else:                                                           # Triangulate n-sided convex polygon.
50                         a, b, c = 0, 1, 2                               # Indices of first triangle.
51                         for j in range(numfaceverts-2): # Number of triangles in polygon.
52                                 face = Blender.NMesh.Face()
53                                 face.v.append(mesh.verts[faces[i][a]])
54                                 face.v.append(mesh.verts[faces[i][b]])
55                                 face.v.append(mesh.verts[faces[i][c]])
56                                 b = c; c += 1
57                                 mesh.faces.append(face)
58                 #face.smooth = 1
59
60 # ===================================
61 # === Append Verts to Vertex List ===
62 # ===================================
63 def append_verts(mesh, verts, normals):
64         #print "Number of normals:", len(normals)
65         #print "Number of verts  :", len(verts)
66         for i in range(len(verts)):
67                 if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(verts), "Generating Verts")
68                 x, y, z = verts[i]
69                 mesh.verts.append(Blender.NMesh.Vert(x, y, z))
70                 if normals:
71                         mesh.verts[i].no[0] = normals[i][0]
72                         mesh.verts[i].no[1] = normals[i][1]
73                         mesh.verts[i].no[2] = normals[i][2]
74
75 # ===========================
76 # === Create Blender Mesh ===
77 # ===========================
78 def create_mesh(verts, faces, objname, facesuv=[], uvcoords=[], normals=[]):
79         if normals: normal_flag = 0
80         else: normal_flag = 1
81         mesh = Blender.NMesh.GetRaw()
82         append_verts(mesh, verts, normals)
83         append_faces(mesh, faces, facesuv, uvcoords)
84         if not overwrite_mesh_name:
85                 objname = versioned_name(objname)
86         Blender.NMesh.PutRaw(mesh, objname, normal_flag)        # Name the Mesh
87         Blender.Object.GetSelected()[0].name=objname            # Name the Object
88         Blender.Redraw()
89
90 # ==============================
91 # === Increment Name Version ===
92 # ==============================
93 def versioned_name(objname):
94         existing_names = []
95         for object in Blender.Object.Get():
96                 existing_names.append(object.name)
97                 existing_names.append(object.data.name)
98         if objname in existing_names: # don't over-write other names
99                 try:
100                         name, ext = objname.split('.')
101                 except ValueError:
102                         name, ext = objname, ''
103                 try:
104                         num = int(ext)
105                         root = name
106                 except ValueError:
107                         root = objname
108                 for i in xrange(1, 1000):
109                         objname = "%s.%03d" % (root, i)
110                         if objname not in existing_names:
111                                 break
112         return objname
113
114 # ===========================
115 # === Print Text In A Box ===
116 # ===========================
117 def print_boxed(text):
118         lines = text.splitlines()
119         maxlinelen = max(map(len, lines))
120         if sys.platform[:3] == "win":
121                 print chr(218)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(191)
122                 for line in lines:
123                         print chr(179) + ' ' + line.ljust(maxlinelen) + ' ' + chr(179)
124                 print chr(192)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(217)
125         else:
126                 print '+-' + '-'*maxlinelen + '-+'
127                 for line in lines: print '| ' + line.ljust(maxlinelen) + ' |'
128                 print '+-' + '-'*maxlinelen + '-+'
129         print '\a\r', # beep when done
130
131 # ===============================================
132 # === Get euler angles from a rotation matrix ===
133 # ===============================================
134 def mat2euler(mat):
135         angle_y = -math.asin(mat[0][2])
136         c = math.cos(angle_y)
137         if math.fabs(c) > 0.005:
138                 angle_x = math.atan2(mat[1][2]/c, mat[2][2]/c)
139                 angle_z = math.atan2(mat[0][1]/c, mat[0][0]/c)
140         else:
141                 angle_x = 0.0
142                 angle_z = -math.atan2(mat[1][0], mat[1][1])
143         return (angle_x, angle_y, angle_z)
144
145 # ==========================
146 # === Transpose A Matrix ===
147 # ==========================
148 def transpose(A):
149         S = len(A)
150         T = len(A[0])
151         B = [[None]*S for i in range(T)]
152         for i in range(T):
153                 for j in range(S):
154                         B[i][j] = A[j][i]
155         return B
156
157 # =======================
158 # === Apply Transform ===
159 # =======================
160 def apply_transform(vertex, matrix):
161         x, y, z = vertex
162         xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
163         xcomponent = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc
164         ycomponent = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc
165         zcomponent = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
166         vertex = [xcomponent, ycomponent, zcomponent]
167         return vertex
168
169 # =========================
170 # === Has Vertex Colors ===
171 # =========================
172 def has_vertex_colors(mesh):
173         # My replacement/workaround for hasVertexColours()
174         # The docs say:
175         # "Warning: If a mesh has both vertex colours and textured faces,
176         # this function will return False. This is due to the way Blender
177         # deals internally with the vertex colours array (if there are
178         # textured faces, it is copied to the textured face structure and
179         # the original array is freed/deleted)."
180         try:
181                 return mesh.faces[0].col[0]
182         except:
183                 return 0
184
185 # ===========================
186 # === Generate Edge Table ===
187 # ===========================
188 def generate_edgetable(mesh):
189         edge_table = {}
190         numfaces = len(mesh.faces)
191
192         for i in range(numfaces):
193                 if not i%100 and show_progress:
194                         Blender.Window.DrawProgressBar(float(i)/numfaces, "Generating Edge Table")
195                 if len(mesh.faces[i].v) == 4:   # Process Quadrilaterals
196                         generate_entry_from_quad(mesh, i, edge_table)
197                 elif len(mesh.faces[i].v) == 3: # Process Triangles
198                         generate_entry_from_tri(mesh, i, edge_table)
199                 else:                                                   # Skip This Face
200                         print "Face #", i, "was skipped."
201
202         # === Sort Edge_Table Keys & Add Edge Indices ===
203         i = 0
204         keys = edge_table.keys()
205         keys.sort()
206         for key in keys:
207                 edge_table[key][6] = i
208                 i += 1
209
210         # === Replace Tuples With Indices ===
211         for key in keys:
212                 for i in [2,3,4,5]:
213                         if edge_table.has_key(edge_table[key][i]):
214                                 edge_table[key][i] = edge_table[edge_table[key][i]][6]
215                         else:
216                                 keyrev = (edge_table[key][i][1], edge_table[key][i][0])
217                                 edge_table[key][i] = edge_table[keyrev][6]
218
219         return edge_table
220
221 # ================================
222 # === Generate Entry From Quad ===
223 # ================================
224 def generate_entry_from_quad(mesh, i, edge_table):
225         vertex4, vertex3, vertex2, vertex1 = mesh.faces[i].v
226
227         if has_vertex_colors(mesh):
228                 vcolor4, vcolor3, vcolor2, vcolor1 = mesh.faces[i].col
229                 Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0)
230                 Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0)
231                 Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0)
232                 Dcol = (vcolor4.r/255.0, vcolor4.g/255.0, vcolor4.b/255.0)
233
234         # === verts are upper case, edges are lower case ===
235         A, B, C, D = vertex1.index, vertex2.index, vertex3.index, vertex4.index
236         a, b, c, d = (A, B), (B, C), (C, D), (D, A)
237
238         if edge_table.has_key((B, A)):
239                 edge_table[(B, A)][1] = i
240                 edge_table[(B, A)][4] = d
241                 edge_table[(B, A)][5] = b
242                 if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol
243         else:
244                 if has_vertex_colors(mesh):
245                         edge_table[(A, B)] = [i, None, d, b, None, None, None, Bcol, None]
246                 else:
247                         edge_table[(A, B)] = [i, None, d, b, None, None, None]
248
249         if edge_table.has_key((C, B)):
250                 edge_table[(C, B)][1] = i
251                 edge_table[(C, B)][4] = a
252                 edge_table[(C, B)][5] = c
253                 if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol
254         else:
255                 if has_vertex_colors(mesh):
256                         edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None]
257                 else:
258                         edge_table[(B, C)] = [i, None, a, c, None, None, None]
259
260         if edge_table.has_key((D, C)):
261                 edge_table[(D, C)][1] = i
262                 edge_table[(D, C)][4] = b
263                 edge_table[(D, C)][5] = d
264                 if has_vertex_colors(mesh): edge_table[(D, C)][8] = Dcol
265         else:
266                 if has_vertex_colors(mesh):
267                         edge_table[(C, D)] = [i, None, b, d, None, None, None, Dcol, None]
268                 else:
269                         edge_table[(C, D)] = [i, None, b, d, None, None, None]
270
271         if edge_table.has_key((A, D)):
272                 edge_table[(A, D)][1] = i
273                 edge_table[(A, D)][4] = c
274                 edge_table[(A, D)][5] = a
275                 if has_vertex_colors(mesh): edge_table[(A, D)][8] = Acol
276         else:
277                 if has_vertex_colors(mesh):
278                         edge_table[(D, A)] = [i, None, c, a, None, None, None, Acol, None]
279                 else:
280                         edge_table[(D, A)] = [i, None, c, a, None, None, None]
281
282 # ====================================
283 # === Generate Entry From Triangle ===
284 # ====================================
285 def generate_entry_from_tri(mesh, i, edge_table):
286         vertex3, vertex2, vertex1 = mesh.faces[i].v
287
288         if has_vertex_colors(mesh):
289                 vcolor3, vcolor2, vcolor1, _vcolor4_ = mesh.faces[i].col
290                 Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0)
291                 Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0)
292                 Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0)
293
294         # === verts are upper case, edges are lower case ===
295         A, B, C = vertex1.index, vertex2.index, vertex3.index
296         a, b, c = (A, B), (B, C), (C, A)
297
298         if edge_table.has_key((B, A)):
299                 edge_table[(B, A)][1] = i
300                 edge_table[(B, A)][4] = c
301                 edge_table[(B, A)][5] = b
302                 if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol
303         else:
304                 if has_vertex_colors(mesh):
305                         edge_table[(A, B)] = [i, None, c, b, None, None, None, Bcol, None]
306                 else:
307                         edge_table[(A, B)] = [i, None, c, b, None, None, None]
308
309         if edge_table.has_key((C, B)):
310                 edge_table[(C, B)][1] = i
311                 edge_table[(C, B)][4] = a
312                 edge_table[(C, B)][5] = c
313                 if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol
314         else:
315                 if has_vertex_colors(mesh):
316                         edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None]
317                 else:
318                         edge_table[(B, C)] = [i, None, a, c, None, None, None]
319
320         if edge_table.has_key((A, C)):
321                 edge_table[(A, C)][1] = i
322                 edge_table[(A, C)][4] = b
323                 edge_table[(A, C)][5] = a
324                 if has_vertex_colors(mesh): edge_table[(A, C)][8] = Acol
325         else:
326                 if has_vertex_colors(mesh):
327                         edge_table[(C, A)] = [i, None, b, a, None, None, None, Acol, None]
328                 else:
329                         edge_table[(C, A)] = [i, None, b, a, None, None, None]
330