comparison stageviewer.py @ 13:58bc264aba38

Refactor
author Thibaut Girka <thib@sitedethib.com>
date Fri, 05 Aug 2011 13:23:33 +0200
parents 548662d70860
children 07a7f28c8aaa
comparison
equal deleted inserted replaced
12:776453783743 13:58bc264aba38
8 from io import BytesIO 8 from io import BytesIO
9 from itertools import chain 9 from itertools import chain
10 10
11 import pygame 11 import pygame
12 12
13 from pytouhou.formats.pbg3 import PBG3
14 from pytouhou.game.background import Background
15
13 import OpenGL 16 import OpenGL
14 OpenGL.FORWARD_COMPATIBLE_ONLY = True 17 OpenGL.FORWARD_COMPATIBLE_ONLY = True
15 from OpenGL.GL import * 18 from OpenGL.GL import *
16 from OpenGL.GLU import * 19 from OpenGL.GLU import *
17 20
18 from pytouhou.formats.pbg3 import PBG3
19 from pytouhou.formats.std import Stage
20 from pytouhou.formats.anm0 import Animations
21
22 from pytouhou.utils.matrix import Matrix
23
24 21
25 def load_texture(image, alpha_image=None): 22 def load_texture(image, alpha_image=None):
23 #TODO: move elsewhere
26 textureSurface = pygame.image.load(image).convert_alpha() 24 textureSurface = pygame.image.load(image).convert_alpha()
27 25
28 if alpha_image: 26 if alpha_image:
29 alphaSurface = pygame.image.load(alpha_image) 27 alphaSurface = pygame.image.load(alpha_image)
30 assert textureSurface.get_size() == alphaSurface.get_size() 28 assert textureSurface.get_size() == alphaSurface.get_size()
49 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 47 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
50 48
51 return texture, width, height 49 return texture, width, height
52 50
53 51
54
55 def build_objects_faces(stage, anim):
56 objects_faces = []
57 for i, obj in enumerate(stage.objects):
58 faces = []
59 for script_index, x, y, z, width_override, height_override in obj.quads:
60 #TODO: move mof of it elsewhere
61 vertices = []
62 uvs = []
63 vertmat = Matrix()
64 vertmat.data[0][0] = -.5
65 vertmat.data[1][0] = -.5
66
67 vertmat.data[0][1] = .5
68 vertmat.data[1][1] = -.5
69
70 vertmat.data[0][2] = .5
71 vertmat.data[1][2] = .5
72
73 vertmat.data[0][3] = -.5
74 vertmat.data[1][3] = .5
75
76 for i in range(4):
77 vertmat.data[2][i] = 0.
78 vertmat.data[3][i] = 1.
79
80 properties = {}
81 for time, instr_type, data in anim.scripts[script_index]:
82 if instr_type == 15:
83 properties[15] = b''
84 break
85 elif time == 0: #TODO
86 properties[instr_type] = data
87 #if 15 not in properties: #TODO: Skip properties
88 # continue
89
90 #TODO: properties 3 and 4
91 if 1 in properties:
92 tx, ty, tw, th = anim.sprites[struct.unpack('<I', properties[1])[0]]
93 width, height = 1., 1.
94 if 2 in properties:
95 width, height = struct.unpack('<ff', properties[2])
96 width = width_override or width * tw
97 height = height_override or height * th
98 transform = Matrix.get_scaling_matrix(width, height, 1.)
99 if 7 in properties:
100 transform = Matrix.get_scaling_matrix(-1., 1., 1.).mult(transform)
101 if 9 in properties:
102 rx, ry, rz = struct.unpack('<fff', properties[9])
103 transform = Matrix.get_rotation_matrix(-rx, 'x').mult(transform)
104 transform = Matrix.get_rotation_matrix(ry, 'y').mult(transform)
105 transform = Matrix.get_rotation_matrix(-rz, 'z').mult(transform) #TODO: minus, really?
106 if 23 in properties: # Reposition
107 transform = Matrix.get_translation_matrix(width / 2., height / 2., 0.).mult(transform)
108
109 transform = Matrix.get_translation_matrix(x, y, z).mult(transform)
110 vertmat = transform.mult(vertmat)
111
112 uvs = [(tx / anim.size[0], 1. - (ty / anim.size[1])),
113 ((tx + tw) / anim.size[0], 1. - (ty / anim.size[1])),
114 ((tx + tw) / anim.size[0], 1. - ((ty + th) / anim.size[1])),
115 (tx / anim.size[0], 1. - ((ty + th) / anim.size[1]))]
116
117 for i in xrange(4):
118 w = vertmat.data[3][i]
119 vertices.append((vertmat.data[0][i] / w, vertmat.data[1][i] / w, vertmat.data[2][i] / w))
120 faces.append((vertices, uvs))
121 objects_faces.append(faces)
122 return objects_faces
123
124
125
126 def objects_faces_to_vertices_uvs(objects):
127 vertices = tuple(vertex for obj in objects for face in obj for vertex in face[0]) #TODO: check
128 uvs = tuple(uv for obj in objects for face in obj for uv in face[1]) #TODO: check
129 return vertices, uvs
130
131
132
133 def main(path, stage_num): 52 def main(path, stage_num):
134 # Initialize pygame 53 # Initialize pygame
135 pygame.init() 54 pygame.init()
136 window = pygame.display.set_mode((384, 448), pygame.OPENGL | pygame.DOUBLEBUF) 55 window = pygame.display.set_mode((384, 448), pygame.OPENGL | pygame.DOUBLEBUF)
137 56
151 glEnableClientState(GL_TEXTURE_COORD_ARRAY) 70 glEnableClientState(GL_TEXTURE_COORD_ARRAY)
152 71
153 # Load data 72 # Load data
154 with open(path, 'rb') as file: 73 with open(path, 'rb') as file:
155 archive = PBG3.read(file) 74 archive = PBG3.read(file)
156 stage = Stage.read(BytesIO(archive.extract('stage%d.std' % stage_num))) 75 background = Background(archive, stage_num)
157 anim = Animations.read(BytesIO(archive.extract('stg%dbg.anm' % stage_num)))
158 textures_components = [None, None]
159 for i, component_name in enumerate((anim.first_name, anim.secondary_name)):
160 if component_name:
161 textures_components[i] = BytesIO(archive.extract(os.path.basename(component_name)))
162 texture = load_texture(*textures_components)
163 76
164 print(stage.name) 77 texture = load_texture(*background.texture_components)
165 78
166 uvs = [] 79 print(background.stage.name)
167 vertices = []
168 objects_faces = build_objects_faces(stage, anim)
169 objects_instances_faces = []
170 for obj, ox, oy, oz in stage.object_instances:
171 obj_id = stage.objects.index(obj)
172 80
173 obj_instance = []
174 for face_vertices, face_uvs in objects_faces[obj_id]:
175 obj_instance.append((tuple((x + ox, y + oy, z + oz) for x, y, z in face_vertices),
176 face_uvs))
177 objects_instances_faces.append(obj_instance)
178
179 def keyfunc(obj):
180 return min(z for face in obj for x, y, z in face[0])
181 objects_instances_faces.sort(key=keyfunc, reverse=True)
182
183 vertices, uvs = objects_faces_to_vertices_uvs(objects_instances_faces)
184 nb_vertices = len(vertices)
185 vertices_format = 'f' * (3 * nb_vertices)
186 uvs_format = 'f' * (2 * nb_vertices)
187 vertices, uvs = objects_faces_to_vertices_uvs(objects_instances_faces)
188 glVertexPointer(3, GL_FLOAT, 0, struct.pack(vertices_format, *chain(*vertices)))
189 glTexCoordPointer(2, GL_FLOAT, 0, struct.pack(uvs_format, *chain(*uvs)))
190
191 x, y, z = 0, 0, 0
192 frame = 0 81 frame = 0
193 interpolation = 0, 0, 0
194 interpolation2 = 0, 0, 0
195 82
196 # Main loop 83 # Main loop
197 clock = pygame.time.Clock() 84 clock = pygame.time.Clock()
198 while True: 85 while True:
86 # Check events
199 for event in pygame.event.get(): 87 for event in pygame.event.get():
200 if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in (pygame.K_ESCAPE, pygame.K_q)): 88 if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in (pygame.K_ESCAPE, pygame.K_q)):
201 sys.exit(0) 89 sys.exit(0)
202 elif event.type == pygame.KEYDOWN: 90 elif event.type == pygame.KEYDOWN:
203 if event.key == pygame.K_RETURN and event.mod & pygame.KMOD_ALT: 91 if event.key == pygame.K_RETURN and event.mod & pygame.KMOD_ALT:
204 pygame.display.toggle_fullscreen() 92 pygame.display.toggle_fullscreen()
205 93
94 # Update game
95 background.update(frame)
96
97 # Draw everything
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 98 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
207 99
208 for frame_num, message_type, data in stage.script: 100 glVertexPointer(3, GL_FLOAT, 0, background._vertices)
209 if frame_num == frame and message_type == 1: 101 glTexCoordPointer(2, GL_FLOAT, 0, background._uvs)
210 #TODO: move interpolation elsewhere
211 next_fog_b, next_fog_g, next_fog_r, _, next_fog_start, next_fog_end = struct.unpack('<BBBBff', data)
212 if frame_num == frame and message_type == 3:
213 duration, junk1, junk2 = struct.unpack('<III', data)
214 interpolation = frame_num, duration, frame_num + duration
215 old_unknownx, old_dy, old_dz = unknownx, dy, dz
216 if frame_num == frame and message_type == 4:
217 duration, junk1, junk2 = struct.unpack('<III', data)
218 interpolation2 = frame_num, duration, frame_num + duration
219 old_fog_b, old_fog_g, old_fog_r, old_fog_start, old_fog_end = fog_b, fog_g, fog_r, fog_start, fog_end
220 if frame_num <= frame and message_type == 0:
221 last_message = frame_num, message_type, data
222 if frame_num <= frame and message_type == 2:
223 next_unknownx, next_dy, next_dz = struct.unpack('<fff', data)
224 if frame_num > frame and message_type == 0:
225 next_message = frame_num, message_type, data
226 break
227 102
228 if frame < interpolation[2]: 103 fog_b, fog_g, fog_r, _, fog_start, fog_end = background.fog_interpolator.values
229 truc = float(frame - interpolation[0]) / interpolation[1] 104 x, y, z = background.position_interpolator.values
230 unknownx = old_unknownx + (next_unknownx - old_unknownx) * truc 105 unknownx, dy, dz = background.position2_interpolator.values
231 dy = old_dy + (next_dy - old_dy) * truc
232 dz = old_dz + (next_dz - old_dz) * truc
233 else:
234 unknownx, dy, dz = next_unknownx, next_dy, next_dz
235
236 if frame < interpolation2[2]:
237 truc = float(frame - interpolation2[0]) / interpolation2[1]
238 fog_b = old_fog_b + (next_fog_b - old_fog_b) * truc
239 fog_g = old_fog_g + (next_fog_g - old_fog_g) * truc
240 fog_r = old_fog_r + (next_fog_r - old_fog_r) * truc
241 fog_start = old_fog_start + (next_fog_start - old_fog_start) * truc
242 fog_end = old_fog_end + (next_fog_end - old_fog_end) * truc
243 else:
244 fog_r, fog_g, fog_b, fog_start, fog_end = next_fog_r, next_fog_g, next_fog_b, next_fog_start, next_fog_end
245
246 106
247 glFogi(GL_FOG_MODE, GL_LINEAR) 107 glFogi(GL_FOG_MODE, GL_LINEAR)
248 glFogf(GL_FOG_START, fog_start) 108 glFogf(GL_FOG_START, fog_start)
249 glFogf(GL_FOG_END, fog_end) 109 glFogf(GL_FOG_END, fog_end)
250 glFogfv(GL_FOG_COLOR, (fog_r / 255., fog_g / 255., fog_b / 255., 1.)) 110 glFogfv(GL_FOG_COLOR, (fog_r / 255., fog_g / 255., fog_b / 255., 1.))
251 111
252 112 #TODO
253 x1, y1, z1 = struct.unpack('<fff', last_message[2])
254 x2, y2, z2 = struct.unpack('<fff', next_message[2])
255
256 truc = (float(frame) - last_message[0]) / (next_message[0] - last_message[0])
257
258 x = x1 + (x2 - x1) * truc
259 y = y1 + (y2 - y1) * truc
260 z = z1 + (z2 - z1) * truc
261
262
263 glMatrixMode(GL_MODELVIEW) 113 glMatrixMode(GL_MODELVIEW)
264 glLoadIdentity() 114 glLoadIdentity()
265 # Some explanations on the magic constants: 115 # Some explanations on the magic constants:
266 # 192. = 384. / 2. = width / 2. 116 # 192. = 384. / 2. = width / 2.
267 # 224. = 448. / 2. = height / 2. 117 # 224. = 448. / 2. = height / 2.
270 gluLookAt(192., 224., - 835.979370 * dz, 120 gluLookAt(192., 224., - 835.979370 * dz,
271 192., 224. - dy, 750 - 835.979370 * dz, 0., -1., 0.) #TODO: 750 might not be accurate 121 192., 224. - dy, 750 - 835.979370 * dz, 0., -1., 0.) #TODO: 750 might not be accurate
272 #print(glGetFloat(GL_MODELVIEW_MATRIX)) 122 #print(glGetFloat(GL_MODELVIEW_MATRIX))
273 glTranslatef(-x, -y, -z) 123 glTranslatef(-x, -y, -z)
274 124
275 glDrawArrays(GL_QUADS, 0, nb_vertices) 125 glDrawArrays(GL_QUADS, 0, background.nb_vertices)
276 126
277 #TODO: show the game itself 127 #TODO: show the game itself
278 # It is displayed on (0, 0, 0), (0, 448, 0), (388, 448, 0), (388, 0, 0) 128 # It is displayed on (0, 0, 0), (0, 448, 0), (388, 448, 0), (388, 0, 0)
279 # using a camera at (192, 224, -835.979370) looking right behind itself 129 # using a camera at (192, 224, -835.979370) looking right behind itself
280 # Depth test should be disabled when rendering the game 130 # Depth test should be disabled when rendering the game