Integrated Freestyle to rendering pipeline
[blender.git] / release / scripts / flt_filewalker.py
1 #!BPY
2
3 # flt_filewalker.py is an utility module for OpenFlight IO scripts for blender.
4 # Copyright (C) 2005 Greg MacDonald
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
20 __bpydoc__ ="""\
21 File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a
22 registered trademark of MultiGen-Paradigm, Inc.
23 """
24
25 import Blender
26 from struct import *
27 import re
28
29 class FltIn:
30     def __init__(self, filename):
31         self.file = open(filename, 'rb')
32         self.position = 0
33         self.next_position = 100000
34         self.opcode = 0
35         self.length = 0
36         self.level = 0
37         self.repeat = False # Repeat the last record.
38
39     def begin_record(self):
40         if self.repeat == True:
41             self.repeat = False
42         else:
43             self.position += self.length
44         try:
45             self.file.seek(self.position)
46             input = self.file.read(4)
47         except:
48             print 'Parse Error!'
49             return False
50             
51         if not input:
52             self.close_file()
53             return False
54             
55         self.opcode = unpack('>h', input[:2])[0]
56         self.length = unpack('>H', input[-2:])[0]
57         
58         self.next_position = self.position + self.length
59         
60         return True
61
62     def repeat_record(self):
63         self.repeat = True
64
65     def get_opcode(self):
66         return self.opcode
67
68     def get_level(self):
69         return self.level
70
71     def up_level(self):
72         self.level += 1
73
74     def down_level(self):
75         self.level -= 1
76
77     def read_string(self, length):
78         s = ''
79         if self.file.tell() + length <= self.next_position:
80             start = self.file.tell()
81             for i in xrange(length):
82                 char = self.file.read(1)
83                 if char == '\x00':
84                     break
85                 s = s + char
86             
87             self.file.seek(start+length)
88 #        else:
89 #            print 'Warning: string truncated'
90
91         return s
92     
93     def read_int(self):
94         if self.file.tell() + 4 <= self.next_position:
95             return unpack('>i', self.file.read(4))[0]
96         else:
97             #print 'Warning: int truncated'
98             return 0
99
100     def read_uint(self):
101         if self.file.tell() + 4 <= self.next_position:
102             return unpack('>I', self.file.read(4))[0]
103         else:
104             #print 'Warning: uint truncated'
105             return 0
106
107     def read_double(self):
108         if self.file.tell() + 8 <= self.next_position:
109             return unpack('>d', self.file.read(8))[0]
110         else:
111             #print 'Warning: double truncated'
112             return 0.0
113
114     def read_float(self):
115         if self.file.tell() + 4 <= self.next_position:
116             return unpack('>f', self.file.read(4))[0]
117         else:
118             #print 'Warning: float truncated'
119             return 0.0
120
121     def read_ushort(self):
122         if self.file.tell() + 2 <= self.next_position:
123             return unpack('>H', self.file.read(2))[0]
124         else:
125             #print 'Warning: ushort truncated'
126             return 0
127
128     def read_short(self):
129         if self.file.tell() + 2 <= self.next_position:
130             return unpack('>h', self.file.read(2))[0]
131         else:
132             #print 'Warning: short trunated'
133             return 0
134
135     def read_uchar(self):
136         if self.file.tell() + 1 <= self.next_position:
137             return unpack('>B', self.file.read(1))[0]
138         else:
139             #print 'Warning: uchar truncated'
140             return 0
141
142     def read_char(self):
143         if self.file.tell() + 1 <= self.next_position:
144             return unpack('>b', self.file.read(1))[0]
145         else:
146             #print 'Warning: char truncated'
147             return 0
148
149     def read_ahead(self, i):
150         if self.file.tell() + i <= self.next_position:
151             self.file.seek(i, 1)
152 #        else:
153 #            print 'Warning: attempt to seek past record'      
154
155     def get_length(self):
156         return self.length
157
158     def close_file(self):
159         self.file.close()
160         
161 class FltOut:
162     # Length includes terminating null
163     def write_string(self, string, length):
164         if len(string) > length - 1:
165             str_len = length - 1
166         else:
167             str_len = len(string)
168
169         pad_len = length - str_len
170
171         self.file.write(string[:str_len])
172
173         self.pad(pad_len)
174
175     def write_int(self, a):
176         self.file.write( pack('>i', a) )
177
178     def write_uint(self, a):
179         self.file.write( pack('>I', a) )
180
181     def write_double(self, a):
182         self.file.write( pack('>d', a) )
183
184     def write_float(self, a):
185         self.file.write( pack('>f', a) )
186
187     def write_ushort(self, a):
188         self.file.write( pack('>H', a) )
189
190     def write_short(self, a):
191         self.file.write( pack('>h', a) )
192
193     def write_uchar(self, a):
194         self.file.write( pack('>B', a) )
195
196     def write_char(self, a):
197         self.file.write( pack('>b', a) )
198
199     def pad(self, reps):
200         for i in xrange(reps):
201             self.file.write('\x00')
202
203     def close_file(self):
204         self.file.close()
205
206     def __init__(self, filename):
207                 self.file = open(filename, 'wb')
208                 self.filename = filename
209                 
210
211 class FileFinder:
212     def add_file_to_search_path(self, filename):
213         dir = Blender.sys.dirname(filename)
214         if dir != None and dir != '':
215             self.search_dirs.append(dir)
216
217     def strip_path(self, full_path):
218         # One of my flt files had a windows path with unix seperation. Basename
219         # returned the whole path + filename, which isn't expected. So my
220         # attempt to fix it is to replace all / or \ with the platform specific
221         # dir seperator.
222         #
223         # note: \\\\ is actually just one \ indirected twice, once for python
224         #       then again for re.sub
225         if Blender.sys.sep == '\\':
226             full_path = re.sub('/', '\\\\', full_path)
227         elif Blender.sys.sep == '/':
228             full_path = re.sub('\\\\', '/', full_path)
229             
230         filename = Blender.sys.basename(full_path)
231         return filename
232
233     def find(self, full_path):
234         if full_path == '':
235             return None
236
237         # Seperate out the path.
238         dirname = Blender.sys.dirname(full_path)
239
240         # Try it first.
241         if Blender.sys.exists(full_path):
242             if not dirname in self.search_dirs:
243                 self.search_dirs.append(dirname)
244             return full_path
245
246         # Maybe it's relative.
247         for path in self.search_dirs:
248             rel_full_path = Blender.sys.join(path, full_path)
249             if Blender.sys.exists(rel_full_path):
250                 return rel_full_path
251
252         # Search previous directories that have worked.
253         filename = self.strip_path(full_path)
254         for path in self.search_dirs:
255             t = Blender.sys.join(path, filename)
256             if Blender.sys.exists(t):
257                 return t
258
259         # Ask user where it is.
260         self.user_input = Blender.Draw.PupStrInput(filename + "? ", '', 100)
261         #self.user_input = None
262         if self.user_input != None:
263             t = Blender.sys.join(self.user_input, filename)
264             if Blender.sys.exists(t):
265                 user_dirname = Blender.sys.dirname(t)
266                 if not user_dirname in self.search_dirs:
267                     self.search_dirs.append(user_dirname)
268                 return t
269
270         # Couldn't find it.
271         return None
272
273     def __init__(self):
274         self.user_input = ''
275         self.current_file = ''
276         self.search_dirs = []
277         
278         dir = Blender.Get('texturesdir')
279         if dir != None and dir != '':
280             self.search_dirs.append(dir)
281         
282         dir = Blender.sys.dirname(Blender.Get('filename'))
283         if dir != None and dir != '':
284             print dir
285             self.search_dirs.append(dir)
286