Final merge of HEAD (bf-blender) into the orange branch.
[blender.git] / release / scripts / nendo_import.py
1 #!BPY
2
3 """
4 Name: 'Nendo (.ndo)...'
5 Blender: 232
6 Group: 'Import'
7 Tooltip: 'Import Nendo Object File Format (.ndo)'
8 """
9
10 __author__ = "Anthony D'Agostino (Scorpius)"
11 __url__ = ("blender", "elysiun",
12 "Author's homepage, http://www.redrival.com/scorpius")
13 __version__ = "Part of IOSuite 0.5"
14
15 __bpydoc__ = """\
16 This script imports Nendo files to Blender.
17
18 Nendo is (was) a commercial polygon modeler that has about half of the
19 features found in Wings. The .ndo file format is a simple, uncompressed,
20 memory dump of structures that represent the mesh objects, uv coords,
21 and image textures.
22
23 Usage:<br>
24         Execute this script from the "File->Import" menu and choose a Nendo file
25 to open.
26
27 Supported:<br>
28         Meshes only.
29
30 Missing:<br>
31     Materials, UV Coordinates, and Vertex Color info will be ignored.
32
33 Known issues:<br>
34         Triangulation of convex polygons works fine, and uses a very simple
35 fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
36 require a different algorithm, and will be triagulated incorrectly.
37
38 Notes:<br>
39         Last tested with Wings 3D 0.98.25 & Nendo 1.1.6. Some models cannot be
40 imported due to the fact that Nendo erroneously creates doubled back
41 edges during the course of modeling.
42 """
43
44 # $Id$
45 #
46 # +---------------------------------------------------------+
47 # | Copyright (c) 2001 Anthony D'Agostino                   |
48 # | http://www.redrival.com/scorpius                        |
49 # | scorpius@netzero.com                                    |
50 # | September 25, 2001                                      |
51 # | Released under the Blender Artistic Licence (BAL)       |
52 # | Import Export Suite v0.5                                |
53 # +---------------------------------------------------------+
54 # | Read and write Nendo File Format (*.nendo)              |
55 # +---------------------------------------------------------+
56
57 import Blender, meshtools
58 import struct, time, sys, os
59
60 # =============================
61 # === Read Nendo 1.x Format ===
62 # =============================
63 def read(filename):
64         start = time.clock()
65         file = open(filename, "rb")
66         version, numobjs = read_header(file)
67
68         for object in range(numobjs):
69                 good, = struct.unpack(">B",  file.read(1))
70                 if not good: continue   # an empty object
71                 objname = read_object_flags(file)
72                 edge_table = read_edge_table(file, version)
73                 face_table = read_face_table(file)
74                 vert_table = read_vert_table(file)
75                 uv = read_uv(file)
76                 verts = make_verts(vert_table)
77                 faces = make_faces(edge_table)
78                 meshtools.create_mesh(verts, faces, objname)
79
80         Blender.Window.DrawProgressBar(1.0, "Done")    # clear progressbar
81         file.close()
82         end = time.clock()
83         seconds = " in %.2f %s" % (end-start, "seconds")
84         message = "Successfully imported " + os.path.basename(filename) + seconds
85         message += " (%s)" % version.title()
86         meshtools.print_boxed(message)
87
88 # =======================
89 # === Read The Header ===
90 # =======================
91 def read_header(file):
92         version, = struct.unpack(">9s", file.read(9))
93         misc,    = struct.unpack(">H",  file.read(2))
94         numobjs, = struct.unpack(">B",  file.read(1))
95         if (version != "nendo 1.0") and (version != "nendo 1.1"):
96                 meshtools.print_boxed(file.name, "is not a Nendo file")
97                 return
98         return version, numobjs
99
100 # =========================
101 # === Read Object Flags ===
102 # =========================
103 def read_object_flags(file):
104         namelen, = struct.unpack(">H",  file.read(2))
105         objname  = file.read(namelen)
106         visible, = struct.unpack(">B", file.read(1))
107         sensity, = struct.unpack(">B", file.read(1))
108         other,   = struct.unpack(">H", file.read(2))    # or 2 more flags?
109         misc     = struct.unpack(">18f", file.read(72))
110         return objname
111
112 # =======================
113 # === Read Edge Table ===
114 # =======================
115 def read_edge_table(file, version):
116         numedges, = struct.unpack(">H", file.read(2))
117         edge_table = {}
118         for i in range(numedges):
119                 if not i%100 and meshtools.show_progress:
120                         Blender.Window.DrawProgressBar(float(i)/numedges, "Reading Edge Table")
121                 edge = struct.unpack(">8H", file.read(16))
122                 if version == "nendo 1.1":
123                         hard, = struct.unpack(">B",  file.read(1))  # edge hardness flag
124                 color = struct.unpack(">8B", file.read(8))
125                 edge_table[i] = edge
126         return edge_table
127
128 # =======================
129 # === Read Face Table ===
130 # =======================
131 def read_face_table(file):
132         numfaces, = struct.unpack(">H", file.read(2))
133         face_table = {}
134         for i in range(numfaces):
135                 if not i%100 and meshtools.show_progress:
136                         Blender.Window.DrawProgressBar(float(i)/numfaces, "Reading Face Table")
137                 face_table[i] = struct.unpack(">H", file.read(2))[0]
138         return face_table
139
140 # =======================
141 # === Read Vert Table ===
142 # =======================
143 def read_vert_table(file):
144         numverts, = struct.unpack(">H", file.read(2))
145         vert_table = []
146         for i in range(numverts):
147                 if not i%100 and meshtools.show_progress:
148                         Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Vertex Table")
149                 w, x, y, z = struct.unpack(">H3f", file.read(14))
150                 vert_table.append((w,(x, y, z)))
151         return vert_table
152
153 # ====================
154 # === Read Texture ===
155 # ====================
156 def read_uv(file):
157         numuvs, = struct.unpack(">H", file.read(2))
158         uvlist  = struct.unpack(">"+`numuvs`+"H", file.read(numuvs*2))
159         numfacesT, = struct.unpack(">H", file.read(2))
160         facesT = struct.unpack(">"+`numfacesT`+"H", file.read(numfacesT*2))
161         textureflag, = struct.unpack(">B", file.read(1))
162         if textureflag:
163                 xres, yres = struct.unpack(">2H", file.read(4))
164                 print "%ix%i" % (xres, yres)
165                 pixel = 0
166                 while pixel < (xres*yres):
167                         if not pixel%100 and meshtools.show_progress:
168                                 Blender.Window.DrawProgressBar(float(pixel)/xres*yres, "Reading Texture")
169                         count, = struct.unpack(">B", file.read(1))
170                         rgb = file.read(3)
171                         pixel = pixel+count
172         return numuvs
173
174 # ==================
175 # === Make Verts ===
176 # ==================
177 def make_verts(vert_table):
178         matrix = [ # Rotate 90*x and Scale 0.1
179         [0.1, 0.0, 0.0, 0.0],
180         [0.0, 0.0, 0.1, 0.0],
181         [0.0,-0.1, 0.0, 0.0],
182         [0.0, 0.0, 0.0, 1.0]]
183         verts = []
184         for i in range(len(vert_table)):
185                 vertex = vert_table[i][1]
186                 vertex = meshtools.apply_transform(vertex, matrix)
187                 verts.append(vertex)
188         return verts
189
190 # =======================
191 # === Make Face Table ===
192 # =======================
193 def make_face_table(edge_table): # For Nendo
194         face_table = {}
195         for i in range(len(edge_table)):
196                 Lf = edge_table[i][2]
197                 Rf = edge_table[i][3]
198                 face_table[Lf] = i
199                 face_table[Rf] = i
200         return face_table
201
202 # =======================
203 # === Make Vert Table ===
204 # =======================
205 def make_vert_table(edge_table): # For Nendo
206         vert_table = {}
207         for i in range(len(edge_table)):
208                 Sv = edge_table[i][1]
209                 Ev = edge_table[i][0]
210                 vert_table[Sv] = i
211                 vert_table[Ev] = i
212         return vert_table
213
214 # ==================
215 # === Make Faces ===
216 # ==================
217 def make_faces(edge_table): # For Nendo
218         face_table = make_face_table(edge_table)
219         faces=[]
220         #for i in range(len(face_table)):
221         for i in face_table.keys(): # avoids a whole class of errors
222                 face_verts = []
223                 current_edge = face_table[i]
224                 while(1):
225                         if i == edge_table[current_edge][3]:
226                                 next_edge = edge_table[current_edge][5] # Right successor edge
227                                 next_vert = edge_table[current_edge][1]
228                         else:
229                                 next_edge = edge_table[current_edge][4] # Left successor edge
230                                 next_vert = edge_table[current_edge][0]
231                         face_verts.append(next_vert)
232                         current_edge = next_edge
233                         if current_edge == face_table[i]: break
234                 face_verts.reverse() # Flip all face normals
235                 faces.append(face_verts)
236         return faces
237
238 def fs_callback(filename):
239         read(filename)
240
241 Blender.Window.FileSelector(fs_callback, "Import Nendo")