2004-06-07 01:34:15 +00:00
|
|
|
|
#!BPY
|
|
|
|
|
|
|
|
|
|
"""
|
2004-06-11 02:12:37 +00:00
|
|
|
|
Name: 'Wings3D (.wings)...'
|
2004-06-07 01:34:15 +00:00
|
|
|
|
Blender: 232
|
|
|
|
|
Group: 'Import'
|
2004-06-11 02:12:37 +00:00
|
|
|
|
Tooltip: 'Import Wings3D File Format (.wings)'
|
2004-06-07 01:34:15 +00:00
|
|
|
|
"""
|
|
|
|
|
|
2004-11-07 16:31:13 +00:00
|
|
|
|
__author__ = "Anthony D'Agostino (Scorpius)"
|
|
|
|
|
__url__ = ("blender", "elysiun",
|
|
|
|
|
"Author's homepage, http://www.redrival.com/scorpius",
|
|
|
|
|
"Wings 3D, http://www.wings3d.com")
|
|
|
|
|
__version__ = "Part of IOSuite 0.5"
|
|
|
|
|
|
|
|
|
|
__bpydoc__ = """\
|
2004-11-30 02:27:46 +00:00
|
|
|
|
This script imports Wings3D files to Blender.
|
2004-11-07 16:31:13 +00:00
|
|
|
|
|
2004-11-30 02:27:46 +00:00
|
|
|
|
Wings3D is an open source polygon modeler written in Erlang, a
|
|
|
|
|
language similar to Lisp. The .wings file format is a binary
|
|
|
|
|
representation of erlang terms (lists, tuples, atoms, etc.) and is
|
|
|
|
|
compressed with zlib.
|
2004-11-07 16:31:13 +00:00
|
|
|
|
|
2004-11-30 02:27:46 +00:00
|
|
|
|
Usage:<br>
|
|
|
|
|
Execute this script from the "File->Import" menu and choose a Wings file
|
|
|
|
|
to open.
|
|
|
|
|
|
|
|
|
|
Supported:<br>
|
|
|
|
|
Meshes only. Not guaranteed to work in all situations.
|
|
|
|
|
|
|
|
|
|
Missing:<br>
|
|
|
|
|
Materials, UV Coordinates, and Vertex Color info will be ignored.
|
|
|
|
|
|
|
|
|
|
Known issues:<br>
|
|
|
|
|
Triangulation of convex polygons works fine, and uses a very simple
|
|
|
|
|
fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
|
|
|
|
|
require a different algorithm, and will be triagulated incorrectly.
|
|
|
|
|
|
|
|
|
|
Notes:<br>
|
|
|
|
|
Last tested with Wings 3D 0.98.25 & Blender 2.35a.
|
2004-11-07 16:31:13 +00:00
|
|
|
|
"""
|
|
|
|
|
|
2004-06-10 03:27:46 +00:00
|
|
|
|
# $Id$
|
|
|
|
|
#
|
2004-06-07 01:34:15 +00:00
|
|
|
|
# +---------------------------------------------------------+
|
|
|
|
|
# | Copyright (c) 2002 Anthony D'Agostino |
|
|
|
|
|
# | http://www.redrival.com/scorpius |
|
|
|
|
|
# | scorpius@netzero.com |
|
|
|
|
|
# | Feb 19, 2002 |
|
|
|
|
|
# | Released under the Blender Artistic Licence (BAL) |
|
|
|
|
|
# | Import Export Suite v0.5 |
|
|
|
|
|
# +---------------------------------------------------------+
|
|
|
|
|
# | Read and write Wings3D File Format (*.wings) |
|
|
|
|
|
# +---------------------------------------------------------+
|
|
|
|
|
|
2005-03-21 05:26:52 +00:00
|
|
|
|
import Blender, meshtools
|
2004-06-07 01:34:15 +00:00
|
|
|
|
import struct, time, sys, os, zlib, cStringIO
|
|
|
|
|
|
|
|
|
|
# ==============================================
|
|
|
|
|
# === Read The 'Header' Common To All Chunks ===
|
|
|
|
|
# ==============================================
|
|
|
|
|
def read_chunkheader(data):
|
|
|
|
|
data.read(2) #version, tag = struct.unpack(">BB", data.read(2))
|
|
|
|
|
misc, namelen = struct.unpack(">BH", data.read(3))
|
|
|
|
|
name = data.read(namelen)
|
|
|
|
|
return name
|
|
|
|
|
|
|
|
|
|
# ==============================
|
|
|
|
|
# === Read The Material Mode ===
|
|
|
|
|
# ==============================
|
|
|
|
|
def read_mode(data):
|
|
|
|
|
data.read(5) # BL
|
|
|
|
|
read_chunkheader(data) # "mode"
|
|
|
|
|
misc, namelen = struct.unpack(">BH", data.read(3))
|
|
|
|
|
data.read(namelen)
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
|
|
|
|
|
# =======================
|
|
|
|
|
# === Read Hard Edges ===
|
|
|
|
|
# =======================
|
|
|
|
|
def read_hardedges(data):
|
|
|
|
|
tag = data.read(1)
|
|
|
|
|
if tag == '\x6A':
|
|
|
|
|
return # There are no hard edges
|
|
|
|
|
elif tag == '\x6B':
|
|
|
|
|
numhardedges, = struct.unpack(">H", data.read(2))
|
|
|
|
|
print "numhardedges:", numhardedges
|
|
|
|
|
for i in range(numhardedges):
|
|
|
|
|
data.read(1)
|
|
|
|
|
elif tag == '\x6C':
|
|
|
|
|
numhardedges, = struct.unpack(">L", data.read(4))
|
|
|
|
|
print "numhardedges:", numhardedges
|
|
|
|
|
for i in range(numhardedges):
|
|
|
|
|
misc = data.read(1)
|
|
|
|
|
if misc == '\x61': # next value is stored as a byte
|
|
|
|
|
data.read(1)
|
|
|
|
|
elif misc == '\x62': # next value is stored as a long
|
|
|
|
|
data.read(4)
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
else:
|
|
|
|
|
print tag
|
|
|
|
|
|
|
|
|
|
# ==================
|
|
|
|
|
# === Read Edges ===
|
|
|
|
|
# ==================
|
|
|
|
|
def read_edges(data):
|
|
|
|
|
misc, numedges = struct.unpack(">BL", data.read(5))
|
|
|
|
|
edge_table = {} # the winged-edge table
|
|
|
|
|
for i in range(numedges):
|
2005-03-21 05:26:52 +00:00
|
|
|
|
if not i%100 and meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numedges, "Reading Edges")
|
2004-06-07 01:34:15 +00:00
|
|
|
|
misc, etype = struct.unpack(">BL", data.read(5))
|
|
|
|
|
if etype == 2: # Vertex Colors
|
|
|
|
|
data.read(10) # or read_chunkheader(data) # "color"
|
|
|
|
|
data.read(5) # BL
|
|
|
|
|
r1,g1,b1,r2,g2,b2 = struct.unpack(">dddddd", data.read(48))
|
|
|
|
|
#print "%3d %3d %3d | %3d %3d %3d" % (r1*255,g1*255,b1*255,r2*255,g2*255,b2*255),
|
|
|
|
|
#print "%f %f %f | %f %f %f" % (r1, g1, b1, r2, g2, b2)
|
|
|
|
|
data.read(9) # or read_chunkheader(data) # "edge"
|
|
|
|
|
edge = [] # the eight entries for this edge
|
|
|
|
|
for e in range(8): # Sv Ev | Lf Rf | Lp Ls | Rp Rs
|
|
|
|
|
misc = data.read(1)
|
|
|
|
|
if misc == '\x61': # next value is stored as a byte
|
|
|
|
|
entry, = struct.unpack(">B", data.read(1))
|
|
|
|
|
edge.append(entry)
|
|
|
|
|
elif misc == '\x62': # next value is stored as a long
|
|
|
|
|
entry, = struct.unpack(">L", data.read(4))
|
|
|
|
|
edge.append(entry)
|
|
|
|
|
edge_table[i] = edge
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
return edge_table
|
|
|
|
|
|
|
|
|
|
# ==================
|
|
|
|
|
# === Read Faces ===
|
|
|
|
|
# ==================
|
|
|
|
|
def read_faces(data):
|
|
|
|
|
misc, numfaces = struct.unpack(">BL", data.read(5))
|
|
|
|
|
for i in range(numfaces):
|
2005-03-21 05:26:52 +00:00
|
|
|
|
if not i%100 and meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numfaces, "Reading Faces")
|
2004-06-07 01:34:15 +00:00
|
|
|
|
if data.read(1) == '\x6C': # a material follows
|
|
|
|
|
data.read(4)
|
|
|
|
|
read_chunkheader(data)
|
|
|
|
|
misc, namelen = struct.unpack(">BH", data.read(3))
|
|
|
|
|
materialname = data.read(namelen)
|
|
|
|
|
data.read(1)
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
return numfaces
|
|
|
|
|
|
|
|
|
|
# ==================
|
|
|
|
|
# === Read Verts ===
|
|
|
|
|
# ==================
|
|
|
|
|
def read_verts(data):
|
|
|
|
|
misc, numverts = struct.unpack(">BL", data.read(5))
|
|
|
|
|
verts = [] # a list of verts
|
|
|
|
|
for i in range(numverts):
|
2005-03-21 05:26:52 +00:00
|
|
|
|
if not i%100 and meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Verts")
|
2004-06-07 01:34:15 +00:00
|
|
|
|
data.read(10)
|
|
|
|
|
x, y, z = struct.unpack(">ddd", data.read(24)) # double precision
|
|
|
|
|
verts.append((x, -z, y))
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
data.read(1) # 6A
|
|
|
|
|
return verts
|
|
|
|
|
|
|
|
|
|
# =======================
|
|
|
|
|
# === Make Face Table ===
|
|
|
|
|
# =======================
|
|
|
|
|
def make_face_table(edge_table): # For Wings
|
|
|
|
|
face_table = {}
|
|
|
|
|
for i in range(len(edge_table)):
|
|
|
|
|
Lf = edge_table[i][2]
|
|
|
|
|
Rf = edge_table[i][3]
|
|
|
|
|
face_table[Lf] = i
|
|
|
|
|
face_table[Rf] = i
|
|
|
|
|
return face_table
|
|
|
|
|
|
|
|
|
|
# =======================
|
|
|
|
|
# === Make Vert Table ===
|
|
|
|
|
# =======================
|
|
|
|
|
def make_vert_table(edge_table): # For Wings
|
|
|
|
|
vert_table = {}
|
|
|
|
|
for i in range(len(edge_table)):
|
|
|
|
|
Sv = edge_table[i][0]
|
|
|
|
|
Ev = edge_table[i][1]
|
|
|
|
|
vert_table[Sv] = i
|
|
|
|
|
vert_table[Ev] = i
|
|
|
|
|
return vert_table
|
|
|
|
|
|
|
|
|
|
# ==================
|
|
|
|
|
# === Make Faces ===
|
|
|
|
|
# ==================
|
|
|
|
|
def make_faces(edge_table): # For Wings
|
|
|
|
|
face_table = make_face_table(edge_table)
|
|
|
|
|
faces=[]
|
|
|
|
|
for i in range(len(face_table)):
|
|
|
|
|
face_verts = []
|
|
|
|
|
current_edge = face_table[i]
|
|
|
|
|
while(1):
|
|
|
|
|
if i == edge_table[current_edge][3]:
|
|
|
|
|
next_edge = edge_table[current_edge][7] # Right successor edge
|
|
|
|
|
next_vert = edge_table[current_edge][0]
|
|
|
|
|
else:
|
|
|
|
|
next_edge = edge_table[current_edge][5] # Left successor edge
|
|
|
|
|
next_vert = edge_table[current_edge][1]
|
|
|
|
|
face_verts.append(next_vert)
|
|
|
|
|
current_edge = next_edge
|
|
|
|
|
if current_edge == face_table[i]: break
|
|
|
|
|
face_verts.reverse()
|
|
|
|
|
faces.append(face_verts)
|
|
|
|
|
return faces
|
|
|
|
|
|
|
|
|
|
# =======================
|
|
|
|
|
# === Dump Wings File ===
|
|
|
|
|
# =======================
|
|
|
|
|
def dump_wings(filename):
|
|
|
|
|
import pprint
|
|
|
|
|
start = time.clock()
|
|
|
|
|
file = open(filename, "rb")
|
|
|
|
|
header = file.read(15)
|
|
|
|
|
fsize, = struct.unpack(">L", file.read(4)) # file_size - 19
|
|
|
|
|
misc, = struct.unpack(">H", file.read(2))
|
|
|
|
|
dsize, = struct.unpack(">L", file.read(4)) # uncompressed data size
|
|
|
|
|
data = file.read(fsize-6)
|
|
|
|
|
file.close()
|
|
|
|
|
data = zlib.decompress(data)
|
|
|
|
|
if dsize != len(data): print "ERROR: uncompressed size does not match."
|
|
|
|
|
data = cStringIO.StringIO(data)
|
|
|
|
|
print "header:", header
|
|
|
|
|
print read_chunkheader(data) # === wings chunk ===
|
|
|
|
|
data.read(4) # misc bytes
|
|
|
|
|
misc, numobjs, = struct.unpack(">BL", data.read(5))
|
|
|
|
|
print "filename:", filename
|
|
|
|
|
print "numobjs :", numobjs
|
|
|
|
|
for obj in range(numobjs):
|
|
|
|
|
print read_chunkheader(data) # === object chunk ===
|
|
|
|
|
misc, namelen = struct.unpack(">BH", data.read(3))
|
|
|
|
|
objname = data.read(namelen)
|
|
|
|
|
print read_chunkheader(data) # === winged chunk ===
|
|
|
|
|
edge_table = read_edges(data)
|
|
|
|
|
numfaces = read_faces(data)
|
|
|
|
|
verts = read_verts(data)
|
|
|
|
|
read_hardedges(data)
|
|
|
|
|
|
|
|
|
|
face_table = {} # contains an incident edge
|
|
|
|
|
vert_table = {} # contains an incident edge
|
|
|
|
|
for i in range(len(edge_table)):
|
|
|
|
|
face_table[edge_table[i][2]] = i # generate face_table
|
|
|
|
|
face_table[edge_table[i][3]] = i
|
|
|
|
|
vert_table[edge_table[i][0]] = i # generate vert_table
|
|
|
|
|
vert_table[edge_table[i][1]] = i
|
|
|
|
|
|
|
|
|
|
print "objname :", objname
|
|
|
|
|
print "numedges:", len(edge_table)
|
|
|
|
|
print "numfaces:", numfaces
|
|
|
|
|
print "numverts:", len(verts)
|
|
|
|
|
print
|
|
|
|
|
print "<EFBFBD>"*79
|
|
|
|
|
print "edge_table:"
|
|
|
|
|
pprint.pprint(edge_table)
|
|
|
|
|
#for i in range(len(edge_table)): print "%2d" % (i), edge_table[i]
|
|
|
|
|
print
|
|
|
|
|
print "face_table:"
|
|
|
|
|
pprint.pprint(face_table)
|
|
|
|
|
#for i in range(len(face_table)): print "%2d %2d" % (i, face_table[i])
|
|
|
|
|
print
|
|
|
|
|
print "vert_table:"
|
|
|
|
|
pprint.pprint(vert_table)
|
|
|
|
|
#for i in range(len(vert_table)): print "%2d %2d" % (i, vert_table[i])
|
|
|
|
|
file.close()
|
|
|
|
|
end = time.clock()
|
|
|
|
|
print '\a\r',
|
|
|
|
|
sys.stderr.write("\nDone in %.2f %s" % (end-start, "seconds"))
|
|
|
|
|
|
|
|
|
|
# =========================
|
|
|
|
|
# === Read Wings Format ===
|
|
|
|
|
# =========================
|
|
|
|
|
def read(filename):
|
|
|
|
|
start = time.clock()
|
|
|
|
|
file = open(filename, "rb")
|
|
|
|
|
header = file.read(15)
|
|
|
|
|
fsize, = struct.unpack(">L", file.read(4)) # file_size - 19
|
|
|
|
|
misc, = struct.unpack(">H", file.read(2))
|
|
|
|
|
dsize, = struct.unpack(">L", file.read(4)) # uncompressed data size
|
|
|
|
|
data = file.read(fsize-6)
|
|
|
|
|
#print file.tell(), "bytes"
|
|
|
|
|
file.close()
|
|
|
|
|
Blender.Window.DrawProgressBar(1.0, "Decompressing Data")
|
|
|
|
|
data = zlib.decompress(data)
|
|
|
|
|
data = cStringIO.StringIO(data)
|
|
|
|
|
read_chunkheader(data) # wings chunk
|
|
|
|
|
data.read(4) # misc bytes
|
|
|
|
|
misc, numobjs = struct.unpack(">BL", data.read(5))
|
|
|
|
|
message = "Successfully imported " + os.path.basename(filename) + '\n\n'
|
|
|
|
|
message += "%s %8s %8s %8s\n" % ("Object".ljust(15), "faces", "edges", "verts")
|
|
|
|
|
message += "%s %8s %8s %8s\n" % ("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>".ljust(15), "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
|
|
|
|
|
|
|
|
|
for obj in range(numobjs):
|
|
|
|
|
read_chunkheader(data) # object chunk
|
|
|
|
|
misc, namelen = struct.unpack(">BH", data.read(3))
|
|
|
|
|
objname = data.read(namelen)
|
|
|
|
|
read_chunkheader(data) # winged chunk
|
|
|
|
|
edge_table = read_edges(data)
|
|
|
|
|
numfaces = read_faces(data)
|
|
|
|
|
verts = read_verts(data)
|
|
|
|
|
read_hardedges(data)
|
|
|
|
|
read_mode(data)
|
|
|
|
|
faces = make_faces(edge_table)
|
|
|
|
|
message += "%s %8s %8s %8s\n" % (objname.ljust(15), len(faces), len(edge_table), len(verts))
|
2005-03-21 05:26:52 +00:00
|
|
|
|
meshtools.create_mesh(verts, faces, objname)
|
2004-06-07 01:34:15 +00:00
|
|
|
|
|
|
|
|
|
material = data.read()
|
|
|
|
|
#for i in material[0:6]: print "%02X" % ord(i),
|
|
|
|
|
#print
|
|
|
|
|
Blender.Window.DrawProgressBar(1.0, "Done") # clear progressbar
|
|
|
|
|
data.close()
|
|
|
|
|
end = time.clock()
|
|
|
|
|
seconds = "\nDone in %.2f %s" % (end-start, "seconds")
|
|
|
|
|
message += seconds
|
2005-03-21 05:26:52 +00:00
|
|
|
|
meshtools.print_boxed(message)
|
2004-06-07 01:34:15 +00:00
|
|
|
|
|
|
|
|
|
def fs_callback(filename):
|
|
|
|
|
read(filename)
|
|
|
|
|
|
2004-06-11 02:12:37 +00:00
|
|
|
|
Blender.Window.FileSelector(fs_callback, "Import Wings3D")
|