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