0
|
1 from struct import pack, unpack
|
|
2 from pytouhou.utils.helpers import read_string
|
|
3
|
|
4
|
|
5
|
|
6 class Object(object):
|
|
7 def __init__(self):
|
|
8 self.header = (b'\x00') * 28 #TODO
|
|
9 self.quads = []
|
|
10
|
|
11
|
|
12
|
|
13 class Stage(object):
|
15
|
14 def __init__(self, num):
|
|
15 self.num = num
|
0
|
16 self.name = ''
|
|
17 self.bgms = (('', ''), ('', ''), ('', ''))
|
|
18 self.objects = []
|
|
19 self.object_instances = []
|
|
20 self.script = []
|
|
21
|
|
22
|
|
23 @classmethod
|
15
|
24 def read(cls, file, num):
|
|
25 stage = Stage(num)
|
0
|
26
|
|
27 nb_objects, nb_faces = unpack('<HH', file.read(4))
|
|
28 object_instances_offset, script_offset = unpack('<II', file.read(8))
|
|
29 if file.read(4) != b'\x00\x00\x00\x00':
|
|
30 raise Exception #TODO
|
|
31
|
|
32 stage.name = read_string(file, 128, 'shift-jis')
|
|
33
|
|
34 bgm_a = read_string(file, 128, 'shift-jis')
|
|
35 bgm_b = read_string(file, 128, 'shift-jis')
|
|
36 bgm_c = read_string(file, 128, 'shift-jis')
|
|
37 bgm_d = read_string(file, 128, 'shift-jis')
|
|
38
|
|
39 bgm_a_path = read_string(file, 128, 'ascii')
|
|
40 bgm_b_path = read_string(file, 128, 'ascii')
|
|
41 bgm_c_path = read_string(file, 128, 'ascii')
|
|
42 bgm_d_path = read_string(file, 128, 'ascii')
|
|
43
|
|
44 stage.bgms = [(bgm_a, bgm_a_path), (bgm_b, bgm_b_path), (bgm_c, bgm_c_path), (bgm_d, bgm_d_path)] #TODO: handle ' '
|
|
45
|
|
46 # Read object definitions
|
|
47 offsets = unpack('<%s' % ('I' * nb_objects), file.read(4 * nb_objects))
|
|
48 for offset in offsets:
|
|
49 obj = Object()
|
|
50 obj.header = file.read(28) #TODO: this has to be reversed!
|
|
51 while True:
|
|
52 unknown, size = unpack('<HH', file.read(4))
|
|
53 if unknown == 0xffff:
|
|
54 break
|
|
55 if size != 0x1c:
|
|
56 raise Exception #TODO
|
|
57 script_index, _padding, x, y, z, width, height = unpack('<HHfffff', file.read(24))
|
|
58 #TODO: store script_index, x, y, z, width and height
|
|
59 obj.quads.append((script_index, x, y, z, width, height))
|
|
60 stage.objects.append(obj)
|
|
61
|
|
62
|
|
63 # Read object usages
|
|
64 file.seek(object_instances_offset)
|
|
65 while True:
|
|
66 obj_id, unknown, x, y, z = unpack('<HHfff', file.read(16))
|
|
67 if (obj_id, unknown) == (0xffff, 0xffff):
|
|
68 break
|
|
69 if unknown != 256:
|
|
70 raise Exception #TODO
|
|
71 stage.object_instances.append((stage.objects[obj_id], x, y, z))
|
|
72
|
|
73
|
|
74 # Read other funny things (script)
|
|
75 file.seek(script_offset)
|
|
76 while True:
|
|
77 frame, message_type, size = unpack('<IHH', file.read(8))
|
|
78 if (frame, message_type, size) == (0xffffffff, 0xffff, 0xffff):
|
|
79 break
|
|
80 if size != 0x0c:
|
|
81 raise Exception #TODO
|
|
82 data = file.read(12)
|
13
|
83 #TODO: maybe add a name somewhere
|
|
84 if message_type == 0: # ViewPos
|
|
85 args = unpack('<fff', data)
|
|
86 elif message_type == 1: # Color
|
|
87 args = unpack('<BBBBff', data)
|
|
88 elif message_type == 2: # ViewPos2
|
|
89 args = unpack('<Iff', data)
|
|
90 elif message_type == 3: # StartInterpolatingViewPos2
|
|
91 args = tuple(unpack('<III', data)[:1])
|
|
92 elif message_type == 4: # StartInterpolatingFog
|
|
93 args = tuple(unpack('<III', data)[:1])
|
|
94 else:
|
|
95 args = (data,)
|
|
96 print('Warning: unknown opcode %d' % message_type) #TODO
|
|
97 stage.script.append((frame, message_type, args))
|
0
|
98
|
|
99 return stage
|
|
100
|