view pytouhou/formats/std.py @ 94:ca571697ec83

Various minor optimisations and refactoring
author Thibaut Girka <thib@sitedethib.com>
date Sun, 04 Sep 2011 20:04:00 +0200
parents 3da4de9decd0
children ac2e5e1c2c3c
line wrap: on
line source

# -*- encoding: utf-8 -*-
##
## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 3 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##


from struct import pack, unpack
from pytouhou.utils.helpers import read_string, get_logger

logger = get_logger(__name__)


class Model(object):
    def __init__(self):
        self.unknown = 0
        self.bounding_box = (0., 0., 0.,
                             0., 0., 0.)
        self.quads = []



class Stage(object):
    def __init__(self, num):
        self.num = num
        self.name = ''
        self.bgms = (('', ''), ('', ''), ('', ''))
        self.models = []
        self.object_instances = []
        self.script = []


    @classmethod
    def read(cls, file, num):
        stage = Stage(num)

        nb_models, nb_faces = unpack('<HH', file.read(4))
        object_instances_offset, script_offset = unpack('<II', file.read(8))
        if file.read(4) != b'\x00\x00\x00\x00':
            raise Exception #TODO

        stage.name = read_string(file, 128, 'shift-jis')

        bgm_a = read_string(file, 128, 'shift-jis')
        bgm_b = read_string(file, 128, 'shift-jis')
        bgm_c = read_string(file, 128, 'shift-jis')
        bgm_d = read_string(file, 128, 'shift-jis')

        bgm_a_path = read_string(file, 128, 'ascii')
        bgm_b_path = read_string(file, 128, 'ascii')
        bgm_c_path = read_string(file, 128, 'ascii')
        bgm_d_path = read_string(file, 128, 'ascii')

        stage.bgms = [(bgm_a, bgm_a_path), (bgm_b, bgm_b_path), (bgm_c, bgm_c_path), (bgm_d, bgm_d_path)] #TODO: handle ' '

        # Read model definitions
        offsets = unpack('<%s' % ('I' * nb_models), file.read(4 * nb_models))
        for offset in offsets:
            model = Model()
            id_, unknown, x, y, z, width, height, depth = unpack('<HHffffff', file.read(28))
            model.unknown = unknown
            model.bounding_box = x, y, z, width, height, depth #TODO: check
            while True:
                unknown, size = unpack('<HH', file.read(4))
                if unknown == 0xffff:
                    break
                if size != 0x1c:
                    raise Exception #TODO
                script_index, _padding, x, y, z, width, height = unpack('<HHfffff', file.read(24))
                #TODO: store script_index, x, y, z, width and height
                model.quads.append((script_index, x, y, z, width, height))
            stage.models.append(model)


        # Read object usages
        file.seek(object_instances_offset)
        while True:
            obj_id, unknown, x, y, z = unpack('<HHfff', file.read(16))
            if (obj_id, unknown) == (0xffff, 0xffff):
                break
            if unknown != 256:
                raise Exception #TODO
            stage.object_instances.append((obj_id, x, y, z))


        # Read other funny things (script)
        file.seek(script_offset)
        while True:
            frame, message_type, size = unpack('<IHH', file.read(8))
            if (frame, message_type, size) == (0xffffffff, 0xffff, 0xffff):
                break
            if size != 0x0c:
                raise Exception #TODO
            data = file.read(12)
            #TODO: maybe add a name somewhere
            if message_type == 0: # ViewPos
                args = unpack('<fff', data)
            elif message_type == 1: # Color
                args = unpack('<BBBBff', data)
            elif message_type == 2: # ViewPos2
                args = unpack('<fff', data)
            elif message_type == 3:  # StartInterpolatingViewPos2
                args = tuple(unpack('<III', data)[:1])
            elif message_type == 4: # StartInterpolatingFog
                args = tuple(unpack('<III', data)[:1])
            else:
                args = (data,)
                logger.warn('unknown opcode %d (data: %r)', message_type, data)
            stage.script.append((frame, message_type, args))

        return stage