df36aec4c9f9c8164a3603adb9d7f6ab6e47faa2
[blender.git] / release / scripts / wings_export.py
1 #!BPY
2
3 """
4 Name: 'Wings3D...'
5 Blender: 232
6 Group: 'Export'
7 Tooltip: 'Export selected mesh to Wings3D File Format (*.wings)'
8 """
9
10 # $Id$
11 #
12 # +---------------------------------------------------------+
13 # | Copyright (c) 2002 Anthony D'Agostino                   |
14 # | http://www.redrival.com/scorpius                        |
15 # | scorpius@netzero.com                                    |
16 # | Feb 19, 2002                                            |
17 # | Released under the Blender Artistic Licence (BAL)       |
18 # | Import Export Suite v0.5                                |
19 # +---------------------------------------------------------+
20 # | Read and write Wings3D File Format (*.wings)            |
21 # +---------------------------------------------------------+
22
23 import Blender, mod_meshtools
24 import struct, time, sys, os, zlib, cStringIO
25
26 # ===============================================
27 # === Write The 'Header' Common To All Chunks ===
28 # ===============================================
29 def write_chunkheader(data, version, tag, name):
30         data.write(struct.pack(">BB", version, tag))
31         data.write(struct.pack(">BH", 0x64, len(name)))
32         data.write(name)
33
34 # ===================
35 # === Write Faces ===
36 # ===================
37 def write_faces(data, mesh):
38         numfaces = len(mesh.faces)
39         data.write(struct.pack(">BL", 0x6C, numfaces))
40         #for i in range(numfaces):
41         #        if not i%100 and mod_meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numfaces, "Writing Faces")
42         #        data.write("\x6A")
43         data.write("\x6A" * numfaces) # same, but faster than the above loop
44         data.write("\x6A")
45
46 # ===================
47 # === Write Verts ===
48 # ===================
49 def write_verts(data, mesh):
50         numverts = len(mesh.verts)
51         data.write(struct.pack(">BL", 0x6C, numverts))
52         for i in range(numverts):
53                 if not i%100 and mod_meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numverts, "Writing Verts")
54                 data.write(struct.pack(">BLBL", 0x6C, 1, 0x6D, 24))
55                 #data.write("\x6c\x00\x00\x00\x01\x6D\x00\x00\x00\x30")
56                 x, y, z = mesh.verts[i].co
57                 data.write(struct.pack(">ddd", x, z, -y))
58                 data.write("\x6A")
59         data.write("\x6A")
60
61 # ===================
62 # === Write Edges ===
63 # ===================
64 def write_edges(data, mesh, edge_table):
65         numedges = len(edge_table)
66         data.write(struct.pack(">BL", 0x6C, numedges))
67         keys = edge_table.keys()
68         keys.sort()
69         for key in keys:
70                 i = edge_table[key][6]
71                 if not i%100 and mod_meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numedges, "Writing Edges")
72
73                 if mod_meshtools.has_vertex_colors(mesh):
74                         r1, g1, b1 = edge_table[key][7]
75                         r2, g2, b2 = edge_table[key][8]
76                         data.write("\x6C\x00\x00\x00\x02")
77                         data.write("\x68\x02\x64\x00\x05color")
78                         data.write("\x6D\x00\x00\x00\x30")
79                         data.write(struct.pack(">dddddd", r1, g1, b1, r2, g2, b2))
80                         #print "%f %f %f - %f %f %f" % (r1, g1, b1, r2, g2, b2)
81                 else:
82                         data.write("\x6C\x00\x00\x00\x01")  # BL
83
84                 #$write_chunkheader(data, 0x68, 0x09, "edge")
85                 data.write("\x68\x09\x64\x00\x04edge") # faster
86
87                 # Sv Ev (Reversed)
88                 data.write(struct.pack(">BLBL", 0x62, key[1], 0x62, key[0]))
89
90                 # Lf Rf LP LS RP RS
91                 for i in range(6):
92                         if edge_table[key][i] < 256:
93                                 data.write(struct.pack(">BB", 0x61, edge_table[key][i]))
94                         else:
95                                 data.write(struct.pack(">BL", 0x62, edge_table[key][i]))
96
97                 data.write("\x6A")
98
99         data.write("\x6A")
100
101 # ===============================
102 # === Write The Material Mode ===
103 # ===============================
104 def write_mode(data, mesh):
105         data.write("\x6A")
106         data.write(struct.pack(">BL", 0x6C, 1))
107         write_chunkheader(data, 0x68, 0x02, "mode")
108         if mod_meshtools.has_vertex_colors(mesh):
109                 data.write(struct.pack(">BH6s", 0x64, 6, "vertex"))
110         else:
111                 data.write(struct.pack(">BH8s", 0x64, 8, "material"))
112         data.write("\x6A")
113
114 # ======================
115 # === Write Material ===
116 # ======================
117 def write_material(data, mesh):
118         data.write("\x6A")
119         data.write(struct.pack(">BL", 0x6C, 1))
120         write_chunkheader(data, 0x68, 0x02, "my default")
121
122         data.write(struct.pack(">BL", 0x6C, 2))
123         write_chunkheader(data, 0x68, 0x02, "maps")
124         data.write("\x6A")
125         write_chunkheader(data, 0x68, 0x02, "opengl")
126
127         # === The Material Components ===
128         data.write(struct.pack(">BL", 0x6C, 5))
129
130         write_chunkheader(data, 0x68, 0x02, "diffuse")
131         data.write("\x68\x04")
132         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
133         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
134         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
135         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
136
137         write_chunkheader(data, 0x68, 0x02, "ambient")
138         data.write("\x68\x04")
139         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
140         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
141         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
142         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
143
144         write_chunkheader(data, 0x68, 0x02, "specular")
145         data.write("\x68\x04")
146         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
147         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
148         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
149         data.write("\x63"+"1.00000000000000000000"+"e+000"+"\x00"*4)
150
151         write_chunkheader(data, 0x68, 0x02, "emission")
152         data.write("\x68\x04")
153         data.write("\x63"+"0.00000000000000000000"+"e+000"+"\x00"*4)
154         data.write("\x63"+"0.00000000000000000000"+"e+000"+"\x00"*4)
155         data.write("\x63"+"0.00000000000000000000"+"e+000"+"\x00"*4)
156         data.write("\x63"+"0.00000000000000000000"+"e+000"+"\x00"*4)
157
158         write_chunkheader(data, 0x68, 0x02, "shininess")
159         data.write("\x63"+"0.00000000000000000000"+"e+000"+"\x00"*4)
160
161         #write_chunkheader(data, 0x68, 0x02, "twosided")
162         #data.write(struct.pack(">BH4s", 0x64, 4, "true"))
163
164         data.write("\x6A"*3)    # use *4 if no ambient light
165
166 # =====================
167 # === Generate Data ===
168 # =====================
169 def generate_data(objname, edge_table, mesh):
170         data = cStringIO.StringIO()
171
172         # === wings chunk ===
173         write_chunkheader(data, 0x68, 0x03, "wings")
174
175         numobjs = 1 # len(Blender.Object.GetSelected())
176         data.write("\x61\x02\x68\x03") # misc bytes
177         data.write(struct.pack(">BL", 0x6C, numobjs))
178
179         # === object chunk ===
180         write_chunkheader(data, 0x68, 0x04, "object")
181         data.write(struct.pack(">BH", 0x6B, len(objname)))
182         data.write(objname)
183
184         # === winged chunk ===
185         write_chunkheader(data, 0x68, 0x05, "winged")
186         write_edges(data, mesh, edge_table)
187         write_faces(data, mesh)
188         write_verts(data, mesh)
189         write_mode(data, mesh)
190         write_material(data, mesh)
191         write_ambient_light(data)
192         return data.getvalue()
193
194 # ===========================
195 # === Write Ambient Light ===
196 # ===========================
197 def write_ambient_light(data):
198         light = [       # A quick cheat ;)
199         0x6C, 0x00, 0x00, 0x00, 0x01, 0x68, 0x02, 0x64, 0x00, 0x06, 0x6C, 0x69,
200         0x67, 0x68, 0x74, 0x73, 0x6C, 0x00, 0x00, 0x00, 0x01, 0x68, 0x02, 0x6B,
201         0x00, 0x07, 0x41, 0x6D, 0x62, 0x69, 0x65, 0x6E, 0x74, 0x6C, 0x00, 0x00,
202         0x00, 0x08, 0x68, 0x02, 0x64, 0x00, 0x07, 0x76, 0x69, 0x73, 0x69, 0x62,
203         0x6C, 0x65, 0x64, 0x00, 0x04, 0x74, 0x72, 0x75, 0x65, 0x68, 0x02, 0x64,
204         0x00, 0x06, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64, 0x64, 0x00, 0x05, 0x66,
205         0x61, 0x6C, 0x73, 0x65, 0x68, 0x02, 0x64, 0x00, 0x06, 0x6F, 0x70, 0x65,
206         0x6E, 0x67, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x03, 0x68, 0x02, 0x64, 0x00,
207         0x04, 0x74, 0x79, 0x70, 0x65, 0x64, 0x00, 0x07, 0x61, 0x6D, 0x62, 0x69,
208         0x65, 0x6E, 0x74, 0x68, 0x02, 0x64, 0x00, 0x07, 0x61, 0x6D, 0x62, 0x69,
209         0x65, 0x6E, 0x74, 0x68, 0x04, 0x63, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x30,
210         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
211         0x30, 0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
212         0x00, 0x63, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
213         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
214         0x65, 0x2B, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x63, 0x31, 0x2E,
215         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
216         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30,
217         0x30, 0x00, 0x00, 0x00, 0x00, 0x63, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x30,
218         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
219         0x30, 0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
220         0x00, 0x68, 0x02, 0x64, 0x00, 0x08, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69,
221         0x6F, 0x6E, 0x68, 0x03, 0x63, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x30,
222         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
223         0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
224         0x63, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
225         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x65,
226         0x2B, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x63, 0x30, 0x2E, 0x30,
227         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
228         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30, 0x30,
229         0x00, 0x00, 0x00, 0x00, 0x6A, 0x68, 0x02, 0x64, 0x00, 0x07, 0x76, 0x69,
230         0x73, 0x69, 0x62, 0x6C, 0x65, 0x64, 0x00, 0x04, 0x74, 0x72, 0x75, 0x65,
231         0x68, 0x02, 0x64, 0x00, 0x06, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64, 0x64,
232         0x00, 0x05, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x68, 0x02, 0x64, 0x00, 0x06,
233         0x79, 0x61, 0x66, 0x72, 0x61, 0x79, 0x6C, 0x00, 0x00, 0x00, 0x0B, 0x68,
234         0x02, 0x64, 0x00, 0x09, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x69, 0x7A, 0x65,
235         0x64, 0x64, 0x00, 0x04, 0x74, 0x72, 0x75, 0x65, 0x68, 0x02, 0x64, 0x00,
236         0x05, 0x70, 0x6F, 0x77, 0x65, 0x72, 0x63, 0x31, 0x2E, 0x30, 0x30, 0x30,
237         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
238         0x30, 0x30, 0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30, 0x30, 0x00, 0x00,
239         0x00, 0x00, 0x68, 0x02, 0x64, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x64,
240         0x00, 0x09, 0x68, 0x65, 0x6D, 0x69, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x68,
241         0x02, 0x64, 0x00, 0x07, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x62,
242         0x00, 0x00, 0x01, 0x00, 0x68, 0x02, 0x64, 0x00, 0x05, 0x64, 0x65, 0x70,
243         0x74, 0x68, 0x61, 0x03, 0x68, 0x02, 0x64, 0x00, 0x0A, 0x62, 0x61, 0x63,
244         0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x64, 0x00, 0x09, 0x75, 0x6E,
245         0x64, 0x65, 0x66, 0x69, 0x6E, 0x65, 0x64, 0x68, 0x02, 0x64, 0x00, 0x18,
246         0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x5F, 0x66,
247         0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x48, 0x44, 0x52, 0x49,
248         0x6A, 0x68, 0x02, 0x64, 0x00, 0x19, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72,
249         0x6F, 0x75, 0x6E, 0x64, 0x5F, 0x66, 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D,
250         0x65, 0x5F, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x6A, 0x68, 0x02, 0x64, 0x00,
251         0x1A, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x5F,
252         0x65, 0x78, 0x70, 0x6F, 0x73, 0x75, 0x72, 0x65, 0x5F, 0x61, 0x64, 0x6A,
253         0x75, 0x73, 0x74, 0x61, 0x00, 0x68, 0x02, 0x64, 0x00, 0x12, 0x62, 0x61,
254         0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x5F, 0x6D, 0x61, 0x70,
255         0x70, 0x69, 0x6E, 0x67, 0x64, 0x00, 0x05, 0x70, 0x72, 0x6F, 0x62, 0x65,
256         0x68, 0x02, 0x64, 0x00, 0x10, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F,
257         0x75, 0x6E, 0x64, 0x5F, 0x70, 0x6F, 0x77, 0x65, 0x72, 0x63, 0x31, 0x2E,
258         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
259         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x65, 0x2B, 0x30, 0x30,
260         0x30, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x68, 0x02, 0x64, 0x00, 0x07, 0x76,
261         0x69, 0x73, 0x69, 0x62, 0x6C, 0x65, 0x64, 0x00, 0x04, 0x74, 0x72, 0x75,
262         0x65, 0x68, 0x02, 0x64, 0x00, 0x06, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64,
263         0x64, 0x00, 0x05, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x6A, 0x6A, 0x6A]
264         data.write("".join(map(chr, light)))
265
266 # ==========================
267 # === Write Wings Format ===
268 # ==========================
269 def write(filename):
270         start = time.clock()
271
272         objects = Blender.Object.GetSelected()
273
274         objname = objects[0].name
275         meshname = objects[0].data.name
276         mesh = Blender.NMesh.GetRaw(meshname)
277         obj = Blender.Object.Get(objname)
278
279         try:
280                 edge_table = mod_meshtools.generate_edgetable(mesh)
281         except:
282                 edge_table = {}
283                 message = "Unable to generate\nEdge Table for mesh.\n"
284                 message += "Object name is: " + meshname
285                 mod_meshtools.print_boxed(message)
286                 Blender.Draw.PupMenu("Wings Export error|Unable to generate Edge Table for mesh")
287                 return 
288
289
290 #               if 0:
291 #                       import Tkinter, tkMessageBox
292 #                       sys.argv=['wings.pyo','wings.pyc'] # ?
293 #
294 #                       #Tkinter.NoDefaultRoot()
295 #                       win1 = Tkinter.Tk()
296 #                       ans = tkMessageBox.showerror("Error", message)
297 #                       win1.pack()
298 #                       print ans
299 #                       if ans:
300 #                               win1.quit()
301 #                       win1.mainloop()
302 #
303 #               else:
304 #                       from Tkinter import Label
305 #                       sys.argv = 'wings.py'
306 #                       widget = Label(None, text=message)
307 #                       #widget.title("Error")
308 #                       widget.pack()
309 #                       widget.mainloop()
310
311         data = generate_data(objname, edge_table, mesh)
312         dsize = len(data)
313         Blender.Window.DrawProgressBar(0.98, "Compressing Data")
314         data = zlib.compress(data, 6)
315         fsize = len(data)+6
316         header = "#!WINGS-1.0\r\n\032\04"
317         misc = 0x8350
318
319         file = open(filename, "wb")
320         file.write(header)
321         file.write(struct.pack(">L", fsize))
322         file.write(struct.pack(">H", misc))
323         file.write(struct.pack(">L", dsize))
324         file.write(data)
325
326         # Blender.Window.RedrawAll()
327         Blender.Window.DrawProgressBar(1.0, '')  # clear progressbar
328         file.close()
329         end = time.clock()
330         seconds = " in %.2f %s" % (end-start, "seconds")
331         message = "Successfully exported " + os.path.basename(filename) + seconds + '\n\n'
332         message += "objname : " + objname + '\n'
333         message += "faces   : " + `len(mesh.faces)` + '\n'
334         message += "edges   : " + `len(edge_table)` + '\n'
335         message += "verts   : " + `len(mesh.verts)` + '\n'
336         mod_meshtools.print_boxed(message)
337
338 def fs_callback(filename):
339         if filename.find('.wings', -6) <= 0: filename += '.wings'
340         write(filename)
341
342
343 if Blender.Object.GetSelected()[0].getType() != "Mesh":
344         Blender.Draw.PupMenu("Wings Export error|Selected object is not a mesh!")
345 else:
346         Blender.Window.FileSelector(fs_callback, "Wings3D Export")