7898fa40fa7c1282023f1751003939c4e8915695
[blender.git] / release / scripts / truespace_import.py
1 #!BPY
2
3 """
4 Name: 'TrueSpace...'
5 Blender: 232
6 Group: 'Import'
7 Tooltip: 'Import trueSpace Object File Format (*.cob)'
8 """
9
10 # $Id$
11 #
12 # +---------------------------------------------------------+
13 # | Copyright (c) 2001 Anthony D'Agostino                   |
14 # | http://www.redrival.com/scorpius                        |
15 # | scorpius@netzero.com                                    |
16 # | June 12, 2001                                           |
17 # | Released under the Blender Artistic Licence (BAL)       |
18 # | Import Export Suite v0.5                                |
19 # +---------------------------------------------------------+
20 # | Read and write Caligari trueSpace File Format (*.cob)   |
21 # +---------------------------------------------------------+
22
23 import Blender, mod_meshtools
24 import struct, chunk, os, cStringIO, time
25
26 # =======================
27 # === COB Chunk Class ===
28 # =======================
29 class CobChunk(chunk.Chunk):
30         def __init__(self, file, align = 0, bigendian = 0, inclheader = 0): #$ COB
31                 self.closed = 0
32                 self.align = align      # whether to align to word (2-byte) boundaries
33                 if bigendian:
34                         strflag = '>'
35                 else:
36                         strflag = '<'
37                 self.file = file
38                 self.chunkname = file.read(4)
39                 if len(self.chunkname) < 4:
40                         raise EOFError
41                 self.major_ver, = struct.unpack(strflag+'h', file.read(2))      #$ COB
42                 self.minor_ver, = struct.unpack(strflag+'h', file.read(2))      #$ COB
43                 self.chunk_id,  = struct.unpack(strflag+'l', file.read(4))      #$ COB
44                 self.parent_id, = struct.unpack(strflag+'l', file.read(4))      #$ COB
45                 try:
46                         self.chunksize = struct.unpack(strflag+'l', file.read(4))[0]
47                 except struct.error:
48                         raise EOFError
49                 if inclheader:
50                         self.chunksize = self.chunksize - 20                                            #$ COB
51                 self.size_read = 0
52                 try:
53                         self.offset = self.file.tell()
54                 except:
55                         self.seekable = 0
56                 else:
57                         self.seekable = 1
58
59 # ============================
60 # === Read COB File Header ===
61 # ============================
62 def read_header(file):
63         magic,   = struct.unpack("<9s", file.read(9))
64         version, = struct.unpack("<6s", file.read(6))
65         format,  = struct.unpack("<1c", file.read(1))
66         endian,  = struct.unpack("<2s", file.read(2))
67         misc,    = struct.unpack("13s", file.read(13))
68         newline, = struct.unpack("<1B", file.read(1))
69         return format
70
71 # ========================================
72 # === Read PolH (Polygonal Data) Chunk ===
73 # ========================================
74 def read_polh(chunk):
75         data = cStringIO.StringIO(chunk.read())
76         oname = read_ObjectName(data)
77         local = read_LocalAxes(data)
78         crpos = read_CurrentPosition(data)
79         verts = read_VertexList(data)
80         uvcoords = read_UVCoords(data)
81         faces, facesuv = read_FaceList(data, chunk)
82         return verts, faces, oname, facesuv, uvcoords
83
84 # === Read Object Name ===
85 def read_ObjectName(data):
86         dupecount, namelen = struct.unpack("<hh", data.read(4))
87         objname = data.read(namelen)
88         if objname == '': objname = 'NoName'
89         if dupecount > 0: objname = objname + ', ' + `dupecount`
90         return objname
91
92 # === Read Local Axes ===
93 def read_LocalAxes(data):
94         location = struct.unpack("<fff", data.read(12))
95         rotation_matrix=[]
96         for i in range(3):
97                 row = struct.unpack("<fff", data.read(12))
98                 #print "% f % f % f" % row
99                 rotation_matrix.append(list(row))
100         #print
101         rotation_matrix = mod_meshtools.transpose(rotation_matrix)
102
103 # === Read Current Position ===
104 def read_CurrentPosition(data):
105         transformation_matrix=[]
106         for i in range(3):
107                 row = struct.unpack("<ffff", data.read(16))
108                 #print "% f % f % f % f" % row
109                 transformation_matrix.append(list(row))
110         #print
111
112 # === Read Vertex List ===
113 def read_VertexList(data):
114         verts = []
115         numverts, = struct.unpack("<l", data.read(4))
116         for i in range(numverts):
117                 if not i%100 and mod_meshtools.show_progress:
118                         Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Verts")
119                 x, y, z = struct.unpack("<fff", data.read(12))
120                 verts.append((y, -x, z))
121         return verts
122
123 # === Read UV Vertex List ===
124 def read_UVCoords(data):
125         uvcoords = []
126         numuvcoords, = struct.unpack("<l", data.read(4))
127         for i in range(numuvcoords):
128                 if not i%100 and mod_meshtools.show_progress:
129                         Blender.Window.DrawProgressBar(float(i)/numuvcoords, "Reading UV Coords")
130                 uv = struct.unpack("<ff", data.read(8))
131                 uvcoords.append(uv)
132
133         #print "num uvcoords:", len(uvcoords)
134         #for i in range(len(uvcoords)): print "%.4f, %.4f" % uvcoords[i]
135         return uvcoords
136
137 # === Read Face List ===
138 def read_FaceList(data, chunk):
139         faces = []                                 ; facesuv = []
140         numfaces, = struct.unpack("<l", data.read(4))
141         for i in range(numfaces):
142                 if not i%100 and mod_meshtools.show_progress:
143                         Blender.Window.DrawProgressBar(float(i)/numfaces, "Reading Faces")
144
145                 face_flags, numfaceverts = struct.unpack("<Bh", data.read(3))
146
147                 if (face_flags & 0x08) == 0x08:
148                         print "face #" + `i-1` + " contains a hole."
149                         pass
150                 else:
151                         data.read(2)  # Material Index
152
153                 facev = []                         ; faceuv = []
154                 for j in range(numfaceverts):
155                         index, uvidx = struct.unpack("<ll", data.read(8))
156                         facev.append(index); faceuv.append(uvidx)
157                 facev.reverse()            ; faceuv.reverse()
158                 faces.append(facev)    ; facesuv.append(faceuv)
159
160         if chunk.minor_ver == 6:
161                 DrawFlags, RadiosityQuality = struct.unpack("<lh", data.read(6))
162         if chunk.minor_ver == 8:
163                 DrawFlags, = struct.unpack("<l", data.read(4))
164
165         return faces                       , facesuv
166
167 # =============================
168 # === Read trueSpace Format ===
169 # =============================
170 def read(filename):
171         start = time.clock()
172         file = open(filename, "rb")
173
174         # === COB header ===
175         if read_header(file) == 'A':
176                 print "Can't read ASCII format"
177                 return
178
179         while 1:
180                 try:
181                         cobchunk = CobChunk(file)
182                 except EOFError:
183                         break
184                 if cobchunk.chunkname == "PolH":
185                         verts, faces, objname, facesuv, uvcoords = read_polh(cobchunk)
186                         mod_meshtools.create_mesh(verts, faces, objname, facesuv, uvcoords)
187
188                         '''
189                         object = Blender.Object.GetSelected()
190                         obj = Blender.Object.Get(objname)
191                         obj.loc = location
192                         obj.rot = mod_meshtools.mat2euler(rotation_matrix)
193                         obj.size = (transformation_matrix[0][0]/rotation_matrix[0][0],
194                                                 transformation_matrix[1][1]/rotation_matrix[1][1],
195                                                 transformation_matrix[2][2]/rotation_matrix[2][2])
196
197                         '''
198                 else:
199                         cobchunk.skip()
200
201         Blender.Window.DrawProgressBar(1.0, '')  # clear progressbar
202         file.close()
203         end = time.clock()
204         seconds = " in %.2f %s" % (end-start, "seconds")
205         message = "Successfully imported " + os.path.basename(filename) + seconds
206         mod_meshtools.print_boxed(message)
207         #print "objname :", objname
208         #print "numverts:", len(verts)
209         #print "numfaces:", len(faces)
210
211 def fs_callback(filename):
212         read(filename)
213
214 Blender.Window.FileSelector(fs_callback, "COB Import")
215
216 #       === Matrix Differences between Blender & trueSpace ===
217 #
218 #       For the 'Local Axes' values:
219 #       The x, y, and z-axis represent a simple rotation matrix.
220 #       This is equivalent to Blender's object matrix before it was
221 #       combined with the object's scaling matrix.  Dividing each value
222 #       by the appropriate scaling factor (and transposing at the same
223 #       time) produces the original rotation matrix.
224 #
225 #       For the 'Current Position' values:
226 #       This is equivalent to Blender's object matrix except that the
227 #       last row is omitted and the xyz location is used in the last
228 #       column.  Binary format uses a 4x3 matrix, ascii format uses a 4x4
229 #       matrix.
230 #
231 #       For Cameras: The matrix is a little confusing.