comparison pytouhou/formats/std.py @ 110:3ac41b966fed

Add writing support to pytouhou.formats.std!
author Thibaut Girka <thib@sitedethib.com>
date Tue, 06 Sep 2011 16:40:32 +0200
parents ac2e5e1c2c3c
children 340fcda8e64a
comparison
equal deleted inserted replaced
109:e93a7ed4f203 110:3ac41b966fed
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details. 12 ## GNU General Public License for more details.
13 ## 13 ##
14 14
15 15
16 from struct import pack, unpack 16 from struct import pack, unpack, calcsize
17 from pytouhou.utils.helpers import read_string, get_logger 17 from pytouhou.utils.helpers import read_string, get_logger
18 18
19 logger = get_logger(__name__) 19 logger = get_logger(__name__)
20 20
21 21
27 self.quads = [] 27 self.quads = []
28 28
29 29
30 30
31 class Stage(object): 31 class Stage(object):
32 _instructions = {0: ('fff', 'set_viewpos'),
33 1: ('BBBBff', 'set_fog'),
34 2: ('fff', 'set_viewpos2'),
35 3: ('III', 'start_interpolating_viewpos2'),
36 4: ('III', 'start_interpolating_fog')}
37
32 def __init__(self): 38 def __init__(self):
33 self.name = '' 39 self.name = ''
34 self.bgms = (('', ''), ('', ''), ('', '')) 40 self.bgms = (('', ''), ('', ''), ('', ''))
35 self.models = [] 41 self.models = []
36 self.object_instances = [] 42 self.object_instances = []
44 nb_models, nb_faces = unpack('<HH', file.read(4)) 50 nb_models, nb_faces = unpack('<HH', file.read(4))
45 object_instances_offset, script_offset = unpack('<II', file.read(8)) 51 object_instances_offset, script_offset = unpack('<II', file.read(8))
46 if file.read(4) != b'\x00\x00\x00\x00': 52 if file.read(4) != b'\x00\x00\x00\x00':
47 raise Exception #TODO 53 raise Exception #TODO
48 54
49 stage.name = read_string(file, 128, 'shift-jis') 55 stage.name = read_string(file, 128, 'shift_jis')
50 56
51 bgm_a = read_string(file, 128, 'shift-jis') 57 bgm_a = read_string(file, 128, 'shift_jis')
52 bgm_b = read_string(file, 128, 'shift-jis') 58 bgm_b = read_string(file, 128, 'shift_jis')
53 bgm_c = read_string(file, 128, 'shift-jis') 59 bgm_c = read_string(file, 128, 'shift_jis')
54 bgm_d = read_string(file, 128, 'shift-jis') 60 bgm_d = read_string(file, 128, 'shift_jis')
55 61
56 bgm_a_path = read_string(file, 128, 'ascii') 62 bgm_a_path = read_string(file, 128, 'ascii')
57 bgm_b_path = read_string(file, 128, 'ascii') 63 bgm_b_path = read_string(file, 128, 'ascii')
58 bgm_c_path = read_string(file, 128, 'ascii') 64 bgm_c_path = read_string(file, 128, 'ascii')
59 bgm_d_path = read_string(file, 128, 'ascii') 65 bgm_d_path = read_string(file, 128, 'ascii')
71 unknown, size = unpack('<HH', file.read(4)) 77 unknown, size = unpack('<HH', file.read(4))
72 if unknown == 0xffff: 78 if unknown == 0xffff:
73 break 79 break
74 if size != 0x1c: 80 if size != 0x1c:
75 raise Exception #TODO 81 raise Exception #TODO
76 script_index, _padding, x, y, z, width, height = unpack('<HHfffff', file.read(24)) 82 script_index, x, y, z, width, height = unpack('<Hxxfffff', file.read(24))
77 #TODO: store script_index, x, y, z, width and height
78 model.quads.append((script_index, x, y, z, width, height)) 83 model.quads.append((script_index, x, y, z, width, height))
79 stage.models.append(model) 84 stage.models.append(model)
80 85
81 86
82 # Read object usages 87 # Read object usages
91 96
92 97
93 # Read other funny things (script) 98 # Read other funny things (script)
94 file.seek(script_offset) 99 file.seek(script_offset)
95 while True: 100 while True:
96 frame, message_type, size = unpack('<IHH', file.read(8)) 101 frame, opcode, size = unpack('<IHH', file.read(8))
97 if (frame, message_type, size) == (0xffffffff, 0xffff, 0xffff): 102 if (frame, opcode, size) == (0xffffffff, 0xffff, 0xffff):
98 break 103 break
99 if size != 0x0c: 104 if size != 0x0c:
100 raise Exception #TODO 105 raise Exception #TODO
101 data = file.read(12) 106 data = file.read(size)
102 #TODO: maybe add a name somewhere 107 if opcode in cls._instructions:
103 if message_type == 0: # ViewPos 108 args = unpack('<%s' % cls._instructions[opcode][0], data)
104 args = unpack('<fff', data)
105 elif message_type == 1: # Color
106 args = unpack('<BBBBff', data)
107 elif message_type == 2: # ViewPos2
108 args = unpack('<fff', data)
109 elif message_type == 3: # StartInterpolatingViewPos2
110 args = tuple(unpack('<III', data)[:1])
111 elif message_type == 4: # StartInterpolatingFog
112 args = tuple(unpack('<III', data)[:1])
113 else: 109 else:
114 args = (data,) 110 args = (data,)
115 logger.warn('unknown opcode %d (data: %r)', message_type, data) 111 logger.warn('unknown opcode %d', opcode)
116 stage.script.append((frame, message_type, args)) 112 stage.script.append((frame, opcode, args))
117 113
118 return stage 114 return stage
119 115
116
117 def write(self, file):
118 model_offsets = []
119 second_section_offset = 0
120 third_section_offset = 0
121
122 nb_faces = sum(len(model.quads) for model in self.models)
123
124 # Write header
125 file.write(pack('<HH', len(self.models), nb_faces)) #TODO: nb_faces
126 file.write(pack('<II', 0, 0))
127 file.write(pack('<I', 0))
128 file.write(pack('<128s', self.name.encode('shift_jis')))
129 for bgm_name, bgm_path in self.bgms:
130 file.write(pack('<128s', bgm_name.encode('shift_jis')))
131 for bgm_name, bgm_path in self.bgms:
132 file.write(pack('<128s', bgm_path.encode('ascii')))
133 file.write(b'\x00\x00\x00\x00' * len(self.models))
134
135 # Write first section
136 for i, model in enumerate(self.models):
137 model_offsets.append(file.tell())
138 file.write(pack('<HHffffff', i, model.unknown, *model.bounding_box))
139 for quad in model.quads:
140 file.write(pack('<HH', 0x00, 0x1c))
141 file.write(pack('<Hxxfffff', *quad))
142 file.write(pack('<HH', 0xffff, 4))
143
144 # Write second section
145 second_section_offset = file.tell()
146 for obj_id, x, y, z in self.object_instances:
147 file.write(pack('<HHfff', obj_id, 256, x, y, z))
148 file.write(b'\xff' * 16)
149
150 # Write third section
151 third_section_offset = file.tell()
152 for frame, opcode, args in self.script:
153 size = calcsize(self._instructions[opcode][0])
154 file.write(pack('<IHH%s' % self._instructions[opcode][0], frame, opcode, size, *args))
155 file.write(b'\xff' * 20)
156
157 # Fix offsets
158 file.seek(4)
159 file.write(pack('<II', second_section_offset, third_section_offset))
160 file.seek(16+128+128*2*4)
161 file.write(pack('<%sI' % len(self.models), *model_offsets))
162